diff --git a/common/src/comp/event.rs b/common/src/comp/event.rs deleted file mode 100644 index bed74d4669..0000000000 --- a/common/src/comp/event.rs +++ /dev/null @@ -1,30 +0,0 @@ -use specs::Component; -use specs_idvs::IDVStorage; -use std::ops::{Deref, DerefMut}; -use vek::*; - -#[derive(Clone, Debug, Default)] -pub struct Events(pub Vec); - -impl Deref for Events { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Events { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Component for Events { - type Storage = IDVStorage; -} - -#[derive(Clone, Debug)] -pub enum EntityEvent { - HitGround { vel: Vec3 }, -} diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 54ac7dd856..bee5458a2c 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -3,7 +3,6 @@ mod agent; mod animation; mod body; mod controller; -mod event; mod inputs; mod inventory; mod last; @@ -18,7 +17,6 @@ pub use agent::Agent; pub use animation::{Animation, AnimationInfo}; pub use body::{humanoid, object, quadruped, quadruped_medium, Body}; pub use controller::Controller; -pub use event::{EntityEvent, Events}; pub use inputs::{ Attacking, CanBuild, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding, }; diff --git a/common/src/event.rs b/common/src/event.rs new file mode 100644 index 0000000000..e9cef710d1 --- /dev/null +++ b/common/src/event.rs @@ -0,0 +1,42 @@ +use specs::Entity as EcsEntity; +use std::{collections::VecDeque, ops::DerefMut, sync::Mutex}; +use vek::*; + +pub enum Event { + LandOnGround { entity: EcsEntity, vel: Vec3 }, +} + +#[derive(Default)] +pub struct EventBus { + queue: Mutex>, +} + +impl EventBus { + pub fn emitter(&self) -> Emitter { + Emitter { + bus: self, + events: VecDeque::new(), + } + } + + pub fn recv_all(&self) -> impl ExactSizeIterator { + std::mem::replace(self.queue.lock().unwrap().deref_mut(), VecDeque::new()).into_iter() + } +} + +pub struct Emitter<'a> { + bus: &'a EventBus, + events: VecDeque, +} + +impl<'a> Emitter<'a> { + pub fn emit(&mut self, event: Event) { + self.events.push_front(event); + } +} + +impl<'a> Drop for Emitter<'a> { + fn drop(&mut self) { + self.bus.queue.lock().unwrap().append(&mut self.events); + } +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 42f30e0e23..e128100c78 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -15,6 +15,7 @@ extern crate log; pub mod assets; pub mod clock; pub mod comp; +pub mod event; pub mod figure; pub mod msg; pub mod npc; diff --git a/common/src/state.rs b/common/src/state.rs index 81cfc2d7bb..65046bc4dd 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -3,6 +3,7 @@ pub use sphynx::Uid; use crate::{ comp, + event::EventBus, msg::{EcsCompPacket, EcsResPacket}, sys, terrain::{Block, TerrainChunk, TerrainMap}, @@ -42,18 +43,11 @@ pub struct DeltaTime(pub f32); /// lag. Ideally, we'd avoid such a situation. const MAX_DELTA_TIME: f32 = 1.0; +#[derive(Default)] pub struct BlockChange { blocks: FxHashMap, Block>, } -impl Default for BlockChange { - fn default() -> Self { - Self { - blocks: FxHashMap::default(), - } - } -} - impl BlockChange { pub fn set(&mut self, pos: Vec3, block: Block) { self.blocks.insert(pos, block); @@ -64,6 +58,7 @@ impl BlockChange { } } +#[derive(Default)] pub struct TerrainChanges { pub new_chunks: FxHashSet>, pub modified_chunks: FxHashSet>, @@ -71,17 +66,6 @@ pub struct TerrainChanges { pub modified_blocks: FxHashMap, Block>, } -impl Default for TerrainChanges { - fn default() -> Self { - Self { - new_chunks: FxHashSet::default(), - modified_chunks: FxHashSet::default(), - removed_chunks: FxHashSet::default(), - modified_blocks: FxHashMap::default(), - } - } -} - impl TerrainChanges { pub fn clear(&mut self) { self.new_chunks.clear(); @@ -161,7 +145,6 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); - ecs.register::(); // Controller effects ecs.register::(); ecs.register::(); @@ -179,6 +162,7 @@ impl State { ecs.add_resource(TerrainMap::new().unwrap()); ecs.add_resource(BlockChange::default()); ecs.add_resource(TerrainChanges::default()); + ecs.add_resource(EventBus::default()); } /// Register a component with the state's ECS. diff --git a/common/src/sys/event_handler.rs b/common/src/sys/event_handler.rs deleted file mode 100644 index c7f6e72198..0000000000 --- a/common/src/sys/event_handler.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::{ - comp::{EntityEvent, Events, HealthSource, Stats}, - state::DeltaTime, -}; -use log::warn; -use specs::{Entities, Join, Read, System, WriteStorage}; - -/// This system kills players -pub struct Sys; -impl<'a> System<'a> for Sys { - type SystemData = ( - Entities<'a>, - WriteStorage<'a, Events>, - WriteStorage<'a, Stats>, - ); - - fn run(&mut self, (entities, mut events, mut stats): Self::SystemData) { - for (entity, mut events) in (&entities, &mut events).join() { - for event in events.drain(..) { - match event { - EntityEvent::HitGround { vel } => { - if let Some(stat) = stats.get_mut(entity) { - let falldmg = (vel.z / 1.5 + 6.0) as i32; - if falldmg < 0 { - stat.health.change_by(falldmg, HealthSource::World); - } - } - } - } - } - } - } -} diff --git a/common/src/sys/mod.rs b/common/src/sys/mod.rs index a71a03bdcb..7664b4af8a 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -3,7 +3,6 @@ pub mod agent; pub mod animation; pub mod combat; pub mod controller; -mod event_handler; pub mod movement; pub mod phys; mod stats; @@ -20,7 +19,6 @@ const MOVEMENT_SYS: &str = "movement_sys"; const COMBAT_SYS: &str = "combat_sys"; const ANIMATION_SYS: &str = "animation_sys"; const STATS_SYS: &str = "stats_sys"; -const EVENT_HANDLER_SYS: &str = "event_handler_sys"; pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(agent::Sys, AGENT_SYS, &[]); @@ -35,9 +33,4 @@ pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) { dispatch_builder.add(combat::Sys, COMBAT_SYS, &[ACTION_STATE_SYS]); dispatch_builder.add(animation::Sys, ANIMATION_SYS, &[ACTION_STATE_SYS]); dispatch_builder.add(stats::Sys, STATS_SYS, &[COMBAT_SYS]); - dispatch_builder.add( - event_handler::Sys, - EVENT_HANDLER_SYS, - &[AGENT_SYS, PHYS_SYS, ACTION_STATE_SYS, COMBAT_SYS], - ); } diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 674e7cd5fb..dadc527fd7 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -1,9 +1,10 @@ use crate::{ comp::HealthSource, comp::{ - ActionState, Body, EntityEvent, Events, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, - Scale, Stats, Vel, Wielding, + ActionState, Body, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, Scale, Stats, Vel, + Wielding, }, + event::{Event, EventBus}, state::DeltaTime, terrain::TerrainMap, vol::{ReadVol, Vox}, @@ -35,6 +36,7 @@ impl<'a> System<'a> for Sys { Entities<'a>, ReadExpect<'a, TerrainMap>, Read<'a, DeltaTime>, + Read<'a, EventBus>, ReadStorage<'a, ActionState>, ReadStorage<'a, Scale>, ReadStorage<'a, Body>, @@ -42,7 +44,6 @@ impl<'a> System<'a> for Sys { WriteStorage<'a, Pos>, WriteStorage<'a, Vel>, WriteStorage<'a, Ori>, - WriteStorage<'a, Events>, ); fn run( @@ -51,6 +52,7 @@ impl<'a> System<'a> for Sys { entities, terrain, dt, + event_bus, action_states, scales, bodies, @@ -58,9 +60,10 @@ impl<'a> System<'a> for Sys { mut positions, mut velocities, mut orientations, - mut events, ): Self::SystemData, ) { + let mut event_emitter = event_bus.emitter(); + // Apply movement inputs for (entity, a, scale, b, mut pos, mut vel, mut ori) in ( &entities, @@ -211,15 +214,8 @@ impl<'a> System<'a> for Sys { if resolve_dir.z > 0.0 && vel.0.z <= 0.0 { on_ground = true; - // Hitting the ground - const COLLISION_VEL: f32 = GRAVITY * 0.75; // Falling for 0.75 seconds - if vel.0.z < -COLLISION_VEL { - if events.get(entity).is_none() { - events.insert(entity, Events::default()); - } - events - .get_mut(entity) // TODO: Use get_mut_or_default when updating to SPECS 15 - .map(|e| e.push(EntityEvent::HitGround { vel: vel.0 })); + if !was_on_ground { + event_emitter.emit(Event::LandOnGround { entity, vel: vel.0 }); } } diff --git a/server/src/lib.rs b/server/src/lib.rs index f0cbf76fd5..7650108e2f 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -15,6 +15,7 @@ use crate::{ }; use common::{ comp, + event::{Event as GameEvent, EventBus}, msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg}, net::PostOffice, state::{State, TimeOfDay, Uid}, @@ -84,6 +85,7 @@ impl Server { state .ecs_mut() .add_resource(SpawnPoint(Vec3::new(16_384.0, 16_384.0, 380.0))); + state.ecs_mut().add_resource(EventBus::default()); // Set starting time for the server. state.ecs_mut().write_resource::().0 = settings.start_time; @@ -199,6 +201,24 @@ impl Server { client.allow_state(ClientState::Character); } + /// Handle events coming through via the event bus + fn handle_events(&mut self) { + let mut stats = self.state.ecs().write_storage::(); + + for event in self.state.ecs().read_resource::().recv_all() { + match event { + GameEvent::LandOnGround { entity, vel } => { + if let Some(stats) = stats.get_mut(entity) { + let falldmg = (vel.z / 1.5 + 10.0) as i32; + if falldmg < 0 { + stats.health.change_by(falldmg, comp::HealthSource::World); + } + } + } + } + } + } + /// Execute a single server tick, handle input and update the game state by the given duration. pub fn tick(&mut self, _input: Input, dt: Duration) -> Result, Error> { // This tick function is the centre of the Veloren universe. Most server-side things are @@ -351,6 +371,9 @@ impl Server { self.state.remove_chunk(key); } + // Handle events + self.handle_events(); + // 6) Synchronise clients with the new state of the world. self.sync_clients();