1use canwu_core::{ArmyId, BoundaryId, CommandId, EntityRef, EventId, PersonId, TerritoryId};
4use canwu_time::SimTime;
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
8#[serde(tag = "type", content = "id", rename_all = "snake_case")]
9pub enum CauseRef {
10 Boundary(BoundaryId),
11 Command(CommandId),
12 Event(EventId),
13 System(String),
14}
15
16#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
17#[serde(tag = "type", rename_all = "snake_case")]
18pub enum EventKind {
19 MoveOrdered {
20 army: ArmyId,
21 from: TerritoryId,
22 to: TerritoryId,
23 arrival_at: SimTime,
24 },
25 ArmyArrived {
26 army: ArmyId,
27 territory: TerritoryId,
28 },
29 ReportDispatched {
30 recipient: PersonId,
31 army: ArmyId,
32 arrives_at: SimTime,
33 },
34 KnowledgeUpdated {
35 recipient: PersonId,
36 army: ArmyId,
37 known_location: TerritoryId,
38 },
39 DebugFieldChanged {
40 entity: EntityRef,
41 field: String,
42 old_value: String,
43 new_value: String,
44 },
45 Plugin {
46 plugin: String,
47 event_type: String,
48 },
49}
50
51#[derive(Clone, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
58#[serde(tag = "type", content = "value", rename_all = "snake_case")]
59pub enum EventAudience {
60 Public,
61 Actor(PersonId),
62 Actors(Vec<PersonId>),
63 AffectedActors,
66 #[default]
67 Private,
68}
69
70impl EventKind {
71 #[must_use]
72 pub const fn event_type(&self) -> &'static str {
73 match self {
74 Self::MoveOrdered { .. } => "move_ordered",
75 Self::ArmyArrived { .. } => "army_arrived",
76 Self::ReportDispatched { .. } => "report_dispatched",
77 Self::KnowledgeUpdated { .. } => "knowledge_updated",
78 Self::DebugFieldChanged { .. } => "debug_field_changed",
79 Self::Plugin { .. } => "plugin",
80 }
81 }
82
83 #[must_use]
91 pub fn qualified_event_type(&self) -> String {
92 match self {
93 Self::Plugin { plugin, event_type } => format!("{plugin}.{event_type}"),
94 _ => self.event_type().to_owned(),
95 }
96 }
97}
98
99#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
100pub struct SimEvent {
101 pub id: EventId,
102 pub timestamp: SimTime,
103 pub kind: EventKind,
104 pub affected_entities: Vec<EntityRef>,
105 pub summary: String,
106 pub cause: Option<CauseRef>,
107 pub correlation_id: u64,
108}
109
110#[cfg(test)]
111mod tests {
112 use super::EventKind;
113 use canwu_core::{ArmyId, TerritoryId};
114
115 #[test]
116 fn qualified_event_type_preserves_legacy_labels_and_disambiguates_plugins() {
117 let built_in = EventKind::ArmyArrived {
118 army: ArmyId::new(1),
119 territory: TerritoryId::new(2),
120 };
121 assert_eq!(built_in.event_type(), "army_arrived");
122 assert_eq!(built_in.qualified_event_type(), "army_arrived");
123
124 let supply = EventKind::Plugin {
125 plugin: "example-supply".to_owned(),
126 event_type: "grain_allocated".to_owned(),
127 };
128 let demand = EventKind::Plugin {
129 plugin: "example-demand".to_owned(),
130 event_type: "grain_allocated".to_owned(),
131 };
132
133 assert_eq!(supply.event_type(), "plugin");
134 assert_eq!(
135 supply.qualified_event_type(),
136 "example-supply.grain_allocated"
137 );
138 assert_eq!(
139 demand.qualified_event_type(),
140 "example-demand.grain_allocated"
141 );
142 assert_ne!(supply.qualified_event_type(), demand.qualified_event_type());
143 }
144}