From 439516a39e5b7cf4f7c4f7310adc86814b58d61e Mon Sep 17 00:00:00 2001 From: Raffaele Ragni Date: Sun, 23 Jun 2024 09:54:27 +0200 Subject: [PATCH] initial sync only on new sessions --- src/client/mod.rs | 17 +++++++++++++++-- src/client/receiver.rs | 12 +++++++++++- src/lib_priv.rs | 9 +++++++++ src/logging.rs | 1 + src/proto.rs | 1 + src/server/mod.rs | 1 - src/server/receiver.rs | 18 ++++++++++++++++-- tests/host_promotion.rs | 3 --- tests/setup/mod.rs | 9 ++------- 9 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/client/mod.rs b/src/client/mod.rs index d91686b..84b6c59 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -5,7 +5,7 @@ use bevy_renet::renet::{ }; use crate::{ - lib_priv::{sync_material_enabled, sync_mesh_enabled, SyncTrackerRes}, + lib_priv::{sync_material_enabled, sync_mesh_enabled, PromotionState, SyncTrackerRes}, proto::Message, ClientState, }; @@ -73,9 +73,22 @@ fn client_connecting(mut client_state: ResMut>) { client_state.set(ClientState::Connecting); } -fn client_connected(mut client_state: ResMut>, mut cmd: Commands) { +fn client_connected( + mut client_state: ResMut>, + mut cmd: Commands, + mut client: ResMut, + promotion_state: Res>, +) { info!("Connected to server."); client_state.set(ClientState::Connected); + if promotion_state.eq(&PromotionState::NeverPromoted) { + // this connection is a new session and requires the initial information + // from initial sync + client.send_message( + DefaultChannel::ReliableOrdered, + bincode::serialize(&Message::RequestInitialSync {}).unwrap(), + ) + } // remove any previous pending server since the instance is a client now // this servers can be pending after a host promotion cmd.remove_resource::(); diff --git a/src/client/receiver.rs b/src/client/receiver.rs index b392719..d2d0832 100644 --- a/src/client/receiver.rs +++ b/src/client/receiver.rs @@ -1,5 +1,5 @@ use crate::{ - lib_priv::PromotedToServer, + lib_priv::{PromotedToServer, PromotionState}, logging::{log_message_received, Who}, networking::{assets::SyncAssetTransfer, create_client, create_server}, proto::SyncAssetType, @@ -15,6 +15,7 @@ pub(crate) fn poll_for_messages( mut sync_assets: ResMut, mut client: ResMut, mut send_promoted_event: EventWriter, + mut promotion_state: ResMut>, ) { while let Some(message) = client.receive_message(DefaultChannel::ReliableOrdered) { let deser_message = bincode::deserialize(&message).unwrap(); @@ -26,10 +27,12 @@ pub(crate) fn poll_for_messages( &mut sync_assets, &mut commands, &mut send_promoted_event, + &mut promotion_state, ); } } +#[allow(clippy::too_many_arguments)] fn client_received_a_message( msg: Message, connection_parameters: &Res, @@ -38,6 +41,7 @@ fn client_received_a_message( sync_assets: &mut ResMut, cmd: &mut Commands, send_promoted_event: &mut EventWriter, + promotion_state: &mut ResMut>, ) { log_message_received(Who::Client, &msg); match msg { @@ -120,6 +124,7 @@ fn client_received_a_message( world.insert_resource(create_server(ip, port)); }); send_promoted_event.send(PromotedToServer {}); + promotion_state.set(PromotionState::PromotedToServer); } Message::NewHost { ip, @@ -131,6 +136,11 @@ fn client_received_a_message( client.disconnect(); cmd.remove_resource::(); cmd.insert_resource(create_client(ip, port)); + // even if it was a client before, this connection is not a new session + // and won't need the initial_sync, so it's consider a client to client promotion + promotion_state.set(PromotionState::PromotedToClient); } + // Nothing to do, only servers send initial sync + Message::RequestInitialSync => {} } } diff --git a/src/lib_priv.rs b/src/lib_priv.rs index 708a132..40c0883 100644 --- a/src/lib_priv.rs +++ b/src/lib_priv.rs @@ -33,6 +33,14 @@ pub(crate) struct PromotedToServer; #[derive(Event)] pub(crate) struct PromotedToClient; +#[derive(Debug, Clone, Eq, PartialEq, Hash, Default, States)] +pub(crate) enum PromotionState { + #[default] + NeverPromoted, + PromotedToServer, + PromotedToClient, +} + #[derive(Resource, Default)] pub(crate) struct SyncTrackerRes { /// Mapping of entity ids between server and clients. key: server, value: client @@ -237,6 +245,7 @@ impl Plugin for SyncPlugin { app.add_plugins(BundleFixPlugin); app.add_plugins(ServerSyncPlugin); app.add_plugins(ClientSyncPlugin); + app.init_state::(); app.init_state::(); app.init_state::(); app.add_event::(); diff --git a/src/logging.rs b/src/logging.rs index fbbe82d..4481145 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -64,5 +64,6 @@ pub(crate) fn log_message_received(from: Who, message: &Message) { } => debug!( "{:?} received NewHost {{ ip: {} }} {{ port: {} }} {{ web_port: {} }} {{ max_transfer: {} }}", from, ip, port, web_port, max_transfer), + Message::RequestInitialSync => debug!("Reveived a request for initial sync") } } diff --git a/src/proto.rs b/src/proto.rs index fe18d64..e21d861 100644 --- a/src/proto.rs +++ b/src/proto.rs @@ -50,6 +50,7 @@ pub(crate) enum Message { web_port: u16, max_transfer: usize, }, + RequestInitialSync, } #[derive(Event)] diff --git a/src/server/mod.rs b/src/server/mod.rs index 8c7abe7..70756e6 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -75,7 +75,6 @@ fn client_connected(mut cmd: Commands, mut server_events: EventReader { let client_id = *client_id; info!("Client connected with client id: {}", client_id); - cmd.add(move |world: &mut World| send_initial_sync(client_id, world)); // remove any previous pending client since the instance is a server now // this clients can be pending after a host promotion cmd.remove_resource::(); diff --git a/src/server/receiver.rs b/src/server/receiver.rs index 49a94c0..ec87feb 100644 --- a/src/server/receiver.rs +++ b/src/server/receiver.rs @@ -1,7 +1,7 @@ use bevy_renet::renet::ClientId; use crate::{ - lib_priv::PromotedToClient, + lib_priv::{PromotedToClient, PromotionState}, logging::{log_message_received, Who}, networking::{assets::SyncAssetTransfer, create_client}, proto::SyncAssetType, @@ -16,6 +16,8 @@ pub(crate) fn poll_for_messages( mut track: ResMut, mut sync_assets: ResMut, mut send_promoted_event: EventWriter, + promotion_state: Res>, + mut next_promotion_state: ResMut>, ) { for client_id in server.clients_id().into_iter() { while let Some(message) = server.receive_message(client_id, DefaultChannel::ReliableOrdered) @@ -29,11 +31,14 @@ pub(crate) fn poll_for_messages( &mut sync_assets, &mut commands, &mut send_promoted_event, + &promotion_state, + &mut next_promotion_state, ); } } } +#[allow(clippy::too_many_arguments)] fn server_received_a_message( client_id: ClientId, msg: Message, @@ -42,6 +47,8 @@ fn server_received_a_message( sync_assets: &mut ResMut, cmd: &mut Commands, send_promoted_event: &mut EventWriter, + promotion_state: &Res>, + next_promotion_state: &mut ResMut>, ) { log_message_received(Who::Server, &msg); match msg { @@ -145,7 +152,7 @@ fn server_received_a_message( ); }) } - // server is already host + // server is already host, no operation to do Message::PromoteToHost => (), Message::NewHost { ip, @@ -171,6 +178,13 @@ fn server_received_a_message( world.insert_resource(create_client(ip, port)); }); send_promoted_event.send(PromotedToClient {}); + next_promotion_state.set(PromotionState::PromotedToClient); + } + Message::RequestInitialSync => { + if promotion_state.eq(&PromotionState::NeverPromoted) { + debug!("Sending initial sync to client id: {}", client_id); + cmd.add(move |world: &mut World| send_initial_sync(client_id, world)); + } } } } diff --git a/tests/host_promotion.rs b/tests/host_promotion.rs index f129c36..f1927dd 100644 --- a/tests/host_promotion.rs +++ b/tests/host_promotion.rs @@ -11,7 +11,6 @@ mod setup; #[test] #[serial] -#[ignore = "host promotion is not complete"] fn test_host_promotion_with_one_client() { TestRun::default().run( 2, @@ -35,8 +34,6 @@ fn test_host_promotion_with_one_client() { .value = 7; }, |env, _, _| { - // todo fix: make the entity id server<>client more agnostic and compatible towards - // host switch let comp = get_first_entity_component::(&mut env.clients[0]).unwrap(); assert_eq!(comp.value, 7); let comp = get_first_entity_component::(&mut env.clients[1]).unwrap(); diff --git a/tests/setup/mod.rs b/tests/setup/mod.rs index b34bbd6..32a1055 100644 --- a/tests/setup/mod.rs +++ b/tests/setup/mod.rs @@ -5,13 +5,7 @@ use std::{ }; use bevy::{ - pbr::PbrPlugin, - prelude::*, - reflect::{DynamicTypePath, FromReflect, GetTypeRegistration, Reflect}, - render::{mesh::Indices, render_asset::RenderAssetUsages, render_resource::PrimitiveTopology}, - transform::TransformBundle, - utils::Uuid, - MinimalPlugins, + log::{Level, LogPlugin}, pbr::PbrPlugin, prelude::*, reflect::{DynamicTypePath, FromReflect, GetTypeRegistration, Reflect}, render::{mesh::Indices, render_asset::RenderAssetUsages, render_resource::PrimitiveTopology}, transform::TransformBundle, utils::Uuid, MinimalPlugins }; use bevy_renet::renet::RenetClient; use bevy_sync::{ClientPlugin, ServerPlugin, SyncComponent, SyncPlugin}; @@ -158,6 +152,7 @@ fn add_plugins(app: &mut App) { app.init_asset::(); app.init_asset::(); app.add_plugins(PbrPlugin::default()); + app.add_plugins(LogPlugin{level:Level::DEBUG,..default()}); app.add_plugins(SyncPlugin); }