source2_demo/parser/demo/writer/
mod.rs1mod baseline;
2mod entity;
3mod input;
4mod output;
5mod packet;
6mod packet_state;
7mod rewriter;
8mod run;
9mod string_table;
10
11use crate::entity::field::{FieldPath, FieldValue, Serializer};
12use crate::entity::{Entity, EntityEvents};
13use crate::error::ParserError;
14use crate::parser::Parser;
15use crate::reader::{BitsReader, FieldPathCodec, MessageReader, SeekableReader, SliceReader};
16use crate::string_table::PackedStringTableState;
17use std::cell::RefCell;
18use std::io::{Seek, Write};
19use std::rc::Rc;
20
21use input::RawDemoMessage;
22pub use rewriter::{
23 rewrite_protobuf_message, DemoRewriter, MessageRewrite, PacketMessage, RewriteInterests,
24};
25
26const INSTANCE_BASELINE_TABLE: &str = "instancebaseline";
27const ENTITY_REWRITE_BUFFER_CAPACITY: usize = 8192;
28
29struct FieldReplacement {
30 serializer: Rc<Serializer>,
31 fp: FieldPath,
32 value: FieldValue,
33 value_start: usize,
34 value_end: usize,
35}
36
37struct DecodedEntityField {
38 fp: FieldPath,
39 name: Rc<str>,
40 value_start: usize,
41 value_end: usize,
42}
43
44pub struct DemoWriter<'a, R, W>
51where
52 R: BitsReader + MessageReader,
53 W: Write + Seek,
54{
55 parser: Parser<'a, R>,
56 writer: W,
57 string_table_rewrite_states: Vec<Option<PackedStringTableState>>,
58 rewriters: Vec<Box<dyn DemoRewriter + 'a>>,
59 rewriter_interests: RewriteInterests,
60 field_path_codec: FieldPathCodec,
61 entity_rewrite_paths: Vec<FieldPath>,
62 entity_decoded_fields: Vec<DecodedEntityField>,
63 entity_replacements: Vec<FieldReplacement>,
64 bytes_written: u64,
65 file_info_offset: Option<u64>,
66}
67
68impl<'a, R, W> DemoWriter<'a, R, W>
69where
70 R: BitsReader + MessageReader,
71 W: Write + Seek,
72{
73 pub fn new(parser: Parser<'a, R>, writer: W) -> Self {
75 Self {
76 parser,
77 writer,
78 string_table_rewrite_states: Vec::new(),
79 rewriters: Vec::new(),
80 rewriter_interests: RewriteInterests::empty(),
81 field_path_codec: FieldPathCodec::default(),
82 entity_rewrite_paths: Vec::with_capacity(ENTITY_REWRITE_BUFFER_CAPACITY),
83 entity_decoded_fields: Vec::with_capacity(ENTITY_REWRITE_BUFFER_CAPACITY),
84 entity_replacements: Vec::with_capacity(ENTITY_REWRITE_BUFFER_CAPACITY),
85 bytes_written: 0,
86 file_info_offset: None,
87 }
88 }
89
90 pub fn add_rewriter<T>(&mut self, rewriter: T) -> Rc<RefCell<T>>
96 where
97 T: DemoRewriter + 'a,
98 {
99 let rewriter = Rc::new(RefCell::new(rewriter));
100 self.rewriter_interests |= rewriter.borrow().interests();
101 self.rewriters.push(Box::new(rewriter.clone()));
102 rewriter
103 }
104
105 pub fn register_rewriter<T>(&mut self) -> Rc<RefCell<T>>
144 where
145 T: DemoRewriter + Default + 'a,
146 {
147 self.add_rewriter(T::default())
148 }
149
150 fn should_rewrite_entity(&mut self, event: EntityEvents, entity: &Entity) -> bool {
151 let ctx = &self.parser.context;
152 self.rewriters
153 .iter_mut()
154 .filter(|rewriter| {
155 rewriter
156 .interests()
157 .contains(RewriteInterests::ENTITY_FIELDS)
158 })
159 .all(|rewriter| rewriter.should_rewrite_entity(ctx, event, entity))
160 }
161
162 fn should_track_entity(&mut self, event: EntityEvents, entity: &Entity) -> bool {
163 let ctx = &self.parser.context;
164 self.rewriters
165 .iter_mut()
166 .filter(|rewriter| {
167 rewriter
168 .interests()
169 .contains(RewriteInterests::ENTITY_FIELDS)
170 })
171 .all(|rewriter| rewriter.should_track_entity(ctx, event, entity))
172 }
173
174 fn replace_entity_field(
175 &mut self,
176 event: EntityEvents,
177 entity: &Entity,
178 field_name: &str,
179 value: &FieldValue,
180 ) -> Option<FieldValue> {
181 let ctx = &self.parser.context;
182 self.rewriters
183 .iter_mut()
184 .filter(|rewriter| {
185 rewriter
186 .interests()
187 .contains(RewriteInterests::ENTITY_FIELDS)
188 })
189 .find_map(|rewriter| {
190 rewriter.replace_entity_field(ctx, event, entity, field_name, value)
191 })
192 }
193
194 fn has_rewriters(&self, interests: RewriteInterests) -> bool {
195 self.rewriter_interests.intersects(interests)
196 }
197
198 fn rewrites_entity_fields(&self) -> bool {
199 self.has_rewriters(RewriteInterests::ENTITY_FIELDS)
200 }
201
202 fn rewrites_string_table_entries(&self) -> bool {
203 self.has_rewriters(RewriteInterests::STRING_TABLE_ENTRIES)
204 }
205
206 fn needs_string_table_context(&self) -> bool {
207 self.rewrites_entity_fields() || self.rewrites_string_table_entries()
208 }
209
210 fn needs_packet_scan(&self) -> bool {
211 self.has_rewriters(RewriteInterests::PACKET_MESSAGE | RewriteInterests::PACKET_MESSAGES)
212 || self.rewrites_entity_fields()
213 || self.rewrites_string_table_entries()
214 || self.has_rewriters(
215 RewriteInterests::SVC_CREATE_STRING_TABLE
216 | RewriteInterests::SVC_UPDATE_STRING_TABLE,
217 )
218 }
219
220 fn needs_svc_packet_scan(&self) -> bool {
221 self.needs_string_table_context()
222 || self.has_rewriters(
223 RewriteInterests::SVC_CREATE_STRING_TABLE
224 | RewriteInterests::SVC_UPDATE_STRING_TABLE,
225 )
226 }
227
228 fn needs_packet_state(&self) -> bool {
229 self.needs_string_table_context()
230 }
231
232 fn needs_class_metadata(&self) -> bool {
233 self.rewrites_entity_fields()
234 }
235
236 fn needs_demo_string_table_scan(&self) -> bool {
237 self.needs_string_table_context()
238 || self.has_rewriters(RewriteInterests::DEMO_STRING_TABLES)
239 }
240
241 fn needs_demo_string_table_state(&self) -> bool {
242 self.rewrites_string_table_entries()
243 }
244
245 pub fn into_parts(self) -> (Parser<'a, R>, W) {
247 (self.parser, self.writer)
248 }
249}
250
251impl<'a, W> DemoWriter<'a, SliceReader<'a>, W>
252where
253 W: Write + Seek,
254{
255 pub fn from_slice(replay: &'a [u8], writer: W) -> Result<Self, ParserError> {
260 Ok(Self::new(Parser::from_slice(replay)?, writer))
261 }
262}
263
264impl<S, W> DemoWriter<'static, SeekableReader<S>, W>
265where
266 S: std::io::Read + std::io::Seek,
267 W: Write + Seek,
268{
269 pub fn from_reader(reader: S, writer: W) -> Result<Self, ParserError> {
274 Ok(Self::new(Parser::from_reader(reader)?, writer))
275 }
276}