Synchronize Trenchbroom map entities (#65)
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user