mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'zesterer/small-fixes' into 'master'
Added entity event system, fixed fall damage See merge request veloren/veloren!418
This commit is contained in:
commit
d5aee13c91
47
common/src/event.rs
Normal file
47
common/src/event.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
use specs::Entity as EcsEntity;
|
||||||
|
use std::{collections::VecDeque, ops::DerefMut, sync::Mutex};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
pub enum Event {
|
||||||
|
LandOnGround { entity: EcsEntity, vel: Vec3<f32> },
|
||||||
|
Explosion { pos: Vec3<f32>, radius: 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 emit(&self, event: Event) {
|
||||||
|
self.queue.lock().unwrap().push_front(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
@ -2,32 +2,47 @@ use crate::vol::{ReadVol, Vox};
|
|||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
pub trait RayUntil<V: Vox> = FnMut(&V) -> bool;
|
pub trait RayUntil<V: Vox> = FnMut(&V) -> bool;
|
||||||
|
pub trait RayForEach = FnMut(Vec3<i32>);
|
||||||
|
|
||||||
pub struct Ray<'a, V: ReadVol, F: RayUntil<V::Vox>> {
|
pub struct Ray<'a, V: ReadVol, F: RayUntil<V::Vox>, G: RayForEach> {
|
||||||
vol: &'a V,
|
vol: &'a V,
|
||||||
from: Vec3<f32>,
|
from: Vec3<f32>,
|
||||||
to: Vec3<f32>,
|
to: Vec3<f32>,
|
||||||
until: F,
|
until: F,
|
||||||
|
for_each: Option<G>,
|
||||||
max_iter: usize,
|
max_iter: usize,
|
||||||
ignore_error: bool,
|
ignore_error: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
|
impl<'a, V: ReadVol, F: RayUntil<V::Vox>, G: RayForEach> Ray<'a, V, F, G> {
|
||||||
pub fn new(vol: &'a V, from: Vec3<f32>, to: Vec3<f32>, until: F) -> Self {
|
pub fn new(vol: &'a V, from: Vec3<f32>, to: Vec3<f32>, until: F) -> Self {
|
||||||
Self {
|
Self {
|
||||||
vol,
|
vol,
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
until,
|
until,
|
||||||
|
for_each: None,
|
||||||
max_iter: 100,
|
max_iter: 100,
|
||||||
ignore_error: false,
|
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 }
|
Ray { until: f, ..self }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn for_each<H: RayForEach>(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 {
|
pub fn max_iter(mut self, max_iter: usize) -> Self {
|
||||||
self.max_iter = max_iter;
|
self.max_iter = max_iter;
|
||||||
self
|
self
|
||||||
@ -56,6 +71,11 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for_each
|
||||||
|
if let Some(g) = &mut self.for_each {
|
||||||
|
g(ipos);
|
||||||
|
}
|
||||||
|
|
||||||
match self.vol.get(ipos).map(|vox| (vox, (self.until)(vox))) {
|
match self.vol.get(ipos).map(|vox| (vox, (self.until)(vox))) {
|
||||||
Ok((vox, true)) => return (dist, Ok(Some(vox))),
|
Ok((vox, true)) => return (dist, Ok(Some(vox))),
|
||||||
Err(err) if !self.ignore_error => return (dist, Err(err)),
|
Err(err) if !self.ignore_error => return (dist, Err(err)),
|
||||||
|
@ -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();
|
||||||
@ -178,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.
|
||||||
@ -330,16 +315,15 @@ impl State {
|
|||||||
.for_each(|(pos, block)| {
|
.for_each(|(pos, block)| {
|
||||||
let _ = terrain.set(*pos, *block);
|
let _ = terrain.set(*pos, *block);
|
||||||
});
|
});
|
||||||
std::mem::swap(
|
self.ecs.write_resource::<TerrainChanges>().modified_blocks = std::mem::replace(
|
||||||
&mut self.ecs.write_resource::<BlockChange>().blocks,
|
&mut self.ecs.write_resource::<BlockChange>().blocks,
|
||||||
&mut self.ecs.write_resource::<TerrainChanges>().modified_blocks,
|
Default::default(),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clean up the state after a tick.
|
/// Clean up the state after a tick.
|
||||||
pub fn cleanup(&mut self) {
|
pub fn cleanup(&mut self) {
|
||||||
// Clean up data structures from the last tick.
|
// Clean up data structures from the last tick.
|
||||||
self.ecs.write_resource::<TerrainChanges>().clear();
|
self.ecs.write_resource::<TerrainChanges>().clear();
|
||||||
self.ecs.write_resource::<BlockChange>().clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use crate::{
|
|||||||
ActionState, Body, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, Scale, Stats, Vel,
|
ActionState, Body, Jumping, MoveDir, OnGround, Ori, Pos, Rolling, 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, Stats>,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
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,11 +60,12 @@ impl<'a> System<'a> for Sys {
|
|||||||
mut positions,
|
mut positions,
|
||||||
mut velocities,
|
mut velocities,
|
||||||
mut orientations,
|
mut orientations,
|
||||||
mut stats,
|
|
||||||
): 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, mut stat) in (
|
for (entity, a, scale, b, mut pos, mut vel, mut ori) in (
|
||||||
&entities,
|
&entities,
|
||||||
&action_states,
|
&action_states,
|
||||||
scales.maybe(),
|
scales.maybe(),
|
||||||
@ -70,7 +73,6 @@ impl<'a> System<'a> for Sys {
|
|||||||
&mut positions,
|
&mut positions,
|
||||||
&mut velocities,
|
&mut velocities,
|
||||||
&mut orientations,
|
&mut orientations,
|
||||||
&mut stats,
|
|
||||||
)
|
)
|
||||||
.join()
|
.join()
|
||||||
{
|
{
|
||||||
@ -210,12 +212,11 @@ impl<'a> System<'a> for Sys {
|
|||||||
|
|
||||||
// When the resolution direction is pointing upwards, we must be on the ground
|
// When the resolution direction is pointing upwards, we must be on the ground
|
||||||
if resolve_dir.z > 0.0 && vel.0.z <= 0.0 {
|
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;
|
on_ground = true;
|
||||||
|
|
||||||
|
if !was_on_ground {
|
||||||
|
event_emitter.emit(Event::LandOnGround { entity, vel: vel.0 });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the resolution direction is non-vertical, we must be colliding with a wall
|
// When the resolution direction is non-vertical, we must be colliding with a wall
|
||||||
|
@ -76,7 +76,11 @@ pub trait ReadVol: BaseVol {
|
|||||||
self.get(pos).unwrap()
|
self.get(pos).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ray(&self, from: Vec3<f32>, to: Vec3<f32>) -> Ray<Self, fn(&Self::Vox) -> bool>
|
fn ray(
|
||||||
|
&self,
|
||||||
|
from: Vec3<f32>,
|
||||||
|
to: Vec3<f32>,
|
||||||
|
) -> Ray<Self, fn(&Self::Vox) -> bool, fn(Vec3<i32>)>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,7 @@ use crate::Server;
|
|||||||
use chrono::{NaiveTime, Timelike};
|
use chrono::{NaiveTime, Timelike};
|
||||||
use common::{
|
use common::{
|
||||||
comp,
|
comp,
|
||||||
|
event::{Event as GameEvent, EventBus},
|
||||||
msg::ServerMsg,
|
msg::ServerMsg,
|
||||||
npc::{get_npc_name, NpcKind},
|
npc::{get_npc_name, NpcKind},
|
||||||
state::TimeOfDay,
|
state::TimeOfDay,
|
||||||
@ -147,10 +148,16 @@ lazy_static! {
|
|||||||
),
|
),
|
||||||
ChatCommand::new(
|
ChatCommand::new(
|
||||||
"lantern",
|
"lantern",
|
||||||
"{} ",
|
"{}",
|
||||||
"/lantern : adds/remove light near player",
|
"/lantern : adds/remove light near player",
|
||||||
handle_lantern,
|
handle_lantern,
|
||||||
),
|
),
|
||||||
|
ChatCommand::new(
|
||||||
|
"explosion",
|
||||||
|
"{}",
|
||||||
|
"/explosion <radius> : Explodes the ground around you",
|
||||||
|
handle_explosion,
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,6 +683,22 @@ fn handle_lantern(server: &mut Server, entity: EcsEntity, args: String, action:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_explosion(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||||
|
let radius = scan_fmt!(&args, action.arg_fmt, f32).unwrap_or(8.0);
|
||||||
|
|
||||||
|
match server.state.read_component_cloned::<comp::Pos>(entity) {
|
||||||
|
Some(pos) => server
|
||||||
|
.state
|
||||||
|
.ecs()
|
||||||
|
.read_resource::<EventBus>()
|
||||||
|
.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) {
|
fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||||
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
|
if let Ok(alias) = scan_fmt!(&args, action.arg_fmt, String) {
|
||||||
let ecs = server.state.ecs();
|
let ecs = server.state.ecs();
|
||||||
|
@ -17,9 +17,10 @@ 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::{BlockChange, State, TimeOfDay, Uid},
|
||||||
terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainMap},
|
terrain::{block::Block, TerrainChunk, TerrainChunkSize, TerrainMap},
|
||||||
vol::Vox,
|
vol::Vox,
|
||||||
vol::{ReadVol, VolSize},
|
vol::{ReadVol, VolSize},
|
||||||
@ -89,6 +90,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;
|
||||||
@ -205,6 +207,44 @@ 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 terrain = self.state.ecs().read_resource::<TerrainMap>();
|
||||||
|
let mut block_change = self.state.ecs().write_resource::<BlockChange>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GameEvent::Explosion { pos, radius } => {
|
||||||
|
const RAYS: usize = 500;
|
||||||
|
|
||||||
|
for _ in 0..RAYS {
|
||||||
|
let dir = Vec3::new(
|
||||||
|
rand::random::<f32>() - 0.5,
|
||||||
|
rand::random::<f32>() - 0.5,
|
||||||
|
rand::random::<f32>() - 0.5,
|
||||||
|
)
|
||||||
|
.normalized();
|
||||||
|
|
||||||
|
let _ = terrain
|
||||||
|
.ray(pos, pos + dir * radius)
|
||||||
|
.until(|_| rand::random::<f32>() < 0.05)
|
||||||
|
.for_each(|pos| block_change.set(pos, Block::empty()))
|
||||||
|
.cast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
@ -235,6 +275,9 @@ impl Server {
|
|||||||
frontend_events.append(&mut self.handle_new_connections()?);
|
frontend_events.append(&mut self.handle_new_connections()?);
|
||||||
frontend_events.append(&mut self.handle_new_messages()?);
|
frontend_events.append(&mut self.handle_new_messages()?);
|
||||||
|
|
||||||
|
// Handle game events
|
||||||
|
self.handle_events();
|
||||||
|
|
||||||
// 4) Tick the client's LocalState.
|
// 4) Tick the client's LocalState.
|
||||||
self.state.tick(dt);
|
self.state.tick(dt);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user