From 19c81f15286f7a82dfc4941ee8d3d77398d52748 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 11 Mar 2021 23:53:25 -0500 Subject: [PATCH] Support for canceling an input. Boost state hooked up to system. --- client/src/lib.rs | 2 +- common/src/comp/ability.rs | 2 ++ common/src/comp/character_state.rs | 2 ++ common/src/comp/controller.rs | 2 +- common/src/states/behavior.rs | 8 +++-- common/src/states/boost.rs | 29 ++++++++++++++++-- common/src/states/utils.rs | 45 ++++++++++++++++++++-------- common/sys/src/character_behavior.rs | 17 +++++++---- server/src/sys/agent.rs | 4 ++- 9 files changed, 87 insertions(+), 24 deletions(-) diff --git a/client/src/lib.rs b/client/src/lib.rs index c98ab89829..4580f0ef0e 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -998,7 +998,7 @@ impl Client { target: None, }); } else { - self.control_action(ControlAction::CancelInput); + self.control_action(ControlAction::CancelInput(input)); } } diff --git a/common/src/comp/ability.rs b/common/src/comp/ability.rs index 9194b552f5..a84efef9ce 100644 --- a/common/src/comp/ability.rs +++ b/common/src/comp/ability.rs @@ -1156,8 +1156,10 @@ impl From<(&CharacterAbility, AbilityInfo)> for CharacterState { static_data: boost::StaticData { movement_duration: Duration::from_secs_f32(*movement_duration), only_up: *only_up, + ability_info, }, timer: Duration::default(), + end: false, }), CharacterAbility::DashMelee { energy_cost: _, diff --git a/common/src/comp/character_state.rs b/common/src/comp/character_state.rs index 33eb2752d6..25d16beeb9 100644 --- a/common/src/comp/character_state.rs +++ b/common/src/comp/character_state.rs @@ -18,6 +18,7 @@ pub struct StateUpdate { pub energy: Energy, pub swap_equipped_weapons: bool, pub queued_inputs: BTreeSet, + pub removed_inputs: Vec, pub local_events: VecDeque, pub server_events: VecDeque, } @@ -32,6 +33,7 @@ impl From<&JoinData<'_>> for StateUpdate { swap_equipped_weapons: false, character: data.character.clone(), queued_inputs: BTreeSet::new(), + removed_inputs: Vec::new(), local_events: VecDeque::new(), server_events: VecDeque::new(), } diff --git a/common/src/comp/controller.rs b/common/src/comp/controller.rs index bdd32b95ef..70d00e28aa 100644 --- a/common/src/comp/controller.rs +++ b/common/src/comp/controller.rs @@ -115,7 +115,7 @@ pub enum ControlAction { ability: InputKind, target: Option, }, - CancelInput, + CancelInput(InputKind), } #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, Eq, Ord, PartialOrd)] diff --git a/common/src/states/behavior.rs b/common/src/states/behavior.rs index 9cb467c79f..391aaf09c1 100644 --- a/common/src/states/behavior.rs +++ b/common/src/states/behavior.rs @@ -34,7 +34,11 @@ pub trait CharacterBehavior { update.queued_inputs.insert(input); update } - fn cancel_input(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) } + fn cancel_input(&self, data: &JoinData, input: InputKind) -> StateUpdate { + let mut update = StateUpdate::from(data); + update.removed_inputs.push(input); + update + } fn handle_event(&self, data: &JoinData, event: ControlAction) -> StateUpdate { match event { ControlAction::SwapEquippedWeapons => self.swap_equipped_weapons(data), @@ -50,7 +54,7 @@ pub trait CharacterBehavior { ControlAction::StartInput { ability, target } => { self.handle_input(data, ability, target) }, - ControlAction::CancelInput => self.cancel_input(data), + ControlAction::CancelInput(input) => self.cancel_input(data, input), } } // fn init(data: &JoinData) -> CharacterState; diff --git a/common/src/states/boost.rs b/common/src/states/boost.rs index 562e120913..a18b520700 100644 --- a/common/src/states/boost.rs +++ b/common/src/states/boost.rs @@ -1,5 +1,5 @@ use crate::{ - comp::{CharacterState, StateUpdate}, + comp::{CharacterState, InputKind, StateUpdate}, states::{ behavior::{CharacterBehavior, JoinData}, utils::*, @@ -13,6 +13,7 @@ use std::time::Duration; pub struct StaticData { pub movement_duration: Duration, pub only_up: bool, + pub ability_info: AbilityInfo, } #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -22,6 +23,8 @@ pub struct Data { pub static_data: StaticData, /// Timer for each stage pub timer: Duration, + /// Whether or not the state should end + pub end: bool, } impl CharacterBehavior for Data { @@ -46,9 +49,31 @@ impl CharacterBehavior for Data { }); } else { // Done - update.character = CharacterState::Wielding; + if self.end || self.static_data.ability_info.input.is_none() { + update.character = CharacterState::Wielding; + } else { + reset_state(self, &mut update); + } + } + + update + } + + fn cancel_input(&self, data: &JoinData, input: InputKind) -> StateUpdate { + let mut update = StateUpdate::from(data); + update.removed_inputs.push(input); + + if Some(input) == self.static_data.ability_info.input { + update.character = CharacterState::Boost(Data { end: true, ..*self }); } update } } + +fn reset_state(data: &Data, update: &mut StateUpdate) { + update.character = CharacterState::Boost(Data { + timer: Duration::default(), + ..*data + }) +} diff --git a/common/src/states/utils.rs b/common/src/states/utils.rs index eac9496cd5..b39c32f60a 100644 --- a/common/src/states/utils.rs +++ b/common/src/states/utils.rs @@ -434,7 +434,12 @@ pub fn handle_jump(data: &JoinData, update: &mut StateUpdate) { } } -fn handle_ability_pressed(data: &JoinData, update: &mut StateUpdate, ability_key: AbilityKey) { +fn handle_ability_pressed( + data: &JoinData, + update: &mut StateUpdate, + ability_key: AbilityKey, + input: Option, +) { let hands = |equip_slot| match data.inventory.equipped(equip_slot).map(|i| i.kind()) { Some(ItemKind::Tool(tool)) => Some(tool.hands), _ => None, @@ -484,7 +489,12 @@ fn handle_ability_pressed(data: &JoinData, update: &mut StateUpdate, ability_key { update.character = ( &ability, - AbilityInfo::from_key(data, ability_key, matches!(equip_slot, EquipSlot::Offhand)), + AbilityInfo::from_key( + data, + ability_key, + matches!(equip_slot, EquipSlot::Offhand), + input, + ), ) .into(); } @@ -493,7 +503,7 @@ fn handle_ability_pressed(data: &JoinData, update: &mut StateUpdate, ability_key pub fn handle_input(data: &JoinData, update: &mut StateUpdate, input: InputKind) { match input { - InputKind::Primary => handle_ability_pressed(data, update, AbilityKey::Mouse1), + InputKind::Primary => handle_ability_pressed(data, update, AbilityKey::Mouse1, Some(input)), } } @@ -505,19 +515,19 @@ pub fn handle_input(data: &JoinData, update: &mut StateUpdate, input: InputKind) pub fn handle_ability2_input(data: &JoinData, update: &mut StateUpdate) { if data.inputs.secondary.is_pressed() { - handle_ability_pressed(data, update, AbilityKey::Mouse2); + handle_ability_pressed(data, update, AbilityKey::Mouse2, None); } } pub fn handle_ability3_input(data: &JoinData, update: &mut StateUpdate) { if data.inputs.ability3.is_pressed() { - handle_ability_pressed(data, update, AbilityKey::Skill1); + handle_ability_pressed(data, update, AbilityKey::Skill1, None); } } pub fn handle_ability4_input(data: &JoinData, update: &mut StateUpdate) { if data.inputs.ability4.is_pressed() { - handle_ability_pressed(data, update, AbilityKey::Skill2); + handle_ability_pressed(data, update, AbilityKey::Skill2, None); } } @@ -539,7 +549,7 @@ pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) { if let CharacterState::ComboMelee(c) = data.character { update.character = ( &ability, - AbilityInfo::from_key(data, AbilityKey::Dodge, false), + AbilityInfo::from_key(data, AbilityKey::Dodge, false, None), ) .into(); if let CharacterState::Roll(roll) = &mut update.character { @@ -549,7 +559,7 @@ pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) { } else if data.character.is_wield() { update.character = ( &ability, - AbilityInfo::from_key(data, AbilityKey::Dodge, false), + AbilityInfo::from_key(data, AbilityKey::Dodge, false, None), ) .into(); if let CharacterState::Roll(roll) = &mut update.character { @@ -558,7 +568,7 @@ pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) { } else if data.character.is_stealthy() { update.character = ( &ability, - AbilityInfo::from_key(data, AbilityKey::Dodge, false), + AbilityInfo::from_key(data, AbilityKey::Dodge, false, None), ) .into(); if let CharacterState::Roll(roll) = &mut update.character { @@ -567,7 +577,7 @@ pub fn handle_dodge_input(data: &JoinData, update: &mut StateUpdate) { } else { update.character = ( &ability, - AbilityInfo::from_key(data, AbilityKey::Dodge, false), + AbilityInfo::from_key(data, AbilityKey::Dodge, false, None), ) .into(); } @@ -687,10 +697,16 @@ pub struct AbilityInfo { pub tool: Option, pub hand: Option, pub key: AbilityKey, + pub input: Option, } impl AbilityInfo { - pub fn from_key(data: &JoinData, key: AbilityKey, from_offhand: bool) -> Self { + pub fn from_key( + data: &JoinData, + key: AbilityKey, + from_offhand: bool, + input: Option, + ) -> Self { let tool_data = if from_offhand { unwrap_tool_data(data, EquipSlot::Offhand) } else { @@ -705,7 +721,12 @@ impl AbilityInfo { ) }; - Self { tool, hand, key } + Self { + tool, + hand, + key, + input, + } } } diff --git a/common/sys/src/character_behavior.rs b/common/sys/src/character_behavior.rs index 1c438729e0..61e0445c51 100644 --- a/common/sys/src/character_behavior.rs +++ b/common/sys/src/character_behavior.rs @@ -23,7 +23,7 @@ use common::{ use common_ecs::{Job, Origin, Phase, System}; use std::time::Duration; -fn incorporate_update(join: &mut JoinStruct, state_update: StateUpdate) { +fn incorporate_update(join: &mut JoinStruct, mut state_update: StateUpdate) { // TODO: if checking equality is expensive use optional field in StateUpdate if join.char_state.get_unchecked() != &state_update.character { *join.char_state.get_mut_unchecked() = state_update.character @@ -35,6 +35,12 @@ fn incorporate_update(join: &mut JoinStruct, state_update: StateUpdate) { if join.energy.get_unchecked() != &state_update.energy { *join.energy.get_mut_unchecked() = state_update.energy }; + join.controller + .queued_inputs + .append(&mut state_update.queued_inputs); + for input in state_update.removed_inputs { + join.controller.queued_inputs.remove(&input); + } if state_update.swap_equipped_weapons { let mut inventory = join.inventory.get_mut_unchecked(); let inventory = &mut *inventory; @@ -350,10 +356,11 @@ impl<'a> System<'a> for Sys { local_emitter.append(&mut state_update.local_events); server_emitter.append(&mut state_update.server_events); - join_struct - .controller - .queued_inputs - .append(&mut state_update.queued_inputs); + // join_struct + // .controller + // .queued_inputs + // .append(&mut state_update.queued_inputs); + // join_struct.controller.queued_inputs. incorporate_update(&mut join_struct, state_update); } } diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index 4d48e29051..0d2ffc1920 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -1638,7 +1638,9 @@ impl<'a> AgentData<'a> { Tactic::TailSlap => { if dist_sqrd < (1.5 * min_attack_dist * self.scale).powi(2) { if agent.action_timer > 4.0 { - controller.actions.push(ControlAction::CancelInput); + controller + .actions + .push(ControlAction::CancelInput(InputKind::Primary)); //controller.inputs.primary.set_state(false); agent.action_timer = 0.0; } else if agent.action_timer > 1.0 {