veloren/common/src/sys/character_behavior.rs

290 lines
11 KiB
Rust
Raw Normal View History

2019-12-20 13:30:37 +00:00
use crate::{
comp::{
Attacking, Body, CharacterState, ControlAction, Controller, ControllerInputs, Energy,
Loadout, Mounting, Ori, PhysicsState, Pos, StateUpdate, Stats, Vel,
2019-12-20 13:30:37 +00:00
},
2019-12-26 14:43:59 +00:00
event::{EventBus, LocalEvent, ServerEvent},
2019-12-20 13:30:37 +00:00
state::DeltaTime,
2020-03-07 18:15:02 +00:00
states,
2020-01-16 13:28:45 +00:00
sync::{Uid, UidAllocator},
2019-12-20 13:30:37 +00:00
};
use specs::{
hibitset,
storage::{PairedStorage, SequentialRestriction},
Entities, Entity, FlaggedStorage, Join, LazyUpdate, Read, ReadStorage, System, WriteStorage,
};
use specs_idvs::IdvStorage;
2020-03-07 21:03:10 +00:00
// use std::collections::VecDeque;
2020-03-07 18:15:02 +00:00
pub trait CharacterBehavior {
fn behavior(&self, data: &JoinData) -> StateUpdate;
2020-03-24 07:38:16 +00:00
// Impl these to provide behavior for these inputs
fn swap_loadout(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
2020-03-26 15:05:17 +00:00
fn wield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn glide_wield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
2020-03-26 15:05:17 +00:00
fn unwield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn sit(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
2020-05-27 06:41:55 +00:00
fn dance(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
2020-08-02 05:09:11 +00:00
fn sneak(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
2020-03-26 15:05:17 +00:00
fn stand(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
2020-03-24 07:38:16 +00:00
fn handle_event(&self, data: &JoinData, event: ControlAction) -> StateUpdate {
match event {
ControlAction::SwapLoadout => self.swap_loadout(data),
2020-03-26 15:05:17 +00:00
ControlAction::Wield => self.wield(data),
ControlAction::GlideWield => self.glide_wield(data),
2020-03-26 15:05:17 +00:00
ControlAction::Unwield => self.unwield(data),
ControlAction::Sit => self.sit(data),
2020-05-27 06:41:55 +00:00
ControlAction::Dance => self.dance(data),
2020-08-02 05:09:11 +00:00
ControlAction::Sneak => self.sneak(data),
2020-03-26 15:05:17 +00:00
ControlAction::Stand => self.stand(data),
2020-03-24 07:38:16 +00:00
}
}
// fn init(data: &JoinData) -> CharacterState;
}
/// Read-Only Data sent from Character Behavior System to behavior fn's
2020-03-07 18:15:02 +00:00
pub struct JoinData<'a> {
pub entity: Entity,
pub uid: &'a Uid,
pub character: &'a CharacterState,
pub pos: &'a Pos,
pub vel: &'a Vel,
pub ori: &'a Ori,
pub dt: &'a DeltaTime,
pub controller: &'a Controller,
pub inputs: &'a ControllerInputs,
pub stats: &'a Stats,
pub energy: &'a Energy,
pub loadout: &'a Loadout,
2020-03-07 18:15:02 +00:00
pub body: &'a Body,
pub physics: &'a PhysicsState,
pub attacking: Option<&'a Attacking>,
2020-03-07 18:15:02 +00:00
pub updater: &'a LazyUpdate,
}
type RestrictedMut<'a, C> = PairedStorage<
'a,
'a,
C,
&'a mut FlaggedStorage<C, IdvStorage<C>>,
&'a hibitset::BitSet,
SequentialRestriction,
>;
2020-03-07 18:15:02 +00:00
pub type JoinTuple<'a> = (
Entity,
&'a Uid,
RestrictedMut<'a, CharacterState>,
2020-03-07 18:15:02 +00:00
&'a mut Pos,
&'a mut Vel,
&'a mut Ori,
RestrictedMut<'a, Energy>,
RestrictedMut<'a, Loadout>,
2020-03-24 07:38:16 +00:00
&'a mut Controller,
2020-03-07 18:15:02 +00:00
&'a Stats,
&'a Body,
&'a PhysicsState,
Option<&'a Attacking>,
2020-03-07 18:15:02 +00:00
);
2020-03-24 07:38:16 +00:00
fn incorporate_update(tuple: &mut JoinTuple, state_update: StateUpdate) {
// TODO: if checking equality is expensive use optional field in StateUpdate
if tuple.2.get_unchecked() != &state_update.character {
*tuple.2.get_mut_unchecked() = state_update.character
};
2020-03-24 07:38:16 +00:00
*tuple.3 = state_update.pos;
*tuple.4 = state_update.vel;
*tuple.5 = state_update.ori;
// Note: might be changed every tick by timer anyway
if tuple.6.get_unchecked() != &state_update.energy {
*tuple.6.get_mut_unchecked() = state_update.energy
};
if state_update.swap_loadout {
let loadout = tuple.7.get_mut_unchecked();
std::mem::swap(&mut loadout.active_item, &mut loadout.second_item);
}
2020-03-24 07:38:16 +00:00
}
2020-03-07 18:15:02 +00:00
impl<'a> JoinData<'a> {
fn new(j: &'a JoinTuple<'a>, updater: &'a LazyUpdate, dt: &'a DeltaTime) -> Self {
Self {
entity: j.0,
uid: j.1,
character: j.2.get_unchecked(),
2020-03-07 18:15:02 +00:00
pos: j.3,
vel: j.4,
ori: j.5,
energy: j.6.get_unchecked(),
loadout: j.7.get_unchecked(),
controller: j.8,
inputs: &j.8.inputs,
stats: j.9,
body: j.10,
physics: j.11,
attacking: j.12,
2020-03-07 18:15:02 +00:00
updater,
dt,
}
}
}
2020-03-21 22:55:20 +00:00
/// ## Character Behavior System
2020-08-25 12:21:25 +00:00
/// Passes `JoinData` to `CharacterState`'s `behavior` handler fn's. Receives a
2020-03-21 22:55:20 +00:00
/// `StateUpdate` in return and performs updates to ECS Components from that.
2019-12-20 13:30:37 +00:00
pub struct Sys;
impl<'a> System<'a> for Sys {
#[allow(clippy::type_complexity)]
2019-12-20 13:30:37 +00:00
type SystemData = (
Entities<'a>,
Read<'a, UidAllocator>,
Read<'a, EventBus<ServerEvent>>,
Read<'a, EventBus<LocalEvent>>,
Read<'a, DeltaTime>,
2019-12-26 14:43:59 +00:00
Read<'a, LazyUpdate>,
2019-12-20 13:30:37 +00:00
WriteStorage<'a, CharacterState>,
2019-12-21 15:57:15 +00:00
WriteStorage<'a, Pos>,
WriteStorage<'a, Vel>,
WriteStorage<'a, Ori>,
2020-02-24 18:17:16 +00:00
WriteStorage<'a, Energy>,
WriteStorage<'a, Loadout>,
2020-03-24 07:38:16 +00:00
WriteStorage<'a, Controller>,
2019-12-20 13:30:37 +00:00
ReadStorage<'a, Stats>,
ReadStorage<'a, Body>,
ReadStorage<'a, PhysicsState>,
ReadStorage<'a, Attacking>,
2019-12-20 13:30:37 +00:00
ReadStorage<'a, Uid>,
ReadStorage<'a, Mounting>,
);
2020-02-24 18:17:16 +00:00
#[allow(clippy::while_let_on_iterator)] // TODO: Pending review in #587
2019-12-20 13:30:37 +00:00
fn run(
&mut self,
(
entities,
2019-12-26 18:01:19 +00:00
_uid_allocator,
2019-12-20 13:30:37 +00:00
server_bus,
local_bus,
dt,
2019-12-26 14:43:59 +00:00
updater,
2019-12-20 13:30:37 +00:00
mut character_states,
2019-12-21 15:57:15 +00:00
mut positions,
mut velocities,
mut orientations,
2020-02-24 18:17:16 +00:00
mut energies,
mut loadouts,
2020-03-24 07:38:16 +00:00
mut controllers,
2019-12-20 13:30:37 +00:00
stats,
bodies,
physics_states,
attacking_storage,
2019-12-20 13:30:37 +00:00
uids,
mountings,
): Self::SystemData,
) {
2020-03-22 04:49:32 +00:00
let mut server_emitter = server_bus.emitter();
let mut local_emitter = local_bus.emitter();
for mut tuple in (
2019-12-20 13:30:37 +00:00
&entities,
&uids,
&mut character_states.restrict_mut(),
2019-12-21 15:57:15 +00:00
&mut positions,
&mut velocities,
&mut orientations,
&mut energies.restrict_mut(),
&mut loadouts.restrict_mut(),
2020-03-24 07:38:16 +00:00
&mut controllers,
2019-12-20 13:30:37 +00:00
&stats,
&bodies,
&physics_states,
attacking_storage.maybe(),
2019-12-20 13:30:37 +00:00
)
.join()
{
2019-12-29 23:47:42 +00:00
// Being dead overrides all other states
2020-03-24 07:38:16 +00:00
if tuple.9.is_dead {
// Do nothing
continue;
2019-12-29 23:47:42 +00:00
}
// If mounted, character state is controlled by mount
// TODO: Make mounting a state
2020-03-24 07:38:16 +00:00
if let Some(Mounting(_)) = mountings.get(tuple.0) {
let sit_state = CharacterState::Sit {};
if tuple.2.get_unchecked() != &sit_state {
*tuple.2.get_mut_unchecked() = sit_state;
}
2020-03-24 07:38:16 +00:00
continue;
}
let actions = std::mem::replace(&mut tuple.8.actions, Vec::new());
for action in actions {
let j = JoinData::new(&tuple, &updater, &dt);
let mut state_update = match j.character {
CharacterState::Idle => states::idle::Data.handle_event(&j, action),
CharacterState::Climb => states::climb::Data.handle_event(&j, action),
CharacterState::Glide => states::glide::Data.handle_event(&j, action),
CharacterState::GlideWield => {
states::glide_wield::Data.handle_event(&j, action)
},
2020-03-24 07:38:16 +00:00
CharacterState::Sit => {
states::sit::Data::handle_event(&states::sit::Data, &j, action)
},
2020-05-27 06:41:55 +00:00
CharacterState::Dance => {
states::dance::Data::handle_event(&states::dance::Data, &j, action)
},
2020-08-02 05:09:11 +00:00
CharacterState::Sneak => {
states::sneak::Data::handle_event(&states::sneak::Data, &j, action)
},
2020-03-24 07:38:16 +00:00
CharacterState::BasicBlock => {
states::basic_block::Data.handle_event(&j, action)
},
CharacterState::Roll(data) => data.handle_event(&j, action),
CharacterState::Wielding => states::wielding::Data.handle_event(&j, action),
CharacterState::Equipping(data) => data.handle_event(&j, action),
CharacterState::TripleStrike(data) => data.handle_event(&j, action),
CharacterState::BasicMelee(data) => data.handle_event(&j, action),
CharacterState::BasicRanged(data) => data.handle_event(&j, action),
CharacterState::Boost(data) => data.handle_event(&j, action),
CharacterState::DashMelee(data) => data.handle_event(&j, action),
CharacterState::LeapMelee(data) => data.handle_event(&j, action),
2020-07-08 19:58:41 +00:00
CharacterState::SpinMelee(data) => data.handle_event(&j, action),
2020-07-26 03:06:53 +00:00
CharacterState::ChargedRanged(data) => data.handle_event(&j, action),
2020-03-24 07:38:16 +00:00
};
local_emitter.append(&mut state_update.local_events);
server_emitter.append(&mut state_update.server_events);
incorporate_update(&mut tuple, state_update);
2019-12-29 23:47:42 +00:00
}
2020-03-24 07:38:16 +00:00
let j = JoinData::new(&tuple, &updater, &dt);
2020-03-07 18:15:02 +00:00
let mut state_update = match j.character {
CharacterState::Idle => states::idle::Data.behavior(&j),
CharacterState::Climb => states::climb::Data.behavior(&j),
CharacterState::Glide => states::glide::Data.behavior(&j),
CharacterState::GlideWield => states::glide_wield::Data.behavior(&j),
2020-03-14 21:17:27 +00:00
CharacterState::Sit => states::sit::Data::behavior(&states::sit::Data, &j),
2020-05-27 06:41:55 +00:00
CharacterState::Dance => states::dance::Data::behavior(&states::dance::Data, &j),
2020-08-02 05:09:11 +00:00
CharacterState::Sneak => states::sneak::Data::behavior(&states::sneak::Data, &j),
2020-03-21 22:55:20 +00:00
CharacterState::BasicBlock => states::basic_block::Data.behavior(&j),
CharacterState::Roll(data) => data.behavior(&j),
CharacterState::Wielding => states::wielding::Data.behavior(&j),
CharacterState::Equipping(data) => data.behavior(&j),
CharacterState::TripleStrike(data) => data.behavior(&j),
CharacterState::BasicMelee(data) => data.behavior(&j),
CharacterState::BasicRanged(data) => data.behavior(&j),
CharacterState::Boost(data) => data.behavior(&j),
2020-03-16 15:34:53 +00:00
CharacterState::DashMelee(data) => data.behavior(&j),
CharacterState::LeapMelee(data) => data.behavior(&j),
2020-07-08 19:58:41 +00:00
CharacterState::SpinMelee(data) => data.behavior(&j),
2020-07-26 03:06:53 +00:00
CharacterState::ChargedRanged(data) => data.behavior(&j),
2020-03-07 18:15:02 +00:00
};
2019-12-26 14:43:59 +00:00
2020-03-22 04:49:32 +00:00
local_emitter.append(&mut state_update.local_events);
server_emitter.append(&mut state_update.server_events);
2020-03-24 07:38:16 +00:00
incorporate_update(&mut tuple, state_update);
2019-12-29 23:47:42 +00:00
}
}
}