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

View File

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

View File

@ -1,16 +1,16 @@
use super::{BLOCK_ACCEL, BLOCK_SPEED}; use super::{BLOCK_ACCEL, BLOCK_SPEED};
use crate::comp::{EcsStateData, StateHandle, StateUpdate}; use crate::comp::{EcsStateData, StateHandler, StateUpdate};
use crate::util::movement_utils::*; use crate::util::state_utils::*;
use std::time::Duration; use std::time::Duration;
use vek::Vec2; 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 { pub struct BasicBlockState {
/// How long the blocking state has been active /// How long the blocking state has been active
pub active_duration: Duration, pub active_duration: Duration,
} }
impl StateHandle for BasicBlockState { impl StateHandler for BasicBlockState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate { fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
pos: *ecs_data.pos, pos: *ecs_data.pos,

View File

@ -1,21 +1,21 @@
use crate::comp::{ use crate::comp::{
ActionState::Attack, AttackKind::Charge, EcsStateData, HealthChange, HealthSource, ActionState::Attack, AttackKind::Charge, EcsStateData, HealthChange, HealthSource,
MoveState::Run, RunState, StateHandle, StateUpdate, MoveState::Run, RunState, StateHandler, StateUpdate,
}; };
use crate::event::ServerEvent; use crate::event::ServerEvent;
use crate::util::movement_utils::*; use crate::util::state_utils::*;
use std::time::Duration; use std::time::Duration;
use vek::Vec3; use vek::Vec3;
use super::CHARGE_SPEED; 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 { pub struct ChargeAttackState {
/// How long the state has until exitting /// How long the state has until exitting
pub remaining_duration: Duration, pub remaining_duration: Duration,
} }
impl StateHandle for ChargeAttackState { impl StateHandler for ChargeAttackState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate { fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
pos: *ecs_data.pos, pos: *ecs_data.pos,
@ -25,7 +25,7 @@ impl StateHandle for ChargeAttackState {
}; };
// Prevent move state handling, handled here // Prevent move state handling, handled here
update.character.move_state = Run(RunState); update.character.move_state = Run(Some(RunState));
// Move player // Move player
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z) 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 // 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: self
.remaining_duration .remaining_duration
.checked_sub(Duration::from_secs_f32(ecs_data.dt.0)) .checked_sub(Duration::from_secs_f32(ecs_data.dt.0))
.unwrap_or_default(), .unwrap_or_default(),
})); })));
return update; return update;
} }

View File

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

View File

@ -1,13 +1,13 @@
use super::{HUMANOID_AIR_ACCEL, HUMANOID_AIR_SPEED}; 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}; 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; pub struct FallState;
impl StateHandle for FallState { impl StateHandler for FallState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate { fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
pos: *ecs_data.pos, pos: *ecs_data.pos,
@ -44,13 +44,13 @@ impl StateHandle for FallState {
// Check to start climbing // Check to start climbing
if can_climb(ecs_data.physics, ecs_data.inputs, ecs_data.body) { 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; return update;
} }
// Check gliding // Check gliding
if ecs_data.inputs.glide.is_pressed() { if ecs_data.inputs.glide.is_pressed() {
update.character.move_state = Glide(GlideState); update.character.move_state = Glide(Some(GlideState));
return update; return update;
} }

View File

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

View File

@ -1,13 +1,13 @@
use super::TEMP_EQUIP_DELAY; use super::TEMP_EQUIP_DELAY;
use crate::comp::{ use crate::comp::{
ActionState::Wield, EcsStateData, ItemKind::Tool, StateHandle, StateUpdate, WieldState, ActionState::Wield, EcsStateData, ItemKind::Tool, StateHandler, StateUpdate, WieldState,
}; };
use std::time::Duration; 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; pub struct IdleState;
impl StateHandle for IdleState { impl StateHandler for IdleState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate { fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
character: *ecs_data.character, character: *ecs_data.character,
@ -23,9 +23,9 @@ impl StateHandle for IdleState {
&& update.character.action_state.is_equip_finished()) && update.character.action_state.is_equip_finished())
{ {
if let Some(Tool { .. }) = ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind) { 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), equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
}) }))
} }
// else unarmed stuff? // 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; 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; pub struct JumpState;
impl StateHandle for JumpState { impl StateHandler for JumpState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate { fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
character: *ecs_data.character, character: *ecs_data.character,
@ -19,7 +19,7 @@ impl StateHandle for JumpState {
.emit(LocalEvent::Jump(*ecs_data.entity)); .emit(LocalEvent::Jump(*ecs_data.entity));
// Immediately go to falling state after jump impulse // Immediately go to falling state after jump impulse
update.character.move_state = Fall(FallState); update.character.move_state = Fall(Some(FallState));
return update; return update;
} }
} }

View File

@ -54,6 +54,8 @@ use super::{
ActionState, ActionState::*, AttackKind::*, BlockKind::*, DodgeKind::*, EcsStateData, ActionState, ActionState::*, AttackKind::*, BlockKind::*, DodgeKind::*, EcsStateData,
MoveState, MoveState::*, StateUpdate, MoveState, MoveState::*, StateUpdate,
}; };
use std::time::Duration;
/// #### A trait for implementing state `handle()`ing logic. /// #### A trait for implementing state `handle()`ing logic.
/// _Mimics the typical OOP style state machine pattern where states implement their own behavior, /// _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. /// 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 /// `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 /// 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. /// 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; fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate;
} }
// Public interface that passes EcsStateData to `StateHandle`s `handle()` fn // Public interface that passes EcsStateData to `StateHandle`s `handle()` fn
impl StateHandle for ActionState { impl ActionState {
/// Passes handle to variant or subvariant handlers /// Passes handle to variant or subvariant handlers
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate { pub fn update(&self, ecs_data: &EcsStateData) -> StateUpdate {
match self { match self {
Attack(kind) => match kind { Attack(kind) => match kind {
BasicAttack(state) => state.handle(ecs_data), BasicAttack(Some(state)) => state.handle(&ecs_data),
Charge(state) => state.handle(ecs_data), Charge(Some(state)) => state.handle(&ecs_data),
}, },
Block(kind) => match kind { Block(kind) => match kind {
BasicBlock(state) => state.handle(ecs_data), BasicBlock(Some(state)) => state.handle(&ecs_data),
}, },
Dodge(kind) => match kind { Dodge(kind) => match kind {
Roll(state) => state.handle(ecs_data), Roll(Some(state)) => state.handle(&ecs_data),
}, },
Wield(state) => state.handle(ecs_data), Wield(Some(state)) => state.handle(&ecs_data),
Idle(state) => state.handle(ecs_data), Idle(Some(state)) => state.handle(&ecs_data),
//
// All states should be explicitly handled // All states should be explicitly handled
// Do not use default match: _ => {}, // 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 /// Returns whether a given `ActionState` overrides `MoveState` `handle()`ing
pub fn overrides_move_state(&self) -> bool { pub fn overrides_move_state(&self) -> bool {
match self { match self {
Attack(kind) => match kind { Attack(kind) => match kind {
BasicAttack(state) => false, BasicAttack(_) => false,
Charge(state) => true, Charge(_) => true,
}, },
Block(kind) => match kind { Block(kind) => match kind {
BasicBlock(state) => true, BasicBlock(_) => true,
}, },
Dodge(kind) => match kind { Dodge(kind) => match kind {
Roll(state) => true, Roll(_) => true,
}, },
Wield(state) => false, Wield(_) => false,
Idle(state) => false, Idle(_) => false,
//
// All states should be explicitly handled // All states should be explicitly handled
// Do not use default match: _ => {}, // Do not use default match: _ => {},
} }
@ -125,33 +126,31 @@ impl MoveState {
/// Returns whether a given `ActionState` overrides `MoveState` `handle()`ing /// Returns whether a given `ActionState` overrides `MoveState` `handle()`ing
pub fn overrides_action_state(&self) -> bool { pub fn overrides_action_state(&self) -> bool {
match self { match self {
Stand(state) => false, Stand(_) => false,
Run(state) => false, Run(_) => false,
Jump(state) => false, Jump(_) => false,
Climb(state) => true, Climb(_) => true,
Glide(state) => true, Glide(_) => true,
Swim(state) => false, Swim(_) => false,
Fall(state) => false, Fall(_) => false,
Sit(state) => true, Sit(_) => true,
//
// All states should be explicitly handled // All states should be explicitly handled
// Do not use default match: _ => {}, // Do not use default match: _ => {},
} }
} }
}
/// Public interface that passes EcsStateData to `StateHandle`s `handle()` fn
impl StateHandle for MoveState {
/// Passes handle to variant handlers /// Passes handle to variant handlers
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate { pub fn update(&self, ecs_data: &EcsStateData) -> StateUpdate {
match self { match self {
Stand(state) => state.handle(&ecs_data), Stand(Some(state)) => state.handle(&ecs_data),
Run(state) => state.handle(&ecs_data), Run(Some(state)) => state.handle(&ecs_data),
Jump(state) => state.handle(&ecs_data), Jump(Some(state)) => state.handle(&ecs_data),
Climb(state) => state.handle(&ecs_data), Climb(Some(state)) => state.handle(&ecs_data),
Glide(state) => state.handle(&ecs_data), Glide(Some(state)) => state.handle(&ecs_data),
Swim(state) => state.handle(&ecs_data), Swim(Some(state)) => state.handle(&ecs_data),
Fall(state) => state.handle(&ecs_data), Fall(Some(state)) => state.handle(&ecs_data),
Sit(state) => state.handle(&ecs_data), Sit(Some(state)) => state.handle(&ecs_data),
// All states should be explicitly handled // All states should be explicitly handled
// Do not use default match: _ => {}, // Do not use default match: _ => {},
} }

View File

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

View File

@ -1,15 +1,15 @@
use super::{HUMANOID_ACCEL, HUMANOID_SPEED}; use super::{HUMANOID_ACCEL, HUMANOID_SPEED};
use crate::comp::{ use crate::comp::{
ClimbState, EcsStateData, GlideState, JumpState, MoveState::*, SitState, StateHandle, ClimbState, EcsStateData, GlideState, JumpState, MoveState::*, SitState, StateHandler,
StateUpdate, StateUpdate,
}; };
use crate::util::movement_utils::*; use crate::util::state_utils::*;
use vek::vec::{Vec2, Vec3}; 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; pub struct RunState;
impl StateHandle for RunState { impl StateHandler for RunState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate { fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
character: *ecs_data.character, character: *ecs_data.character,
@ -46,25 +46,25 @@ impl StateHandle for RunState {
// Try to sit // Try to sit
if can_sit(ecs_data.physics, ecs_data.inputs, ecs_data.body) { 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; return update;
} }
// Try to climb // Try to climb
if can_climb(ecs_data.physics, ecs_data.inputs, ecs_data.body) { 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; return update;
} }
// Try to jump // Try to jump
if can_jump(ecs_data.physics, ecs_data.inputs) { if can_jump(ecs_data.physics, ecs_data.inputs) {
update.character.move_state = Jump(JumpState); update.character.move_state = Jump(Some(JumpState));
return update; return update;
} }
// Try to glide // Try to glide
if can_glide(ecs_data.physics, ecs_data.inputs, ecs_data.body) { 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; return update;
} }

View File

@ -1,13 +1,13 @@
use crate::comp::{ use crate::comp::{
ActionState::*, EcsStateData, IdleState, JumpState, MoveState::*, RunState, StandState, 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; pub struct SitState;
impl StateHandle for SitState { impl StateHandler for SitState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate { fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
character: *ecs_data.character, character: *ecs_data.character,
@ -17,8 +17,8 @@ impl StateHandle for SitState {
}; };
// Prevent action state handling // Prevent action state handling
update.character.action_state = Idle(IdleState); update.character.action_state = Idle(Some(IdleState));
update.character.move_state = Sit(SitState); update.character.move_state = Sit(Some(SitState));
// Try to Fall // Try to Fall
// ... maybe the ground disappears, // ... maybe the ground disappears,
@ -30,19 +30,19 @@ impl StateHandle for SitState {
} }
// Try to jump // Try to jump
if ecs_data.inputs.jump.is_pressed() { if ecs_data.inputs.jump.is_pressed() {
update.character.move_state = Jump(JumpState); update.character.move_state = Jump(Some(JumpState));
return update; return update;
} }
// Try to Run // Try to Run
if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 { 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; return update;
} }
// Try to Stand // Try to Stand
if ecs_data.inputs.sit.is_just_pressed() { if ecs_data.inputs.sit.is_just_pressed() {
update.character.move_state = Stand(StandState); update.character.move_state = Stand(Some(StandState));
return update; return update;
} }

View File

@ -1,13 +1,13 @@
use crate::comp::{ use crate::comp::{
ClimbState, EcsStateData, GlideState, JumpState, MoveState::*, SitState, StateHandle, ClimbState, EcsStateData, GlideState, JumpState, MoveState::*, SitState, StateHandler,
StateUpdate, 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; pub struct StandState;
impl StateHandle for StandState { impl StateHandler for StandState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate { fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
character: *ecs_data.character, character: *ecs_data.character,
@ -18,25 +18,25 @@ impl StateHandle for StandState {
// Try to sit // Try to sit
if can_sit(ecs_data.physics, ecs_data.inputs, ecs_data.body) { 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; return update;
} }
// Try to climb // Try to climb
if can_climb(ecs_data.physics, ecs_data.inputs, ecs_data.body) { 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; return update;
} }
// Try to jump // Try to jump
if can_jump(ecs_data.physics, ecs_data.inputs) { if can_jump(ecs_data.physics, ecs_data.inputs) {
update.character.move_state = Jump(JumpState); update.character.move_state = Jump(Some(JumpState));
return update; return update;
} }
// Check gliding // Check gliding
if can_glide(ecs_data.physics, ecs_data.inputs, ecs_data.body) { 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; return update;
} }

View File

@ -1,12 +1,12 @@
use super::{HUMANOID_WATER_ACCEL, HUMANOID_WATER_SPEED}; 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 crate::sys::phys::GRAVITY;
use vek::{Vec2, Vec3}; 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; pub struct SwimState;
impl StateHandle for SwimState { impl StateHandler for SwimState {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate { fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate {
let mut update = StateUpdate { let mut update = StateUpdate {
character: *ecs_data.character, character: *ecs_data.character,
@ -51,16 +51,16 @@ impl StateHandle for SwimState {
// Not on ground // Not on ground
if !ecs_data.physics.on_ground { if !ecs_data.physics.on_ground {
update.character.move_state = Swim(SwimState); update.character.move_state = Swim(Some(SwimState));
return update; return update;
} }
// On ground // On ground
else { else {
// Return to running or standing based on move inputs // Return to running or standing based on move inputs
update.character.move_state = if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 { update.character.move_state = if ecs_data.inputs.move_dir.magnitude_squared() > 0.0 {
Run(RunState) Run(Some(RunState))
} else { } else {
Stand(StandState) Stand(Some(StandState))
}; };
return update; return update;

View File

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

View File

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

View File

@ -163,7 +163,7 @@ impl<'a> System<'a> for Sys {
inputs.roll.set_state(true); 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 && target_pos.0.z > pos.0.z + 5.0
{ {
inputs.glide.set_state(true); inputs.glide.set_state(true);

View File

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

View File

@ -7,7 +7,7 @@ lazy_static::lazy_static! {
use vek::{Mat3, Rgb, Rgba, Vec3}; 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. /// 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. /// 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?_ /// ... or Idle if nothing it possible?_
pub fn determine_primary_ability(stats: &Stats) -> ActionState { pub fn determine_primary_ability(stats: &Stats) -> ActionState {
if let Some(Tool(data)) = stats.equipment.main.as_ref().map(|i| &i.kind) { 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(), remaining_duration: data.attack_duration(),
})) })))
} else { } else {
Idle(IdleState) Idle(Some(IdleState))
} }
} }
@ -24,11 +24,11 @@ pub fn determine_primary_ability(stats: &Stats) -> ActionState {
/// ... or Idle if nothing it possible?_ /// ... or Idle if nothing it possible?_
pub fn determine_secondary_ability(stats: &Stats) -> ActionState { pub fn determine_secondary_ability(stats: &Stats) -> ActionState {
if let Some(Tool(data)) = stats.equipment.main.as_ref().map(|i| &i.kind) { 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(), active_duration: Duration::default(),
})) })))
} else { } 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 { pub fn determine_fall_or_swim(physics: &PhysicsState) -> MoveState {
// Check if in fluid to go to swimming or back to falling // Check if in fluid to go to swimming or back to falling
if physics.in_fluid { if physics.in_fluid {
Swim(SwimState) Swim(Some(SwimState))
} else { } else {
Fall(FallState) Fall(Some(FallState))
} }
} }
/// __Returns a `MoveState` based on `move_dir` magnitude__ /// __Returns a `MoveState` based on `move_dir` magnitude__
pub fn determine_stand_or_run(inputs: &ControllerInputs) -> MoveState { pub fn determine_stand_or_run(inputs: &ControllerInputs) -> MoveState {
// Return to running or standing based on move inputs // Return to running or standing based on move inputs
if inputs.move_dir.magnitude_squared() > 0.0 { if inputs.move_dir.magnitude_squared() > 0.0 {
Run(RunState) Run(Some(RunState))
} else { } 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.__ /// __Returns an ActionState based on whether character has a weapon equipped.__
pub fn attempt_wield(stats: &Stats) -> ActionState { pub fn attempt_wield(stats: &Stats) -> ActionState {
if let Some(Tool { .. }) = stats.equipment.main.as_ref().map(|i| &i.kind) { 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), equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY),
}) }))
} else { } else {
Idle(IdleState) Idle(Some(IdleState))
} }
} }