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};
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 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 }
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}