1use std::collections::HashMap;
2
3use rustc_hash::FxHashMap;
4use std::sync::Arc;
8
9use prost::Message;
10
11use crate::error::Result;
12use crate::io::ByteReader;
13
14use super::field_decoder::{self, FieldMetadata};
15use super::field_path::FieldPath;
16
17use boon_proto::proto::{CDemoSendTables, CsvcMsgFlattenedSerializer};
18
19#[derive(Debug, Clone)]
21pub struct FieldType {
22 pub base_type: String,
24 pub pointer: bool,
26 pub generic_type: Option<Box<FieldType>>,
28 pub array_length: Option<usize>,
30 pub count: Option<String>,
32}
33
34#[derive(Debug, Clone)]
36pub struct SerializerField {
37 pub var_type: String,
39 pub var_name: String,
41 pub bit_count: Option<i32>,
43 pub low_value: Option<f32>,
45 pub high_value: Option<f32>,
47 pub encode_flags: Option<i32>,
49 pub field_serializer_name: Option<String>,
51 pub send_node: Option<String>,
53 pub var_encoder: Option<String>,
55 pub field_serializer: Option<Arc<Serializer>>,
57 pub field_type: FieldType,
59 pub metadata: FieldMetadata,
61}
62
63impl SerializerField {
64 pub fn get_child(&self, index: usize) -> Option<&SerializerField> {
66 self.field_serializer
67 .as_ref()
68 .and_then(|s| s.fields.get(index).map(|f| f.as_ref()))
69 }
70
71 pub fn is_dynamic_array(&self) -> bool {
73 self.metadata.is_dynamic_array()
74 }
75}
76
77#[derive(Debug, Clone)]
79pub struct Serializer {
80 pub name: String,
81 pub fields: Vec<Arc<SerializerField>>,
82}
83
84impl Serializer {
85 pub fn resolve_field_key(&self, path: &str) -> Option<u64> {
88 let parts: Vec<&str> = path.split('.').collect();
89 self.resolve_parts(&parts, 0)
90 }
91
92 fn resolve_parts(&self, parts: &[&str], depth: usize) -> Option<u64> {
93 if depth >= parts.len() {
94 return None;
95 }
96
97 for (field_idx, field) in self.fields.iter().enumerate() {
98 let mut field_parts: Vec<&str> = Vec::new();
100 if let Some(ref sn) = field.send_node
101 && !sn.is_empty()
102 {
103 for part in sn.split('.') {
104 field_parts.push(part);
105 }
106 }
107 if !field.var_name.is_empty() {
108 field_parts.push(&field.var_name);
109 }
110
111 let remaining = &parts[depth..];
113 if remaining.len() < field_parts.len() {
114 continue;
115 }
116 if field_parts != remaining[..field_parts.len()] {
117 continue;
118 }
119
120 let consumed = depth + field_parts.len();
121
122 if consumed == parts.len() {
124 let mut fp = FieldPath::default();
125 fp.data[0] = field_idx as u8;
126 return Some(fp.pack());
128 }
129
130 let next_part = parts[consumed];
132
133 if field.is_dynamic_array() {
135 if let Ok(array_idx) = next_part.parse::<usize>()
136 && let Some(ref fs) = field.field_serializer
137 {
138 let inner_field = &fs.fields[0];
139 let after_idx = consumed + 1;
140
141 if after_idx == parts.len() {
142 let mut fp = FieldPath::default();
144 fp.data[0] = field_idx as u8;
145 fp.data[1] = array_idx as u8;
146 fp.last = 1;
147 return Some(fp.pack());
148 }
149
150 if let Some(ref inner_fs) = inner_field.field_serializer
152 && let Some(key) = inner_fs.resolve_parts(parts, after_idx)
153 {
154 let inner_fp = FieldPath::unpack(key);
155 let mut fp = FieldPath::default();
156 fp.data[0] = field_idx as u8;
157 fp.data[1] = array_idx as u8;
158 fp.last = 2 + inner_fp.last;
159 for i in 0..=inner_fp.last {
160 fp.data[2 + i] = inner_fp.data[i];
161 }
162 return Some(fp.pack());
163 }
164 }
165 continue;
166 }
167
168 if let Some(ref fs) = field.field_serializer
170 && let Some(key) = fs.resolve_parts(parts, consumed)
171 {
172 let inner_fp = FieldPath::unpack(key);
173 let mut fp = FieldPath::default();
174 fp.data[0] = field_idx as u8;
175 fp.last = 1 + inner_fp.last;
176 for i in 0..=inner_fp.last {
177 fp.data[1 + i] = inner_fp.data[i];
178 }
179 return Some(fp.pack());
180 }
181 }
182
183 None
184 }
185
186 pub fn field_name_for_key(&self, key: u64) -> Option<String> {
189 let fp = FieldPath::unpack(key);
190 let mut parts: Vec<String> = Vec::new();
191 let mut field = self.fields.get(fp.get(0))?;
192
193 if let Some(ref sn) = field.send_node
194 && !sn.is_empty()
195 {
196 for part in sn.split('.') {
197 parts.push(part.to_string());
198 }
199 }
200 parts.push(field.var_name.clone());
201
202 for i in 1..=fp.last {
203 let idx = fp.get(i);
204 if field.is_dynamic_array() {
205 parts.push(idx.to_string());
206 if let Some(ref fs) = field.field_serializer {
207 field = &fs.fields[0];
208 } else {
209 break;
210 }
211 } else if let Some(ref fs) = field.field_serializer {
212 field = fs.fields.get(idx)?;
213 if let Some(ref sn) = field.send_node
214 && !sn.is_empty()
215 {
216 for part in sn.split('.') {
217 parts.push(part.to_string());
218 }
219 }
220 parts.push(field.var_name.clone());
221 } else {
222 break;
223 }
224 }
225
226 Some(parts.join("."))
227 }
228}
229
230pub struct SerializerContainer {
232 pub serializers: FxHashMap<String, Arc<Serializer>>,
236}
237
238impl SerializerContainer {
239 pub fn parse(cmd: CDemoSendTables) -> Result<Self> {
241 let data = cmd.data.unwrap_or_default();
242 let mut data_reader = ByteReader::new(&data);
243
244 let _size = data_reader.read_uvarint64()?;
246 let remaining = data_reader.read_bytes(data_reader.remaining())?;
247 let msg = CsvcMsgFlattenedSerializer::decode(remaining)?;
248
249 let symbols = &msg.symbols;
250
251 let resolve_sym = |i: i32| -> &str { &symbols[i as usize] };
252
253 let mut field_cache: HashMap<i32, Arc<SerializerField>> = HashMap::new();
255 let mut serializer_map: FxHashMap<String, Arc<Serializer>> = FxHashMap::default();
256
257 for serializer_proto in &msg.serializers {
258 let ser_name = resolve_sym(serializer_proto.serializer_name_sym.unwrap_or(0));
259 let mut serializer = Serializer {
260 name: ser_name.to_string(),
261 fields: Vec::with_capacity(serializer_proto.fields_index.len()),
262 };
263
264 for &field_index in &serializer_proto.fields_index {
265 if let Some(cached) = field_cache.get(&field_index) {
266 serializer.fields.push(cached.clone());
267 continue;
268 }
269
270 let field_proto = &msg.fields[field_index as usize];
271
272 let var_type = field_proto
273 .var_type_sym
274 .map(resolve_sym)
275 .unwrap_or("")
276 .to_string();
277 let var_name = field_proto
278 .var_name_sym
279 .map(resolve_sym)
280 .unwrap_or("")
281 .to_string();
282 let send_node = field_proto.send_node_sym.map(resolve_sym).map(String::from);
283 let var_encoder = field_proto
284 .var_encoder_sym
285 .map(resolve_sym)
286 .map(String::from);
287 let field_serializer_name = field_proto
288 .field_serializer_name_sym
289 .map(resolve_sym)
290 .map(String::from);
291
292 let field_type = parse_type(&var_type);
293 let metadata = field_decoder::get_field_metadata(
294 &var_type,
295 &var_name,
296 field_proto.bit_count,
297 field_proto.low_value,
298 field_proto.high_value,
299 field_proto.encode_flags,
300 var_encoder.as_deref(),
301 field_serializer_name.is_some(),
302 );
303
304 let field_serializer = match &metadata {
306 fm if fm.is_fixed_array() => {
307 let length = fm.fixed_array_length().unwrap_or(0);
308 let inner_ser = field_serializer_name
310 .as_deref()
311 .and_then(|n| serializer_map.get(n).cloned());
312
313 let inner_field = SerializerField {
314 var_type: var_type.clone(),
315 var_name: var_name.clone(),
316 bit_count: field_proto.bit_count,
317 low_value: field_proto.low_value,
318 high_value: field_proto.high_value,
319 encode_flags: field_proto.encode_flags,
320 field_serializer_name: field_serializer_name.clone(),
321 send_node: send_node.clone(),
322 var_encoder: var_encoder.clone(),
323 field_serializer: inner_ser,
324 field_type: field_type.clone(),
325 metadata: metadata.clone(),
326 };
327 let inner_rc = Arc::new(inner_field);
328 let mut fields = Vec::with_capacity(length);
329 fields.resize(length, inner_rc);
330 Some(Arc::new(Serializer {
331 name: String::new(),
332 fields,
333 }))
334 }
335 fm if fm.is_dynamic_array() => {
336 if fm.is_dynamic_serializer_array() {
338 let inner_ser = field_serializer_name
339 .as_deref()
340 .and_then(|n| serializer_map.get(n).cloned());
341 let inner = Arc::new(SerializerField {
342 var_type: String::new(),
343 var_name: String::new(),
344 bit_count: None,
345 low_value: None,
346 high_value: None,
347 encode_flags: None,
348 field_serializer_name: None,
349 send_node: None,
350 var_encoder: None,
351 field_serializer: inner_ser,
352 field_type: parse_type(""),
353 metadata: FieldMetadata::default(),
354 });
355 Some(Arc::new(Serializer {
356 name: String::new(),
357 fields: vec![inner],
358 }))
359 } else {
360 let inner_metadata = fm.dynamic_array_inner_metadata();
362 let inner = Arc::new(SerializerField {
363 var_type: String::new(),
364 var_name: String::new(),
365 bit_count: None,
366 low_value: None,
367 high_value: None,
368 encode_flags: None,
369 field_serializer_name: None,
370 send_node: None,
371 var_encoder: None,
372 field_serializer: None,
373 field_type: parse_type(""),
374 metadata: inner_metadata,
375 });
376 Some(Arc::new(Serializer {
377 name: String::new(),
378 fields: vec![inner],
379 }))
380 }
381 }
382 fm if fm.is_pointer() => field_serializer_name
383 .as_deref()
384 .and_then(|n| serializer_map.get(n).cloned()),
385 _ => field_serializer_name
386 .as_deref()
387 .and_then(|n| serializer_map.get(n).cloned()),
388 };
389
390 let field = Arc::new(SerializerField {
391 var_type,
392 var_name,
393 bit_count: field_proto.bit_count,
394 low_value: field_proto.low_value,
395 high_value: field_proto.high_value,
396 encode_flags: field_proto.encode_flags,
397 field_serializer_name,
398 send_node,
399 var_encoder,
400 field_serializer,
401 field_type,
402 metadata,
403 });
404
405 field_cache.insert(field_index, field.clone());
406 serializer.fields.push(field);
407 }
408
409 serializer_map.insert(serializer.name.clone(), Arc::new(serializer));
410 }
411
412 Ok(Self {
413 serializers: serializer_map,
414 })
415 }
416
417 pub fn get(&self, name: &str) -> Option<&Serializer> {
419 self.serializers.get(name).map(|arc| arc.as_ref())
420 }
421}
422
423pub fn parse_type(s: &str) -> FieldType {
425 let s = s.trim();
426
427 if let Some(stripped) = s.strip_suffix('*') {
429 return FieldType {
430 base_type: stripped.trim().to_string(),
431 pointer: true,
432 generic_type: None,
433 array_length: None,
434 count: None,
435 };
436 }
437
438 if let Some(bracket_pos) = s.find('[')
440 && s.ends_with(']')
441 {
442 let base = s[..bracket_pos].trim();
443 let len_str = s[bracket_pos + 1..s.len() - 1].trim();
444 let array_length = len_str.parse::<usize>().ok();
445 let count = if array_length.is_none() {
446 Some(len_str.to_string())
447 } else {
448 None
449 };
450 return FieldType {
451 base_type: base.to_string(),
452 pointer: false,
453 generic_type: None,
454 array_length,
455 count,
456 };
457 }
458
459 if let Some(angle_pos) = s.find('<')
461 && let Some(close_pos) = s.rfind('>')
462 {
463 let base = s[..angle_pos].trim();
464 let inner = s[angle_pos + 1..close_pos].trim();
465 return FieldType {
466 base_type: base.to_string(),
467 pointer: false,
468 generic_type: Some(Box::new(parse_type(inner))),
469 array_length: None,
470 count: None,
471 };
472 }
473
474 FieldType {
476 base_type: s.to_string(),
477 pointer: false,
478 generic_type: None,
479 array_length: None,
480 count: None,
481 }
482}
483
484#[cfg(test)]
485mod tests {
486 use super::super::field_decoder::{Decoder, FieldMetadata};
487 use super::*;
488
489 #[test]
492 fn parse_type_simple() {
493 let ft = parse_type("int32");
494 assert_eq!(ft.base_type, "int32");
495 assert!(!ft.pointer);
496 assert!(ft.generic_type.is_none());
497 assert!(ft.array_length.is_none());
498 assert!(ft.count.is_none());
499 }
500
501 #[test]
502 fn parse_type_pointer() {
503 let ft = parse_type("CBaseEntity*");
504 assert_eq!(ft.base_type, "CBaseEntity");
505 assert!(ft.pointer);
506 }
507
508 #[test]
509 fn parse_type_array_numeric() {
510 let ft = parse_type("int32[4]");
511 assert_eq!(ft.base_type, "int32");
512 assert_eq!(ft.array_length, Some(4));
513 assert!(ft.count.is_none());
514 }
515
516 #[test]
517 fn parse_type_array_symbolic() {
518 let ft = parse_type("int32[MAX_ABILITIES]");
519 assert_eq!(ft.base_type, "int32");
520 assert!(ft.array_length.is_none());
521 assert_eq!(ft.count.as_deref(), Some("MAX_ABILITIES"));
522 }
523
524 #[test]
525 fn parse_type_generic() {
526 let ft = parse_type("CNetworkUtlVectorBase< int32 >");
527 assert_eq!(ft.base_type, "CNetworkUtlVectorBase");
528 let inner = ft.generic_type.as_ref().unwrap();
529 assert_eq!(inner.base_type, "int32");
530 }
531
532 #[test]
533 fn parse_type_generic_nested() {
534 let ft = parse_type("CHandle< CBaseEntity >");
535 assert_eq!(ft.base_type, "CHandle");
536 assert_eq!(ft.generic_type.as_ref().unwrap().base_type, "CBaseEntity");
537 }
538
539 #[test]
540 fn parse_type_whitespace_trimming() {
541 let ft = parse_type(" float32 ");
542 assert_eq!(ft.base_type, "float32");
543 }
544
545 #[test]
546 fn parse_type_empty_string() {
547 let ft = parse_type("");
548 assert_eq!(ft.base_type, "");
549 assert!(!ft.pointer);
550 }
551
552 #[test]
553 fn parse_type_complex_all_fields() {
554 let ft = parse_type("uint32[16]");
555 assert_eq!(ft.base_type, "uint32");
556 assert!(!ft.pointer);
557 assert!(ft.generic_type.is_none());
558 assert_eq!(ft.array_length, Some(16));
559 assert!(ft.count.is_none());
560 }
561
562 fn make_field(name: &str, send_node: Option<&str>) -> Arc<SerializerField> {
565 Arc::new(SerializerField {
566 var_type: String::new(),
567 var_name: name.to_string(),
568 bit_count: None,
569 low_value: None,
570 high_value: None,
571 encode_flags: None,
572 field_serializer_name: None,
573 send_node: send_node.map(String::from),
574 var_encoder: None,
575 field_serializer: None,
576 field_type: parse_type(""),
577 metadata: FieldMetadata {
578 decoder: Decoder::U64,
579 special: None,
580 },
581 })
582 }
583
584 #[test]
585 fn resolve_field_key_found() {
586 let ser = Serializer {
587 name: "test".to_string(),
588 fields: vec![make_field("m_iHealth", None)],
589 };
590 assert!(ser.resolve_field_key("m_iHealth").is_some());
591 }
592
593 #[test]
594 fn resolve_field_key_not_found() {
595 let ser = Serializer {
596 name: "test".to_string(),
597 fields: vec![make_field("m_iHealth", None)],
598 };
599 assert!(ser.resolve_field_key("m_iMana").is_none());
600 }
601
602 #[test]
603 fn field_name_roundtrip() {
604 let ser = Serializer {
605 name: "test".to_string(),
606 fields: vec![make_field("m_iHealth", None), make_field("m_iMana", None)],
607 };
608 let key = ser.resolve_field_key("m_iMana").unwrap();
609 let name = ser.field_name_for_key(key).unwrap();
610 assert_eq!(name, "m_iMana");
611 }
612
613 #[test]
614 fn resolve_with_send_node() {
615 let ser = Serializer {
616 name: "test".to_string(),
617 fields: vec![make_field("m_bPaused", Some("m_pGameRules"))],
618 };
619 let key = ser.resolve_field_key("m_pGameRules.m_bPaused");
620 assert!(key.is_some());
621 let name = ser.field_name_for_key(key.unwrap()).unwrap();
622 assert_eq!(name, "m_pGameRules.m_bPaused");
623 }
624}