tf_demo_parser/demo/parser/
state.rs

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