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> {
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 vehicle: VehicleId,
pub steering: bool,

View File

@ -183,7 +183,7 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
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<SimulateNpcs, OnTick>) {
}
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<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
if matches!(vehicle.mode, SimulationMode::Simulated) {
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);
}
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
// This is done by removing NPCs in unloaded chunks
let to_delete = {
@ -818,9 +820,15 @@ impl Server {
&self.state.ecs().read_storage::<comp::Pos>(),
!&self.state.ecs().read_storage::<comp::Presence>(),
self.state.ecs().read_storage::<Anchor>().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::<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>();
// 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 {

View File

@ -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) {

View File

@ -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<Self>,
(
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));
},
}
}
}
}
}