From 11ed44a250017a0508927b34f18a597d1db1ed7d Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Fri, 5 Jun 2026 21:12:10 -0500 Subject: [PATCH] feat: serverbound messages implemented but untested --- crates/unified/src/shared/ecs.rs | 8 +- crates/unified/src/shared/net.rs | 108 ++++++++++++++++++++++----- crates/unified/src/shared/plugins.rs | 7 +- crates/unified/src/shared/thrust.rs | 5 +- 4 files changed, 100 insertions(+), 28 deletions(-) diff --git a/crates/unified/src/shared/ecs.rs b/crates/unified/src/shared/ecs.rs index 03bdef78d99c8755fbb4f2e02d39daadedc84c07..fcda652bedc9fa7ecceb9b0a344a2f3cbdf7c8a9 100644 --- a/crates/unified/src/shared/ecs.rs +++ b/crates/unified/src/shared/ecs.rs @@ -44,13 +44,13 @@ pub struct Player { pub client: Entity, } -#[derive(Message, Debug, Clone)] +#[derive(Message, Debug, Clone, Serialize, Deserialize, TypePath)] pub struct DragRequestEvent { pub drag_target: Entity, pub action: DragAction, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub enum DragAction { Attach { snap_target: Entity, peer_snap: Entity }, Free { position: Vec2, rotation: Quat }, @@ -66,7 +66,7 @@ pub struct PlayerStorage { #[derive(Component, Serialize, Deserialize, Debug)] pub struct CanCraft; -#[derive(Message, Debug, Clone)] +#[derive(Message, Debug, Clone, Serialize, Deserialize, TypePath)] pub struct CraftPartRequest { pub crafting_part: Entity, pub crafted_part: String, @@ -92,7 +92,7 @@ pub struct Drill { pub resource_multiplier: f32, pub on_planet: Option, } -#[derive(Message, Debug, Clone)] +#[derive(Message, Debug, Clone, Serialize, Deserialize, TypePath)] pub struct ToggleDrillEvent { pub drill_entity: Entity, } diff --git a/crates/unified/src/shared/net.rs b/crates/unified/src/shared/net.rs index f1a29d9a1201fff957563abea29fed6a6a875a6e..cfcd9f870d1be814dbadec3f7f2d2daa7ddcbee7 100644 --- a/crates/unified/src/shared/net.rs +++ b/crates/unified/src/shared/net.rs @@ -12,11 +12,12 @@ use bevy::ecs::system::SystemState; use bevy::prelude::*; use postcard::{from_bytes, to_allocvec, to_slice, to_vec}; use crate::prelude::{App, Message}; +use crate::shared::thrust::ThrustSolution; //use bevy_replicon::prelude::*; use serde::{Deserialize, Serialize}; use crate::shared::attachment::{Joint, JointOf, PartInShip, Peer, Ship, SnapOf, SnapOfJoint}; use crate::shared::config::planet::{Planet, PlanetSpring, PlanetSpringJoint}; -use crate::shared::ecs::{CanCraft, Drill, Part, Player, PlayerStorage, SingleStorage, Temperature}; +use crate::shared::ecs::{CanCraft, CraftPartRequest, DragRequestEvent, Drill, Part, Player, PlayerStorage, SingleStorage, Temperature, ToggleDrillEvent}; use crate::shared::ecs::thruster::{Thruster, ThrusterOfPart}; @@ -59,14 +60,13 @@ use crate::shared::ecs::thruster::{Thruster, ThrusterOfPart}; }*/ pub fn register_net(app: &mut App) { - /*app - .add_message::>() - .add_message::() - .add_systems(Update, send_hi_to_client);*/ -} -pub fn setup_net(app: &mut App) { - app.insert_resource(MessageRegistry::default()); - app.add_systems(PostUpdate, recv_from_server); + app + .add_server_message::() + + .add_client_message::() + .add_client_message::() + .add_client_message::() + .add_client_message::(); } #[derive(Message, Deserialize, Serialize, TypePath, MapEntities)] @@ -76,12 +76,24 @@ pub struct Hi { pub time_offset: f64, } +pub fn setup_net(app: &mut App) { + app.insert_resource(ServerMessageRegistry::default()); + app.insert_resource(ClientMessageRegistry::default()); + app.add_systems(PostUpdate, recv_from_server); + app.add_systems(PostUpdate, recv_from_client); +} #[derive(Message, Deref, Deserialize, Serialize)] pub struct ToClients { #[deref] pub message: T, pub targets: SendTargets, } +#[derive(Message, Deref, Deserialize, Serialize)] +pub struct FromClients { + pub client_id: ClientId, + #[deref] + pub message: T, +} #[derive(Deserialize, Serialize)] pub enum SendTargets { @@ -96,10 +108,15 @@ pub enum ClientId { } #[derive(Resource, Default)] -pub struct MessageRegistry { +pub struct ServerMessageRegistry { forward: HashMap, reverse: HashMap, &mut World)>, } +#[derive(Resource, Default)] +pub struct ClientMessageRegistry { + forward: HashMap, + reverse: HashMap, ClientId, &mut World)>, +} static COUNTER: AtomicU32 = AtomicU32::new(0); fn get_lane_index() -> LaneIndex { @@ -107,29 +124,47 @@ fn get_lane_index() -> LaneIndex { } pub trait NetAppExt { - fn add_server_message Deserialize<'a>>(&mut self) -> &mut Self; + fn add_server_message Deserialize<'a>>(&mut self) -> &mut Self; + fn add_client_message Deserialize<'a>>(&mut self) -> &mut Self; } impl NetAppExt for App { - fn add_server_message Deserialize<'a>>(&mut self) -> &mut Self { + fn add_server_message Deserialize<'a>>(&mut self) -> &mut Self { self .add_message::>() .add_message::() - .add_systems(Startup, register_message::) + .add_systems(Startup, register_server_message::) .add_systems(Update, send_to_client::) } + fn add_client_message Deserialize<'a>>(&mut self) -> &mut Self { + self + .add_message::>() + .add_message::() + .add_systems(Startup, register_client_message::) + .add_systems(Update, send_to_server::) + } } -fn register_message Deserialize<'a>>(mut registry: ResMut) { +fn register_server_message Deserialize<'a>>(mut registry: ResMut) { registry.forward.insert(T::type_path().to_string(), get_lane_index()); registry.reverse.insert(get_lane_index(), |payload: Vec, world: &mut World| { let message = from_bytes::(&payload).expect(&format!("Failed to deserialize message of type {}", T::type_path())); world.write_message(message).expect("Could not send message to game"); }); } +fn register_client_message Deserialize<'a>>(mut registry: ResMut) { + registry.forward.insert(T::type_path().to_string(), get_lane_index()); + registry.reverse.insert(get_lane_index(), |payload: Vec, client_id: ClientId, world: &mut World| { + let message = from_bytes::(&payload).expect(&format!("Failed to deserialize message of type {}", T::type_path())); + world.write_message(FromClients { + client_id, + message, + }).expect("Could not send message to game"); + }); +} -fn send_to_client( +fn send_to_client( mut messages: MessageReader>, mut clients: Query<(Entity, &mut Transport), With>, - message_registry: Res, + message_registry: Res, ) { for message in messages.read() { match &message.targets { @@ -158,12 +193,28 @@ fn send_to_client( } } } +fn send_to_server( + mut messages: MessageReader, + mut sessions: Query<&mut Transport, Without>, + message_registry: Res, +) { + for message in messages.read() { + for mut transport in &mut sessions { + transport.send.push( + *message_registry.forward.get(M::type_path()) + .expect("Failed to get message lane; the message likely isn't serialized yet"), + to_allocvec(&message).expect("Failed to serialize message").into(), + Instant::now(), + ).expect("Failed to send message"); + } + } +} fn recv_from_server( world: &mut World ) { let mut system_state: SystemState<( Query<&mut Transport, Without>, - Res, + Res, )> = SystemState::new(world); let (mut sessions, message_registry) = system_state.get_mut(world); let mut messages = Vec::new(); @@ -181,3 +232,26 @@ fn recv_from_server( message_fn(payload, world); } } +fn recv_from_client( + world: &mut World +) { + let mut system_state: SystemState<( + Query<(Entity, &mut Transport), With>, + Res, + )> = SystemState::new(world); + let (mut clients, message_registry) = system_state.get_mut(world); + let mut messages = Vec::new(); + for (client_entity, mut transport) in clients.iter_mut() { + for message in transport.recv.msgs.drain() { + let payload = message.payload; + let message_fn = message_registry.reverse.get(&message.lane).expect("Packet was sent across a lane that didn't have a message assigned to it yet"); + messages.push((payload, ClientId::Client(client_entity), *message_fn)); + } + for _ in transport.recv.acks.drain() { + + } + } + for (payload, client_id, message_fn) in messages { + message_fn(payload, client_id, world); + } +} diff --git a/crates/unified/src/shared/plugins.rs b/crates/unified/src/shared/plugins.rs index 4c7a8ba33d40423402e8cedcaa23132d35ff0679..4390058cffe244c1ad551b16f69d66c4ca3bafe0 100644 --- a/crates/unified/src/shared/plugins.rs +++ b/crates/unified/src/shared/plugins.rs @@ -1,6 +1,6 @@ use aeronet_transport::AeronetTransportPlugin; use crate::shared::ecs::{CraftPartRequest, DragRequestEvent, TimeOffset, ToggleDrillEvent}; -use crate::shared::net::register_net; +use crate::shared::net::{register_net, setup_net}; use crate::shared::thrust::ThrustSolution; use bevy::app::{App, PluginGroup, PluginGroupBuilder}; use bevy::diagnostic::DiagnosticsPlugin; @@ -42,6 +42,7 @@ impl PluginGroup for SharedPluginGroup { .add(physics_setup_plugin) //.add(register_replication) .add(register_everything) + .add(setup_net) .add(register_net) .add(world_config_plugin) @@ -54,10 +55,6 @@ impl PluginGroup for SharedPluginGroup { } pub fn register_everything(app: &mut App) { - app.add_message::(); - app.add_message::(); - app.add_message::(); - app.add_message::(); } fn physics_setup_plugin(app: &mut App) { diff --git a/crates/unified/src/shared/thrust.rs b/crates/unified/src/shared/thrust.rs index d6a8648669030b5f21512a955916214fd0019ac7..886a0e5fd5fe61ff58d7228e9e6e6fe28b514a60 100644 --- a/crates/unified/src/shared/thrust.rs +++ b/crates/unified/src/shared/thrust.rs @@ -1,10 +1,11 @@ use std::collections::BTreeSet; -use bevy::prelude::{Component, Entity, Message, Resource}; +use bevy::{prelude::{Component, Entity, Message, Resource}, reflect::TypePath}; +use serde::{Deserialize, Serialize}; /// A thrust solution, found by the thrust solver on the client. /// `thrusters_on` is the set of thrusters that should be on. /// Any thrusters not in this set should be off. -#[derive(Eq, PartialEq, Debug, Clone, Resource, Component, Message)] +#[derive(Eq, PartialEq, Debug, Clone, Resource, Component, Message, Serialize, Deserialize, TypePath)] pub struct ThrustSolution { pub thrusters_on: BTreeSet, pub converged: bool