From 06d7548dc66e9c013b794e5e08a36a849222e7b2 Mon Sep 17 00:00:00 2001 From: Isse Date: Tue, 29 Aug 2023 12:56:25 +0000 Subject: [PATCH] Fix rtsim airships --- common/src/event.rs | 6 +++- rtsim/src/data/npc.rs | 2 +- rtsim/src/rule/simulate_npcs.rs | 13 ++++++-- server/src/lib.rs | 16 +++++++--- server/src/rtsim/mod.rs | 20 +++++++----- server/src/rtsim/tick.rs | 54 ++++++++++++++++++++------------- 6 files changed, 74 insertions(+), 37 deletions(-) diff --git a/common/src/event.rs b/common/src/event.rs index 07986b0589..94601da3ea 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -387,5 +387,9 @@ impl<'a, E> Emitter<'a, E> { } impl<'a, E> Drop for Emitter<'a, E> { - fn drop(&mut self) { self.bus.queue.lock().unwrap().append(&mut self.events); } + fn drop(&mut self) { + if !self.events.is_empty() { + self.bus.queue.lock().unwrap().append(&mut self.events); + } + } } diff --git a/rtsim/src/data/npc.rs b/rtsim/src/data/npc.rs index b6b707180e..121a12e3b5 100644 --- a/rtsim/src/data/npc.rs +++ b/rtsim/src/data/npc.rs @@ -258,7 +258,7 @@ impl Npc { } } -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct Riding { pub vehicle: VehicleId, pub steering: bool, diff --git a/rtsim/src/rule/simulate_npcs.rs b/rtsim/src/rule/simulate_npcs.rs index 82e45d2c39..4a29480779 100644 --- a/rtsim/src/rule/simulate_npcs.rs +++ b/rtsim/src/rule/simulate_npcs.rs @@ -183,7 +183,7 @@ fn on_tick(ctx: EventCtx) { match npc.controller.activity { // If steering, the NPC controls the vehicle's motion Some(NpcActivity::Goto(target, speed_factor)) if riding.steering => { - let diff = target.xy() - vehicle.wpos.xy(); + let diff = target - vehicle.wpos; let dist2 = diff.magnitude_squared(); if dist2 > 0.5f32.powi(2) { @@ -212,7 +212,7 @@ fn on_tick(ctx: EventCtx) { } vehicle.dir = (target.xy() - vehicle.wpos.xy()) .try_normalized() - .unwrap_or(Vec2::unit_y()); + .unwrap_or(vehicle.dir); } }, // When riding, other actions are disabled @@ -294,7 +294,7 @@ fn on_tick(ctx: EventCtx) { } } - for (_, vehicle) in data.npcs.vehicles.iter_mut() { + for (id, vehicle) in data.npcs.vehicles.iter_mut() { // Try to keep ships above ground and within the map if matches!(vehicle.mode, SimulationMode::Simulated) { vehicle.wpos = vehicle @@ -312,5 +312,12 @@ fn on_tick(ctx: EventCtx) { ), ); } + if let Some(Actor::Npc(driver)) = vehicle.driver + && data.npcs.npcs.get(driver).and_then(|driver| { + Some(driver.riding.as_ref()?.vehicle != id) + }).unwrap_or(true) + { + vehicle.driver = None; + } } } diff --git a/server/src/lib.rs b/server/src/lib.rs index d5aa548cea..fe7b14c373 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -809,6 +809,8 @@ impl Server { self.state.delete_component::(entity); } + let mut rtsim = self.state.ecs().write_resource::(); + let rtsim_entities = self.state.ecs().read_storage::(); // Remove NPCs that are outside the view distances of all players // This is done by removing NPCs in unloaded chunks let to_delete = { @@ -818,9 +820,15 @@ impl Server { &self.state.ecs().read_storage::(), !&self.state.ecs().read_storage::(), self.state.ecs().read_storage::().maybe(), + rtsim_entities.maybe(), ) .join() - .filter(|(_, pos, _, anchor)| { + .filter(|(_, pos, _, anchor, rtsim_entity)| { + if rtsim_entity.map_or(false, |rtsim_entity| { + !rtsim.can_unload_entity(*rtsim_entity) + }) { + return false; + } let chunk_key = terrain.pos_key(pos.0.map(|e| e.floor() as i32)); match anchor { Some(Anchor::Chunk(hc)) => { @@ -835,13 +843,11 @@ impl Server { None => terrain.get_key_real(chunk_key).is_none(), } }) - .map(|(entity, _, _, _)| entity) + .map(|(entity, _, _, _, _)| entity) .collect::>() }; { - let mut rtsim = self.state.ecs().write_resource::(); - let rtsim_entities = self.state.ecs().read_storage::(); let rtsim_vehicles = self.state.ecs().read_storage::(); // Assimilate entities that are part of the real-time world simulation @@ -856,6 +862,8 @@ impl Server { } } } + drop(rtsim_entities); + drop(rtsim); // Actually perform entity deletion for entity in to_delete { diff --git a/server/src/rtsim/mod.rs b/server/src/rtsim/mod.rs index 3b8a1968cd..d92dc95369 100644 --- a/server/src/rtsim/mod.rs +++ b/server/src/rtsim/mod.rs @@ -177,17 +177,23 @@ impl RtSim { } pub fn hook_rtsim_entity_unload(&mut self, entity: RtSimEntity) { - if let Some(npc) = self - .state - .get_data_mut() - .npcs - .get_mut(entity.0) - .filter(|npc| npc.riding.is_none()) - { + if let Some(npc) = self.state.get_data_mut().npcs.get_mut(entity.0) { npc.mode = SimulationMode::Simulated; } } + pub fn can_unload_entity(&self, entity: RtSimEntity) -> bool { + let data = self.state.data(); + data.npcs + .get(entity.0) + .and_then(|npc| { + let riding = npc.riding.as_ref()?; + let vehicle = data.npcs.vehicles.get(riding.vehicle)?; + Some(matches!(vehicle.mode, SimulationMode::Simulated)) + }) + .unwrap_or(true) + } + pub fn hook_rtsim_vehicle_unload(&mut self, entity: RtSimVehicle) { let data = self.state.get_data_mut(); if let Some(vehicle) = data.npcs.vehicles.get_mut(entity.0) { diff --git a/server/src/rtsim/tick.rs b/server/src/rtsim/tick.rs index af6938be4d..313f6001b7 100644 --- a/server/src/rtsim/tick.rs +++ b/server/src/rtsim/tick.rs @@ -19,7 +19,7 @@ use rtsim::data::{ npc::{Profession, SimulationMode}, Npc, Sites, }; -use specs::{Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage}; +use specs::{Entities, Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage}; use std::{sync::Arc, time::Duration}; use tracing::error; use world::site::settlement::trader_loadout; @@ -212,6 +212,7 @@ fn get_npc_entity_info(npc: &Npc, sites: &Sites, index: IndexRef) -> EntityInfo pub struct Sys; impl<'a> System<'a> for Sys { type SystemData = ( + Entities<'a>, Read<'a, DeltaTime>, Read<'a, Time>, Read<'a, TimeOfDay>, @@ -234,6 +235,7 @@ impl<'a> System<'a> for Sys { fn run( _job: &mut Job, ( + entities, dt, time, time_of_day, @@ -419,30 +421,40 @@ impl<'a> System<'a> for Sys { }); } + let mut emitter = server_event_bus.emitter(); // Synchronise rtsim NPC with entity data - for (pos, rtsim_entity, agent) in - (&positions, &rtsim_entities, (&mut agents).maybe()).join() + for (entity, pos, rtsim_entity, agent) in ( + &entities, + &positions, + &rtsim_entities, + (&mut agents).maybe(), + ) + .join() { - data.npcs - .get_mut(rtsim_entity.0) - .filter(|npc| matches!(npc.mode, SimulationMode::Loaded)) - .map(|npc| { - // Update rtsim NPC state - npc.wpos = pos.0; + if let Some(npc) = data.npcs.get_mut(rtsim_entity.0) { + match npc.mode { + SimulationMode::Loaded => { + // Update rtsim NPC state + npc.wpos = pos.0; - // Update entity state - if let Some(agent) = agent { - agent.rtsim_controller.personality = npc.personality; - agent.rtsim_controller.activity = npc.controller.activity; - agent - .rtsim_controller - .actions - .extend(std::mem::take(&mut npc.controller.actions)); - if let Some(rtsim_outbox) = &mut agent.rtsim_outbox { - npc.inbox.append(rtsim_outbox); + // Update entity state + if let Some(agent) = agent { + agent.rtsim_controller.personality = npc.personality; + agent.rtsim_controller.activity = npc.controller.activity; + agent + .rtsim_controller + .actions + .extend(std::mem::take(&mut npc.controller.actions)); + if let Some(rtsim_outbox) = &mut agent.rtsim_outbox { + npc.inbox.append(rtsim_outbox); + } } - } - }); + }, + SimulationMode::Simulated => { + emitter.emit(ServerEvent::Delete(entity)); + }, + } + } } } }