d2_stampede/
parser.rs

1use crate::class::{Class, ClassError, Classes};
2use crate::combat_log::{CombatLogEntry, CombatLogError};
3use crate::decoder::Decoder;
4use crate::entity::{Entities, Entity, EntityError, EntityEvents};
5use crate::field::{Encoder, Field, FieldModel, FieldProperties, FieldState, FieldType};
6use crate::field_reader::FieldReader;
7use crate::field_value::FieldValueError;
8use crate::proto::*;
9use crate::reader::Reader;
10use crate::serializer::Serializer;
11use crate::string_table::{StringTable, StringTableError, StringTableRow, StringTables};
12use crate::ObserverResult;
13use hashbrown::HashMap;
14use prettytable::{row, Table};
15use std::cell::RefCell;
16use std::cmp::min;
17use std::collections::VecDeque;
18use std::fmt::{Display, Formatter};
19use std::mem;
20use std::rc::Rc;
21
22macro_rules! try_observers {
23    ($self:ident, $method:ident ( $($arg:expr),* )) => {
24        $self.observers
25            .iter()
26            .try_for_each(|obs| obs.borrow_mut().$method($($arg),*))
27    };
28}
29
30/// Main error type
31#[derive(thiserror::Error, Debug)]
32pub enum ParserError {
33    #[error(transparent)]
34    ProtobufDecode(#[from] prost::DecodeError),
35
36    #[error(transparent)]
37    SnapDecompress(#[from] snap::Error),
38
39    #[error(transparent)]
40    StringTable(#[from] StringTableError),
41
42    #[error(transparent)]
43    Class(#[from] ClassError),
44
45    #[error(transparent)]
46    Entity(#[from] EntityError),
47
48    #[error(transparent)]
49    FieldValue(#[from] FieldValueError),
50
51    #[error(transparent)]
52    CombatLog(#[from] CombatLogError),
53
54    #[error(transparent)]
55    ObserverError(#[from] anyhow::Error),
56
57    #[error("Wrong CDemoFileInfo offset")]
58    ReplayEncodingError,
59
60    #[error("Supports only Source 2 replays")]
61    WrongMagic,
62}
63
64pub struct Parser<'a> {
65    reader: Reader<'a>,
66    field_reader: FieldReader,
67    observers: Vec<Rc<RefCell<dyn Observer + 'a>>>,
68
69    combat_log: VecDeque<CMsgDotaCombatLogEntry>,
70
71    prologue_completed: bool,
72    skip_deltas: bool,
73
74    replay_info: CDemoFileInfo,
75    last_tick: u32,
76    context: Context,
77}
78
79#[derive(Default)]
80pub(crate) struct Baselines {
81    baselines: HashMap<i32, Rc<Vec<u8>>>,
82    states: HashMap<i32, FieldState>,
83}
84
85impl Baselines {
86    pub(crate) fn add_baseline(&mut self, id: i32, baseline: Rc<Vec<u8>>) {
87        self.baselines.insert(id, baseline);
88    }
89}
90
91/// Current replay state.
92pub struct Context {
93    pub(crate) classes: Classes,
94    pub(crate) entities: Entities,
95    pub(crate) string_tables: StringTables,
96
97    pub(crate) tick: u32,
98    pub(crate) previous_tick: u32,
99
100    pub(crate) net_tick: u32,
101    pub(crate) game_build: u32,
102
103    baselines: Baselines,
104    serializers: HashMap<Box<str>, Rc<Serializer>>,
105    last_full_packet_tick: u32,
106}
107
108impl Default for Context {
109    fn default() -> Self {
110        Context {
111            classes: Classes::default(),
112            entities: Entities::default(),
113            string_tables: StringTables::default(),
114            tick: u32::MAX,
115            previous_tick: u32::MAX,
116            net_tick: u32::MAX,
117            game_build: 0,
118            baselines: Baselines::default(),
119            serializers: HashMap::default(),
120            last_full_packet_tick: u32::MAX,
121        }
122    }
123}
124
125impl Context {
126    pub fn classes(&self) -> &Classes {
127        &self.classes
128    }
129
130    pub fn entities(&self) -> &Entities {
131        &self.entities
132    }
133
134    pub fn string_tables(&self) -> &StringTables {
135        &self.string_tables
136    }
137
138    pub fn tick(&self) -> u32 {
139        self.tick
140    }
141
142    pub fn net_tick(&self) -> u32 {
143        self.net_tick
144    }
145
146    pub fn game_build(&self) -> u32 {
147        self.game_build
148    }
149}
150
151impl Display for Context {
152    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
153        let mut table = Table::new();
154        table.add_row(row!["Classes", self.classes.classes_vec.len()]);
155        table.add_row(row!["Entities", self.entities.entities_vec.len()]);
156        table.add_row(row!["String Tables", self.string_tables.tables.len()]);
157        table.add_row(row!["Tick", self.tick]);
158        table.add_row(row!["Net Tick", self.net_tick]);
159        table.add_row(row!["Game Build", format!("{:?}", self.game_build)]);
160        write!(f, "{}", table)
161    }
162}
163
164pub(crate) struct OuterMessage {
165    pub(crate) msg_type: EDemoCommands,
166    pub(crate) tick: u32,
167    pub(crate) buf: Vec<u8>,
168}
169
170impl<'a> Parser<'a> {
171    /// Creates new instance of parser and performs validation of replay file.
172    pub fn new(replay: &'a [u8]) -> Result<Self, ParserError> {
173        let mut reader = Reader::new(replay);
174
175        if replay.len() < 16 || reader.read_bytes(8) != b"PBDEMS2\0" {
176            return Err(ParserError::WrongMagic);
177        };
178
179        reader.read_bytes(8);
180
181        let replay_info = reader.read_replay_info()?;
182        let last_tick = replay_info.playback_ticks() as u32;
183
184        Ok(Parser {
185            reader,
186            field_reader: FieldReader::default(),
187            observers: Vec::default(),
188            combat_log: VecDeque::default(),
189            prologue_completed: false,
190            skip_deltas: false,
191
192            replay_info,
193            last_tick,
194
195            context: Context::default(),
196        })
197    }
198
199    /// Registers new observer and returns `Rc<RefCell<T>>` of it.
200    /// Observer struct must implement Observer and Default traits.
201    pub fn register_observer<T>(&mut self) -> Rc<RefCell<T>>
202    where
203        T: Observer + Default + 'a,
204    {
205        let rc = Rc::new(RefCell::new(T::default()));
206        self.observers.push(rc.clone());
207        rc.clone()
208    }
209
210    fn prologue(&mut self) -> Result<(), ParserError> {
211        if self.prologue_completed && self.context.tick != u32::MAX {
212            return Ok(());
213        }
214
215        while let Some(message) = self.reader.read_next_message()? {
216            if self.prologue_completed
217                && (message.msg_type == EDemoCommands::DemSendTables
218                    || message.msg_type == EDemoCommands::DemClassInfo)
219            {
220                continue;
221            }
222
223            self.on_demo_command(message.msg_type, message.buf.as_slice())?;
224
225            if message.msg_type == EDemoCommands::DemSyncTick {
226                self.prologue_completed = true;
227                break;
228            }
229        }
230
231        Ok(())
232    }
233
234    pub fn context(&self) -> &Context {
235        &self.context
236    }
237
238    pub fn replay_info(&self) -> &CDemoFileInfo {
239        &self.replay_info
240    }
241
242    /// Moves to the end of replay. Last packet is [`CDemoFileInfo`].
243    pub fn run_to_end(&mut self) -> Result<(), ParserError> {
244        self.prologue()?;
245
246        while let Some(message) = self.reader.read_next_message()? {
247            self.on_tick_start(message.tick)?;
248            self.on_demo_command(message.msg_type, message.buf.as_slice())?;
249            self.on_tick_end(message.tick)?;
250        }
251
252        try_observers!(self, epilogue(&self.context))?;
253        Ok(())
254    }
255
256    /// Moves to target tick without calling observers and processing delta
257    /// packets.
258    pub fn jump_to_tick(&mut self, mut target_tick: u32) -> Result<(), ParserError> {
259        target_tick = min(target_tick, self.last_tick);
260
261        if target_tick < self.context.tick {
262            self.context.last_full_packet_tick = u32::MAX;
263            self.context.tick = u32::MAX;
264            self.context.net_tick = u32::MAX;
265            self.reader.reset_to(16);
266
267            self.context.entities.entities_vec = vec![None; 8192];
268
269            self.context.string_tables.tables.clear();
270            self.context.string_tables.name_to_table.clear();
271        }
272
273        self.prologue()?;
274
275        self.skip_deltas = true;
276        let observers = mem::take(&mut self.observers);
277
278        let mut first_fp_checked = false;
279        let mut last_fp_checked = false;
280
281        while let Some(mut message) = self.reader.read_next_message()? {
282            self.context.previous_tick = self.context.tick;
283            self.context.tick = message.tick;
284
285            if message.msg_type == EDemoCommands::DemFullPacket {
286                self.context.last_full_packet_tick = self.context.tick;
287            }
288
289            let next_fp = self.context.last_full_packet_tick == u32::MAX
290                || (target_tick - self.context.last_full_packet_tick) > 1800;
291
292            if message.msg_type == EDemoCommands::DemFullPacket {
293                if next_fp && first_fp_checked {
294                    message.msg_type = EDemoCommands::DemStringTables;
295                    message.buf = CDemoFullPacket::decode(message.buf.as_slice())?
296                        .string_table
297                        .unwrap()
298                        .encode_to_vec();
299                }
300
301                self.on_demo_command(message.msg_type, message.buf.as_slice())?;
302            }
303
304            if last_fp_checked {
305                self.on_demo_command(message.msg_type, message.buf.as_slice())?;
306            }
307
308            if message.msg_type == EDemoCommands::DemFullPacket && !first_fp_checked {
309                first_fp_checked = true;
310            }
311
312            if message.msg_type == EDemoCommands::DemFullPacket && !next_fp {
313                last_fp_checked = true;
314                self.skip_deltas = false;
315            }
316
317            if self.context.tick >= target_tick && first_fp_checked {
318                break;
319            }
320        }
321
322        self.skip_deltas = false;
323        self.observers = observers;
324
325        Ok(())
326    }
327
328    /// Moves to target tick.
329    pub fn run_to_tick(&mut self, mut target_tick: u32) -> Result<(), ParserError> {
330        assert!(target_tick > self.context.tick || self.context.tick == u32::MAX);
331
332        self.prologue()?;
333
334        target_tick = min(target_tick, self.last_tick);
335
336        while let Some(message) = self.reader.read_next_message()? {
337            self.on_tick_start(message.tick)?;
338            self.on_demo_command(message.msg_type, message.buf.as_slice())?;
339            self.on_tick_end(message.tick)?;
340            if self.context.tick >= target_tick {
341                break;
342            }
343        }
344
345        Ok(())
346    }
347
348    fn on_demo_command(&mut self, msg_type: EDemoCommands, msg: &[u8]) -> Result<(), ParserError> {
349        match msg_type {
350            EDemoCommands::DemSendTables => self.dem_send_tables(msg)?,
351            EDemoCommands::DemClassInfo => self.dem_class_info(msg)?,
352            EDemoCommands::DemPacket | EDemoCommands::DemSignonPacket => self.dem_packet(msg)?,
353            EDemoCommands::DemFullPacket => self.dem_full_packet(msg)?,
354            EDemoCommands::DemStringTables => self.dem_string_tables(msg)?,
355            _ => {}
356        };
357
358        try_observers!(self, on_demo_command(&self.context, msg_type, msg))?;
359        Ok(())
360    }
361
362    fn on_net_message(&mut self, msg_type: NetMessages, msg: &[u8]) -> Result<(), ParserError> {
363        if msg_type == NetMessages::NetTick {
364            self.context.net_tick = CNetMsgTick::decode(msg)?.tick();
365        }
366
367        try_observers!(self, on_net_message(&self.context, msg_type, msg))?;
368        Ok(())
369    }
370
371    fn on_svc_message(&mut self, msg_type: SvcMessages, msg: &[u8]) -> Result<(), ParserError> {
372        match msg_type {
373            SvcMessages::SvcServerInfo => self.server_info(msg)?,
374            SvcMessages::SvcCreateStringTable => self.create_string_table(msg)?,
375            SvcMessages::SvcUpdateStringTable => self.update_string_table(msg)?,
376            SvcMessages::SvcPacketEntities => self.packet_entities(msg)?,
377            _ => {}
378        }
379
380        try_observers!(self, on_svc_message(&self.context, msg_type, msg))?;
381        Ok(())
382    }
383
384    fn on_base_user_message(
385        &mut self,
386        msg_type: EBaseUserMessages,
387        msg: &[u8],
388    ) -> Result<(), ParserError> {
389        try_observers!(self, on_base_user_message(&self.context, msg_type, msg))?;
390        Ok(())
391    }
392
393    fn on_base_game_event(
394        &mut self,
395        msg_type: EBaseGameEvents,
396        msg: &[u8],
397    ) -> Result<(), ParserError> {
398        try_observers!(self, on_base_game_event(&self.context, msg_type, msg))?;
399        Ok(())
400    }
401
402    fn on_dota_user_message(
403        &mut self,
404        msg_type: EDotaUserMessages,
405        msg: &[u8],
406    ) -> Result<(), ParserError> {
407        if msg_type == EDotaUserMessages::DotaUmCombatLogDataHltv {
408            let entry = CMsgDotaCombatLogEntry::decode(msg)?;
409            self.combat_log.push_back(entry);
410        }
411
412        try_observers!(self, on_dota_user_message(&self.context, msg_type, msg))?;
413        Ok(())
414    }
415
416    pub(crate) fn on_tick_start(&mut self, msg_tick: u32) -> Result<(), ParserError> {
417        self.context.previous_tick = self.context.tick;
418        self.context.tick = msg_tick;
419
420        if self.context.previous_tick == msg_tick {
421            return Ok(());
422        }
423
424        try_observers!(self, on_tick_start(&self.context))?;
425        Ok(())
426    }
427
428    pub(crate) fn on_tick_end(&mut self, msg_tick: u32) -> Result<(), ParserError> {
429        if self.context.previous_tick == msg_tick {
430            return Ok(());
431        }
432
433        if let Ok(names) = self.context.string_tables.get_by_name("CombatLogNames") {
434            while let Some(log) = self.combat_log.pop_front() {
435                self.on_combat_log(&CombatLogEntry { names, log })?;
436            }
437        }
438
439        try_observers!(self, on_tick_end(&self.context))?;
440        Ok(())
441    }
442
443    pub(crate) fn on_combat_log(&self, entry: &CombatLogEntry) -> Result<(), ParserError> {
444        try_observers!(self, on_combat_log(&self.context, entry))?;
445        Ok(())
446    }
447
448    fn dem_send_tables(&mut self, msg: &[u8]) -> Result<(), ParserError> {
449        let send_tables = CDemoSendTables::decode(msg)?;
450        let mut reader = Reader::new(send_tables.data());
451        let amount = reader.read_var_u32();
452        let buf = reader.read_bytes(amount);
453
454        let fs = CSvcMsgFlattenedSerializer::decode(buf.as_slice())?;
455
456        let resolve = |p: Option<i32>| -> Box<str> {
457            if let Some(i) = p {
458                return fs.symbols[i as usize].clone().into();
459            }
460            "".into()
461        };
462
463        let mut fields: Vec<Rc<Field>> = vec![];
464        let mut field_types: HashMap<Box<str>, Rc<FieldType>> = HashMap::default();
465
466        for s in fs.serializers.iter() {
467            let serializer_name = fs.symbols[s.serializer_name_sym() as usize].clone();
468            let mut serializer = Serializer::default();
469
470            for i in s.fields_index.iter().map(|x| *x as usize) {
471                let current_field = &fs.fields[i];
472                let field_serializer_name = resolve(current_field.field_serializer_name_sym);
473
474                if i >= fields.len() {
475                    let var_type_str = resolve(current_field.var_type_sym);
476                    let var_name = resolve(current_field.var_name_sym);
477
478                    let current_field_serializer = self
479                        .context
480                        .serializers
481                        .get(&field_serializer_name)
482                        .cloned();
483
484                    let field_type = field_types
485                        .entry(var_type_str.clone())
486                        .or_insert_with(|| FieldType::new(var_type_str.clone().as_ref()).into())
487                        .clone();
488
489                    let properties = FieldProperties {
490                        encoder: match var_name.as_ref() {
491                            "m_flSimulationTime" | "m_flAnimTime" => Some(Encoder::SimTime),
492                            "m_flRuneTime" => Some(Encoder::RuneTime),
493                            _ => Encoder::from_str(&resolve(current_field.var_encoder_sym)),
494                        },
495                        encoder_flags: current_field.encode_flags(),
496                        bit_count: current_field.bit_count(),
497                        low_value: current_field.low_value(),
498                        high_value: current_field.high_value(),
499                    };
500
501                    let model = if let Some(serializer) = current_field_serializer {
502                        if field_type.pointer {
503                            FieldModel::FixedTable(serializer)
504                        } else {
505                            FieldModel::VariableTable(serializer)
506                        }
507                    } else if field_type.count.is_some_and(|x| x > 0)
508                        && field_type.base.as_ref() != "char"
509                    {
510                        FieldModel::FixedArray
511                    } else if field_type.base.as_ref() == "CUtlVector"
512                        || field_type.base.as_ref() == "CNetworkUtlVectorBase"
513                    {
514                        FieldModel::VariableArray(Decoder::from_field(
515                            field_type.generic.as_ref().unwrap(),
516                            properties,
517                        ))
518                    } else {
519                        FieldModel::Simple
520                    };
521
522                    let decoder = match model {
523                        FieldModel::Simple | FieldModel::FixedArray => {
524                            Decoder::from_field(&field_type, properties)
525                        }
526                        FieldModel::VariableArray(_) => Decoder::Unsigned32,
527                        FieldModel::FixedTable(_) => Decoder::Boolean,
528                        FieldModel::VariableTable(_) => Decoder::Unsigned32,
529                    };
530
531                    let field = Field {
532                        var_name,
533                        field_type,
534                        model,
535
536                        decoder,
537                    };
538                    fields.push(field.into());
539                }
540                serializer.fields.push(fields[i].clone());
541            }
542            self.context
543                .serializers
544                .insert(serializer_name.into(), serializer.into());
545        }
546        Ok(())
547    }
548
549    fn dem_class_info(&mut self, msg: &[u8]) -> Result<(), ParserError> {
550        let info = CDemoClassInfo::decode(msg)?;
551        for class in info.classes {
552            let class_id = class.class_id();
553            let network_name = class.network_name();
554
555            let serializer = self.context.serializers[network_name].clone();
556
557            let class = Rc::new(Class::new(class_id, network_name.into(), serializer));
558
559            self.context.classes.classes_vec.push(class.clone());
560            self.context
561                .classes
562                .classes_by_name
563                .insert(network_name.into(), class);
564        }
565        Ok(())
566    }
567
568    fn dem_packet(&mut self, msg: &[u8]) -> Result<(), ParserError> {
569        let packet = CDemoPacket::decode(msg)?;
570        let mut packet_reader = Reader::new(packet.data());
571        while packet_reader.bytes_remaining() != 0 {
572            let msg_type = packet_reader.read_ubit_var() as i32;
573            let size = packet_reader.read_var_u32();
574            let packet_buf = packet_reader.read_bytes(size);
575
576            if let Ok(msg) = EDotaUserMessages::try_from(msg_type) {
577                self.on_dota_user_message(msg, &packet_buf)?;
578            } else if let Ok(msg) = SvcMessages::try_from(msg_type) {
579                self.on_svc_message(msg, &packet_buf)?;
580            } else if let Ok(msg) = EBaseUserMessages::try_from(msg_type) {
581                self.on_base_user_message(msg, &packet_buf)?;
582            } else if let Ok(msg) = EBaseGameEvents::try_from(msg_type) {
583                self.on_base_game_event(msg, &packet_buf)?;
584            } else if let Ok(msg) = NetMessages::try_from(msg_type) {
585                self.on_net_message(msg, &packet_buf)?;
586            }
587        }
588
589        Ok(())
590    }
591
592    fn dem_full_packet(&mut self, msg: &[u8]) -> Result<(), ParserError> {
593        let packet = CDemoFullPacket::decode(msg)?;
594
595        if self.context.last_full_packet_tick == u32::MAX || self.skip_deltas {
596            self.on_demo_command(
597                EDemoCommands::DemStringTables,
598                &packet.string_table.unwrap().encode_to_vec(),
599            )?;
600
601            self.on_demo_command(
602                EDemoCommands::DemPacket,
603                &packet.packet.unwrap().encode_to_vec(),
604            )?;
605        }
606
607        self.context.last_full_packet_tick = self.context.tick;
608
609        Ok(())
610    }
611
612    fn dem_string_tables(&mut self, msg: &[u8]) -> Result<(), ParserError> {
613        let cmd = CDemoStringTables::decode(msg)?;
614        for table in cmd.tables.iter() {
615            let x = self
616                .context
617                .string_tables
618                .get_by_name_mut(table.table_name())?;
619            if table.items.len() < x.items.len() {
620                return Ok(());
621            }
622            x.items
623                .resize_with(table.items.len(), StringTableRow::default);
624            for (i, item) in table.items.iter().enumerate() {
625                x.items[i].index = i as i32;
626                x.items[i].key = item.str().to_string();
627                x.items[i].value = Rc::new(item.data().to_vec()).into();
628                if table.table_name() == "instancebaseline" {
629                    self.context.baselines.add_baseline(
630                        item.str().parse().unwrap(),
631                        x.items[i].value.as_ref().unwrap().clone(),
632                    );
633                }
634            }
635        }
636
637        Ok(())
638    }
639
640    fn packet_entities(&mut self, msg: &[u8]) -> Result<(), ParserError> {
641        let packet = CSvcMsgPacketEntities::decode(msg)?;
642        let mut reader = Reader::new(packet.entity_data());
643
644        let mut index = usize::MAX;
645
646        for _ in 0..packet.updated_entries() {
647            index = index.wrapping_add((reader.read_ubit_var() + 1) as usize);
648
649            let cmd = reader.read_bits(2);
650            if cmd == 1 {
651                continue;
652            }
653
654            match EntityEvents::from_cmd(cmd) {
655                EntityEvents::Created => {
656                    let class_id = reader.read_bits(self.context.classes.class_id_size) as i32;
657                    let serial = reader.read_bits(17);
658                    let _ = reader.read_var_u32();
659
660                    let class = self.context.classes.get_by_id_rc(class_id as usize).clone();
661
662                    let entity_baseline = self
663                        .context
664                        .baselines
665                        .states
666                        .entry(class_id)
667                        .or_insert_with(|| {
668                            let mut state = FieldState::default();
669                            self.field_reader.read_fields(
670                                &mut Reader::new(&self.context.baselines.baselines[&class_id]),
671                                &class.serializer,
672                                &mut state,
673                            );
674                            state
675                        })
676                        .clone();
677
678                    self.context.entities.entities_vec[index] = Some(Entity::new(
679                        index as u32,
680                        serial,
681                        class.clone(),
682                        entity_baseline,
683                    ));
684
685                    let entity = self.context.entities.entities_vec[index].as_mut().unwrap();
686
687                    self.field_reader.read_fields(
688                        &mut reader,
689                        &entity.class.serializer,
690                        &mut entity.state,
691                    );
692
693                    try_observers!(
694                        self,
695                        on_entity(
696                            &self.context,
697                            EntityEvents::Created,
698                            self.context.entities.entities_vec[index].as_ref().unwrap()
699                        )
700                    )?;
701                }
702                EntityEvents::Updated => {
703                    let entity = self.context.entities.entities_vec[index].as_mut().unwrap();
704
705                    self.field_reader.read_fields(
706                        &mut reader,
707                        &entity.class.serializer,
708                        &mut entity.state,
709                    );
710
711                    try_observers!(
712                        self,
713                        on_entity(
714                            &self.context,
715                            EntityEvents::Updated,
716                            self.context.entities.entities_vec[index].as_ref().unwrap()
717                        )
718                    )?;
719                }
720                EntityEvents::Deleted => {
721                    if let Some(entity) = self.context.entities.entities_vec[index].as_ref() {
722                        try_observers!(
723                            self,
724                            on_entity(&self.context, EntityEvents::Deleted, entity)
725                        )?;
726                    }
727                    self.context.entities.entities_vec[index] = None;
728                }
729            }
730        }
731
732        Ok(())
733    }
734
735    fn update_string_table(&mut self, msg: &[u8]) -> Result<(), ParserError> {
736        let table_msg = CSvcMsgUpdateStringTable::decode(msg)?;
737        let table = self
738            .context
739            .string_tables
740            .tables
741            .get_mut(table_msg.table_id() as usize)
742            .unwrap();
743
744        table.parse(
745            &mut self.context.baselines,
746            table_msg.string_data(),
747            table_msg.num_changed_entries(),
748        )?;
749
750        Ok(())
751    }
752
753    fn create_string_table(&mut self, msg: &[u8]) -> Result<(), ParserError> {
754        let table_msg = CSvcMsgCreateStringTable::decode(msg)?;
755
756        let mut table = StringTable {
757            index: self.context.string_tables.tables.len() as i32,
758            name: table_msg.name().into(),
759            items: vec![],
760            user_data_fixed_size: table_msg.user_data_fixed_size(),
761            user_data_size: table_msg.user_data_size(),
762            flags: table_msg.flags() as u32,
763            var_int_bit_counts: table_msg.using_varint_bitcounts(),
764            keys: RefCell::new(vec![String::default(); 32]),
765        };
766
767        let buf = if table_msg.data_compressed() {
768            let mut decoder = snap::raw::Decoder::new();
769            decoder.decompress_vec(table_msg.string_data())?
770        } else {
771            table_msg.string_data().into()
772        };
773
774        table.parse(
775            &mut self.context.baselines,
776            buf.as_slice(),
777            table_msg.num_entries(),
778        )?;
779
780        self.context
781            .string_tables
782            .name_to_table
783            .insert(table.name().into(), table.index as usize);
784        self.context.string_tables.tables.push(table);
785
786        Ok(())
787    }
788
789    fn server_info(&mut self, msg: &[u8]) -> Result<(), ParserError> {
790        let info = CSvcMsgServerInfo::decode(msg)?;
791        self.context.classes.class_id_size = (f64::log2(info.max_classes() as f64) + 1.0) as u32;
792
793        let game_dir = info.game_dir();
794        if let Some(start) = game_dir.find("dota_v") {
795            let start = start + "dota_v".len();
796            if let Some(end) = game_dir[start..].find('/') {
797                let build_str = &game_dir[start..start + end];
798                let build = build_str.parse::<u32>().unwrap();
799                self.context.game_build = build;
800            }
801        }
802        Ok(())
803    }
804}
805
806/// A trait defining methods for handling game events and protobuf messages. Can
807/// be attached to [`Parser`] instance with [`Parser::register_observer`]
808/// method.
809#[allow(unused_variables)]
810pub trait Observer {
811    fn on_demo_command(
812        &mut self,
813        ctx: &Context,
814        msg_type: EDemoCommands,
815        msg: &[u8],
816    ) -> ObserverResult {
817        Ok(())
818    }
819
820    fn on_net_message(
821        &mut self,
822        ctx: &Context,
823        msg_type: NetMessages,
824        msg: &[u8],
825    ) -> ObserverResult {
826        Ok(())
827    }
828
829    fn on_svc_message(
830        &mut self,
831        ctx: &Context,
832        msg_type: SvcMessages,
833        msg: &[u8],
834    ) -> ObserverResult {
835        Ok(())
836    }
837
838    fn on_base_user_message(
839        &mut self,
840        ctx: &Context,
841        msg_type: EBaseUserMessages,
842        msg: &[u8],
843    ) -> ObserverResult {
844        Ok(())
845    }
846
847    fn on_base_game_event(
848        &mut self,
849        ctx: &Context,
850        msg_type: EBaseGameEvents,
851        msg: &[u8],
852    ) -> ObserverResult {
853        Ok(())
854    }
855
856    fn on_dota_user_message(
857        &mut self,
858        ctx: &Context,
859        msg_type: EDotaUserMessages,
860        msg: &[u8],
861    ) -> ObserverResult {
862        Ok(())
863    }
864
865    fn on_tick_start(&mut self, ctx: &Context) -> ObserverResult {
866        Ok(())
867    }
868
869    fn on_tick_end(&mut self, ctx: &Context) -> ObserverResult {
870        Ok(())
871    }
872
873    fn on_entity(&mut self, ctx: &Context, event: EntityEvents, entity: &Entity) -> ObserverResult {
874        Ok(())
875    }
876
877    fn on_combat_log(&mut self, ctx: &Context, cle: &CombatLogEntry) -> ObserverResult {
878        Ok(())
879    }
880
881    fn epilogue(&mut self, ctx: &Context) -> ObserverResult {
882        Ok(())
883    }
884}