csgo_gsi/update/
mod.rs

1//! all information that can be contained in a GSI update
2
3use std::collections::HashMap;
4
5use serde::{Serialize, Deserialize, de::IgnoredAny};
6
7pub mod player;
8use player::Player;
9
10pub mod map;
11use map::Map;
12
13pub mod round;
14use round::Round;
15
16// TODO abuse generics to align subscriptions with these types
17
18/// a team
19#[derive(Clone, Debug, Deserialize, Serialize)]
20pub enum Team {
21    /// counter-terrorists
22    CT,
23    /// terrorists
24    T,
25}
26
27/// an update received from CS:GO
28#[derive(Clone, Debug, Deserialize, Serialize)]
29#[serde(deny_unknown_fields)]
30pub struct Update {
31    /// map info
32    pub map: Option<Map>,
33    /// player info
34    pub player: Option<Player>,
35    /// provider (CS:GO) info
36    pub provider: Option<Provider>,
37    /// authentication info, matching initial config
38    pub auth: HashMap<String, String>,
39    /// round info
40    pub round: Option<Round>,
41    #[serde(skip_serializing, default)]
42    added: IgnoredAny,
43    #[serde(skip_serializing, default)]
44    previously: IgnoredAny,
45}
46
47/// information about the GSI info provider (CS:GO itself)
48#[derive(Clone, Debug, Deserialize, Serialize)]
49#[serde(deny_unknown_fields)]
50pub struct Provider {
51    /// game name
52    pub name: String,
53    /// steam app ID
54    #[serde(rename = "appid")]
55    pub app_id: u64,
56    /// version number
57    pub version: u64,
58    /// player's steam ID
59    #[serde(rename = "steamid")]
60    pub steam_id: String,
61    /// update timestamp
62    pub timestamp: u64,
63}
64
65#[cfg(feature = "rhai")]
66#[allow(missing_docs)]
67mod rhai_package {
68    use std::fmt::Display;
69    use rhai::{
70        def_package,
71        Dynamic,
72        ImmutableString,
73        Map as RhaiMap,
74        packages::CorePackage,
75    };
76    use super::*;
77
78    trait OptionExt {
79        fn into_dynamic(self) -> Dynamic;
80    }
81
82    impl<T: Send + Sync + Clone + 'static> OptionExt for Option<T> {
83        fn into_dynamic(self) -> Dynamic {
84            match self {
85                Some(x) => Dynamic::from(x),
86                None => Dynamic::from(()),
87            }
88        }
89    }
90
91    trait StringExt {
92        fn into_immutable(self) -> ImmutableString;
93    }
94
95    impl StringExt for String {
96        fn into_immutable(self) -> ImmutableString {
97            self.into()
98        }
99    }
100
101    trait MapExt {
102        fn into_rhai_map(self) -> RhaiMap;
103    }
104
105    impl<K: Display, V: 'static + Send + Sync + Clone> MapExt for HashMap<K, V> {
106        fn into_rhai_map(self) -> RhaiMap {
107            self.into_iter()
108                .map(|(k, v)| -> (ImmutableString, Dynamic) {
109                    (format!("{}", k).into(), Dynamic::from(v))
110                })
111                .collect()
112        }
113    }
114
115    def_package!(rhai:CSGOPackage:"Rhai package for CS:GO GSI updates", module, {
116        CorePackage::init(module);
117
118        macro_rules! make_debug {
119            ($ty:ty) => {
120                module.set_fn_1_mut("debug", |x: &mut $ty| -> Result<ImmutableString, _> {
121                    Ok(format!("{:?}", x).into())
122                });
123            }
124        }
125
126        macro_rules! make_stringable {
127            ($ty:ty as Debug) => {
128                make_debug!($ty);
129                module.set_fn_1_mut("to_string", |x: &mut $ty| -> Result<ImmutableString, _> {
130                    Ok(format!("{:?}", x).into())
131                });
132                module.set_fn_1_mut("print", |x: &mut $ty| -> Result<ImmutableString, _> {
133                    Ok(format!("{:?}", x).into())
134                });
135                module.set_fn_2("+", |s1: ImmutableString, s: $ty| -> Result<ImmutableString, _> {
136                    Ok(s1 + format!("{:?}", s))
137                });
138                module.set_fn_2("+", |s: $ty, s2: ImmutableString| -> Result<ImmutableString, _> {
139                    Ok(format!("{:?}{}", s, s2).into())
140                });
141                module.set_fn_2_mut("+=", |s1: &mut ImmutableString, s: $ty| -> Result<(), _> {
142                    *s1 = format!("{}{:?}", s1, s).into();
143                    Ok(())
144                })
145            }
146        }
147
148        macro_rules! make_getter {
149            ($ty:ty:type.$into:ident()) => {
150                module.set_getter_fn("type", |x: &mut $ty| Ok(x.r#type.clone().$into()));
151            };
152
153            ($ty:ty:$name:ident) => {
154                module.set_getter_fn(stringify!($name), |x: &mut $ty| Ok(x.$name.clone()));
155            };
156
157            ($ty:ty:$name:ident.$into:ident()) => {
158                module.set_getter_fn(stringify!($name), |x: &mut $ty| Ok(x.$name.clone().$into()));
159            };
160        }
161
162        make_debug!(Update);
163        make_getter!(Update:map.into_dynamic());
164        make_getter!(Update:player.into_dynamic());
165        make_getter!(Update:provider.into_dynamic());
166        make_getter!(Update:round.into_dynamic());
167
168        make_debug!(Provider);
169        make_getter!(Provider:name.into_immutable());
170        make_getter!(Provider:app_id);
171        make_getter!(Provider:version);
172        make_getter!(Provider:steam_id.into_immutable());
173        make_getter!(Provider:timestamp);
174
175        make_stringable!(Team as Debug);
176
177        make_debug!(Map);
178        make_getter!(Map:current_spectators);
179        make_getter!(Map:mode);
180        make_getter!(Map:name.into_immutable());
181        make_getter!(Map:num_matches_to_win_series);
182        make_getter!(Map:phase);
183        make_getter!(Map:round);
184        make_getter!(Map:round_wins.into_rhai_map());
185        make_getter!(Map:souvenirs_total);
186        make_getter!(Map:team_ct);
187        make_getter!(Map:team_t);
188
189        make_stringable!(map::Mode as Debug);
190
191        make_stringable!(map::Phase as Debug);
192
193        make_debug!(map::Team);
194        make_getter!(map::Team:score);
195        make_getter!(map::Team:consecutive_round_losses);
196        make_getter!(map::Team:timeouts_remaining);
197        make_getter!(map::Team:matches_won_this_series);
198        make_getter!(map::Team:name.into_dynamic());
199        make_getter!(map::Team:flag.into_dynamic());
200
201        make_debug!(Player);
202        make_getter!(Player:steam_id);
203        make_getter!(Player:name);
204        make_getter!(Player:observer_slot.into_dynamic());
205        make_getter!(Player:activity);
206        make_getter!(Player:match_stats.into_dynamic());
207        make_getter!(Player:state.into_dynamic());
208        make_getter!(Player:team.into_dynamic());
209        make_getter!(Player:weapons.into_rhai_map());
210        make_getter!(Player:clan.into_dynamic());
211
212        make_stringable!(player::Activity as Debug);
213
214        make_debug!(player::MatchStats);
215        make_getter!(player::MatchStats:kills);
216        make_getter!(player::MatchStats:assists);
217        make_getter!(player::MatchStats:deaths);
218        make_getter!(player::MatchStats:mvps);
219        make_getter!(player::MatchStats:score);
220
221        make_debug!(player::State);
222        make_getter!(player::State:health);
223        make_getter!(player::State:armor);
224        make_getter!(player::State:helmet);
225        make_getter!(player::State:flashed);
226        make_getter!(player::State:smoked);
227        make_getter!(player::State:burning);
228        make_getter!(player::State:money);
229        make_getter!(player::State:round_kills);
230        make_getter!(player::State:round_killhs);
231        make_getter!(player::State:equip_value);
232        make_getter!(player::State:round_totaldmg.into_dynamic());
233        make_getter!(player::State:defuse_kit.into_dynamic());
234
235        make_debug!(player::Weapon);
236        make_getter!(player::Weapon:name);
237        make_getter!(player::Weapon:paintkit);
238        make_getter!(player::Weapon:type.into_dynamic());
239        make_getter!(player::Weapon:state);
240        make_getter!(player::Weapon:ammo_clip.into_dynamic());
241        make_getter!(player::Weapon:ammo_clip_max.into_dynamic());
242        make_getter!(player::Weapon:ammo_reserve.into_dynamic());
243
244        make_stringable!(player::WeaponType as Debug);
245
246        make_stringable!(player::WeaponState as Debug);
247
248        make_debug!(Round);
249        make_getter!(Round:phase);
250        make_getter!(Round:bomb.into_dynamic());
251        make_getter!(Round:win_team.into_dynamic());
252
253        make_stringable!(round::Phase as Debug);
254
255        make_stringable!(round::BombState as Debug);
256    });
257}
258
259#[cfg(feature = "rhai")]
260pub use rhai_package::CSGOPackage;