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 =
254 |i: i32| -> &str { symbols.get(i as usize).map(String::as_str).unwrap_or("") };
255
256 let mut field_cache: HashMap<i32, Arc<SerializerField>> = HashMap::new();
258 let mut serializer_map: FxHashMap<String, Arc<Serializer>> = FxHashMap::default();
259
260 for serializer_proto in &msg.serializers {
261 let ser_name = resolve_sym(serializer_proto.serializer_name_sym.unwrap_or(0));
262 let mut serializer = Serializer {
263 name: ser_name.to_string(),
264 fields: Vec::with_capacity(serializer_proto.fields_index.len()),
265 };
266
267 for &field_index in &serializer_proto.fields_index {
268 if let Some(cached) = field_cache.get(&field_index) {
269 serializer.fields.push(cached.clone());
270 continue;
271 }
272
273 let field_proto = msg.fields.get(field_index as usize).ok_or_else(|| {
274 crate::error::Error::Parse {
275 context: format!(
276 "serializer field index {field_index} out of range ({} fields)",
277 msg.fields.len()
278 ),
279 }
280 })?;
281
282 let var_type = field_proto
283 .var_type_sym
284 .map(resolve_sym)
285 .unwrap_or("")
286 .to_string();
287 let var_name = field_proto
288 .var_name_sym
289 .map(resolve_sym)
290 .unwrap_or("")
291 .to_string();
292 let send_node = field_proto.send_node_sym.map(resolve_sym).map(String::from);
293 let var_encoder = field_proto
294 .var_encoder_sym
295 .map(resolve_sym)
296 .map(String::from);
297 let field_serializer_name = field_proto
298 .field_serializer_name_sym
299 .map(resolve_sym)
300 .map(String::from);
301
302 let field_type = parse_type(&var_type);
303 let mut metadata = field_decoder::get_field_metadata(
304 &var_type,
305 &var_name,
306 field_proto.bit_count,
307 field_proto.low_value,
308 field_proto.high_value,
309 field_proto.encode_flags,
310 var_encoder.as_deref(),
311 field_serializer_name.is_some(),
312 );
313
314 if !field_proto.polymorphic_types.is_empty() {
318 metadata.decoder = field_decoder::Decoder::Poly;
319 }
320
321 let field_serializer = match &metadata {
323 fm if fm.is_fixed_array() => {
324 let length = fm.fixed_array_length().unwrap_or(0);
325 let inner_ser = field_serializer_name
327 .as_deref()
328 .and_then(|n| serializer_map.get(n).cloned());
329
330 let inner_field = SerializerField {
331 var_type: var_type.clone(),
332 var_name: var_name.clone(),
333 bit_count: field_proto.bit_count,
334 low_value: field_proto.low_value,
335 high_value: field_proto.high_value,
336 encode_flags: field_proto.encode_flags,
337 field_serializer_name: field_serializer_name.clone(),
338 send_node: send_node.clone(),
339 var_encoder: var_encoder.clone(),
340 field_serializer: inner_ser,
341 field_type: field_type.clone(),
342 metadata: metadata.clone(),
343 };
344 let inner_rc = Arc::new(inner_field);
345 let mut fields = Vec::with_capacity(length);
346 fields.resize(length, inner_rc);
347 Some(Arc::new(Serializer {
348 name: String::new(),
349 fields,
350 }))
351 }
352 fm if fm.is_dynamic_array() => {
353 if fm.is_dynamic_serializer_array() {
355 let inner_ser = field_serializer_name
356 .as_deref()
357 .and_then(|n| serializer_map.get(n).cloned());
358 let inner = Arc::new(SerializerField {
359 var_type: String::new(),
360 var_name: String::new(),
361 bit_count: None,
362 low_value: None,
363 high_value: None,
364 encode_flags: None,
365 field_serializer_name: None,
366 send_node: None,
367 var_encoder: None,
368 field_serializer: inner_ser,
369 field_type: parse_type(""),
370 metadata: FieldMetadata::default(),
371 });
372 Some(Arc::new(Serializer {
373 name: String::new(),
374 fields: vec![inner],
375 }))
376 } else {
377 let inner_metadata = fm.dynamic_array_inner_metadata();
379 let inner = Arc::new(SerializerField {
380 var_type: String::new(),
381 var_name: String::new(),
382 bit_count: None,
383 low_value: None,
384 high_value: None,
385 encode_flags: None,
386 field_serializer_name: None,
387 send_node: None,
388 var_encoder: None,
389 field_serializer: None,
390 field_type: parse_type(""),
391 metadata: inner_metadata,
392 });
393 Some(Arc::new(Serializer {
394 name: String::new(),
395 fields: vec![inner],
396 }))
397 }
398 }
399 fm if fm.is_pointer() => field_serializer_name
400 .as_deref()
401 .and_then(|n| serializer_map.get(n).cloned()),
402 _ => field_serializer_name
403 .as_deref()
404 .and_then(|n| serializer_map.get(n).cloned()),
405 };
406
407 let field = Arc::new(SerializerField {
408 var_type,
409 var_name,
410 bit_count: field_proto.bit_count,
411 low_value: field_proto.low_value,
412 high_value: field_proto.high_value,
413 encode_flags: field_proto.encode_flags,
414 field_serializer_name,
415 send_node,
416 var_encoder,
417 field_serializer,
418 field_type,
419 metadata,
420 });
421
422 field_cache.insert(field_index, field.clone());
423 serializer.fields.push(field);
424 }
425
426 serializer_map.insert(serializer.name.clone(), Arc::new(serializer));
427 }
428
429 Ok(Self {
430 serializers: serializer_map,
431 })
432 }
433
434 pub fn get(&self, name: &str) -> Option<&Serializer> {
436 self.serializers.get(name).map(|arc| arc.as_ref())
437 }
438}
439
440pub fn parse_type(s: &str) -> FieldType {
442 let s = s.trim();
443
444 if let Some(stripped) = s.strip_suffix('*') {
446 return FieldType {
447 base_type: stripped.trim().to_string(),
448 pointer: true,
449 generic_type: None,
450 array_length: None,
451 count: None,
452 };
453 }
454
455 if let Some(bracket_pos) = s.find('[')
457 && s.ends_with(']')
458 {
459 let base = s[..bracket_pos].trim();
460 let len_str = s[bracket_pos + 1..s.len() - 1].trim();
461 let array_length = len_str.parse::<usize>().ok();
462 let count = if array_length.is_none() {
463 Some(len_str.to_string())
464 } else {
465 None
466 };
467 return FieldType {
468 base_type: base.to_string(),
469 pointer: false,
470 generic_type: None,
471 array_length,
472 count,
473 };
474 }
475
476 if let Some(angle_pos) = s.find('<')
478 && let Some(close_pos) = s.rfind('>')
479 {
480 let base = s[..angle_pos].trim();
481 let inner = s[angle_pos + 1..close_pos].trim();
482 return FieldType {
483 base_type: base.to_string(),
484 pointer: false,
485 generic_type: Some(Box::new(parse_type(inner))),
486 array_length: None,
487 count: None,
488 };
489 }
490
491 FieldType {
493 base_type: s.to_string(),
494 pointer: false,
495 generic_type: None,
496 array_length: None,
497 count: None,
498 }
499}
500
501#[cfg(test)]
502mod tests {
503 use super::super::field_decoder::{Decoder, FieldMetadata};
504 use super::*;
505
506 #[test]
509 fn parse_type_simple() {
510 let ft = parse_type("int32");
511 assert_eq!(ft.base_type, "int32");
512 assert!(!ft.pointer);
513 assert!(ft.generic_type.is_none());
514 assert!(ft.array_length.is_none());
515 assert!(ft.count.is_none());
516 }
517
518 #[test]
519 fn parse_type_pointer() {
520 let ft = parse_type("CBaseEntity*");
521 assert_eq!(ft.base_type, "CBaseEntity");
522 assert!(ft.pointer);
523 }
524
525 #[test]
526 fn parse_type_array_numeric() {
527 let ft = parse_type("int32[4]");
528 assert_eq!(ft.base_type, "int32");
529 assert_eq!(ft.array_length, Some(4));
530 assert!(ft.count.is_none());
531 }
532
533 #[test]
534 fn parse_type_array_symbolic() {
535 let ft = parse_type("int32[MAX_ABILITIES]");
536 assert_eq!(ft.base_type, "int32");
537 assert!(ft.array_length.is_none());
538 assert_eq!(ft.count.as_deref(), Some("MAX_ABILITIES"));
539 }
540
541 #[test]
542 fn parse_type_generic() {
543 let ft = parse_type("CNetworkUtlVectorBase< int32 >");
544 assert_eq!(ft.base_type, "CNetworkUtlVectorBase");
545 let inner = ft.generic_type.as_ref().unwrap();
546 assert_eq!(inner.base_type, "int32");
547 }
548
549 #[test]
550 fn parse_type_generic_nested() {
551 let ft = parse_type("CHandle< CBaseEntity >");
552 assert_eq!(ft.base_type, "CHandle");
553 assert_eq!(ft.generic_type.as_ref().unwrap().base_type, "CBaseEntity");
554 }
555
556 #[test]
557 fn parse_type_whitespace_trimming() {
558 let ft = parse_type(" float32 ");
559 assert_eq!(ft.base_type, "float32");
560 }
561
562 #[test]
563 fn parse_type_empty_string() {
564 let ft = parse_type("");
565 assert_eq!(ft.base_type, "");
566 assert!(!ft.pointer);
567 }
568
569 #[test]
570 fn parse_type_complex_all_fields() {
571 let ft = parse_type("uint32[16]");
572 assert_eq!(ft.base_type, "uint32");
573 assert!(!ft.pointer);
574 assert!(ft.generic_type.is_none());
575 assert_eq!(ft.array_length, Some(16));
576 assert!(ft.count.is_none());
577 }
578
579 fn make_field(name: &str, send_node: Option<&str>) -> Arc<SerializerField> {
582 Arc::new(SerializerField {
583 var_type: String::new(),
584 var_name: name.to_string(),
585 bit_count: None,
586 low_value: None,
587 high_value: None,
588 encode_flags: None,
589 field_serializer_name: None,
590 send_node: send_node.map(String::from),
591 var_encoder: None,
592 field_serializer: None,
593 field_type: parse_type(""),
594 metadata: FieldMetadata {
595 decoder: Decoder::U64,
596 special: None,
597 },
598 })
599 }
600
601 #[test]
602 fn resolve_field_key_found() {
603 let ser = Serializer {
604 name: "test".to_string(),
605 fields: vec![make_field("m_iHealth", None)],
606 };
607 assert!(ser.resolve_field_key("m_iHealth").is_some());
608 }
609
610 #[test]
611 fn resolve_field_key_not_found() {
612 let ser = Serializer {
613 name: "test".to_string(),
614 fields: vec![make_field("m_iHealth", None)],
615 };
616 assert!(ser.resolve_field_key("m_iMana").is_none());
617 }
618
619 #[test]
620 fn field_name_roundtrip() {
621 let ser = Serializer {
622 name: "test".to_string(),
623 fields: vec![make_field("m_iHealth", None), make_field("m_iMana", None)],
624 };
625 let key = ser.resolve_field_key("m_iMana").unwrap();
626 let name = ser.field_name_for_key(key).unwrap();
627 assert_eq!(name, "m_iMana");
628 }
629
630 #[test]
631 fn resolve_with_send_node() {
632 let ser = Serializer {
633 name: "test".to_string(),
634 fields: vec![make_field("m_bPaused", Some("m_pGameRules"))],
635 };
636 let key = ser.resolve_field_key("m_pGameRules.m_bPaused");
637 assert!(key.is_some());
638 let name = ser.field_name_for_key(key.unwrap()).unwrap();
639 assert_eq!(name, "m_pGameRules.m_bPaused");
640 }
641}