Skip to main content

aetheris_protocol/
events.rs

1use serde::{Deserialize, Serialize};
2
3use crate::types::{ClientId, ComponentKind, NetworkId};
4
5/// An event representing a fragment of a larger message.
6/// Used for MTU stability to prevent packet drops and enable reassembly.
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8pub struct FragmentedEvent {
9    /// Unique identifier for the fragmented message.
10    pub message_id: u32,
11    /// The index of this fragment (0-based).
12    pub fragment_index: u16,
13    /// Total number of fragments for this message.
14    pub total_fragments: u16,
15    /// The raw payload of this fragment.
16    #[serde(with = "serde_bytes")]
17    pub payload: Vec<u8>,
18}
19
20/// An event representing a change to a single component on a single entity.
21/// Produced by `WorldState::extract_deltas()` on the server.
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23pub struct ReplicationEvent {
24    /// Which entity changed.
25    pub network_id: NetworkId,
26    /// Which component type changed.
27    pub component_kind: ComponentKind,
28    /// The serialized delta payload (only the changed fields).
29    /// In Phase 1, this is a full snapshot per component for simplicity.
30    #[serde(with = "serde_bytes")]
31    pub payload: Vec<u8>,
32    /// The server tick at which this change was recorded.
33    pub tick: u64,
34}
35
36/// An inbound update to be applied to the ECS.
37/// Produced by `Encoder::decode()` on the receiving end.
38#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
39pub struct ComponentUpdate {
40    /// The entity to update.
41    pub network_id: NetworkId,
42    /// Which component type to update.
43    pub component_kind: ComponentKind,
44    /// The deserialized field values.
45    #[serde(with = "serde_bytes")]
46    pub payload: Vec<u8>,
47    /// The tick this update originated from.
48    pub tick: u64,
49}
50
51/// Events produced by `GameTransport::poll_events()`.
52#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
53pub enum NetworkEvent {
54    /// A new client has connected and been assigned a `ClientId`.
55    ClientConnected(ClientId),
56    /// A client has disconnected (graceful or timeout).
57    ClientDisconnected(ClientId),
58    /// Raw unreliable data received from a client.
59    UnreliableMessage {
60        /// The client that sent the message.
61        client_id: ClientId,
62        /// The raw message bytes.
63        #[serde(with = "serde_bytes")]
64        data: Vec<u8>,
65    },
66    /// Raw reliable data received from a client.
67    ReliableMessage {
68        /// The client that sent the message.
69        client_id: ClientId,
70        /// The raw message bytes.
71        #[serde(with = "serde_bytes")]
72        data: Vec<u8>,
73    },
74    /// A heartbeat ping from a client.
75    Ping {
76        /// The client that sent the ping.
77        client_id: ClientId,
78        /// The client's tick/timestamp when the ping was sent.
79        tick: u64,
80    },
81    /// A heartbeat pong from the server.
82    Pong {
83        /// The original tick/timestamp from the ping.
84        tick: u64,
85    },
86    /// A session authentication request from the client.
87    Auth {
88        /// The session token obtained from the Control Plane.
89        session_token: String,
90    },
91    /// A WebTransport session was closed by the remote or due to error.
92    SessionClosed(ClientId),
93    /// A WebTransport stream was reset.
94    StreamReset(ClientId),
95    /// A fragment of a larger message.
96    Fragment {
97        /// The client that sent the fragment.
98        client_id: ClientId,
99        /// The fragment data.
100        fragment: FragmentedEvent,
101    },
102    /// A testing command to trigger a stress test (Phase 1/Playground only).
103    StressTest {
104        /// The client that requested the stress test.
105        client_id: ClientId,
106        /// Number of entities to spawn.
107        count: u16,
108        /// Whether spawned entities should rotate.
109        rotate: bool,
110    },
111    /// A testing command to spawn a specific entity (Phase 1/Playground only).
112    Spawn {
113        /// The client that requested the spawn.
114        client_id: ClientId,
115        /// Which entity type to spawn.
116        entity_type: u16,
117        /// Position X
118        x: f32,
119        /// Position Y
120        y: f32,
121        /// Initial rotation
122        rot: f32,
123    },
124    /// A command to clear all entities from the world (Phase 1/Playground only).
125    ClearWorld {
126        /// The client that requested the clear.
127        client_id: ClientId,
128    },
129}
130
131/// A restricted view of `NetworkEvent` for over-the-wire transport.
132/// Prevents local-only variants (like `ClientConnected`) from being sent/received.
133#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
134pub enum WireEvent {
135    /// A heartbeat ping.
136    Ping {
137        /// The client's tick/timestamp when the ping was sent.
138        tick: u64,
139    },
140    /// A heartbeat pong.
141    Pong {
142        /// The original tick/timestamp from the ping.
143        tick: u64,
144    },
145    /// A session authentication request.
146    Auth {
147        /// The session token.
148        session_token: String,
149    },
150    /// A fragment of a larger message.
151    Fragment(FragmentedEvent),
152    /// A testing command to trigger a stress test.
153    StressTest {
154        /// Number of entities to spawn.
155        count: u16,
156        /// Whether spawned entities should rotate.
157        rotate: bool,
158    },
159    /// A testing command to spawn a specific entity.
160    Spawn {
161        /// Which entity type to spawn.
162        entity_type: u16,
163        /// Position X
164        x: f32,
165        /// Position Y
166        y: f32,
167        /// Initial rotation
168        rot: f32,
169    },
170    /// A command to clear all entities from the world.
171    ClearWorld,
172}
173
174#[cfg(test)]
175mod tests {
176    use super::*;
177
178    #[test]
179    fn test_event_sizes_and_derives() {
180        let ev = NetworkEvent::ClientConnected(ClientId(1));
181        assert_eq!(ev, NetworkEvent::ClientConnected(ClientId(1)));
182
183        let re = ReplicationEvent {
184            network_id: NetworkId(1),
185            component_kind: ComponentKind(0),
186            payload: vec![1, 2, 3],
187            tick: 0,
188        };
189        assert_eq!(re.payload.len(), 3);
190        assert_eq!(
191            re,
192            ReplicationEvent {
193                network_id: NetworkId(1),
194                component_kind: ComponentKind(0),
195                payload: vec![1, 2, 3],
196                tick: 0,
197            }
198        );
199    }
200}