From 13ff574f3067094b9c252b6353fa0df5d6317624 Mon Sep 17 00:00:00 2001 From: core Date: Mon, 8 Jun 2026 23:03:27 -0400 Subject: [PATCH] netcode: unreliable updates --- Cargo.lock | 7 ++ Cargo.toml | 1 + crates/unified/Cargo.toml | 1 + crates/unified/src/client/mod.rs | 16 ++-- .../unified/src/client/net/incoming_parts.rs | 47 ++++++----- .../src/client/net/incoming_planets.rs | 43 +++++----- crates/unified/src/server/mod.rs | 15 +--- crates/unified/src/server/net/update_parts.rs | 78 ++++--------------- .../unified/src/server/net/update_planets.rs | 74 ++++-------------- crates/unified/src/shared/net.rs | 62 ++++++++------- crates/unified/src/shared/net/part.rs | 16 ++-- crates/unified/src/shared/net/planet.rs | 14 +--- crates/unified/src/shared/net/was_updated.rs | 24 ++++++ 13 files changed, 152 insertions(+), 246 deletions(-) create mode 100644 crates/unified/src/shared/net/was_updated.rs diff --git a/Cargo.lock b/Cargo.lock index bbe6003aa89b1f6d78ab00edf19903a8e6d4ff23..c8bf7d9ca06a01bff67487443abe01af8a92b32d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5569,6 +5569,12 @@ dependencies = [ "serde", ] +[[package]] +name = "smolvec" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b43855ed42c16647e6f7d19fdef4b020529c822f77a5ab417eb2278e11756da7" + [[package]] name = "socket2" version = "0.6.3" @@ -5653,6 +5659,7 @@ dependencies = [ "postcard", "rand 0.10.1", "serde", + "smolvec", "tracing-subscriber", "tracing-web", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 6f73d7a0dbd950ca66552aaede57214235d7b64f..db014f773729d80c4687c5f636add12a8f10c63a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ aeronet_transport = { version = "0.20" } aeronet_replicon = { version = "0.20" } bevy_replicon = { version = "0.39"} postcard = { version = "1.1.3", features = ["alloc"] } +smolvec = { version = "1" } [profile.dev] opt-level = 1 diff --git a/crates/unified/Cargo.toml b/crates/unified/Cargo.toml index 532d44e0bb38368a20a825f491a073ebf7e21e3c..19e5edaf232efd2c57c4b7ced77990c047e12a41 100644 --- a/crates/unified/Cargo.toml +++ b/crates/unified/Cargo.toml @@ -20,6 +20,7 @@ web-time = { workspace = true } aeronet = { workspace = true } aeronet_transport = { workspace = true } postcard = { workspace = true } +smolvec = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ctrlc = { workspace = true, optional = true } diff --git a/crates/unified/src/client/mod.rs b/crates/unified/src/client/mod.rs index 25793db12eaaf09b5fc445a7b16bbd2713074838..8fa0ef61fd842c81ab1c03a6c0ae23c4ca9f413b 100644 --- a/crates/unified/src/client/mod.rs +++ b/crates/unified/src/client/mod.rs @@ -22,7 +22,7 @@ use crate::client::components::Me; use crate::client::ship::attachment::client_attachment_plugin; use crate::shared::ecs::{GameplayState, TimeOffset}; use crate::shared::gravity::update_gravity; -use crate::shared::net::{Hi, ClientMessageRegistry, ServerMessageRegistry, ServerEntityMap}; +use crate::shared::net::{Hi, ClientMessageRegistry, ServerMessageRegistry, ServerEntityMap, TransportLanes}; use crate::shared::orbit::OrbitPlugin; pub mod colors; @@ -104,8 +104,7 @@ pub fn on_connected( trigger: On, names: Query<&Name>, sessions: Query<&Session>, - server_message_registry: Res, - client_message_registry: Res, + lanes: Res, mut commands: Commands, ) { let entity = trigger.event_target(); @@ -114,15 +113,10 @@ pub fn on_connected( return; }; - let server_message_count = server_message_registry.message_count(); - let client_message_count = client_message_registry.message_count(); - let message_count = server_message_count + client_message_count; - debug!("message count: {}", message_count); - let lanes = [LaneKind::ReliableOrdered].repeat(message_count); let transport = Transport::new( session, - lanes.clone(), - lanes, + lanes.lanes.iter().map(|u| u.clone()), + lanes.lanes.iter().map(|u| u.clone()), bevy::platform::time::Instant::now(), ).expect("packet MTU too small to support transport"); commands.entity(entity).insert(transport); @@ -147,7 +141,7 @@ pub fn on_disconnected(trigger: On, names: Query<&Name>) { } #[derive(Resource)] -struct HeartyEntityId(Option); +pub struct HeartyEntityId(Option); pub fn handle_hi( mut msgs: MessageReader, diff --git a/crates/unified/src/client/net/incoming_parts.rs b/crates/unified/src/client/net/incoming_parts.rs index 0bdab9a8c96ef3b2905347948c796842f30fe43c..dacd1d225f049bbd959b191cd47c3a413ea58379 100644 --- a/crates/unified/src/client/net/incoming_parts.rs +++ b/crates/unified/src/client/net/incoming_parts.rs @@ -2,39 +2,36 @@ use bevy::log::{debug, warn}; use bevy::prelude::{Commands, MessageReader, ResMut, Transform}; use crate::prelude::Query; use crate::shared::ecs::{Part, Temperature}; -use crate::shared::net::part::PartUpdatePacket; +use crate::shared::net::part::{PartDto}; use crate::shared::net::ServerEntityMap; pub fn handle_incoming_parts( - mut msgs: MessageReader, + mut msgs: MessageReader, mut q_parts: Query<(&mut Part, &mut Transform, &mut Temperature)>, mut entity_map: ResMut, mut commands: Commands ) { - for msg in msgs.read() { - 'to_next_part: for part in &msg.updated_parts { - if let Some(local_entity) = entity_map.server_to_client.get(&part.server_entity) { - let Ok((mut part_data, mut transform, mut temperature)) = q_parts.get_mut(*local_entity) else { - warn!("local part entity {:?} for part srv:{:?} doesn't exist? skipping update, this is a bug", local_entity, part.server_entity); - continue 'to_next_part - }; - if part.part_data_changed { - *part_data = part.part.clone(); - } - *transform = part.transform; - *temperature = part.temperature; - } else { - // Spawn new part - let e = commands.spawn(( - part.part.clone(), - part.transform, - part.temperature, - )).id(); - entity_map.server_to_client.insert(part.server_entity, e.clone()); - entity_map.client_to_server.insert(e.clone(), part.server_entity); - debug!(?part.part, "spawned new part"); - } + for part in msgs.read() { + if let Some(local_entity) = entity_map.server_to_client.get(&part.server_entity) { + let Ok((mut part_data, mut transform, mut temperature)) = q_parts.get_mut(*local_entity) else { + warn!("local part entity {:?} for part srv:{:?} doesn't exist? skipping update, this is a bug", local_entity, part.server_entity); + continue; + }; + part.part.update(part_data); + part.transform.update(transform); + part.temperature.update(temperature); + } else { + // Spawn new part + let e = commands.spawn(( + part.part.data().clone(), + *part.transform.data(), + *part.temperature.data(), + )).id(); + entity_map.server_to_client.insert(part.server_entity, e.clone()); + entity_map.client_to_server.insert(e.clone(), part.server_entity); + debug!(?part.part, "spawned new part"); } + } } \ No newline at end of file diff --git a/crates/unified/src/client/net/incoming_planets.rs b/crates/unified/src/client/net/incoming_planets.rs index 93332a1ba7dd8155495f57c53dfdfc8ecbf57dd5..6749970fd64e42bef1098a2c44a2861a8e28f2c4 100644 --- a/crates/unified/src/client/net/incoming_planets.rs +++ b/crates/unified/src/client/net/incoming_planets.rs @@ -2,37 +2,34 @@ use bevy::log::{debug, warn}; use bevy::prelude::{Commands, MessageReader, ResMut, Transform}; use crate::prelude::Query; use crate::shared::config::planet::Planet; -use crate::shared::net::planet::PlanetUpdatePacket; +use crate::shared::net::planet::{PlanetDto}; use crate::shared::net::ServerEntityMap; pub fn handle_incoming_planets( - mut msgs: MessageReader, + mut msgs: MessageReader, mut q_planets: Query<(&mut Planet, &mut Transform)>, mut entity_map: ResMut, mut commands: Commands ) { - for msg in msgs.read() { - 'to_next_planet: for planet in &msg.updated_planets { - if let Some(local_entity) = entity_map.server_to_client.get(&planet.server_entity) { - let Ok((mut planet_data, mut transform)) = q_planets.get_mut(*local_entity) else { - warn!("local planet entity {:?} for planet srv:{:?} doesn't exist? skipping update, this is a bug", local_entity, planet.server_entity); - continue 'to_next_planet - }; - if planet.planet_data_changed { - *planet_data = planet.planet.clone(); - } - *transform = planet.transform; - } else { - // Spawn new planet - let e = commands.spawn(( - planet.planet.clone(), - planet.transform - )).id(); - entity_map.server_to_client.insert(planet.server_entity, e.clone()); - entity_map.client_to_server.insert(e.clone(), planet.server_entity); - debug!(?planet.planet, "spawned new planet"); - } + for planet in msgs.read() { + if let Some(local_entity) = entity_map.server_to_client.get(&planet.server_entity) { + let Ok((mut planet_data, mut transform)) = q_planets.get_mut(*local_entity) else { + warn!("local planet entity {:?} for planet srv:{:?} doesn't exist? skipping update, this is a bug", local_entity, planet.server_entity); + continue; + }; + planet.planet.update(planet_data); + planet.transform.update(transform); + } else { + // Spawn new planet + let e = commands.spawn(( + planet.planet.data().clone(), + *planet.transform.data(), + )).id(); + entity_map.server_to_client.insert(planet.server_entity, e.clone()); + entity_map.client_to_server.insert(e.clone(), planet.server_entity); + debug!(?planet.planet, "spawned new planet"); } + } } \ No newline at end of file diff --git a/crates/unified/src/server/mod.rs b/crates/unified/src/server/mod.rs index a5cb92d3b17587ab8dd947c540e96577edd06bac..2e6265b902c25a62f689fa68a99061e21539770a 100644 --- a/crates/unified/src/server/mod.rs +++ b/crates/unified/src/server/mod.rs @@ -37,7 +37,7 @@ use crate::server::system_sets::{PlayerInputSet, WorldUpdateSet}; use crate::prelude::*; use crate::server::orbit::OrbitPlugin; use crate::server::player::thrust::server_thrust_plugin; -use crate::shared::net::{ClientMessageRegistry, ServerMessageRegistry}; +use crate::shared::net::{ClientMessageRegistry, ServerMessageRegistry, TransportLanes}; pub struct ServerPlugin { pub bind: SocketAddr @@ -95,8 +95,7 @@ fn on_connected( trigger: On, clients: Query<&ChildOf>, sessions: Query<&Session>, - server_message_registry: Res, - client_message_registry: Res, + lanes: Res, mut commands: Commands, ) { let client = trigger.event_target(); @@ -112,16 +111,10 @@ fn on_connected( network_entity: client, })) .id(); - - let server_message_count = server_message_registry.message_count(); - let client_message_count = client_message_registry.message_count(); - let message_count = server_message_count + client_message_count; - debug!("message count: {}", message_count); - let lanes = [LaneKind::ReliableOrdered].repeat(message_count); let transport = Transport::new( session, - lanes.clone(), - lanes, + lanes.lanes.iter().map(|u| u.clone()), + lanes.lanes.iter().map(|u| u.clone()), bevy::platform::time::Instant::now(), ).expect("packet MTU too small to support transport"); commands.entity(client).insert(( diff --git a/crates/unified/src/server/net/update_parts.rs b/crates/unified/src/server/net/update_parts.rs index f3e891aae68e4b191b0c42bb4a6abffceb384679..25cb111cd89da69a76b3bd767794cd85b3d8ce5e 100644 --- a/crates/unified/src/server/net/update_parts.rs +++ b/crates/unified/src/server/net/update_parts.rs @@ -1,75 +1,23 @@ use std::collections::BTreeSet; -use bevy::prelude::{Added, Changed, Commands, MessageWriter, Query}; +use bevy::prelude::{Added, Changed, Commands, MessageWriter, Query, Ref}; use crate::prelude::{debug, Entity, ParamSet, Transform}; use crate::shared::ecs::{Part, Temperature}; -use crate::shared::net::part::{PartUpdatePacket, PartDto}; +use crate::shared::net::part::{PartDto}; use crate::shared::net::staged_transform::LastStagedTransform; use crate::shared::net::{SendTargets, ToClients}; - pub fn send_updated_parts( - mut set: ParamSet<( - // If you need to send more data, don't add it here... - Query<(Entity, &Transform), Added>, - Query<(Entity, &Transform, &LastStagedTransform), Changed>, - Query>, - - // add it here. - Query<(&Part, &Transform, &Temperature, &mut LastStagedTransform)>, - )>, - - mut update_packets_out: MessageWriter>, - mut commands: Commands + parts: Query<(Entity, Ref, Ref, Ref)>, + mut messages: MessageWriter> ) { - let start = bevy::platform::time::Instant::now(); - let mut parts_to_send: BTreeSet = BTreeSet::new(); - - // Updating the part behavior triggers sprite loading on the client. We don't want to send it every time the Transform changes - let mut parts_with_part_change: BTreeSet = BTreeSet::new(); - - for (new_part, transform) in set.p0().iter() { - parts_to_send.insert(new_part); // Always send newly created parts... - // ...and add LastStagedTransform... - commands.entity(new_part).insert(LastStagedTransform(*transform)); - // and put a marker, we need to copy part data across - parts_with_part_change.insert(new_part); - } - for (moved_part, current_transform, maybe_staged_transform) in set.p1().iter() { - // have we had a significant transform change? - if !maybe_staged_transform.should_update(current_transform) { continue; } - // we have, resend - parts_to_send.insert(moved_part); - } - for changed_part in set.p2().iter() { - // if part changed, always resend - parts_to_send.insert(changed_part); - // and put a marker, we need to copy part data across - parts_with_part_change.insert(changed_part); - } - - // process all parts to send - let mut packet = PartUpdatePacket { - updated_parts: vec![] - }; - - for part_to_send in parts_to_send.iter() { - let mut q = set.p3(); - let Ok(mut part_info) = q.get_mut(*part_to_send) else { continue }; - - *part_info.3 = LastStagedTransform(*part_info.1); - - packet.updated_parts.push(PartDto { - server_entity: *part_to_send, - part: part_info.0.clone(), - part_data_changed: parts_with_part_change.contains(part_to_send), - transform: *part_info.1, - temperature: *part_info.2 + for part in parts { + messages.write(ToClients { + message: PartDto { + server_entity: part.0, + part: part.1.into(), + transform: part.2.into(), + temperature: part.3.into() + }, + targets: SendTargets::All }); - } - - update_packets_out.write(ToClients { - message: packet, - targets: SendTargets::All, - }); - } \ No newline at end of file diff --git a/crates/unified/src/server/net/update_planets.rs b/crates/unified/src/server/net/update_planets.rs index c7e9e73398b8cf24f1b58df165f1d560161128ca..b3298b5291b45cab7098484deefb06dd751217d3 100644 --- a/crates/unified/src/server/net/update_planets.rs +++ b/crates/unified/src/server/net/update_planets.rs @@ -1,71 +1,25 @@ use std::collections::BTreeSet; use bevy::prelude::{Added, Changed, Commands, MessageWriter, Query}; -use crate::prelude::{Entity, ParamSet, Transform}; +use crate::prelude::{Entity, ParamSet, Ref, Transform}; use crate::shared::config::planet::Planet; -use crate::shared::net::planet::{PlanetUpdatePacket, PlanetDto}; +use crate::shared::ecs::{Part, Temperature}; +use crate::shared::net::planet::PlanetDto; use crate::shared::net::staged_transform::LastStagedTransform; use crate::shared::net::{SendTargets, ToClients}; +use crate::shared::net::part::PartDto; pub fn send_updated_planets( - mut set: ParamSet<( - // If you need to send more data, don't add it here... - Query<(Entity, &Transform), Added>, - Query<(Entity, &Transform, &LastStagedTransform), Changed>, - Query>, - - // add it here. - Query<(&Planet, &Transform, &mut LastStagedTransform)>, - )>, - - mut update_packets_out: MessageWriter>, - mut commands: Commands + planets: Query<(Entity, Ref, Ref, Ref)>, + mut messages: MessageWriter> ) { - let mut planets_to_send: BTreeSet = BTreeSet::new(); - - // Updating the Planet behavior triggers sprite loading on the client. We don't want to send it every time the Transform changes - let mut planets_with_planet_change: BTreeSet = BTreeSet::new(); - - for (new_planet, transform) in set.p0().iter() { - planets_to_send.insert(new_planet); // Always send newly created planets... - // ...and add LastStagedTransform... - commands.entity(new_planet).insert(LastStagedTransform(*transform)); - // and put a marker, we need to copy planet data across - planets_with_planet_change.insert(new_planet); - } - for (moved_planet, current_transform, maybe_staged_transform) in set.p1().iter() { - // have we had a significant transform change? - if !maybe_staged_transform.should_update(current_transform) { continue; } - // we have, resend - planets_to_send.insert(moved_planet); - } - for changed_planet in set.p2().iter() { - // if Planet changed, always resend - planets_to_send.insert(changed_planet); - // and put a marker, we need to copy planet data across - planets_with_planet_change.insert(changed_planet); - } - - // process all planets to send - let mut packet = PlanetUpdatePacket { - updated_planets: vec![] - }; - - for planet_to_send in planets_to_send.iter() { - let mut p3 = set.p3(); - let Ok(mut planet_info) = p3.get_mut(*planet_to_send) else { continue }; - - *planet_info.2 = LastStagedTransform(*planet_info.1); - - packet.updated_planets.push(PlanetDto { - server_entity: *planet_to_send, - planet: planet_info.0.clone(), - planet_data_changed: planets_with_planet_change.contains(planet_to_send), - transform: *planet_info.1, + for planet in planets { + messages.write(ToClients { + message: PlanetDto { + server_entity: planet.0, + planet: planet.1.into(), + transform: planet.2.into(), + }, + targets: SendTargets::All }); } - - update_packets_out.write(ToClients { - message: packet, - targets: SendTargets::All, - }); } \ No newline at end of file diff --git a/crates/unified/src/shared/net.rs b/crates/unified/src/shared/net.rs index 081963d07a74fa72654b2acaa482fd916cbc91d9..4904b0a082eafea05f09d965efdb413785208ea9 100644 --- a/crates/unified/src/shared/net.rs +++ b/crates/unified/src/shared/net.rs @@ -1,6 +1,7 @@ pub mod planet; pub mod staged_transform; pub mod part; +pub mod was_updated; use std::any::TypeId; use std::collections::HashMap; @@ -9,7 +10,7 @@ use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; use std::time::Instant; use aeronet_transport::Transport; -use aeronet_transport::lane::LaneIndex; +use aeronet_transport::lane::{LaneIndex, LaneKind}; use aeronet_websocket::tungstenite::Bytes; use avian2d::prelude::{AngularInertia, AngularVelocity, Collider, LinearVelocity, Mass, Position, Rotation}; use bevy::ecs::entity::{EntityHashMap, MapEntities}; @@ -20,24 +21,25 @@ use postcard::{from_bytes, to_allocvec, to_slice, to_vec}; use crate::prelude::{App, Message}; use crate::shared::thrust::ThrustSolution; use serde::{Deserialize, Serialize}; +use smolvec::SmolVec; use crate::shared::attachment::{Joint, JointOf, PartInShip, Peer, Ship, SnapOf, SnapOfJoint}; use crate::shared::config::planet::{Planet, PlanetSpring, PlanetSpringJoint}; use crate::shared::ecs::{CanCraft, CraftPartRequest, DragRequestEvent, Drill, Part, Player, PlayerStorage, SingleStorage, Temperature, ToggleDrillEvent}; use crate::shared::ecs::thruster::{Thruster, ThrusterOfPart}; -use crate::shared::net::part::PartUpdatePacket; -use crate::shared::net::planet::PlanetUpdatePacket; +use crate::shared::net::part::PartDto; +use crate::shared::net::planet::PlanetDto; pub fn register_net(app: &mut App) { app - .add_server_message::() + .add_server_message::(LaneKind::ReliableOrdered) - .add_server_message::() - .add_server_message::() + .add_server_message::(LaneKind::UnreliableSequenced) + .add_server_message::(LaneKind::UnreliableSequenced) - .add_client_message::() - .add_client_message::() - .add_client_message::() - .add_client_message::() + .add_client_message::(LaneKind::ReliableOrdered) + .add_client_message::(LaneKind::ReliableOrdered) + .add_client_message::(LaneKind::ReliableOrdered) + .add_client_message::(LaneKind::ReliableOrdered) .add_systems(PostStartup, |srv_msg_reg: Res, client_msg_reg: Res| { debug!("network registration complete"); @@ -56,6 +58,7 @@ pub struct Hi { pub fn setup_net(app: &mut App) { app.insert_resource(ServerMessageRegistry::default()); app.insert_resource(ClientMessageRegistry::default()); + app.insert_resource(TransportLanes::default()); app.add_systems(Update, recv_from_server); app.add_systems(Update, recv_from_client); } @@ -84,6 +87,11 @@ pub enum ClientId { Client(Entity), } +#[derive(Resource, Default)] +pub struct TransportLanes { + pub lanes: Vec +} + #[derive(Resource, Default)] pub struct ServerEntityMap { pub server_to_client: EntityHashMap, @@ -94,21 +102,11 @@ pub struct ServerMessageRegistry { forward: HashMap, reverse: HashMap, &mut World)>, } -impl ServerMessageRegistry { - pub fn message_count(&self) -> usize { - self.forward.len() - } -} #[derive(Resource, Default, Debug)] pub struct ClientMessageRegistry { forward: HashMap, reverse: HashMap, ClientId, &mut World)>, } -impl ClientMessageRegistry { - pub fn message_count(&self) -> usize { - self.forward.len() - } -} static COUNTER: AtomicU32 = AtomicU32::new(0); fn get_lane_index() -> LaneIndex { @@ -116,39 +114,43 @@ fn get_lane_index() -> LaneIndex { } pub trait NetAppExt { - fn add_mapped_server_message Deserialize<'a>>(&mut self) -> &mut Self; - fn add_server_message Deserialize<'a>>(&mut self) -> &mut Self; - fn add_mapped_client_message Deserialize<'a>>(&mut self) -> &mut Self; - fn add_client_message Deserialize<'a>>(&mut self) -> &mut Self; + fn add_mapped_server_message Deserialize<'a>>(&mut self, kind: LaneKind) -> &mut Self; + fn add_server_message Deserialize<'a>>(&mut self, kind: LaneKind) -> &mut Self; + fn add_mapped_client_message Deserialize<'a>>(&mut self, kind: LaneKind) -> &mut Self; + fn add_client_message Deserialize<'a>>(&mut self, kind: LaneKind) -> &mut Self; } impl NetAppExt for App { - fn add_mapped_server_message Deserialize<'a>>(&mut self) -> &mut Self { + fn add_mapped_server_message Deserialize<'a>>(&mut self, kind: LaneKind) -> &mut Self { let mut registry = self.world_mut().resource_mut::(); register_mapped_server_message::(&mut registry); + self.world_mut().resource_mut::().lanes.push(kind); self .add_message::>() .add_message::() .add_systems(Update, send_to_client::) } - fn add_server_message Deserialize<'a>>(&mut self) -> &mut Self { + fn add_server_message Deserialize<'a>>(&mut self, kind: LaneKind) -> &mut Self { let mut registry = self.world_mut().resource_mut::(); register_server_message::(&mut registry); + self.world_mut().resource_mut::().lanes.push(kind); self .add_message::>() .add_message::() .add_systems(Update, send_to_client::) } - fn add_mapped_client_message Deserialize<'a>>(&mut self) -> &mut Self { + fn add_mapped_client_message Deserialize<'a>>(&mut self, kind: LaneKind) -> &mut Self { let mut registry = self.world_mut().resource_mut::(); register_client_message::(&mut registry); + self.world_mut().resource_mut::().lanes.push(kind); self .add_message::>() .add_message::() .add_systems(Update, send_mapped_to_server::) } - fn add_client_message Deserialize<'a>>(&mut self) -> &mut Self { + fn add_client_message Deserialize<'a>>(&mut self, kind: LaneKind) -> &mut Self { let mut registry = self.world_mut().resource_mut::(); register_client_message::(&mut registry); + self.world_mut().resource_mut::().lanes.push(kind); self .add_message::>() .add_message::() @@ -260,7 +262,7 @@ fn recv_from_server( Res, )> = SystemState::new(world); let (mut sessions, message_registry) = system_state.get_mut(world); - let mut messages = Vec::new(); + let mut messages = SmolVec::new(); for mut transport in sessions.iter_mut() { for message in transport.recv.msgs.drain() { let payload = message.payload; @@ -283,7 +285,7 @@ fn recv_from_client( Res, )> = SystemState::new(world); let (mut clients, message_registry) = system_state.get_mut(world); - let mut messages = Vec::new(); + let mut messages = SmolVec::new(); for (client_entity, mut transport) in clients.iter_mut() { for message in transport.recv.msgs.drain() { let payload = message.payload; diff --git a/crates/unified/src/shared/net/part.rs b/crates/unified/src/shared/net/part.rs index 73f84bdcedaf592a17719dd86b0b0aba922bd888..4294245a18eed6f528db25003fbd53cc8962534d 100644 --- a/crates/unified/src/shared/net/part.rs +++ b/crates/unified/src/shared/net/part.rs @@ -2,19 +2,13 @@ use bevy::prelude::{Entity, Message, Transform, TypePath}; use serde::{Deserialize, Serialize}; use crate::shared::config::planet::Planet; use crate::shared::ecs::{Part, Temperature}; +use crate::shared::net::was_updated::WasUpdated; -#[derive(Serialize, Deserialize, Message, TypePath, Debug, Clone)] -pub struct PartUpdatePacket { - pub updated_parts: Vec -} - -#[derive(Serialize, Deserialize, TypePath, Debug, Clone)] +#[derive(Serialize, Deserialize, TypePath, Debug, Clone, Message)] pub struct PartDto { pub server_entity: Entity, - pub part: Part, - pub part_data_changed: bool, - - pub transform: Transform, - pub temperature: Temperature, + pub part: WasUpdated, + pub transform: WasUpdated, + pub temperature: WasUpdated, } \ No newline at end of file diff --git a/crates/unified/src/shared/net/planet.rs b/crates/unified/src/shared/net/planet.rs index d3cbe8e9044ed00f03cde6c9cee4ce748c065854..d74f667be143269aeaa68b3984463e1f657ffcc6 100644 --- a/crates/unified/src/shared/net/planet.rs +++ b/crates/unified/src/shared/net/planet.rs @@ -1,18 +1,12 @@ use bevy::prelude::{Entity, Message, Transform, TypePath}; use serde::{Deserialize, Serialize}; use crate::shared::config::planet::Planet; +use crate::shared::net::was_updated::WasUpdated; -#[derive(Serialize, Deserialize, Message, TypePath, Debug, Clone)] -pub struct PlanetUpdatePacket { - pub updated_planets: Vec -} - -#[derive(Serialize, Deserialize, TypePath, Debug, Clone)] +#[derive(Serialize, Deserialize, TypePath, Debug, Clone, Message)] pub struct PlanetDto { pub server_entity: Entity, - pub planet: Planet, - pub planet_data_changed: bool, - - pub transform: Transform + pub planet: WasUpdated, + pub transform: WasUpdated } \ No newline at end of file diff --git a/crates/unified/src/shared/net/was_updated.rs b/crates/unified/src/shared/net/was_updated.rs new file mode 100644 index 0000000000000000000000000000000000000000..5f10cd710abeb73d167350ec96410f713b0d3b2a --- /dev/null +++ b/crates/unified/src/shared/net/was_updated.rs @@ -0,0 +1,24 @@ +use std::fmt::Debug; +use bevy::prelude::{Mut, Ref}; +use serde::{Deserialize, Serialize}; +use serde::de::DeserializeOwned; +use crate::prelude::DetectChanges; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct WasUpdated(T, bool); +impl From> for WasUpdated { + fn from(value: Ref) -> Self { + let changed = value.is_changed(); + Self(value.into_inner().clone(), changed) + } +} +impl WasUpdated { + pub fn update(&self, mut data: Mut) { + if self.1 { + *data = self.0.clone(); + } + } + pub fn data(&self) -> &T { + &self.0 + } +} \ No newline at end of file