From 98a913195b5e22681bba0ad79c4e343a51e65755 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 7 Aug 2019 10:50:49 +0100 Subject: [PATCH 1/4] Added entity event system, fixed fall damage --- common/src/comp/event.rs | 30 ++++++++++++++++++++++++++++++ common/src/comp/mod.rs | 2 ++ common/src/state.rs | 1 + common/src/sys/event_handler.rs | 33 +++++++++++++++++++++++++++++++++ common/src/sys/mod.rs | 7 +++++++ common/src/sys/phys.rs | 27 ++++++++++++++++----------- 6 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 common/src/comp/event.rs create mode 100644 common/src/sys/event_handler.rs diff --git a/common/src/comp/event.rs b/common/src/comp/event.rs new file mode 100644 index 0000000000..bed74d4669 --- /dev/null +++ b/common/src/comp/event.rs @@ -0,0 +1,30 @@ +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 bee5458a2c..54ac7dd856 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -3,6 +3,7 @@ mod agent; mod animation; mod body; mod controller; +mod event; mod inputs; mod inventory; mod last; @@ -17,6 +18,7 @@ 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/state.rs b/common/src/state.rs index 0a5a4ef7af..81cfc2d7bb 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -161,6 +161,7 @@ impl State { ecs.register::(); ecs.register::(); ecs.register::(); + ecs.register::(); // Controller effects ecs.register::(); ecs.register::(); diff --git a/common/src/sys/event_handler.rs b/common/src/sys/event_handler.rs new file mode 100644 index 0000000000..c7f6e72198 --- /dev/null +++ b/common/src/sys/event_handler.rs @@ -0,0 +1,33 @@ +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 7664b4af8a..a71a03bdcb 100644 --- a/common/src/sys/mod.rs +++ b/common/src/sys/mod.rs @@ -3,6 +3,7 @@ pub mod agent; pub mod animation; pub mod combat; pub mod controller; +mod event_handler; pub mod movement; pub mod phys; mod stats; @@ -19,6 +20,7 @@ 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, &[]); @@ -33,4 +35,9 @@ 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 de3045b0a6..674e7cd5fb 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -1,8 +1,8 @@ use crate::{ comp::HealthSource, comp::{ - ActionState, Body, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, Scale, Stats, Vel, - Wielding, + ActionState, Body, EntityEvent, Events, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, + Scale, Stats, Vel, Wielding, }, state::DeltaTime, terrain::TerrainMap, @@ -42,7 +42,7 @@ impl<'a> System<'a> for Sys { WriteStorage<'a, Pos>, WriteStorage<'a, Vel>, WriteStorage<'a, Ori>, - WriteStorage<'a, Stats>, + WriteStorage<'a, Events>, ); fn run( @@ -58,11 +58,11 @@ impl<'a> System<'a> for Sys { mut positions, mut velocities, mut orientations, - mut stats, + mut events, ): Self::SystemData, ) { // Apply movement inputs - for (entity, a, scale, b, mut pos, mut vel, mut ori, mut stat) in ( + for (entity, a, scale, b, mut pos, mut vel, mut ori) in ( &entities, &action_states, scales.maybe(), @@ -70,7 +70,6 @@ impl<'a> System<'a> for Sys { &mut positions, &mut velocities, &mut orientations, - &mut stats, ) .join() { @@ -210,12 +209,18 @@ impl<'a> System<'a> for Sys { // When the resolution direction is pointing upwards, we must be on the ground if resolve_dir.z > 0.0 && vel.0.z <= 0.0 { - // Check for fall damage - let falldmg = (vel.0.z / 1.5 + 6.0) as i32; - if falldmg < 0 { - stat.health.change_by(falldmg, HealthSource::World); - } 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 })); + } } // When the resolution direction is non-vertical, we must be colliding with a wall From 192f5d355f59ee5b0773b8c4ef35bd1f99de0e65 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 7 Aug 2019 16:39:16 +0100 Subject: [PATCH 2/4] Switched to EventBus system --- common/src/comp/event.rs | 30 ----------------------- common/src/comp/mod.rs | 2 -- common/src/event.rs | 42 +++++++++++++++++++++++++++++++++ common/src/lib.rs | 1 + common/src/state.rs | 24 ++++--------------- common/src/sys/event_handler.rs | 33 -------------------------- common/src/sys/mod.rs | 7 ------ common/src/sys/phys.rs | 22 +++++++---------- server/src/lib.rs | 23 ++++++++++++++++++ 9 files changed, 79 insertions(+), 105 deletions(-) delete mode 100644 common/src/comp/event.rs create mode 100644 common/src/event.rs delete mode 100644 common/src/sys/event_handler.rs 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(); From 5b62531da3081023edb81a4b6252e597a6312400 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 7 Aug 2019 18:17:04 +0100 Subject: [PATCH 3/4] Added /explosion command --- common/src/event.rs | 5 +++++ common/src/ray.rs | 26 +++++++++++++++++++++++--- common/src/state.rs | 7 +++---- common/src/vol.rs | 6 +++++- server/src/cmd.rs | 25 ++++++++++++++++++++++++- server/src/lib.rs | 28 ++++++++++++++++++++++++---- 6 files changed, 84 insertions(+), 13 deletions(-) diff --git a/common/src/event.rs b/common/src/event.rs index e9cef710d1..8332317593 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -4,6 +4,7 @@ use vek::*; pub enum Event { LandOnGround { entity: EcsEntity, vel: Vec3 }, + Explosion { pos: Vec3, radius: f32 }, } #[derive(Default)] @@ -19,6 +20,10 @@ impl EventBus { } } + pub fn emit(&self, event: Event) { + self.queue.lock().unwrap().push_front(event); + } + pub fn recv_all(&self) -> impl ExactSizeIterator { std::mem::replace(self.queue.lock().unwrap().deref_mut(), VecDeque::new()).into_iter() } diff --git a/common/src/ray.rs b/common/src/ray.rs index 98fb20475b..741581cbac 100644 --- a/common/src/ray.rs +++ b/common/src/ray.rs @@ -2,32 +2,47 @@ use crate::vol::{ReadVol, Vox}; use vek::*; pub trait RayUntil = FnMut(&V) -> bool; +pub trait RayForEach = FnMut(Vec3); -pub struct Ray<'a, V: ReadVol, F: RayUntil> { +pub struct Ray<'a, V: ReadVol, F: RayUntil, G: RayForEach> { vol: &'a V, from: Vec3, to: Vec3, until: F, + for_each: Option, max_iter: usize, ignore_error: bool, } -impl<'a, V: ReadVol, F: RayUntil> Ray<'a, V, F> { +impl<'a, V: ReadVol, F: RayUntil, G: RayForEach> Ray<'a, V, F, G> { pub fn new(vol: &'a V, from: Vec3, to: Vec3, until: F) -> Self { Self { vol, from, to, until, + for_each: None, max_iter: 100, ignore_error: false, } } - pub fn until(self, f: F) -> Ray<'a, V, F> { + pub fn until(self, f: F) -> Ray<'a, V, F, G> { Ray { until: f, ..self } } + pub fn for_each(self, f: H) -> Ray<'a, V, F, H> { + Ray { + for_each: Some(f), + vol: self.vol, + from: self.from, + to: self.to, + until: self.until, + max_iter: self.max_iter, + ignore_error: self.ignore_error, + } + } + pub fn max_iter(mut self, max_iter: usize) -> Self { self.max_iter = max_iter; self @@ -56,6 +71,11 @@ impl<'a, V: ReadVol, F: RayUntil> Ray<'a, V, F> { break; } + // for_each + if let Some(g) = &mut self.for_each { + g(ipos); + } + match self.vol.get(ipos).map(|vox| (vox, (self.until)(vox))) { Ok((vox, true)) => return (dist, Ok(Some(vox))), Err(err) if !self.ignore_error => return (dist, Err(err)), diff --git a/common/src/state.rs b/common/src/state.rs index 65046bc4dd..2a19a74da9 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -315,16 +315,15 @@ impl State { .for_each(|(pos, block)| { let _ = terrain.set(*pos, *block); }); - std::mem::swap( + self.ecs.write_resource::().modified_blocks = std::mem::replace( &mut self.ecs.write_resource::().blocks, - &mut self.ecs.write_resource::().modified_blocks, - ) + Default::default(), + ); } /// Clean up the state after a tick. pub fn cleanup(&mut self) { // Clean up data structures from the last tick. self.ecs.write_resource::().clear(); - self.ecs.write_resource::().clear(); } } diff --git a/common/src/vol.rs b/common/src/vol.rs index 47307344fc..266a3193a9 100644 --- a/common/src/vol.rs +++ b/common/src/vol.rs @@ -76,7 +76,11 @@ pub trait ReadVol: BaseVol { self.get(pos).unwrap() } - fn ray(&self, from: Vec3, to: Vec3) -> Ray bool> + fn ray( + &self, + from: Vec3, + to: Vec3, + ) -> Ray bool, fn(Vec3)> where Self: Sized, { diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 45865c334b..3915d7abdf 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -6,6 +6,7 @@ use crate::Server; use chrono::{NaiveTime, Timelike}; use common::{ comp, + event::{Event as GameEvent, EventBus}, msg::ServerMsg, npc::{get_npc_name, NpcKind}, state::TimeOfDay, @@ -147,10 +148,16 @@ lazy_static! { ), ChatCommand::new( "lantern", - "{} ", + "{}", "/lantern : adds/remove light near player", handle_lantern, ), + ChatCommand::new( + "explosion", + "{}", + "/explosion : Explodes the ground around you", + handle_explosion, + ), ]; } @@ -669,6 +676,22 @@ fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action: } } +fn handle_explosion(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { + if let Ok(radius) = scan_fmt!(&args, action.arg_fmt, f32) { + match server.state.read_component_cloned::(entity) { + Some(pos) => server + .state + .ecs() + .read_resource::() + .emit(GameEvent::Explosion { pos: pos.0, radius }), + None => server.clients.notify( + entity, + ServerMsg::private(String::from("You have no position!")), + ), + } + } +} + fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) { let ecs = server.state.ecs(); diff --git a/server/src/lib.rs b/server/src/lib.rs index 7650108e2f..712e440300 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -18,7 +18,7 @@ use common::{ event::{Event as GameEvent, EventBus}, msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg}, net::PostOffice, - state::{State, TimeOfDay, Uid}, + state::{BlockChange, State, TimeOfDay, Uid}, terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainMap}, vol::Vox, vol::{ReadVol, VolSize}, @@ -203,6 +203,8 @@ impl Server { /// Handle events coming through via the event bus fn handle_events(&mut self) { + let terrain = self.state.ecs().read_resource::(); + let mut block_change = self.state.ecs().write_resource::(); let mut stats = self.state.ecs().write_storage::(); for event in self.state.ecs().read_resource::().recv_all() { @@ -215,6 +217,24 @@ impl Server { } } } + GameEvent::Explosion { pos, radius } => { + const RAYS: usize = 500; + + for _ in 0..RAYS { + let dir = Vec3::new( + rand::random::() - 0.5, + rand::random::() - 0.5, + rand::random::() - 0.5, + ) + .normalized(); + + let _ = terrain + .ray(pos, pos + dir * radius) + .until(|_| rand::random::() < 0.05) + .for_each(|pos| block_change.set(pos, Block::empty())) + .cast(); + } + } } } } @@ -249,6 +269,9 @@ impl Server { frontend_events.append(&mut self.handle_new_connections()?); frontend_events.append(&mut self.handle_new_messages()?); + // Handle game events + self.handle_events(); + // 4) Tick the client's LocalState. self.state.tick(dt); @@ -371,9 +394,6 @@ 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(); From e6f384fc11eef11c4d0f6b38af2022e6413986a7 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 7 Aug 2019 18:18:32 +0100 Subject: [PATCH 4/4] Added default explosion radius --- server/src/cmd.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 3915d7abdf..e5d9e8bbc5 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -677,18 +677,18 @@ fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action: } fn handle_explosion(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { - if let Ok(radius) = scan_fmt!(&args, action.arg_fmt, f32) { - match server.state.read_component_cloned::(entity) { - Some(pos) => server - .state - .ecs() - .read_resource::() - .emit(GameEvent::Explosion { pos: pos.0, radius }), - None => server.clients.notify( - entity, - ServerMsg::private(String::from("You have no position!")), - ), - } + let radius = scan_fmt!(&args, action.arg_fmt, f32).unwrap_or(8.0); + + match server.state.read_component_cloned::(entity) { + Some(pos) => server + .state + .ecs() + .read_resource::() + .emit(GameEvent::Explosion { pos: pos.0, radius }), + None => server.clients.notify( + entity, + ServerMsg::private(String::from("You have no position!")), + ), } }