1use 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};
16use uuid::Uuid;
17
18pub type Listener = Receiver<(Bytes, EventTarget)>;
19
20#[derive(Clone)]
21pub(crate) struct Emitter {
22 sender: Sender<(Bytes, EventTarget)>,
23}
24
25impl Emitter {
26 pub fn new() -> Self {
27 let (sender, _) = channel(100);
28 Self { sender }
29 }
30
31 pub(crate) fn emit(&self, event: Event, target: EventTarget) -> Result<()> {
32 tracing::trace!(?target, ?event);
33 let bytes = Bytes::try_from(event)?;
34 let _ = self.sender.send((bytes, target));
35 Ok(())
36 }
37
38 pub(crate) fn emit_to(&self, target: PlayerId, event: Event) -> Result<()> {
39 self.emit(event, EventTarget::Player(target))
40 }
41
42 pub(crate) fn broadcast(&self, event: Event) -> Result<()> {
43 self.emit(event, EventTarget::Broadcast)
44 }
45
46 pub(crate) fn subscribe(&self) -> Listener {
47 self.sender.subscribe()
48 }
49}
50
51impl Default for Emitter {
52 fn default() -> Self {
53 Self::new()
54 }
55}
56
57impl fmt::Debug for Emitter {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 f.debug_struct("Emitter")
60 .field("sender", &self.sender.receiver_count())
61 .finish()
62 }
63}
64
65#[derive(Clone, Display, Deserialize, Serialize)]
66#[serde(tag = "kind", rename_all = "kebab-case")]
67#[strum(serialize_all = "kebab-case")]
68#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
69#[cfg_attr(feature = "typescript", ts(export))]
70#[remain::sorted]
71pub enum Event {
72 ChatMessage {
74 id: EventId,
75 world: WorldId,
76 message: ChatMessage,
77 },
78
79 City {
85 id: EventId,
86 world: WorldId,
87 coord: Coord,
88 },
89
90 Drop { id: EventId, world: WorldId },
94
95 Market { id: EventId, world: WorldId },
97
98 Military {
102 id: EventId,
103 world: WorldId,
104 player: PlayerId,
105 },
106
107 Player {
109 id: EventId,
110 world: WorldId,
111 player: PlayerId,
112 },
113
114 PublicCity {
122 id: EventId,
123 world: WorldId,
124 coord: Coord,
125 },
126
127 Report {
129 id: EventId,
130 world: WorldId,
131 report: Box<ReportKind>,
132 },
133
134 Round {
141 id: EventId,
142 world: WorldId,
143 round: Round,
144 },
145}
146
147impl fmt::Debug for Event {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 match self {
150 Self::ChatMessage { id, world, message } => {
151 f.debug_struct("ChatMessage")
152 .field("id", id)
153 .field("world", world)
154 .field("message", &message.id())
155 .finish()
156 }
157 Self::City { id, world, coord } => {
158 f.debug_struct("City")
159 .field("id", id)
160 .field("world", world)
161 .field("coord", coord)
162 .finish()
163 }
164 Self::Drop { id, world } => {
165 f.debug_struct("Drop")
166 .field("id", id)
167 .field("world", world)
168 .finish()
169 }
170 Self::Market { id, world } => {
171 f.debug_struct("Market")
172 .field("id", id)
173 .field("world", world)
174 .finish()
175 }
176 Self::Military { id, world, player } => {
177 f.debug_struct("Military")
178 .field("id", id)
179 .field("world", world)
180 .field("player", player)
181 .finish()
182 }
183 Self::Player { id, world, player } => {
184 f.debug_struct("Player")
185 .field("id", id)
186 .field("world", world)
187 .field("player", player)
188 .finish()
189 }
190 Self::PublicCity { id, world, coord } => {
191 f.debug_struct("PublicCity")
192 .field("id", id)
193 .field("world", world)
194 .field("coord", coord)
195 .finish()
196 }
197 Self::Report { id, world, report } => {
198 f.debug_struct("Report")
199 .field("id", id)
200 .field("world", world)
201 .field("report", &report.id())
202 .finish()
203 }
204 Self::Round { id, world, round } => {
205 f.debug_struct("Round")
206 .field("id", id)
207 .field("world", world)
208 .field("round", &round.id())
209 .finish()
210 }
211 }
212 }
213}
214
215impl TryFrom<Bytes> for Event {
216 type Error = Error;
217
218 fn try_from(bytes: Bytes) -> Result<Self> {
219 serde_json::from_slice(&bytes).map_err(|err| {
220 tracing::error!("Failed to deserialize event: {err}");
221 Error::FailedToDeserializeEvent
222 })
223 }
224}
225
226impl TryFrom<Event> for Bytes {
227 type Error = Error;
228
229 fn try_from(event: Event) -> Result<Self> {
230 serde_json::to_vec(&event)
231 .map(Bytes::from)
232 .map_err(|err| {
233 tracing::error!("Failed to serialize event: {err}");
234 Error::FailedToSerializeEvent
235 })
236 }
237}
238
239#[derive(
240 Clone,
241 Copy,
242 Debug,
243 derive_more::Deref,
244 derive_more::Display,
245 PartialEq,
246 Eq,
247 PartialOrd,
248 Ord,
249 Hash,
250 Deserialize,
251 Serialize,
252)]
253#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
254pub struct EventId(Uuid);
255
256impl EventId {
257 #[must_use]
258 pub fn new() -> Self {
259 Self(Uuid::now_v7())
260 }
261}
262
263impl Default for EventId {
264 fn default() -> Self {
265 Self::new()
266 }
267}
268
269#[derive(Clone, Debug, PartialEq, Eq)]
270pub enum EventTarget {
271 Broadcast,
272 Player(PlayerId),
273}