Skip to main content

source2_demo/parser/demo/writer/
run.rs

1use super::*;
2use crate::parser::demo::DemoCommands;
3use crate::proto::{
4    CDemoClassInfo, CDemoFullPacket, CDemoPacket, CDemoSendTables, CDemoStringTables,
5    EDemoCommands, Message,
6};
7use crate::reader::{BitsReader, MessageReader};
8use std::io::{Seek, Write};
9
10impl<'a, R, W> DemoWriter<'a, R, W>
11where
12    R: BitsReader + MessageReader,
13    W: Write + Seek,
14{
15    /// Parses the demo while writing the rewritten stream.
16    pub fn run(&mut self) -> Result<(), ParserError> {
17        self.parser.reader.seek(0);
18        let header = self.parser.reader.read_bytes(16);
19        self.writer.write_all(&header)?;
20        self.bytes_written = header.len() as u64;
21
22        'messages: while let Some(message) = self.read_next_raw_message()? {
23            self.update_context_tick(message.tick);
24
25            let mut payload = None;
26            if self.has_rewriters(RewriteInterests::DEMO_MESSAGE) {
27                let mut decoded = Self::decode_raw_payload(&message)?;
28                let ctx = &self.parser.context;
29                for rewriter in self.rewriters.iter_mut().filter(|rewriter| {
30                    rewriter
31                        .interests()
32                        .contains(RewriteInterests::DEMO_MESSAGE)
33                }) {
34                    match rewriter.rewrite_demo_message(
35                        ctx,
36                        message.tick,
37                        message.msg_type,
38                        decoded.as_slice(),
39                    )? {
40                        MessageRewrite::Drop => continue 'messages,
41                        MessageRewrite::Replace(bytes) => decoded = bytes,
42                        MessageRewrite::Keep | MessageRewrite::Rewrite => {}
43                    }
44                }
45                payload = Some(decoded);
46            }
47
48            match message.msg_type {
49                EDemoCommands::DemPacket | EDemoCommands::DemSignonPacket => {
50                    if !self.needs_packet_scan() {
51                        self.write_message_or_raw(&message, payload.as_deref())?;
52                        continue;
53                    }
54
55                    let payload = Self::materialize_payload(&mut payload, &message)?;
56                    let mut packet = CDemoPacket::decode(payload.as_slice())?;
57                    let rewritten = self.rewrite_packet_data(
58                        message.tick,
59                        packet.data(),
60                        self.needs_packet_state(),
61                    )?;
62                    packet.data = Some(rewritten);
63                    let packet_bytes = packet.encode_to_vec();
64                    self.write_demo_message_with_compression(
65                        message.msg_type,
66                        message.tick,
67                        &packet_bytes,
68                        message.compressed,
69                    )?;
70                }
71                EDemoCommands::DemFullPacket => {
72                    if !self.needs_packet_scan() && !self.needs_demo_string_table_scan() {
73                        self.write_message_or_raw(&message, payload.as_deref())?;
74                        continue;
75                    }
76
77                    let payload = Self::materialize_payload(&mut payload, &message)?;
78                    let mut full = CDemoFullPacket::decode(payload.as_slice())?;
79                    let should_process = self.parser.context.last_full_packet_tick == u32::MAX
80                        || self.parser.skip_deltas;
81
82                    if let Some(table) = full.string_table.take() {
83                        if self.needs_demo_string_table_scan() {
84                            if let Some(rewritten) =
85                                self.rewrite_string_tables(message.tick, table)?
86                            {
87                                if should_process && self.needs_demo_string_table_state() {
88                                    self.parser.dem_string_tables(rewritten.clone())?;
89                                }
90                                full.string_table = Some(rewritten);
91                            }
92                        } else {
93                            full.string_table = Some(table);
94                        }
95                    }
96
97                    if let Some(packet) = full.packet.as_mut() {
98                        if self.needs_packet_scan() {
99                            let rewritten = self.rewrite_packet_data(
100                                message.tick,
101                                packet.data(),
102                                should_process && self.needs_packet_state(),
103                            )?;
104                            packet.data = Some(rewritten);
105                        }
106                    }
107
108                    self.parser.context.last_full_packet_tick = message.tick;
109                    let full_bytes = full.encode_to_vec();
110                    self.write_demo_message_with_compression(
111                        message.msg_type,
112                        message.tick,
113                        &full_bytes,
114                        message.compressed,
115                    )?;
116                }
117                EDemoCommands::DemSendTables if self.needs_class_metadata() => {
118                    let payload = Self::materialize_payload(&mut payload, &message)?;
119                    let msg = CDemoSendTables::decode(payload.as_slice())?;
120                    self.parser.dem_send_tables(msg)?;
121                    self.write_demo_message_with_compression(
122                        message.msg_type,
123                        message.tick,
124                        &payload,
125                        message.compressed,
126                    )?;
127                }
128                EDemoCommands::DemClassInfo if self.needs_class_metadata() => {
129                    let payload = Self::materialize_payload(&mut payload, &message)?;
130                    let msg = CDemoClassInfo::decode(payload.as_slice())?;
131                    self.parser.dem_class_info(msg)?;
132                    self.write_demo_message_with_compression(
133                        message.msg_type,
134                        message.tick,
135                        &payload,
136                        message.compressed,
137                    )?;
138                }
139                EDemoCommands::DemStringTables => {
140                    if !self.needs_demo_string_table_scan() {
141                        self.write_message_or_raw(&message, payload.as_deref())?;
142                        continue;
143                    }
144
145                    let payload = Self::materialize_payload(&mut payload, &message)?;
146                    let mut msg = CDemoStringTables::decode(payload.as_slice())?;
147                    let mut changed = false;
148                    if self.rewrites_entity_fields() {
149                        changed |= self.rewrite_instance_baselines(&mut msg)?;
150                    }
151                    changed |= self.rewrite_demo_string_table_entries(message.tick, &mut msg)?;
152                    let mut out_payload: Option<Vec<u8>> = None;
153                    let ctx = &self.parser.context;
154                    for rewriter in self.rewriters.iter_mut().filter(|rewriter| {
155                        rewriter
156                            .interests()
157                            .contains(RewriteInterests::DEMO_STRING_TABLES)
158                    }) {
159                        match rewriter.rewrite_demo_string_tables(ctx, message.tick, &mut msg)? {
160                            MessageRewrite::Drop => continue 'messages,
161                            MessageRewrite::Keep => {}
162                            MessageRewrite::Rewrite => {
163                                changed = false;
164                                out_payload = Some(msg.encode_to_vec());
165                            }
166                            MessageRewrite::Replace(bytes) => {
167                                msg = CDemoStringTables::decode(bytes.as_slice())?;
168                                changed = false;
169                                out_payload = Some(bytes);
170                            }
171                        }
172                    }
173                    let payload = out_payload.unwrap_or_else(|| {
174                        if changed {
175                            msg.encode_to_vec()
176                        } else {
177                            payload
178                        }
179                    });
180                    if self.needs_demo_string_table_state() {
181                        self.parser.dem_string_tables(msg)?;
182                    }
183                    self.write_demo_message_with_compression(
184                        message.msg_type,
185                        message.tick,
186                        &payload,
187                        message.compressed,
188                    )?;
189                }
190                _ => {
191                    self.write_message_or_raw(&message, payload.as_deref())?;
192                }
193            }
194        }
195
196        self.finalize_file_info_offset()?;
197        Ok(())
198    }
199
200    fn update_context_tick(&mut self, tick: u32) {
201        self.parser.context.previous_tick = self.parser.context.tick;
202        self.parser.context.tick = tick;
203    }
204}