tf_demo_parser/demo/parser/
state.rs1use fnv::FnvHashMap;
2use std::borrow::Cow;
3use std::collections::HashMap;
4
5use crate::demo::gamevent::GameEventDefinition;
6
7use crate::demo::message::packetentities::{
8 BaselineIndex, EntityId, PacketEntitiesMessage, PacketEntity, UpdateType,
9};
10use crate::demo::message::stringtable::StringTableMeta;
11use crate::demo::message::{Message, MessageType, log_base2};
12use crate::demo::packet::datatable::{
13 ClassId, ParseSendTable, SendTable, SendTableName, ServerClass,
14};
15use crate::demo::packet::stringtable::StringTableEntry;
16
17use crate::demo::data::DemoTick;
18use crate::demo::sendprop::{SendProp, SendPropIdentifier};
19use crate::nullhasher::NullHasherBuilder;
20use crate::{Result, Stream};
21use serde::{Deserialize, Serialize};
22use std::cell::RefCell;
23#[cfg(feature = "trace")]
24use tracing::warn;
25
26#[derive(Default, Clone, Serialize, Deserialize)]
27pub struct DemoMeta {
28 pub version: u16,
29 pub game: String,
30 pub interval_per_tick: f32,
31}
32
33#[derive(Clone)]
34pub struct ParserState {
35 pub static_baselines: HashMap<ClassId, StaticBaseline, NullHasherBuilder>,
36 pub parsed_static_baselines: RefCell<HashMap<ClassId, Vec<SendProp>, NullHasherBuilder>>,
37 pub event_definitions: Vec<GameEventDefinition>,
38 pub string_tables: Vec<StringTableMeta>,
39 pub entity_classes: HashMap<EntityId, ClassId, NullHasherBuilder>,
40 pub send_tables: Vec<SendTable>,
42 pub server_classes: Vec<ServerClass>,
43 pub server_class_bits: usize,
44 pub instance_baselines: [Baseline; 2],
45 pub demo_meta: DemoMeta,
46 analyser_handles: fn(message_type: MessageType) -> bool,
47 handle_entities: bool,
48 parse_all: bool,
49 pub protocol_version: u32,
50}
51
52#[derive(Clone)]
53pub struct StaticBaseline {
54 pub class_id: ClassId,
55 pub raw: Stream<'static>,
56}
57
58impl StaticBaseline {
59 fn new(class_id: ClassId, raw: Stream<'static>) -> Self {
60 StaticBaseline { class_id, raw }
61 }
62
63 pub fn parse(&self, send_table: &SendTable) -> Result<Vec<SendProp>> {
64 let mut props = Vec::with_capacity(8);
65 PacketEntitiesMessage::read_update(
66 &mut self.raw.clone(),
67 send_table,
68 &mut props,
69 0u32.into(),
70 )?;
71 Ok(props)
72 }
73}
74
75impl ParserState {
76 pub fn new(
77 protocol_version: u32,
78 analyser_handles: fn(message_type: MessageType) -> bool,
79 parse_all: bool,
80 ) -> Self {
81 ParserState {
82 static_baselines: HashMap::with_hasher(NullHasherBuilder),
83 parsed_static_baselines: RefCell::new(HashMap::with_hasher(NullHasherBuilder)),
84 event_definitions: Vec::new(),
85 string_tables: Vec::new(),
86 entity_classes: HashMap::with_hasher(NullHasherBuilder),
87 send_tables: Vec::new(),
88 server_classes: Vec::new(),
89 server_class_bits: 0,
90 instance_baselines: [Baseline::default(), Baseline::default()],
91 demo_meta: DemoMeta::default(),
92 analyser_handles,
93 handle_entities: analyser_handles(MessageType::PacketEntities) || parse_all,
94 parse_all,
95 protocol_version,
96 }
97 }
98
99 pub fn set_server_classes(&mut self, server_classes: Vec<ServerClass>) {
100 self.server_class_bits = log_base2(server_classes.len()) as usize + 1;
101 self.server_classes = server_classes;
102 }
103
104 pub fn get_static_baseline(
105 &self,
106 class_id: ClassId,
107 send_table: &SendTable,
108 ) -> Result<Vec<SendProp>> {
109 match self.static_baselines.get(&class_id) {
110 Some(static_baseline) => static_baseline.parse(send_table),
111 None => {
112 #[cfg(feature = "trace")]
113 warn!(
114 class_id = display(class_id),
115 "class without static baseline"
116 );
117 Ok(Vec::new())
118 }
119 }
120 }
139
140 fn get_instance_baseline(&self, index: BaselineIndex) -> &Baseline {
141 match index {
142 BaselineIndex::First => &self.instance_baselines[0],
143 BaselineIndex::Second => &self.instance_baselines[1],
144 }
145 }
146
147 fn get_instance_baseline_mut(&mut self, index: BaselineIndex) -> &mut Baseline {
148 match index {
149 BaselineIndex::First => &mut self.instance_baselines[0],
150 BaselineIndex::Second => &mut self.instance_baselines[1],
151 }
152 }
153
154 pub fn get_baseline(
155 &self,
156 baseline_index: BaselineIndex,
157 entity_index: EntityId,
158 class_id: ClassId,
159 send_table: &SendTable,
160 is_delta: bool,
161 ) -> Result<Cow<'_, [SendProp]>> {
162 match self.get_instance_baseline(baseline_index).get(entity_index) {
163 Some(baseline) if baseline.server_class == class_id && is_delta => {
164 Ok(Cow::Borrowed(&baseline.props))
165 }
166 _ => match self.static_baselines.get(&class_id) {
167 Some(_static_baseline) => {
168 Ok(Cow::Owned(self.get_static_baseline(class_id, send_table)?))
169 }
170 None => {
171 #[cfg(feature = "trace")]
172 warn!(
173 class_id = display(class_id),
174 "class without static baseline"
175 );
176 Ok(Cow::Owned(Vec::new()))
177 }
178 },
179 }
180 }
181
182 pub fn handle_data_table(
183 &mut self,
184 parse_tables: &[ParseSendTable],
185 server_classes: Vec<ServerClass>,
186 ) -> Result<()> {
187 if self.handle_entities {
188 let mut send_tables: FnvHashMap<SendTableName, SendTable> = parse_tables
189 .iter()
190 .map(|parse_table| {
191 let flat = parse_table.flatten_props(parse_tables);
192 Ok((
193 parse_table.name.clone(),
194 SendTable {
195 name: parse_table.name.clone(),
196 needs_decoder: parse_table.needs_decoder,
197 flattened_props: flat?,
198 },
199 ))
200 })
201 .collect::<Result<_>>()?;
202
203 self.set_server_classes(server_classes);
204
205 self.send_tables.reserve(self.server_classes.len());
206
207 for class in self.server_classes.iter() {
208 if let Some(table) = send_tables.remove(&class.data_table) {
209 self.send_tables.push(table);
210 } else {
211 #[cfg(feature = "trace")]
212 warn!(class = debug(class), "class without table");
213 }
214 }
215 }
216
217 Ok(())
218 }
219
220 pub fn handle_string_table_meta(&mut self, table: StringTableMeta) {
221 self.string_tables.push(table);
222 }
223
224 pub fn should_parse_message(&self, message_type: MessageType) -> bool {
225 self.parse_all
226 || if message_type == MessageType::PacketEntities {
227 self.handle_entities
228 } else {
229 Self::does_handle(message_type) || (self.analyser_handles)(message_type)
230 }
231 }
232
233 pub fn does_handle(message_type: MessageType) -> bool {
234 matches!(
235 message_type,
236 MessageType::ServerInfo
237 | MessageType::NetTick
238 | MessageType::GameEventList
239 | MessageType::CreateStringTable
240 | MessageType::PacketEntities
241 | MessageType::UpdateStringTable
242 )
243 }
244
245 pub fn handle_message(&mut self, message: Message, _tick: DemoTick) {
246 match message {
247 Message::ServerInfo(message) => {
248 self.demo_meta.version = message.version;
249 self.demo_meta.game = message.game;
250 self.demo_meta.interval_per_tick = message.interval_per_tick;
251 }
252 Message::GameEventList(message) => {
253 self.event_definitions = message.event_list;
254 }
255 Message::PacketEntities(ent_message) => {
256 for removed in ent_message.removed_entities.iter() {
257 self.entity_classes.remove(removed);
258 }
259
260 for entity in ent_message.entities.iter() {
261 if entity.update_type == UpdateType::Delete {
262 self.entity_classes.remove(&entity.entity_index);
263 }
264 self.entity_classes
265 .insert(entity.entity_index, entity.server_class);
266 }
267
268 if ent_message.updated_base_line {
269 let old_index = ent_message.base_line;
270 let new_index = old_index.other();
271 let [baseline1, baseline2] = &mut self.instance_baselines;
272 if old_index == BaselineIndex::First {
273 baseline2.copy_from(baseline1);
274 } else {
275 baseline1.copy_from(baseline2);
276 }
277
278 for entity in ent_message.entities {
279 if entity.update_type == UpdateType::Enter {
280 let updated_baseline = match self
281 .get_instance_baseline(old_index)
282 .get(entity.entity_index)
283 {
284 Some(baseline_entity)
285 if baseline_entity.server_class == entity.server_class
286 && ent_message.delta.is_some() =>
287 {
288 let mut updated_baseline = baseline_entity.clone();
289 updated_baseline.apply_update(&entity.props);
290 updated_baseline
291 }
292 _ => entity.into(),
293 };
294 self.get_instance_baseline_mut(new_index)
295 .set(updated_baseline);
296 }
297 }
298 }
299 }
300 _ => {}
301 }
302 }
303
304 pub fn handle_string_entry(&mut self, table: &str, _index: usize, entry: &StringTableEntry) {
305 if table == "instancebaseline"
306 && let (Some(extra), Ok(class_id)) = (&entry.extra_data, entry.text().parse()) {
307 let baseline = StaticBaseline::new(class_id, extra.data.to_owned());
308 self.static_baselines.insert(class_id, baseline);
309 self.parsed_static_baselines.borrow_mut().remove(&class_id);
310 }
311 }
312
313 pub fn index_for_prop(&self, class: ClassId, prop: SendPropIdentifier) -> Option<u32> {
314 let send_table = self.send_tables.get(usize::from(class))?;
315 send_table
316 .flattened_props
317 .iter()
318 .enumerate()
319 .find(|(_i, def)| def.identifier == prop)
320 .map(|(index, _)| index as u32)
321 }
322}
323
324#[derive(Clone)]
325pub struct Baseline {
326 instances: Vec<Option<BaselineEntity>>,
327}
328
329impl Default for Baseline {
330 fn default() -> Self {
331 Baseline {
332 instances: vec![None; 2048],
333 }
334 }
335}
336
337impl Baseline {
338 pub fn get(&self, index: EntityId) -> Option<&BaselineEntity> {
339 self.instances
340 .get(usize::from(index))
341 .and_then(|opt| opt.as_ref())
342 }
343
344 fn set(&mut self, entity: BaselineEntity) {
345 if let Some(instance) = self.instances.get_mut(usize::from(entity.entity_id)) {
346 *instance = Some(entity);
347 }
348 }
349
350 pub fn keys(&self) -> impl Iterator<Item = EntityId> + '_ {
351 self.instances
352 .iter()
353 .filter_map(|entity| entity.as_ref().map(|entity| entity.entity_id))
354 }
355
356 pub fn into_values(self) -> impl Iterator<Item = PacketEntity> {
357 self.instances
358 .into_iter()
359 .filter_map(|entity| entity.map(|entity| entity.into()))
360 }
361
362 pub fn contains(&self, index: EntityId) -> bool {
363 self.get(index).is_some()
364 }
365
366 fn copy_from(&mut self, other: &Baseline) {
367 for (ent, other_ent) in self.instances.iter_mut().zip(other.instances.iter()) {
368 match (ent, other_ent) {
369 (ent, Some(other_ent)) => *ent = Some(other_ent.clone()),
370 (ent, None) => {
371 *ent = None;
372 }
373 }
374 }
375 }
376}
377
378#[derive(Clone)]
379pub struct BaselineEntity {
380 pub entity_id: EntityId,
381 pub server_class: ClassId,
382 pub props: Vec<SendProp>,
383 pub serial: u32,
384}
385
386impl BaselineEntity {
387 fn mut_prop_by_identifier(&mut self, index: &SendPropIdentifier) -> Option<&mut SendProp> {
388 self.props.iter_mut().find(|prop| prop.identifier == *index)
389 }
390
391 pub fn apply_update(&mut self, props: &[SendProp]) {
392 for prop in props {
393 match self.mut_prop_by_identifier(&prop.identifier) {
394 Some(existing_prop) => existing_prop.value = prop.value.clone(),
395 None => self.props.push(prop.clone()),
396 }
397 }
398 }
399}
400
401impl From<PacketEntity> for BaselineEntity {
402 fn from(entity: PacketEntity) -> Self {
403 BaselineEntity {
404 entity_id: entity.entity_index,
405 server_class: entity.server_class,
406 props: entity.props,
407 serial: entity.serial_number,
408 }
409 }
410}
411
412impl From<BaselineEntity> for PacketEntity {
413 fn from(baseline: BaselineEntity) -> Self {
414 PacketEntity {
415 server_class: baseline.server_class,
416 entity_index: baseline.entity_id,
417 props: baseline.props,
418 in_pvs: false,
419 update_type: UpdateType::Enter,
420 serial_number: baseline.serial,
421 delay: None,
422 delta: None,
423 baseline_index: BaselineIndex::First,
424 }
425 }
426}