Skip to main content

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<'a, R> DemoRunner for Parser<'a, R>
23where
24    R: BitsReader + MessageReader,
25{
26    fn run_to_end(&mut self) -> Result<(), ParserError> {
27        self.prologue()?;
28
29        while let Some(message) = self.reader.read_next_message()? {
30            self.on_tick_start(message.tick)?;
31            self.on_demo_command(message.msg_type, message.buf.as_slice())?;
32        }
33        self.on_tick_end()?;
34
35        Ok(())
36    }
37
38    fn run_to_tick(&mut self, target_tick: u32) -> Result<(), ParserError> {
39        assert!(target_tick > self.context.tick || self.context.tick == u32::MAX);
40
41        self.prologue()?;
42
43        let target_tick = min(target_tick, self.last_tick);
44
45        while let Some(message) = self.reader.read_next_message()? {
46            self.on_tick_start(message.tick)?;
47            self.on_demo_command(message.msg_type, message.buf.as_slice())?;
48            if self.context.tick >= target_tick {
49                self.on_tick_end()?;
50                break;
51            }
52        }
53
54        Ok(())
55    }
56
57    fn jump_to_tick(&mut self, target_tick: u32) -> Result<(), ParserError> {
58        let fp_delta = if cfg!(feature = "deadlock") {
59            3600
60        } else {
61            1800
62        };
63
64        let target_tick = min(target_tick, self.last_tick);
65
66        if target_tick < self.context.tick {
67            self.context.last_full_packet_tick = u32::MAX;
68            self.context.tick = u32::MAX;
69            self.context.net_tick = u32::MAX;
70            self.reader.seek(16);
71
72            self.context.entities.entities_vec = vec![Entity::default(); 8192];
73
74            self.context.string_tables.tables.clear();
75            self.context.string_tables.name_to_table.clear();
76            self.context.game_events.list.clear();
77        }
78
79        self.prologue()?;
80
81        self.skip_deltas = true;
82        let observers = mem::take(&mut self.observers);
83
84        let mut first_fp_checked = self.context.last_full_packet_tick != u32::MAX;
85        let mut last_fp_checked = false;
86
87        while let Some(mut message) = self.reader.read_next_message()? {
88            self.context.previous_tick = self.context.tick;
89            self.context.tick = message.tick;
90
91            if message.msg_type == EDemoCommands::DemFullPacket {
92                self.context.last_full_packet_tick = self.context.tick;
93            }
94
95            let next_fp = self.context.last_full_packet_tick == u32::MAX
96                || self.context.last_full_packet_tick < target_tick
97                    && (target_tick - self.context.last_full_packet_tick) > fp_delta;
98
99            if message.msg_type == EDemoCommands::DemFullPacket {
100                if next_fp && first_fp_checked {
101                    message.msg_type = EDemoCommands::DemStringTables;
102                    message.buf = CDemoFullPacket::decode(message.buf.as_slice())?
103                        .string_table
104                        .unwrap()
105                        .encode_to_vec();
106                }
107
108                self.on_demo_command(message.msg_type, message.buf.as_slice())?;
109            }
110
111            if last_fp_checked {
112                self.on_demo_command(message.msg_type, message.buf.as_slice())?;
113            }
114
115            if message.msg_type == EDemoCommands::DemFullPacket && !first_fp_checked {
116                first_fp_checked = true;
117            }
118
119            if message.msg_type == EDemoCommands::DemFullPacket && !next_fp {
120                last_fp_checked = true;
121                self.skip_deltas = false;
122            }
123
124            if self.context.tick >= target_tick && first_fp_checked {
125                break;
126            }
127        }
128
129        self.skip_deltas = false;
130        self.observers = observers;
131
132        Ok(())
133    }
134}