source2_demo/parser/demo/
runner.rs

1use crate::error::ParserError;
2use crate::parser::demo::DemoMessages;
3use crate::parser::Parser;
4use crate::proto::*;
5use crate::reader::*;
6use crate::Entity;
7use std::cmp::min;
8use std::mem;
9
10pub trait DemoRunner {
11    /// Moves to the end of replay. The last packet is [`CDemoFileInfo`].
12    fn run_to_end(&mut self) -> Result<(), ParserError>;
13
14    /// Moves to target tick.
15    fn run_to_tick(&mut self, target_tick: u32) -> Result<(), ParserError>;
16
17    /// Moves to target tick without calling observers and processing delta
18    /// packets.
19    fn jump_to_tick(&mut self, target_tick: u32) -> Result<(), ParserError>;
20}
21
22impl DemoRunner for Parser<'_> {
23    fn run_to_end(&mut self) -> Result<(), ParserError> {
24        self.prologue()?;
25
26        while let Some(message) = self.reader.read_next_message()? {
27            self.on_tick_start(message.tick)?;
28            self.on_demo_command(message.msg_type, message.buf.as_slice())?;
29        }
30        self.on_tick_end()?;
31
32        Ok(())
33    }
34
35    fn run_to_tick(&mut self, target_tick: u32) -> Result<(), ParserError> {
36        assert!(target_tick > self.context.tick || self.context.tick == u32::MAX);
37
38        self.prologue()?;
39
40        let target_tick = min(target_tick, self.last_tick);
41
42        while let Some(message) = self.reader.read_next_message()? {
43            self.on_tick_start(message.tick)?;
44            self.on_demo_command(message.msg_type, message.buf.as_slice())?;
45            if self.context.tick >= target_tick {
46                self.on_tick_end()?;
47                break;
48            }
49        }
50
51        Ok(())
52    }
53
54    fn jump_to_tick(&mut self, target_tick: u32) -> Result<(), ParserError> {
55        let fp_delta = if cfg!(feature = "deadlock") {
56            3600
57        } else {
58            1800
59        };
60
61        let target_tick = min(target_tick, self.last_tick);
62
63        if target_tick < self.context.tick {
64            self.context.last_full_packet_tick = u32::MAX;
65            self.context.tick = u32::MAX;
66            self.context.net_tick = u32::MAX;
67            self.reader.reset_to(16);
68
69            self.context.entities.entities_vec = vec![Entity::default(); 8192];
70
71            self.context.string_tables.tables.clear();
72            self.context.string_tables.name_to_table.clear();
73            self.context.game_events.list.clear();
74        }
75
76        self.prologue()?;
77
78        self.skip_deltas = true;
79        let observers = mem::take(&mut self.observers);
80
81        let mut first_fp_checked = self.context.last_full_packet_tick != u32::MAX;
82        let mut last_fp_checked = false;
83
84        while let Some(mut message) = self.reader.read_next_message()? {
85            self.context.previous_tick = self.context.tick;
86            self.context.tick = message.tick;
87
88            if message.msg_type == EDemoCommands::DemFullPacket {
89                self.context.last_full_packet_tick = self.context.tick;
90            }
91
92            let next_fp = self.context.last_full_packet_tick == u32::MAX
93                || self.context.last_full_packet_tick < target_tick
94                    && (target_tick - self.context.last_full_packet_tick) > fp_delta;
95
96            if message.msg_type == EDemoCommands::DemFullPacket {
97                if next_fp && first_fp_checked {
98                    message.msg_type = EDemoCommands::DemStringTables;
99                    message.buf = CDemoFullPacket::decode(message.buf.as_slice())?
100                        .string_table
101                        .unwrap()
102                        .encode_to_vec();
103                }
104
105                self.on_demo_command(message.msg_type, message.buf.as_slice())?;
106            }
107
108            if last_fp_checked {
109                self.on_demo_command(message.msg_type, message.buf.as_slice())?;
110            }
111
112            if message.msg_type == EDemoCommands::DemFullPacket && !first_fp_checked {
113                first_fp_checked = true;
114            }
115
116            if message.msg_type == EDemoCommands::DemFullPacket && !next_fp {
117                last_fp_checked = true;
118                self.skip_deltas = false;
119            }
120
121            if self.context.tick >= target_tick && first_fp_checked {
122                break;
123            }
124        }
125
126        self.skip_deltas = false;
127        self.observers = observers;
128
129        Ok(())
130    }
131}