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::Coord;
6use crate::error::{Error, Result};
7use crate::player::PlayerId;
8use crate::report::ReportKind;
9use crate::round::Round;
10use crate::world::config::WorldId;
11use bytes::Bytes;
12use serde::{Deserialize, Serialize};
13use std::fmt;
14use strum::Display;
15use tokio::sync::broadcast::{Receiver, Sender, channel};
16
17pub type Listener = Receiver<(Bytes, EventTarget)>;
18
19#[derive(Clone)]
20pub(crate) struct Emitter {
21  sender: Sender<(Bytes, EventTarget)>,
22}
23
24impl Emitter {
25  pub fn new() -> Self {
26    let (sender, _) = channel(100);
27    Self { sender }
28  }
29
30  pub(crate) fn emit(&self, event: Event, target: EventTarget) -> Result<()> {
31    tracing::trace!(?target, ?event);
32    let bytes = Bytes::try_from(event)?;
33    let _ = self.sender.send((bytes, target));
34    Ok(())
35  }
36
37  pub(crate) fn emit_to(&self, target: PlayerId, event: Event) -> Result<()> {
38    self.emit(event, EventTarget::Player(target))
39  }
40
41  pub(crate) fn broadcast(&self, event: Event) -> Result<()> {
42    self.emit(event, EventTarget::Broadcast)
43  }
44
45  pub(crate) fn subscribe(&self) -> Listener {
46    self.sender.subscribe()
47  }
48}
49
50impl Default for Emitter {
51  fn default() -> Self {
52    Self::new()
53  }
54}
55
56impl fmt::Debug for Emitter {
57  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58    f.debug_struct("Emitter")
59      .field("sender", &self.sender.receiver_count())
60      .finish()
61  }
62}
63
64#[derive(Clone, Display, Deserialize, Serialize)]
65#[serde(tag = "kind", rename_all = "kebab-case")]
66#[strum(serialize_all = "kebab-case")]
67#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
68#[cfg_attr(feature = "typescript", ts(export))]
69#[remain::sorted]
70pub enum Event {
71  /// A new message has been sent in the chat.
72  ChatMessage {
73    world: WorldId,
74    message: ChatMessage,
75  },
76
77  /// Indicates that there has been a change in the city's data, be it public or not.
78  ///
79  /// This event is only emitted to the city owner.
80  /// If you believe that all players should be notified,
81  /// consider using [`Event::PublicCity`] instead.
82  City { world: WorldId, coord: Coord },
83
84  /// Signals that all active players should disconnect, as the world is about to be dropped.
85  ///
86  /// This event **MUST** only be emitted inside the `Drop` implementation of the `World` struct.
87  Drop { world: WorldId },
88
89  /// Indicates that the market prices have changed.
90  Market { world: WorldId },
91
92  /// Indicates that the player's military has changed.
93  /// It usually means new maneuvers have been initiated,
94  /// since the armies themselves are processed at the end of the round.
95  Military { world: WorldId, player: PlayerId },
96
97  /// Indicates that there has been a change in some of the player's data, be it public or not.
98  Player { world: WorldId, player: PlayerId },
99
100  /// Indicates that there has been a change in public data for the city.
101  ///
102  /// Unlike [`Event::City`], which is emitted only to the city owner,
103  /// this event is sent to all players in the world.
104  ///
105  /// As a rule, whenever the situation requires this event to be emitted,
106  /// [`Event::City`] should also be emitted, but the opposite is not true!
107  PublicCity { world: WorldId, coord: Coord },
108
109  /// A report was generated.
110  Report {
111    world: WorldId,
112    report: Box<ReportKind>,
113  },
114
115  /// Indicates changes in the round, such as the end of a player's turn or
116  /// the transition from one round to another, after all players have completed their actions.
117  ///
118  /// When emitted at the start of the game or at the end of a round,
119  /// [`Event::Round`] typically makes it unnecessary to emit other events,
120  /// as this situation naturally prompts all entities to update themselves.
121  Round { world: WorldId, round: Round },
122}
123
124impl fmt::Debug for Event {
125  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126    match self {
127      Self::ChatMessage { world, message } => {
128        f.debug_struct("ChatMessage")
129          .field("world", world)
130          .field("message", &message.id())
131          .finish()
132      }
133      Self::City { world, coord } => {
134        f.debug_struct("City")
135          .field("world", world)
136          .field("coord", coord)
137          .finish()
138      }
139      Self::Drop { world } => {
140        f.debug_struct("Drop")
141          .field("world", world)
142          .finish()
143      }
144      Self::Market { world } => {
145        f.debug_struct("Market")
146          .field("world", world)
147          .finish()
148      }
149      Self::Military { world, player } => {
150        f.debug_struct("Military")
151          .field("world", world)
152          .field("player", player)
153          .finish()
154      }
155      Self::Player { world, player } => {
156        f.debug_struct("Player")
157          .field("world", world)
158          .field("player", player)
159          .finish()
160      }
161      Self::PublicCity { world, coord } => {
162        f.debug_struct("PublicCity")
163          .field("world", world)
164          .field("coord", coord)
165          .finish()
166      }
167      Self::Report { world, report } => {
168        f.debug_struct("Report")
169          .field("world", world)
170          .field("report", &report.id())
171          .finish()
172      }
173      Self::Round { world, round } => {
174        f.debug_struct("Round")
175          .field("world", world)
176          .field("round", &round.id())
177          .finish()
178      }
179    }
180  }
181}
182
183impl TryFrom<Bytes> for Event {
184  type Error = Error;
185
186  fn try_from(bytes: Bytes) -> Result<Self> {
187    serde_json::from_slice(&bytes).map_err(|err| {
188      tracing::error!("Failed to deserialize event: {err}");
189      Error::FailedToDeserializeEvent
190    })
191  }
192}
193
194impl TryFrom<Event> for Bytes {
195  type Error = Error;
196
197  fn try_from(event: Event) -> Result<Self> {
198    serde_json::to_vec(&event)
199      .map(Bytes::from)
200      .map_err(|err| {
201        tracing::error!("Failed to serialize event: {err}");
202        Error::FailedToSerializeEvent
203      })
204  }
205}
206
207#[derive(Clone, Debug, PartialEq, Eq)]
208pub enum EventTarget {
209  Broadcast,
210  Player(PlayerId),
211}