Skip to main content

naia_client/
world_events.rs

1use std::{
2    collections::HashMap, hash::Hash, marker::PhantomData, mem, net::SocketAddr, vec::IntoIter,
3};
4
5use naia_shared::{
6    handshake::RejectReason, Channel, ChannelKind, ComponentKind, DisconnectReason,
7    GlobalResponseId, Message, MessageContainer, MessageKind, Replicate, Request, ResponseSendKey, Tick,
8};
9
10use crate::NaiaClientError;
11
12type RemovesMap<E> = HashMap<ComponentKind, Vec<(E, Box<dyn Replicate>)>>;
13
14/// All events produced in one frame: connections, entity lifecycle, component changes, messages, and errors.
15pub struct Events<E: Hash + Copy + Eq + Sync + Send> {
16    connections: Vec<SocketAddr>,
17    rejections: Vec<(SocketAddr, RejectReason)>,
18    disconnections: Vec<(SocketAddr, DisconnectReason)>,
19    errors: Vec<NaiaClientError>,
20    messages: HashMap<ChannelKind, HashMap<MessageKind, Vec<MessageContainer>>>,
21    requests: HashMap<ChannelKind, HashMap<MessageKind, Vec<(GlobalResponseId, MessageContainer)>>>,
22    spawns: Vec<E>,
23    despawns: Vec<E>,
24    publishes: Vec<E>,
25    unpublishes: Vec<E>,
26    auth_grants: Vec<E>,
27    auth_denies: Vec<E>,
28    auth_resets: Vec<E>,
29    inserts: HashMap<ComponentKind, Vec<E>>,
30    removes: RemovesMap<E>,
31    updates: HashMap<ComponentKind, Vec<(Tick, E)>>,
32    empty: bool,
33}
34
35impl<E: Hash + Copy + Eq + Sync + Send> Default for Events<E> {
36    fn default() -> Self {
37        Events::new()
38    }
39}
40
41impl<E: Hash + Copy + Eq + Sync + Send> Events<E> {
42    pub(crate) fn new() -> Self {
43        Self {
44            connections: Vec::new(),
45            rejections: Vec::new(),
46            disconnections: Vec::new(), // (SocketAddr, DisconnectReason)
47            errors: Vec::new(),
48            messages: HashMap::new(),
49            requests: HashMap::new(),
50            spawns: Vec::new(),
51            despawns: Vec::new(),
52            publishes: Vec::new(),
53            unpublishes: Vec::new(),
54            auth_grants: Vec::new(),
55            auth_denies: Vec::new(),
56            auth_resets: Vec::new(),
57            inserts: HashMap::new(),
58            removes: HashMap::new(),
59            updates: HashMap::new(),
60            empty: true,
61        }
62    }
63
64    /// Returns `true` if no events were queued this frame.
65    pub fn is_empty(&self) -> bool {
66        self.empty
67    }
68
69    /// Drains and returns an iterator over events of type `V`.
70    pub fn read<V: WorldEvent<E>>(&mut self) -> V::Iter {
71        V::iter(self)
72    }
73
74    /// Returns `true` if at least one event of type `V` is queued.
75    pub fn has<V: WorldEvent<E>>(&self) -> bool {
76        V::has(self)
77    }
78
79    // This method is exposed for adapter crates ... prefer using Events.read::<SomeEvent>() instead.
80    /// Returns `true` if any messages are queued; prefer `read::<MessageEvent<C, M>>()` in application code.
81    pub fn has_messages(&self) -> bool {
82        !self.messages.is_empty()
83    }
84    /// Takes all queued messages, leaving the internal buffer empty; prefer `read::<MessageEvent<C, M>>()` in application code.
85    pub fn take_messages(
86        &mut self,
87    ) -> HashMap<ChannelKind, HashMap<MessageKind, Vec<MessageContainer>>> {
88        mem::take(&mut self.messages)
89    }
90
91    // This method is exposed for adapter crates ... prefer using Events.read::<SomeEvent>() instead.
92    /// Returns `true` if any requests are queued; prefer `read::<RequestEvent<C, Q>>()` in application code.
93    pub fn has_requests(&self) -> bool {
94        !self.requests.is_empty()
95    }
96    /// Takes all queued requests, leaving the internal buffer empty; prefer `read::<RequestEvent<C, Q>>()` in application code.
97    pub fn take_requests(
98        &mut self,
99    ) -> HashMap<ChannelKind, HashMap<MessageKind, Vec<(GlobalResponseId, MessageContainer)>>> {
100        mem::take(&mut self.requests)
101    }
102
103    // These methods are exposed for adapter crates ... prefer using Events.read::<SomeEvent>() instead.
104    /// Returns `true` if any component-insert events are queued; prefer `read::<InsertComponentEvent<C>>()` in application code.
105    pub fn has_inserts(&self) -> bool {
106        !self.inserts.is_empty()
107    }
108    /// Takes all queued component-insert events; prefer `read::<InsertComponentEvent<C>>()` in application code.
109    pub fn take_inserts(&mut self) -> Option<HashMap<ComponentKind, Vec<E>>> {
110        if self.inserts.is_empty() {
111            None
112        } else {
113            Some(mem::take(&mut self.inserts))
114        }
115    }
116
117    // These methods are exposed for adapter crates ... prefer using Events.read::<SomeEvent>() instead.
118    /// Returns `true` if any component-update events are queued; prefer `read::<UpdateComponentEvent<C>>()` in application code.
119    pub fn has_updates(&self) -> bool {
120        !self.updates.is_empty()
121    }
122    /// Takes all queued component-update events; prefer `read::<UpdateComponentEvent<C>>()` in application code.
123    pub fn take_updates(&mut self) -> Option<HashMap<ComponentKind, Vec<(Tick, E)>>> {
124        if self.updates.is_empty() {
125            None
126        } else {
127            Some(mem::take(&mut self.updates))
128        }
129    }
130
131    // These method are exposed for adapter crates ... prefer using Events.read::<SomeEvent>() instead.
132    /// Returns `true` if any component-remove events are queued; prefer `read::<RemoveComponentEvent<C>>()` in application code.
133    pub fn has_removes(&self) -> bool {
134        !self.removes.is_empty()
135    }
136    /// Takes all queued component-remove events; prefer `read::<RemoveComponentEvent<C>>()` in application code.
137    pub fn take_removes(&mut self) -> Option<RemovesMap<E>> {
138        if self.removes.is_empty() {
139            None
140        } else {
141            Some(mem::take(&mut self.removes))
142        }
143    }
144
145    // Crate-public
146
147    pub(crate) fn push_connection(&mut self, socket_addr: &SocketAddr) {
148        self.connections.push(*socket_addr);
149        self.empty = false;
150    }
151
152    pub(crate) fn push_rejection(&mut self, socket_addr: &SocketAddr, reason: RejectReason) {
153        self.rejections.push((*socket_addr, reason));
154        self.empty = false;
155    }
156
157    pub(crate) fn push_disconnection(&mut self, socket_addr: &SocketAddr, reason: DisconnectReason) {
158        self.disconnections.push((*socket_addr, reason));
159        self.empty = false;
160    }
161
162    pub(crate) fn push_message(&mut self, channel_kind: &ChannelKind, message: MessageContainer) {
163        if !self.messages.contains_key(channel_kind) {
164            self.messages.insert(*channel_kind, HashMap::new());
165        }
166        let channel_map = self.messages.get_mut(channel_kind).unwrap();
167
168        let message_kind: MessageKind = message.kind();
169        channel_map.entry(message_kind).or_default();
170        let list = channel_map.get_mut(&message_kind).unwrap();
171        list.push(message);
172        self.empty = false;
173    }
174
175    pub(crate) fn push_request(
176        &mut self,
177        channel_kind: &ChannelKind,
178        global_response_id: GlobalResponseId,
179        request: MessageContainer,
180    ) {
181        if !self.requests.contains_key(channel_kind) {
182            self.requests.insert(*channel_kind, HashMap::new());
183        }
184        let channel_map = self.requests.get_mut(channel_kind).unwrap();
185
186        let message_kind: MessageKind = request.kind();
187        channel_map.entry(message_kind).or_default();
188        let list = channel_map.get_mut(&message_kind).unwrap();
189        list.push((global_response_id, request));
190
191        self.empty = false;
192    }
193
194    pub(crate) fn push_error(&mut self, error: NaiaClientError) {
195        self.errors.push(error);
196        self.empty = false;
197    }
198
199    pub(crate) fn push_spawn(&mut self, world_entity: E) {
200        self.spawns.push(world_entity);
201        self.empty = false;
202    }
203
204    pub(crate) fn push_despawn(&mut self, world_entity: E) {
205        self.despawns.push(world_entity);
206        self.empty = false;
207    }
208
209    pub(crate) fn push_publish(&mut self, world_entity: E) {
210        self.publishes.push(world_entity);
211        self.empty = false;
212    }
213
214    pub(crate) fn push_unpublish(&mut self, world_entity: E) {
215        self.unpublishes.push(world_entity);
216        self.empty = false;
217    }
218
219    pub(crate) fn push_auth_grant(&mut self, world_entity: E) {
220        self.auth_grants.push(world_entity);
221        self.empty = false;
222    }
223
224    pub(crate) fn push_auth_deny(&mut self, world_entity: E) {
225        self.auth_denies.push(world_entity);
226        self.empty = false;
227    }
228
229    pub(crate) fn push_auth_reset(&mut self, world_entity: E) {
230        self.auth_resets.push(world_entity);
231        self.empty = false;
232    }
233
234    pub(crate) fn push_insert(&mut self, world_entity: E, component_kind: ComponentKind) {
235        self.inserts.entry(component_kind).or_insert_with(|| Vec::new());
236        let list = self.inserts.get_mut(&component_kind).unwrap();
237        list.push(world_entity);
238        self.empty = false;
239    }
240
241    pub(crate) fn push_update(
242        &mut self,
243        tick: Tick,
244        world_entity: E,
245        component_kind: ComponentKind,
246    ) {
247        self.updates.entry(component_kind).or_default();
248        let list = self.updates.get_mut(&component_kind).unwrap();
249        list.push((tick, world_entity));
250        self.empty = false;
251    }
252
253    pub(crate) fn push_remove(&mut self, world_entity: E, component: Box<dyn Replicate>) {
254        let component_kind: ComponentKind = component.kind();
255        self.removes.entry(component_kind).or_default();
256        let list = self.removes.get_mut(&component_kind).unwrap();
257        list.push((world_entity, component));
258        self.empty = false;
259    }
260
261    pub(crate) fn clear(&mut self) {
262        self.connections.clear();
263        self.rejections.clear();
264        self.disconnections.clear();
265        self.errors.clear();
266        self.messages.clear();
267        self.requests.clear();
268        self.spawns.clear();
269        self.despawns.clear();
270        self.publishes.clear();
271        self.unpublishes.clear();
272        self.auth_grants.clear();
273        self.auth_denies.clear();
274        self.auth_resets.clear();
275        self.inserts.clear();
276        self.removes.clear();
277        self.updates.clear();
278        self.empty = true;
279    }
280}
281
282/// Type-indexed world event; each concrete type selects one category from [`Events`].
283pub trait WorldEvent<E: Hash + Copy + Eq + Sync + Send> {
284    /// Iterator type returned from [`Events::read`].
285    type Iter;
286
287    /// Drains events of this variant out of `events` and returns an iterator over them.
288    fn iter(events: &mut Events<E>) -> Self::Iter;
289
290    /// Returns `true` if `events` contains at least one event of this variant.
291    fn has(events: &Events<E>) -> bool;
292}
293
294/// Fires when the client successfully establishes a connection to the server; yields the server's [`SocketAddr`].
295pub struct ConnectEvent;
296impl<E: Hash + Copy + Eq + Sync + Send> WorldEvent<E> for ConnectEvent {
297    type Iter = IntoIter<SocketAddr>;
298
299    fn iter(events: &mut Events<E>) -> Self::Iter {
300        let list = std::mem::take(&mut events.connections);
301        IntoIterator::into_iter(list)
302    }
303
304    fn has(events: &Events<E>) -> bool {
305        !events.connections.is_empty()
306    }
307}
308
309/// Fires when the server explicitly rejects the connection; yields the server address and the [`RejectReason`].
310pub struct RejectEvent;
311impl<E: Hash + Copy + Eq + Sync + Send> WorldEvent<E> for RejectEvent {
312    type Iter = IntoIter<(SocketAddr, RejectReason)>;
313
314    fn iter(events: &mut Events<E>) -> Self::Iter {
315        let list = std::mem::take(&mut events.rejections);
316        IntoIterator::into_iter(list)
317    }
318
319    fn has(events: &Events<E>) -> bool {
320        !events.rejections.is_empty()
321    }
322}
323
324/// Fires when the connection to the server is lost; yields the server address and the [`DisconnectReason`].
325pub struct DisconnectEvent;
326impl<E: Hash + Copy + Eq + Sync + Send> WorldEvent<E> for DisconnectEvent {
327    type Iter = IntoIter<(SocketAddr, DisconnectReason)>;
328
329    fn iter(events: &mut Events<E>) -> Self::Iter {
330        let list = std::mem::take(&mut events.disconnections);
331        IntoIterator::into_iter(list)
332    }
333
334    fn has(events: &Events<E>) -> bool {
335        !events.disconnections.is_empty()
336    }
337}
338
339/// Fires when a transport or protocol error occurs; yields a [`NaiaClientError`].
340pub struct ErrorEvent;
341impl<E: Hash + Copy + Eq + Sync + Send> WorldEvent<E> for ErrorEvent {
342    type Iter = IntoIter<NaiaClientError>;
343
344    fn iter(events: &mut Events<E>) -> Self::Iter {
345        let list = std::mem::take(&mut events.errors);
346        IntoIterator::into_iter(list)
347    }
348
349    fn has(events: &Events<E>) -> bool {
350        !events.errors.is_empty()
351    }
352}
353
354/// Fires when a message of type `M` arrives on channel `C`; yields the decoded `M` value.
355pub struct MessageEvent<C: Channel, M: Message> {
356    phantom_c: PhantomData<C>,
357    phantom_m: PhantomData<M>,
358}
359impl<E: Hash + Copy + Eq + Sync + Send, C: Channel, M: Message> WorldEvent<E>
360    for MessageEvent<C, M>
361{
362    type Iter = IntoIter<M>;
363
364    fn iter(events: &mut Events<E>) -> Self::Iter {
365        let channel_kind: ChannelKind = ChannelKind::of::<C>();
366        if let Some(channel_map) = events.messages.get_mut(&channel_kind) {
367            let message_kind: MessageKind = MessageKind::of::<M>();
368            if let Some(boxed_list) = channel_map.remove(&message_kind) {
369                let mut output_list: Vec<M> = Vec::new();
370
371                for boxed_message in boxed_list {
372                    let boxed_any = boxed_message.to_boxed_any();
373                    let message = boxed_any.downcast::<M>().unwrap();
374                    output_list.push(*message);
375                }
376
377                return IntoIterator::into_iter(output_list);
378            }
379        }
380        IntoIterator::into_iter(Vec::new())
381    }
382
383    fn has(events: &Events<E>) -> bool {
384        let channel_kind: ChannelKind = ChannelKind::of::<C>();
385        if let Some(channel_map) = events.messages.get(&channel_kind) {
386            let message_kind: MessageKind = MessageKind::of::<M>();
387            return channel_map.contains_key(&message_kind);
388        }
389        false
390    }
391}
392
393/// Fires when a request of type `Q` arrives on channel `C`; yields a `(ResponseSendKey, Q)` pair.
394pub struct RequestEvent<C: Channel, Q: Request> {
395    phantom_c: PhantomData<C>,
396    phantom_m: PhantomData<Q>,
397}
398impl<E: Hash + Copy + Eq + Sync + Send, C: Channel, Q: Request> WorldEvent<E>
399    for RequestEvent<C, Q>
400{
401    type Iter = IntoIter<(ResponseSendKey<Q::Response>, Q)>;
402
403    fn iter(events: &mut Events<E>) -> Self::Iter {
404        let channel_kind: ChannelKind = ChannelKind::of::<C>();
405        let Some(channel_map) = events.requests.get_mut(&channel_kind) else {
406            return IntoIterator::into_iter(Vec::new());
407        };
408        let message_kind: MessageKind = MessageKind::of::<Q>();
409        let Some(requests) = channel_map.remove(&message_kind) else {
410            return IntoIterator::into_iter(Vec::new());
411        };
412        let mut output_list = Vec::new();
413
414        for (global_response_id, boxed_request) in requests {
415            let boxed_any = boxed_request.to_boxed_any();
416            let request = boxed_any.downcast::<Q>().unwrap();
417            let response_send_key = ResponseSendKey::<Q::Response>::new(global_response_id);
418            output_list.push((response_send_key, *request));
419        }
420
421        IntoIterator::into_iter(output_list)
422    }
423
424    fn has(events: &Events<E>) -> bool {
425        let channel_kind: ChannelKind = ChannelKind::of::<C>();
426        if let Some(channel_map) = events.requests.get(&channel_kind) {
427            let message_kind: MessageKind = MessageKind::of::<Q>();
428            return channel_map.contains_key(&message_kind);
429        }
430        false
431    }
432}
433
434/// Fires when the server spawns a new replicated entity on this client; yields the world entity `E`.
435pub struct SpawnEntityEvent;
436impl<E: Hash + Copy + Eq + Sync + Send> WorldEvent<E> for SpawnEntityEvent {
437    type Iter = IntoIter<E>;
438
439    fn iter(events: &mut Events<E>) -> Self::Iter {
440        let list = std::mem::take(&mut events.spawns);
441        IntoIterator::into_iter(list)
442    }
443
444    fn has(events: &Events<E>) -> bool {
445        !events.spawns.is_empty()
446    }
447}
448
449/// Fires when the server despawns a previously replicated entity; yields the world entity `E`.
450pub struct DespawnEntityEvent;
451impl<E: Hash + Copy + Eq + Sync + Send> WorldEvent<E> for DespawnEntityEvent {
452    type Iter = IntoIter<E>;
453
454    fn iter(events: &mut Events<E>) -> Self::Iter {
455        let list = std::mem::take(&mut events.despawns);
456        IntoIterator::into_iter(list)
457    }
458
459    fn has(events: &Events<E>) -> bool {
460        !events.despawns.is_empty()
461    }
462}
463
464/// Fires when an entity transitions to the `Public` visibility state and becomes visible to all users.
465pub struct PublishEntityEvent;
466impl<E: Hash + Copy + Eq + Sync + Send> WorldEvent<E> for PublishEntityEvent {
467    type Iter = IntoIter<E>;
468
469    fn iter(events: &mut Events<E>) -> Self::Iter {
470        let list = std::mem::take(&mut events.publishes);
471        IntoIterator::into_iter(list)
472    }
473
474    fn has(events: &Events<E>) -> bool {
475        !events.publishes.is_empty()
476    }
477}
478
479/// Fires when an entity's visibility is retracted from the `Public` state.
480pub struct UnpublishEntityEvent;
481impl<E: Hash + Copy + Eq + Sync + Send> WorldEvent<E> for UnpublishEntityEvent {
482    type Iter = IntoIter<E>;
483
484    fn iter(events: &mut Events<E>) -> Self::Iter {
485        let list = std::mem::take(&mut events.unpublishes);
486        IntoIterator::into_iter(list)
487    }
488
489    fn has(events: &Events<E>) -> bool {
490        !events.unpublishes.is_empty()
491    }
492}
493
494/// Fires when the server grants this client authority over a delegated entity.
495pub struct EntityAuthGrantedEvent;
496impl<E: Hash + Copy + Eq + Sync + Send> WorldEvent<E> for EntityAuthGrantedEvent {
497    type Iter = IntoIter<E>;
498
499    fn iter(events: &mut Events<E>) -> Self::Iter {
500        let list = std::mem::take(&mut events.auth_grants);
501        IntoIterator::into_iter(list)
502    }
503
504    fn has(events: &Events<E>) -> bool {
505        !events.auth_grants.is_empty()
506    }
507}
508
509/// Fires when the server reclaims authority over an entity that was previously delegated to this client.
510pub struct EntityAuthResetEvent;
511impl<E: Hash + Copy + Eq + Sync + Send> WorldEvent<E> for EntityAuthResetEvent {
512    type Iter = IntoIter<E>;
513
514    fn iter(events: &mut Events<E>) -> Self::Iter {
515        let list = std::mem::take(&mut events.auth_resets);
516        IntoIterator::into_iter(list)
517    }
518
519    fn has(events: &Events<E>) -> bool {
520        !events.auth_resets.is_empty()
521    }
522}
523
524/// Fires when the server denies this client's authority request for a delegated entity.
525pub struct EntityAuthDeniedEvent;
526impl<E: Hash + Copy + Eq + Sync + Send> WorldEvent<E> for EntityAuthDeniedEvent {
527    type Iter = IntoIter<E>;
528
529    fn iter(events: &mut Events<E>) -> Self::Iter {
530        let list = std::mem::take(&mut events.auth_denies);
531        IntoIterator::into_iter(list)
532    }
533
534    fn has(events: &Events<E>) -> bool {
535        !events.auth_denies.is_empty()
536    }
537}
538
539/// Fires when component `C` is inserted on a replicated entity; yields the world entity `E`.
540pub struct InsertComponentEvent<C: Replicate> {
541    phantom_c: PhantomData<C>,
542}
543impl<E: Hash + Copy + Eq + Sync + Send, C: Replicate> WorldEvent<E> for InsertComponentEvent<C> {
544    type Iter = IntoIter<E>;
545
546    fn iter(events: &mut Events<E>) -> Self::Iter {
547        let component_kind: ComponentKind = ComponentKind::of::<C>();
548        if let Some(boxed_list) = events.inserts.remove(&component_kind) {
549            return IntoIterator::into_iter(boxed_list);
550        }
551
552        IntoIterator::into_iter(Vec::new())
553    }
554
555    fn has(events: &Events<E>) -> bool {
556        let component_kind: ComponentKind = ComponentKind::of::<C>();
557        events.inserts.contains_key(&component_kind)
558    }
559}
560
561/// Fires when component `C` on a replicated entity is mutated; yields `(Tick, E)`.
562pub struct UpdateComponentEvent<C: Replicate> {
563    phantom_c: PhantomData<C>,
564}
565impl<E: Hash + Copy + Eq + Sync + Send, C: Replicate> WorldEvent<E> for UpdateComponentEvent<C> {
566    type Iter = IntoIter<(Tick, E)>;
567
568    fn iter(events: &mut Events<E>) -> Self::Iter {
569        let component_kind: ComponentKind = ComponentKind::of::<C>();
570        if let Some(boxed_list) = events.updates.remove(&component_kind) {
571            return IntoIterator::into_iter(boxed_list);
572        }
573
574        IntoIterator::into_iter(Vec::new())
575    }
576
577    fn has(events: &Events<E>) -> bool {
578        let component_kind: ComponentKind = ComponentKind::of::<C>();
579        events.updates.contains_key(&component_kind)
580    }
581}
582
583/// Fires when component `C` is removed from a replicated entity; yields `(E, C)` with the last value of the component.
584pub struct RemoveComponentEvent<C: Replicate> {
585    phantom_c: PhantomData<C>,
586}
587impl<E: Hash + Copy + Eq + Sync + Send, C: Replicate> WorldEvent<E> for RemoveComponentEvent<C> {
588    type Iter = IntoIter<(E, C)>;
589
590    fn iter(events: &mut Events<E>) -> Self::Iter {
591        let component_kind: ComponentKind = ComponentKind::of::<C>();
592        if let Some(boxed_list) = events.removes.remove(&component_kind) {
593            let mut output_list: Vec<(E, C)> = Vec::new();
594
595            for (entity, boxed_component) in boxed_list {
596                let boxed_any = boxed_component.to_boxed_any();
597                let component = boxed_any.downcast::<C>().unwrap();
598                output_list.push((entity, *component));
599            }
600
601            return IntoIterator::into_iter(output_list);
602        }
603
604        IntoIterator::into_iter(Vec::new())
605    }
606
607    fn has(events: &Events<E>) -> bool {
608        let component_kind: ComponentKind = ComponentKind::of::<C>();
609        events.removes.contains_key(&component_kind)
610    }
611}