Clean up, make state handlers options

This commit is contained in:
Adam Whitehurst 2020-01-05 10:19:09 -08:00
parent 2f3ccbc5d6
commit 8fe5cec947
21 changed files with 199 additions and 194 deletions

View File

@ -5,6 +5,8 @@ use crate::{
event::{EventBus, LocalEvent, ServerEvent},
state::DeltaTime,
};
use serde::Deserialize;
use serde::Serialize;
use specs::LazyUpdate;
use specs::{Component, Entity, FlaggedStorage, HashMapStorage, NullStorage};
use sphynx::Uid;
@ -36,20 +38,20 @@ pub struct StateUpdate {
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub enum MoveState {
Stand(StandState),
Run(RunState),
Sit(SitState),
Jump(JumpState),
Fall(FallState),
Glide(GlideState),
Swim(SwimState),
Climb(ClimbState),
Stand(Option<StandState>),
Run(Option<RunState>),
Sit(Option<SitState>),
Jump(Option<JumpState>),
Fall(Option<FallState>),
Glide(Option<GlideState>),
Swim(Option<SwimState>),
Climb(Option<ClimbState>),
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub enum ActionState {
Idle(IdleState),
Wield(WieldState),
Idle(Option<IdleState>),
Wield(Option<WieldState>),
Attack(AttackKind),
Block(BlockKind),
Dodge(DodgeKind),
@ -58,24 +60,24 @@ pub enum ActionState {
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub enum AttackKind {
BasicAttack(BasicAttackState),
Charge(ChargeAttackState),
BasicAttack(Option<BasicAttackState>),
Charge(Option<ChargeAttackState>),
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub enum BlockKind {
BasicBlock(BasicBlockState),
BasicBlock(Option<BasicBlockState>),
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub enum DodgeKind {
Roll(RollState),
Roll(Option<RollState>),
}
impl ActionState {
pub fn is_equip_finished(&self) -> bool {
match self {
Wield(WieldState { equip_delay }) => *equip_delay == Duration::default(),
Wield(Some(WieldState { equip_delay })) => *equip_delay == Duration::default(),
_ => true,
}
}
@ -83,21 +85,21 @@ impl ActionState {
/// Returns the current `equip_delay` if in `WieldState`, otherwise `Duration::default()`
pub fn get_delay(&self) -> Duration {
match self {
Wield(WieldState { equip_delay }) => *equip_delay,
Wield(Some(WieldState { equip_delay })) => *equip_delay,
_ => Duration::default(),
}
}
pub fn is_attacking(&self) -> bool {
match self {
Block(_) => true,
Attack(_) => true,
_ => false,
}
}
pub fn is_blocking(&self) -> bool {
match self {
Attack(_) => true,
Block(_) => true,
_ => false,
}
}
@ -126,7 +128,7 @@ impl ActionState {
}
/// __A concurrent state machine that allows for separate `ActionState`s and `MoveState`s.__
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct CharacterState {
/// __How the character is currently moving, e.g. Running, Standing, Falling.__
///
@ -162,8 +164,8 @@ impl CharacterState {
impl Default for CharacterState {
fn default() -> Self {
Self {
move_state: MoveState::Fall(FallState),
action_state: ActionState::Idle(IdleState),
move_state: MoveState::Fall(Some(FallState)),
action_state: ActionState::Idle(Some(IdleState)),
}
}
}

View File

@ -1,7 +1,8 @@
use crate::comp::{
ActionState::Attack, AttackKind::BasicAttack, EcsStateData, StateHandle, StateUpdate,
ActionState::Attack, AttackKind::BasicAttack, EcsStateData, MoveState, StateHandler,
StateUpdate, ToolData,
};
use crate::util::movement_utils::*;
use crate::util::state_utils::*;
use std::time::Duration;
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
@ -10,7 +11,7 @@ pub struct BasicAttackState {
pub remaining_duration: Duration,
}
impl StateHandle for BasicAttackState {
impl StateHandler for BasicAttackState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
pos: *ecs_data.pos,
@ -27,12 +28,12 @@ impl StateHandle for BasicAttackState {
}
// Otherwise, tick down remaining_duration, and keep rolling
update.character.action_state = Attack(BasicAttack(BasicAttackState {
update.character.action_state = Attack(BasicAttack(Some(BasicAttackState {
remaining_duration: self
.remaining_duration
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
.unwrap_or_default(),
}));
})));
return update;
}

View File

@ -1,16 +1,16 @@
use super::{BLOCK_ACCEL, BLOCK_SPEED};
use crate::comp::{EcsStateData, StateHandle, StateUpdate};
use crate::util::movement_utils::*;
use crate::comp::{EcsStateData, StateHandler, StateUpdate};
use crate::util::state_utils::*;
use std::time::Duration;
use vek::Vec2;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct BasicBlockState {
/// How long the blocking state has been active
pub active_duration: Duration,
}
impl StateHandle for BasicBlockState {
impl StateHandler for BasicBlockState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
pos: *ecs_data.pos,

View File

@ -1,21 +1,21 @@
use crate::comp::{
ActionState::Attack, AttackKind::Charge, EcsStateData, HealthChange, HealthSource,
MoveState::Run, RunState, StateHandle, StateUpdate,
MoveState::Run, RunState, StateHandler, StateUpdate,
};
use crate::event::ServerEvent;
use crate::util::movement_utils::*;
use crate::util::state_utils::*;
use std::time::Duration;
use vek::Vec3;
use super::CHARGE_SPEED;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct ChargeAttackState {
/// How long the state has until exitting
pub remaining_duration: Duration,
}
impl StateHandle for ChargeAttackState {
impl StateHandler for ChargeAttackState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
pos: *ecs_data.pos,
@ -25,7 +25,7 @@ impl StateHandle for ChargeAttackState {
};
// Prevent move state handling, handled here
update.character.move_state = Run(RunState);
update.character.move_state = Run(Some(RunState));
// Move player
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z)
@ -64,12 +64,12 @@ impl StateHandle for ChargeAttackState {
}
// Tick remaining-duration and keep charging
update.character.action_state = Attack(Charge(ChargeAttackState {
update.character.action_state = Attack(Charge(Some(ChargeAttackState {
remaining_duration: self
.remaining_duration
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
.unwrap_or_default(),
}));
})));
return update;
}

View File

@ -1,16 +1,16 @@
use super::{
ActionState::*, EcsStateData, FallState, IdleState, JumpState, MoveState::*, StandState,
StateHandle, StateUpdate,
StateHandler, StateUpdate,
};
use super::{CLIMB_SPEED, HUMANOID_CLIMB_ACCEL, HUMANOID_SPEED};
use crate::sys::phys::GRAVITY;
use vek::vec::{Vec2, Vec3};
use vek::Lerp;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct ClimbState;
impl StateHandle for ClimbState {
impl StateHandler for ClimbState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
pos: *ecs_data.pos,
@ -19,7 +19,7 @@ impl StateHandle for ClimbState {
character: *ecs_data.character,
};
update.character.action_state = Idle(IdleState);
update.character.action_state = Idle(Some(IdleState));
// Move player
update.vel.0 += Vec2::broadcast(ecs_data.dt.0)
@ -78,12 +78,12 @@ impl StateHandle for ClimbState {
if let None = ecs_data.physics.on_wall {
if ecs_data.inputs.jump.is_pressed() {
// They've climbed atop something, give them a boost
update.character.move_state = Jump(JumpState);
update.character.move_state = Jump(Some(JumpState));
return update;
} else {
// Just fall off
update.character.move_state = Fall(FallState);
update.character.move_state = Fall(Some(FallState));
return update;
}
@ -91,7 +91,7 @@ impl StateHandle for ClimbState {
// Remove climb state on ground, otherwise character will get stuck
if ecs_data.physics.on_ground {
update.character.move_state = Stand(StandState);
update.character.move_state = Stand(Some(StandState));
return update;
}

View File

@ -1,13 +1,13 @@
use super::{HUMANOID_AIR_ACCEL, HUMANOID_AIR_SPEED};
use crate::comp::{ClimbState, EcsStateData, GlideState, MoveState::*, StateHandle, StateUpdate};
use crate::comp::{ClimbState, EcsStateData, GlideState, MoveState::*, StateHandler, StateUpdate};
use crate::util::movement_utils::*;
use crate::util::state_utils::*;
use vek::{Vec2, Vec3};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct FallState;
impl StateHandle for FallState {
impl StateHandler for FallState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
pos: *ecs_data.pos,
@ -44,13 +44,13 @@ impl StateHandle for FallState {
// Check to start climbing
if can_climb(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
update.character.move_state = Climb(ClimbState);
update.character.move_state = Climb(Some(ClimbState));
return update;
}
// Check gliding
if ecs_data.inputs.glide.is_pressed() {
update.character.move_state = Glide(GlideState);
update.character.move_state = Glide(Some(GlideState));
return update;
}

View File

@ -1,14 +1,14 @@
use super::{GLIDE_ACCEL, GLIDE_ANTIGRAV, GLIDE_SPEED};
use crate::comp::{
ActionState::*, ClimbState, EcsStateData, FallState, IdleState, MoveState::*, StandState,
StateHandle, StateUpdate,
StateHandler, StateUpdate,
};
use vek::{Vec2, Vec3};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct GlideState;
impl StateHandle for GlideState {
impl StateHandler for GlideState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
pos: *ecs_data.pos,
@ -18,8 +18,8 @@ impl StateHandle for GlideState {
};
// Defaults for this state
update.character.action_state = Idle(IdleState);
update.character.move_state = Glide(GlideState);
update.character.action_state = Idle(Some(IdleState));
update.character.move_state = Glide(Some(GlideState));
// Move player according to movement direction vector
update.vel.0 += Vec2::broadcast(ecs_data.dt.0)
@ -54,19 +54,19 @@ impl StateHandle for GlideState {
// If glide button isn't held, start falling
if !ecs_data.inputs.glide.is_pressed() {
update.character.move_state = Fall(FallState);
update.character.move_state = Fall(Some(FallState));
return update;
}
// If there is a wall in front of character go to climb
if let Some(_wall_dir) = ecs_data.physics.on_wall {
update.character.move_state = Climb(ClimbState);
update.character.move_state = Climb(Some(ClimbState));
return update;
}
// If on ground go to stand
if ecs_data.physics.on_ground {
update.character.move_state = Stand(StandState);
update.character.move_state = Stand(Some(StandState));
return update;
}

View File

@ -1,13 +1,13 @@
use super::TEMP_EQUIP_DELAY;
use crate::comp::{
ActionState::Wield, EcsStateData, ItemKind::Tool, StateHandle, StateUpdate, WieldState,
ActionState::Wield, EcsStateData, ItemKind::Tool, StateHandler, StateUpdate, WieldState,
};
use std::time::Duration;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct IdleState;
impl StateHandle for IdleState {
impl StateHandler for IdleState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
character: *ecs_data.character,
@ -23,9 +23,9 @@ impl StateHandle for IdleState {
&& update.character.action_state.is_equip_finished())
{
if let Some(Tool { .. }) = ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind) {
update.character.action_state = Wield(WieldState {
update.character.action_state = Wield(Some(WieldState {
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
})
}))
}
// else unarmed stuff?

View File

@ -1,10 +1,10 @@
use super::{EcsStateData, FallState, MoveState::*, StateHandle, StateUpdate};
use super::{EcsStateData, FallState, MoveState::*, StateHandler, StateUpdate};
use crate::event::LocalEvent;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct JumpState;
impl StateHandle for JumpState {
impl StateHandler for JumpState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
character: *ecs_data.character,
@ -19,7 +19,7 @@ impl StateHandle for JumpState {
.emit(LocalEvent::Jump(*ecs_data.entity));
// Immediately go to falling state after jump impulse
update.character.move_state = Fall(FallState);
update.character.move_state = Fall(Some(FallState));
return update;
}
}

View File

@ -54,6 +54,8 @@ use super::{
ActionState, ActionState::*, AttackKind::*, BlockKind::*, DodgeKind::*, EcsStateData,
MoveState, MoveState::*, StateUpdate,
};
use std::time::Duration;
/// #### A trait for implementing state `handle()`ing logic.
/// _Mimics the typical OOP style state machine pattern where states implement their own behavior,
/// exit conditions, and return new states to the state machine upon exit.
@ -70,50 +72,49 @@ use super::{
/// `CharacterState` update `System` passes `EcsStateData` to `ActionState`/`MoveState` `handle()` which matches the character's
/// current state to its `handle()` fn, hiding the implementation details, since the System is only concerned with
/// how the update flow occurs and is in charge of updating the ECS components.
pub trait StateHandle {
pub trait StateHandler: Default {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate;
}
// Public interface that passes EcsStateData to `StateHandle`s `handle()` fn
impl StateHandle for ActionState {
impl ActionState {
/// Passes handle to variant or subvariant handlers
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
pub fn update(&self, ecs_data: &EcsStateData) -> StateUpdate {
match self {
Attack(kind) => match kind {
BasicAttack(state) => state.handle(ecs_data),
Charge(state) => state.handle(ecs_data),
BasicAttack(Some(state)) => state.handle(&ecs_data),
Charge(Some(state)) => state.handle(&ecs_data),
},
Block(kind) => match kind {
BasicBlock(state) => state.handle(ecs_data),
BasicBlock(Some(state)) => state.handle(&ecs_data),
},
Dodge(kind) => match kind {
Roll(state) => state.handle(ecs_data),
Roll(Some(state)) => state.handle(&ecs_data),
},
Wield(state) => state.handle(ecs_data),
Idle(state) => state.handle(ecs_data),
Wield(Some(state)) => state.handle(&ecs_data),
Idle(Some(state)) => state.handle(&ecs_data),
//
// All states should be explicitly handled
// Do not use default match: _ => {},
}
}
}
// Other fn's that relate to individual `ActionState`s
impl ActionState {
/// Returns whether a given `ActionState` overrides `MoveState` `handle()`ing
pub fn overrides_move_state(&self) -> bool {
match self {
Attack(kind) => match kind {
BasicAttack(state) => false,
Charge(state) => true,
BasicAttack(_) => false,
Charge(_) => true,
},
Block(kind) => match kind {
BasicBlock(state) => true,
BasicBlock(_) => true,
},
Dodge(kind) => match kind {
Roll(state) => true,
Roll(_) => true,
},
Wield(state) => false,
Idle(state) => false,
Wield(_) => false,
Idle(_) => false,
//
// All states should be explicitly handled
// Do not use default match: _ => {},
}
@ -125,33 +126,31 @@ impl MoveState {
/// Returns whether a given `ActionState` overrides `MoveState` `handle()`ing
pub fn overrides_action_state(&self) -> bool {
match self {
Stand(state) => false,
Run(state) => false,
Jump(state) => false,
Climb(state) => true,
Glide(state) => true,
Swim(state) => false,
Fall(state) => false,
Sit(state) => true,
Stand(_) => false,
Run(_) => false,
Jump(_) => false,
Climb(_) => true,
Glide(_) => true,
Swim(_) => false,
Fall(_) => false,
Sit(_) => true,
//
// All states should be explicitly handled
// Do not use default match: _ => {},
}
}
}
/// Public interface that passes EcsStateData to `StateHandle`s `handle()` fn
impl StateHandle for MoveState {
/// Passes handle to variant handlers
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
pub fn update(&self, ecs_data: &EcsStateData) -> StateUpdate {
match self {
Stand(state) => state.handle(&ecs_data),
Run(state) => state.handle(&ecs_data),
Jump(state) => state.handle(&ecs_data),
Climb(state) => state.handle(&ecs_data),
Glide(state) => state.handle(&ecs_data),
Swim(state) => state.handle(&ecs_data),
Fall(state) => state.handle(&ecs_data),
Sit(state) => state.handle(&ecs_data),
Stand(Some(state)) => state.handle(&ecs_data),
Run(Some(state)) => state.handle(&ecs_data),
Jump(Some(state)) => state.handle(&ecs_data),
Climb(Some(state)) => state.handle(&ecs_data),
Glide(Some(state)) => state.handle(&ecs_data),
Swim(Some(state)) => state.handle(&ecs_data),
Fall(Some(state)) => state.handle(&ecs_data),
Sit(Some(state)) => state.handle(&ecs_data),
// All states should be explicitly handled
// Do not use default match: _ => {},
}

View File

@ -1,6 +1,6 @@
use super::ROLL_SPEED;
use crate::comp::{ActionState::*, DodgeKind::*, EcsStateData, StateHandle, StateUpdate};
use crate::util::movement_utils::*;
use crate::comp::{ActionState::*, DodgeKind::*, EcsStateData, StateHandler, StateUpdate};
use crate::util::state_utils::*;
use std::time::Duration;
use vek::Vec3;
@ -10,7 +10,7 @@ pub struct RollState {
remaining_duration: Duration,
}
impl StateHandle for RollState {
impl StateHandler for RollState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
character: *ecs_data.character,
@ -40,12 +40,12 @@ impl StateHandle for RollState {
}
// Otherwise, tick down remaining_duration
update.character.action_state = Dodge(Roll(RollState {
update.character.action_state = Dodge(Roll(Some(RollState {
remaining_duration: self
.remaining_duration
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
.unwrap_or_default(),
}));
})));
// Keep rolling
return update;

View File

@ -1,15 +1,15 @@
use super::{HUMANOID_ACCEL, HUMANOID_SPEED};
use crate::comp::{
ClimbState, EcsStateData, GlideState, JumpState, MoveState::*, SitState, StateHandle,
ClimbState, EcsStateData, GlideState, JumpState, MoveState::*, SitState, StateHandler,
StateUpdate,
};
use crate::util::movement_utils::*;
use crate::util::state_utils::*;
use vek::vec::{Vec2, Vec3};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct RunState;
impl StateHandle for RunState {
impl StateHandler for RunState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
character: *ecs_data.character,
@ -46,25 +46,25 @@ impl StateHandle for RunState {
// Try to sit
if can_sit(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
update.character.move_state = Sit(SitState);
update.character.move_state = Sit(Some(SitState));
return update;
}
// Try to climb
if can_climb(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
update.character.move_state = Climb(ClimbState);
update.character.move_state = Climb(Some(ClimbState));
return update;
}
// Try to jump
if can_jump(ecs_data.physics, ecs_data.inputs) {
update.character.move_state = Jump(JumpState);
update.character.move_state = Jump(Some(JumpState));
return update;
}
// Try to glide
if can_glide(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
update.character.move_state = Glide(GlideState);
update.character.move_state = Glide(Some(GlideState));
return update;
}

View File

@ -1,13 +1,13 @@
use crate::comp::{
ActionState::*, EcsStateData, IdleState, JumpState, MoveState::*, RunState, StandState,
StateHandle, StateUpdate,
StateHandler, StateUpdate,
};
use crate::util::movement_utils::*;
use crate::util::state_utils::*;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct SitState;
impl StateHandle for SitState {
impl StateHandler for SitState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
character: *ecs_data.character,
@ -17,8 +17,8 @@ impl StateHandle for SitState {
};
// Prevent action state handling
update.character.action_state = Idle(IdleState);
update.character.move_state = Sit(SitState);
update.character.action_state = Idle(Some(IdleState));
update.character.move_state = Sit(Some(SitState));
// Try to Fall
// ... maybe the ground disappears,
@ -30,19 +30,19 @@ impl StateHandle for SitState {
}
// Try to jump
if ecs_data.inputs.jump.is_pressed() {
update.character.move_state = Jump(JumpState);
update.character.move_state = Jump(Some(JumpState));
return update;
}
// Try to Run
if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
update.character.move_state = Run(RunState);
update.character.move_state = Run(Some(RunState));
return update;
}
// Try to Stand
if ecs_data.inputs.sit.is_just_pressed() {
update.character.move_state = Stand(StandState);
update.character.move_state = Stand(Some(StandState));
return update;
}

View File

@ -1,13 +1,13 @@
use crate::comp::{
ClimbState, EcsStateData, GlideState, JumpState, MoveState::*, SitState, StateHandle,
ClimbState, EcsStateData, GlideState, JumpState, MoveState::*, SitState, StateHandler,
StateUpdate,
};
use crate::util::movement_utils::*;
use crate::util::state_utils::*;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct StandState;
impl StateHandle for StandState {
impl StateHandler for StandState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
character: *ecs_data.character,
@ -18,25 +18,25 @@ impl StateHandle for StandState {
// Try to sit
if can_sit(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
update.character.move_state = Sit(SitState);
update.character.move_state = Sit(Some(SitState));
return update;
}
// Try to climb
if can_climb(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
update.character.move_state = Climb(ClimbState);
update.character.move_state = Climb(Some(ClimbState));
return update;
}
// Try to jump
if can_jump(ecs_data.physics, ecs_data.inputs) {
update.character.move_state = Jump(JumpState);
update.character.move_state = Jump(Some(JumpState));
return update;
}
// Check gliding
if can_glide(ecs_data.physics, ecs_data.inputs, ecs_data.body) {
update.character.move_state = Glide(GlideState);
update.character.move_state = Glide(Some(GlideState));
return update;
}

View File

@ -1,12 +1,12 @@
use super::{HUMANOID_WATER_ACCEL, HUMANOID_WATER_SPEED};
use crate::comp::{EcsStateData, MoveState::*, RunState, StandState, StateHandle, StateUpdate};
use crate::comp::{EcsStateData, MoveState::*, RunState, StandState, StateHandler, StateUpdate};
use crate::sys::phys::GRAVITY;
use vek::{Vec2, Vec3};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct SwimState;
impl StateHandle for SwimState {
impl StateHandler for SwimState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
character: *ecs_data.character,
@ -51,16 +51,16 @@ impl StateHandle for SwimState {
// Not on ground
if !ecs_data.physics.on_ground {
update.character.move_state = Swim(SwimState);
update.character.move_state = Swim(Some(SwimState));
return update;
}
// On ground
else {
// Return to running or standing based on move inputs
update.character.move_state = if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
Run(RunState)
Run(Some(RunState))
} else {
Stand(StandState)
Stand(Some(StandState))
};
return update;

View File

@ -1,18 +1,18 @@
use crate::comp::{
AbilityAction, AbilityActionKind::*, ActionState::*, EcsStateData, IdleState, StateHandle,
AbilityAction, AbilityActionKind::*, ActionState::*, EcsStateData, IdleState, StateHandler,
StateUpdate,
};
use crate::util::movement_utils::*;
use crate::util::state_utils::*;
use std::time::Duration;
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
#[derive(Clone, Copy, Default, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub struct WieldState {
/// How long before a new action can be performed
/// after equipping
pub equip_delay: Duration,
}
impl StateHandle for WieldState {
impl StateHandler for WieldState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate {
character: *ecs_data.character,
@ -27,29 +27,29 @@ impl StateHandle for WieldState {
if ecs_data.inputs.toggle_wield.is_just_pressed()
&& ecs_data.character.action_state.is_equip_finished()
{
update.character.action_state = Idle(IdleState);
update.character.action_state = Idle(Some(IdleState));
return update;
}
// Try weapon actions
if ecs_data.inputs.primary.is_pressed() {
ecs_data
.updater
.insert(*ecs_data.entity, AbilityAction(Primary));
// ecs_data
// .updater
// .insert(*ecs_data.entity, AbilityAction(Primary));
} else if ecs_data.inputs.secondary.is_pressed() {
ecs_data
.updater
.insert(*ecs_data.entity, AbilityAction(Secondary));
// ecs_data
// .updater
// .insert(*ecs_data.entity, AbilityAction(Secondary));
}
} else {
// Equip delay hasn't expired yet
// Update wield delay
update.character.action_state = Wield(WieldState {
update.character.action_state = Wield(Some(WieldState {
equip_delay: self
.equip_delay
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
.unwrap_or_default(),
});
}));
}
return update;

View File

@ -1,5 +1,8 @@
#![allow(unused_imports)]
#![allow(dead_code)]
use crate::comp::{
AbilityAction, AbilityActionKind, AbilityPool, ActionState::*, AttackKind, CharacterState,
StateHandler,
};
use specs::{Entities, Join, LazyUpdate, Read, ReadStorage, System, WriteStorage};
@ -37,27 +40,27 @@ impl<'a> System<'a> for Sys {
.join()
{
match ability_action.0 {
AbilityActionKind::Primary => {
if let Some(attack_kind) = ability_pool.primary {
character.action_state = Attack(attack_kind);
}
}
AbilityActionKind::Secondary => {
if let Some(attack_kind) = ability_pool.secondary {
character.action_state = Attack(attack_kind);
}
}
AbilityActionKind::Block => {
if let Some(block_kind) = ability_pool.block {
character.action_state = Block(block_kind);
}
}
AbilityActionKind::Dodge => {
if let Some(dodge_kind) = ability_pool.dodge {
character.action_state = Dodge(dodge_kind);
}
}
_ => {}
// AbilityActionKind::Primary => {
// if let Some(AttackKind(Some(attack_kind))) = ability_pool.primary {
// character.action_state = Attack(attack_kind::default());
// }
// }
// AbilityActionKind::Secondary => {
// if let Some(attack_kind) = ability_pool.secondary {
// character.action_state = Attack(attack_kind::default());
// }
// }
// AbilityActionKind::Block => {
// if let Some(block_kind) = ability_pool.block {
// character.action_state = Block(block_kind::default());
// }
// }
// AbilityActionKind::Dodge => {
// if let Some(dodge_kind) = ability_pool.dodge {
// character.action_state = Dodge(dodge_kind::default());
// }
// }
// _ => {}
}
}
}

View File

@ -163,7 +163,7 @@ impl<'a> System<'a> for Sys {
inputs.roll.set_state(true);
}
if target_character.move_state == Glide(GlideState)
if target_character.move_state == Glide(Some(GlideState))
&& target_pos.0.z > pos.0.z + 5.0
{
inputs.glide.set_state(true);

View File

@ -1,7 +1,7 @@
use crate::{
comp::{
states::*, Body, CharacterState, Controller, EcsStateData, Mounting, MoveState::*, Ori,
OverrideAction, OverrideMove, OverrideState, PhysicsState, Pos, SitState, StateHandle,
OverrideAction, OverrideMove, OverrideState, PhysicsState, Pos, SitState, StateHandler,
Stats, Vel,
},
event::{EventBus, LocalEvent, ServerEvent},
@ -102,7 +102,7 @@ impl<'a> System<'a> for Sys {
// If mounted, character state is controlled by mount
// TODO: Make mounting a state
if let Some(Mounting(_)) = mountings.get(entity) {
character.move_state = Sit(SitState);
character.move_state = Sit(Some(SitState));
return;
}
@ -111,7 +111,7 @@ impl<'a> System<'a> for Sys {
action_overrides.get(entity),
character.action_state.overrides_move_state(),
) {
let state_update = character.action_state.handle(&EcsStateData {
let state_update = character.action_state.update(&EcsStateData {
entity: &entity,
uid,
character,
@ -139,7 +139,7 @@ impl<'a> System<'a> for Sys {
move_overrides.get(entity),
character.move_state.overrides_action_state(),
) {
let state_update = character.move_state.handle(&EcsStateData {
let state_update = character.move_state.update(&EcsStateData {
entity: &entity,
uid,
character,

View File

@ -7,7 +7,7 @@ lazy_static::lazy_static! {
use vek::{Mat3, Rgb, Rgba, Vec3};
pub mod movement_utils;
pub mod state_utils;
/// TODO: Move these to a named utils folder. Are they even being used? I couldnt find references.
/// This is a fast approximation of powf. This should only be used when minor accuracy loss is acceptable.

View File

@ -11,11 +11,11 @@ use std::time::Duration;
/// ... or Idle if nothing it possible?_
pub fn determine_primary_ability(stats: &Stats) -> ActionState {
if let Some(Tool(data)) = stats.equipment.main.as_ref().map(|i| &i.kind) {
Attack(BasicAttack(BasicAttackState {
Attack(BasicAttack(Some(BasicAttackState {
remaining_duration: data.attack_duration(),
}))
})))
} else {
Idle(IdleState)
Idle(Some(IdleState))
}
}
@ -24,11 +24,11 @@ pub fn determine_primary_ability(stats: &Stats) -> ActionState {
/// ... or Idle if nothing it possible?_
pub fn determine_secondary_ability(stats: &Stats) -> ActionState {
if let Some(Tool(data)) = stats.equipment.main.as_ref().map(|i| &i.kind) {
Block(BasicBlock(BasicBlockState {
Block(BasicBlock(Some(BasicBlockState {
active_duration: Duration::default(),
}))
})))
} else {
Idle(IdleState)
Idle(Some(IdleState))
}
}
@ -36,18 +36,18 @@ pub fn determine_secondary_ability(stats: &Stats) -> ActionState {
pub fn determine_fall_or_swim(physics: &PhysicsState) -> MoveState {
// Check if in fluid to go to swimming or back to falling
if physics.in_fluid {
Swim(SwimState)
Swim(Some(SwimState))
} else {
Fall(FallState)
Fall(Some(FallState))
}
}
/// __Returns a `MoveState` based on `move_dir` magnitude__
pub fn determine_stand_or_run(inputs: &ControllerInputs) -> MoveState {
// Return to running or standing based on move inputs
if inputs.move_dir.magnitude_squared() > 0.0 {
Run(RunState)
Run(Some(RunState))
} else {
Stand(StandState)
Stand(Some(StandState))
}
}
@ -72,11 +72,11 @@ pub fn determine_move_from_grounded_state(
/// __Returns an ActionState based on whether character has a weapon equipped.__
pub fn attempt_wield(stats: &Stats) -> ActionState {
if let Some(Tool { .. }) = stats.equipment.main.as_ref().map(|i| &i.kind) {
Wield(WieldState {
Wield(Some(WieldState {
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
})
}))
} else {
Idle(IdleState)
Idle(Some(IdleState))
}
}