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