mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Switched to EventBus system
This commit is contained in:
@ -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<EntityEvent>);
|
|
||||||
|
|
||||||
impl Deref for Events {
|
|
||||||
type Target = Vec<EntityEvent>;
|
|
||||||
|
|
||||||
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<Self>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum EntityEvent {
|
|
||||||
HitGround { vel: Vec3<f32> },
|
|
||||||
}
|
|
@ -3,7 +3,6 @@ mod agent;
|
|||||||
mod animation;
|
mod animation;
|
||||||
mod body;
|
mod body;
|
||||||
mod controller;
|
mod controller;
|
||||||
mod event;
|
|
||||||
mod inputs;
|
mod inputs;
|
||||||
mod inventory;
|
mod inventory;
|
||||||
mod last;
|
mod last;
|
||||||
@ -18,7 +17,6 @@ pub use agent::Agent;
|
|||||||
pub use animation::{Animation, AnimationInfo};
|
pub use animation::{Animation, AnimationInfo};
|
||||||
pub use body::{humanoid, object, quadruped, quadruped_medium, Body};
|
pub use body::{humanoid, object, quadruped, quadruped_medium, Body};
|
||||||
pub use controller::Controller;
|
pub use controller::Controller;
|
||||||
pub use event::{EntityEvent, Events};
|
|
||||||
pub use inputs::{
|
pub use inputs::{
|
||||||
Attacking, CanBuild, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding,
|
Attacking, CanBuild, Gliding, Jumping, MoveDir, OnGround, Respawning, Rolling, Wielding,
|
||||||
};
|
};
|
||||||
|
42
common/src/event.rs
Normal file
42
common/src/event.rs
Normal file
@ -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<f32> },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct EventBus {
|
||||||
|
queue: Mutex<VecDeque<Event>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventBus {
|
||||||
|
pub fn emitter(&self) -> Emitter {
|
||||||
|
Emitter {
|
||||||
|
bus: self,
|
||||||
|
events: VecDeque::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recv_all(&self) -> impl ExactSizeIterator<Item = Event> {
|
||||||
|
std::mem::replace(self.queue.lock().unwrap().deref_mut(), VecDeque::new()).into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Emitter<'a> {
|
||||||
|
bus: &'a EventBus,
|
||||||
|
events: VecDeque<Event>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ extern crate log;
|
|||||||
pub mod assets;
|
pub mod assets;
|
||||||
pub mod clock;
|
pub mod clock;
|
||||||
pub mod comp;
|
pub mod comp;
|
||||||
|
pub mod event;
|
||||||
pub mod figure;
|
pub mod figure;
|
||||||
pub mod msg;
|
pub mod msg;
|
||||||
pub mod npc;
|
pub mod npc;
|
||||||
|
@ -3,6 +3,7 @@ pub use sphynx::Uid;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
comp,
|
comp,
|
||||||
|
event::EventBus,
|
||||||
msg::{EcsCompPacket, EcsResPacket},
|
msg::{EcsCompPacket, EcsResPacket},
|
||||||
sys,
|
sys,
|
||||||
terrain::{Block, TerrainChunk, TerrainMap},
|
terrain::{Block, TerrainChunk, TerrainMap},
|
||||||
@ -42,18 +43,11 @@ pub struct DeltaTime(pub f32);
|
|||||||
/// lag. Ideally, we'd avoid such a situation.
|
/// lag. Ideally, we'd avoid such a situation.
|
||||||
const MAX_DELTA_TIME: f32 = 1.0;
|
const MAX_DELTA_TIME: f32 = 1.0;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct BlockChange {
|
pub struct BlockChange {
|
||||||
blocks: FxHashMap<Vec3<i32>, Block>,
|
blocks: FxHashMap<Vec3<i32>, Block>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BlockChange {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
blocks: FxHashMap::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlockChange {
|
impl BlockChange {
|
||||||
pub fn set(&mut self, pos: Vec3<i32>, block: Block) {
|
pub fn set(&mut self, pos: Vec3<i32>, block: Block) {
|
||||||
self.blocks.insert(pos, block);
|
self.blocks.insert(pos, block);
|
||||||
@ -64,6 +58,7 @@ impl BlockChange {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct TerrainChanges {
|
pub struct TerrainChanges {
|
||||||
pub new_chunks: FxHashSet<Vec2<i32>>,
|
pub new_chunks: FxHashSet<Vec2<i32>>,
|
||||||
pub modified_chunks: FxHashSet<Vec2<i32>>,
|
pub modified_chunks: FxHashSet<Vec2<i32>>,
|
||||||
@ -71,17 +66,6 @@ pub struct TerrainChanges {
|
|||||||
pub modified_blocks: FxHashMap<Vec3<i32>, Block>,
|
pub modified_blocks: FxHashMap<Vec3<i32>, 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 {
|
impl TerrainChanges {
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.new_chunks.clear();
|
self.new_chunks.clear();
|
||||||
@ -161,7 +145,6 @@ impl State {
|
|||||||
ecs.register::<comp::ForceUpdate>();
|
ecs.register::<comp::ForceUpdate>();
|
||||||
ecs.register::<comp::InventoryUpdate>();
|
ecs.register::<comp::InventoryUpdate>();
|
||||||
ecs.register::<comp::Inventory>();
|
ecs.register::<comp::Inventory>();
|
||||||
ecs.register::<comp::Events>();
|
|
||||||
// Controller effects
|
// Controller effects
|
||||||
ecs.register::<comp::MoveDir>();
|
ecs.register::<comp::MoveDir>();
|
||||||
ecs.register::<comp::OnGround>();
|
ecs.register::<comp::OnGround>();
|
||||||
@ -179,6 +162,7 @@ impl State {
|
|||||||
ecs.add_resource(TerrainMap::new().unwrap());
|
ecs.add_resource(TerrainMap::new().unwrap());
|
||||||
ecs.add_resource(BlockChange::default());
|
ecs.add_resource(BlockChange::default());
|
||||||
ecs.add_resource(TerrainChanges::default());
|
ecs.add_resource(TerrainChanges::default());
|
||||||
|
ecs.add_resource(EventBus::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a component with the state's ECS.
|
/// Register a component with the state's ECS.
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,7 +3,6 @@ pub mod agent;
|
|||||||
pub mod animation;
|
pub mod animation;
|
||||||
pub mod combat;
|
pub mod combat;
|
||||||
pub mod controller;
|
pub mod controller;
|
||||||
mod event_handler;
|
|
||||||
pub mod movement;
|
pub mod movement;
|
||||||
pub mod phys;
|
pub mod phys;
|
||||||
mod stats;
|
mod stats;
|
||||||
@ -20,7 +19,6 @@ const MOVEMENT_SYS: &str = "movement_sys";
|
|||||||
const COMBAT_SYS: &str = "combat_sys";
|
const COMBAT_SYS: &str = "combat_sys";
|
||||||
const ANIMATION_SYS: &str = "animation_sys";
|
const ANIMATION_SYS: &str = "animation_sys";
|
||||||
const STATS_SYS: &str = "stats_sys";
|
const STATS_SYS: &str = "stats_sys";
|
||||||
const EVENT_HANDLER_SYS: &str = "event_handler_sys";
|
|
||||||
|
|
||||||
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
pub fn add_local_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||||
dispatch_builder.add(agent::Sys, AGENT_SYS, &[]);
|
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(combat::Sys, COMBAT_SYS, &[ACTION_STATE_SYS]);
|
||||||
dispatch_builder.add(animation::Sys, ANIMATION_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(stats::Sys, STATS_SYS, &[COMBAT_SYS]);
|
||||||
dispatch_builder.add(
|
|
||||||
event_handler::Sys,
|
|
||||||
EVENT_HANDLER_SYS,
|
|
||||||
&[AGENT_SYS, PHYS_SYS, ACTION_STATE_SYS, COMBAT_SYS],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
comp::HealthSource,
|
comp::HealthSource,
|
||||||
comp::{
|
comp::{
|
||||||
ActionState, Body, EntityEvent, Events, Jumping, MoveDir, OnGround, Ori, Pos, Rolling,
|
ActionState, Body, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, Scale, Stats, Vel,
|
||||||
Scale, Stats, Vel, Wielding,
|
Wielding,
|
||||||
},
|
},
|
||||||
|
event::{Event, EventBus},
|
||||||
state::DeltaTime,
|
state::DeltaTime,
|
||||||
terrain::TerrainMap,
|
terrain::TerrainMap,
|
||||||
vol::{ReadVol, Vox},
|
vol::{ReadVol, Vox},
|
||||||
@ -35,6 +36,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
Entities<'a>,
|
Entities<'a>,
|
||||||
ReadExpect<'a, TerrainMap>,
|
ReadExpect<'a, TerrainMap>,
|
||||||
Read<'a, DeltaTime>,
|
Read<'a, DeltaTime>,
|
||||||
|
Read<'a, EventBus>,
|
||||||
ReadStorage<'a, ActionState>,
|
ReadStorage<'a, ActionState>,
|
||||||
ReadStorage<'a, Scale>,
|
ReadStorage<'a, Scale>,
|
||||||
ReadStorage<'a, Body>,
|
ReadStorage<'a, Body>,
|
||||||
@ -42,7 +44,6 @@ impl<'a> System<'a> for Sys {
|
|||||||
WriteStorage<'a, Pos>,
|
WriteStorage<'a, Pos>,
|
||||||
WriteStorage<'a, Vel>,
|
WriteStorage<'a, Vel>,
|
||||||
WriteStorage<'a, Ori>,
|
WriteStorage<'a, Ori>,
|
||||||
WriteStorage<'a, Events>,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
@ -51,6 +52,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
entities,
|
entities,
|
||||||
terrain,
|
terrain,
|
||||||
dt,
|
dt,
|
||||||
|
event_bus,
|
||||||
action_states,
|
action_states,
|
||||||
scales,
|
scales,
|
||||||
bodies,
|
bodies,
|
||||||
@ -58,9 +60,10 @@ impl<'a> System<'a> for Sys {
|
|||||||
mut positions,
|
mut positions,
|
||||||
mut velocities,
|
mut velocities,
|
||||||
mut orientations,
|
mut orientations,
|
||||||
mut events,
|
|
||||||
): Self::SystemData,
|
): Self::SystemData,
|
||||||
) {
|
) {
|
||||||
|
let mut event_emitter = event_bus.emitter();
|
||||||
|
|
||||||
// Apply movement inputs
|
// Apply movement inputs
|
||||||
for (entity, a, scale, b, mut pos, mut vel, mut ori) in (
|
for (entity, a, scale, b, mut pos, mut vel, mut ori) in (
|
||||||
&entities,
|
&entities,
|
||||||
@ -211,15 +214,8 @@ impl<'a> System<'a> for Sys {
|
|||||||
if resolve_dir.z > 0.0 && vel.0.z <= 0.0 {
|
if resolve_dir.z > 0.0 && vel.0.z <= 0.0 {
|
||||||
on_ground = true;
|
on_ground = true;
|
||||||
|
|
||||||
// Hitting the ground
|
if !was_on_ground {
|
||||||
const COLLISION_VEL: f32 = GRAVITY * 0.75; // Falling for 0.75 seconds
|
event_emitter.emit(Event::LandOnGround { entity, vel: vel.0 });
|
||||||
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 }));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
comp,
|
comp,
|
||||||
|
event::{Event as GameEvent, EventBus},
|
||||||
msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg},
|
msg::{ClientMsg, ClientState, RequestStateError, ServerError, ServerInfo, ServerMsg},
|
||||||
net::PostOffice,
|
net::PostOffice,
|
||||||
state::{State, TimeOfDay, Uid},
|
state::{State, TimeOfDay, Uid},
|
||||||
@ -84,6 +85,7 @@ impl Server {
|
|||||||
state
|
state
|
||||||
.ecs_mut()
|
.ecs_mut()
|
||||||
.add_resource(SpawnPoint(Vec3::new(16_384.0, 16_384.0, 380.0)));
|
.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.
|
// Set starting time for the server.
|
||||||
state.ecs_mut().write_resource::<TimeOfDay>().0 = settings.start_time;
|
state.ecs_mut().write_resource::<TimeOfDay>().0 = settings.start_time;
|
||||||
@ -199,6 +201,24 @@ impl Server {
|
|||||||
client.allow_state(ClientState::Character);
|
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::<comp::Stats>();
|
||||||
|
|
||||||
|
for event in self.state.ecs().read_resource::<EventBus>().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.
|
/// 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<Vec<Event>, Error> {
|
pub fn tick(&mut self, _input: Input, dt: Duration) -> Result<Vec<Event>, Error> {
|
||||||
// This tick function is the centre of the Veloren universe. Most server-side things are
|
// 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);
|
self.state.remove_chunk(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle events
|
||||||
|
self.handle_events();
|
||||||
|
|
||||||
// 6) Synchronise clients with the new state of the world.
|
// 6) Synchronise clients with the new state of the world.
|
||||||
self.sync_clients();
|
self.sync_clients();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user