veloren/server/src/rtsim/tick.rs

106 lines
3.6 KiB
Rust
Raw Normal View History

use super::*;
use common::{
event::{EventBus, ServerEvent},
terrain::TerrainGrid,
state::DeltaTime,
comp,
};
use specs::{Join, Read, ReadStorage, WriteStorage, System, WriteExpect, ReadExpect};
use std::sync::Arc;
const ENTITY_TICK_PERIOD: u64 = 30;
pub struct Sys;
impl<'a> System<'a> for Sys {
type SystemData = (
Read<'a, DeltaTime>,
Read<'a, EventBus<ServerEvent>>,
WriteExpect<'a, RtSim>,
ReadExpect<'a, TerrainGrid>,
ReadExpect<'a, Arc<world::World>>,
ReadExpect<'a, world::IndexOwned>,
2020-11-12 00:08:28 +00:00
ReadStorage<'a, comp::Pos>,
ReadStorage<'a, RtSimEntity>,
WriteStorage<'a, comp::Agent>,
);
fn run(
&mut self,
(
dt,
server_event_bus,
mut rtsim,
terrain,
world,
index,
2020-11-12 00:08:28 +00:00
positions,
rtsim_entities,
mut agents,
): Self::SystemData,
) {
let rtsim = &mut *rtsim;
rtsim.tick += 1;
2020-11-12 00:08:28 +00:00
// Update rtsim entities
// TODO: don't update all of them each tick
let mut to_reify = Vec::new();
for (id, entity) in rtsim.entities.iter_mut() {
if entity.is_loaded {
// No load-specific behaviour yet
} else if rtsim.chunks.chunk_at(entity.pos.xy()).map(|c| c.is_loaded).unwrap_or(false) {
to_reify.push(id);
} else {
// Simulate behaviour
if let Some(travel_to) = entity.controller.travel_to {
// Move towards target at approximate character speed
entity.pos += Vec3::from((travel_to.xy() - entity.pos.xy())
.try_normalized()
.unwrap_or_else(Vec2::zero)
* entity.get_body().max_speed_approx()
* entity.controller.speed_factor)
* dt.0;
}
if let Some(alt) = world.sim().get_alt_approx(entity.pos.xy().map(|e| e.floor() as i32)) {
entity.pos.z = alt;
}
}
// Tick entity AI
if entity.last_tick + ENTITY_TICK_PERIOD <= rtsim.tick {
entity.tick(&terrain, &world);
entity.last_tick = rtsim.tick;
}
}
let mut server_emitter = server_event_bus.emitter();
for id in to_reify {
rtsim.reify_entity(id);
let entity = &rtsim.entities[id];
let spawn_pos = terrain.find_space(entity.pos.map(|e| e.floor() as i32)).map(|e| e as f32) + Vec3::new(0.5, 0.5, 0.0);
let body = entity.get_body();
server_emitter.emit(ServerEvent::CreateNpc {
pos: comp::Pos(spawn_pos),
stats: comp::Stats::new("Traveller [rt]".to_string(), body),
health: comp::Health::new(body, 10),
loadout: entity.get_loadout(),
body,
agent: Some(comp::Agent::new(None, true, &body)),
alignment: comp::Alignment::Npc,
scale: comp::Scale(1.0),
drop_item: None,
home_chunk: None,
rtsim_entity: Some(RtSimEntity(id)),
});
}
2020-11-12 00:08:28 +00:00
// Update rtsim with real entity data
for (pos, rtsim_entity, agent) in (&positions, &rtsim_entities, &mut agents).join() {
rtsim.entities.get_mut(rtsim_entity.0).map(|entity| {
entity.pos = pos.0;
agent.rtsim_controller = entity.controller.clone();
});
2020-11-12 00:08:28 +00:00
}
}
}