diff --git a/src/client.rs b/src/client.rs index 68dcf828..05fdaf0d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -63,15 +63,15 @@ impl Plugin for ClientPlugin { PostUpdate, (ClientSet::Send, ClientSet::SendPackets).chain(), ) - .add_systems(Startup, Self::setup_channels) + .add_systems(Startup, setup_channels) .add_systems( PreUpdate, - Self::receive_replication + receive_replication .map(Result::unwrap) .in_set(ClientSet::Receive) .run_if(client_connected), ) - .add_systems(PreUpdate, Self::reset.in_set(ClientSet::Reset)); + .add_systems(PreUpdate, reset.in_set(ClientSet::Reset)); } fn finish(&self, app: &mut App) { @@ -81,90 +81,86 @@ impl Plugin for ClientPlugin { } } -impl ClientPlugin { - fn setup_channels(mut client: ResMut, channels: Res) { - client.setup_server_channels(channels.server_channels().len()); - } +fn setup_channels(mut client: ResMut, channels: Res) { + client.setup_server_channels(channels.server_channels().len()); +} - /// Receives and applies replication messages from the server. - /// - /// Update messages are sent over the [`ReplicationChannel::Updates`] and are applied first to ensure valid state - /// for component mutations. - /// - /// Mutate messages are sent over [`ReplicationChannel::Mutations`], which means they may appear - /// ahead-of or behind update messages from the same server tick. A mutation will only be applied if its - /// update tick has already appeared in an update message, otherwise it will be buffered while waiting. - /// Since component mutations can arrive in any order, they will only be applied if they correspond to a more - /// recent server tick than the last acked server tick for each entity. - /// - /// Buffered mutate messages are processed last. - /// - /// Acknowledgments for received mutate messages are sent back to the server. - /// - /// See also [`ReplicationMessages`](crate::server::replication_messages::ReplicationMessages). - pub(super) fn receive_replication( - world: &mut World, - mut queue: Local, - mut entity_markers: Local, - ) -> bincode::Result<()> { - world.resource_scope(|world, mut client: Mut| { - world.resource_scope(|world, mut entity_map: Mut| { - world.resource_scope(|world, mut buffered_mutations: Mut| { - world.resource_scope(|world, command_markers: Mut| { - world.resource_scope(|world, registry: Mut| { - world.resource_scope( - |world, mut replicated_events: Mut>| { - let mut stats = - world.remove_resource::(); - let mut mutate_ticks = - world.remove_resource::(); - let mut params = ReceiveParams { - queue: &mut queue, - entity_markers: &mut entity_markers, - entity_map: &mut entity_map, - replicated_events: &mut replicated_events, - mutate_ticks: mutate_ticks.as_mut(), - stats: stats.as_mut(), - command_markers: &command_markers, - registry: ®istry, - }; - - apply_replication( - world, - &mut params, - &mut client, - &mut buffered_mutations, - )?; - - if let Some(stats) = stats { - world.insert_resource(stats); - } - if let Some(mutate_ticks) = mutate_ticks { - world.insert_resource(mutate_ticks); - } - - Ok(()) - }, - ) - }) +/// Receives and applies replication messages from the server. +/// +/// Update messages are sent over the [`ReplicationChannel::Updates`] and are applied first to ensure valid state +/// for component mutations. +/// +/// Mutate messages are sent over [`ReplicationChannel::Mutations`], which means they may appear +/// ahead-of or behind update messages from the same server tick. A mutation will only be applied if its +/// update tick has already appeared in an update message, otherwise it will be buffered while waiting. +/// Since component mutations can arrive in any order, they will only be applied if they correspond to a more +/// recent server tick than the last acked server tick for each entity. +/// +/// Buffered mutate messages are processed last. +/// +/// Acknowledgments for received mutate messages are sent back to the server. +/// +/// See also [`ReplicationMessages`](crate::server::replication_messages::ReplicationMessages). +pub(super) fn receive_replication( + world: &mut World, + mut queue: Local, + mut entity_markers: Local, +) -> bincode::Result<()> { + world.resource_scope(|world, mut client: Mut| { + world.resource_scope(|world, mut entity_map: Mut| { + world.resource_scope(|world, mut buffered_mutations: Mut| { + world.resource_scope(|world, command_markers: Mut| { + world.resource_scope(|world, registry: Mut| { + world.resource_scope( + |world, mut replicated_events: Mut>| { + let mut stats = world.remove_resource::(); + let mut mutate_ticks = world.remove_resource::(); + let mut params = ReceiveParams { + queue: &mut queue, + entity_markers: &mut entity_markers, + entity_map: &mut entity_map, + replicated_events: &mut replicated_events, + mutate_ticks: mutate_ticks.as_mut(), + stats: stats.as_mut(), + command_markers: &command_markers, + registry: ®istry, + }; + + apply_replication( + world, + &mut params, + &mut client, + &mut buffered_mutations, + )?; + + if let Some(stats) = stats { + world.insert_resource(stats); + } + if let Some(mutate_ticks) = mutate_ticks { + world.insert_resource(mutate_ticks); + } + + Ok(()) + }, + ) }) }) }) }) - } + }) +} - fn reset( - mut update_tick: ResMut, - mut entity_map: ResMut, - mut buffered_mutations: ResMut, - stats: Option>, - ) { - *update_tick = Default::default(); - entity_map.clear(); - buffered_mutations.clear(); - if let Some(mut stats) = stats { - *stats = Default::default(); - } +fn reset( + mut update_tick: ResMut, + mut entity_map: ResMut, + mut buffered_mutations: ResMut, + stats: Option>, +) { + *update_tick = Default::default(); + entity_map.clear(); + buffered_mutations.clear(); + if let Some(mut stats) = stats { + *stats = Default::default(); } } diff --git a/src/client/diagnostics.rs b/src/client/diagnostics.rs index 73df8e7b..a75c7454 100644 --- a/src/client/diagnostics.rs +++ b/src/client/diagnostics.rs @@ -17,122 +17,115 @@ impl Plugin for ClientDiagnosticsPlugin { app.init_resource::() .add_systems( PreUpdate, - Self::add_measurements + add_measurements .in_set(ClientSet::Diagnostics) .run_if(client_connected), ) .register_diagnostic( - Diagnostic::new(Self::RTT) + Diagnostic::new(RTT) .with_suffix(" s") - .with_max_history_length(Self::DIAGNOSTIC_HISTORY_LEN), + .with_max_history_length(DIAGNOSTIC_HISTORY_LEN), ) .register_diagnostic( - Diagnostic::new(Self::PACKET_LOSS) + Diagnostic::new(PACKET_LOSS) .with_suffix(" %") - .with_max_history_length(Self::DIAGNOSTIC_HISTORY_LEN), + .with_max_history_length(DIAGNOSTIC_HISTORY_LEN), ) .register_diagnostic( - Diagnostic::new(Self::SENT_BPS) + Diagnostic::new(SENT_BPS) .with_suffix(" byte/s") - .with_max_history_length(Self::DIAGNOSTIC_HISTORY_LEN), + .with_max_history_length(DIAGNOSTIC_HISTORY_LEN), ) .register_diagnostic( - Diagnostic::new(Self::RECEIVED_BPS) + Diagnostic::new(RECEIVED_BPS) .with_suffix(" byte/s") - .with_max_history_length(Self::DIAGNOSTIC_HISTORY_LEN), + .with_max_history_length(DIAGNOSTIC_HISTORY_LEN), ) .register_diagnostic( - Diagnostic::new(Self::ENTITIES_CHANGED) + Diagnostic::new(ENTITIES_CHANGED) .with_suffix(" entities changed") - .with_max_history_length(Self::DIAGNOSTIC_HISTORY_LEN), + .with_max_history_length(DIAGNOSTIC_HISTORY_LEN), ) .register_diagnostic( - Diagnostic::new(Self::COMPONENTS_CHANGED) + Diagnostic::new(COMPONENTS_CHANGED) .with_suffix(" components changed") - .with_max_history_length(Self::DIAGNOSTIC_HISTORY_LEN), + .with_max_history_length(DIAGNOSTIC_HISTORY_LEN), ) .register_diagnostic( - Diagnostic::new(Self::MAPPINGS) + Diagnostic::new(MAPPINGS) .with_suffix(" mappings") - .with_max_history_length(Self::DIAGNOSTIC_HISTORY_LEN), + .with_max_history_length(DIAGNOSTIC_HISTORY_LEN), ) .register_diagnostic( - Diagnostic::new(Self::DESPAWNS) + Diagnostic::new(DESPAWNS) .with_suffix(" despawns") - .with_max_history_length(Self::DIAGNOSTIC_HISTORY_LEN), + .with_max_history_length(DIAGNOSTIC_HISTORY_LEN), ) .register_diagnostic( - Diagnostic::new(Self::REPLICATION_MESSAGES) + Diagnostic::new(REPLICATION_MESSAGES) .with_suffix(" replication messages") - .with_max_history_length(Self::DIAGNOSTIC_HISTORY_LEN), + .with_max_history_length(DIAGNOSTIC_HISTORY_LEN), ) .register_diagnostic( - Diagnostic::new(Self::REPLICATION_BYTES) + Diagnostic::new(REPLICATION_BYTES) .with_suffix(" replication bytes") - .with_max_history_length(Self::DIAGNOSTIC_HISTORY_LEN), + .with_max_history_length(DIAGNOSTIC_HISTORY_LEN), ); } } -impl ClientDiagnosticsPlugin { - /// Round-trip time. - pub const RTT: DiagnosticPath = DiagnosticPath::const_new("client/rtt"); - /// The percent of packet loss. - pub const PACKET_LOSS: DiagnosticPath = DiagnosticPath::const_new("client/packet_loss"); - /// How many messages sent per second. - pub const SENT_BPS: DiagnosticPath = DiagnosticPath::const_new("client/sent_bps"); - /// How many bytes received per second. - pub const RECEIVED_BPS: DiagnosticPath = DiagnosticPath::const_new("client/received_bps"); +/// Round-trip time. +pub const RTT: DiagnosticPath = DiagnosticPath::const_new("client/rtt"); +/// The percent of packet loss. +pub const PACKET_LOSS: DiagnosticPath = DiagnosticPath::const_new("client/packet_loss"); +/// How many messages sent per second. +pub const SENT_BPS: DiagnosticPath = DiagnosticPath::const_new("client/sent_bps"); +/// How many bytes received per second. +pub const RECEIVED_BPS: DiagnosticPath = DiagnosticPath::const_new("client/received_bps"); - /// How many entities changed by replication. - pub const ENTITIES_CHANGED: DiagnosticPath = - DiagnosticPath::const_new("client/replication/entities_changed"); - /// How many components changed by replication. - pub const COMPONENTS_CHANGED: DiagnosticPath = - DiagnosticPath::const_new("client/replication/components_changed"); - /// How many client-mappings added by replication. - pub const MAPPINGS: DiagnosticPath = DiagnosticPath::const_new("client/replication/mappings"); - /// How many despawns applied by replication. - pub const DESPAWNS: DiagnosticPath = DiagnosticPath::const_new("client/replication/despawns"); - /// How many replication messages received. - pub const REPLICATION_MESSAGES: DiagnosticPath = - DiagnosticPath::const_new("client/replication/messages"); - /// How many replication bytes received. - pub const REPLICATION_BYTES: DiagnosticPath = - DiagnosticPath::const_new("client/replication/bytes"); +/// How many entities changed by replication. +pub const ENTITIES_CHANGED: DiagnosticPath = + DiagnosticPath::const_new("client/replication/entities_changed"); +/// How many components changed by replication. +pub const COMPONENTS_CHANGED: DiagnosticPath = + DiagnosticPath::const_new("client/replication/components_changed"); +/// How many client-mappings added by replication. +pub const MAPPINGS: DiagnosticPath = DiagnosticPath::const_new("client/replication/mappings"); +/// How many despawns applied by replication. +pub const DESPAWNS: DiagnosticPath = DiagnosticPath::const_new("client/replication/despawns"); +/// How many replication messages received. +pub const REPLICATION_MESSAGES: DiagnosticPath = + DiagnosticPath::const_new("client/replication/messages"); +/// How many replication bytes received. +pub const REPLICATION_BYTES: DiagnosticPath = DiagnosticPath::const_new("client/replication/bytes"); - /// Max diagnostic history length. - pub const DIAGNOSTIC_HISTORY_LEN: usize = 60; +/// Max diagnostic history length. +pub const DIAGNOSTIC_HISTORY_LEN: usize = 60; - fn add_measurements( - mut diagnostics: Diagnostics, - stats: Res, - mut last_stats: Local, - client: Res, - ) { - diagnostics.add_measurement(&Self::RTT, || client.rtt()); - diagnostics.add_measurement(&Self::PACKET_LOSS, || client.packet_loss()); - diagnostics.add_measurement(&Self::SENT_BPS, || client.sent_bps()); - diagnostics.add_measurement(&Self::RECEIVED_BPS, || client.received_bps()); +fn add_measurements( + mut diagnostics: Diagnostics, + stats: Res, + mut last_stats: Local, + client: Res, +) { + diagnostics.add_measurement(&RTT, || client.rtt()); + diagnostics.add_measurement(&PACKET_LOSS, || client.packet_loss()); + diagnostics.add_measurement(&SENT_BPS, || client.sent_bps()); + diagnostics.add_measurement(&RECEIVED_BPS, || client.received_bps()); - diagnostics.add_measurement(&Self::ENTITIES_CHANGED, || { - (stats.entities_changed - last_stats.entities_changed) as f64 - }); - diagnostics.add_measurement(&Self::COMPONENTS_CHANGED, || { - (stats.components_changed - last_stats.components_changed) as f64 - }); - diagnostics.add_measurement(&Self::MAPPINGS, || { - (stats.mappings - last_stats.mappings) as f64 - }); - diagnostics.add_measurement(&Self::DESPAWNS, || { - (stats.despawns - last_stats.despawns) as f64 - }); - diagnostics.add_measurement(&Self::REPLICATION_MESSAGES, || { - (stats.messages - last_stats.messages) as f64 - }); - diagnostics.add_measurement(&Self::REPLICATION_BYTES, || { - (stats.bytes - last_stats.bytes) as f64 - }); - *last_stats = *stats; - } + diagnostics.add_measurement(&ENTITIES_CHANGED, || { + (stats.entities_changed - last_stats.entities_changed) as f64 + }); + diagnostics.add_measurement(&COMPONENTS_CHANGED, || { + (stats.components_changed - last_stats.components_changed) as f64 + }); + diagnostics.add_measurement(&MAPPINGS, || (stats.mappings - last_stats.mappings) as f64); + diagnostics.add_measurement(&DESPAWNS, || (stats.despawns - last_stats.despawns) as f64); + diagnostics.add_measurement(&REPLICATION_MESSAGES, || { + (stats.messages - last_stats.messages) as f64 + }); + diagnostics.add_measurement(&REPLICATION_BYTES, || { + (stats.bytes - last_stats.bytes) as f64 + }); + *last_stats = *stats; } diff --git a/src/client/event.rs b/src/client/event.rs index 5ad04f0c..e8686ed1 100644 --- a/src/client/event.rs +++ b/src/client/event.rs @@ -1,4 +1,4 @@ -use super::{ClientPlugin, ClientSet, ServerUpdateTick}; +use super::{ClientSet, ServerUpdateTick}; use crate::core::{ common_conditions::*, event::{ @@ -15,7 +15,7 @@ use bevy::{ /// Sending events from a client to the server. /// -/// Requires [`ClientPlugin`]. +/// Requires [`ClientPlugin`](super::ClientPlugin). /// Can be disabled for apps that act only as servers. pub struct ClientEventPlugin; @@ -47,7 +47,7 @@ impl Plugin for ClientEventPlugin { ParamBuilder, ) .build_state(app.world_mut()) - .build_system(Self::send); + .build_system(send); let receive = ( FilteredResourcesMutParamBuilder::new(|builder| { @@ -67,7 +67,7 @@ impl Plugin for ClientEventPlugin { ParamBuilder, ) .build_state(app.world_mut()) - .build_system(Self::receive); + .build_system(receive); let trigger = ( FilteredResourcesMutParamBuilder::new(|builder| { @@ -79,7 +79,7 @@ impl Plugin for ClientEventPlugin { ParamBuilder, ) .build_state(app.world_mut()) - .build_system(Self::trigger); + .build_system(trigger); let resend_locally = ( FilteredResourcesMutParamBuilder::new(|builder| { @@ -95,7 +95,7 @@ impl Plugin for ClientEventPlugin { ParamBuilder, ) .build_state(app.world_mut()) - .build_system(Self::resend_locally); + .build_system(resend_locally); let reset = ( FilteredResourcesMutParamBuilder::new(|builder| { @@ -111,7 +111,7 @@ impl Plugin for ClientEventPlugin { ParamBuilder, ) .build_state(app.world_mut()) - .build_system(Self::reset); + .build_system(reset); app.insert_resource(event_registry) .add_systems( @@ -120,7 +120,7 @@ impl Plugin for ClientEventPlugin { reset.in_set(ClientSet::ResetEvents), ( receive - .after(ClientPlugin::receive_replication) + .after(super::receive_replication) .run_if(client_connected), trigger.run_if(not(server_running)), ) @@ -140,123 +140,121 @@ impl Plugin for ClientEventPlugin { } } -impl ClientEventPlugin { - fn send( - events: FilteredResources, - mut readers: FilteredResourcesMut, - mut client: ResMut, - registry: Res, - entity_map: Res, - event_registry: Res, - ) { - let mut ctx = ClientSendCtx { - entity_map: &entity_map, - registry: ®istry.read(), - }; +fn send( + events: FilteredResources, + mut readers: FilteredResourcesMut, + mut client: ResMut, + registry: Res, + entity_map: Res, + event_registry: Res, +) { + let mut ctx = ClientSendCtx { + entity_map: &entity_map, + registry: ®istry.read(), + }; - for event in event_registry.iter_client_events() { - let events = events - .get_by_id(event.events_id()) - .expect("events resource should be accessible"); - let reader = readers - .get_mut_by_id(event.reader_id()) - .expect("event reader resource should be accessible"); + for event in event_registry.iter_client_events() { + let events = events + .get_by_id(event.events_id()) + .expect("events resource should be accessible"); + let reader = readers + .get_mut_by_id(event.reader_id()) + .expect("event reader resource should be accessible"); - // SAFETY: passed pointers were obtained using this event data. - unsafe { - event.send(&mut ctx, &events, reader.into_inner(), &mut client); - } + // SAFETY: passed pointers were obtained using this event data. + unsafe { + event.send(&mut ctx, &events, reader.into_inner(), &mut client); } } +} - fn receive( - mut events: FilteredResourcesMut, - mut queues: FilteredResourcesMut, - mut client: ResMut, - registry: Res, - entity_map: Res, - event_registry: Res, - update_tick: Res, - ) { - let mut ctx = ClientReceiveCtx { - registry: ®istry.read(), - entity_map: &entity_map, - invalid_entities: Vec::new(), - }; +fn receive( + mut events: FilteredResourcesMut, + mut queues: FilteredResourcesMut, + mut client: ResMut, + registry: Res, + entity_map: Res, + event_registry: Res, + update_tick: Res, +) { + let mut ctx = ClientReceiveCtx { + registry: ®istry.read(), + entity_map: &entity_map, + invalid_entities: Vec::new(), + }; - for event in event_registry.iter_server_events() { - let events = events - .get_mut_by_id(event.events_id()) - .expect("events resource should be accessible"); - let queue = queues - .get_mut_by_id(event.queue_id()) - .expect("queue resource should be accessible"); + for event in event_registry.iter_server_events() { + let events = events + .get_mut_by_id(event.events_id()) + .expect("events resource should be accessible"); + let queue = queues + .get_mut_by_id(event.queue_id()) + .expect("queue resource should be accessible"); - // SAFETY: passed pointers were obtained using this event data. - unsafe { - event.receive( - &mut ctx, - events.into_inner(), - queue.into_inner(), - &mut client, - **update_tick, - ) - }; - } + // SAFETY: passed pointers were obtained using this event data. + unsafe { + event.receive( + &mut ctx, + events.into_inner(), + queue.into_inner(), + &mut client, + **update_tick, + ) + }; } +} - fn trigger( - mut events: FilteredResourcesMut, - mut commands: Commands, - event_registry: Res, - ) { - for trigger in event_registry.iter_server_triggers() { - let events = events - .get_mut_by_id(trigger.event().events_id()) - .expect("events resource should be accessible"); - trigger.trigger(&mut commands, events.into_inner()); - } +fn trigger( + mut events: FilteredResourcesMut, + mut commands: Commands, + event_registry: Res, +) { + for trigger in event_registry.iter_server_triggers() { + let events = events + .get_mut_by_id(trigger.event().events_id()) + .expect("events resource should be accessible"); + trigger.trigger(&mut commands, events.into_inner()); } +} - fn resend_locally( - mut client_events: FilteredResourcesMut, - mut events: FilteredResourcesMut, - event_registry: Res, - ) { - for event in event_registry.iter_client_events() { - let client_events = client_events - .get_mut_by_id(event.client_events_id()) - .expect("client events resource should be accessible"); - let events = events - .get_mut_by_id(event.events_id()) - .expect("events resource should be accessible"); +fn resend_locally( + mut client_events: FilteredResourcesMut, + mut events: FilteredResourcesMut, + event_registry: Res, +) { + for event in event_registry.iter_client_events() { + let client_events = client_events + .get_mut_by_id(event.client_events_id()) + .expect("client events resource should be accessible"); + let events = events + .get_mut_by_id(event.events_id()) + .expect("events resource should be accessible"); - // SAFETY: passed pointers were obtained using this event data. - unsafe { event.resend_locally(client_events.into_inner(), events.into_inner()) }; - } + // SAFETY: passed pointers were obtained using this event data. + unsafe { event.resend_locally(client_events.into_inner(), events.into_inner()) }; } +} - fn reset( - mut events: FilteredResourcesMut, - mut queues: FilteredResourcesMut, - event_registry: Res, - ) { - for event in event_registry.iter_client_events() { - let events = events - .get_mut_by_id(event.events_id()) - .expect("events resource should be accessible"); +fn reset( + mut events: FilteredResourcesMut, + mut queues: FilteredResourcesMut, + event_registry: Res, +) { + for event in event_registry.iter_client_events() { + let events = events + .get_mut_by_id(event.events_id()) + .expect("events resource should be accessible"); - // SAFETY: passed pointer was obtained using this event data. - unsafe { event.reset(events.into_inner()) }; - } + // SAFETY: passed pointer was obtained using this event data. + unsafe { event.reset(events.into_inner()) }; + } - for event in event_registry.iter_server_events() { - let queue = queues - .get_mut_by_id(event.queue_id()) - .expect("event queue resource should be accessible"); + for event in event_registry.iter_server_events() { + let queue = queues + .get_mut_by_id(event.queue_id()) + .expect("event queue resource should be accessible"); - // SAFETY: passed pointer was obtained using this event data. - unsafe { event.reset(queue.into_inner()) }; - } + // SAFETY: passed pointer was obtained using this event data. + unsafe { event.reset(queue.into_inner()) }; } } diff --git a/src/parent_sync.rs b/src/parent_sync.rs index fbd48d4c..ff6f82f3 100644 --- a/src/parent_sync.rs +++ b/src/parent_sync.rs @@ -33,80 +33,75 @@ impl Plugin for ParentSyncPlugin { .replicate_mapped::(); #[cfg(feature = "client")] - app.add_systems( - PreUpdate, - Self::sync_hierarchy.in_set(ClientSet::SyncHierarchy), - ); + app.add_systems(PreUpdate, sync_hierarchy.in_set(ClientSet::SyncHierarchy)); // Trigger on both `Parent` and `ParentSync` to initialize depending on what inserted last. #[cfg(feature = "server")] - app.add_observer(Self::init::) - .add_observer(Self::init::) - .add_observer(Self::store_removals) + app.add_observer(init::) + .add_observer(init::) + .add_observer(store_removals) .add_systems( PostUpdate, - Self::store_changes + store_changes .run_if(server_or_singleplayer) .in_set(ServerSet::StoreHierarchy), ); } } -impl ParentSyncPlugin { - /// Synchronizes hierarchy if [`ParentSync`] changes. - /// - /// Runs not only on clients, but also on server in order to update the hierarchy when the server state is deserialized. - #[cfg(feature = "client")] - fn sync_hierarchy( - mut commands: Commands, - hierarchy: Query<(Entity, &ParentSync, Option<&Parent>), Changed>, - ) { - for (entity, parent_sync, parent) in &hierarchy { - if let Some(sync_entity) = parent_sync.0 { - if parent.is_none_or(|parent| **parent != sync_entity) { - commands.entity(entity).set_parent(sync_entity); - } - } else if parent.is_some() { - commands.entity(entity).remove_parent(); +/// Synchronizes hierarchy if [`ParentSync`] changes. +/// +/// Runs not only on clients, but also on server in order to update the hierarchy when the server state is deserialized. +#[cfg(feature = "client")] +fn sync_hierarchy( + mut commands: Commands, + hierarchy: Query<(Entity, &ParentSync, Option<&Parent>), Changed>, +) { + for (entity, parent_sync, parent) in &hierarchy { + if let Some(sync_entity) = parent_sync.0 { + if parent.is_none_or(|parent| **parent != sync_entity) { + commands.entity(entity).set_parent(sync_entity); } + } else if parent.is_some() { + commands.entity(entity).remove_parent(); } } +} - #[cfg(feature = "server")] - fn store_changes(mut hierarchy: Query<(&Parent, &mut ParentSync), Changed>) { - for (parent, mut parent_sync) in &mut hierarchy { - parent_sync.set_if_neq(ParentSync(Some(**parent))); - } +#[cfg(feature = "server")] +fn store_changes(mut hierarchy: Query<(&Parent, &mut ParentSync), Changed>) { + for (parent, mut parent_sync) in &mut hierarchy { + parent_sync.set_if_neq(ParentSync(Some(**parent))); } +} - #[cfg(feature = "server")] - fn init( - trigger: Trigger, - client: Option>, - mut hierarchy: Query<(&Parent, &mut ParentSync)>, - ) { - if !server_or_singleplayer(client) { - return; - } +#[cfg(feature = "server")] +fn init( + trigger: Trigger, + client: Option>, + mut hierarchy: Query<(&Parent, &mut ParentSync)>, +) { + if !server_or_singleplayer(client) { + return; + } - if let Ok((parent, mut parent_sync)) = hierarchy.get_mut(trigger.entity()) { - parent_sync.set_if_neq(ParentSync(Some(**parent))); - } + if let Ok((parent, mut parent_sync)) = hierarchy.get_mut(trigger.entity()) { + parent_sync.set_if_neq(ParentSync(Some(**parent))); } +} - #[cfg(feature = "server")] - fn store_removals( - trigger: Trigger, - client: Option>, - mut hierarchy: Query<&mut ParentSync>, - ) { - if !server_or_singleplayer(client) { - return; - } +#[cfg(feature = "server")] +fn store_removals( + trigger: Trigger, + client: Option>, + mut hierarchy: Query<&mut ParentSync>, +) { + if !server_or_singleplayer(client) { + return; + } - if let Ok(mut parent_sync) = hierarchy.get_mut(trigger.entity()) { - parent_sync.0 = None; - } + if let Ok(mut parent_sync) = hierarchy.get_mut(trigger.entity()) { + parent_sync.0 = None; } } diff --git a/src/server.rs b/src/server.rs index ac18307c..0e874ec4 100644 --- a/src/server.rs +++ b/src/server.rs @@ -114,16 +114,15 @@ impl Plugin for ServerPlugin { ) .chain(), ) - .add_observer(Self::handle_connects) - .add_observer(Self::handle_disconnects) - .add_observer(Self::enable_replication) - .add_systems(Startup, Self::setup_channels) + .add_observer(handle_connects) + .add_observer(handle_disconnects) + .add_observer(enable_replication) + .add_systems(Startup, setup_channels) .add_systems( PreUpdate, ( - Self::receive_acks, - Self::cleanup_acks(self.mutations_timeout) - .run_if(on_timer(self.mutations_timeout)), + receive_acks, + cleanup_acks(self.mutations_timeout).run_if(on_timer(self.mutations_timeout)), ) .chain() .in_set(ServerSet::Receive) @@ -132,12 +131,12 @@ impl Plugin for ServerPlugin { .add_systems( PostUpdate, ( - Self::send_replication + send_replication .map(Result::unwrap) .in_set(ServerSet::Send) .run_if(server_running) .run_if(resource_changed::), - Self::reset.run_if(server_just_stopped), + reset.run_if(server_just_stopped), ), ); @@ -146,8 +145,8 @@ impl Plugin for ServerPlugin { let tick_time = Duration::from_millis(1000 / max_tick_rate as u64); app.add_systems( PostUpdate, - Self::increment_tick - .before(Self::send_replication) + increment_tick + .before(send_replication) .run_if(server_running) .run_if(on_timer(tick_time)), ); @@ -155,8 +154,8 @@ impl Plugin for ServerPlugin { TickPolicy::EveryFrame => { app.add_systems( PostUpdate, - Self::increment_tick - .before(Self::send_replication) + increment_tick + .before(send_replication) .run_if(server_running), ); } @@ -165,187 +164,185 @@ impl Plugin for ServerPlugin { } } -impl ServerPlugin { - fn setup_channels(mut server: ResMut, channels: Res) { - server.setup_client_channels(channels.client_channels().len()); - } +fn setup_channels(mut server: ResMut, channels: Res) { + server.setup_client_channels(channels.client_channels().len()); +} - /// Increments current server tick which causes the server to replicate this frame. - pub fn increment_tick(mut server_tick: ResMut) { - server_tick.increment(); - trace!("incremented {server_tick:?}"); - } +/// Increments current server tick which causes the server to replicate this frame. +pub fn increment_tick(mut server_tick: ResMut) { + server_tick.increment(); + trace!("incremented {server_tick:?}"); +} - fn handle_connects( - trigger: Trigger, - mut commands: Commands, - mut connected_clients: ResMut, - replicated_clients: Res, - mut buffered_events: ResMut, - ) { - debug!("`{:?}` connected", trigger.client_id); - connected_clients.add(trigger.client_id); - if replicated_clients.replicate_after_connect() { - commands.trigger(StartReplication(trigger.client_id)); - } - buffered_events.exclude_client(trigger.client_id); +fn handle_connects( + trigger: Trigger, + mut commands: Commands, + mut connected_clients: ResMut, + replicated_clients: Res, + mut buffered_events: ResMut, +) { + debug!("`{:?}` connected", trigger.client_id); + connected_clients.add(trigger.client_id); + if replicated_clients.replicate_after_connect() { + commands.trigger(StartReplication(trigger.client_id)); } + buffered_events.exclude_client(trigger.client_id); +} - fn handle_disconnects( - trigger: Trigger, - mut entity_map: ResMut, - mut connected_clients: ResMut, - mut replicated_clients: ResMut, - mut server: ResMut, - mut client_buffers: ResMut, - ) { - debug!("`{:?}` disconnected: {}", trigger.client_id, trigger.reason); - entity_map.0.remove(&trigger.client_id); - connected_clients.remove(trigger.client_id); - replicated_clients.remove(&mut client_buffers, trigger.client_id); - server.remove_client(trigger.client_id); - } +fn handle_disconnects( + trigger: Trigger, + mut entity_map: ResMut, + mut connected_clients: ResMut, + mut replicated_clients: ResMut, + mut server: ResMut, + mut client_buffers: ResMut, +) { + debug!("`{:?}` disconnected: {}", trigger.client_id, trigger.reason); + entity_map.0.remove(&trigger.client_id); + connected_clients.remove(trigger.client_id); + replicated_clients.remove(&mut client_buffers, trigger.client_id); + server.remove_client(trigger.client_id); +} - fn enable_replication( - trigger: Trigger, - mut replicated_clients: ResMut, - mut client_buffers: ResMut, - ) { - replicated_clients.add(&mut client_buffers, **trigger); - } +fn enable_replication( + trigger: Trigger, + mut replicated_clients: ResMut, + mut client_buffers: ResMut, +) { + replicated_clients.add(&mut client_buffers, **trigger); +} - fn cleanup_acks( - mutations_timeout: Duration, - ) -> impl FnMut(ResMut, ResMut, Res