Skip to main content

source2_demo/event/
mod.rs

1//! Game event system for handling in-game events.
2//!
3//! This module provides types for working with game events - structured events
4//! that occur during gameplay like player kills, item purchases, ability uses,
5//! etc.
6//!
7//! # Overview
8//!
9//! Game events are defined by the game and contain named key-value pairs.
10//! Each event has a name (e.g., "dota_player_kill") and a set of values.
11//!
12//! # Examples
13//!
14//! ## Handling game events
15//!
16//! ```no_run
17//! use source2_demo::prelude::*;
18//!
19//! #[derive(Default)]
20//! struct EventLogger;
21//!
22//! #[observer]
23//! #[uses_game_events]
24//! impl EventLogger {
25//!     #[on_game_event]
26//!     fn on_game_event(&mut self, ctx: &Context, ge: &GameEvent) -> ObserverResult {
27//!         println!("Event: {}", ge.name());
28//!
29//!         // Iterate all key-value pairs
30//!         for (key, value) in ge.iter() {
31//!             println!("  {}: {:?}", key, value);
32//!         }
33//!
34//!         // Get specific value
35//!         if let Ok(player_id) = ge.get_value("player_id") {
36//!             let id: i32 = player_id.try_into()?;
37//!             println!("Player ID: {}", id);
38//!         }
39//!
40//!         Ok(())
41//!     }
42//! }
43//! ```
44
45#[cfg(feature = "dota")]
46mod combat_log;
47mod definition;
48mod list;
49mod value;
50
51#[cfg(feature = "dota")]
52pub use combat_log::*;
53use definition::*;
54pub use list::*;
55pub use value::*;
56
57use crate::error::GameEventError;
58use crate::proto::CSvcMsgGameEvent;
59
60/// Represents a game event with its name and values.
61///
62/// Game events are structured in-game occurrences. Each event has a name and a
63/// set of named values.
64///
65/// # Examples
66///
67/// ## Accessing event data
68///
69/// ```no_run
70/// use source2_demo::prelude::*;
71///
72/// # fn example(ge: &GameEvent) -> anyhow::Result<()> {
73/// // Get the event name
74/// println!("Event: {}", ge.name());
75///
76/// // Iterate all key-value pairs
77/// for (key, value) in ge.iter() {
78///     println!("{}: {:?}", key, value);
79/// }
80///
81/// // Get a specific value
82/// let player_id: i32 = ge.get_value("player_id")?.try_into()?;
83/// # Ok(())
84/// # }
85/// ```
86pub struct GameEvent<'a> {
87    id: i32,
88    list: &'a GameEventList,
89    keys: Vec<EventValue>,
90}
91
92impl<'a> GameEvent<'a> {
93    pub(crate) fn new(list: &'a GameEventList, ge: CSvcMsgGameEvent) -> Self {
94        let id = ge.eventid();
95        let keys = ge
96            .keys
97            .iter()
98            .map(|key| match key.r#type() {
99                1 => EventValue::String(key.val_string().into()),
100                2 => EventValue::Float(key.val_float()),
101                3 => EventValue::Int(key.val_long()),
102                4 => EventValue::Int(key.val_short()),
103                5 => EventValue::Byte(key.val_byte() as u8),
104                6 => EventValue::Bool(key.val_bool()),
105                7 => EventValue::U64(key.val_uint64()),
106                8 => EventValue::Int(key.val_long()),
107                9 => EventValue::Int(key.val_short()),
108                _ => unreachable!("Unknown event type: {}", key.r#type()),
109            })
110            .collect::<Vec<_>>();
111
112        Self { id, list, keys }
113    }
114
115    /// Returns the event's numeric ID.
116    pub fn id(&self) -> i32 {
117        self.id
118    }
119
120    /// Returns the event's name.
121    ///
122    /// Event names are strings
123    pub fn name(&self) -> &str {
124        &self.list.list[&self.id].name
125    }
126
127    /// Returns an iterator over all key-value pairs in the event.
128    ///
129    /// # Examples
130    ///
131    /// ```no_run
132    /// use source2_demo::prelude::*;
133    ///
134    /// # fn example(ge: &GameEvent) {
135    /// for (key, value) in ge.iter() {
136    ///     println!("{}: {:?}", key, value);
137    /// }
138    /// # }
139    /// ```
140    pub fn iter(&self) -> impl Iterator<Item = (&str, &EventValue)> {
141        self.keys
142            .iter()
143            .zip(self.list.list[&self.id].keys.iter())
144            .map(|(value, key)| (key.name.as_str(), value))
145    }
146
147    /// Gets the value for a specific key.
148    ///
149    /// # Arguments
150    ///
151    /// * `key` - The name of the key to look up
152    ///
153    /// # Errors
154    ///
155    /// Returns [`GameEventError::UnknownKey`] if the key doesn't exist for this
156    /// event.
157    ///
158    /// # Examples
159    ///
160    /// ```no_run
161    /// use source2_demo::prelude::*;
162    ///
163    /// # fn example(ge: &GameEvent) -> anyhow::Result<()> {
164    /// // Get a value and convert it
165    /// let player_id: i32 = ge.get_value("player_id")?.try_into()?;
166    /// let hero_name: String = ge.get_value("hero_name")?.try_into()?;
167    /// # Ok(())
168    /// # }
169    /// ```
170    pub fn get_value(&self, key: &str) -> Result<&EventValue, GameEventError> {
171        let key = self.list.list[&self.id]
172            .name_to_key
173            .get(key)
174            .ok_or_else(|| GameEventError::UnknownKey(key.to_string()))?;
175        Ok(&self.keys[key.id as usize])
176    }
177}