Skip to main content

nil_core/
event.rs

1// Copyright (C) Call of Nil contributors
2// SPDX-License-Identifier: AGPL-3.0-only
3
4use crate::chat::ChatMessage;
5use crate::continent::Coord;
6use crate::player::PlayerId;
7use crate::report::ReportId;
8use crate::round::Round;
9use crate::world::config::WorldId;
10use bytes::Bytes;
11use serde::{Deserialize, Serialize};
12use std::fmt;
13use strum::Display;
14use tokio::sync::broadcast::{Receiver, Sender, channel};
15
16pub type Listener = Receiver<(Bytes, EventTarget)>;
17
18#[derive(Clone)]
19pub(crate) struct Emitter {
20  sender: Sender<(Bytes, EventTarget)>,
21}
22
23impl Emitter {
24  fn new(capacity: usize) -> Self {
25    let (sender, _) = channel(capacity);
26    Self { sender }
27  }
28
29  pub(crate) fn emit(&self, event: Event, target: EventTarget) {
30    tracing::info!(?target, ?event);
31    let bytes = Bytes::from(event);
32    let _ = self.sender.send((bytes, target));
33  }
34
35  pub(crate) fn emit_to(&self, target: PlayerId, event: Event) {
36    self.emit(event, EventTarget::Player(target));
37  }
38
39  pub(crate) fn broadcast(&self, event: Event) {
40    self.emit(event, EventTarget::Broadcast);
41  }
42
43  pub(crate) fn subscribe(&self) -> Listener {
44    self.sender.subscribe()
45  }
46}
47
48impl Default for Emitter {
49  fn default() -> Self {
50    Self::new(100)
51  }
52}
53
54impl fmt::Debug for Emitter {
55  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56    f.debug_struct("Emitter")
57      .field("sender", &self.sender.receiver_count())
58      .finish()
59  }
60}
61
62#[derive(Clone, Debug, Display, Deserialize, Serialize)]
63#[serde(tag = "kind", rename_all = "kebab-case")]
64#[strum(serialize_all = "kebab-case")]
65#[remain::sorted]
66pub enum Event {
67  /// A new message has been sent in the chat.
68  ChatUpdated {
69    world: WorldId,
70    message: ChatMessage,
71  },
72
73  /// Indicates that there has been a change in the city's data, be it public or not.
74  ///
75  /// This event is only emitted to the city owner.
76  /// If you believe that all players should be notified,
77  /// consider using [`Event::PublicCityUpdated`] instead.
78  CityUpdated { world: WorldId, coord: Coord },
79
80  /// Signals that all active players should disconnect, as the world is about to be dropped.
81  ///
82  /// This event **MUST** only be emitted inside the `Drop` implementation of the `World` struct.
83  Drop { world: WorldId },
84
85  /// Indicates that the player's military has changed.
86  /// It usually means new maneuvers have been initiated,
87  /// since the armies themselves are processed at the end of the round.
88  MilitaryUpdated { world: WorldId, player: PlayerId },
89
90  /// Indicates that there has been a change in some of the player's data, be it public or not.
91  PlayerUpdated { world: WorldId, player: PlayerId },
92
93  /// Indicates that there has been a change in public data for the city.
94  ///
95  /// As a rule, whenever the situation requires this event to be emitted,
96  /// `Event::CityUpdated` should also be emitted, but the opposite is not true!
97  ///
98  /// Unlike [`Event::CityUpdated`], which is emitted only to the city owner,
99  /// this event is sent to all players in the world.
100  PublicCityUpdated { world: WorldId, coord: Coord },
101
102  /// A report was generated.
103  Report { world: WorldId, report: ReportId },
104
105  /// Indicates changes in the round, such as the end of a player's turn or
106  /// the transition from one round to another, after all players have completed their actions.
107  ///
108  /// When emitted at the start of the game or at the end of a round,
109  /// [`Event::RoundUpdated`] typically makes it unnecessary to emit other events,
110  /// as this situation naturally prompts all entities to update themselves.
111  RoundUpdated { world: WorldId, round: Round },
112}
113
114impl From<Event> for Bytes {
115  fn from(event: Event) -> Self {
116    serde_json::to_vec(&event)
117      .map(Bytes::from)
118      .unwrap()
119  }
120}
121
122impl From<Bytes> for Event {
123  fn from(bytes: Bytes) -> Self {
124    serde_json::from_slice(&bytes).unwrap()
125  }
126}
127
128#[derive(Clone, Debug, PartialEq, Eq)]
129pub enum EventTarget {
130  Broadcast,
131  Player(PlayerId),
132}