Merge branch 'imbris/opt-character-behavior' into 'master'

Optimize parts of the character behavior system

See merge request veloren/veloren!2924
This commit is contained in:
Joshua Yanovski 2021-10-15 15:55:04 +00:00
commit a8fada63bc
42 changed files with 652 additions and 363 deletions

View File

@ -10,6 +10,7 @@ csv-import = "run --manifest-path common/Cargo.toml --features=bin_csv --bin csv
test-server = "run --bin veloren-server-cli --no-default-features"
tracy-server = "-Zunstable-options run --bin veloren-server-cli --no-default-features --features tracy,simd --profile no_overflow"
tracy-world-server = "-Zunstable-options run --bin veloren-server-cli --features tracy,simd --profile no_overflow"
tracy-world-server-releasedebuginfo = "-Zunstable-options run --bin veloren-server-cli --features tracy,simd --profile releasedebuginfo"
test-voxygen = "run --bin veloren-voxygen --no-default-features --features simd,egui-ui"
tracy-voxygen = "-Zunstable-options run --bin veloren-voxygen --no-default-features --features tracy,simd,egui-ui --profile no_overflow"
server = "run --bin veloren-server-cli"

6
.gitignore vendored
View File

@ -34,7 +34,13 @@ maps
screenshots
todo.txt
userdata
# Profiling and traces
heaptrack.*
cargo-timing*
flamegraph.*
perf.*
wgpu-trace/
# allow asset hud settings
!assets/voxygen/i18n/*/hud/settings.ron

View File

@ -15,7 +15,7 @@ use crate::{
use serde::{Deserialize, Serialize};
use specs::{Component, DerefFlaggedStorage, VecStorage};
use specs_idvs::IdvStorage;
use std::collections::{BTreeMap, VecDeque};
use std::collections::BTreeMap;
use strum_macros::Display;
use vek::*;
@ -31,8 +31,21 @@ pub struct StateUpdate {
pub should_strafe: bool,
pub queued_inputs: BTreeMap<InputKind, InputAttr>,
pub removed_inputs: Vec<InputKind>,
pub local_events: VecDeque<LocalEvent>,
pub server_events: VecDeque<ServerEvent>,
}
pub struct OutputEvents<'a> {
local: &'a mut Vec<LocalEvent>,
server: &'a mut Vec<ServerEvent>,
}
impl<'a> OutputEvents<'a> {
pub fn new(local: &'a mut Vec<LocalEvent>, server: &'a mut Vec<ServerEvent>) -> Self {
Self { local, server }
}
pub fn emit_local(&mut self, event: LocalEvent) { self.local.push(event); }
pub fn emit_server(&mut self, event: ServerEvent) { self.server.push(event); }
}
impl From<&JoinData<'_>> for StateUpdate {
@ -48,8 +61,6 @@ impl From<&JoinData<'_>> for StateUpdate {
character: data.character.clone(),
queued_inputs: BTreeMap::new(),
removed_inputs: Vec::new(),
local_events: VecDeque::new(),
server_events: VecDeque::new(),
}
}
}
@ -245,81 +256,96 @@ impl CharacterState {
std::mem::discriminant(self) == std::mem::discriminant(other)
}
pub fn behavior(&self, j: &JoinData) -> StateUpdate {
pub fn behavior(&self, j: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
match &self {
CharacterState::Idle => states::idle::Data.behavior(j),
CharacterState::Talk => states::talk::Data.behavior(j),
CharacterState::Climb(data) => data.behavior(j),
CharacterState::Glide(data) => data.behavior(j),
CharacterState::GlideWield(data) => data.behavior(j),
CharacterState::Stunned(data) => data.behavior(j),
CharacterState::Sit => states::sit::Data::behavior(&states::sit::Data, j),
CharacterState::Dance => states::dance::Data::behavior(&states::dance::Data, j),
CharacterState::Sneak => states::sneak::Data::behavior(&states::sneak::Data, j),
CharacterState::BasicBlock(data) => data.behavior(j),
CharacterState::Roll(data) => data.behavior(j),
CharacterState::Wielding => states::wielding::Data.behavior(j),
CharacterState::Equipping(data) => data.behavior(j),
CharacterState::ComboMelee(data) => data.behavior(j),
CharacterState::BasicMelee(data) => data.behavior(j),
CharacterState::BasicRanged(data) => data.behavior(j),
CharacterState::Boost(data) => data.behavior(j),
CharacterState::DashMelee(data) => data.behavior(j),
CharacterState::LeapMelee(data) => data.behavior(j),
CharacterState::SpinMelee(data) => data.behavior(j),
CharacterState::ChargedMelee(data) => data.behavior(j),
CharacterState::ChargedRanged(data) => data.behavior(j),
CharacterState::RepeaterRanged(data) => data.behavior(j),
CharacterState::Shockwave(data) => data.behavior(j),
CharacterState::BasicBeam(data) => data.behavior(j),
CharacterState::BasicAura(data) => data.behavior(j),
CharacterState::Blink(data) => data.behavior(j),
CharacterState::BasicSummon(data) => data.behavior(j),
CharacterState::SelfBuff(data) => data.behavior(j),
CharacterState::SpriteSummon(data) => data.behavior(j),
CharacterState::UseItem(data) => data.behavior(j),
CharacterState::SpriteInteract(data) => data.behavior(j),
CharacterState::Idle => states::idle::Data.behavior(j, output_events),
CharacterState::Talk => states::talk::Data.behavior(j, output_events),
CharacterState::Climb(data) => data.behavior(j, output_events),
CharacterState::Glide(data) => data.behavior(j, output_events),
CharacterState::GlideWield(data) => data.behavior(j, output_events),
CharacterState::Stunned(data) => data.behavior(j, output_events),
CharacterState::Sit => {
states::sit::Data::behavior(&states::sit::Data, j, output_events)
},
CharacterState::Dance => {
states::dance::Data::behavior(&states::dance::Data, j, output_events)
},
CharacterState::Sneak => {
states::sneak::Data::behavior(&states::sneak::Data, j, output_events)
},
CharacterState::BasicBlock(data) => data.behavior(j, output_events),
CharacterState::Roll(data) => data.behavior(j, output_events),
CharacterState::Wielding => states::wielding::Data.behavior(j, output_events),
CharacterState::Equipping(data) => data.behavior(j, output_events),
CharacterState::ComboMelee(data) => data.behavior(j, output_events),
CharacterState::BasicMelee(data) => data.behavior(j, output_events),
CharacterState::BasicRanged(data) => data.behavior(j, output_events),
CharacterState::Boost(data) => data.behavior(j, output_events),
CharacterState::DashMelee(data) => data.behavior(j, output_events),
CharacterState::LeapMelee(data) => data.behavior(j, output_events),
CharacterState::SpinMelee(data) => data.behavior(j, output_events),
CharacterState::ChargedMelee(data) => data.behavior(j, output_events),
CharacterState::ChargedRanged(data) => data.behavior(j, output_events),
CharacterState::RepeaterRanged(data) => data.behavior(j, output_events),
CharacterState::Shockwave(data) => data.behavior(j, output_events),
CharacterState::BasicBeam(data) => data.behavior(j, output_events),
CharacterState::BasicAura(data) => data.behavior(j, output_events),
CharacterState::Blink(data) => data.behavior(j, output_events),
CharacterState::BasicSummon(data) => data.behavior(j, output_events),
CharacterState::SelfBuff(data) => data.behavior(j, output_events),
CharacterState::SpriteSummon(data) => data.behavior(j, output_events),
CharacterState::UseItem(data) => data.behavior(j, output_events),
CharacterState::SpriteInteract(data) => data.behavior(j, output_events),
}
}
pub fn handle_event(&self, j: &JoinData, action: ControlAction) -> StateUpdate {
pub fn handle_event(
&self,
j: &JoinData,
output_events: &mut OutputEvents,
action: ControlAction,
) -> StateUpdate {
match &self {
CharacterState::Idle => states::idle::Data.handle_event(j, action),
CharacterState::Talk => states::talk::Data.handle_event(j, action),
CharacterState::Climb(data) => data.handle_event(j, action),
CharacterState::Glide(data) => data.handle_event(j, action),
CharacterState::GlideWield(data) => data.handle_event(j, action),
CharacterState::Stunned(data) => data.handle_event(j, action),
CharacterState::Sit => states::sit::Data::handle_event(&states::sit::Data, j, action),
CharacterState::Idle => states::idle::Data.handle_event(j, output_events, action),
CharacterState::Talk => states::talk::Data.handle_event(j, output_events, action),
CharacterState::Climb(data) => data.handle_event(j, output_events, action),
CharacterState::Glide(data) => data.handle_event(j, output_events, action),
CharacterState::GlideWield(data) => data.handle_event(j, output_events, action),
CharacterState::Stunned(data) => data.handle_event(j, output_events, action),
CharacterState::Sit => {
states::sit::Data::handle_event(&states::sit::Data, j, output_events, action)
},
CharacterState::Dance => {
states::dance::Data::handle_event(&states::dance::Data, j, action)
states::dance::Data::handle_event(&states::dance::Data, j, output_events, action)
},
CharacterState::Sneak => {
states::sneak::Data::handle_event(&states::sneak::Data, j, action)
states::sneak::Data::handle_event(&states::sneak::Data, j, output_events, action)
},
CharacterState::BasicBlock(data) => 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::ComboMelee(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),
CharacterState::SpinMelee(data) => data.handle_event(j, action),
CharacterState::ChargedMelee(data) => data.handle_event(j, action),
CharacterState::ChargedRanged(data) => data.handle_event(j, action),
CharacterState::RepeaterRanged(data) => data.handle_event(j, action),
CharacterState::Shockwave(data) => data.handle_event(j, action),
CharacterState::BasicBeam(data) => data.handle_event(j, action),
CharacterState::BasicAura(data) => data.handle_event(j, action),
CharacterState::Blink(data) => data.handle_event(j, action),
CharacterState::BasicSummon(data) => data.handle_event(j, action),
CharacterState::SelfBuff(data) => data.handle_event(j, action),
CharacterState::SpriteSummon(data) => data.handle_event(j, action),
CharacterState::UseItem(data) => data.handle_event(j, action),
CharacterState::SpriteInteract(data) => data.handle_event(j, action),
CharacterState::BasicBlock(data) => data.handle_event(j, output_events, action),
CharacterState::Roll(data) => data.handle_event(j, output_events, action),
CharacterState::Wielding => {
states::wielding::Data.handle_event(j, output_events, action)
},
CharacterState::Equipping(data) => data.handle_event(j, output_events, action),
CharacterState::ComboMelee(data) => data.handle_event(j, output_events, action),
CharacterState::BasicMelee(data) => data.handle_event(j, output_events, action),
CharacterState::BasicRanged(data) => data.handle_event(j, output_events, action),
CharacterState::Boost(data) => data.handle_event(j, output_events, action),
CharacterState::DashMelee(data) => data.handle_event(j, output_events, action),
CharacterState::LeapMelee(data) => data.handle_event(j, output_events, action),
CharacterState::SpinMelee(data) => data.handle_event(j, output_events, action),
CharacterState::ChargedMelee(data) => data.handle_event(j, output_events, action),
CharacterState::ChargedRanged(data) => data.handle_event(j, output_events, action),
CharacterState::RepeaterRanged(data) => data.handle_event(j, output_events, action),
CharacterState::Shockwave(data) => data.handle_event(j, output_events, action),
CharacterState::BasicBeam(data) => data.handle_event(j, output_events, action),
CharacterState::BasicAura(data) => data.handle_event(j, output_events, action),
CharacterState::Blink(data) => data.handle_event(j, output_events, action),
CharacterState::BasicSummon(data) => data.handle_event(j, output_events, action),
CharacterState::SelfBuff(data) => data.handle_event(j, output_events, action),
CharacterState::SpriteSummon(data) => data.handle_event(j, output_events, action),
CharacterState::UseItem(data) => data.handle_event(j, output_events, action),
CharacterState::SpriteInteract(data) => data.handle_event(j, output_events, action),
}
}
}

View File

@ -8,7 +8,7 @@ pub mod anchor;
#[cfg(not(target_arch = "wasm32"))] pub mod body;
pub mod buff;
#[cfg(not(target_arch = "wasm32"))]
mod character_state;
pub mod character_state;
#[cfg(not(target_arch = "wasm32"))] pub mod chat;
#[cfg(not(target_arch = "wasm32"))] pub mod combo;
pub mod compass;

View File

@ -1,8 +1,8 @@
use crate::util::{Dir, Plane, Projection};
use core::f32::consts::{FRAC_PI_2, PI, TAU};
use serde::{Deserialize, Serialize};
use specs::Component;
use specs_idvs::IdvStorage;
use std::f32::consts::PI;
use vek::{Quaternion, Vec2, Vec3};
// Orientation
@ -149,25 +149,59 @@ impl Ori {
}
pub fn to_horizontal(self) -> Self {
let fw = self.look_dir();
Dir::from_unnormalized(fw.xy().into())
.or_else(|| {
// if look_dir is straight down, pitch up, or if straight up, pitch down
Dir::from_unnormalized(
if fw.dot(Vec3::unit_z()) < 0.0 {
self.up()
} else {
self.down()
}
.xy()
.into(),
)
})
.map(|dir| dir.into())
.expect(
"If the horizontal component of a Dir can not be normalized, the horizontal \
component of a Dir perpendicular to it must be",
)
// We don't use Self::look_dir to avoid the extra normalization step within
// Dir's Quaternion Mul impl
let fw = self.to_quat() * Dir::default().to_vec();
// Check that dir is not straight up/down
// Uses a multiple of EPSILON to be safe
// We can just check z since beyond floating point errors `fw` should be
// normalized
if 1.0 - fw.z.abs() > f32::EPSILON * 4.0 {
// We know direction lies in the xy plane so we only need to compute a rotation
// about the z-axis
let Vec2 { x, y } = fw.xy().normalized();
// Negate x and swap coords since we want to compute the angle from y+
let quat = rotation_2d(Vec2::new(y, -x), Vec3::unit_z());
Self(quat)
} else {
// if the direction is straight down, pitch up, or if straight up, pitch down
if fw.z < 0.0 {
self.pitched_up(FRAC_PI_2)
} else {
self.pitched_down(FRAC_PI_2)
}
// TODO: test this alternative for speed and correctness compared to
// current impl
//
// removes a branch
//
// use core::f32::consts::FRAC_1_SQRT_2;
// let cos = FRAC_1_SQRT_2;
// let sin = -FRAC_1_SQRT_2 * fw.z.signum();
// let axis = Vec3::unit_x();
// let scalar = cos;
// let vector = sin * axis;
// Self((self.0 * Quaternion::from_scalar_and_vec3((scalar,
// vector))).normalized())
}
}
/// Find the angle between two `Ori`s
///
/// NOTE: This finds the angle of the quaternion between the two `Ori`s
/// which can involve rolling and thus can be larger than simply the
/// angle between vectors at the start and end points.
///
/// Returns angle in radians
pub fn angle_between(self, other: Self) -> f32 {
// Compute quaternion from one ori to the other
// https://www.mathworks.com/matlabcentral/answers/476474-how-to-find-the-angle-between-two-quaternions#answer_387973
let between = self.to_quat().conjugate() * other.to_quat();
// Then compute it's angle
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/
let angle = 2.0 * between.w.acos();
if angle < PI { angle } else { TAU - angle }
}
pub fn pitched_up(self, angle_radians: f32) -> Self {
@ -239,38 +273,68 @@ impl Ori {
/// let ang2 = pd_rr.up().angle_between(zenith);
/// assert!((ang1 - ang2).abs() <= std::f32::EPSILON);
/// ```
pub fn uprighted(self) -> Self {
let fw = self.look_dir();
match Dir::up().projected(&Plane::from(fw)) {
Some(dir_p) => {
let up = self.up();
let go_right_s = fw.cross(*up).dot(*dir_p).signum();
self.rolled_right(up.angle_between(*dir_p) * go_right_s)
},
None => self,
}
}
pub fn uprighted(self) -> Self { self.look_dir().into() }
fn is_normalized(&self) -> bool { self.0.into_vec4().is_normalized() }
}
/// Produce a quaternion from an axis to rotate about and a 2D point on the unit
/// circle to rotate to
///
/// NOTE: the provided axis and 2D vector must be normalized
fn rotation_2d(Vec2 { x, y }: Vec2<f32>, axis: Vec3<f32>) -> Quaternion<f32> {
// Skip needing the angle for quaternion construction by computing cos/sin
// directly from the normalized x value
//
// scalar = cos(theta / 2)
// vector = axis * sin(theta / 2)
//
// cos(a / 2) = +/- ((1 + cos(a)) / 2)^0.5
// sin(a / 2) = +/- ((1 - cos(a)) / 2)^0.5
//
// scalar = +/- sqrt((1 + cos(a)) / 2)
// vector = vec3(0, 0, 1) * +/- sqrt((1 - cos(a)) / 2)
//
// cos(a) = x / |xy| => x (when normalized)
let scalar = ((1.0 + x) / 2.0).sqrt() * y.signum();
let vector = axis * ((1.0 - x) / 2.0).sqrt();
// This is normalized by our construction above
Quaternion::from_scalar_and_vec3((scalar, vector))
}
impl From<Dir> for Ori {
fn from(dir: Dir) -> Self {
let from = Dir::default();
let q = Quaternion::<f32>::rotation_from_to_3d(*from, *dir).normalized();
// Check that dir is not straight up/down
// Uses a multiple of EPSILON to be safe
let quat = if 1.0 - dir.z.abs() > f32::EPSILON * 4.0 {
// Compute rotation that will give an "upright" orientation (no
// rolling):
let xy_len = dir.xy().magnitude();
let xy_norm = dir.xy() / xy_len;
// Rotation to get to this projected point from the default direction of y+
// Negate x and swap coords since we want to compute the angle from y+
let yaw = rotation_2d(Vec2::new(xy_norm.y, -xy_norm.x), Vec3::unit_z());
// Rotation to then rotate up/down to the match the input direction
// In this rotated space the xy_len becomes the distance along the x axis
// And since we rotated around the z-axis the z value is unchanged
let pitch = rotation_2d(Vec2::new(xy_len, dir.z), Vec3::unit_x());
Self(q).uprighted()
(yaw * pitch).normalized()
} else {
// Nothing in particular can be considered upright if facing up or down
// so we just produce a quaternion that will rotate to that direction
// (once again rotating from y+)
let pitch = PI / 2.0 * dir.z.signum();
Quaternion::rotation_x(pitch)
};
Self(quat)
}
}
impl From<Vec3<f32>> for Ori {
fn from(dir: Vec3<f32>) -> Self {
let dir = Dir::from_unnormalized(dir).unwrap_or_default();
let from = Dir::default();
let q = Quaternion::<f32>::rotation_from_to_3d(*from, *dir).normalized();
Self(q).uprighted()
}
fn from(dir: Vec3<f32>) -> Self { Dir::from_unnormalized(dir).unwrap_or_default().into() }
}
impl From<Quaternion<f32>> for Ori {
@ -354,32 +418,83 @@ impl Component for Ori {
mod tests {
use super::*;
// Helper method to produce Dirs at different angles to test
fn dirs() -> impl Iterator<Item = Dir> {
let angles = 32;
(0..angles).flat_map(move |i| {
let theta = PI * 2.0 * (i as f32) / (angles as f32);
let v = Vec3::unit_y();
let q = Quaternion::rotation_x(theta);
let dir_1 = Dir::new(q * v);
let v = Vec3::unit_z();
let q = Quaternion::rotation_y(theta);
let dir_2 = Dir::new(q * v);
let v = Vec3::unit_x();
let q = Quaternion::rotation_z(theta);
let dir_3 = Dir::new(q * v);
[dir_1, dir_2, dir_3]
})
}
#[test]
fn to_horizontal() {
let to_horizontal = |dir: Dir| {
let ori = Ori::from(dir);
let horizontal = ori.to_horizontal();
approx::assert_relative_eq!(horizontal.look_dir().xy().magnitude(), 1.0);
approx::assert_relative_eq!(horizontal.look_dir().z, 0.0);
// Check correctness by comparing with Dir::to_horizontal
if let Some(dir_h) = ori.look_dir().to_horizontal() {
let quat_correct = Quaternion::<f32>::rotation_from_to_3d(Dir::default(), dir_h);
#[rustfmt::skip]
assert!(
dir_h
.map2(*horizontal.look_dir(), |d, o| approx::relative_eq!(d, o, epsilon = f32::EPSILON * 4.0))
.reduce_and(),
"\n\
Original: {:?}\n\
Dir::to_horizontal: {:?}\n\
Ori::to_horizontal(as dir): {:?}\n\
Ori::to_horizontal(as quat): {:?}\n\
Correct quaternion {:?}",
ori.look_dir(),
dir_h,
horizontal.look_dir(),
horizontal,
quat_correct,
);
}
};
dirs().for_each(to_horizontal);
}
#[test]
fn from_to_dir() {
let from_to = |dir: Dir| {
let ori = Ori::from(dir);
approx::assert_relative_eq!(ori.look_dir().dot(*dir), 1.0);
assert!(ori.is_normalized(), "ori {:?}\ndir {:?}", ori, dir);
assert!(
approx::relative_eq!(ori.look_dir().dot(*dir), 1.0),
"Ori::from(dir).look_dir() != dir\ndir: {:?}\nOri::from(dir).look_dir(): {:?}",
dir,
ori.look_dir(),
);
approx::assert_relative_eq!((ori.to_quat() * Dir::default()).dot(*dir), 1.0);
};
let angles = 32;
for i in 0..angles {
let theta = PI * 2. * (i as f32) / (angles as f32);
let v = Vec3::unit_y();
let q = Quaternion::rotation_x(theta);
from_to(Dir::new(q * v));
let v = Vec3::unit_z();
let q = Quaternion::rotation_y(theta);
from_to(Dir::new(q * v));
let v = Vec3::unit_x();
let q = Quaternion::rotation_z(theta);
from_to(Dir::new(q * v));
}
dirs().for_each(from_to);
}
#[test]
fn dirs() {
fn orthogonal_dirs() {
let ori = Ori::default();
let def = Dir::default();
for dir in &[ori.up(), ori.down(), ori.left(), ori.right()] {

View File

@ -242,6 +242,9 @@ impl<'a, E> Emitter<'a, E> {
pub fn emit(&mut self, event: E) { self.events.push_back(event); }
pub fn append(&mut self, other: &mut VecDeque<E>) { self.events.append(other) }
// TODO: allow just emitting the whole vec of events at once? without copying
pub fn append_vec(&mut self, vec: Vec<E>) { self.events.extend(vec) }
}
impl<'a, E> Drop for Emitter<'a, E> {

View File

@ -10,7 +10,8 @@
label_break_value,
option_zip,
trait_alias,
type_alias_impl_trait
type_alias_impl_trait,
extend_one
)]
/// Re-exported crates

View File

@ -2,6 +2,7 @@ use crate::{
combat::GroupTarget,
comp::{
aura::{AuraBuffConstructor, AuraChange, AuraKind, AuraTarget, Specifier},
character_state::OutputEvents,
CharacterState, StateUpdate,
},
event::ServerEvent,
@ -52,12 +53,12 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, 0.8);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
match self.stage_section {
StageSection::Buildup => {
@ -89,12 +90,12 @@ impl CharacterBehavior for Data {
1.0 + (self.static_data.combo_at_cast.max(1) as f32).log(2.0);
},
}
update.server_events.push_front(ServerEvent::ComboChange {
output_events.emit_server(ServerEvent::ComboChange {
entity: data.entity,
change: -(self.static_data.combo_at_cast as i32),
});
}
update.server_events.push_front(ServerEvent::Aura {
output_events.emit_server(ServerEvent::Aura {
entity: data.entity,
aura_change: AuraChange::Add(aura),
});

View File

@ -3,7 +3,10 @@ use crate::{
Attack, AttackDamage, AttackEffect, CombatEffect, CombatRequirement, Damage, DamageKind,
DamageSource, GroupTarget,
},
comp::{beam, body::biped_large, Body, CharacterState, Ori, Pos, StateUpdate},
comp::{
beam, body::biped_large, character_state::OutputEvents, Body, CharacterState, Ori, Pos,
StateUpdate,
},
event::ServerEvent,
states::{
behavior::{CharacterBehavior, JoinData},
@ -60,14 +63,14 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
let ori_rate = self.static_data.ori_rate;
handle_orientation(data, &mut update, ori_rate, None);
handle_move(data, &mut update, 0.4);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
match self.stage_section {
StageSection::Buildup => {
@ -171,7 +174,7 @@ impl CharacterBehavior for Data {
let pos = Pos(data.pos.0 + body_offsets);
// Create beam segment
update.server_events.push_front(ServerEvent::BeamSegment {
output_events.emit_server(ServerEvent::BeamSegment {
properties,
pos,
ori: beam_ori,

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{CharacterState, InputKind, StateUpdate},
comp::{character_state::OutputEvents, CharacterState, InputKind, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
@ -35,7 +35,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);

View File

@ -3,7 +3,7 @@ use crate::{
Attack, AttackDamage, AttackEffect, CombatEffect, CombatRequirement, Damage, DamageKind,
DamageSource, GroupTarget, Knockback,
},
comp::{tool::ToolKind, CharacterState, Melee, StateUpdate},
comp::{character_state::OutputEvents, tool::ToolKind, CharacterState, Melee, StateUpdate},
states::{
behavior::{CharacterBehavior, JoinData},
utils::*,
@ -53,12 +53,12 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, 0.7);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
match self.stage_section {
StageSection::Buildup => {
@ -161,7 +161,7 @@ impl CharacterBehavior for Data {
} else {
// Done
if input_is_pressed(data, self.static_data.ability_info.input) {
reset_state(self, data, &mut update);
reset_state(self, data, output_events, &mut update);
} else {
update.character = CharacterState::Wielding;
}
@ -184,6 +184,16 @@ impl CharacterBehavior for Data {
}
}
fn reset_state(data: &Data, join: &JoinData, update: &mut StateUpdate) {
handle_input(join, update, data.static_data.ability_info.input);
fn reset_state(
data: &Data,
join: &JoinData,
output_events: &mut OutputEvents,
update: &mut StateUpdate,
) {
handle_input(
join,
output_events,
update,
data.static_data.ability_info.input,
);
}

View File

@ -1,5 +1,8 @@
use crate::{
comp::{Body, CharacterState, LightEmitter, Pos, ProjectileConstructor, StateUpdate},
comp::{
character_state::OutputEvents, Body, CharacterState, LightEmitter, Pos,
ProjectileConstructor, StateUpdate,
},
event::ServerEvent,
states::{
behavior::{CharacterBehavior, JoinData},
@ -45,12 +48,12 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, 0.3);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
match self.stage_section {
StageSection::Buildup => {
@ -96,7 +99,7 @@ impl CharacterBehavior for Data {
}))
.unwrap_or(data.inputs.look_dir);
// Tells server to create and shoot the projectile
update.server_events.push_front(ServerEvent::Shoot {
output_events.emit_server(ServerEvent::Shoot {
entity: data.entity,
pos,
dir,
@ -121,7 +124,7 @@ impl CharacterBehavior for Data {
} else {
// Done
if input_is_pressed(data, self.static_data.ability_info.input) {
reset_state(self, data, &mut update);
reset_state(self, data, output_events, &mut update);
} else {
update.character = CharacterState::Wielding;
}
@ -142,6 +145,16 @@ impl CharacterBehavior for Data {
}
}
fn reset_state(data: &Data, join: &JoinData, update: &mut StateUpdate) {
handle_input(join, update, data.static_data.ability_info.input);
fn reset_state(
data: &Data,
join: &JoinData,
output_events: &mut OutputEvents,
update: &mut StateUpdate,
) {
handle_input(
join,
output_events,
update,
data.static_data.ability_info.input,
);
}

View File

@ -1,6 +1,7 @@
use crate::{
comp::{
self,
character_state::OutputEvents,
inventory::loadout_builder::{self, LoadoutBuilder},
Behavior, BehaviorCapability, CharacterState, Projectile, StateUpdate,
},
@ -54,7 +55,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
match self.stage_section {
@ -167,7 +168,7 @@ impl CharacterBehavior for Data {
});
// Send server event to create npc
update.server_events.push_front(ServerEvent::CreateNpc {
output_events.emit_server(ServerEvent::CreateNpc {
pos: comp::Pos(collision_vector - Vec3::unit_z() * obstacle_z),
stats,
skill_set,
@ -193,7 +194,7 @@ impl CharacterBehavior for Data {
});
// Send local event used for frontend shenanigans
update.local_events.push_front(LocalEvent::CreateOutcome(
output_events.emit_local(LocalEvent::CreateOutcome(
Outcome::SummonedCreature {
pos: data.pos.0,
body,

View File

@ -1,8 +1,9 @@
use crate::{
comp::{
self, item::MaterialStatManifest, Beam, Body, CharacterState, Combo, ControlAction,
Controller, ControllerInputs, Density, Energy, Health, InputAttr, InputKind, Inventory,
InventoryAction, Mass, Melee, Ori, PhysicsState, Pos, SkillSet, StateUpdate, Stats, Vel,
self, character_state::OutputEvents, item::MaterialStatManifest, Beam, Body,
CharacterState, Combo, ControlAction, Controller, ControllerInputs, Density, Energy,
Health, InputAttr, InputKind, Inventory, InventoryAction, Mass, Melee, Ori, PhysicsState,
Pos, SkillSet, StateUpdate, Stats, Vel,
},
resources::DeltaTime,
terrain::TerrainGrid,
@ -12,20 +13,47 @@ use specs::{storage::FlaggedAccessMut, Entity, LazyUpdate};
use vek::*;
pub trait CharacterBehavior {
fn behavior(&self, data: &JoinData) -> StateUpdate;
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate;
// Impl these to provide behavior for these inputs
fn swap_equipped_weapons(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn manipulate_loadout(&self, data: &JoinData, _inv_action: InventoryAction) -> StateUpdate {
fn swap_equipped_weapons(
&self,
data: &JoinData,
_output_events: &mut OutputEvents,
) -> StateUpdate {
StateUpdate::from(data)
}
fn manipulate_loadout(
&self,
data: &JoinData,
_output_events: &mut OutputEvents,
_inv_action: InventoryAction,
) -> StateUpdate {
StateUpdate::from(data)
}
fn wield(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
StateUpdate::from(data)
}
fn glide_wield(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
StateUpdate::from(data)
}
fn unwield(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
StateUpdate::from(data)
}
fn sit(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
StateUpdate::from(data)
}
fn dance(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
StateUpdate::from(data)
}
fn sneak(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
StateUpdate::from(data)
}
fn stand(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
StateUpdate::from(data)
}
fn talk(&self, data: &JoinData, _output_events: &mut OutputEvents) -> StateUpdate {
StateUpdate::from(data)
}
fn wield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn glide_wield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn unwield(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn sit(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn dance(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn sneak(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn stand(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn talk(&self, data: &JoinData) -> StateUpdate { StateUpdate::from(data) }
fn start_input(
&self,
data: &JoinData,
@ -45,18 +73,25 @@ pub trait CharacterBehavior {
update.removed_inputs.push(input);
update
}
fn handle_event(&self, data: &JoinData, event: ControlAction) -> StateUpdate {
fn handle_event(
&self,
data: &JoinData,
output_events: &mut OutputEvents,
event: ControlAction,
) -> StateUpdate {
match event {
ControlAction::SwapEquippedWeapons => self.swap_equipped_weapons(data),
ControlAction::InventoryAction(inv_action) => self.manipulate_loadout(data, inv_action),
ControlAction::Wield => self.wield(data),
ControlAction::GlideWield => self.glide_wield(data),
ControlAction::Unwield => self.unwield(data),
ControlAction::Sit => self.sit(data),
ControlAction::Dance => self.dance(data),
ControlAction::Sneak => self.sneak(data),
ControlAction::Stand => self.stand(data),
ControlAction::Talk => self.talk(data),
ControlAction::SwapEquippedWeapons => self.swap_equipped_weapons(data, output_events),
ControlAction::InventoryAction(inv_action) => {
self.manipulate_loadout(data, output_events, inv_action)
},
ControlAction::Wield => self.wield(data, output_events),
ControlAction::GlideWield => self.glide_wield(data, output_events),
ControlAction::Unwield => self.unwield(data, output_events),
ControlAction::Sit => self.sit(data, output_events),
ControlAction::Dance => self.dance(data, output_events),
ControlAction::Sneak => self.sneak(data, output_events),
ControlAction::Stand => self.stand(data, output_events),
ControlAction::Talk => self.talk(data, output_events),
ControlAction::StartInput {
input,
target_entity,

View File

@ -1,5 +1,5 @@
use crate::{
comp::{CharacterState, StateUpdate},
comp::{character_state::OutputEvents, CharacterState, StateUpdate},
event::ServerEvent,
states::{
behavior::{CharacterBehavior, JoinData},
@ -34,7 +34,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
@ -52,7 +52,7 @@ impl CharacterBehavior for Data {
// provided
if let Some(input_attr) = self.static_data.ability_info.input_attr {
if let Some(target) = input_attr.target_entity {
update.server_events.push_front(ServerEvent::TeleportTo {
output_events.emit_server(ServerEvent::TeleportTo {
entity: data.entity,
target,
max_range: Some(self.static_data.max_range),

View File

@ -1,5 +1,5 @@
use crate::{
comp::{CharacterState, StateUpdate},
comp::{character_state::OutputEvents, CharacterState, StateUpdate},
states::{
behavior::{CharacterBehavior, JoinData},
utils::*,
@ -28,7 +28,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_move(data, &mut update, 1.0);
@ -47,7 +47,7 @@ impl CharacterBehavior for Data {
} else {
// Done
if input_is_pressed(data, self.static_data.ability_info.input) {
reset_state(self, data, &mut update);
reset_state(self, data, output_events, &mut update);
} else {
update.vel.0 = update.vel.0.try_normalized().unwrap_or_default()
* update
@ -63,6 +63,16 @@ impl CharacterBehavior for Data {
}
}
fn reset_state(data: &Data, join: &JoinData, update: &mut StateUpdate) {
handle_input(join, update, data.static_data.ability_info.input);
fn reset_state(
data: &Data,
join: &JoinData,
output_events: &mut OutputEvents,
update: &mut StateUpdate,
) {
handle_input(
join,
output_events,
update,
data.static_data.ability_info.input,
);
}

View File

@ -1,6 +1,6 @@
use crate::{
combat::{Attack, AttackDamage, AttackEffect, CombatEffect, CombatRequirement},
comp::{tool::ToolKind, CharacterState, Melee, StateUpdate},
comp::{character_state::OutputEvents, tool::ToolKind, CharacterState, Melee, StateUpdate},
event::LocalEvent,
outcome::Outcome,
states::{
@ -69,12 +69,12 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, 0.7);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
match self.stage_section {
StageSection::Charge => {
@ -190,13 +190,11 @@ impl CharacterBehavior for Data {
if let Some(FrontendSpecifier::GroundCleave) = self.static_data.specifier {
// Send local event used for frontend shenanigans
update.local_events.push_front(LocalEvent::CreateOutcome(
Outcome::GroundSlam {
pos: data.pos.0
+ *data.ori.look_dir()
* (data.body.max_radius() + self.static_data.range),
},
));
output_events.emit_local(LocalEvent::CreateOutcome(Outcome::GroundSlam {
pos: data.pos.0
+ *data.ori.look_dir()
* (data.body.max_radius() + self.static_data.range),
}));
}
} else if self.timer < self.static_data.swing_duration {
// Swings

View File

@ -1,6 +1,7 @@
use crate::{
comp::{
projectile::ProjectileConstructor, Body, CharacterState, LightEmitter, Pos, StateUpdate,
character_state::OutputEvents, projectile::ProjectileConstructor, Body, CharacterState,
LightEmitter, Pos, StateUpdate,
},
event::ServerEvent,
states::{
@ -70,12 +71,12 @@ impl Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, self.static_data.move_speed);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
match self.stage_section {
StageSection::Buildup => {
@ -118,7 +119,7 @@ impl CharacterBehavior for Data {
crit_mult,
buff_strength,
);
update.server_events.push_front(ServerEvent::Shoot {
output_events.emit_server(ServerEvent::Shoot {
entity: data.entity,
pos,
dir: data.inputs.look_dir,

View File

@ -1,5 +1,6 @@
use crate::{
comp::{
character_state::OutputEvents,
skills::{ClimbSkill::*, Skill, SKILL_MODIFIERS},
CharacterState, Climb, InputKind, Ori, StateUpdate,
},
@ -54,7 +55,7 @@ impl Default for Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
// If no wall is in front of character or we stopped climbing;
@ -72,7 +73,7 @@ impl CharacterBehavior for Data {
// How strong the climb boost is relative to a normal jump
const CLIMB_BOOST_JUMP_FACTOR: f32 = 0.5;
// They've climbed atop something, give them a boost
update.local_events.push_front(LocalEvent::Jump(
output_events.emit_local(LocalEvent::Jump(
data.entity,
CLIMB_BOOST_JUMP_FACTOR * impulse / data.mass.0,
));

View File

@ -1,6 +1,7 @@
use crate::{
combat::{Attack, AttackDamage, AttackEffect, CombatBuff, CombatEffect, CombatRequirement},
comp::{
character_state::OutputEvents,
tool::{Stats, ToolKind},
CharacterState, Melee, StateUpdate,
},
@ -151,7 +152,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_move(data, &mut update, 0.4);
@ -340,7 +341,7 @@ impl CharacterBehavior for Data {
} else {
// Done
if input_is_pressed(data, self.static_data.ability_info.input) {
reset_state(self, data, &mut update);
reset_state(self, data, output_events, &mut update);
} else {
update.character = CharacterState::Wielding;
}
@ -363,8 +364,18 @@ impl CharacterBehavior for Data {
}
}
fn reset_state(data: &Data, join: &JoinData, update: &mut StateUpdate) {
handle_input(join, update, data.static_data.ability_info.input);
fn reset_state(
data: &Data,
join: &JoinData,
output_events: &mut OutputEvents,
update: &mut StateUpdate,
) {
handle_input(
join,
output_events,
update,
data.static_data.ability_info.input,
);
if let CharacterState::ComboMelee(c) = &mut update.character {
c.stage = (data.stage % data.static_data.num_stages) + 1;

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{CharacterState, InventoryAction, StateUpdate},
comp::{character_state::OutputEvents, CharacterState, InventoryAction, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
@ -9,11 +9,11 @@ use serde::{Deserialize, Serialize};
pub struct Data;
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_wield(data, &mut update);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
// Try to Fall/Stand up/Move
if data.physics.on_ground.is_none() || data.inputs.move_dir.magnitude_squared() > 0.0 {
@ -23,25 +23,30 @@ impl CharacterBehavior for Data {
update
}
fn manipulate_loadout(&self, data: &JoinData, inv_action: InventoryAction) -> StateUpdate {
fn manipulate_loadout(
&self,
data: &JoinData,
output_events: &mut OutputEvents,
inv_action: InventoryAction,
) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(data, &mut update, inv_action);
handle_manipulate_loadout(data, output_events, &mut update, inv_action);
update
}
fn wield(&self, data: &JoinData) -> StateUpdate {
fn wield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_wield(data, &mut update);
update
}
fn sit(&self, data: &JoinData) -> StateUpdate {
fn sit(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_sit(data, &mut update);
update
}
fn stand(&self, data: &JoinData) -> StateUpdate {
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
// Try to Fall/Stand up/Move
update.character = CharacterState::Idle;

View File

@ -1,6 +1,6 @@
use crate::{
combat::{Attack, AttackDamage, AttackEffect, CombatEffect, CombatRequirement},
comp::{tool::ToolKind, CharacterState, Melee, StateUpdate},
comp::{character_state::OutputEvents, tool::ToolKind, CharacterState, Melee, StateUpdate},
states::{
behavior::{CharacterBehavior, JoinData},
utils::*,
@ -74,7 +74,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_move(data, &mut update, 0.1);

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{CharacterState, StateUpdate},
comp::{character_state::OutputEvents, CharacterState, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
@ -23,12 +23,12 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, 1.0);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
if self.timer < self.static_data.buildup_duration {
// Draw weapon

View File

@ -1,8 +1,8 @@
use super::utils::handle_climb;
use crate::{
comp::{
fluid_dynamics::angle_of_attack, inventory::slot::EquipSlot, CharacterState, Ori,
StateUpdate, Vel,
character_state::OutputEvents, fluid_dynamics::angle_of_attack, inventory::slot::EquipSlot,
CharacterState, Ori, StateUpdate, Vel,
},
states::{
behavior::{CharacterBehavior, JoinData},
@ -73,7 +73,7 @@ impl Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
// If player is on ground, end glide
@ -199,7 +199,7 @@ impl CharacterBehavior for Data {
update
}
fn unwield(&self, data: &JoinData) -> StateUpdate {
fn unwield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
update.character = CharacterState::Idle;
update

View File

@ -1,6 +1,9 @@
use super::utils::*;
use crate::{
comp::{slot::EquipSlot, CharacterState, InventoryAction, Ori, StateUpdate},
comp::{
character_state::OutputEvents, slot::EquipSlot, CharacterState, InventoryAction, Ori,
StateUpdate,
},
states::{
behavior::{CharacterBehavior, JoinData},
glide,
@ -32,12 +35,12 @@ impl From<&JoinData<'_>> for Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, 1.0);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
handle_dodge_input(data, &mut update);
handle_wield(data, &mut update);
@ -76,31 +79,36 @@ impl CharacterBehavior for Data {
update
}
fn manipulate_loadout(&self, data: &JoinData, inv_action: InventoryAction) -> StateUpdate {
fn manipulate_loadout(
&self,
data: &JoinData,
output_events: &mut OutputEvents,
inv_action: InventoryAction,
) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(data, &mut update, inv_action);
handle_manipulate_loadout(data, output_events, &mut update, inv_action);
update
}
fn unwield(&self, data: &JoinData) -> StateUpdate {
fn unwield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
update.character = CharacterState::Idle;
update
}
fn sit(&self, data: &JoinData) -> StateUpdate {
fn sit(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_sit(data, &mut update);
update
}
fn dance(&self, data: &JoinData) -> StateUpdate {
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_dance(data, &mut update);
update
}
fn sneak(&self, data: &JoinData) -> StateUpdate {
fn sneak(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_sneak(data, &mut update);
update

View File

@ -1,18 +1,18 @@
use super::utils::*;
use crate::{
comp::{InventoryAction, StateUpdate},
comp::{character_state::OutputEvents, InventoryAction, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
pub struct Data;
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, 1.0);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
handle_wield(data, &mut update);
handle_climb(data, &mut update);
handle_dodge_input(data, &mut update);
@ -20,49 +20,54 @@ impl CharacterBehavior for Data {
update
}
fn swap_equipped_weapons(&self, data: &JoinData) -> StateUpdate {
fn swap_equipped_weapons(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_swap_equipped_weapons(data, &mut update);
update
}
fn manipulate_loadout(&self, data: &JoinData, inv_action: InventoryAction) -> StateUpdate {
fn manipulate_loadout(
&self,
data: &JoinData,
output_events: &mut OutputEvents,
inv_action: InventoryAction,
) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(data, &mut update, inv_action);
handle_manipulate_loadout(data, output_events, &mut update, inv_action);
update
}
fn wield(&self, data: &JoinData) -> StateUpdate {
fn wield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_wield(data, &mut update);
update
}
fn glide_wield(&self, data: &JoinData) -> StateUpdate {
fn glide_wield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_glide_wield(data, &mut update);
update
}
fn sit(&self, data: &JoinData) -> StateUpdate {
fn sit(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_sit(data, &mut update);
update
}
fn dance(&self, data: &JoinData) -> StateUpdate {
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_dance(data, &mut update);
update
}
fn sneak(&self, data: &JoinData) -> StateUpdate {
fn sneak(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_sneak(data, &mut update);
update
}
fn talk(&self, data: &JoinData) -> StateUpdate {
fn talk(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_talk(data, &mut update);
update

View File

@ -1,6 +1,6 @@
use crate::{
combat::{Attack, AttackDamage, AttackEffect, CombatEffect, CombatRequirement},
comp::{tool::ToolKind, CharacterState, Melee, StateUpdate},
comp::{character_state::OutputEvents, tool::ToolKind, CharacterState, Melee, StateUpdate},
states::{
behavior::{CharacterBehavior, JoinData},
utils::{StageSection, *},
@ -57,12 +57,12 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, 0.3);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
match self.stage_section {
// Delay before leaping into the air

View File

@ -1,5 +1,8 @@
use crate::{
comp::{Body, CharacterState, LightEmitter, Pos, ProjectileConstructor, StateUpdate},
comp::{
character_state::OutputEvents, Body, CharacterState, LightEmitter, Pos,
ProjectileConstructor, StateUpdate,
},
event::ServerEvent,
states::{
behavior::{CharacterBehavior, JoinData},
@ -49,7 +52,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, 0.3);
@ -97,7 +100,7 @@ impl CharacterBehavior for Data {
crit_mult,
buff_strength,
);
update.server_events.push_front(ServerEvent::Shoot {
output_events.emit_server(ServerEvent::Shoot {
entity: data.entity,
pos,
dir: data.inputs.look_dir,
@ -109,7 +112,7 @@ impl CharacterBehavior for Data {
});
// Removes energy from character when arrow is fired
update.server_events.push_front(ServerEvent::EnergyChange {
output_events.emit_server(ServerEvent::EnergyChange {
entity: data.entity,
change: -self.static_data.energy_cost,
});

View File

@ -1,6 +1,7 @@
use crate::{
comp::{
buff::{BuffChange, BuffKind},
character_state::OutputEvents,
CharacterState, InputKind, StateUpdate,
},
event::ServerEvent,
@ -47,7 +48,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
// You should not be able to strafe while rolling
@ -67,7 +68,7 @@ impl CharacterBehavior for Data {
});
} else {
// Remove burning effect if active
update.server_events.push_front(ServerEvent::Buff {
output_events.emit_server(ServerEvent::Buff {
entity: data.entity,
buff_change: BuffChange::RemoveByKind(BuffKind::Burning),
});
@ -109,7 +110,7 @@ impl CharacterBehavior for Data {
handle_move(data, &mut update, 1.0);
// Allows for jumps to interrupt recovery in roll
if self.timer < self.static_data.recover_duration
&& !handle_jump(data, &mut update, 1.5)
&& !handle_jump(data, output_events, &mut update, 1.5)
{
// Recover
update.character = CharacterState::Roll(Data {
@ -120,7 +121,7 @@ impl CharacterBehavior for Data {
// Done
if let Some((input, stage)) = self.was_combo {
if input_is_pressed(data, input) {
handle_input(data, &mut update, input);
handle_input(data, output_events, &mut update, input);
// If other states are introduced that progress through stages, add them
// here
if let CharacterState::ComboMelee(c) = &mut update.character {

View File

@ -1,6 +1,7 @@
use crate::{
comp::{
buff::{Buff, BuffChange, BuffData, BuffKind, BuffSource},
character_state::OutputEvents,
CharacterState, StateUpdate,
},
event::ServerEvent,
@ -43,11 +44,11 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_move(data, &mut update, 0.8);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
match self.stage_section {
StageSection::Buildup => {
@ -68,7 +69,7 @@ impl CharacterBehavior for Data {
Vec::new(),
BuffSource::Character { by: *data.uid },
);
update.server_events.push_front(ServerEvent::Buff {
output_events.emit_server(ServerEvent::Buff {
entity: data.entity,
buff_change: BuffChange::Add(buff),
});

View File

@ -3,7 +3,7 @@ use crate::{
Attack, AttackDamage, AttackEffect, CombatEffect, CombatRequirement, Damage, DamageKind,
DamageSource, GroupTarget, Knockback,
},
comp::{shockwave, CharacterState, StateUpdate},
comp::{character_state::OutputEvents, shockwave, CharacterState, StateUpdate},
event::ServerEvent,
states::{
behavior::{CharacterBehavior, JoinData},
@ -62,7 +62,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
@ -117,7 +117,7 @@ impl CharacterBehavior for Data {
owner: Some(*data.uid),
specifier: self.static_data.specifier,
};
update.server_events.push_front(ServerEvent::Shockwave {
output_events.emit_server(ServerEvent::Shockwave {
properties,
pos: *data.pos,
ori: *data.ori,

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{CharacterState, InventoryAction, StateUpdate},
comp::{character_state::OutputEvents, CharacterState, InventoryAction, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
@ -9,11 +9,11 @@ use serde::{Deserialize, Serialize};
pub struct Data;
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_wield(data, &mut update);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
// Try to Fall/Stand up/Move
if data.physics.on_ground.is_none() || data.inputs.move_dir.magnitude_squared() > 0.0 {
@ -23,25 +23,30 @@ impl CharacterBehavior for Data {
update
}
fn manipulate_loadout(&self, data: &JoinData, inv_action: InventoryAction) -> StateUpdate {
fn manipulate_loadout(
&self,
data: &JoinData,
output_events: &mut OutputEvents,
inv_action: InventoryAction,
) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(data, &mut update, inv_action);
handle_manipulate_loadout(data, output_events, &mut update, inv_action);
update
}
fn wield(&self, data: &JoinData) -> StateUpdate {
fn wield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_wield(data, &mut update);
update
}
fn dance(&self, data: &JoinData) -> StateUpdate {
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_dance(data, &mut update);
update
}
fn stand(&self, data: &JoinData) -> StateUpdate {
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
// Try to Fall/Stand up/Move
update.character = CharacterState::Idle;

View File

@ -1,18 +1,18 @@
use super::utils::*;
use crate::{
comp::{CharacterState, InventoryAction, StateUpdate},
comp::{character_state::OutputEvents, CharacterState, InventoryAction, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
pub struct Data;
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, 0.4);
handle_jump(data, &mut update, 1.0);
handle_jump(data, output_events, &mut update, 1.0);
handle_wield(data, &mut update);
handle_climb(data, &mut update);
handle_dodge_input(data, &mut update);
@ -25,43 +25,48 @@ impl CharacterBehavior for Data {
update
}
fn swap_equipped_weapons(&self, data: &JoinData) -> StateUpdate {
fn swap_equipped_weapons(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_swap_equipped_weapons(data, &mut update);
update
}
fn manipulate_loadout(&self, data: &JoinData, inv_action: InventoryAction) -> StateUpdate {
fn manipulate_loadout(
&self,
data: &JoinData,
output_events: &mut OutputEvents,
inv_action: InventoryAction,
) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(data, &mut update, inv_action);
handle_manipulate_loadout(data, output_events, &mut update, inv_action);
update
}
fn wield(&self, data: &JoinData) -> StateUpdate {
fn wield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_wield(data, &mut update);
update
}
fn glide_wield(&self, data: &JoinData) -> StateUpdate {
fn glide_wield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_glide_wield(data, &mut update);
update
}
fn sit(&self, data: &JoinData) -> StateUpdate {
fn sit(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_sit(data, &mut update);
update
}
fn dance(&self, data: &JoinData) -> StateUpdate {
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_dance(data, &mut update);
update
}
fn stand(&self, data: &JoinData) -> StateUpdate {
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
update.character = CharacterState::Idle;
update

View File

@ -3,7 +3,7 @@ use crate::{
Attack, AttackDamage, AttackEffect, CombatEffect, CombatRequirement, Damage, DamageKind,
DamageSource, GroupTarget, Knockback,
},
comp::{tool::ToolKind, CharacterState, Melee, StateUpdate},
comp::{character_state::OutputEvents, tool::ToolKind, CharacterState, Melee, StateUpdate},
consts::GRAVITY,
states::{
behavior::{CharacterBehavior, JoinData},
@ -71,7 +71,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
match self.static_data.movement_behavior {

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{CharacterState, InventoryManip, StateUpdate},
comp::{character_state::OutputEvents, CharacterState, InventoryManip, StateUpdate},
event::ServerEvent,
states::behavior::{CharacterBehavior, JoinData},
terrain::SpriteKind,
@ -41,7 +41,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
let ori_dir = Dir::from_unnormalized(Vec3::from(
@ -93,9 +93,7 @@ impl CharacterBehavior for Data {
} else {
// Create inventory manipulation event
let inv_manip = InventoryManip::Collect(self.static_data.sprite_pos);
update
.server_events
.push_front(ServerEvent::InventoryManip(data.entity, inv_manip));
output_events.emit_server(ServerEvent::InventoryManip(data.entity, inv_manip));
// Done
if self.static_data.was_wielded {
update.character = CharacterState::Wielding;

View File

@ -1,5 +1,5 @@
use crate::{
comp::{CharacterState, StateUpdate},
comp::{character_state::OutputEvents, CharacterState, StateUpdate},
event::ServerEvent,
spiral::Spiral2d,
states::{
@ -47,7 +47,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
match self.stage_section {
@ -119,7 +119,7 @@ impl CharacterBehavior for Data {
Vec3::new(sprite_pos.x as i32, sprite_pos.y as i32, z);
// Send server event to create sprite
update.server_events.push_front(ServerEvent::CreateSprite {
output_events.emit_server(ServerEvent::CreateSprite {
pos: sprite_pos,
sprite: self.static_data.sprite,
});

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{CharacterState, PoiseState, StateUpdate},
comp::{character_state::OutputEvents, CharacterState, PoiseState, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
@ -33,7 +33,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);

View File

@ -1,6 +1,6 @@
use super::utils::*;
use crate::{
comp::{CharacterState, InventoryAction, StateUpdate},
comp::{character_state::OutputEvents, CharacterState, InventoryAction, StateUpdate},
states::behavior::{CharacterBehavior, JoinData},
};
use serde::{Deserialize, Serialize};
@ -11,7 +11,7 @@ const TURN_RATE: f32 = 40.0;
pub struct Data;
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_wield(data, &mut update);
@ -20,33 +20,38 @@ impl CharacterBehavior for Data {
update
}
fn manipulate_loadout(&self, data: &JoinData, inv_action: InventoryAction) -> StateUpdate {
fn manipulate_loadout(
&self,
data: &JoinData,
output_events: &mut OutputEvents,
inv_action: InventoryAction,
) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_manipulate_loadout(data, &mut update, inv_action);
handle_manipulate_loadout(data, output_events, &mut update, inv_action);
update
}
fn wield(&self, data: &JoinData) -> StateUpdate {
fn wield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_wield(data, &mut update);
update
}
fn sit(&self, data: &JoinData) -> StateUpdate {
fn sit(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
update.character = CharacterState::Idle;
attempt_sit(data, &mut update);
update
}
fn dance(&self, data: &JoinData) -> StateUpdate {
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
update.character = CharacterState::Idle;
attempt_dance(data, &mut update);
update
}
fn stand(&self, data: &JoinData) -> StateUpdate {
fn stand(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
// Try to Fall/Stand up/Move
update.character = CharacterState::Idle;

View File

@ -2,6 +2,7 @@ use super::utils::*;
use crate::{
comp::{
buff::{BuffChange, BuffKind},
character_state::OutputEvents,
inventory::{
item::{ConsumableKind, ItemKind},
slot::{InvSlotId, Slot},
@ -47,7 +48,7 @@ pub struct Data {
}
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
match self.static_data.item_kind {
@ -86,7 +87,7 @@ impl CharacterBehavior for Data {
});
if let UsePoint::BuildupUse = use_point {
// Create inventory manipulation event
use_item(data, &mut update, self);
use_item(data, output_events, self);
}
}
},
@ -107,7 +108,7 @@ impl CharacterBehavior for Data {
});
if let UsePoint::UseRecover = use_point {
// Create inventory manipulation event
use_item(data, &mut update, self);
use_item(data, output_events, self);
}
}
},
@ -141,11 +142,11 @@ impl CharacterBehavior for Data {
if matches!(update.character, CharacterState::Roll(_)) {
// Remove potion/saturation effect if left the use item state early by rolling
update.server_events.push_front(ServerEvent::Buff {
output_events.emit_server(ServerEvent::Buff {
entity: data.entity,
buff_change: BuffChange::RemoveByKind(BuffKind::Potion),
});
update.server_events.push_front(ServerEvent::Buff {
output_events.emit_server(ServerEvent::Buff {
entity: data.entity,
buff_change: BuffChange::RemoveByKind(BuffKind::Saturation),
});
@ -201,7 +202,7 @@ enum UsePoint {
UseRecover,
}
fn use_item(data: &JoinData, update: &mut StateUpdate, state: &Data) {
fn use_item(data: &JoinData, output_events: &mut OutputEvents, state: &Data) {
// Check if the same item is in the slot
let item_is_same = data
.inventory
@ -212,8 +213,6 @@ fn use_item(data: &JoinData, update: &mut StateUpdate, state: &Data) {
if item_is_same {
// Create inventory manipulation event
let inv_manip = InventoryManip::Use(Slot::Inventory(state.static_data.inv_slot));
update
.server_events
.push_front(ServerEvent::InventoryManip(data.entity, inv_manip));
output_events.emit_server(ServerEvent::InventoryManip(data.entity, inv_manip));
}
}

View File

@ -3,6 +3,7 @@ use crate::{
combat,
comp::{
biped_large, biped_small,
character_state::OutputEvents,
inventory::slot::{EquipSlot, Slot},
item::{Hands, ItemKind, Tool, ToolKind},
quadruped_low, quadruped_medium, quadruped_small,
@ -390,21 +391,25 @@ pub fn handle_orientation(
// Direction is set to the override if one is provided, else if entity is
// strafing or attacking the horiontal component of the look direction is used,
// else the current horizontal movement direction is used
let dir = if let Some(dir_override) = dir_override {
dir_override
let target_ori = if let Some(dir_override) = dir_override {
dir_override.into()
} else if is_strafing(data, update) || update.character.is_attack() {
data.inputs.look_dir.to_horizontal().unwrap_or_default()
data.inputs
.look_dir
.to_horizontal()
.unwrap_or_default()
.into()
} else {
Dir::from_unnormalized(data.inputs.move_dir.into())
.unwrap_or_else(|| data.ori.to_horizontal().look_dir())
.map_or_else(|| data.ori.to_horizontal(), |dir| dir.into())
};
let rate = {
let angle = update.ori.look_dir().angle_between(*dir);
let angle = update.ori.angle_between(target_ori);
data.body.base_ori_rate() * efficiency * std::f32::consts::PI / angle
};
update.ori = update
.ori
.slerped_towards(dir.into(), (data.dt.0 * rate).min(1.0));
.slerped_towards(target_ori, (data.dt.0 * rate).min(1.0));
}
/// Updates components to move player as if theyre swimming
@ -627,6 +632,7 @@ pub fn attempt_swap_equipped_weapons(data: &JoinData<'_>, update: &mut StateUpda
/// Handles inventory manipulations that affect the loadout
pub fn handle_manipulate_loadout(
data: &JoinData<'_>,
output_events: &mut OutputEvents,
update: &mut StateUpdate,
inv_action: InventoryAction,
) {
@ -659,9 +665,8 @@ pub fn handle_manipulate_loadout(
});
} else {
// Else emit inventory action instantnaneously
update
.server_events
.push_front(ServerEvent::InventoryManip(data.entity, inv_action.into()));
output_events
.emit_server(ServerEvent::InventoryManip(data.entity, inv_action.into()));
}
},
InventoryAction::Collect(sprite_pos) => {
@ -768,9 +773,7 @@ pub fn handle_manipulate_loadout(
},
_ => {
// Else just do event instantaneously
update
.server_events
.push_front(ServerEvent::InventoryManip(data.entity, inv_action.into()));
output_events.emit_server(ServerEvent::InventoryManip(data.entity, inv_action.into()));
},
}
}
@ -793,12 +796,18 @@ pub fn attempt_glide_wield(data: &JoinData<'_>, update: &mut StateUpdate) {
}
/// Checks that player can jump and sends jump event if so
pub fn handle_jump(data: &JoinData<'_>, update: &mut StateUpdate, strength: f32) -> bool {
pub fn handle_jump(
data: &JoinData<'_>,
output_events: &mut OutputEvents,
// TODO: remove?
_update: &mut StateUpdate,
strength: f32,
) -> bool {
(input_is_pressed(data, InputKind::Jump) && data.physics.on_ground.is_some())
.then(|| data.body.jump_impulse())
.flatten()
.map(|impulse| {
update.local_events.push_front(LocalEvent::Jump(
output_events.emit_local(LocalEvent::Jump(
data.entity,
strength * impulse / data.mass.0 * data.stats.move_speed_modifier,
));
@ -876,24 +885,33 @@ pub fn handle_ability_input(data: &JoinData<'_>, update: &mut StateUpdate) {
}
}
pub fn handle_input(data: &JoinData<'_>, update: &mut StateUpdate, input: InputKind) {
pub fn handle_input(
data: &JoinData<'_>,
output_events: &mut OutputEvents,
update: &mut StateUpdate,
input: InputKind,
) {
match input {
InputKind::Primary | InputKind::Secondary | InputKind::Ability(_) => {
handle_ability(data, update, input)
},
InputKind::Roll => handle_dodge_input(data, update),
InputKind::Jump => {
handle_jump(data, update, 1.0);
handle_jump(data, output_events, update, 1.0);
},
InputKind::Block => handle_block_input(data, update),
InputKind::Fly => {},
}
}
pub fn attempt_input(data: &JoinData<'_>, update: &mut StateUpdate) {
pub fn attempt_input(
data: &JoinData<'_>,
output_events: &mut OutputEvents,
update: &mut StateUpdate,
) {
// TODO: look into using first() when it becomes stable
if let Some(input) = data.controller.queued_inputs.keys().next() {
handle_input(data, update, *input);
handle_input(data, output_events, update, *input);
}
}

View File

@ -1,6 +1,7 @@
use super::utils::*;
use crate::{
comp::{
character_state::OutputEvents,
slot::{EquipSlot, Slot},
CharacterState, InventoryAction, StateUpdate,
},
@ -10,24 +11,29 @@ use crate::{
pub struct Data;
impl CharacterBehavior for Data {
fn behavior(&self, data: &JoinData) -> StateUpdate {
fn behavior(&self, data: &JoinData, output_events: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
handle_orientation(data, &mut update, 1.0, None);
handle_move(data, &mut update, 1.0);
handle_climb(data, &mut update);
attempt_input(data, &mut update);
attempt_input(data, output_events, &mut update);
update
}
fn swap_equipped_weapons(&self, data: &JoinData) -> StateUpdate {
fn swap_equipped_weapons(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_swap_equipped_weapons(data, &mut update);
update
}
fn manipulate_loadout(&self, data: &JoinData, inv_action: InventoryAction) -> StateUpdate {
fn manipulate_loadout(
&self,
data: &JoinData,
output_events: &mut OutputEvents,
inv_action: InventoryAction,
) -> StateUpdate {
let mut update = StateUpdate::from(data);
match inv_action {
InventoryAction::Drop(EquipSlot::ActiveMainhand | EquipSlot::ActiveOffhand)
@ -40,35 +46,35 @@ impl CharacterBehavior for Data {
},
_ => (),
}
handle_manipulate_loadout(data, &mut update, inv_action);
handle_manipulate_loadout(data, output_events, &mut update, inv_action);
update
}
fn glide_wield(&self, data: &JoinData) -> StateUpdate {
fn glide_wield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_glide_wield(data, &mut update);
update
}
fn unwield(&self, data: &JoinData) -> StateUpdate {
fn unwield(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
update.character = CharacterState::Idle;
update
}
fn sit(&self, data: &JoinData) -> StateUpdate {
fn sit(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_sit(data, &mut update);
update
}
fn dance(&self, data: &JoinData) -> StateUpdate {
fn dance(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_dance(data, &mut update);
update
}
fn sneak(&self, data: &JoinData) -> StateUpdate {
fn sneak(&self, data: &JoinData, _: &mut OutputEvents) -> StateUpdate {
let mut update = StateUpdate::from(data);
attempt_sneak(data, &mut update);
update

View File

@ -5,11 +5,12 @@ use specs::{
use common::{
comp::{
self, inventory::item::MaterialStatManifest, Beam, Body, CharacterState, Combo, Controller,
Density, Energy, Health, Inventory, InventoryManip, Mass, Melee, Mounting, Ori,
PhysicsState, Poise, PoiseState, Pos, SkillSet, StateUpdate, Stats, Vel,
self, character_state::OutputEvents, inventory::item::MaterialStatManifest, Beam, Body,
CharacterState, Combo, Controller, Density, Energy, Health, Inventory, InventoryManip,
Mass, Melee, Mounting, Ori, PhysicsState, Poise, PoiseState, Pos, SkillSet, StateUpdate,
Stats, Vel,
},
event::{Emitter, EventBus, LocalEvent, ServerEvent},
event::{EventBus, LocalEvent, ServerEvent},
outcome::Outcome,
resources::DeltaTime,
states::behavior::{JoinData, JoinStruct},
@ -86,6 +87,10 @@ impl<'a> System<'a> for Sys {
let mut server_emitter = read_data.server_bus.emitter();
let mut local_emitter = read_data.local_bus.emitter();
let mut local_events = Vec::new();
let mut server_events = Vec::new();
let mut output_events = OutputEvents::new(&mut local_events, &mut server_events);
for (
entity,
uid,
@ -257,13 +262,8 @@ impl<'a> System<'a> for Sys {
&read_data.dt,
&read_data.msm,
);
let state_update = j.character.handle_event(&j, action);
Self::publish_state_update(
&mut join_struct,
state_update,
&mut local_emitter,
&mut server_emitter,
);
let state_update = j.character.handle_event(&j, &mut output_events, action);
Self::publish_state_update(&mut join_struct, state_update, &mut output_events);
}
// Mounted occurs after control actions have been handled
@ -283,14 +283,12 @@ impl<'a> System<'a> for Sys {
&read_data.msm,
);
let state_update = j.character.behavior(&j);
Self::publish_state_update(
&mut join_struct,
state_update,
&mut local_emitter,
&mut server_emitter,
);
let state_update = j.character.behavior(&j, &mut output_events);
Self::publish_state_update(&mut join_struct, state_update, &mut output_events);
}
local_emitter.append_vec(local_events);
server_emitter.append_vec(server_events);
}
}
@ -298,12 +296,8 @@ impl Sys {
fn publish_state_update(
join: &mut JoinStruct,
mut state_update: StateUpdate,
local_emitter: &mut Emitter<LocalEvent>,
server_emitter: &mut Emitter<ServerEvent>,
output_events: &mut OutputEvents,
) {
local_emitter.append(&mut state_update.local_events);
server_emitter.append(&mut state_update.server_events);
// TODO: if checking equality is expensive use optional field in StateUpdate
if *join.char_state != state_update.character {
*join.char_state = state_update.character
@ -320,7 +314,7 @@ impl Sys {
join.controller.queued_inputs.remove(&input);
}
if state_update.swap_equipped_weapons {
server_emitter.emit(ServerEvent::InventoryManip(
output_events.emit_server(ServerEvent::InventoryManip(
join.entity,
InventoryManip::SwapEquippedWeapons,
));