Add new() to states

This commit is contained in:
Adam Whitehurst 2020-01-05 15:17:22 -08:00
parent 4e5cf63452
commit 542f06eef4
16 changed files with 191 additions and 29 deletions

View File

@ -28,6 +28,12 @@ pub enum ToolKind {
Debug(Debug), Debug(Debug),
} }
impl Default for ToolKind {
fn default() -> Self {
Self::Axe
}
}
impl ToolData { impl ToolData {
pub fn equip_time(&self) -> Duration { pub fn equip_time(&self) -> Duration {
Duration::from_millis(self.equip_time_millis) Duration::from_millis(self.equip_time_millis)
@ -83,7 +89,7 @@ pub enum Ingredient {
Grass, Grass,
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ToolData { pub struct ToolData {
pub kind: ToolKind, pub kind: ToolKind,
equip_time_millis: u64, equip_time_millis: u64,

View File

@ -1,6 +1,6 @@
use crate::comp::{ use crate::comp::{
ActionState::Attack, AttackKind::BasicAttack, EcsStateData, MoveState, StateHandler, ActionState::Attack, AttackKind::BasicAttack, EcsStateData, ItemKind::Tool, MoveState,
StateUpdate, ToolData, StateHandler, StateUpdate, ToolData,
}; };
use crate::util::state_utils::*; use crate::util::state_utils::*;
use std::time::Duration; use std::time::Duration;
@ -12,6 +12,18 @@ pub struct BasicAttackState {
} }
impl StateHandler for BasicAttackState { impl StateHandler for BasicAttackState {
fn new(ecs_data: &EcsStateData) -> Self {
let tool_data =
if let Some(Tool(data)) = ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind) {
data
} else {
&ToolData::default()
};
Self {
remaining_duration: tool_data.attack_duration(),
}
}
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

@ -11,6 +11,12 @@ pub struct BasicBlockState {
} }
impl StateHandler for BasicBlockState { impl StateHandler for BasicBlockState {
fn new(ecs_data: &EcsStateData) -> Self {
Self {
active_duration: Duration::default(),
}
}
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,6 +1,6 @@
use crate::comp::{ use crate::comp::{
ActionState::Attack, AttackKind::Charge, EcsStateData, HealthChange, HealthSource, ActionState::Attack, AttackKind::Charge, EcsStateData, HealthChange, HealthSource,
MoveState::Run, RunState, StateHandler, StateUpdate, ItemKind::Tool, MoveState::Run, RunState, StateHandler, StateUpdate, ToolData,
}; };
use crate::event::ServerEvent; use crate::event::ServerEvent;
use crate::util::state_utils::*; use crate::util::state_utils::*;
@ -16,6 +16,18 @@ pub struct ChargeAttackState {
} }
impl StateHandler for ChargeAttackState { impl StateHandler for ChargeAttackState {
fn new(ecs_data: &EcsStateData) -> Self {
let tool_data =
if let Some(Tool(data)) = ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind) {
data
} else {
&ToolData::default()
};
Self {
remaining_duration: tool_data.attack_duration(),
}
}
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

@ -11,6 +11,10 @@ use vek::Lerp;
pub struct ClimbState; pub struct ClimbState;
impl StateHandler for ClimbState { impl StateHandler for ClimbState {
fn new(ecs_data: &EcsStateData) -> Self {
Self {}
}
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

@ -8,6 +8,10 @@ use vek::{Vec2, Vec3};
pub struct FallState; pub struct FallState;
impl StateHandler for FallState { impl StateHandler for FallState {
fn new(ecs_data: &EcsStateData) -> Self {
Self {}
}
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

@ -9,6 +9,10 @@ use vek::{Vec2, Vec3};
pub struct GlideState; pub struct GlideState;
impl StateHandler for GlideState { impl StateHandler for GlideState {
fn new(ecs_data: &EcsStateData) -> Self {
Self {}
}
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

@ -8,6 +8,10 @@ use std::time::Duration;
pub struct IdleState; pub struct IdleState;
impl StateHandler for IdleState { impl StateHandler for IdleState {
fn new(ecs_data: &EcsStateData) -> Self {
Self {}
}
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,
@ -22,10 +26,10 @@ impl StateHandler for IdleState {
|| (ecs_data.inputs.toggle_wield.is_just_pressed() || (ecs_data.inputs.toggle_wield.is_just_pressed()
&& 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(data)) = ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind) {
update.character.action_state = Wield(Some(WieldState { update.character.action_state = Wield(Some(WieldState {
equip_delay: Duration::from_millis(TEMP_EQUIP_DELAY), equip_delay: data.equip_time(),
})) }));
} }
// else unarmed stuff? // else unarmed stuff?

View File

@ -5,6 +5,10 @@ use crate::event::LocalEvent;
pub struct JumpState; pub struct JumpState;
impl StateHandler for JumpState { impl StateHandler for JumpState {
fn new(ecs_data: &EcsStateData) -> Self {
Self {}
}
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,

View File

@ -54,7 +54,6 @@ 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,
@ -74,25 +73,54 @@ use std::time::Duration;
/// 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 StateHandler: Default { pub trait StateHandler: Default {
fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate; fn handle(&self, ecs_data: &EcsStateData) -> StateUpdate;
fn new(ecs_data: &EcsStateData) -> Self;
} }
// Public interface that passes EcsStateData to `StateHandle`s `handle()` fn // fn's relating to individual `ActionState`s
// or passing data from system to handlers
impl ActionState { impl ActionState {
/// Passes handle to variant or subvariant handlers /// Passes data to variant or subvariant handlers
/// States contain `Option<StateHandler Implementor>`s, and will be
/// `None` if state data has not been initialized. So we have to
/// check and intialize new state data if so.
pub fn update(&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(Some(state)) => state.handle(&ecs_data), BasicAttack(opt_state) => opt_state
Charge(Some(state)) => state.handle(&ecs_data), // If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| BasicAttackState::new(ecs_data))
// Call handler
.handle(ecs_data),
Charge(opt_state) => opt_state
// If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| ChargeAttackState::new(ecs_data))
// Call handler
.handle(ecs_data),
}, },
Block(kind) => match kind { Block(kind) => match kind {
BasicBlock(Some(state)) => state.handle(&ecs_data), BasicBlock(opt_state) => opt_state
// If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| BasicBlockState::new(ecs_data))
// Call handler
.handle(ecs_data),
}, },
Dodge(kind) => match kind { Dodge(kind) => match kind {
Roll(Some(state)) => state.handle(&ecs_data), Roll(opt_state) => opt_state
// If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| RollState::new(ecs_data))
// Call handler
.handle(ecs_data),
}, },
Wield(Some(state)) => state.handle(&ecs_data), Wield(opt_state) => opt_state
Idle(Some(state)) => state.handle(&ecs_data), // If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| WieldState::new(ecs_data))
// Call handler
.handle(ecs_data),
Idle(opt_state) => opt_state
// If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| IdleState::new(ecs_data))
// Call handler
.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: _ => {},
@ -121,9 +149,13 @@ impl ActionState {
} }
} }
// Other fn's that relate to individual `MoveState`s // fn's that relate to individual `MoveState`s
// or passing data from system to handlers
impl MoveState { impl MoveState {
/// Returns whether a given `ActionState` overrides `MoveState` `handle()`ing /// Passes data to variant or subvariant handlers
/// States contain `Option<StateHandler Implementor>`s, and will be
/// `None` if state data has not been initialized. So we have to
/// check and intialize new state data if so.
pub fn overrides_action_state(&self) -> bool { pub fn overrides_action_state(&self) -> bool {
match self { match self {
Stand(_) => false, Stand(_) => false,
@ -143,14 +175,46 @@ impl MoveState {
/// Passes handle to variant handlers /// Passes handle to variant handlers
pub fn update(&self, ecs_data: &EcsStateData) -> StateUpdate { pub fn update(&self, ecs_data: &EcsStateData) -> StateUpdate {
match self { match self {
Stand(Some(state)) => state.handle(&ecs_data), Stand(opt_state) => opt_state
Run(Some(state)) => state.handle(&ecs_data), // If data hasn't been initialized, initialize a new one
Jump(Some(state)) => state.handle(&ecs_data), .unwrap_or_else(|| StandState::new(ecs_data))
Climb(Some(state)) => state.handle(&ecs_data), // Call handler
Glide(Some(state)) => state.handle(&ecs_data), .handle(ecs_data),
Swim(Some(state)) => state.handle(&ecs_data), Run(opt_state) => opt_state
Fall(Some(state)) => state.handle(&ecs_data), // If data hasn't been initialized, initialize a new one
Sit(Some(state)) => state.handle(&ecs_data), .unwrap_or_else(|| RunState::new(ecs_data))
// Call handler
.handle(ecs_data),
Jump(opt_state) => opt_state
// If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| JumpState::new(ecs_data))
// Call handler
.handle(ecs_data),
Climb(opt_state) => opt_state
// If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| ClimbState::new(ecs_data))
// Call handler
.handle(ecs_data),
Glide(opt_state) => opt_state
// If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| GlideState::new(ecs_data))
// Call handler
.handle(ecs_data),
Swim(opt_state) => opt_state
// If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| SwimState::new(ecs_data))
// Call handler
.handle(ecs_data),
Fall(opt_state) => opt_state
// If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| FallState::new(ecs_data))
// Call handler
.handle(ecs_data),
Sit(opt_state) => opt_state
// If data hasn't been initialized, initialize a new one
.unwrap_or_else(|| SitState::new(ecs_data))
// Call handler
.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,5 +1,7 @@
use super::ROLL_SPEED; use super::ROLL_SPEED;
use crate::comp::{ActionState::*, DodgeKind::*, EcsStateData, StateHandler, StateUpdate}; use crate::comp::{
ActionState::*, DodgeKind::*, EcsStateData, ItemKind::Tool, StateHandler, StateUpdate, ToolData,
};
use crate::util::state_utils::*; use crate::util::state_utils::*;
use std::time::Duration; use std::time::Duration;
use vek::Vec3; use vek::Vec3;
@ -11,6 +13,18 @@ pub struct RollState {
} }
impl StateHandler for RollState { impl StateHandler for RollState {
fn new(ecs_data: &EcsStateData) -> Self {
let tool_data =
if let Some(Tool(data)) = ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind) {
data
} else {
&ToolData::default()
};
Self {
remaining_duration: tool_data.attack_duration(),
}
}
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,

View File

@ -10,6 +10,10 @@ use vek::vec::{Vec2, Vec3};
pub struct RunState; pub struct RunState;
impl StateHandler for RunState { impl StateHandler for RunState {
fn new(ecs_data: &EcsStateData) -> Self {
Self {}
}
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,

View File

@ -8,6 +8,10 @@ use crate::util::state_utils::*;
pub struct SitState; pub struct SitState;
impl StateHandler for SitState { impl StateHandler for SitState {
fn new(ecs_data: &EcsStateData) -> Self {
Self {}
}
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,

View File

@ -8,6 +8,10 @@ use crate::util::state_utils::*;
pub struct StandState; pub struct StandState;
impl StateHandler for StandState { impl StateHandler for StandState {
fn new(ecs_data: &EcsStateData) -> Self {
Self {}
}
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,

View File

@ -7,6 +7,10 @@ use vek::{Vec2, Vec3};
pub struct SwimState; pub struct SwimState;
impl StateHandler for SwimState { impl StateHandler for SwimState {
fn new(ecs_data: &EcsStateData) -> Self {
Self {}
}
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,

View File

@ -1,6 +1,6 @@
use crate::comp::{ use crate::comp::{
AbilityAction, AbilityActionKind::*, ActionState::*, EcsStateData, IdleState, StateHandler, AbilityAction, AbilityActionKind::*, ActionState::*, EcsStateData, IdleState, ItemKind::Tool,
StateUpdate, StateHandler, StateUpdate, ToolData,
}; };
use crate::util::state_utils::*; use crate::util::state_utils::*;
use std::time::Duration; use std::time::Duration;
@ -13,6 +13,18 @@ pub struct WieldState {
} }
impl StateHandler for WieldState { impl StateHandler for WieldState {
fn new(ecs_data: &EcsStateData) -> Self {
let tool_data =
if let Some(Tool(data)) = ecs_data.stats.equipment.main.as_ref().map(|i| &i.kind) {
data
} else {
&ToolData::default()
};
Self {
equip_delay: tool_data.equip_time(),
}
}
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,