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}