1use 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#[derive(Clone, Debug, Deserialize, Serialize)]
20pub enum Team {
21 CT,
23 T,
25}
26
27#[derive(Clone, Debug, Deserialize, Serialize)]
29#[serde(deny_unknown_fields)]
30pub struct Update {
31 pub map: Option<Map>,
33 pub player: Option<Player>,
35 pub provider: Option<Provider>,
37 pub auth: HashMap<String, String>,
39 pub round: Option<Round>,
41 #[serde(skip_serializing, default)]
42 added: IgnoredAny,
43 #[serde(skip_serializing, default)]
44 previously: IgnoredAny,
45}
46
47#[derive(Clone, Debug, Deserialize, Serialize)]
49#[serde(deny_unknown_fields)]
50pub struct Provider {
51 pub name: String,
53 #[serde(rename = "appid")]
55 pub app_id: u64,
56 pub version: u64,
58 #[serde(rename = "steamid")]
60 pub steam_id: String,
61 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;