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};
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::mem::MaybeUninit;
20use std::rc::Rc;
21
22use input::RawDemoMessage;
23pub use rewriter::{
24 rewrite_protobuf_message, DemoRewriter, MessageRewrite, PacketMessage, RewriteInterests,
25};
26
27const INSTANCE_BASELINE_TABLE: &str = "instancebaseline";
28
29fn uninit_array_box<T, const N: usize>() -> Box<[MaybeUninit<T>; N]> {
30 unsafe { Box::<[MaybeUninit<T>; N]>::new_uninit().assume_init() }
31}
32
33pub struct DemoWriter<'a, R, W>
40where
41 R: BitsReader + MessageReader,
42 W: Write + Seek,
43{
44 parser: Parser<'a, R>,
45 writer: W,
46 string_table_rewrite_states: Vec<Option<PackedStringTableState>>,
47 rewriters: Vec<Box<dyn DemoRewriter + 'a>>,
48 rewriter_interests: RewriteInterests,
49 field_path_codec: FieldPathCodec,
50 entity_rewrite_paths: Box<[MaybeUninit<FieldPath>; entity::ENTITY_REWRITE_BUFFER_LEN]>,
51 entity_rewrite_paths_len: usize,
52 entity_decoded_fields:
53 Box<[MaybeUninit<entity::DecodedEntityField>; entity::ENTITY_REWRITE_BUFFER_LEN]>,
54 entity_decoded_fields_len: usize,
55 entity_replacements:
56 Box<[MaybeUninit<entity::FieldReplacement>; entity::ENTITY_REWRITE_BUFFER_LEN]>,
57 entity_replacements_len: usize,
58 bytes_written: u64,
59 file_info_offset: Option<u64>,
60}
61
62impl<'a, R, W> DemoWriter<'a, R, W>
63where
64 R: BitsReader + MessageReader,
65 W: Write + Seek,
66{
67 pub fn new(parser: Parser<'a, R>, writer: W) -> Self {
69 Self {
70 parser,
71 writer,
72 string_table_rewrite_states: Vec::new(),
73 rewriters: Vec::new(),
74 rewriter_interests: RewriteInterests::empty(),
75 field_path_codec: FieldPathCodec::default(),
76 entity_rewrite_paths: uninit_array_box(),
77 entity_rewrite_paths_len: 0,
78 entity_decoded_fields: uninit_array_box(),
79 entity_decoded_fields_len: 0,
80 entity_replacements: uninit_array_box(),
81 entity_replacements_len: 0,
82 bytes_written: 0,
83 file_info_offset: None,
84 }
85 }
86
87 pub fn add_rewriter<T>(&mut self, rewriter: T) -> Rc<RefCell<T>>
93 where
94 T: DemoRewriter + 'a,
95 {
96 let rewriter = Rc::new(RefCell::new(rewriter));
97 self.rewriter_interests |= rewriter.borrow().interests();
98 self.rewriters.push(Box::new(rewriter.clone()));
99 rewriter
100 }
101
102 pub fn register_rewriter<T>(&mut self) -> Rc<RefCell<T>>
141 where
142 T: DemoRewriter + Default + 'a,
143 {
144 self.add_rewriter(T::default())
145 }
146
147 pub(crate) fn should_rewrite_entity(&mut self, event: EntityEvents, entity: &Entity) -> bool {
148 let ctx = &self.parser.context;
149 self.rewriters
150 .iter_mut()
151 .filter(|rewriter| {
152 rewriter
153 .interests()
154 .contains(RewriteInterests::ENTITY_FIELDS)
155 })
156 .all(|rewriter| rewriter.should_rewrite_entity(ctx, event, entity))
157 }
158
159 pub(crate) fn should_track_entity(&mut self, event: EntityEvents, entity: &Entity) -> bool {
160 let ctx = &self.parser.context;
161 self.rewriters
162 .iter_mut()
163 .filter(|rewriter| {
164 rewriter
165 .interests()
166 .contains(RewriteInterests::ENTITY_FIELDS)
167 })
168 .all(|rewriter| rewriter.should_track_entity(ctx, event, entity))
169 }
170
171 pub(crate) fn replace_entity_field(
172 &mut self,
173 event: EntityEvents,
174 entity: &Entity,
175 field_name: &str,
176 value: &FieldValue,
177 ) -> Option<FieldValue> {
178 let ctx = &self.parser.context;
179 self.rewriters
180 .iter_mut()
181 .filter(|rewriter| {
182 rewriter
183 .interests()
184 .contains(RewriteInterests::ENTITY_FIELDS)
185 })
186 .find_map(|rewriter| {
187 rewriter.replace_entity_field(ctx, event, entity, field_name, value)
188 })
189 }
190
191 fn has_rewriters(&self, interests: RewriteInterests) -> bool {
192 self.rewriter_interests.intersects(interests)
193 }
194
195 fn rewrites_entity_fields(&self) -> bool {
196 self.has_rewriters(RewriteInterests::ENTITY_FIELDS)
197 }
198
199 fn rewrites_string_table_entries(&self) -> bool {
200 self.has_rewriters(RewriteInterests::STRING_TABLE_ENTRIES)
201 }
202
203 fn needs_string_table_context(&self) -> bool {
204 self.rewrites_entity_fields() || self.rewrites_string_table_entries()
205 }
206
207 fn needs_packet_scan(&self) -> bool {
208 self.has_rewriters(RewriteInterests::PACKET_MESSAGE | RewriteInterests::PACKET_MESSAGES)
209 || self.rewrites_entity_fields()
210 || self.rewrites_string_table_entries()
211 || self.has_rewriters(
212 RewriteInterests::SVC_CREATE_STRING_TABLE
213 | RewriteInterests::SVC_UPDATE_STRING_TABLE,
214 )
215 }
216
217 fn needs_svc_packet_scan(&self) -> bool {
218 self.needs_string_table_context()
219 || self.has_rewriters(
220 RewriteInterests::SVC_CREATE_STRING_TABLE
221 | RewriteInterests::SVC_UPDATE_STRING_TABLE,
222 )
223 }
224
225 fn needs_packet_state(&self) -> bool {
226 self.needs_string_table_context()
227 }
228
229 fn needs_class_metadata(&self) -> bool {
230 self.rewrites_entity_fields()
231 }
232
233 fn needs_demo_string_table_scan(&self) -> bool {
234 self.needs_string_table_context()
235 || self.has_rewriters(RewriteInterests::DEMO_STRING_TABLES)
236 }
237
238 fn needs_demo_string_table_state(&self) -> bool {
239 self.rewrites_string_table_entries()
240 }
241
242 pub fn into_parts(self) -> (Parser<'a, R>, W) {
244 (self.parser, self.writer)
245 }
246}
247
248impl<'a, W> DemoWriter<'a, SliceReader<'a>, W>
249where
250 W: Write + Seek,
251{
252 pub fn from_slice(replay: &'a [u8], writer: W) -> Result<Self, ParserError> {
257 Ok(Self::new(Parser::from_slice(replay)?, writer))
258 }
259}
260
261impl<S, W> DemoWriter<'static, SeekableReader<S>, W>
262where
263 S: std::io::Read + std::io::Seek,
264 W: Write + Seek,
265{
266 pub fn from_reader(reader: S, writer: W) -> Result<Self, ParserError> {
271 Ok(Self::new(Parser::from_reader(reader)?, writer))
272 }
273}