tf_demo_parser/demo/message/
gameevent.rs1use bitbuffer::{BitRead, BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
2use parse_display::Display;
3use serde::{Deserialize, Serialize};
4
5use crate::demo::gameevent_gen::GameEventType;
6use crate::demo::gamevent::{
7 GameEvent, GameEventDefinition, GameEventEntry, GameEventValueType, RawGameEvent,
8};
9use crate::demo::parser::{Encode, ParseBitSkip};
10use crate::{GameEventError, Parse, ParseError, ParserState, ReadResult, Result, Stream};
11
12#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
13#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
14pub struct GameEventMessage {
15 pub event_type_id: GameEventTypeId,
16 pub event_type: GameEventType,
17 pub event: GameEvent,
18}
19
20impl Parse<'_> for GameEventMessage {
21 fn parse(stream: &mut Stream, state: &ParserState) -> Result<Self> {
22 let length: u16 = stream.read_sized(11)?;
23 let mut data = stream.read_bits(length as usize)?;
24 let event_type_id: GameEventTypeId = data.read()?;
25
26 if state.event_definitions.is_empty() {
28 return Ok(GameEventMessage {
29 event_type_id,
30 event_type: GameEventType::Unknown(String::new()),
31 event: GameEvent::Unknown(RawGameEvent {
32 event_type: GameEventType::Unknown(String::new()),
33 values: Vec::new(),
34 }),
35 });
36 }
37
38 let event = match state.event_definitions.get(usize::from(event_type_id)) {
39 Some(definition) => GameEvent::read(&mut data, definition)?,
40 None => {
41 return Err(ParseError::MalformedGameEvent(GameEventError::UnknownType(
42 event_type_id,
43 )));
44 }
45 };
46 Ok(GameEventMessage {
47 event_type_id,
48 event_type: event.event_type(),
49 event,
50 })
51 }
52}
53
54impl Encode for GameEventMessage {
55 fn encode(&self, stream: &mut BitWriteStream<LittleEndian>, state: &ParserState) -> Result<()> {
56 let definition = state
57 .event_definitions
58 .iter()
59 .find(|def| def.event_type == self.event_type)
60 .ok_or(ParseError::MalformedGameEvent(GameEventError::UnknownType(
61 self.event_type_id,
62 )))?;
63 stream.reserve_length(11, |stream| {
64 self.event_type_id.write(stream)?;
65 self.event.write(stream, definition)
66 })
67 }
68}
69
70#[test]
71fn test_game_event_roundtrip() {
72 use crate::demo::gameevent_gen::{GameInitEvent, ServerShutdownEvent};
73
74 let definitions = vec![
75 GameEventDefinition {
76 id: GameEventTypeId(0),
77 event_type: GameEventType::ServerShutdown,
78 entries: vec![GameEventEntry {
79 name: "reason".to_string(),
80 kind: GameEventValueType::String,
81 }],
82 },
83 GameEventDefinition {
84 id: GameEventTypeId(1),
85 event_type: GameEventType::ServerChangeLevelFailed,
86 entries: vec![GameEventEntry {
87 name: "level_name".to_string(),
88 kind: GameEventValueType::String,
89 }],
90 },
91 GameEventDefinition {
92 id: GameEventTypeId(2),
93 event_type: GameEventType::GameInit,
94 entries: vec![],
95 },
96 ];
97 let mut state = ParserState::new(24, |_| false, false);
98 state.event_definitions = definitions;
99
100 crate::test_roundtrip_encode(
101 GameEventMessage {
102 event_type_id: GameEventTypeId(0),
103 event_type: GameEventType::ServerShutdown,
104 event: GameEvent::ServerShutdown(ServerShutdownEvent {
105 reason: "asd".into(),
106 }),
107 },
108 &state,
109 );
110 crate::test_roundtrip_encode(
111 GameEventMessage {
112 event_type_id: GameEventTypeId(2),
113 event_type: GameEventType::GameInit,
114 event: GameEvent::GameInit(GameInitEvent {}),
115 },
116 &state,
117 );
118}
119
120impl ParseBitSkip<'_> for GameEventMessage {
121 fn parse_skip(stream: &mut Stream, _state: &ParserState) -> Result<()> {
122 let length: u16 = stream.read_sized(11)?;
123 stream.skip_bits(length as usize).map_err(ParseError::from)
124 }
125}
126
127#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
128#[derive(
129 BitRead,
130 BitWrite,
131 Debug,
132 Clone,
133 Copy,
134 PartialEq,
135 Eq,
136 Hash,
137 PartialOrd,
138 Ord,
139 Display,
140 Serialize,
141 Deserialize,
142)]
143pub struct GameEventTypeId(#[size = 9] u16);
144
145impl From<GameEventTypeId> for usize {
146 fn from(id: GameEventTypeId) -> Self {
147 id.0 as usize
148 }
149}
150
151impl From<GameEventTypeId> for u16 {
152 fn from(id: GameEventTypeId) -> Self {
153 id.0
154 }
155}
156
157#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
158#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
159pub struct GameEventListMessage {
160 pub event_list: Vec<GameEventDefinition>,
161}
162
163impl BitRead<'_, LittleEndian> for GameEventDefinition {
164 fn read(stream: &mut Stream) -> ReadResult<Self> {
165 let event_type: GameEventTypeId = stream.read()?;
166 let name: String = stream.read()?;
167 let mut entries = Vec::new();
168
169 let mut entry_type = stream.read()?;
170 while entry_type != GameEventValueType::None {
171 let entry_name = stream.read()?;
172 entries.push(GameEventEntry {
173 name: entry_name,
174 kind: entry_type,
175 });
176 entry_type = stream.read()?;
177 }
178
179 Ok(GameEventDefinition {
180 id: event_type,
181 event_type: GameEventType::from_type_name(name.as_str()),
182 entries,
183 })
184 }
185}
186
187impl BitWrite<LittleEndian> for GameEventDefinition {
188 fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
189 self.id.write(stream)?;
190 self.event_type.as_str().write(stream)?;
194
195 for entry in self.entries.iter() {
196 entry.kind.write(stream)?;
197 entry.name.write(stream)?;
198 }
199 GameEventValueType::None.write(stream)?;
200
201 Ok(())
202 }
203}
204
205#[test]
206fn test_event_definition_roundtrip() {
207 crate::test_roundtrip_write(GameEventDefinition {
208 id: GameEventTypeId(0),
209 event_type: GameEventType::ServerChangeLevelFailed,
210 entries: vec![GameEventEntry {
211 name: "level_name".to_string(),
212 kind: GameEventValueType::String,
213 }],
214 });
215}
216
217impl BitRead<'_, LittleEndian> for GameEventListMessage {
218 fn read(stream: &mut Stream) -> ReadResult<Self> {
219 let count: u16 = stream.read_sized(9)?;
220 let length: u32 = stream.read_sized(20)?;
221 let mut data = stream.read_bits(length as usize)?;
222 let event_list: Vec<GameEventDefinition> = data.read_sized(count as usize)?;
223
224 Ok(GameEventListMessage { event_list })
225 }
226}
227
228impl BitWrite<LittleEndian> for GameEventListMessage {
229 fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
230 (self.event_list.len() as u16).write_sized(stream, 9)?;
231 stream.reserve_length(20, |stream| {
232 for event in self.event_list.iter() {
233 event.write(stream)?;
234 }
235 Ok(())
236 })
237 }
238}
239
240#[test]
241fn test_event_list_roundtrip() {
242 crate::test_roundtrip_write(GameEventListMessage { event_list: vec![] });
243 crate::test_roundtrip_write(GameEventListMessage {
244 event_list: vec![GameEventDefinition {
245 id: GameEventTypeId(0),
246 event_type: GameEventType::ServerChangeLevelFailed,
247 entries: vec![GameEventEntry {
248 name: "level_name".to_string(),
249 kind: GameEventValueType::String,
250 }],
251 }],
252 });
253 crate::test_roundtrip_write(GameEventListMessage {
254 event_list: vec![
255 GameEventDefinition {
256 id: GameEventTypeId(0),
257 event_type: GameEventType::ServerSpawn,
258 entries: vec![
259 GameEventEntry {
260 name: "hostname".to_string(),
261 kind: GameEventValueType::String,
262 },
263 GameEventEntry {
264 name: "address".to_string(),
265 kind: GameEventValueType::String,
266 },
267 GameEventEntry {
268 name: "ip".to_string(),
269 kind: GameEventValueType::Long,
270 },
271 GameEventEntry {
272 name: "port".to_string(),
273 kind: GameEventValueType::Short,
274 },
275 GameEventEntry {
276 name: "game".to_string(),
277 kind: GameEventValueType::String,
278 },
279 GameEventEntry {
280 name: "map_name".to_string(),
281 kind: GameEventValueType::String,
282 },
283 GameEventEntry {
284 name: "max_players".to_string(),
285 kind: GameEventValueType::Long,
286 },
287 GameEventEntry {
288 name: "os".to_string(),
289 kind: GameEventValueType::String,
290 },
291 GameEventEntry {
292 name: "dedicated".to_string(),
293 kind: GameEventValueType::Boolean,
294 },
295 GameEventEntry {
296 name: "password".to_string(),
297 kind: GameEventValueType::Boolean,
298 },
299 ],
300 },
301 GameEventDefinition {
302 id: GameEventTypeId(1),
303 event_type: GameEventType::ServerChangeLevelFailed,
304 entries: vec![GameEventEntry {
305 name: "level_name".to_string(),
306 kind: GameEventValueType::String,
307 }],
308 },
309 GameEventDefinition {
310 id: GameEventTypeId(2),
311 event_type: GameEventType::GameInit,
312 entries: vec![],
313 },
314 ],
315 });
316}