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