Fix rtsim airships

This commit is contained in:
Isse 2023-08-29 12:56:25 +00:00
parent a386c68df5
commit 06d7548dc6
6 changed files with 74 additions and 37 deletions

View File

@ -387,5 +387,9 @@ impl<'a, E> Emitter<'a, E> {
} }
impl<'a, E> Drop for 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);
}
}
} }

View File

@ -258,7 +258,7 @@ impl Npc {
} }
} }
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Riding { pub struct Riding {
pub vehicle: VehicleId, pub vehicle: VehicleId,
pub steering: bool, pub steering: bool,

View File

@ -183,7 +183,7 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
match npc.controller.activity { match npc.controller.activity {
// If steering, the NPC controls the vehicle's motion // If steering, the NPC controls the vehicle's motion
Some(NpcActivity::Goto(target, speed_factor)) if riding.steering => { 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(); let dist2 = diff.magnitude_squared();
if dist2 > 0.5f32.powi(2) { if dist2 > 0.5f32.powi(2) {
@ -212,7 +212,7 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
} }
vehicle.dir = (target.xy() - vehicle.wpos.xy()) vehicle.dir = (target.xy() - vehicle.wpos.xy())
.try_normalized() .try_normalized()
.unwrap_or(Vec2::unit_y()); .unwrap_or(vehicle.dir);
} }
}, },
// When riding, other actions are disabled // When riding, other actions are disabled
@ -294,7 +294,7 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
} }
} }
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 // Try to keep ships above ground and within the map
if matches!(vehicle.mode, SimulationMode::Simulated) { if matches!(vehicle.mode, SimulationMode::Simulated) {
vehicle.wpos = vehicle vehicle.wpos = vehicle
@ -312,5 +312,12 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
), ),
); );
} }
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;
}
} }
} }

View File

@ -809,6 +809,8 @@ impl Server {
self.state.delete_component::<Anchor>(entity); self.state.delete_component::<Anchor>(entity);
} }
let mut rtsim = self.state.ecs().write_resource::<rtsim::RtSim>();
let rtsim_entities = self.state.ecs().read_storage::<RtSimEntity>();
// Remove NPCs that are outside the view distances of all players // Remove NPCs that are outside the view distances of all players
// This is done by removing NPCs in unloaded chunks // This is done by removing NPCs in unloaded chunks
let to_delete = { let to_delete = {
@ -818,9 +820,15 @@ impl Server {
&self.state.ecs().read_storage::<comp::Pos>(), &self.state.ecs().read_storage::<comp::Pos>(),
!&self.state.ecs().read_storage::<comp::Presence>(), !&self.state.ecs().read_storage::<comp::Presence>(),
self.state.ecs().read_storage::<Anchor>().maybe(), self.state.ecs().read_storage::<Anchor>().maybe(),
rtsim_entities.maybe(),
) )
.join() .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)); let chunk_key = terrain.pos_key(pos.0.map(|e| e.floor() as i32));
match anchor { match anchor {
Some(Anchor::Chunk(hc)) => { Some(Anchor::Chunk(hc)) => {
@ -835,13 +843,11 @@ impl Server {
None => terrain.get_key_real(chunk_key).is_none(), None => terrain.get_key_real(chunk_key).is_none(),
} }
}) })
.map(|(entity, _, _, _)| entity) .map(|(entity, _, _, _, _)| entity)
.collect::<Vec<_>>() .collect::<Vec<_>>()
}; };
{ {
let mut rtsim = self.state.ecs().write_resource::<rtsim::RtSim>();
let rtsim_entities = self.state.ecs().read_storage::<RtSimEntity>();
let rtsim_vehicles = self.state.ecs().read_storage::<RtSimVehicle>(); let rtsim_vehicles = self.state.ecs().read_storage::<RtSimVehicle>();
// Assimilate entities that are part of the real-time world simulation // 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 // Actually perform entity deletion
for entity in to_delete { for entity in to_delete {

View File

@ -177,17 +177,23 @@ impl RtSim {
} }
pub fn hook_rtsim_entity_unload(&mut self, entity: RtSimEntity) { pub fn hook_rtsim_entity_unload(&mut self, entity: RtSimEntity) {
if let Some(npc) = self if let Some(npc) = self.state.get_data_mut().npcs.get_mut(entity.0) {
.state
.get_data_mut()
.npcs
.get_mut(entity.0)
.filter(|npc| npc.riding.is_none())
{
npc.mode = SimulationMode::Simulated; 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) { pub fn hook_rtsim_vehicle_unload(&mut self, entity: RtSimVehicle) {
let data = self.state.get_data_mut(); let data = self.state.get_data_mut();
if let Some(vehicle) = data.npcs.vehicles.get_mut(entity.0) { if let Some(vehicle) = data.npcs.vehicles.get_mut(entity.0) {

View File

@ -19,7 +19,7 @@ use rtsim::data::{
npc::{Profession, SimulationMode}, npc::{Profession, SimulationMode},
Npc, Sites, 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 std::{sync::Arc, time::Duration};
use tracing::error; use tracing::error;
use world::site::settlement::trader_loadout; 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; pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> System<'a> for Sys {
type SystemData = ( type SystemData = (
Entities<'a>,
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
Read<'a, Time>, Read<'a, Time>,
Read<'a, TimeOfDay>, Read<'a, TimeOfDay>,
@ -234,6 +235,7 @@ impl<'a> System<'a> for Sys {
fn run( fn run(
_job: &mut Job<Self>, _job: &mut Job<Self>,
( (
entities,
dt, dt,
time, time,
time_of_day, 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 // Synchronise rtsim NPC with entity data
for (pos, rtsim_entity, agent) in for (entity, pos, rtsim_entity, agent) in (
(&positions, &rtsim_entities, (&mut agents).maybe()).join() &entities,
&positions,
&rtsim_entities,
(&mut agents).maybe(),
)
.join()
{ {
data.npcs if let Some(npc) = data.npcs.get_mut(rtsim_entity.0) {
.get_mut(rtsim_entity.0) match npc.mode {
.filter(|npc| matches!(npc.mode, SimulationMode::Loaded)) SimulationMode::Loaded => {
.map(|npc| { // Update rtsim NPC state
// Update rtsim NPC state npc.wpos = pos.0;
npc.wpos = pos.0;
// Update entity state // Update entity state
if let Some(agent) = agent { if let Some(agent) = agent {
agent.rtsim_controller.personality = npc.personality; agent.rtsim_controller.personality = npc.personality;
agent.rtsim_controller.activity = npc.controller.activity; agent.rtsim_controller.activity = npc.controller.activity;
agent agent
.rtsim_controller .rtsim_controller
.actions .actions
.extend(std::mem::take(&mut npc.controller.actions)); .extend(std::mem::take(&mut npc.controller.actions));
if let Some(rtsim_outbox) = &mut agent.rtsim_outbox { if let Some(rtsim_outbox) = &mut agent.rtsim_outbox {
npc.inbox.append(rtsim_outbox); npc.inbox.append(rtsim_outbox);
}
} }
} },
}); SimulationMode::Simulated => {
emitter.emit(ServerEvent::Delete(entity));
},
}
}
} }
} }
} }