bevy_fleet/
events.rs

1use bevy::prelude::*;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use std::collections::HashMap;
5
6/// A tracked event in the application.
7#[derive(Clone, Debug, Serialize, Deserialize, Event, Message)]
8pub struct FleetEvent {
9    pub event_type: String,
10    pub data: HashMap<String, String>,
11    pub timestamp: u64,
12}
13
14impl FleetEvent {
15    pub fn new(event_type: impl Into<String>) -> Self {
16        Self {
17            event_type: event_type.into(),
18            data: HashMap::new(),
19            timestamp: current_unix_time_secs(),
20        }
21    }
22
23    pub fn with_data(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
24        self.data.insert(key.into(), value.into());
25        self
26    }
27}
28
29/// Buffer that retains Fleet events across frames until the publisher collects them.
30#[derive(Default, Resource)]
31pub struct FleetEventBuffer {
32    events: Vec<FleetEvent>,
33}
34
35impl FleetEventBuffer {
36    pub fn extend<I>(&mut self, iter: I)
37    where
38        I: IntoIterator<Item = FleetEvent>,
39    {
40        self.events.extend(iter);
41    }
42
43    pub fn take(&mut self) -> Vec<FleetEvent> {
44        std::mem::take(&mut self.events)
45    }
46}
47
48/// Serializes custom Bevy events into `FleetEvent`s so they can be consumed by Fleet.
49pub fn forward_serialized_events<T>(
50    mut reader: MessageReader<T>,
51    mut fleet_writer: MessageWriter<FleetEvent>,
52) where
53    T: Message + Serialize + Clone + Send + Sync + 'static,
54{
55    for event in reader.read() {
56        let event_type = std::any::type_name::<T>().to_string();
57
58        let (serialized_value, serialization_error) = match serde_json::to_value(event) {
59            Ok(value) => (value, None),
60            Err(err) => (Value::Null, Some(err.to_string())),
61        };
62
63        let mut fleet_event = FleetEvent::new(event_type.clone());
64
65        match &serialized_value {
66            Value::Object(map) => {
67                for (key, value) in map {
68                    fleet_event.data.insert(key.clone(), value_to_string(value));
69                }
70            }
71            Value::Null => {}
72            other => {
73                fleet_event
74                    .data
75                    .insert("value".to_string(), value_to_string(other));
76            }
77        }
78
79        if let Some(err) = &serialization_error {
80            fleet_event
81                .data
82                .insert("serialization_error".to_string(), err.clone());
83        }
84
85        fleet_writer.write(fleet_event);
86    }
87}
88
89/// Collects Fleet events written this frame and stores them in the persistent buffer.
90pub fn collect_fleet_events(
91    mut reader: MessageReader<FleetEvent>,
92    mut buffer: ResMut<FleetEventBuffer>,
93) {
94    let new_events: Vec<FleetEvent> = reader.read().cloned().collect();
95    if !new_events.is_empty() {
96        buffer.extend(new_events);
97    }
98}
99
100fn current_unix_time_secs() -> u64 {
101    std::time::SystemTime::now()
102        .duration_since(std::time::UNIX_EPOCH)
103        .unwrap_or_default()
104        .as_secs()
105}
106
107fn value_to_string(value: &Value) -> String {
108    match value {
109        Value::String(s) => s.clone(),
110        Value::Null => "null".to_string(),
111        other => other.to_string(),
112    }
113}