tf_demo_parser/demo/message/
gameevent.rs

1use 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        // game event definitions haven't been sent yet, ignore
27        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        // if self.event_type == GameEventType::Unknown {
191        //     panic!("unknown");
192        // }
193        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}