Synchronize Trenchbroom map entities (#65)

This commit is contained in:
PROMETHIA-27
2025-09-27 15:17:09 -04:00
committed by GitHub
parent d582313013
commit 83c59519e5
11 changed files with 303 additions and 63 deletions

View File

@@ -1,10 +1,24 @@
use bevy::{prelude::*, utils::synccell::SyncCell};
use avian3d::prelude::{
Collider, ColliderAabb, ColliderDensity, ColliderMarker, ColliderMassProperties,
CollisionEventsEnabled, CollisionLayers, Sensor,
};
use bevy::{
ecs::bundle::BundleFromComponents, prelude::*, scene::SceneInstance, utils::synccell::SyncCell,
};
use bevy_trenchbroom::geometry::Brushes;
use lightyear::{
netcode::Key,
prelude::{client::NetcodeConfig, input::native::InputMarker, *},
};
use nil::prelude::Mutex;
use shared::{GameState, control::ControlState, global_observer, player::Player};
use shared::{
GameState,
control::ControlState,
global_observer,
player::Player,
protocol::{DespawnTbMapEntity, TbMapEntityId, TbMapEntityMapping},
tb_entities::{Platform, PlatformTarget},
};
use std::{
env::current_exe,
io::{BufRead, BufReader},
@@ -23,12 +37,14 @@ pub fn plugin(app: &mut App) {
parse_local_server_stdout.run_if(resource_exists::<LocalServerStdout>),
);
app.add_systems(Last, close_server_processes);
app.add_systems(FixedUpdate, despawn_absent_map_entities);
global_observer!(app, on_connecting);
global_observer!(app, on_connection_failed);
global_observer!(app, on_connection_succeeded);
global_observer!(app, temp_give_player_marker);
global_observer!(app, connect_on_local_server_started);
global_observer!(app, received_remote_map_entity);
}
fn close_server_processes(mut app_exit: EventReader<AppExit>) {
@@ -190,3 +206,74 @@ fn temp_give_player_marker(trigger: Trigger<OnAdd, Player>, mut commands: Comman
.entity(trigger.target())
.insert(InputMarker::<ControlState>::default());
}
fn received_remote_map_entity(
trigger: Trigger<OnAdd, TbMapEntityId>,
world: &mut World,
mut child_buffer: Local<Vec<Entity>>,
) {
let serverside = trigger.target();
if world.get::<Replicated>(serverside).is_none() {
return;
}
let id = *world.get::<TbMapEntityId>(serverside).unwrap();
let Some(clientside) = world.resource_mut::<TbMapEntityMapping>().0.remove(&id.id) else {
warn!("received unknown MapEntity ID `{id:?}`");
return;
};
// cannot just use `take` directly with a bundle because then any missing component would cause
// the entire bundle to fail
move_component::<Brushes>(world, clientside, serverside);
move_component::<(
Collider,
ColliderAabb,
ColliderDensity,
ColliderMarker,
ColliderMassProperties,
CollisionLayers,
)>(world, clientside, serverside);
move_component::<CollisionEventsEnabled>(world, clientside, serverside);
move_component::<Platform>(world, clientside, serverside);
move_component::<PlatformTarget>(world, clientside, serverside);
move_component::<SceneInstance>(world, clientside, serverside);
move_component::<SceneRoot>(world, clientside, serverside);
move_component::<Sensor>(world, clientside, serverside);
if let Some(children) = world.get::<Children>(clientside) {
child_buffer.extend(children.iter());
for child in child_buffer.drain(..) {
world.entity_mut(child).insert(ChildOf(serverside));
}
}
world.entity_mut(clientside).despawn();
}
fn move_component<B: Bundle + BundleFromComponents>(world: &mut World, from: Entity, to: Entity) {
let comp = world.entity_mut(from).take::<B>();
if let Some(comp) = comp {
world.entity_mut(to).insert(comp);
}
}
fn despawn_absent_map_entities(
mut commands: Commands,
mut messages: Query<&mut MessageReceiver<DespawnTbMapEntity>>,
mut map: ResMut<TbMapEntityMapping>,
) {
for mut recv in messages.iter_mut() {
for msg in recv.receive() {
// the server may double-send DespawnTbMapEntity for a given ID, so ignore it if the entity
// was already despawned.
let Some(entity) = map.0.remove(&msg.0) else {
continue;
};
commands.entity(entity).despawn();
}
}
}