1mod archive;
31mod context;
32mod error;
33mod serialization;
34
35#[cfg(test)]
36mod tests;
37
38pub use archive::{ArchiveReader, ArchiveType, ArchiveWriter, SaveGameArchiveType};
39pub use context::{PropertySchemas, Scope, Types};
40pub use error::{Error, ParseError};
41
42use byteorder::{ReadBytesExt, WriteBytesExt, LE};
43use context::SaveGameArchive;
44use std::{
45 borrow::Cow,
46 cell::RefCell,
47 io::{Cursor, Read, Seek, Write},
48 rc::Rc,
49};
50
51use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
52
53#[cfg(feature = "tracing")]
54use tracing::instrument;
55
56type Result<T, E = Error> = std::result::Result<T, E>;
57
58struct SeekReader<R: Read> {
59 inner: R,
60 buffer: Vec<u8>,
61 position: usize,
62 reached_eof: bool,
63}
64
65impl<R: Read> SeekReader<R> {
66 fn new(inner: R) -> Self {
67 Self {
68 inner,
69 buffer: vec![],
70 position: 0,
71 reached_eof: false,
72 }
73 }
74 fn position(&self) -> usize {
75 self.position
76 }
77 fn ensure_buffered(&mut self, min_bytes: usize) -> std::io::Result<()> {
78 if self.reached_eof {
79 return Ok(());
80 }
81
82 let available = self.buffer.len().saturating_sub(self.position);
83 if available >= min_bytes {
84 return Ok(());
85 }
86
87 let needed = min_bytes - available;
88
89 self.buffer.reserve(needed);
91
92 let mut temp_buf = vec![0; needed];
94 let mut total_read = 0;
95
96 while total_read < needed && !self.reached_eof {
97 let bytes_read = self.inner.read(&mut temp_buf[total_read..])?;
98 if bytes_read == 0 {
99 self.reached_eof = true;
100 break;
101 }
102 total_read += bytes_read;
103 }
104
105 self.buffer.extend_from_slice(&temp_buf[..total_read]);
107
108 Ok(())
109 }
110}
111impl<R: Read> Seek for SeekReader<R> {
112 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
119 let new_position = match pos {
120 std::io::SeekFrom::Start(offset) => offset as i64,
121 std::io::SeekFrom::Current(offset) => self.position as i64 + offset,
122 std::io::SeekFrom::End(_) => {
123 return Err(std::io::Error::new(
124 std::io::ErrorKind::Unsupported,
125 "Seeking from end is not supported for non-seekable readers",
126 ));
127 }
128 };
129
130 if new_position < 0 {
131 return Err(std::io::Error::new(
132 std::io::ErrorKind::InvalidInput,
133 "Cannot seek to a negative position",
134 ));
135 }
136
137 let new_position = new_position as usize;
138
139 if new_position <= self.buffer.len() {
141 self.position = new_position;
142 return Ok(new_position as u64);
143 }
144
145 let bytes_needed = new_position - self.buffer.len();
147 self.position = self.buffer.len();
148
149 let mut temp_buf = vec![0; bytes_needed.min(8192)];
151 let mut remaining = bytes_needed;
152
153 while remaining > 0 {
154 let to_read = remaining.min(temp_buf.len());
155 let bytes_read = self.read(&mut temp_buf[..to_read])?;
156 if bytes_read == 0 {
157 return Ok(self.position as u64);
159 }
160 remaining -= bytes_read;
161 }
162
163 Ok(new_position as u64)
164 }
165}
166impl<R: Read> Read for SeekReader<R> {
167 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
171 if buf.is_empty() {
172 return Ok(0);
173 }
174
175 self.ensure_buffered(1)?;
177
178 let available = self.buffer.len() - self.position;
180 if available == 0 {
181 return Ok(0); }
183
184 let to_copy = buf.len().min(available);
185 buf[..to_copy].copy_from_slice(&self.buffer[self.position..self.position + to_copy]);
186 self.position += to_copy;
187
188 Ok(to_copy)
189 }
190}
191
192#[cfg_attr(feature = "tracing", instrument(skip_all))]
193fn read_optional_uuid<A: ArchiveReader>(ar: &mut A) -> Result<Option<FGuid>> {
194 Ok(if ar.read_u8()? > 0 {
195 Some(FGuid::read(ar)?)
196 } else {
197 None
198 })
199}
200fn write_optional_uuid<A: ArchiveWriter>(ar: &mut A, id: Option<FGuid>) -> Result<()> {
201 if let Some(id) = id {
202 ar.write_u8(1)?;
203 id.write(ar)?;
204 } else {
205 ar.write_u8(0)?;
206 }
207 Ok(())
208}
209
210#[cfg_attr(feature = "tracing", instrument(skip_all, ret))]
211fn read_string<A: ArchiveReader>(ar: &mut A) -> Result<String> {
212 let len = ar.read_i32::<LE>()?;
213 if len < 0 {
214 let chars = read_array((-len) as u32, ar, |r| Ok(r.read_u16::<LE>()?))?;
215 let length = chars.iter().position(|&c| c == 0).unwrap_or(chars.len());
216 Ok(String::from_utf16(&chars[..length]).unwrap())
217 } else {
218 let mut chars = vec![0; len as usize];
219 ar.read_exact(&mut chars)?;
220 let length = chars.iter().position(|&c| c == 0).unwrap_or(chars.len());
221 Ok(String::from_utf8_lossy(&chars[..length]).into_owned())
222 }
223}
224#[cfg_attr(feature = "tracing", instrument(skip(ar)))]
225fn write_string<A: ArchiveWriter>(ar: &mut A, string: &str) -> Result<()> {
226 if string.is_empty() {
227 ar.write_u32::<LE>(0)?;
228 } else {
229 write_string_trailing(ar, string, None)?;
230 }
231 Ok(())
232}
233
234#[cfg_attr(feature = "tracing", instrument(skip_all))]
235fn read_string_trailing<A: ArchiveReader>(ar: &mut A) -> Result<(String, Vec<u8>)> {
236 let len = ar.read_i32::<LE>()?;
237 if len < 0 {
238 let bytes = (-len) as usize * 2;
239 let mut chars = vec![];
240 let mut rest = vec![];
241 let mut read = 0;
242 while read < bytes {
243 let next = ar.read_u16::<LE>()?;
244 read += 2;
245 if next == 0 {
246 rest.extend(next.to_le_bytes());
247 break;
248 } else {
249 chars.push(next);
250 }
251 }
252 while read < bytes {
253 rest.push(ar.read_u8()?);
254 read += 1;
255 }
256 Ok((String::from_utf16(&chars).unwrap(), rest))
257 } else {
258 let bytes = len as usize;
259 let mut chars = vec![];
260 let mut rest = vec![];
261 let mut read = 0;
262 while read < bytes {
263 let next = ar.read_u8()?;
264 read += 1;
265 if next == 0 {
266 rest.push(next);
267 break;
268 } else {
269 chars.push(next);
270 }
271 }
272 while read < bytes {
273 rest.push(ar.read_u8()?);
274 read += 1;
275 }
276 Ok((String::from_utf8(chars).unwrap(), rest))
277 }
278}
279#[cfg_attr(feature = "tracing", instrument(skip_all))]
280fn write_string_trailing<A: ArchiveWriter>(
281 ar: &mut A,
282 string: &str,
283 trailing: Option<&[u8]>,
284) -> Result<()> {
285 if string.is_empty() || string.is_ascii() {
286 ar.write_u32::<LE>((string.len() + trailing.map(|t| t.len()).unwrap_or(1)) as u32)?;
287 ar.write_all(string.as_bytes())?;
288 ar.write_all(trailing.unwrap_or(&[0]))?;
289 } else {
290 let chars: Vec<u16> = string.encode_utf16().collect();
291 ar.write_i32::<LE>(-((chars.len() + trailing.map(|t| t.len()).unwrap_or(2) / 2) as i32))?;
292 for c in chars {
293 ar.write_u16::<LE>(c)?;
294 }
295 ar.write_all(trailing.unwrap_or(&[0, 0]))?;
296 }
297 Ok(())
298}
299
300#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
301pub struct PropertyKey(pub u32, pub String);
302impl From<String> for PropertyKey {
303 fn from(value: String) -> Self {
304 Self(0, value)
305 }
306}
307impl From<&str> for PropertyKey {
308 fn from(value: &str) -> Self {
309 Self(0, value.to_string())
310 }
311}
312
313struct PropertyKeyVisitor;
314impl Visitor<'_> for PropertyKeyVisitor {
315 type Value = PropertyKey;
316 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
317 formatter.write_str(
318 "a property key in the form of key name and index seperated by '_' e.g. property_2",
319 )
320 }
321 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
322 where
323 E: serde::de::Error,
324 {
325 let (name_str, index_str) = value
326 .rsplit_once('_')
327 .ok_or_else(|| serde::de::Error::custom("property key does not contain a '_'"))?;
328 let index: u32 = index_str.parse().map_err(serde::de::Error::custom)?;
329
330 Ok(PropertyKey(index, name_str.to_string()))
331 }
332}
333impl<'de> Deserialize<'de> for PropertyKey {
334 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
335 where
336 D: Deserializer<'de>,
337 {
338 deserializer.deserialize_str(PropertyKeyVisitor)
339 }
340}
341impl Serialize for PropertyKey {
342 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
343 where
344 S: Serializer,
345 {
346 serializer.serialize_str(&format!("{}_{}", self.1, self.0))
347 }
348}
349
350#[derive(Debug, Clone, Default, PartialEq, Serialize)]
351#[serde(bound(serialize = "T::ObjectRef: Serialize"))]
352pub struct Properties<T: ArchiveType = SaveGameArchiveType>(
353 pub indexmap::IndexMap<PropertyKey, Property<T>>,
354);
355impl<T: ArchiveType> Properties<T> {
356 pub fn insert(&mut self, k: impl Into<PropertyKey>, v: Property<T>) -> Option<Property<T>> {
357 self.0.insert(k.into(), v)
358 }
359}
360impl<K, T: ArchiveType> std::ops::Index<K> for Properties<T>
361where
362 K: Into<PropertyKey>,
363{
364 type Output = Property<T>;
365 fn index(&self, index: K) -> &Self::Output {
366 self.0.index(&index.into())
367 }
368}
369impl<K, T: ArchiveType> std::ops::IndexMut<K> for Properties<T>
370where
371 K: Into<PropertyKey>,
372{
373 fn index_mut(&mut self, index: K) -> &mut Property<T> {
374 self.0.index_mut(&index.into())
375 }
376}
377impl<'a, T: ArchiveType> IntoIterator for &'a Properties<T> {
378 type Item = <&'a indexmap::IndexMap<PropertyKey, Property<T>> as IntoIterator>::Item;
379 type IntoIter = <&'a indexmap::IndexMap<PropertyKey, Property<T>> as IntoIterator>::IntoIter;
380 fn into_iter(self) -> Self::IntoIter {
381 self.0.iter()
382 }
383}
384
385#[cfg_attr(feature = "tracing", instrument(skip_all))]
386pub fn read_properties_until_none<T: ArchiveType, A: ArchiveReader<ArchiveType = T>>(
387 ar: &mut A,
388) -> Result<Properties<T>> {
389 let mut properties = Properties::default();
390 while let Some((name, prop)) = read_property(ar)? {
391 properties.insert(name, prop);
392 }
393 Ok(properties)
394}
395#[cfg_attr(feature = "tracing", instrument(skip_all))]
396pub fn write_properties_none_terminated<T: ArchiveType, A: ArchiveWriter<ArchiveType = T>>(
397 ar: &mut A,
398 properties: &Properties<T>,
399) -> Result<()> {
400 for p in properties {
401 write_property(p, ar)?;
402 }
403 ar.write_string("None")?;
404 Ok(())
405}
406
407#[cfg_attr(feature = "tracing", instrument(skip_all))]
408fn read_property<T: ArchiveType, A: ArchiveReader<ArchiveType = T>>(
409 ar: &mut A,
410) -> Result<Option<(PropertyKey, Property<T>)>> {
411 if let Some(mut tag) = PropertyTagFull::read(ar)? {
412 let tag_name = tag.name.to_string();
413 ar.scope().push(&tag_name);
414 let result = Property::read(ar, tag.clone());
415 ar.scope().pop();
416 let (value, updated_tag_data) = result?;
417
418 if let Some(new_data) = updated_tag_data {
421 tag.data = new_data;
422 }
423
424 let key = PropertyKey(tag.index, tag_name.clone());
425
426 ar.scope().push(&tag_name);
428 ar.record_schema(ar.path().to_string(), tag.into_partial());
429 ar.scope().pop();
430
431 Ok(Some((key, value)))
432 } else {
433 Ok(None)
434 }
435}
436#[cfg_attr(feature = "tracing", instrument(skip_all))]
437fn write_property<T: ArchiveType, A: ArchiveWriter<ArchiveType = T>>(
438 prop: (&PropertyKey, &Property<T>),
439 ar: &mut A,
440) -> Result<()> {
441 ar.scope().push(&prop.0 .1);
442 let result = (|| {
443 let tag_partial = ar
444 .get_schema(&ar.path())
445 .ok_or_else(|| Error::MissingPropertySchema(ar.path()))?;
446
447 let mut tag = tag_partial.into_full(&prop.0 .1, 0, prop.0 .0, prop.1);
448
449 tag.size = 0;
451 let tag_start = ar.stream_position()?;
452 tag.write(ar)?;
453 let data_start = ar.stream_position()?;
454
455 prop.1.write(ar, &tag)?;
457 let data_end = ar.stream_position()?;
458
459 let size = (data_end - data_start) as u32;
461 tag.size = size;
462
463 ar.seek(std::io::SeekFrom::Start(tag_start))?;
465 tag.write(ar)?;
466
467 ar.seek(std::io::SeekFrom::Start(data_end))?;
469 Ok(())
470 })();
471 ar.scope().pop();
472 result
473}
474
475#[cfg_attr(feature = "tracing", instrument(skip_all))]
476fn read_array<T, F, A: ArchiveReader>(length: u32, ar: &mut A, f: F) -> Result<Vec<T>>
477where
478 F: Fn(&mut A) -> Result<T>,
479{
480 (0..length).map(|_| f(ar)).collect()
481}
482
483#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
484pub struct FGuid {
485 a: u32,
486 b: u32,
487 c: u32,
488 d: u32,
489}
490
491impl FGuid {
492 pub fn new(a: u32, b: u32, c: u32, d: u32) -> Self {
493 Self { a, b, c, d }
494 }
495
496 pub fn nil() -> Self {
497 Self::default()
498 }
499
500 pub fn is_nil(&self) -> bool {
501 self.a == 0 && self.b == 0 && self.c == 0 && self.d == 0
502 }
503
504 pub fn parse_str(s: &str) -> Result<Self, Error> {
505 let s = s.replace("-", "");
506 if s.len() != 32 {
507 return Err(Error::Other("Invalid GUID string length".into()));
508 }
509
510 let parse_hex_u32 = |start: usize| -> Result<u32, Error> {
511 u32::from_str_radix(&s[start..start + 8], 16)
512 .map_err(|_| Error::Other("Invalid hex in GUID".into()))
513 };
514
515 Ok(Self {
516 a: parse_hex_u32(0)?,
517 b: parse_hex_u32(8)?,
518 c: parse_hex_u32(16)?,
519 d: parse_hex_u32(24)?,
520 })
521 }
522}
523
524impl std::fmt::Display for FGuid {
525 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
526 let b = self.b.to_le_bytes();
527 let c = self.c.to_le_bytes();
528
529 write!(
530 f,
531 "{:08x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:08x}",
532 self.a, b[3], b[2], b[1], b[0], c[3], c[2], c[1], c[0], self.d,
533 )
534 }
535}
536
537impl Serialize for FGuid {
538 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
539 where
540 S: Serializer,
541 {
542 serializer.serialize_str(&self.to_string())
543 }
544}
545
546impl<'de> Deserialize<'de> for FGuid {
547 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
548 where
549 D: Deserializer<'de>,
550 {
551 struct FGuidVisitor;
552
553 impl<'de> Visitor<'de> for FGuidVisitor {
554 type Value = FGuid;
555
556 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
557 formatter.write_str("a UUID string in format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
558 }
559
560 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
561 where
562 E: serde::de::Error,
563 {
564 FGuid::parse_str(value).map_err(|e| E::custom(format!("Invalid UUID: {}", e)))
565 }
566 }
567
568 deserializer.deserialize_str(FGuidVisitor)
569 }
570}
571
572impl FGuid {
573 #[cfg_attr(feature = "tracing", instrument(name = "FGuid_read", skip_all))]
574 fn read<A: ArchiveReader>(ar: &mut A) -> Result<FGuid> {
575 Ok(Self {
576 a: ar.read_u32::<LE>()?,
577 b: ar.read_u32::<LE>()?,
578 c: ar.read_u32::<LE>()?,
579 d: ar.read_u32::<LE>()?,
580 })
581 }
582}
583impl FGuid {
584 #[cfg_attr(feature = "tracing", instrument(name = "FGuid_write", skip_all))]
585 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
586 ar.write_u32::<LE>(self.a)?;
587 ar.write_u32::<LE>(self.b)?;
588 ar.write_u32::<LE>(self.c)?;
589 ar.write_u32::<LE>(self.d)?;
590 Ok(())
591 }
592}
593
594#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
595struct PropertyTagFull<'a> {
596 name: Cow<'a, str>,
597 id: Option<FGuid>,
598 size: u32,
599 index: u32,
600 data: PropertyTagDataFull,
601}
602#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
603enum PropertyTagDataFull {
604 Array(std::boxed::Box<PropertyTagDataFull>),
605 Struct {
606 struct_type: StructType,
607 id: FGuid,
608 },
609 Set {
610 key_type: std::boxed::Box<PropertyTagDataFull>,
611 },
612 Map {
613 key_type: std::boxed::Box<PropertyTagDataFull>,
614 value_type: std::boxed::Box<PropertyTagDataFull>,
615 },
616 Byte(Option<String>),
617 Enum(String, Option<String>),
618 Bool(bool),
619 Other(PropertyType),
620}
621#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
622pub struct PropertyTagPartial {
623 #[serde(skip_serializing_if = "Option::is_none")]
624 pub id: Option<FGuid>,
625 pub data: PropertyTagDataPartial,
626}
627#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
628pub enum PropertyTagDataPartial {
629 Array(std::boxed::Box<PropertyTagDataPartial>),
630 Struct {
631 struct_type: StructType,
632 id: FGuid,
633 },
634 Set {
635 key_type: std::boxed::Box<PropertyTagDataPartial>,
636 },
637 Map {
638 key_type: std::boxed::Box<PropertyTagDataPartial>,
639 value_type: std::boxed::Box<PropertyTagDataPartial>,
640 },
641 Byte(Option<String>),
642 Enum(String, Option<String>),
643 Other(PropertyType),
644}
645impl PropertyTagDataFull {
646 fn into_partial(self) -> PropertyTagDataPartial {
647 match self {
648 Self::Array(inner) => PropertyTagDataPartial::Array(inner.into_partial().into()),
649 Self::Struct { struct_type, id } => PropertyTagDataPartial::Struct { struct_type, id },
650 Self::Set { key_type } => PropertyTagDataPartial::Set {
651 key_type: key_type.into_partial().into(),
652 },
653 Self::Map {
654 key_type,
655 value_type,
656 } => PropertyTagDataPartial::Map {
657 key_type: key_type.into_partial().into(),
658 value_type: value_type.into_partial().into(),
659 },
660 Self::Byte(a) => PropertyTagDataPartial::Byte(a),
661 Self::Enum(a, b) => PropertyTagDataPartial::Enum(a, b),
662 Self::Bool(_) => PropertyTagDataPartial::Other(PropertyType::BoolProperty),
663 Self::Other(t) => PropertyTagDataPartial::Other(t),
664 }
665 }
666}
667impl PropertyTagDataPartial {
668 fn into_full<T: ArchiveType>(self, prop: &Property<T>) -> PropertyTagDataFull {
669 match self {
670 Self::Array(inner) => PropertyTagDataFull::Array(inner.into_full(prop).into()),
671 Self::Struct { struct_type, id } => PropertyTagDataFull::Struct { struct_type, id },
672 Self::Set { key_type } => PropertyTagDataFull::Set {
673 key_type: key_type.into_full(prop).into(),
674 },
675 Self::Map {
676 key_type,
677 value_type,
678 } => PropertyTagDataFull::Map {
679 key_type: key_type.into_full(prop).into(),
680 value_type: value_type.into_full(prop).into(),
681 },
682 Self::Byte(a) => PropertyTagDataFull::Byte(a),
683 Self::Enum(a, b) => PropertyTagDataFull::Enum(a, b),
684 Self::Other(PropertyType::BoolProperty) => PropertyTagDataFull::Bool(match prop {
685 Property::Bool(value) => *value,
686 _ => false,
687 }),
688 Self::Other(t) => PropertyTagDataFull::Other(t),
689 }
690 }
691}
692
693impl PropertyTagDataFull {
694 fn basic_type(&self) -> PropertyType {
695 match self {
696 Self::Array(_) => PropertyType::ArrayProperty,
697 Self::Struct { .. } => PropertyType::StructProperty,
698 Self::Set { .. } => PropertyType::SetProperty,
699 Self::Map { .. } => PropertyType::MapProperty,
700 Self::Byte(_) => PropertyType::ByteProperty,
701 Self::Enum(_, _) => PropertyType::EnumProperty,
702 Self::Bool(_) => PropertyType::BoolProperty,
703 Self::Other(property_type) => *property_type,
704 }
705 }
706 fn has_raw_struct(&self) -> bool {
707 match self {
708 Self::Array(inner) => inner.has_raw_struct(),
709 Self::Struct { struct_type, .. } => struct_type.raw(),
710 Self::Set { key_type } => key_type.has_raw_struct(),
711 Self::Map {
712 key_type,
713 value_type,
714 } => key_type.has_raw_struct() || value_type.has_raw_struct(),
715 Self::Byte(_) => false,
716 Self::Enum(_, _) => false,
717 Self::Bool(_) => false,
718 Self::Other(_) => false,
719 }
720 }
721 fn from_type(inner_type: PropertyType, struct_type: Option<StructType>) -> Self {
722 match inner_type {
723 PropertyType::BoolProperty => Self::Bool(false),
724 PropertyType::ByteProperty => Self::Byte(None),
725 PropertyType::EnumProperty => Self::Enum("".to_string(), None),
726 PropertyType::ArrayProperty => unreachable!("array of array is invalid"),
727 PropertyType::SetProperty => unreachable!("array of set is invalid"),
728 PropertyType::MapProperty => unreachable!("array of map is invalid"),
729 PropertyType::StructProperty => Self::Struct {
730 struct_type: struct_type.unwrap_or(StructType::Struct(None)),
731 id: Default::default(),
732 },
733 other => Self::Other(other),
734 }
735 }
736}
737bitflags::bitflags! {
738 #[derive(Debug, Clone, Copy)]
739 struct EPropertyTagFlags : u8 {
740 const None = 0x00;
741 const HasArrayIndex = 0x01;
742 const HasPropertyGuid = 0x02;
743 const HasPropertyExtensions = 0x04;
744 const HasBinaryOrNativeSerialize = 0x08;
745 const BoolTrue = 0x10;
746 }
747}
748impl PropertyTagPartial {
749 fn into_full<'a, T: ArchiveType>(
750 self,
751 name: &'a str,
752 size: u32,
753 index: u32,
754 prop: &Property<T>,
755 ) -> PropertyTagFull<'a> {
756 PropertyTagFull {
757 name: name.into(),
758 id: self.id,
759 size,
760 index,
761 data: self.data.into_full(prop),
762 }
763 }
764}
765impl PropertyTagFull<'_> {
766 fn into_partial(self) -> PropertyTagPartial {
767 PropertyTagPartial {
768 id: self.id,
769 data: self.data.into_partial(),
770 }
771 }
772 #[cfg_attr(feature = "tracing", instrument(name = "PropertyTag_read", skip_all))]
773 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Option<Self>> {
774 let name = ar.read_string()?;
775 if name == "None" {
776 return Ok(None);
777 }
778 if ar.version().property_tag() {
779 let root_node = read_node(ar)?;
780
781 #[derive(Default, Debug)]
782 struct Node {
783 name: String,
784 inner: Vec<Node>,
785 }
786 fn read_node<A: ArchiveReader>(ar: &mut A) -> Result<Node> {
787 Ok(Node {
788 name: ar.read_string()?,
789 inner: read_array(ar.read_u32::<LE>()?, ar, read_node)?,
790 })
791 }
792 fn read_path(node: &Node) -> Result<String> {
793 let name = node;
794 assert_eq!(1, name.inner.len());
795 let package = &name.inner[0];
796 assert_eq!(0, package.inner.len());
797 Ok(format!("{}.{}", package.name, name.name))
798 }
799 fn read_type(node: &Node, flags: EPropertyTagFlags) -> Result<PropertyTagDataFull> {
800 Ok(match node.name.as_str() {
801 "ArrayProperty" => {
802 PropertyTagDataFull::Array(read_type(&node.inner[0], flags)?.into())
803 }
804 "StructProperty" => {
805 let raw = flags.contains(EPropertyTagFlags::HasBinaryOrNativeSerialize);
806 let struct_type = StructType::from_full(&read_path(&node.inner[0])?, raw);
807 let id = match node.inner.len() {
808 1 => Default::default(),
809 2 => FGuid::parse_str(&node.inner[1].name)?,
810 _ => unimplemented!(),
811 };
812 PropertyTagDataFull::Struct { struct_type, id }
813 }
814 "SetProperty" => PropertyTagDataFull::Set {
815 key_type: read_type(&node.inner[0], flags)?.into(),
816 },
817 "MapProperty" => PropertyTagDataFull::Map {
818 key_type: read_type(&node.inner[0], flags)?.into(),
819 value_type: read_type(&node.inner[1], flags)?.into(),
820 },
821 "ByteProperty" => {
822 let inner = match node.inner.len() {
823 0 => None,
824 1 => Some(read_path(&node.inner[0])?),
825 _ => unimplemented!(),
826 };
827 PropertyTagDataFull::Byte(inner)
828 }
829 "EnumProperty" => {
830 assert_eq!(2, node.inner.len());
831 let inner = read_path(&node.inner[0])?;
832 let container = &node.inner[1];
833 assert_eq!(0, container.inner.len());
834 PropertyTagDataFull::Enum(inner, Some(container.name.to_owned()))
835 }
836 "BoolProperty" => {
837 PropertyTagDataFull::Bool(flags.contains(EPropertyTagFlags::BoolTrue))
838 }
839 other => {
840 assert_eq!(0, node.inner.len());
841 PropertyTagDataFull::Other(PropertyType::try_from(other)?)
842 }
843 })
844 }
845
846 let size = ar.read_u32::<LE>()?;
847
848 let flags = EPropertyTagFlags::from_bits(ar.read_u8()?)
849 .ok_or_else(|| error::Error::Other("unknown EPropertyTagFlags bits".into()))?;
850
851 let mut tag = Self {
852 name: name.into(),
853 size,
854 index: 0,
855 id: None,
856 data: read_type(&root_node, flags)?,
857 };
858
859 if flags.contains(EPropertyTagFlags::HasArrayIndex) {
860 tag.index = ar.read_u32::<LE>()?;
861 }
862 if flags.contains(EPropertyTagFlags::HasPropertyGuid) {
863 tag.id = Some(FGuid::read(ar)?);
864 }
865 if flags.contains(EPropertyTagFlags::HasPropertyExtensions) {
866 unimplemented!();
867 }
868
869 Ok(Some(tag))
870 } else {
871 ar.scope().push(&name.clone());
872 let result = (|| {
873 let type_ = PropertyType::read(ar)?;
874 let size = ar.read_u32::<LE>()?;
875 let index = ar.read_u32::<LE>()?;
876 let data = match type_ {
877 PropertyType::BoolProperty => {
878 let value = ar.read_u8()? > 0;
879 PropertyTagDataFull::Bool(value)
880 }
881 PropertyType::IntProperty
882 | PropertyType::Int8Property
883 | PropertyType::Int16Property
884 | PropertyType::Int64Property
885 | PropertyType::UInt8Property
886 | PropertyType::UInt16Property
887 | PropertyType::UInt32Property
888 | PropertyType::UInt64Property
889 | PropertyType::FloatProperty
890 | PropertyType::DoubleProperty
891 | PropertyType::StrProperty
892 | PropertyType::ObjectProperty
893 | PropertyType::FieldPathProperty
894 | PropertyType::SoftObjectProperty
895 | PropertyType::NameProperty
896 | PropertyType::TextProperty
897 | PropertyType::DelegateProperty
898 | PropertyType::MulticastDelegateProperty
899 | PropertyType::MulticastInlineDelegateProperty
900 | PropertyType::MulticastSparseDelegateProperty => {
901 PropertyTagDataFull::Other(type_)
902 }
903 PropertyType::ByteProperty => {
904 let enum_type = ar.read_string()?;
905 PropertyTagDataFull::Byte((enum_type != "None").then_some(enum_type))
906 }
907 PropertyType::EnumProperty => {
908 let enum_type = ar.read_string()?;
909 PropertyTagDataFull::Enum(enum_type, None)
910 }
911 PropertyType::ArrayProperty => {
912 let inner_type = PropertyType::read(ar)?;
913
914 PropertyTagDataFull::Array(std::boxed::Box::new(
915 PropertyTagDataFull::from_type(inner_type, None),
916 ))
917 }
918 PropertyType::SetProperty => {
919 let key_type = PropertyType::read(ar)?;
920 let key_struct_type = match key_type {
921 PropertyType::StructProperty => {
922 Some(ar.get_type_or(&StructType::Guid)?)
923 }
924 _ => None,
925 };
926
927 let key_type =
928 PropertyTagDataFull::from_type(key_type, key_struct_type.clone())
929 .into();
930
931 PropertyTagDataFull::Set { key_type }
932 }
933 PropertyType::MapProperty => {
934 let key_type = PropertyType::read(ar)?;
935 let key_struct_type = match key_type {
936 PropertyType::StructProperty => {
937 ar.scope().push("Key");
938 let result = ar.get_type_or(&StructType::Guid);
939 ar.scope().pop();
940 Some(result?)
941 }
942 _ => None,
943 };
944 let value_type = PropertyType::read(ar)?;
945 let value_struct_type = match value_type {
946 PropertyType::StructProperty => {
947 ar.scope().push("Value");
948 let result = ar.get_type_or(&StructType::Struct(None));
949 ar.scope().pop();
950 Some(result?)
951 }
952 _ => None,
953 };
954
955 let key_type =
956 PropertyTagDataFull::from_type(key_type, key_struct_type.clone())
957 .into();
958 let value_type =
959 PropertyTagDataFull::from_type(value_type, value_struct_type.clone())
960 .into();
961
962 PropertyTagDataFull::Map {
963 key_type,
964 value_type,
965 }
966 }
967 PropertyType::StructProperty => {
968 let struct_type = StructType::read(ar)?;
969 let struct_id = FGuid::read(ar)?;
970 PropertyTagDataFull::Struct {
971 struct_type,
972 id: struct_id,
973 }
974 }
975 };
976 let id = if ar.version().property_guid() {
977 read_optional_uuid(ar)?
978 } else {
979 None
980 };
981 Ok(Some(Self {
982 name: name.into(),
983 size,
984 index,
985 id,
986 data,
987 }))
988 })();
989 ar.scope().pop();
990 result
991 }
992 }
993 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
994 ar.write_string(&self.name)?;
995
996 if ar.version().property_tag() {
997 fn write_node<A: ArchiveWriter>(
998 ar: &mut A,
999 name: &str,
1000 inner_count: u32,
1001 ) -> Result<()> {
1002 ar.write_string(name)?;
1003 ar.write_u32::<LE>(inner_count)?;
1004 Ok(())
1005 }
1006 fn write_full_type<A: ArchiveWriter>(ar: &mut A, full_type: &str) -> Result<()> {
1007 let (a, b) = full_type.split_once('.').unwrap(); write_node(ar, b, 1)?;
1009 write_node(ar, a, 0)?;
1010 Ok(())
1011 }
1012 fn write_nodes<A: ArchiveWriter>(
1013 ar: &mut A,
1014 flags: &mut EPropertyTagFlags,
1015 data: &PropertyTagDataFull,
1016 ) -> Result<()> {
1017 match data {
1018 PropertyTagDataFull::Array(inner) => {
1019 write_node(ar, "ArrayProperty", 1)?;
1020 write_nodes(ar, flags, inner)?;
1021 }
1022 PropertyTagDataFull::Struct { struct_type, id } => {
1023 write_node(ar, "StructProperty", if id.is_nil() { 1 } else { 2 })?;
1024 match struct_type {
1025 StructType::Struct(Some(_)) => {}
1026 _ => *flags |= EPropertyTagFlags::HasBinaryOrNativeSerialize,
1027 }
1028 write_full_type(ar, struct_type.full_str())?;
1029
1030 if !id.is_nil() {
1031 write_node(ar, &id.to_string(), 0)?;
1032 }
1033 }
1034 PropertyTagDataFull::Set { key_type } => {
1035 write_node(ar, "SetProperty", 1)?;
1036 write_nodes(ar, flags, key_type)?;
1037 }
1038 PropertyTagDataFull::Map {
1039 key_type,
1040 value_type,
1041 } => {
1042 write_node(ar, "MapProperty", 2)?;
1043 write_nodes(ar, flags, key_type)?;
1044 write_nodes(ar, flags, value_type)?;
1045 }
1046 PropertyTagDataFull::Byte(enum_type) => {
1047 write_node(ar, "ByteProperty", if enum_type.is_some() { 1 } else { 0 })?;
1048 if let Some(enum_type) = enum_type {
1049 write_full_type(ar, enum_type)?;
1050 }
1051 }
1052 PropertyTagDataFull::Enum(enum_type, container) => {
1053 write_node(ar, "EnumProperty", 2)?;
1054 write_full_type(ar, enum_type)?;
1055 write_node(ar, container.as_ref().unwrap(), 0)?;
1056 }
1057 PropertyTagDataFull::Bool(value) => {
1058 if *value {
1059 *flags |= EPropertyTagFlags::BoolTrue;
1060 }
1061 write_node(ar, "BoolProperty", 0)?;
1062 }
1063 PropertyTagDataFull::Other(property_type) => {
1064 write_node(ar, property_type.get_name(), 0)?;
1065 }
1066 }
1067 Ok(())
1068 }
1069
1070 let mut flags = EPropertyTagFlags::empty();
1071 write_nodes(ar, &mut flags, &self.data)?;
1072
1073 ar.write_u32::<LE>(self.size)?;
1074
1075 if self.index != 0 {
1076 flags |= EPropertyTagFlags::HasArrayIndex;
1077 }
1078 if self.id.is_some() {
1079 flags |= EPropertyTagFlags::HasPropertyGuid;
1080 }
1081
1082 ar.write_u8(flags.bits())?;
1083
1084 if self.index != 0 {
1085 ar.write_u32::<LE>(self.index)?;
1086 }
1087 } else {
1088 self.data.basic_type().write(ar)?;
1089 ar.write_u32::<LE>(self.size)?;
1090 ar.write_u32::<LE>(self.index)?;
1091 match &self.data {
1092 PropertyTagDataFull::Array(inner_type) => {
1093 inner_type.basic_type().write(ar)?;
1094 }
1095 PropertyTagDataFull::Struct { struct_type, id } => {
1096 struct_type.write(ar)?;
1097 id.write(ar)?;
1098 }
1099 PropertyTagDataFull::Set { key_type, .. } => {
1100 key_type.basic_type().write(ar)?;
1101 }
1102 PropertyTagDataFull::Map {
1103 key_type,
1104 value_type,
1105 ..
1106 } => {
1107 key_type.basic_type().write(ar)?;
1108 value_type.basic_type().write(ar)?;
1109 }
1110 PropertyTagDataFull::Byte(enum_type) => {
1111 ar.write_string(enum_type.as_deref().unwrap_or("None"))?;
1112 }
1113 PropertyTagDataFull::Enum(enum_type, _) => {
1114 ar.write_string(enum_type)?;
1115 }
1116 PropertyTagDataFull::Bool(value) => {
1117 ar.write_u8(*value as u8)?;
1118 }
1119 PropertyTagDataFull::Other(_) => {}
1120 }
1121 if ar.version().property_guid() {
1122 write_optional_uuid(ar, self.id)?;
1123 }
1124 }
1125 Ok(())
1126 }
1127}
1128
1129macro_rules! define_property_types {
1130 ($($variant:ident),* $(,)?) => {
1131 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1132 pub enum PropertyType {
1133 $($variant,)*
1134 }
1135
1136 impl PropertyType {
1137 fn get_name(&self) -> &str {
1138 match self {
1139 $(PropertyType::$variant => stringify!($variant),)*
1140 }
1141 }
1142
1143 #[cfg_attr(feature = "tracing", instrument(name = "PropertyType_read", skip_all))]
1144 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1145 Self::try_from(&ar.read_string()?)
1146 }
1147
1148 fn try_from(name: &str) -> Result<Self> {
1149 match name {
1150 $(stringify!($variant) => Ok(PropertyType::$variant),)*
1151 _ => Err(Error::UnknownPropertyType(format!("{name:?}"))),
1152 }
1153 }
1154
1155 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1156 ar.write_string(self.get_name())?;
1157 Ok(())
1158 }
1159 }
1160 };
1161}
1162
1163define_property_types! {
1164 IntProperty,
1165 Int8Property,
1166 Int16Property,
1167 Int64Property,
1168 UInt8Property,
1169 UInt16Property,
1170 UInt32Property,
1171 UInt64Property,
1172 FloatProperty,
1173 DoubleProperty,
1174 BoolProperty,
1175 ByteProperty,
1176 EnumProperty,
1177 ArrayProperty,
1178 ObjectProperty,
1179 StrProperty,
1180 FieldPathProperty,
1181 SoftObjectProperty,
1182 NameProperty,
1183 TextProperty,
1184 DelegateProperty,
1185 MulticastDelegateProperty,
1186 MulticastInlineDelegateProperty,
1187 MulticastSparseDelegateProperty,
1188 SetProperty,
1189 MapProperty,
1190 StructProperty,
1191}
1192
1193macro_rules! define_struct_types {
1194 ($(($package:literal, $variant:ident)),* $(,)?) => {
1195 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1196 pub enum StructType {
1197 $($variant,)*
1198 Raw(String),
1199 Struct(Option<String>),
1200 }
1201
1202 impl From<&str> for StructType {
1203 fn from(t: &str) -> Self {
1204 match t {
1205 $(stringify!($variant) => StructType::$variant,)*
1206 "Struct" => StructType::Struct(None),
1207 _ => StructType::Struct(Some(t.to_owned())),
1208 }
1209 }
1210 }
1211
1212 impl From<String> for StructType {
1213 fn from(t: String) -> Self {
1214 match t.as_str() {
1215 $(stringify!($variant) => StructType::$variant,)*
1216 "Struct" => StructType::Struct(None),
1217 _ => StructType::Struct(Some(t)),
1218 }
1219 }
1220 }
1221
1222 impl StructType {
1223 pub fn from_full(t: &str, raw: bool) -> Self {
1224 match t {
1225 $(concat!($package, ".", stringify!($variant)) => StructType::$variant,)*
1226 "/Script/CoreUObject.Struct" => StructType::Struct(None),
1227 _ if raw => StructType::Raw(t.to_owned()),
1228 _ => StructType::Struct(Some(t.to_owned())),
1229 }
1230 }
1231
1232 pub fn full_str(&self) -> &str {
1233 match self {
1234 $(StructType::$variant => concat!($package, ".", stringify!($variant)),)*
1235 StructType::Raw(t) => t,
1236 StructType::Struct(Some(t)) => t,
1237 _ => unreachable!(),
1238 }
1239 }
1240
1241 pub fn as_str(&self) -> &str {
1242 match self {
1243 $(StructType::$variant => stringify!($variant),)*
1244 StructType::Raw(t) => t,
1245 StructType::Struct(Some(t)) => t,
1246 _ => unreachable!(),
1247 }
1248 }
1249
1250 #[cfg_attr(feature = "tracing", instrument(name = "StructType_read", skip_all))]
1251 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1252 Ok(ar.read_string()?.into())
1253 }
1254
1255 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1256 ar.write_string(self.as_str())?;
1257 Ok(())
1258 }
1259
1260 fn raw(&self) -> bool {
1261 matches!(self, StructType::Raw(_))
1262 }
1263 }
1264 };
1265}
1266
1267define_struct_types! {
1268 ("/Script/CoreUObject", Guid),
1269 ("/Script/CoreUObject", DateTime),
1270 ("/Script/CoreUObject", Timespan),
1271 ("/Script/CoreUObject", Vector2D),
1272 ("/Script/CoreUObject", Vector),
1273 ("/Script/CoreUObject", Vector4),
1274 ("/Script/CoreUObject", IntVector),
1275 ("/Script/CoreUObject", Box),
1276 ("/Script/CoreUObject", Box2D),
1277 ("/Script/CoreUObject", IntPoint),
1278 ("/Script/CoreUObject", Quat),
1279 ("/Script/CoreUObject", Rotator),
1280 ("/Script/CoreUObject", LinearColor),
1281 ("/Script/CoreUObject", Color),
1282 ("/Script/CoreUObject", SoftObjectPath),
1283 ("/Script/CoreUObject", SoftClassPath),
1284 ("/Script/GameplayTags", GameplayTagContainer),
1285 ("/Script/Engine", UniqueNetIdRepl),
1286 ("/Script/Engine", KeyHandleMap),
1287 ("/Script/Engine", RichCurveKey),
1288 ("/Script/Engine", SkeletalMeshSamplingLODBuiltData),
1289 ("/Script/Engine", PerPlatformFloat),
1290}
1291
1292type DateTime = u64;
1293type Timespan = i64;
1294type Int8 = i8;
1295type Int16 = i16;
1296type Int = i32;
1297type Int64 = i64;
1298type UInt8 = u8;
1299type UInt16 = u16;
1300type UInt32 = u32;
1301type UInt64 = u64;
1302type Bool = bool;
1303type Enum = String;
1304
1305#[derive(Debug, Clone, Copy, PartialEq)]
1306pub struct Float(pub f32);
1307#[derive(Debug, Clone, Copy, PartialEq)]
1308pub struct Double(pub f64);
1309
1310impl std::fmt::Display for Float {
1311 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1312 self.0.fmt(f)
1313 }
1314}
1315impl std::fmt::Display for Double {
1316 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1317 self.0.fmt(f)
1318 }
1319}
1320impl From<f32> for Float {
1321 fn from(value: f32) -> Self {
1322 Self(value)
1323 }
1324}
1325impl From<f64> for Float {
1326 fn from(value: f64) -> Self {
1327 Self(value as f32)
1328 }
1329}
1330impl From<Float> for f32 {
1331 fn from(val: Float) -> Self {
1332 val.0
1333 }
1334}
1335impl From<Float> for f64 {
1336 fn from(val: Float) -> Self {
1337 val.0 as f64
1338 }
1339}
1340impl From<f32> for Double {
1341 fn from(value: f32) -> Self {
1342 Self(value as f64)
1343 }
1344}
1345impl From<f64> for Double {
1346 fn from(value: f64) -> Self {
1347 Self(value)
1348 }
1349}
1350impl From<Double> for f32 {
1351 fn from(val: Double) -> Self {
1352 val.0 as f32
1353 }
1354}
1355impl From<Double> for f64 {
1356 fn from(val: Double) -> Self {
1357 val.0
1358 }
1359}
1360impl<'de> Deserialize<'de> for Float {
1361 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1362 where
1363 D: Deserializer<'de>,
1364 {
1365 struct FloatVisitor;
1366
1367 impl serde::de::Visitor<'_> for FloatVisitor {
1368 type Value = f32;
1369
1370 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1371 formatter.write_str("a float or string representation of NaN/Infinity")
1372 }
1373 fn visit_i8<E>(self, value: i8) -> Result<Self::Value, E> {
1374 Ok(value as f32)
1375 }
1376 fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E> {
1377 Ok(value as f32)
1378 }
1379 fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E> {
1380 Ok(value as f32)
1381 }
1382 fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E> {
1383 Ok(value as f32)
1384 }
1385 fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E> {
1386 Ok(value as f32)
1387 }
1388 fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E> {
1389 Ok(value as f32)
1390 }
1391 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
1392 Ok(value as f32)
1393 }
1394 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
1395 Ok(value as f32)
1396 }
1397 fn visit_f32<E>(self, value: f32) -> Result<Self::Value, E> {
1398 Ok(value)
1399 }
1400 fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> {
1401 Ok(value as f32)
1402 }
1403 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
1404 where
1405 E: serde::de::Error,
1406 {
1407 match value {
1408 "NaN" => Ok(f32::NAN),
1409 "-NaN" => Ok(-f32::NAN),
1410 "Infinity" => Ok(f32::INFINITY),
1411 "-Infinity" => Ok(f32::NEG_INFINITY),
1412 _ => Err(E::custom(format!(
1413 "unxpected string value in place of float '{value}'"
1414 ))),
1415 }
1416 }
1417
1418 fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
1419 where
1420 E: serde::de::Error,
1421 {
1422 self.visit_str(&value)
1423 }
1424 }
1425
1426 let value = deserializer.deserialize_any(FloatVisitor)?;
1427 Ok(Self(value))
1428 }
1429}
1430impl<'de> Deserialize<'de> for Double {
1431 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1432 where
1433 D: Deserializer<'de>,
1434 {
1435 struct FloatVisitor;
1436
1437 impl serde::de::Visitor<'_> for FloatVisitor {
1438 type Value = f64;
1439
1440 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1441 formatter.write_str("a float or string representation of NaN/Infinity")
1442 }
1443 fn visit_i8<E>(self, value: i8) -> Result<Self::Value, E> {
1444 Ok(value as f64)
1445 }
1446 fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E> {
1447 Ok(value as f64)
1448 }
1449 fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E> {
1450 Ok(value as f64)
1451 }
1452 fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E> {
1453 Ok(value as f64)
1454 }
1455 fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E> {
1456 Ok(value as f64)
1457 }
1458 fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E> {
1459 Ok(value as f64)
1460 }
1461 fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
1462 Ok(value as f64)
1463 }
1464 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
1465 Ok(value as f64)
1466 }
1467 fn visit_f32<E>(self, value: f32) -> Result<Self::Value, E> {
1468 Ok(value as f64)
1469 }
1470 fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> {
1471 Ok(value)
1472 }
1473 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
1474 where
1475 E: serde::de::Error,
1476 {
1477 match value {
1478 "NaN" => Ok(f64::NAN),
1479 "-NaN" => Ok(-f64::NAN),
1480 "Infinity" => Ok(f64::INFINITY),
1481 "-Infinity" => Ok(f64::NEG_INFINITY),
1482 _ => Err(E::custom(format!(
1483 "unxpected string value in place of float '{value}'"
1484 ))),
1485 }
1486 }
1487
1488 fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
1489 where
1490 E: serde::de::Error,
1491 {
1492 self.visit_str(&value)
1493 }
1494 }
1495
1496 let value = deserializer.deserialize_any(FloatVisitor)?;
1497 Ok(Self(value))
1498 }
1499}
1500impl Serialize for Float {
1501 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1502 where
1503 S: Serializer,
1504 {
1505 let value = self.0;
1506 let sign = if value.is_sign_negative() { "-" } else { "" };
1507 if value.is_nan() {
1508 serializer.serialize_str(&format!("{sign}NaN"))
1509 } else if value.is_infinite() {
1510 serializer.serialize_str(&format!("{sign}Infinity"))
1511 } else {
1512 serializer.serialize_f32(value)
1513 }
1514 }
1515}
1516impl Serialize for Double {
1517 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1518 where
1519 S: Serializer,
1520 {
1521 let value = self.0;
1522 let sign = if value.is_sign_negative() { "-" } else { "" };
1523 if value.is_nan() {
1524 serializer.serialize_str(&format!("{sign}NaN"))
1525 } else if value.is_infinite() {
1526 serializer.serialize_str(&format!("{sign}Infinity"))
1527 } else {
1528 serializer.serialize_f64(value)
1529 }
1530 }
1531}
1532
1533#[derive(Debug, Clone, PartialEq, Serialize)]
1534pub struct MapEntry<T: ArchiveType = SaveGameArchiveType> {
1535 pub key: Property<T>,
1536 pub value: Property<T>,
1537}
1538impl<T: ArchiveType> MapEntry<T> {
1539 #[cfg_attr(feature = "tracing", instrument(name = "MapEntry_read", skip_all))]
1540 fn read<A: ArchiveReader<ArchiveType = T>>(
1541 ar: &mut A,
1542 key_type: &PropertyTagDataFull,
1543 value_type: &PropertyTagDataFull,
1544 ) -> Result<MapEntry<T>> {
1545 let key = Property::read_value(ar, key_type)?;
1546 let value = Property::read_value(ar, value_type)?;
1547 Ok(Self { key, value })
1548 }
1549 fn write<A: ArchiveWriter<ArchiveType = T>>(&self, ar: &mut A) -> Result<()> {
1550 self.key.write_value(ar)?;
1551 self.value.write_value(ar)?;
1552 Ok(())
1553 }
1554}
1555
1556#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1557pub struct FieldPath {
1558 path: Vec<String>,
1559 owner: String,
1560}
1561impl FieldPath {
1562 #[cfg_attr(feature = "tracing", instrument(name = "FieldPath_read", skip_all))]
1563 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1564 Ok(Self {
1565 path: read_array(ar.read_u32::<LE>()?, ar, |ar| ar.read_string())?,
1566 owner: ar.read_string()?,
1567 })
1568 }
1569 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1570 ar.write_u32::<LE>(self.path.len() as u32)?;
1571 for p in &self.path {
1572 ar.write_string(p)?;
1573 }
1574 ar.write_string(&self.owner)?;
1575 Ok(())
1576 }
1577}
1578
1579#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1580#[serde(bound(
1581 serialize = "T::ObjectRef: Serialize",
1582 deserialize = "T::ObjectRef: Deserialize<'de>"
1583))]
1584pub struct Delegate<T: ArchiveType = SaveGameArchiveType> {
1585 pub object: T::ObjectRef,
1586 pub delegate: String,
1587}
1588impl<T: ArchiveType> Delegate<T> {
1589 #[cfg_attr(feature = "tracing", instrument(name = "Delegate_read", skip_all))]
1590 fn read<A: ArchiveReader<ArchiveType = T>>(ar: &mut A) -> Result<Self> {
1591 Ok(Self {
1592 object: ar.read_object_ref()?,
1593 delegate: ar.read_string()?,
1594 })
1595 }
1596 fn write<A: ArchiveWriter<ArchiveType = T>>(&self, ar: &mut A) -> Result<()> {
1597 ar.write_object_ref(&self.object)?;
1598 ar.write_string(&self.delegate)?;
1599 Ok(())
1600 }
1601}
1602
1603#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1604#[serde(bound(
1605 serialize = "T::ObjectRef: Serialize",
1606 deserialize = "T::ObjectRef: Deserialize<'de>"
1607))]
1608pub struct MulticastDelegate<T: ArchiveType = SaveGameArchiveType>(pub Vec<Delegate<T>>);
1609impl<T: ArchiveType> MulticastDelegate<T> {
1610 #[cfg_attr(
1611 feature = "tracing",
1612 instrument(name = "MulticastDelegate_read", skip_all)
1613 )]
1614 fn read<A: ArchiveReader<ArchiveType = T>>(ar: &mut A) -> Result<Self> {
1615 Ok(Self(read_array(ar.read_u32::<LE>()?, ar, Delegate::read)?))
1616 }
1617 fn write<A: ArchiveWriter<ArchiveType = T>>(&self, ar: &mut A) -> Result<()> {
1618 ar.write_u32::<LE>(self.0.len() as u32)?;
1619 for entry in &self.0 {
1620 entry.write(ar)?;
1621 }
1622 Ok(())
1623 }
1624}
1625
1626#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1627#[serde(bound(
1628 serialize = "T::ObjectRef: Serialize",
1629 deserialize = "T::ObjectRef: Deserialize<'de>"
1630))]
1631pub struct MulticastInlineDelegate<T: ArchiveType = SaveGameArchiveType>(pub Vec<Delegate<T>>);
1632impl<T: ArchiveType> MulticastInlineDelegate<T> {
1633 #[cfg_attr(
1634 feature = "tracing",
1635 instrument(name = "MulticastInlineDelegate_read", skip_all)
1636 )]
1637 fn read<A: ArchiveReader<ArchiveType = T>>(ar: &mut A) -> Result<Self> {
1638 Ok(Self(read_array(ar.read_u32::<LE>()?, ar, Delegate::read)?))
1639 }
1640 fn write<A: ArchiveWriter<ArchiveType = T>>(&self, ar: &mut A) -> Result<()> {
1641 ar.write_u32::<LE>(self.0.len() as u32)?;
1642 for entry in &self.0 {
1643 entry.write(ar)?;
1644 }
1645 Ok(())
1646 }
1647}
1648
1649#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1650#[serde(bound(
1651 serialize = "T::ObjectRef: Serialize",
1652 deserialize = "T::ObjectRef: Deserialize<'de>"
1653))]
1654pub struct MulticastSparseDelegate<T: ArchiveType = SaveGameArchiveType>(pub Vec<Delegate<T>>);
1655impl<T: ArchiveType> MulticastSparseDelegate<T> {
1656 #[cfg_attr(
1657 feature = "tracing",
1658 instrument(name = "MulticastSparseDelegate_read", skip_all)
1659 )]
1660 fn read<A: ArchiveReader<ArchiveType = T>>(ar: &mut A) -> Result<Self> {
1661 Ok(Self(read_array(ar.read_u32::<LE>()?, ar, Delegate::read)?))
1662 }
1663 fn write<A: ArchiveWriter<ArchiveType = T>>(&self, ar: &mut A) -> Result<()> {
1664 ar.write_u32::<LE>(self.0.len() as u32)?;
1665 for entry in &self.0 {
1666 entry.write(ar)?;
1667 }
1668 Ok(())
1669 }
1670}
1671
1672#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1673pub struct LinearColor {
1674 pub r: Float,
1675 pub g: Float,
1676 pub b: Float,
1677 pub a: Float,
1678}
1679impl LinearColor {
1680 #[cfg_attr(feature = "tracing", instrument(name = "LinearColor_read", skip_all))]
1681 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1682 Ok(Self {
1683 r: ar.read_f32::<LE>()?.into(),
1684 g: ar.read_f32::<LE>()?.into(),
1685 b: ar.read_f32::<LE>()?.into(),
1686 a: ar.read_f32::<LE>()?.into(),
1687 })
1688 }
1689 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1690 ar.write_f32::<LE>(self.r.into())?;
1691 ar.write_f32::<LE>(self.g.into())?;
1692 ar.write_f32::<LE>(self.b.into())?;
1693 ar.write_f32::<LE>(self.a.into())?;
1694 Ok(())
1695 }
1696}
1697#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1698pub struct Quat {
1699 pub x: Double,
1700 pub y: Double,
1701 pub z: Double,
1702 pub w: Double,
1703}
1704impl Quat {
1705 #[cfg_attr(feature = "tracing", instrument(name = "Quat_read", skip_all))]
1706 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1707 if ar.version().large_world_coordinates() {
1708 Ok(Self {
1709 x: ar.read_f64::<LE>()?.into(),
1710 y: ar.read_f64::<LE>()?.into(),
1711 z: ar.read_f64::<LE>()?.into(),
1712 w: ar.read_f64::<LE>()?.into(),
1713 })
1714 } else {
1715 Ok(Self {
1716 x: ar.read_f32::<LE>()?.into(),
1717 y: ar.read_f32::<LE>()?.into(),
1718 z: ar.read_f32::<LE>()?.into(),
1719 w: ar.read_f32::<LE>()?.into(),
1720 })
1721 }
1722 }
1723 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1724 if ar.version().large_world_coordinates() {
1725 ar.write_f64::<LE>(self.x.into())?;
1726 ar.write_f64::<LE>(self.y.into())?;
1727 ar.write_f64::<LE>(self.z.into())?;
1728 ar.write_f64::<LE>(self.w.into())?;
1729 } else {
1730 ar.write_f32::<LE>(self.x.into())?;
1731 ar.write_f32::<LE>(self.y.into())?;
1732 ar.write_f32::<LE>(self.z.into())?;
1733 ar.write_f32::<LE>(self.w.into())?;
1734 }
1735 Ok(())
1736 }
1737}
1738#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1739pub struct Rotator {
1740 pub x: Double,
1741 pub y: Double,
1742 pub z: Double,
1743}
1744impl Rotator {
1745 #[cfg_attr(feature = "tracing", instrument(name = "Rotator_read", skip_all))]
1746 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1747 if ar.version().large_world_coordinates() {
1748 Ok(Self {
1749 x: ar.read_f64::<LE>()?.into(),
1750 y: ar.read_f64::<LE>()?.into(),
1751 z: ar.read_f64::<LE>()?.into(),
1752 })
1753 } else {
1754 Ok(Self {
1755 x: ar.read_f32::<LE>()?.into(),
1756 y: ar.read_f32::<LE>()?.into(),
1757 z: ar.read_f32::<LE>()?.into(),
1758 })
1759 }
1760 }
1761 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1762 if ar.version().large_world_coordinates() {
1763 ar.write_f64::<LE>(self.x.into())?;
1764 ar.write_f64::<LE>(self.y.into())?;
1765 ar.write_f64::<LE>(self.z.into())?;
1766 } else {
1767 ar.write_f32::<LE>(self.x.into())?;
1768 ar.write_f32::<LE>(self.y.into())?;
1769 ar.write_f32::<LE>(self.z.into())?;
1770 }
1771 Ok(())
1772 }
1773}
1774#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1775pub struct Color {
1776 pub r: u8,
1777 pub g: u8,
1778 pub b: u8,
1779 pub a: u8,
1780}
1781impl Color {
1782 #[cfg_attr(feature = "tracing", instrument(name = "Color_read", skip_all))]
1783 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1784 Ok(Self {
1785 r: ar.read_u8()?,
1786 g: ar.read_u8()?,
1787 b: ar.read_u8()?,
1788 a: ar.read_u8()?,
1789 })
1790 }
1791 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1792 ar.write_u8(self.r)?;
1793 ar.write_u8(self.g)?;
1794 ar.write_u8(self.b)?;
1795 ar.write_u8(self.a)?;
1796 Ok(())
1797 }
1798}
1799#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1800pub struct Vector {
1801 pub x: Double,
1802 pub y: Double,
1803 pub z: Double,
1804}
1805impl Vector {
1806 #[cfg_attr(feature = "tracing", instrument(name = "Vector_read", skip_all))]
1807 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1808 if ar.version().large_world_coordinates() {
1809 Ok(Self {
1810 x: ar.read_f64::<LE>()?.into(),
1811 y: ar.read_f64::<LE>()?.into(),
1812 z: ar.read_f64::<LE>()?.into(),
1813 })
1814 } else {
1815 Ok(Self {
1816 x: ar.read_f32::<LE>()?.into(),
1817 y: ar.read_f32::<LE>()?.into(),
1818 z: ar.read_f32::<LE>()?.into(),
1819 })
1820 }
1821 }
1822 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1823 if ar.version().large_world_coordinates() {
1824 ar.write_f64::<LE>(self.x.into())?;
1825 ar.write_f64::<LE>(self.y.into())?;
1826 ar.write_f64::<LE>(self.z.into())?;
1827 } else {
1828 ar.write_f32::<LE>(self.x.into())?;
1829 ar.write_f32::<LE>(self.y.into())?;
1830 ar.write_f32::<LE>(self.z.into())?;
1831 }
1832 Ok(())
1833 }
1834}
1835#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1836pub struct Vector2D {
1837 pub x: Double,
1838 pub y: Double,
1839}
1840impl Vector2D {
1841 #[cfg_attr(feature = "tracing", instrument(name = "Vector2D_read", skip_all))]
1842 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1843 if ar.version().large_world_coordinates() {
1844 Ok(Self {
1845 x: ar.read_f64::<LE>()?.into(),
1846 y: ar.read_f64::<LE>()?.into(),
1847 })
1848 } else {
1849 Ok(Self {
1850 x: ar.read_f32::<LE>()?.into(),
1851 y: ar.read_f32::<LE>()?.into(),
1852 })
1853 }
1854 }
1855 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1856 if ar.version().large_world_coordinates() {
1857 ar.write_f64::<LE>(self.x.into())?;
1858 ar.write_f64::<LE>(self.y.into())?;
1859 } else {
1860 ar.write_f32::<LE>(self.x.into())?;
1861 ar.write_f32::<LE>(self.y.into())?;
1862 }
1863 Ok(())
1864 }
1865}
1866#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1867pub struct Box2D {
1868 pub min: Vector2D,
1869 pub max: Vector2D,
1870 pub is_valid: bool,
1871}
1872impl Box2D {
1873 #[cfg_attr(feature = "tracing", instrument(name = "Box2D_read", skip_all))]
1874 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1875 Ok(Self {
1876 min: Vector2D::read(ar)?,
1877 max: Vector2D::read(ar)?,
1878 is_valid: ar.read_u8()? > 0,
1879 })
1880 }
1881 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1882 self.min.write(ar)?;
1883 self.max.write(ar)?;
1884 ar.write_u8(self.is_valid as u8)?;
1885 Ok(())
1886 }
1887}
1888#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1889pub struct Vector4 {
1890 pub x: Double,
1891 pub y: Double,
1892 pub z: Double,
1893 pub w: Double,
1894}
1895impl Vector4 {
1896 #[cfg_attr(feature = "tracing", instrument(name = "Vector4_read", skip_all))]
1897 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1898 if ar.version().large_world_coordinates() {
1899 Ok(Self {
1900 x: ar.read_f64::<LE>()?.into(),
1901 y: ar.read_f64::<LE>()?.into(),
1902 z: ar.read_f64::<LE>()?.into(),
1903 w: ar.read_f64::<LE>()?.into(),
1904 })
1905 } else {
1906 Ok(Self {
1907 x: ar.read_f32::<LE>()?.into(),
1908 y: ar.read_f32::<LE>()?.into(),
1909 z: ar.read_f32::<LE>()?.into(),
1910 w: ar.read_f32::<LE>()?.into(),
1911 })
1912 }
1913 }
1914 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1915 if ar.version().large_world_coordinates() {
1916 ar.write_f64::<LE>(self.x.into())?;
1917 ar.write_f64::<LE>(self.y.into())?;
1918 ar.write_f64::<LE>(self.z.into())?;
1919 ar.write_f64::<LE>(self.w.into())?;
1920 } else {
1921 ar.write_f32::<LE>(self.x.into())?;
1922 ar.write_f32::<LE>(self.y.into())?;
1923 ar.write_f32::<LE>(self.z.into())?;
1924 ar.write_f32::<LE>(self.w.into())?;
1925 }
1926 Ok(())
1927 }
1928}
1929#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1930pub struct IntVector {
1931 pub x: i32,
1932 pub y: i32,
1933 pub z: i32,
1934}
1935impl IntVector {
1936 #[cfg_attr(feature = "tracing", instrument(name = "IntVector_read", skip_all))]
1937 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1938 Ok(Self {
1939 x: ar.read_i32::<LE>()?,
1940 y: ar.read_i32::<LE>()?,
1941 z: ar.read_i32::<LE>()?,
1942 })
1943 }
1944 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1945 ar.write_i32::<LE>(self.x)?;
1946 ar.write_i32::<LE>(self.y)?;
1947 ar.write_i32::<LE>(self.z)?;
1948 Ok(())
1949 }
1950}
1951#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1952pub struct Box {
1953 pub min: Vector,
1954 pub max: Vector,
1955 pub is_valid: bool,
1956}
1957impl Box {
1958 #[cfg_attr(feature = "tracing", instrument(name = "Box_read", skip_all))]
1959 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1960 Ok(Self {
1961 min: Vector::read(ar)?,
1962 max: Vector::read(ar)?,
1963 is_valid: ar.read_u8()? > 0,
1964 })
1965 }
1966 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1967 self.min.write(ar)?;
1968 self.max.write(ar)?;
1969 ar.write_u8(self.is_valid as u8)?;
1970 Ok(())
1971 }
1972}
1973#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1974pub struct IntPoint {
1975 pub x: i32,
1976 pub y: i32,
1977}
1978impl IntPoint {
1979 #[cfg_attr(feature = "tracing", instrument(name = "IntPoint_read", skip_all))]
1980 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
1981 Ok(Self {
1982 x: ar.read_i32::<LE>()?,
1983 y: ar.read_i32::<LE>()?,
1984 })
1985 }
1986 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
1987 ar.write_i32::<LE>(self.x)?;
1988 ar.write_i32::<LE>(self.y)?;
1989 Ok(())
1990 }
1991}
1992
1993#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1994pub struct FKeyHandleMap {}
1995impl FKeyHandleMap {
1996 #[cfg_attr(feature = "tracing", instrument(name = "FKeyHandleMap_read", skip_all))]
1997 fn read<A: ArchiveReader>(_ar: &mut A) -> Result<Self> {
1998 Ok(Self {})
1999 }
2000 fn write<A: ArchiveWriter>(&self, _ar: &mut A) -> Result<()> {
2001 Ok(())
2002 }
2003}
2004
2005#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2006pub struct FRichCurveKey {
2007 pub interp_mode: u8,
2009 pub tangent_mode: u8,
2011 pub tangent_weight_mode: u8,
2013 pub time: Float,
2015 pub value: Float,
2017 pub arrive_tangent: Float,
2019 pub arrive_tangent_weight: Float,
2021 pub leave_tangent: Float,
2023 pub leave_tangent_weight: Float,
2025}
2026impl FRichCurveKey {
2027 #[cfg_attr(feature = "tracing", instrument(name = "FRichCurveKey_read", skip_all))]
2028 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2029 Ok(Self {
2030 interp_mode: ar.read_u8()?,
2031 tangent_mode: ar.read_u8()?,
2032 tangent_weight_mode: ar.read_u8()?,
2033 time: ar.read_f32::<LE>()?.into(),
2034 value: ar.read_f32::<LE>()?.into(),
2035 arrive_tangent: ar.read_f32::<LE>()?.into(),
2036 arrive_tangent_weight: ar.read_f32::<LE>()?.into(),
2037 leave_tangent: ar.read_f32::<LE>()?.into(),
2038 leave_tangent_weight: ar.read_f32::<LE>()?.into(),
2039 })
2040 }
2041 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2042 ar.write_u8(self.interp_mode)?;
2043 ar.write_u8(self.tangent_mode)?;
2044 ar.write_u8(self.tangent_weight_mode)?;
2045 ar.write_f32::<LE>(self.time.into())?;
2046 ar.write_f32::<LE>(self.value.into())?;
2047 ar.write_f32::<LE>(self.arrive_tangent.into())?;
2048 ar.write_f32::<LE>(self.arrive_tangent_weight.into())?;
2049 ar.write_f32::<LE>(self.leave_tangent.into())?;
2050 ar.write_f32::<LE>(self.leave_tangent_weight.into())?;
2051 Ok(())
2052 }
2053}
2054
2055#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2056pub struct FWeightedRandomSampler {
2057 pub prob: Vec<Float>,
2058 pub alias: Vec<i32>,
2059 pub total_weight: Float,
2060}
2061impl FWeightedRandomSampler {
2062 #[cfg_attr(
2063 feature = "tracing",
2064 instrument(name = "FWeightedRandomSampler_read", skip_all)
2065 )]
2066 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2067 Ok(Self {
2068 prob: read_array(ar.read_u32::<LE>()?, ar, |r| Ok(r.read_f32::<LE>()?.into()))?,
2069 alias: read_array(ar.read_u32::<LE>()?, ar, |r| Ok(r.read_i32::<LE>()?))?,
2070 total_weight: ar.read_f32::<LE>()?.into(),
2071 })
2072 }
2073 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2074 ar.write_u32::<LE>(self.prob.len() as u32)?;
2075 for p in &self.prob {
2076 ar.write_f32::<LE>((*p).into())?;
2077 }
2078 ar.write_u32::<LE>(self.alias.len() as u32)?;
2079 for a in &self.alias {
2080 ar.write_i32::<LE>(*a)?;
2081 }
2082 ar.write_f32::<LE>(self.total_weight.into())?;
2083 Ok(())
2084 }
2085}
2086
2087#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2088pub struct FSkeletalMeshSamplingLODBuiltData {
2089 pub weighted_random_sampler: FWeightedRandomSampler,
2090}
2091impl FSkeletalMeshSamplingLODBuiltData {
2092 #[cfg_attr(
2093 feature = "tracing",
2094 instrument(name = "SkeletalMeshSamplingLODBuiltData_read", skip_all)
2095 )]
2096 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2097 Ok(Self {
2098 weighted_random_sampler: FWeightedRandomSampler::read(ar)?,
2099 })
2100 }
2101 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2102 self.weighted_random_sampler.write(ar)?;
2103 Ok(())
2104 }
2105}
2106
2107#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2108pub struct FPerPlatformFloat {
2109 pub is_cooked: bool,
2110 pub value: Float,
2111}
2112impl FPerPlatformFloat {
2113 #[cfg_attr(
2114 feature = "tracing",
2115 instrument(name = "FPerPlatformFloat_read", skip_all)
2116 )]
2117 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2118 let is_cooked = ar.read_u32::<LE>()? != 0;
2119 assert!(
2120 is_cooked,
2121 "TODO implement !is_cooked (read map of platform => value)"
2122 );
2123 Ok(Self {
2124 is_cooked,
2125 value: ar.read_f32::<LE>()?.into(),
2126 })
2127 }
2128 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2129 ar.write_u32::<LE>(self.is_cooked as u32)?;
2130 ar.write_f32::<LE>(self.value.into())?;
2131 Ok(())
2132 }
2133}
2134
2135#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2136pub enum SoftObjectPath {
2137 Old {
2138 asset_path_name: String,
2139 sub_path_string: String,
2140 },
2141 New {
2142 asset_path_name: String,
2143 package_name: String,
2144 asset_name: (String, Vec<u8>),
2145 },
2146}
2147impl SoftObjectPath {
2148 #[cfg_attr(
2149 feature = "tracing",
2150 instrument(name = "SoftObjectPath_read", skip_all)
2151 )]
2152 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2153 Ok(if ar.version().remove_asset_path_fnames() {
2154 Self::New {
2155 asset_path_name: ar.read_string()?,
2156 package_name: ar.read_string()?,
2157 asset_name: ar.read_string_trailing()?,
2158 }
2159 } else {
2160 Self::Old {
2161 asset_path_name: ar.read_string()?,
2162 sub_path_string: ar.read_string()?,
2163 }
2164 })
2165 }
2166 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2167 match self {
2168 Self::Old {
2169 asset_path_name,
2170 sub_path_string,
2171 } => {
2172 ar.write_string(asset_path_name)?;
2173 ar.write_string(sub_path_string)?;
2174 }
2175 Self::New {
2176 asset_path_name,
2177 package_name,
2178 asset_name: (asset_name, trailing),
2179 } => {
2180 ar.write_string(asset_path_name)?;
2181 ar.write_string(package_name)?;
2182 ar.write_string_trailing(asset_name, Some(trailing))?;
2183 }
2184 }
2185 Ok(())
2186 }
2187}
2188
2189#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2190pub struct SoftClassPath(pub SoftObjectPath);
2191impl SoftClassPath {
2192 #[cfg_attr(feature = "tracing", instrument(name = "SoftClassPath_read", skip_all))]
2193 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2194 Ok(Self(SoftObjectPath::read(ar)?))
2195 }
2196 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2197 self.0.write(ar)
2198 }
2199}
2200
2201#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2202pub struct GameplayTag {
2203 pub name: String,
2204}
2205impl GameplayTag {
2206 #[cfg_attr(feature = "tracing", instrument(name = "GameplayTag_read", skip_all))]
2207 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2208 Ok(Self {
2209 name: ar.read_string()?,
2210 })
2211 }
2212 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2213 ar.write_string(&self.name)?;
2214 Ok(())
2215 }
2216}
2217
2218#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2219pub struct GameplayTagContainer {
2220 pub gameplay_tags: Vec<GameplayTag>,
2221}
2222impl GameplayTagContainer {
2223 #[cfg_attr(
2224 feature = "tracing",
2225 instrument(name = "GameplayTagContainer_read", skip_all)
2226 )]
2227 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2228 Ok(Self {
2229 gameplay_tags: read_array(ar.read_u32::<LE>()?, ar, GameplayTag::read)?,
2230 })
2231 }
2232 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2233 ar.write_u32::<LE>(self.gameplay_tags.len() as u32)?;
2234 for entry in &self.gameplay_tags {
2235 entry.write(ar)?;
2236 }
2237 Ok(())
2238 }
2239}
2240
2241#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2242pub struct UniqueNetIdRepl {
2243 pub inner: Option<UniqueNetIdReplInner>,
2244}
2245#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2246pub struct UniqueNetIdReplInner {
2247 pub size: std::num::NonZeroU32,
2248 pub type_: String,
2249 pub contents: String,
2250}
2251impl UniqueNetIdRepl {
2252 #[cfg_attr(
2253 feature = "tracing",
2254 instrument(name = "UniqueNetIdRepl_read", skip_all)
2255 )]
2256 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2257 let size = ar.read_u32::<LE>()?;
2258 let inner = if let Ok(size) = size.try_into() {
2259 Some(UniqueNetIdReplInner {
2260 size,
2261 type_: ar.read_string()?,
2262 contents: ar.read_string()?,
2263 })
2264 } else {
2265 None
2266 };
2267 Ok(Self { inner })
2268 }
2269 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2270 match &self.inner {
2271 Some(inner) => {
2272 ar.write_u32::<LE>(inner.size.into())?;
2273 ar.write_string(&inner.type_)?;
2274 ar.write_string(&inner.contents)?;
2275 }
2276 None => ar.write_u32::<LE>(0)?,
2277 }
2278 Ok(())
2279 }
2280}
2281
2282#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2283pub struct FFormatArgumentData {
2284 name: String,
2285 value: FFormatArgumentDataValue,
2286}
2287impl FFormatArgumentData {
2288 #[cfg_attr(
2289 feature = "tracing",
2290 instrument(name = "FFormatArgumentData_read", skip_all)
2291 )]
2292 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2293 Ok(Self {
2294 name: read_string(ar)?,
2295 value: FFormatArgumentDataValue::read(ar)?,
2296 })
2297 }
2298}
2299impl FFormatArgumentData {
2300 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2301 write_string(ar, &self.name)?;
2302 self.value.write(ar)?;
2303 Ok(())
2304 }
2305}
2306#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2309pub enum FFormatArgumentDataValue {
2310 Int(i32),
2311 UInt(u32),
2312 Float(Float),
2313 Double(Double),
2314 Text(std::boxed::Box<Text>),
2315 Gender(u64),
2316}
2317impl FFormatArgumentDataValue {
2318 #[cfg_attr(
2319 feature = "tracing",
2320 instrument(name = "FFormatArgumentDataValue_read", skip_all)
2321 )]
2322 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2323 let type_ = ar.read_u8()?;
2324 match type_ {
2325 0 => Ok(Self::Int(ar.read_i32::<LE>()?)),
2326 1 => Ok(Self::UInt(ar.read_u32::<LE>()?)),
2327 2 => Ok(Self::Float(ar.read_f32::<LE>()?.into())),
2328 3 => Ok(Self::Double(ar.read_f64::<LE>()?.into())),
2329 4 => Ok(Self::Text(std::boxed::Box::new(Text::read(ar)?))),
2330 5 => Ok(Self::Gender(ar.read_u64::<LE>()?)),
2331 _ => Err(Error::Other(format!(
2332 "unimplemented variant for FFormatArgumentDataValue 0x{type_:x}"
2333 ))),
2334 }
2335 }
2336}
2337impl FFormatArgumentDataValue {
2338 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2339 match self {
2340 Self::Int(value) => {
2341 ar.write_u8(0)?;
2342 ar.write_i32::<LE>(*value)?;
2343 }
2344 Self::UInt(value) => {
2345 ar.write_u8(1)?;
2346 ar.write_u32::<LE>(*value)?;
2347 }
2348 Self::Float(value) => {
2349 ar.write_u8(2)?;
2350 ar.write_f32::<LE>((*value).into())?;
2351 }
2352 Self::Double(value) => {
2353 ar.write_u8(3)?;
2354 ar.write_f64::<LE>((*value).into())?;
2355 }
2356 Self::Text(value) => {
2357 ar.write_u8(4)?;
2358 value.write(ar)?;
2359 }
2360 Self::Gender(value) => {
2361 ar.write_u8(5)?;
2362 ar.write_u64::<LE>(*value)?;
2363 }
2364 };
2365 Ok(())
2366 }
2367}
2368
2369#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2370pub enum FFormatArgumentValue {
2371 Int(i64),
2372 UInt(u64),
2373 Float(Float),
2374 Double(Double),
2375 Text(std::boxed::Box<Text>),
2376 Gender(u64),
2377}
2378
2379impl FFormatArgumentValue {
2380 #[cfg_attr(
2381 feature = "tracing",
2382 instrument(name = "FFormatArgumentValue_read", skip_all)
2383 )]
2384 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2385 let type_ = ar.read_u8()?;
2386 match type_ {
2387 0 => Ok(Self::Int(ar.read_i64::<LE>()?)),
2388 1 => Ok(Self::UInt(ar.read_u64::<LE>()?)),
2389 2 => Ok(Self::Float(ar.read_f32::<LE>()?.into())),
2390 3 => Ok(Self::Double(ar.read_f64::<LE>()?.into())),
2391 4 => Ok(Self::Text(std::boxed::Box::new(Text::read(ar)?))),
2392 5 => Ok(Self::Gender(ar.read_u64::<LE>()?)),
2393 _ => Err(Error::Other(format!(
2394 "unimplemented variant for FFormatArgumentValue 0x{type_:x}"
2395 ))),
2396 }
2397 }
2398}
2399impl FFormatArgumentValue {
2400 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2401 match self {
2402 Self::Int(value) => {
2403 ar.write_u8(0)?;
2404 ar.write_i64::<LE>(*value)?;
2405 }
2406 Self::UInt(value) => {
2407 ar.write_u8(1)?;
2408 ar.write_u64::<LE>(*value)?;
2409 }
2410 Self::Float(value) => {
2411 ar.write_u8(2)?;
2412 ar.write_f32::<LE>((*value).into())?;
2413 }
2414 Self::Double(value) => {
2415 ar.write_u8(3)?;
2416 ar.write_f64::<LE>((*value).into())?;
2417 }
2418 Self::Text(value) => {
2419 ar.write_u8(4)?;
2420 value.write(ar)?;
2421 }
2422 Self::Gender(value) => {
2423 ar.write_u8(5)?;
2424 ar.write_u64::<LE>(*value)?;
2425 }
2426 };
2427 Ok(())
2428 }
2429}
2430
2431#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2432pub struct FNumberFormattingOptions {
2433 always_sign: bool,
2434 use_grouping: bool,
2435 rounding_mode: i8, minimum_integral_digits: i32,
2437 maximum_integral_digits: i32,
2438 minimum_fractional_digits: i32,
2439 maximum_fractional_digits: i32,
2440}
2441impl FNumberFormattingOptions {
2442 #[cfg_attr(
2443 feature = "tracing",
2444 instrument(name = "FNumberFormattingOptions_read", skip_all)
2445 )]
2446 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2447 Ok(Self {
2448 always_sign: ar.read_u32::<LE>()? != 0,
2449 use_grouping: ar.read_u32::<LE>()? != 0,
2450 rounding_mode: ar.read_i8()?,
2451 minimum_integral_digits: ar.read_i32::<LE>()?,
2452 maximum_integral_digits: ar.read_i32::<LE>()?,
2453 minimum_fractional_digits: ar.read_i32::<LE>()?,
2454 maximum_fractional_digits: ar.read_i32::<LE>()?,
2455 })
2456 }
2457}
2458impl FNumberFormattingOptions {
2459 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2460 ar.write_u32::<LE>(self.always_sign as u32)?;
2461 ar.write_u32::<LE>(self.use_grouping as u32)?;
2462 ar.write_i8(self.rounding_mode)?;
2463 ar.write_i32::<LE>(self.minimum_integral_digits)?;
2464 ar.write_i32::<LE>(self.maximum_integral_digits)?;
2465 ar.write_i32::<LE>(self.minimum_fractional_digits)?;
2466 ar.write_i32::<LE>(self.maximum_fractional_digits)?;
2467 Ok(())
2468 }
2469}
2470
2471#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2472pub struct Text {
2473 flags: u32,
2474 variant: TextVariant,
2475}
2476#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2477pub enum TextVariant {
2478 None {
2480 culture_invariant: Option<String>,
2481 },
2482 Base {
2484 namespace: (String, Vec<u8>),
2485 key: String,
2486 source_string: String,
2487 },
2488 ArgumentFormat {
2490 format_text: std::boxed::Box<Text>,
2492 arguments: Vec<FFormatArgumentData>,
2493 },
2494 AsNumber {
2496 source_value: FFormatArgumentValue,
2497 format_options: Option<FNumberFormattingOptions>,
2498 culture_name: String,
2499 },
2500 AsDate {
2502 source_date_time: DateTime,
2503 date_style: i8, time_zone: String,
2505 culture_name: String,
2506 },
2507 StringTableEntry {
2508 table: String,
2510 key: String,
2511 },
2512}
2513
2514impl Text {
2515 #[cfg_attr(feature = "tracing", instrument(name = "Text_read", skip_all))]
2516 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
2517 let flags = ar.read_u32::<LE>()?;
2518 let text_history_type = ar.read_i8()?;
2519 let variant = match text_history_type {
2520 -0x1 => Ok(TextVariant::None {
2521 culture_invariant: (ar.read_u32::<LE>()? != 0) .then(|| read_string(ar))
2523 .transpose()?,
2524 }),
2525 0x0 => Ok(TextVariant::Base {
2526 namespace: read_string_trailing(ar)?,
2527 key: read_string(ar)?,
2528 source_string: read_string(ar)?,
2529 }),
2530 0x3 => Ok(TextVariant::ArgumentFormat {
2531 format_text: std::boxed::Box::new(Text::read(ar)?),
2532 arguments: read_array(ar.read_u32::<LE>()?, ar, FFormatArgumentData::read)?,
2533 }),
2534 0x4 => Ok(TextVariant::AsNumber {
2535 source_value: FFormatArgumentValue::read(ar)?,
2536 format_options: (ar.read_u32::<LE>()? != 0) .then(|| FNumberFormattingOptions::read(ar))
2538 .transpose()?,
2539 culture_name: ar.read_string()?,
2540 }),
2541 0x7 => Ok(TextVariant::AsDate {
2542 source_date_time: ar.read_u64::<LE>()?,
2543 date_style: ar.read_i8()?,
2544 time_zone: ar.read_string()?,
2545 culture_name: ar.read_string()?,
2546 }),
2547 0xb => Ok({
2548 TextVariant::StringTableEntry {
2549 table: ar.read_string()?,
2550 key: read_string(ar)?,
2551 }
2552 }),
2553 _ => Err(Error::Other(format!(
2554 "unimplemented variant for FTextHistory 0x{text_history_type:x}"
2555 ))),
2556 }?;
2557 Ok(Self { flags, variant })
2558 }
2559}
2560impl Text {
2561 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
2562 ar.write_u32::<LE>(self.flags)?;
2563 match &self.variant {
2564 TextVariant::None { culture_invariant } => {
2565 ar.write_i8(-0x1)?;
2566 ar.write_u32::<LE>(culture_invariant.is_some() as u32)?;
2567 if let Some(culture_invariant) = culture_invariant {
2568 write_string(ar, culture_invariant)?;
2569 }
2570 }
2571 TextVariant::Base {
2572 namespace,
2573 key,
2574 source_string,
2575 } => {
2576 ar.write_i8(0x0)?;
2577 write_string_trailing(ar, &namespace.0, Some(&namespace.1))?;
2581 write_string(ar, key)?;
2582 write_string(ar, source_string)?;
2583 }
2584 TextVariant::ArgumentFormat {
2585 format_text,
2586 arguments,
2587 } => {
2588 ar.write_i8(0x3)?;
2589 format_text.write(ar)?;
2590 ar.write_u32::<LE>(arguments.len() as u32)?;
2591 for a in arguments {
2592 a.write(ar)?;
2593 }
2594 }
2595 TextVariant::AsNumber {
2596 source_value,
2597 format_options,
2598 culture_name,
2599 } => {
2600 ar.write_i8(0x4)?;
2601 source_value.write(ar)?;
2602 ar.write_u32::<LE>(format_options.is_some() as u32)?;
2603 if let Some(format_options) = format_options {
2604 format_options.write(ar)?;
2605 }
2606 ar.write_string(culture_name)?;
2607 }
2608 TextVariant::AsDate {
2609 source_date_time,
2610 date_style,
2611 time_zone,
2612 culture_name,
2613 } => {
2614 ar.write_i8(0x7)?;
2615 ar.write_u64::<LE>(*source_date_time)?;
2616 ar.write_i8(*date_style)?;
2617 ar.write_string(time_zone)?;
2618 ar.write_string(culture_name)?;
2619 }
2620 TextVariant::StringTableEntry { table, key } => {
2621 ar.write_i8(0xb)?;
2622 ar.write_string(table)?;
2623 write_string(ar, key)?;
2624 }
2625 }
2626 Ok(())
2627 }
2628}
2629
2630#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2632#[serde(untagged)]
2633pub enum Byte {
2634 Byte(u8),
2635 Label(String),
2636}
2637#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
2639pub enum ByteArray {
2640 Byte(Vec<u8>),
2641 Label(Vec<String>),
2642}
2643
2644#[derive(Debug, Clone, PartialEq, Serialize)]
2645#[serde(untagged)]
2646#[serde(bound(serialize = "T::ObjectRef: Serialize, T::SoftObjectPath: Serialize"))]
2647pub enum StructValue<T: ArchiveType = SaveGameArchiveType> {
2648 Guid(FGuid),
2649 DateTime(DateTime),
2650 Timespan(Timespan),
2651 Vector2D(Vector2D),
2652 Vector(Vector),
2653 Vector4(Vector4),
2654 IntVector(IntVector),
2655 Box(Box),
2656 Box2D(Box2D),
2657 IntPoint(IntPoint),
2658 Quat(Quat),
2659 LinearColor(LinearColor),
2660 Color(Color),
2661 Rotator(Rotator),
2662 SoftObjectPath(T::SoftObjectPath),
2663 SoftClassPath(T::SoftObjectPath),
2664 GameplayTagContainer(GameplayTagContainer),
2665 UniqueNetIdRepl(UniqueNetIdRepl),
2666 KeyHandleMap(FKeyHandleMap),
2667 RichCurveKey(FRichCurveKey),
2668 SkeletalMeshSamplingLODBuiltData(FSkeletalMeshSamplingLODBuiltData),
2669 PerPlatformFloat(FPerPlatformFloat),
2670 Raw(Vec<u8>),
2672 Struct(Properties<T>),
2674}
2675
2676#[derive(Debug, Clone, PartialEq, Serialize)]
2678#[serde(untagged)]
2679#[serde(bound(serialize = "T::ObjectRef: Serialize, T::SoftObjectPath: Serialize"))]
2680pub enum ValueVec<T: ArchiveType = SaveGameArchiveType> {
2681 Int8(Vec<Int8>),
2682 Int16(Vec<Int16>),
2683 Int(Vec<Int>),
2684 Int64(Vec<Int64>),
2685 UInt8(Vec<UInt8>),
2686 UInt16(Vec<UInt16>),
2687 UInt32(Vec<UInt32>),
2688 UInt64(Vec<UInt64>),
2689 Float(Vec<Float>),
2690 Double(Vec<Double>),
2691 Bool(Vec<bool>),
2692 Byte(ByteArray),
2693 Enum(Vec<Enum>),
2694 Str(Vec<String>),
2695 Text(Vec<Text>),
2696 SoftObject(Vec<T::SoftObjectPath>),
2697 Name(Vec<String>),
2698 Object(Vec<T::ObjectRef>),
2699 Box(Vec<Box>),
2700 Box2D(Vec<Box2D>),
2701 Struct(Vec<StructValue<T>>),
2702}
2703
2704impl<T: ArchiveType> StructValue<T> {
2705 #[cfg_attr(feature = "tracing", instrument(name = "StructValue_read", skip_all))]
2706 fn read<A: ArchiveReader<ArchiveType = T>>(
2707 ar: &mut A,
2708 t: &StructType,
2709 ) -> Result<StructValue<T>> {
2710 Ok(match t {
2711 StructType::Guid => StructValue::Guid(FGuid::read(ar)?),
2712 StructType::DateTime => StructValue::DateTime(ar.read_u64::<LE>()?),
2713 StructType::Timespan => StructValue::Timespan(ar.read_i64::<LE>()?),
2714 StructType::Vector2D => StructValue::Vector2D(Vector2D::read(ar)?),
2715 StructType::Vector => StructValue::Vector(Vector::read(ar)?),
2716 StructType::Vector4 => StructValue::Vector4(Vector4::read(ar)?),
2717 StructType::IntVector => StructValue::IntVector(IntVector::read(ar)?),
2718 StructType::Box => StructValue::Box(Box::read(ar)?),
2719 StructType::Box2D => StructValue::Box2D(Box2D::read(ar)?),
2720 StructType::IntPoint => StructValue::IntPoint(IntPoint::read(ar)?),
2721 StructType::Quat => StructValue::Quat(Quat::read(ar)?),
2722 StructType::LinearColor => StructValue::LinearColor(LinearColor::read(ar)?),
2723 StructType::Color => StructValue::Color(Color::read(ar)?),
2724 StructType::Rotator => StructValue::Rotator(Rotator::read(ar)?),
2725 StructType::SoftObjectPath => StructValue::SoftObjectPath(ar.read_soft_object_path()?),
2726 StructType::SoftClassPath => StructValue::SoftClassPath(ar.read_soft_object_path()?),
2727 StructType::GameplayTagContainer => {
2728 StructValue::GameplayTagContainer(GameplayTagContainer::read(ar)?)
2729 }
2730 StructType::UniqueNetIdRepl => StructValue::UniqueNetIdRepl(UniqueNetIdRepl::read(ar)?),
2731 StructType::KeyHandleMap => StructValue::KeyHandleMap(FKeyHandleMap::read(ar)?),
2732 StructType::RichCurveKey => StructValue::RichCurveKey(FRichCurveKey::read(ar)?),
2733 StructType::SkeletalMeshSamplingLODBuiltData => {
2734 StructValue::SkeletalMeshSamplingLODBuiltData(
2735 FSkeletalMeshSamplingLODBuiltData::read(ar)?,
2736 )
2737 }
2738 StructType::PerPlatformFloat => {
2739 StructValue::PerPlatformFloat(FPerPlatformFloat::read(ar)?)
2740 }
2741 StructType::Raw(_) => unreachable!("should be handled at property level"),
2742 StructType::Struct(_) => StructValue::Struct(read_properties_until_none(ar)?),
2743 })
2744 }
2745 fn write<A: ArchiveWriter<ArchiveType = T>>(&self, ar: &mut A) -> Result<()> {
2746 match self {
2747 StructValue::Guid(v) => v.write(ar)?,
2748 StructValue::DateTime(v) => ar.write_u64::<LE>(*v)?,
2749 StructValue::Timespan(v) => ar.write_i64::<LE>(*v)?,
2750 StructValue::Vector2D(v) => v.write(ar)?,
2751 StructValue::Vector(v) => v.write(ar)?,
2752 StructValue::Vector4(v) => v.write(ar)?,
2753 StructValue::IntVector(v) => v.write(ar)?,
2754 StructValue::Box(v) => v.write(ar)?,
2755 StructValue::Box2D(v) => v.write(ar)?,
2756 StructValue::IntPoint(v) => v.write(ar)?,
2757 StructValue::Quat(v) => v.write(ar)?,
2758 StructValue::LinearColor(v) => v.write(ar)?,
2759 StructValue::Color(v) => v.write(ar)?,
2760 StructValue::Rotator(v) => v.write(ar)?,
2761 StructValue::SoftObjectPath(v) => ar.write_soft_object_path(v)?,
2762 StructValue::SoftClassPath(v) => ar.write_soft_object_path(v)?,
2763 StructValue::GameplayTagContainer(v) => v.write(ar)?,
2764 StructValue::UniqueNetIdRepl(v) => v.write(ar)?,
2765 StructValue::KeyHandleMap(v) => v.write(ar)?,
2766 StructValue::RichCurveKey(v) => v.write(ar)?,
2767 StructValue::SkeletalMeshSamplingLODBuiltData(v) => v.write(ar)?,
2768 StructValue::PerPlatformFloat(v) => v.write(ar)?,
2769 StructValue::Raw(v) => ar.write_all(v)?,
2770 StructValue::Struct(v) => write_properties_none_terminated(ar, v)?,
2771 }
2772 Ok(())
2773 }
2774}
2775impl<T: ArchiveType> ValueVec<T> {
2776 #[cfg_attr(feature = "tracing", instrument(name = "ValueVec_read", skip_all))]
2777 fn read<A: ArchiveReader<ArchiveType = T>>(
2778 ar: &mut A,
2779 t: &PropertyType,
2780 size: u32,
2781 count: u32,
2782 ) -> Result<ValueVec<T>> {
2783 Ok(match t {
2784 PropertyType::IntProperty => {
2785 ValueVec::Int(read_array(count, ar, |r| Ok(r.read_i32::<LE>()?))?)
2786 }
2787 PropertyType::Int16Property => {
2788 ValueVec::Int16(read_array(count, ar, |r| Ok(r.read_i16::<LE>()?))?)
2789 }
2790 PropertyType::Int64Property => {
2791 ValueVec::Int64(read_array(count, ar, |r| Ok(r.read_i64::<LE>()?))?)
2792 }
2793 PropertyType::UInt16Property => {
2794 ValueVec::UInt16(read_array(count, ar, |r| Ok(r.read_u16::<LE>()?))?)
2795 }
2796 PropertyType::UInt32Property => {
2797 ValueVec::UInt32(read_array(count, ar, |r| Ok(r.read_u32::<LE>()?))?)
2798 }
2799 PropertyType::FloatProperty => {
2800 ValueVec::Float(read_array(count, ar, |r| Ok(r.read_f32::<LE>()?.into()))?)
2801 }
2802 PropertyType::DoubleProperty => {
2803 ValueVec::Double(read_array(count, ar, |r| Ok(r.read_f64::<LE>()?.into()))?)
2804 }
2805 PropertyType::BoolProperty => {
2806 ValueVec::Bool(read_array(count, ar, |r| Ok(r.read_u8()? > 0))?)
2807 }
2808 PropertyType::ByteProperty => {
2809 if size == count {
2810 ValueVec::Byte(ByteArray::Byte(read_array(
2811 count,
2812 ar,
2813 |r| Ok(r.read_u8()?),
2814 )?))
2815 } else {
2816 ValueVec::Byte(ByteArray::Label(read_array(count, ar, |r| {
2817 r.read_string()
2818 })?))
2819 }
2820 }
2821 PropertyType::EnumProperty => {
2822 ValueVec::Enum(read_array(count, ar, |r| r.read_string())?)
2823 }
2824 PropertyType::StrProperty => ValueVec::Str(read_array(count, ar, |r| read_string(r))?),
2825 PropertyType::TextProperty => ValueVec::Text(read_array(count, ar, Text::read)?),
2826 PropertyType::SoftObjectProperty => {
2827 ValueVec::SoftObject(read_array(count, ar, |r| r.read_soft_object_path())?)
2828 }
2829 PropertyType::NameProperty => {
2830 ValueVec::Name(read_array(count, ar, |r| r.read_string())?)
2831 }
2832 PropertyType::ObjectProperty => {
2833 ValueVec::Object(read_array(count, ar, |r| r.read_object_ref())?)
2834 }
2835 _ => return Err(Error::UnknownVecType(format!("{t:?}"))),
2836 })
2837 }
2838 fn write<A: ArchiveWriter<ArchiveType = T>>(&self, ar: &mut A) -> Result<()> {
2839 match &self {
2840 ValueVec::Int8(v) => {
2841 ar.write_u32::<LE>(v.len() as u32)?;
2842 for i in v {
2843 ar.write_i8(*i)?;
2844 }
2845 }
2846 ValueVec::Int16(v) => {
2847 ar.write_u32::<LE>(v.len() as u32)?;
2848 for i in v {
2849 ar.write_i16::<LE>(*i)?;
2850 }
2851 }
2852 ValueVec::Int(v) => {
2853 ar.write_u32::<LE>(v.len() as u32)?;
2854 for i in v {
2855 ar.write_i32::<LE>(*i)?;
2856 }
2857 }
2858 ValueVec::Int64(v) => {
2859 ar.write_u32::<LE>(v.len() as u32)?;
2860 for i in v {
2861 ar.write_i64::<LE>(*i)?;
2862 }
2863 }
2864 ValueVec::UInt8(v) => {
2865 ar.write_u32::<LE>(v.len() as u32)?;
2866 for i in v {
2867 ar.write_u8(*i)?;
2868 }
2869 }
2870 ValueVec::UInt16(v) => {
2871 ar.write_u32::<LE>(v.len() as u32)?;
2872 for i in v {
2873 ar.write_u16::<LE>(*i)?;
2874 }
2875 }
2876 ValueVec::UInt32(v) => {
2877 ar.write_u32::<LE>(v.len() as u32)?;
2878 for i in v {
2879 ar.write_u32::<LE>(*i)?;
2880 }
2881 }
2882 ValueVec::UInt64(v) => {
2883 ar.write_u32::<LE>(v.len() as u32)?;
2884 for i in v {
2885 ar.write_u64::<LE>(*i)?;
2886 }
2887 }
2888 ValueVec::Float(v) => {
2889 ar.write_u32::<LE>(v.len() as u32)?;
2890 for i in v {
2891 ar.write_f32::<LE>((*i).into())?;
2892 }
2893 }
2894 ValueVec::Double(v) => {
2895 ar.write_u32::<LE>(v.len() as u32)?;
2896 for i in v {
2897 ar.write_f64::<LE>((*i).into())?;
2898 }
2899 }
2900 ValueVec::Bool(v) => {
2901 ar.write_u32::<LE>(v.len() as u32)?;
2902 for b in v {
2903 ar.write_u8(*b as u8)?;
2904 }
2905 }
2906 ValueVec::Byte(v) => match v {
2907 ByteArray::Byte(b) => {
2908 ar.write_u32::<LE>(b.len() as u32)?;
2909 for b in b {
2910 ar.write_u8(*b)?;
2911 }
2912 }
2913 ByteArray::Label(l) => {
2914 ar.write_u32::<LE>(l.len() as u32)?;
2915 for l in l {
2916 ar.write_string(l)?;
2917 }
2918 }
2919 },
2920 ValueVec::Enum(v) => {
2921 ar.write_u32::<LE>(v.len() as u32)?;
2922 for i in v {
2923 ar.write_string(i)?;
2924 }
2925 }
2926 ValueVec::Str(v) => {
2927 ar.write_u32::<LE>(v.len() as u32)?;
2928 for i in v {
2929 write_string(ar, i)?;
2930 }
2931 }
2932 ValueVec::Name(v) => {
2933 ar.write_u32::<LE>(v.len() as u32)?;
2934 for i in v {
2935 ar.write_string(i)?;
2936 }
2937 }
2938 ValueVec::Object(v) => {
2939 ar.write_u32::<LE>(v.len() as u32)?;
2940 for i in v {
2941 ar.write_object_ref(i)?;
2942 }
2943 }
2944 ValueVec::Text(v) => {
2945 ar.write_u32::<LE>(v.len() as u32)?;
2946 for i in v {
2947 i.write(ar)?;
2948 }
2949 }
2950 ValueVec::SoftObject(v) => {
2951 ar.write_u32::<LE>(v.len() as u32)?;
2952 for i in v {
2953 ar.write_soft_object_path(i)?;
2954 }
2955 }
2956 ValueVec::Box(v) => {
2957 ar.write_u32::<LE>(v.len() as u32)?;
2958 for i in v {
2959 i.write(ar)?;
2960 }
2961 }
2962 ValueVec::Box2D(v) => {
2963 ar.write_u32::<LE>(v.len() as u32)?;
2964 for i in v {
2965 i.write(ar)?;
2966 }
2967 }
2968 ValueVec::Struct(v) => {
2969 ar.write_u32::<LE>(v.len() as u32)?;
2970 for i in v {
2971 i.write(ar)?;
2972 }
2973 }
2974 }
2975 Ok(())
2976 }
2977}
2978impl<T: ArchiveType> ValueVec<T> {
2979 #[cfg_attr(
2980 feature = "tracing",
2981 instrument(name = "ValueVec_read_array", skip_all)
2982 )]
2983 fn read_array<A: ArchiveReader<ArchiveType = T>>(
2984 ar: &mut A,
2985 tag: PropertyTagDataFull,
2986 size: u32,
2987 ) -> Result<(ValueVec<T>, Option<PropertyTagDataFull>)> {
2988 let count = ar.read_u32::<LE>()?;
2989 Ok(match tag {
2990 PropertyTagDataFull::Struct { struct_type, id: _ } => {
2991 let (struct_type, updated) = if !ar.version().property_tag() {
2992 if ar.version().array_inner_tag() {
2994 let inner_tag = PropertyTagFull::read(ar)?.unwrap();
2996 match inner_tag.data {
2997 PropertyTagDataFull::Struct { struct_type, id } => {
2998 (
3000 struct_type.clone(),
3001 Some(PropertyTagDataFull::Struct { struct_type, id }),
3002 )
3003 }
3004 _ => {
3005 return Err(Error::Other(format!(
3006 "expected StructProperty tag, found {inner_tag:?}"
3007 )))
3008 }
3009 }
3010 } else {
3011 (StructType::Struct(None), None)
3014 }
3015 } else {
3016 (struct_type, None)
3017 };
3018
3019 let mut value = vec![];
3020 for _ in 0..count {
3021 value.push(StructValue::read(ar, &struct_type)?);
3022 }
3023 (ValueVec::Struct(value), updated)
3024 }
3025 _ => (ValueVec::read(ar, &tag.basic_type(), size, count)?, None),
3026 })
3027 }
3028 fn write_array<A: ArchiveWriter<ArchiveType = T>>(
3029 &self,
3030 ar: &mut A,
3031 tag: &PropertyTagFull,
3032 ) -> Result<()> {
3033 match &self {
3034 ValueVec::Struct(value) => {
3035 ar.write_u32::<LE>(value.len() as u32)?;
3036
3037 if !ar.version().property_tag() && ar.version().array_inner_tag() {
3038 let (struct_type, id) = match &tag.data {
3040 PropertyTagDataFull::Array(inner) => match &**inner {
3041 PropertyTagDataFull::Struct { struct_type, id } => (struct_type, id),
3042 _ => {
3043 return Err(Error::Other(
3044 "Array tag must contain Struct type".into(),
3045 ))
3046 }
3047 },
3048 _ => return Err(Error::Other("Expected Array tag".into())),
3049 };
3050
3051 ar.write_string(&tag.name)?;
3053 PropertyType::StructProperty.write(ar)?;
3054
3055 let size_pos = ar.stream_position()?;
3057 ar.write_u32::<LE>(0)?;
3058 ar.write_u32::<LE>(0)?;
3059 struct_type.write(ar)?;
3060 id.write(ar)?;
3061 ar.write_u8(0)?;
3062
3063 let data_start = ar.stream_position()?;
3065 for v in value {
3066 v.write(ar)?;
3067 }
3068 let data_end = ar.stream_position()?;
3069 let size = (data_end - data_start) as u32;
3070
3071 ar.seek(std::io::SeekFrom::Start(size_pos))?;
3073 ar.write_u32::<LE>(size)?;
3074 ar.seek(std::io::SeekFrom::Start(data_end))?;
3075 } else {
3076 for v in value {
3077 v.write(ar)?;
3078 }
3079 }
3080 }
3081 _ => {
3082 self.write(ar)?;
3083 }
3084 }
3085 Ok(())
3086 }
3087 #[cfg_attr(feature = "tracing", instrument(name = "ValueVec_read_set", skip_all))]
3088 fn read_set<A: ArchiveReader<ArchiveType = T>>(
3089 ar: &mut A,
3090 t: &PropertyTagDataFull,
3091 size: u32,
3092 ) -> Result<ValueVec<T>> {
3093 let count = ar.read_u32::<LE>()?;
3094 Ok(match t {
3095 PropertyTagDataFull::Struct { struct_type, .. } => {
3096 ValueVec::Struct(read_array(count, ar, |r| {
3097 StructValue::read(r, struct_type)
3098 })?)
3099 }
3100 _ => ValueVec::read(ar, &t.basic_type(), size, count)?,
3101 })
3102 }
3103}
3104
3105#[derive(Debug, Clone, PartialEq, Serialize)]
3108#[serde(untagged)]
3109#[serde(bound(serialize = "T::ObjectRef: Serialize, T::SoftObjectPath: Serialize"))]
3110pub enum Property<T: ArchiveType = SaveGameArchiveType> {
3111 Int8(Int8),
3112 Int16(Int16),
3113 Int(Int),
3114 Int64(Int64),
3115 UInt8(UInt8),
3116 UInt16(UInt16),
3117 UInt32(UInt32),
3118 UInt64(UInt64),
3119 Float(Float),
3120 Double(Double),
3121 Bool(Bool),
3122 Byte(Byte),
3123 Enum(Enum),
3124 Str(String),
3125 FieldPath(FieldPath),
3126 SoftObject(T::SoftObjectPath),
3127 Name(String),
3128 Object(T::ObjectRef),
3129 Text(Text),
3130 Delegate(Delegate<T>),
3131 MulticastDelegate(MulticastDelegate<T>),
3132 MulticastInlineDelegate(MulticastInlineDelegate<T>),
3133 MulticastSparseDelegate(MulticastSparseDelegate<T>),
3134 Set(ValueVec<T>),
3135 Map(Vec<MapEntry<T>>),
3136 Struct(StructValue<T>),
3137 Array(ValueVec<T>),
3138 Raw(Vec<u8>),
3140}
3141
3142impl<T: ArchiveType> Property<T> {
3143 #[cfg_attr(feature = "tracing", instrument(name = "Property_read", skip_all))]
3144 fn read<A: ArchiveReader<ArchiveType = T>>(
3145 ar: &mut A,
3146 tag: PropertyTagFull,
3147 ) -> Result<(Property<T>, Option<PropertyTagDataFull>)> {
3148 if tag.data.has_raw_struct() {
3149 let mut raw = vec![0; tag.size as usize];
3150 ar.read_exact(&mut raw)?;
3151 return Ok((Property::Raw(raw), None));
3152 }
3153 let start_position = ar.stream_position()?;
3155
3156 let (inner, updated_tag_data) = match Self::try_read_inner(ar, &tag) {
3158 Ok(result) => result,
3159 Err(e) => {
3160 if ar.error_to_raw() {
3162 if ar.log() {
3164 eprintln!("Warning: Failed to parse property '{}': {}", ar.path(), e);
3165 }
3166 ar.seek(std::io::SeekFrom::Start(start_position))?;
3167 let mut property_data = vec![0u8; tag.size as usize];
3168 ar.read_exact(&mut property_data)?;
3169 (Property::Raw(property_data), None)
3170 } else {
3171 return Err(e);
3173 }
3174 }
3175 };
3176
3177 Ok((inner, updated_tag_data))
3178 }
3179
3180 fn try_read_inner<A: ArchiveReader<ArchiveType = T>>(
3181 ar: &mut A,
3182 tag: &PropertyTagFull,
3183 ) -> Result<(Property<T>, Option<PropertyTagDataFull>)> {
3184 let (inner, updated_tag_data) = match &tag.data {
3185 PropertyTagDataFull::Set { key_type } => {
3187 ar.read_u32::<LE>()?;
3188 (
3189 Property::Set(ValueVec::read_set(ar, key_type, tag.size - 8)?),
3190 None,
3191 )
3192 }
3193 PropertyTagDataFull::Map {
3194 key_type,
3195 value_type,
3196 } => {
3197 let _keys_to_remove = read_array(ar.read_u32::<LE>()?, ar, |ar| {
3199 Property::read_value(ar, key_type)
3200 })?;
3201 let count = ar.read_u32::<LE>()?;
3202 let mut value = vec![];
3203
3204 for _ in 0..count {
3205 value.push(MapEntry::read(ar, key_type, value_type)?)
3206 }
3207
3208 (Property::Map(value), None)
3209 }
3210 PropertyTagDataFull::Array(data) => {
3211 let (array, updated_data) = ValueVec::read_array(ar, *data.clone(), tag.size - 4)?;
3212 (Property::Array(array), updated_data)
3213 }
3214 PropertyTagDataFull::Bool(value) => (Property::Bool(*value), None),
3216 PropertyTagDataFull::Other(PropertyType::FieldPathProperty) => {
3217 (Property::FieldPath(FieldPath::read(ar)?), None)
3218 }
3219 PropertyTagDataFull::Other(PropertyType::DelegateProperty) => {
3220 (Property::Delegate(Delegate::read(ar)?), None)
3221 }
3222 PropertyTagDataFull::Other(PropertyType::MulticastDelegateProperty) => (
3223 Property::MulticastDelegate(MulticastDelegate::read(ar)?),
3224 None,
3225 ),
3226 PropertyTagDataFull::Other(PropertyType::MulticastInlineDelegateProperty) => (
3227 Property::MulticastInlineDelegate(MulticastInlineDelegate::read(ar)?),
3228 None,
3229 ),
3230 PropertyTagDataFull::Other(PropertyType::MulticastSparseDelegateProperty) => (
3231 Property::MulticastSparseDelegate(MulticastSparseDelegate::read(ar)?),
3232 None,
3233 ),
3234 _ => (Property::read_value(ar, &tag.data)?, None),
3236 };
3237
3238 let updated_tag =
3240 updated_tag_data.map(|data| PropertyTagDataFull::Array(std::boxed::Box::new(data)));
3241
3242 Ok((inner, updated_tag))
3243 }
3244 fn write<A: ArchiveWriter<ArchiveType = T>>(
3245 &self,
3246 ar: &mut A,
3247 tag: &PropertyTagFull,
3248 ) -> Result<()> {
3249 match &self {
3250 Property::Set(value) => {
3251 ar.write_u32::<LE>(0)?;
3252 value.write(ar)?;
3253 }
3254 Property::Map(value) => {
3255 ar.write_u32::<LE>(0)?;
3256 ar.write_u32::<LE>(value.len() as u32)?;
3257 for v in value {
3258 v.write(ar)?;
3259 }
3260 }
3261 Property::Array(value) => {
3262 value.write_array(ar, tag)?;
3263 }
3264 Property::Raw(value) => {
3265 ar.write_all(value)?;
3266 }
3267 Property::FieldPath(value) => {
3268 value.write(ar)?;
3269 }
3270 Property::Delegate(value) => {
3271 value.write(ar)?;
3272 }
3273 Property::MulticastDelegate(value) => {
3274 value.write(ar)?;
3275 }
3276 Property::MulticastInlineDelegate(value) => {
3277 value.write(ar)?;
3278 }
3279 Property::MulticastSparseDelegate(value) => {
3280 value.write(ar)?;
3281 }
3282 Property::Bool(_) => {}
3284 _ => self.write_value(ar)?,
3286 }
3287 Ok(())
3288 }
3289
3290 #[cfg_attr(
3291 feature = "tracing",
3292 instrument(name = "Property_read_value", skip_all)
3293 )]
3294 fn read_value<A: ArchiveReader<ArchiveType = T>>(
3295 ar: &mut A,
3296 t: &PropertyTagDataFull,
3297 ) -> Result<Property<T>> {
3298 Ok(match t {
3299 PropertyTagDataFull::Array(_) => {
3300 unreachable!("Arrays should be handled at property level")
3301 }
3302 PropertyTagDataFull::Set { .. } => {
3303 unreachable!("Sets should be handled at property level")
3304 }
3305 PropertyTagDataFull::Map { .. } => {
3306 unreachable!("Maps should be handled at property level")
3307 }
3308 PropertyTagDataFull::Struct { struct_type, .. } => {
3309 Property::Struct(StructValue::read(ar, struct_type)?)
3310 }
3311 PropertyTagDataFull::Byte(ref enum_type) => {
3312 let value = if enum_type.is_none() {
3313 Byte::Byte(ar.read_u8()?)
3314 } else {
3315 Byte::Label(ar.read_string()?)
3316 };
3317 Property::Byte(value)
3318 }
3319 PropertyTagDataFull::Enum(_, _) => Property::Enum(ar.read_string()?),
3320 PropertyTagDataFull::Bool(_) => Property::Bool(ar.read_u8()? > 0),
3321 PropertyTagDataFull::Other(property_type) => match property_type {
3322 PropertyType::BoolProperty
3323 | PropertyType::ByteProperty
3324 | PropertyType::EnumProperty
3325 | PropertyType::SetProperty
3326 | PropertyType::MapProperty
3327 | PropertyType::StructProperty
3328 | PropertyType::ArrayProperty
3329 | PropertyType::FieldPathProperty
3330 | PropertyType::DelegateProperty
3331 | PropertyType::MulticastDelegateProperty
3332 | PropertyType::MulticastInlineDelegateProperty
3333 | PropertyType::MulticastSparseDelegateProperty => {
3334 unreachable!("Should be handled by dedicated tag variants")
3335 }
3336 PropertyType::Int8Property => Property::Int8(ar.read_i8()?),
3337 PropertyType::Int16Property => Property::Int16(ar.read_i16::<LE>()?),
3338 PropertyType::IntProperty => Property::Int(ar.read_i32::<LE>()?),
3339 PropertyType::Int64Property => Property::Int64(ar.read_i64::<LE>()?),
3340 PropertyType::UInt8Property => Property::UInt8(ar.read_u8()?),
3341 PropertyType::UInt16Property => Property::UInt16(ar.read_u16::<LE>()?),
3342 PropertyType::UInt32Property => Property::UInt32(ar.read_u32::<LE>()?),
3343 PropertyType::UInt64Property => Property::UInt64(ar.read_u64::<LE>()?),
3344 PropertyType::FloatProperty => Property::Float(ar.read_f32::<LE>()?.into()),
3345 PropertyType::DoubleProperty => Property::Double(ar.read_f64::<LE>()?.into()),
3346 PropertyType::NameProperty => Property::Name(ar.read_string()?),
3347 PropertyType::StrProperty => Property::Str(read_string(ar)?),
3348 PropertyType::SoftObjectProperty => {
3349 Property::SoftObject(ar.read_soft_object_path()?)
3350 }
3351 PropertyType::ObjectProperty => Property::Object(ar.read_object_ref()?),
3352 PropertyType::TextProperty => Property::Text(Text::read(ar)?),
3353 },
3354 })
3355 }
3356
3357 fn write_value<A: ArchiveWriter<ArchiveType = T>>(&self, ar: &mut A) -> Result<()> {
3358 match &self {
3359 Property::Int8(v) => ar.write_i8(*v)?,
3360 Property::Int16(v) => ar.write_i16::<LE>(*v)?,
3361 Property::Int(v) => ar.write_i32::<LE>(*v)?,
3362 Property::Int64(v) => ar.write_i64::<LE>(*v)?,
3363 Property::UInt8(v) => ar.write_u8(*v)?,
3364 Property::UInt16(v) => ar.write_u16::<LE>(*v)?,
3365 Property::UInt32(v) => ar.write_u32::<LE>(*v)?,
3366 Property::UInt64(v) => ar.write_u64::<LE>(*v)?,
3367 Property::Float(v) => ar.write_f32::<LE>((*v).into())?,
3368 Property::Double(v) => ar.write_f64::<LE>((*v).into())?,
3369 Property::Bool(v) => ar.write_u8(u8::from(*v))?,
3370 Property::Byte(v) => match v {
3371 Byte::Byte(b) => ar.write_u8(*b)?,
3372 Byte::Label(l) => ar.write_string(l)?,
3373 },
3374 Property::Enum(v) => ar.write_string(v)?,
3375 Property::Name(v) => ar.write_string(v)?,
3376 Property::Str(v) => write_string(ar, v)?,
3377 Property::SoftObject(v) => ar.write_soft_object_path(v)?,
3378 Property::Object(v) => ar.write_object_ref(v)?,
3379 Property::Text(v) => v.write(ar)?,
3380 Property::Struct(v) => v.write(ar)?,
3381 Property::Set(_)
3382 | Property::Map(_)
3383 | Property::Array(_)
3384 | Property::FieldPath(_)
3385 | Property::Delegate(_)
3386 | Property::MulticastDelegate(_)
3387 | Property::MulticastInlineDelegate(_)
3388 | Property::MulticastSparseDelegate(_)
3389 | Property::Raw(_) => {
3390 return Err(Error::Other(format!(
3391 "Property variant {:?} cannot be written in value context (Maps/Sets/Arrays)",
3392 self
3393 )))
3394 }
3395 };
3396 Ok(())
3397 }
3398}
3399
3400#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
3401pub struct CustomFormatData {
3402 pub id: FGuid,
3403 pub value: i32,
3404}
3405impl CustomFormatData {
3406 #[cfg_attr(
3407 feature = "tracing",
3408 instrument(name = "CustomFormatData_read", skip_all)
3409 )]
3410 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
3411 Ok(CustomFormatData {
3412 id: FGuid::read(ar)?,
3413 value: ar.read_i32::<LE>()?,
3414 })
3415 }
3416}
3417impl CustomFormatData {
3418 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
3419 self.id.write(ar)?;
3420 ar.write_i32::<LE>(self.value)?;
3421 Ok(())
3422 }
3423}
3424
3425#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
3426pub struct PackageVersion {
3427 ue4: u32,
3428 ue5: Option<u32>,
3429}
3430
3431pub trait VersionInfo {
3432 fn engine_version_major(&self) -> u16;
3433 fn engine_version_minor(&self) -> u16;
3434 fn engine_version_patch(&self) -> u16;
3435 fn package_file_version_ue4(&self) -> u32;
3436 fn package_file_version_ue5(&self) -> u32;
3437
3438 fn large_world_coordinates(&self) -> bool {
3440 self.engine_version_major() >= 5
3441 }
3442
3443 fn property_tag(&self) -> bool {
3445 (self.engine_version_major(), self.engine_version_minor()) >= (5, 4)
3447 }
3448
3449 fn property_guid(&self) -> bool {
3451 (self.engine_version_major(), self.engine_version_minor()) >= (4, 12)
3453 }
3454
3455 fn array_inner_tag(&self) -> bool {
3457 (self.engine_version_major(), self.engine_version_minor()) >= (4, 12)
3459 }
3460
3461 fn remove_asset_path_fnames(&self) -> bool {
3463 self.package_file_version_ue5() >= 1007
3465 }
3466}
3467
3468#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
3469pub struct Header {
3470 pub magic: u32,
3471 pub save_game_version: u32,
3472 pub package_version: PackageVersion,
3473 pub engine_version_major: u16,
3474 pub engine_version_minor: u16,
3475 pub engine_version_patch: u16,
3476 pub engine_version_build: u32,
3477 pub engine_version: String,
3478 pub custom_version: Option<(u32, Vec<CustomFormatData>)>,
3479}
3480impl VersionInfo for Header {
3481 fn engine_version_major(&self) -> u16 {
3482 self.engine_version_major
3483 }
3484 fn engine_version_minor(&self) -> u16 {
3485 self.engine_version_minor
3486 }
3487 fn engine_version_patch(&self) -> u16 {
3488 self.engine_version_patch
3489 }
3490 fn package_file_version_ue4(&self) -> u32 {
3491 self.package_version.ue4
3492 }
3493 fn package_file_version_ue5(&self) -> u32 {
3494 self.package_version.ue5.unwrap_or(0)
3495 }
3496}
3497impl Header {
3498 #[cfg_attr(feature = "tracing", instrument(name = "Header_read", skip_all))]
3499 fn read<A: ArchiveReader>(ar: &mut A) -> Result<Self> {
3500 let magic = ar.read_u32::<LE>()?;
3501 if ar.log() && magic != u32::from_le_bytes(*b"GVAS") {
3502 eprintln!(
3503 "Found non-standard magic: {:02x?} ({}) expected: GVAS, continuing to parse...",
3504 &magic.to_le_bytes(),
3505 String::from_utf8_lossy(&magic.to_le_bytes())
3506 );
3507 }
3508 let save_game_version = ar.read_u32::<LE>()?;
3509 let package_version = PackageVersion {
3510 ue4: ar.read_u32::<LE>()?,
3511 ue5: (save_game_version >= 3 && save_game_version != 34) .then(|| ar.read_u32::<LE>())
3513 .transpose()?,
3514 };
3515 let engine_version_major = ar.read_u16::<LE>()?;
3516 let engine_version_minor = ar.read_u16::<LE>()?;
3517 let engine_version_patch = ar.read_u16::<LE>()?;
3518 let engine_version_build = ar.read_u32::<LE>()?;
3519 let engine_version = ar.read_string()?;
3520 let custom_version = if (engine_version_major, engine_version_minor) >= (4, 12) {
3521 Some((
3522 ar.read_u32::<LE>()?,
3523 read_array(ar.read_u32::<LE>()?, ar, CustomFormatData::read)?,
3524 ))
3525 } else {
3526 None
3527 };
3528 Ok(Header {
3529 magic,
3530 save_game_version,
3531 package_version,
3532 engine_version_major,
3533 engine_version_minor,
3534 engine_version_patch,
3535 engine_version_build,
3536 engine_version,
3537 custom_version,
3538 })
3539 }
3540}
3541impl Header {
3542 fn write<A: ArchiveWriter>(&self, ar: &mut A) -> Result<()> {
3543 ar.write_u32::<LE>(self.magic)?;
3544 ar.write_u32::<LE>(self.save_game_version)?;
3545 ar.write_u32::<LE>(self.package_version.ue4)?;
3546 if let Some(ue5) = self.package_version.ue5 {
3547 ar.write_u32::<LE>(ue5)?;
3548 }
3549 ar.write_u16::<LE>(self.engine_version_major)?;
3550 ar.write_u16::<LE>(self.engine_version_minor)?;
3551 ar.write_u16::<LE>(self.engine_version_patch)?;
3552 ar.write_u32::<LE>(self.engine_version_build)?;
3553 ar.write_string(&self.engine_version)?;
3554 if let Some((custom_format_version, custom_format)) = &self.custom_version {
3555 ar.write_u32::<LE>(*custom_format_version)?;
3556 ar.write_u32::<LE>(custom_format.len() as u32)?;
3557 for cf in custom_format {
3558 cf.write(ar)?;
3559 }
3560 }
3561 Ok(())
3562 }
3563}
3564
3565#[derive(Debug, PartialEq, Serialize)]
3567pub struct Root {
3568 pub save_game_type: String,
3569 pub properties: Properties,
3570}
3571impl Root {
3572 #[cfg_attr(feature = "tracing", instrument(name = "Root_read", skip_all))]
3573 fn read<A: ArchiveReader<ArchiveType = SaveGameArchiveType>>(ar: &mut A) -> Result<Self> {
3574 let save_game_type = ar.read_string()?;
3575 if ar.version().property_tag() {
3576 ar.read_u8()?;
3577 }
3578 let properties = read_properties_until_none(ar)?;
3579 Ok(Self {
3580 save_game_type,
3581 properties,
3582 })
3583 }
3584 fn write<A: ArchiveWriter<ArchiveType = SaveGameArchiveType>>(&self, ar: &mut A) -> Result<()> {
3585 ar.write_string(&self.save_game_type)?;
3586 if ar.version().property_tag() {
3587 ar.write_u8(0)?;
3588 }
3589 write_properties_none_terminated(ar, &self.properties)?;
3590 Ok(())
3591 }
3592}
3593
3594#[derive(Debug, PartialEq, Serialize)]
3595pub struct Save {
3596 pub header: Header,
3597 pub schemas: PropertySchemas,
3599 pub root: Root,
3600 pub extra: Vec<u8>,
3601}
3602impl Save {
3603 #[cfg_attr(feature = "tracing", instrument(name = "Root_read", skip_all))]
3605 pub fn read<R: Read>(reader: &mut R) -> Result<Self, ParseError> {
3606 Self::read_with_types(reader, Types::new())
3607 }
3608 #[cfg_attr(
3610 feature = "tracing",
3611 instrument(name = "Save_read_with_types", skip_all)
3612 )]
3613 pub fn read_with_types<R: Read>(reader: &mut R, types: Types) -> Result<Self, ParseError> {
3614 SaveReader::new().types(types).read(reader)
3615 }
3616 pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
3617 let mut buffer = vec![];
3618 let schemas = Rc::new(RefCell::new(self.schemas.clone()));
3619
3620 let mut archive_writer = SaveGameArchive {
3621 stream: Cursor::new(&mut buffer),
3622 version: Some(self.header.clone()),
3623 types: Rc::new(Types::new()),
3624 scope: Scope::root(),
3625 log: false,
3626 error_to_raw: true,
3627 schemas,
3628 };
3629
3630 self.header.write(&mut archive_writer)?;
3631 self.root.write(&mut archive_writer)?;
3632 archive_writer.write_all(&self.extra)?;
3633
3634 writer.write_all(&buffer)?;
3635 Ok(())
3636 }
3637}
3638
3639pub struct SaveReader {
3640 log: bool,
3641 error_to_raw: bool,
3642 types: Option<Rc<Types>>,
3643}
3644impl Default for SaveReader {
3645 fn default() -> Self {
3646 Self::new()
3647 }
3648}
3649impl SaveReader {
3650 pub fn new() -> Self {
3651 Self {
3652 log: false,
3653 error_to_raw: false,
3654 types: None,
3655 }
3656 }
3657 pub fn log(mut self, log: bool) -> Self {
3658 self.log = log;
3659 self
3660 }
3661 pub fn error_to_raw(mut self, error_to_raw: bool) -> Self {
3670 self.error_to_raw = error_to_raw;
3671 self
3672 }
3673 pub fn types(mut self, types: Types) -> Self {
3674 self.types = Some(Rc::new(types));
3675 self
3676 }
3677 pub fn read<S: Read>(self, stream: S) -> Result<Save, ParseError> {
3678 let types = self.types.unwrap_or_else(|| Rc::new(Types::new()));
3679 let schemas = Rc::new(RefCell::new(PropertySchemas::new()));
3680
3681 let stream = SeekReader::new(stream);
3682 let mut reader = SaveGameArchive {
3683 stream,
3684 version: None,
3685 types,
3686 scope: Scope::root(),
3687 log: self.log,
3688 error_to_raw: self.error_to_raw,
3689 schemas: schemas.clone(),
3690 };
3691
3692 let result = || -> Result<_> {
3693 let header = Header::read(&mut reader)?;
3694 reader.set_version(header.clone());
3695
3696 let root = Root::read(&mut reader)?;
3697 let extra = {
3698 let mut buf = vec![];
3699 reader.read_to_end(&mut buf)?;
3700 if reader.log() && buf != [0; 4] {
3701 eprintln!(
3702 "{} extra bytes. Save may not have been parsed completely.",
3703 buf.len()
3704 );
3705 }
3706 buf
3707 };
3708
3709 Ok((header, root, extra))
3710 }();
3711
3712 let offset = reader.stream_position().unwrap() as usize;
3713
3714 drop(reader);
3715
3716 let schemas = Rc::try_unwrap(schemas)
3717 .expect("Failed to extract schemas")
3718 .into_inner();
3719
3720 result
3721 .map(|(header, root, extra)| Save {
3722 header,
3723 schemas,
3724 root,
3725 extra,
3726 })
3727 .map_err(|e| error::ParseError { offset, error: e })
3728 }
3729}