From 5eba736dacd7c60c4419a8b8a73af87631f031a7 Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchyk Date: Thu, 22 May 2025 00:05:21 +0300 Subject: [PATCH] Initialize channels in `App::finish` instead of `Startup` This allows users to access channels earlier if necessary. Requires adding a few `finish` calls in tests where they were previously missing. --- CHANGELOG.md | 1 + .../tests/backend.rs | 6 +- src/client.rs | 11 ++-- src/server.rs | 11 ++-- src/shared/backend/replicon_channels.rs | 3 + src/test_app.rs | 3 +- tests/connection.rs | 48 +++----------- tests/despawn.rs | 12 ++-- tests/insertion.rs | 42 ++++++++---- tests/mutate_ticks.rs | 12 ++-- tests/mutations.rs | 64 ++++++++++++------- tests/removal.rs | 33 ++++++---- tests/scene.rs | 11 ++-- tests/spawn.rs | 21 ++++-- tests/stats.rs | 3 +- tests/visibility.rs | 18 ++++-- 16 files changed, 174 insertions(+), 125 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3017d656..0a309078 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Rename `replication_registry::despawn_recursive` into `replication_registry::despawn`. - `ReplicationRule` now stores `Vec` instead of `Vec<(ComponentId, FnsId)>` - `RuleFns` now available from prelude. +- Initialize channels in `App::finish` instead of `Startup`. It's called automatically on `App::run`, but in tests you need to call `App::finish` manually. - Rules created with the same priority now evaluated in their creation order. - Component removals and insertions for an entity are now buffered and applied as bundles to avoid triggering observers without all components being inserted or removed. This also significantly improves performance by avoiding extra archetype moves and lookups. - The `Replicated` component is no longer automatically inserted into non-replicated entities spawned from replicated components. diff --git a/bevy_replicon_example_backend/tests/backend.rs b/bevy_replicon_example_backend/tests/backend.rs index 2803c189..1c2ce014 100644 --- a/bevy_replicon_example_backend/tests/backend.rs +++ b/bevy_replicon_example_backend/tests/backend.rs @@ -17,7 +17,8 @@ fn connect_disconnect() { ..Default::default() }), RepliconExampleBackendPlugins, - )); + )) + .finish(); } setup(&mut server_app, &mut client_app).unwrap(); @@ -62,7 +63,8 @@ fn replication() { ..Default::default() }), RepliconExampleBackendPlugins, - )); + )) + .finish(); } setup(&mut server_app, &mut client_app).unwrap(); diff --git a/src/client.rs b/src/client.rs index b7ca6a87..c0e3a826 100644 --- a/src/client.rs +++ b/src/client.rs @@ -64,7 +64,6 @@ impl Plugin for ClientPlugin { PostUpdate, (ClientSet::Send, ClientSet::SendPackets).chain(), ) - .add_systems(Startup, setup_channels) .add_systems( PreUpdate, receive_replication @@ -78,11 +77,13 @@ impl Plugin for ClientPlugin { if **app.world().resource::() { app.init_resource::(); } - } -} -fn setup_channels(mut client: ResMut, channels: Res) { - client.setup_server_channels(channels.server_channels().len()); + app.world_mut() + .resource_scope(|world, mut client: Mut| { + let channels = world.resource::(); + client.setup_server_channels(channels.server_channels().len()); + }); + } } /// Receives and applies replication messages from the server. diff --git a/src/server.rs b/src/server.rs index 138557e1..6ff406f2 100644 --- a/src/server.rs +++ b/src/server.rs @@ -110,7 +110,6 @@ impl Plugin for ServerPlugin { .add_observer(handle_connects) .add_observer(handle_disconnects) .add_observer(buffer_despawns) - .add_systems(Startup, setup_channels) .add_systems( PreUpdate, ( @@ -175,10 +174,14 @@ impl Plugin for ServerPlugin { app.register_required_components::(); } } -} -fn setup_channels(mut server: ResMut, channels: Res) { - server.setup_client_channels(channels.client_channels().len()); + fn finish(&self, app: &mut App) { + app.world_mut() + .resource_scope(|world, mut server: Mut| { + let channels = world.resource::(); + server.setup_client_channels(channels.client_channels().len()); + }); + } } /// Increments current server tick which causes the server to replicate this frame. diff --git a/src/shared/backend/replicon_channels.rs b/src/shared/backend/replicon_channels.rs index 7720e1c1..b7a5e058 100644 --- a/src/shared/backend/replicon_channels.rs +++ b/src/shared/backend/replicon_channels.rs @@ -3,6 +3,9 @@ use log::debug; /// A resource with all channels used by Replicon. /// +/// Initialized in [`ClientPlugin::finish`](crate::client::ClientPlugin) and +/// [`ServerPlugin::finish`](crate::server::ServerPlugin). +/// /// Channel IDs are represented by [`usize`], but backends may limit the number of channels. /// /// The first two channels are used for replication. For more details, see [`ReplicationChannel`]. diff --git a/src/test_app.rs b/src/test_app.rs index 03708b22..36bbc707 100644 --- a/src/test_app.rs +++ b/src/test_app.rs @@ -25,7 +25,8 @@ for app in [&mut server_app, &mut client_app] { tick_policy: TickPolicy::EveryFrame, // To tick each app update. ..Default::default() }), - )); + )) + .finish(); // Don't forget to call `finish`. } // Simulate connection between two apps: diff --git a/tests/connection.rs b/tests/connection.rs index a3b8a5fc..33a5e61c 100644 --- a/tests/connection.rs +++ b/tests/connection.rs @@ -14,8 +14,7 @@ fn client_to_server() { let mut server_app = App::new(); let mut client_app = App::new(); for app in [&mut server_app, &mut client_app] { - app.add_plugins((MinimalPlugins, RepliconPlugins)); - app.update(); + app.add_plugins((MinimalPlugins, RepliconPlugins)).finish(); } const MESSAGES: &[&[u8]] = &[&[0], &[1]]; @@ -44,8 +43,7 @@ fn server_to_client() { let mut server_app = App::new(); let mut client_app = App::new(); for app in [&mut server_app, &mut client_app] { - app.add_plugins((MinimalPlugins, RepliconPlugins)); - app.update(); + app.add_plugins((MinimalPlugins, RepliconPlugins)).finish(); } const MESSAGES: &[&[u8]] = &[&[0], &[1]]; @@ -71,13 +69,7 @@ fn connect_disconnect() { let mut server_app = App::new(); let mut client_app = App::new(); for app in [&mut server_app, &mut client_app] { - app.add_plugins(( - MinimalPlugins, - RepliconPlugins.set(ServerPlugin { - tick_policy: TickPolicy::EveryFrame, - ..Default::default() - }), - )); + app.add_plugins((MinimalPlugins, RepliconPlugins)).finish(); } server_app.connect_client(&mut client_app); @@ -102,15 +94,7 @@ fn connect_disconnect() { #[test] fn client_cleanup_on_disconnect() { let mut app = App::new(); - app.add_plugins(( - MinimalPlugins, - RepliconPlugins.set(ServerPlugin { - tick_policy: TickPolicy::EveryFrame, - ..Default::default() - }), - )); - - app.update(); + app.add_plugins((MinimalPlugins, RepliconPlugins)).finish(); let mut client = app.world_mut().resource_mut::(); client.set_status(RepliconClientStatus::Connected); @@ -129,15 +113,7 @@ fn client_cleanup_on_disconnect() { #[test] fn server_cleanup_on_stop() { let mut app = App::new(); - app.add_plugins(( - MinimalPlugins, - RepliconPlugins.set(ServerPlugin { - tick_policy: TickPolicy::EveryFrame, - ..Default::default() - }), - )); - - app.update(); + app.add_plugins((MinimalPlugins, RepliconPlugins)).finish(); let mut server = app.world_mut().resource_mut::(); server.set_running(true); @@ -158,13 +134,7 @@ fn server_cleanup_on_stop() { #[test] fn client_disconnected() { let mut app = App::new(); - app.add_plugins(( - MinimalPlugins, - RepliconPlugins.set(ServerPlugin { - tick_policy: TickPolicy::EveryFrame, - ..Default::default() - }), - )); + app.add_plugins((MinimalPlugins, RepliconPlugins)).finish(); app.update(); @@ -188,7 +158,8 @@ fn server_inactive() { tick_policy: TickPolicy::EveryFrame, ..Default::default() }), - )); + )) + .finish(); app.update(); @@ -217,7 +188,8 @@ fn deferred_replication() { replicate_after_connect: false, ..Default::default() }), - )); + )) + .finish(); } server_app.connect_client(&mut client_app); diff --git a/tests/despawn.rs b/tests/despawn.rs index 3205ab81..6f21d2cf 100644 --- a/tests/despawn.rs +++ b/tests/despawn.rs @@ -15,7 +15,8 @@ fn single() { tick_policy: TickPolicy::EveryFrame, ..Default::default() }), - )); + )) + .finish(); } server_app.connect_client(&mut client_app); @@ -52,7 +53,8 @@ fn with_hierarchy() { tick_policy: TickPolicy::EveryFrame, ..Default::default() }), - )); + )) + .finish(); } server_app.connect_client(&mut client_app); @@ -98,7 +100,8 @@ fn after_spawn() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -129,7 +132,8 @@ fn hidden() { visibility_policy: VisibilityPolicy::Whitelist, // Hide all spawned entities by default. ..Default::default() }), - )); + )) + .finish(); } server_app.connect_client(&mut client_app); diff --git a/tests/insertion.rs b/tests/insertion.rs index cf3a95b0..13ba7622 100644 --- a/tests/insertion.rs +++ b/tests/insertion.rs @@ -27,7 +27,8 @@ fn table_storage() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -64,7 +65,8 @@ fn sparse_set_storage() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -101,7 +103,8 @@ fn immutable() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -151,7 +154,8 @@ fn mapped_existing_entity() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -200,7 +204,8 @@ fn mapped_new_entity() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -246,7 +251,8 @@ fn multiple_components() { }), )) .replicate::() - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -291,7 +297,8 @@ fn command_fns() { }), )) .replicate::() - .set_command_fns(replace, command_fns::default_remove::); + .set_command_fns(replace, command_fns::default_remove::) + .finish(); } server_app.connect_client(&mut client_app); @@ -335,7 +342,8 @@ fn marker() { .set_marker_fns::( replace, command_fns::default_remove::, - ); + ) + .finish(); } server_app.connect_client(&mut client_app); @@ -382,7 +390,8 @@ fn group() { ..Default::default() }), )) - .replicate_bundle::<(ComponentA, ComponentB)>(); + .replicate_bundle::<(ComponentA, ComponentB)>() + .finish(); } server_app.connect_client(&mut client_app); @@ -418,7 +427,8 @@ fn not_replicated() { tick_policy: TickPolicy::EveryFrame, ..Default::default() }), - )); + )) + .finish(); } server_app.connect_client(&mut client_app); @@ -455,7 +465,8 @@ fn after_removal() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -507,7 +518,8 @@ fn before_started_replication() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -553,7 +565,8 @@ fn after_started_replication() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -592,7 +605,8 @@ fn confirm_history() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); diff --git a/tests/mutate_ticks.rs b/tests/mutate_ticks.rs index e696575e..a232d2a3 100644 --- a/tests/mutate_ticks.rs +++ b/tests/mutate_ticks.rs @@ -21,9 +21,9 @@ fn without_changes() { }), )) .track_mutate_messages() - .replicate::(); + .replicate::() + .finish(); } - client_app.finish(); server_app.connect_client(&mut client_app); @@ -56,9 +56,9 @@ fn one_message() { }), )) .track_mutate_messages() - .replicate::(); + .replicate::() + .finish(); } - client_app.finish(); server_app.connect_client(&mut client_app); @@ -123,9 +123,9 @@ fn multiple_messages() { }), )) .track_mutate_messages() - .replicate::(); + .replicate::() + .finish(); } - client_app.finish(); server_app.connect_client(&mut client_app); diff --git a/tests/mutations.rs b/tests/mutations.rs index d9fb165a..30c77fde 100644 --- a/tests/mutations.rs +++ b/tests/mutations.rs @@ -33,7 +33,8 @@ fn small_component() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -79,7 +80,8 @@ fn package_size_component() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -132,7 +134,8 @@ fn many_components() { }), )) .replicate::() - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -186,7 +189,8 @@ fn once() { ..Default::default() }), )) - .replicate_once::(); + .replicate_once::() + .finish(); } server_app.connect_client(&mut client_app); @@ -233,7 +237,8 @@ fn periodic() { ..Default::default() }), )) - .replicate_periodic::(PERIOD); + .replicate_periodic::(PERIOD) + .finish(); } server_app.connect_client(&mut client_app); @@ -289,7 +294,8 @@ fn periodic_with_miss() { ..Default::default() }), )) - .replicate_periodic::(PERIOD); + .replicate_periodic::(PERIOD) + .finish(); } server_app.connect_client(&mut client_app); @@ -353,7 +359,8 @@ fn related() { }), )) .sync_related_entities::() - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -398,7 +405,8 @@ fn command_fns() { }), )) .replicate::() - .set_command_fns(replace, command_fns::default_remove::); + .set_command_fns(replace, command_fns::default_remove::) + .finish(); } server_app.connect_client(&mut client_app); @@ -450,7 +458,8 @@ fn marker() { .set_marker_fns::( replace, command_fns::default_remove::, - ); + ) + .finish(); } server_app.connect_client(&mut client_app); @@ -512,7 +521,8 @@ fn marker_with_history() { write_history, command_fns::default_remove::, ) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -588,7 +598,8 @@ fn marker_with_history_consume() { command_fns::default_remove::, ) .replicate::() - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -676,7 +687,8 @@ fn marker_with_history_old_update() { write_history, command_fns::default_remove::, ) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -744,7 +756,8 @@ fn many_entities() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -797,7 +810,8 @@ fn with_insertion() { }), )) .replicate::() - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -841,7 +855,8 @@ fn with_removal() { }), )) .replicate::() - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -884,7 +899,8 @@ fn with_despawn() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -932,7 +948,8 @@ fn buffering() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -989,7 +1006,8 @@ fn old_ignored() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -1056,7 +1074,8 @@ fn acknowledgment() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -1132,9 +1151,9 @@ fn confirm_history() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } - client_app.finish(); server_app.connect_client(&mut client_app); @@ -1198,7 +1217,8 @@ fn after_disconnect() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); diff --git a/tests/removal.rs b/tests/removal.rs index e46731e6..200f0225 100644 --- a/tests/removal.rs +++ b/tests/removal.rs @@ -24,7 +24,8 @@ fn single() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -67,7 +68,8 @@ fn multiple() { }), )) .replicate::() - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -117,7 +119,8 @@ fn command_fns() { }), )) .replicate::() - .set_command_fns(replace, command_fns::default_remove::); + .set_command_fns(replace, command_fns::default_remove::) + .finish(); } server_app.connect_client(&mut client_app); @@ -164,7 +167,8 @@ fn marker() { .set_marker_fns::( replace, command_fns::default_remove::, - ); + ) + .finish(); } server_app.connect_client(&mut client_app); @@ -213,7 +217,8 @@ fn group() { ..Default::default() }), )) - .replicate_bundle::<(ComponentA, ComponentB)>(); + .replicate_bundle::<(ComponentA, ComponentB)>() + .finish(); } server_app.connect_client(&mut client_app); @@ -259,7 +264,8 @@ fn not_replicated() { tick_policy: TickPolicy::EveryFrame, ..Default::default() }), - )); + )) + .finish(); } server_app.connect_client(&mut client_app); @@ -310,7 +316,8 @@ fn after_insertion() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -354,7 +361,8 @@ fn with_spawn() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -386,7 +394,8 @@ fn with_despawn() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -430,7 +439,8 @@ fn confirm_history() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -499,7 +509,8 @@ fn hidden() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); diff --git a/tests/scene.rs b/tests/scene.rs index b560f410..531388ff 100644 --- a/tests/scene.rs +++ b/tests/scene.rs @@ -10,7 +10,8 @@ fn replicated_entity() { .register_type::() .replicate::() .replicate::() // Reflected, but the type is not registered. - .replicate::(); + .replicate::() + .finish(); let entity = app .world_mut() @@ -40,7 +41,7 @@ fn replicated_entity() { #[test] fn empty_entity() { let mut app = App::new(); - app.add_plugins(RepliconPlugins); + app.add_plugins(RepliconPlugins).finish(); let entity = app.world_mut().spawn(Replicated).id(); @@ -61,7 +62,8 @@ fn not_replicated_entity() { let mut app = App::new(); app.add_plugins(RepliconPlugins) .register_type::() - .replicate::(); + .replicate::() + .finish(); app.world_mut().spawn(TestComponent); @@ -78,7 +80,8 @@ fn entity_update() { app.add_plugins(RepliconPlugins) .register_type::() .replicate::() - .register_type::(); + .register_type::() + .finish(); let entity = app .world_mut() diff --git a/tests/spawn.rs b/tests/spawn.rs index bf781bf3..9deae559 100644 --- a/tests/spawn.rs +++ b/tests/spawn.rs @@ -18,7 +18,8 @@ fn empty() { tick_policy: TickPolicy::EveryFrame, ..Default::default() }), - )); + )) + .finish(); } server_app.connect_client(&mut client_app); @@ -60,7 +61,8 @@ fn with_component() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -90,7 +92,8 @@ fn with_multiple_components() { }), )) .replicate::() - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -128,7 +131,8 @@ fn with_old_component() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -172,7 +176,8 @@ fn before_connection() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } // Spawn an entity before client connected. @@ -201,7 +206,8 @@ fn pre_spawn() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -269,7 +275,8 @@ fn after_despawn() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); diff --git a/tests/stats.rs b/tests/stats.rs index 8d8c0399..aba3426f 100644 --- a/tests/stats.rs +++ b/tests/stats.rs @@ -17,7 +17,8 @@ fn client_stats() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); diff --git a/tests/visibility.rs b/tests/visibility.rs index 3e147e2f..71e21302 100644 --- a/tests/visibility.rs +++ b/tests/visibility.rs @@ -18,7 +18,8 @@ fn empty_blacklist() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -48,7 +49,8 @@ fn blacklist() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -103,7 +105,8 @@ fn blacklist_with_despawn() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -145,7 +148,8 @@ fn empty_whitelist() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -177,7 +181,8 @@ fn whitelist() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app); @@ -235,7 +240,8 @@ fn whitelist_with_despawn() { ..Default::default() }), )) - .replicate::(); + .replicate::() + .finish(); } server_app.connect_client(&mut client_app);