uesave/
lib.rs

1/*!
2A library for reading and writing Unreal Engine save files (commonly referred to
3as GVAS).
4
5It has been tested on an extensive set of object structures and can fully read
6and write Deep Rock Galactic save files (and likely a lot more).
7
8There is a small binary utility to quickly convert saves to and from a plain
9text JSON format which can be used for manual save editing.
10
11# Example
12
13```
14use std::fs::File;
15
16use uesave::{Property, PropertyInner, Save};
17
18let save = Save::read(&mut File::open("drg-save-test.sav")?)?;
19match save.root.properties["NumberOfGamesPlayed"] {
20    Property { inner: PropertyInner::Int(value), .. } => {
21        assert_eq!(2173, value);
22    }
23    _ => {}
24}
25# Ok::<(), Box<dyn std::error::Error>>(())
26
27```
28*/
29
30mod error;
31
32#[cfg(test)]
33mod tests;
34
35pub use error::{Error, ParseError};
36
37use byteorder::{ReadBytesExt, WriteBytesExt, LE};
38use std::{
39    borrow::Cow,
40    io::{Read, Seek, Write},
41};
42
43use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
44
45type TResult<T> = Result<T, Error>;
46
47trait Readable<R: Read + Seek, V> {
48    fn read(reader: &mut Context<R, V>) -> TResult<Self>
49    where
50        Self: Sized;
51}
52trait Writable<W, V> {
53    fn write(&self, writer: &mut Context<W, V>) -> TResult<()>;
54}
55
56struct SeekReader<R: Read> {
57    reader: R,
58    read_bytes: usize,
59}
60
61impl<R: Read> SeekReader<R> {
62    fn new(reader: R) -> Self {
63        Self {
64            reader,
65            read_bytes: 0,
66        }
67    }
68}
69impl<R: Read> Seek for SeekReader<R> {
70    fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
71        match pos {
72            std::io::SeekFrom::Current(0) => Ok(self.read_bytes as u64),
73            _ => unimplemented!(),
74        }
75    }
76}
77impl<R: Read> Read for SeekReader<R> {
78    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
79        self.reader.read(buf).inspect(|s| self.read_bytes += s)
80    }
81}
82
83fn read_optional_uuid<R: Read + Seek, V>(
84    reader: &mut Context<R, V>,
85) -> TResult<Option<uuid::Uuid>> {
86    Ok(if reader.read_u8()? > 0 {
87        Some(uuid::Uuid::read(reader)?)
88    } else {
89        None
90    })
91}
92fn write_optional_uuid<W: Write, V>(
93    writer: &mut Context<W, V>,
94    id: Option<uuid::Uuid>,
95) -> TResult<()> {
96    if let Some(id) = id {
97        writer.write_u8(1)?;
98        id.write(writer)?;
99    } else {
100        writer.write_u8(0)?;
101    }
102    Ok(())
103}
104
105fn read_string<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<String> {
106    let len = reader.read_i32::<LE>()?;
107    if len < 0 {
108        let chars = read_array((-len) as u32, reader, |r| Ok(r.read_u16::<LE>()?))?;
109        let length = chars.iter().position(|&c| c == 0).unwrap_or(chars.len());
110        Ok(String::from_utf16(&chars[..length]).unwrap())
111    } else {
112        let mut chars = vec![0; len as usize];
113        reader.read_exact(&mut chars)?;
114        let length = chars.iter().position(|&c| c == 0).unwrap_or(chars.len());
115        Ok(String::from_utf8_lossy(&chars[..length]).into_owned())
116    }
117}
118fn write_string<W: Write, V>(writer: &mut Context<W, V>, string: &str) -> TResult<()> {
119    if string.is_empty() {
120        writer.write_u32::<LE>(0)?;
121    } else {
122        write_string_trailing(writer, string, None)?;
123    }
124    Ok(())
125}
126
127fn read_string_trailing<R: Read + Seek, V>(
128    reader: &mut Context<R, V>,
129) -> TResult<(String, Vec<u8>)> {
130    let len = reader.read_i32::<LE>()?;
131    if len < 0 {
132        let bytes = (-len) as usize * 2;
133        let mut chars = vec![];
134        let mut rest = vec![];
135        let mut read = 0;
136        while read < bytes {
137            let next = reader.read_u16::<LE>()?;
138            read += 2;
139            if next == 0 {
140                rest.extend(next.to_le_bytes());
141                break;
142            } else {
143                chars.push(next);
144            }
145        }
146        while read < bytes {
147            rest.push(reader.read_u8()?);
148            read += 1;
149        }
150        Ok((String::from_utf16(&chars).unwrap(), rest))
151    } else {
152        let bytes = len as usize;
153        let mut chars = vec![];
154        let mut rest = vec![];
155        let mut read = 0;
156        while read < bytes {
157            let next = reader.read_u8()?;
158            read += 1;
159            if next == 0 {
160                rest.push(next);
161                break;
162            } else {
163                chars.push(next);
164            }
165        }
166        while read < bytes {
167            rest.push(reader.read_u8()?);
168            read += 1;
169        }
170        Ok((String::from_utf8(chars).unwrap(), rest))
171    }
172}
173fn write_string_trailing<W: Write, V>(
174    writer: &mut Context<W, V>,
175    string: &str,
176    trailing: Option<&[u8]>,
177) -> TResult<()> {
178    if string.is_empty() || string.is_ascii() {
179        writer.write_u32::<LE>((string.len() + trailing.map(|t| t.len()).unwrap_or(1)) as u32)?;
180        writer.write_all(string.as_bytes())?;
181        writer.write_all(trailing.unwrap_or(&[0]))?;
182    } else {
183        let chars: Vec<u16> = string.encode_utf16().collect();
184        writer.write_i32::<LE>(
185            -((chars.len() + trailing.map(|t| t.len()).unwrap_or(2) / 2) as i32),
186        )?;
187        for c in chars {
188            writer.write_u16::<LE>(c)?;
189        }
190        writer.write_all(trailing.unwrap_or(&[0, 0]))?;
191    }
192    Ok(())
193}
194
195#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
196pub struct PropertyKey(pub u32, pub String);
197impl From<String> for PropertyKey {
198    fn from(value: String) -> Self {
199        Self(0, value)
200    }
201}
202impl From<&str> for PropertyKey {
203    fn from(value: &str) -> Self {
204        Self(0, value.to_string())
205    }
206}
207
208struct PropertyKeyVisitor;
209impl Visitor<'_> for PropertyKeyVisitor {
210    type Value = PropertyKey;
211    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
212        formatter.write_str(
213            "a property key in the form of key name and index seperated by '_' e.g. property_2",
214        )
215    }
216    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
217    where
218        E: serde::de::Error,
219    {
220        let (name_str, index_str) = value
221            .rsplit_once('_')
222            .ok_or_else(|| serde::de::Error::custom("property key does not contain a '_'"))?;
223        let index: u32 = index_str.parse().map_err(serde::de::Error::custom)?;
224
225        Ok(PropertyKey(index, name_str.to_string()))
226    }
227}
228impl<'de> Deserialize<'de> for PropertyKey {
229    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
230    where
231        D: Deserializer<'de>,
232    {
233        deserializer.deserialize_str(PropertyKeyVisitor)
234    }
235}
236impl Serialize for PropertyKey {
237    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
238    where
239        S: Serializer,
240    {
241        serializer.serialize_str(&format!("{}_{}", self.1, self.0))
242    }
243}
244
245#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
246pub struct Properties(pub indexmap::IndexMap<PropertyKey, Property>);
247impl Properties {
248    fn insert(&mut self, k: impl Into<PropertyKey>, v: Property) -> Option<Property> {
249        self.0.insert(k.into(), v)
250    }
251}
252impl<K> std::ops::Index<K> for Properties
253where
254    K: Into<PropertyKey>,
255{
256    type Output = Property;
257    fn index(&self, index: K) -> &Self::Output {
258        self.0.index(&index.into())
259    }
260}
261impl<K> std::ops::IndexMut<K> for Properties
262where
263    K: Into<PropertyKey>,
264{
265    fn index_mut(&mut self, index: K) -> &mut Property {
266        self.0.index_mut(&index.into())
267    }
268}
269impl<'a> IntoIterator for &'a Properties {
270    type Item = <&'a indexmap::IndexMap<PropertyKey, Property> as IntoIterator>::Item;
271    type IntoIter = <&'a indexmap::IndexMap<PropertyKey, Property> as IntoIterator>::IntoIter;
272    fn into_iter(self) -> Self::IntoIter {
273        self.0.iter()
274    }
275}
276
277fn read_properties_until_none<R: Read + Seek, V: VersionInfo>(
278    reader: &mut Context<R, V>,
279) -> TResult<Properties> {
280    let mut properties = Properties::default();
281    while let Some((name, prop)) = read_property(reader)? {
282        properties.insert(name, prop);
283    }
284    Ok(properties)
285}
286fn write_properties_none_terminated<W: Write, V: VersionInfo>(
287    writer: &mut Context<W, V>,
288    properties: &Properties,
289) -> TResult<()> {
290    for p in properties {
291        write_property(p, writer)?;
292    }
293    write_string(writer, "None")?;
294    Ok(())
295}
296
297fn read_property<R: Read + Seek, V: VersionInfo>(
298    reader: &mut Context<R, V>,
299) -> TResult<Option<(PropertyKey, Property)>> {
300    if let Some(tag) = PropertyTagFull::read(reader)? {
301        let value = reader.with_scope(&tag.name, |reader| Property::read(reader, tag.clone()))?;
302        Ok(Some((PropertyKey(tag.index, tag.name.to_string()), value)))
303    } else {
304        Ok(None)
305    }
306}
307fn write_property<W: Write, V: VersionInfo>(
308    prop: (&PropertyKey, &Property),
309    writer: &mut Context<W, V>,
310) -> TResult<()> {
311    let mut tag = prop
312        .1
313        .tag
314        .clone()
315        .into_full(&prop.0 .1, 0, prop.0 .0, prop.1);
316    let mut buf = vec![];
317    let size = writer.with_stream(&mut buf, |writer| prop.1.write(writer, &tag))? as u32;
318    tag.size = size;
319
320    tag.write(writer)?;
321    writer.write_all(&buf[..])?;
322    Ok(())
323}
324
325fn read_array<T, F, R: Read + Seek, V>(
326    length: u32,
327    reader: &mut Context<R, V>,
328    f: F,
329) -> TResult<Vec<T>>
330where
331    F: Fn(&mut Context<R, V>) -> TResult<T>,
332{
333    (0..length).map(|_| f(reader)).collect()
334}
335
336#[rustfmt::skip]
337impl<R: Read + Seek, V> Readable<R, V> for uuid::Uuid {
338    fn read(reader: &mut Context<R, V>) -> TResult<uuid::Uuid> {
339        let mut b = [0; 16];
340        reader.read_exact(&mut b)?;
341        Ok(uuid::Uuid::from_bytes([
342            b[0x3], b[0x2], b[0x1], b[0x0],
343            b[0x7], b[0x6], b[0x5], b[0x4],
344            b[0xb], b[0xa], b[0x9], b[0x8],
345            b[0xf], b[0xe], b[0xd], b[0xc],
346        ]))
347    }
348}
349#[rustfmt::skip]
350impl<W: Write, V> Writable<W, V> for uuid::Uuid {
351    fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
352        let b = self.as_bytes();
353        writer.write_all(&[
354            b[0x3], b[0x2], b[0x1], b[0x0],
355            b[0x7], b[0x6], b[0x5], b[0x4],
356            b[0xb], b[0xa], b[0x9], b[0x8],
357            b[0xf], b[0xe], b[0xd], b[0xc],
358        ])?;
359        Ok(())
360    }
361}
362
363/// Used to disambiguate types within a [`Property::Set`] or [`Property::Map`] during parsing.
364#[derive(Debug, Default, Clone)]
365pub struct Types {
366    types: std::collections::HashMap<String, StructType>,
367}
368impl Types {
369    /// Create an empty [`Types`] specification
370    pub fn new() -> Self {
371        Self::default()
372    }
373    /// Add a new type at the given path
374    pub fn add(&mut self, path: String, t: StructType) {
375        // TODO: Handle escaping of '.' in property names
376        // probably should store keys as Vec<String>
377        self.types.insert(path, t);
378    }
379}
380
381#[derive(Debug)]
382enum Scope<'p, 'n> {
383    Root,
384    Node {
385        parent: &'p Scope<'p, 'p>,
386        name: &'n str,
387    },
388}
389
390impl Scope<'_, '_> {
391    fn path(&self) -> String {
392        match self {
393            Self::Root => "".into(),
394            Self::Node { parent, name } => {
395                format!("{}.{}", parent.path(), name)
396            }
397        }
398    }
399}
400
401#[derive(Debug)]
402struct Context<'stream, 'version, 'types, 'scope, S, V> {
403    stream: &'stream mut S,
404    state: ContextState<'version, 'types, 'scope, V>,
405}
406#[derive(Debug)]
407struct ContextState<'version, 'types, 'scope, V> {
408    version: &'version V,
409    types: &'types Types,
410    scope: &'scope Scope<'scope, 'scope>,
411    log: bool,
412}
413impl<R: Read, V> Read for Context<'_, '_, '_, '_, R, V> {
414    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
415        self.stream.read(buf)
416    }
417}
418impl<S: Seek, V> Seek for Context<'_, '_, '_, '_, S, V> {
419    fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
420        self.stream.seek(pos)
421    }
422}
423impl<W: Write, V> Write for Context<'_, '_, '_, '_, W, V> {
424    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
425        self.stream.write(buf)
426    }
427    fn flush(&mut self) -> std::io::Result<()> {
428        self.stream.flush()
429    }
430}
431
432impl<'stream, 'scope, S> Context<'stream, '_, '_, 'scope, S, ()> {
433    fn run<F, T>(stream: &'stream mut S, f: F) -> T
434    where
435        F: FnOnce(&mut Context<'stream, '_, '_, 'scope, S, ()>) -> T,
436    {
437        f(&mut Context::<'stream, '_, '_, 'scope> {
438            stream,
439            state: ContextState {
440                version: &(),
441                types: &Types::new(),
442                scope: &Scope::Root,
443                log: false,
444            },
445        })
446    }
447}
448impl<'types, S, V> Context<'_, '_, 'types, '_, S, V> {
449    fn with_scope<'name, F, T>(&mut self, name: &'name str, f: F) -> T
450    where
451        F: FnOnce(&mut Context<'_, '_, 'types, '_, S, V>) -> T,
452    {
453        f(&mut Context {
454            stream: self.stream,
455            state: ContextState {
456                scope: &Scope::Node {
457                    name,
458                    parent: self.state.scope,
459                },
460                ..self.state
461            },
462        })
463    }
464    fn with_version<'h, F, T, V2>(&mut self, version: &'h V2, f: F) -> T
465    where
466        F: FnOnce(&mut Context<'_, '_, 'types, '_, S, V2>) -> T,
467    {
468        f(&mut Context {
469            stream: self.stream,
470            state: ContextState {
471                version,
472                types: self.state.types,
473                scope: self.state.scope,
474                log: self.state.log,
475            },
476        })
477    }
478    fn with_stream<'s, F, T, S2>(&mut self, stream: &'s mut S2, f: F) -> T
479    where
480        F: FnOnce(&mut Context<'_, '_, 'types, '_, S2, V>) -> T,
481    {
482        f(&mut Context {
483            stream,
484            state: ContextState { ..self.state },
485        })
486    }
487    fn path(&self) -> String {
488        self.state.scope.path()
489    }
490    fn get_type(&self) -> Option<&'types StructType> {
491        self.state.types.types.get(&self.path())
492    }
493    fn version(&self) -> &V {
494        self.state.version
495    }
496    fn log(&self) -> bool {
497        self.state.log
498    }
499}
500impl<'types, R: Read + Seek, V> Context<'_, '_, 'types, '_, R, V> {
501    fn get_type_or<'t>(&mut self, t: &'t StructType) -> TResult<&'t StructType>
502    where
503        'types: 't,
504    {
505        let offset = self.stream.stream_position()?;
506        Ok(self.get_type().unwrap_or_else(|| {
507            if self.log() {
508                eprintln!(
509                    "offset {}: StructType for \"{}\" unspecified, assuming {:?}",
510                    offset,
511                    self.path(),
512                    t
513                );
514            }
515            t
516        }))
517    }
518}
519
520#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
521struct PropertyTagFull<'a> {
522    name: Cow<'a, str>,
523    id: Option<uuid::Uuid>,
524    size: u32,
525    index: u32,
526    data: PropertyTagDataFull,
527}
528#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
529enum PropertyTagDataFull {
530    Array(std::boxed::Box<PropertyTagDataFull>),
531    Struct {
532        struct_type: StructType,
533        id: uuid::Uuid,
534    },
535    Set {
536        key_type: std::boxed::Box<PropertyTagDataFull>,
537    },
538    Map {
539        key_type: std::boxed::Box<PropertyTagDataFull>,
540        value_type: std::boxed::Box<PropertyTagDataFull>,
541    },
542    Byte(Option<String>),
543    Enum(String, Option<String>),
544    Bool(bool),
545    Other(PropertyType),
546}
547#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
548pub struct PropertyTagPartial {
549    #[serde(skip_serializing_if = "Option::is_none")]
550    pub id: Option<uuid::Uuid>,
551    pub data: PropertyTagDataPartial,
552}
553#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
554pub enum PropertyTagDataPartial {
555    Array(std::boxed::Box<PropertyTagDataPartial>),
556    Struct {
557        struct_type: StructType,
558        id: uuid::Uuid,
559    },
560    Set {
561        key_type: std::boxed::Box<PropertyTagDataPartial>,
562    },
563    Map {
564        key_type: std::boxed::Box<PropertyTagDataPartial>,
565        value_type: std::boxed::Box<PropertyTagDataPartial>,
566    },
567    Byte(Option<String>),
568    Enum(String, Option<String>),
569    Other(PropertyType),
570}
571impl PropertyTagDataFull {
572    fn into_partial(self) -> PropertyTagDataPartial {
573        match self {
574            Self::Array(inner) => PropertyTagDataPartial::Array(inner.into_partial().into()),
575            Self::Struct { struct_type, id } => PropertyTagDataPartial::Struct { struct_type, id },
576            Self::Set { key_type } => PropertyTagDataPartial::Set {
577                key_type: key_type.into_partial().into(),
578            },
579            Self::Map {
580                key_type,
581                value_type,
582            } => PropertyTagDataPartial::Map {
583                key_type: key_type.into_partial().into(),
584                value_type: value_type.into_partial().into(),
585            },
586            Self::Byte(a) => PropertyTagDataPartial::Byte(a),
587            Self::Enum(a, b) => PropertyTagDataPartial::Enum(a, b),
588            Self::Bool(_) => PropertyTagDataPartial::Other(PropertyType::BoolProperty),
589            Self::Other(t) => PropertyTagDataPartial::Other(t),
590        }
591    }
592}
593impl PropertyTagDataPartial {
594    fn into_full(self, prop: &Property) -> PropertyTagDataFull {
595        match self {
596            Self::Array(inner) => PropertyTagDataFull::Array(inner.into_full(prop).into()),
597            Self::Struct { struct_type, id } => PropertyTagDataFull::Struct { struct_type, id },
598            Self::Set { key_type } => PropertyTagDataFull::Set {
599                key_type: key_type.into_full(prop).into(),
600            },
601            Self::Map {
602                key_type,
603                value_type,
604            } => PropertyTagDataFull::Map {
605                key_type: key_type.into_full(prop).into(),
606                value_type: value_type.into_full(prop).into(),
607            },
608            Self::Byte(a) => PropertyTagDataFull::Byte(a),
609            Self::Enum(a, b) => PropertyTagDataFull::Enum(a, b),
610            Self::Other(PropertyType::BoolProperty) => {
611                PropertyTagDataFull::Bool(match prop.inner {
612                    PropertyInner::Bool(value) => value,
613                    _ => false,
614                })
615            }
616            Self::Other(t) => PropertyTagDataFull::Other(t),
617        }
618    }
619}
620
621impl PropertyTagDataFull {
622    fn basic_type(&self) -> PropertyType {
623        match self {
624            Self::Array(_) => PropertyType::ArrayProperty,
625            Self::Struct { .. } => PropertyType::StructProperty,
626            Self::Set { .. } => PropertyType::SetProperty,
627            Self::Map { .. } => PropertyType::MapProperty,
628            Self::Byte(_) => PropertyType::ByteProperty,
629            Self::Enum(_, _) => PropertyType::EnumProperty,
630            Self::Bool(_) => PropertyType::BoolProperty,
631            Self::Other(property_type) => *property_type,
632        }
633    }
634    fn from_type(inner_type: PropertyType, struct_type: Option<StructType>) -> Self {
635        match inner_type {
636            PropertyType::BoolProperty => Self::Bool(false),
637            PropertyType::ByteProperty => Self::Byte(None),
638            PropertyType::EnumProperty => Self::Enum("".to_string(), None),
639            PropertyType::ArrayProperty => unreachable!("array of array is invalid"),
640            PropertyType::SetProperty => unreachable!("array of set is invalid"),
641            PropertyType::MapProperty => unreachable!("array of map is invalid"),
642            PropertyType::StructProperty => Self::Struct {
643                struct_type: struct_type.unwrap_or(StructType::Struct(None)),
644                id: Default::default(),
645            },
646            other => Self::Other(other),
647        }
648    }
649}
650bitflags::bitflags! {
651    #[derive(Debug, Clone, Copy)]
652    struct EPropertyTagFlags : u8 {
653        const None = 0x00;
654        const HasArrayIndex = 0x01;
655        const HasPropertyGuid = 0x02;
656        const HasPropertyExtensions = 0x04;
657        const HasBinaryOrNativeSerialize = 0x08;
658        const BoolTrue = 0x10;
659    }
660}
661impl PropertyTagPartial {
662    fn into_full<'a>(
663        self,
664        name: &'a str,
665        size: u32,
666        index: u32,
667        prop: &Property,
668    ) -> PropertyTagFull<'a> {
669        PropertyTagFull {
670            name: name.into(),
671            id: self.id,
672            size,
673            index,
674            data: self.data.into_full(prop),
675        }
676    }
677}
678impl PropertyTagFull<'_> {
679    fn into_full(self) -> PropertyTagPartial {
680        PropertyTagPartial {
681            id: self.id,
682            data: self.data.into_partial(),
683        }
684    }
685    fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Option<Self>> {
686        let name = read_string(reader)?;
687        if name == "None" {
688            return Ok(None);
689        }
690        if reader.version().property_tag() {
691            let data = read_type(reader)?;
692
693            let mut tag = Self {
694                name: name.into(),
695                size: 0,
696                index: 0,
697                id: None,
698                data,
699            };
700
701            #[derive(Default, Debug)]
702            struct Node {
703                name: String,
704                inner_count: u32,
705            }
706            fn read_node<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Node> {
707                Ok(Node {
708                    name: read_string(reader)?,
709                    inner_count: reader.read_u32::<LE>()?,
710                })
711            }
712            fn read_path<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<String> {
713                let name = read_node(reader)?;
714                assert_eq!(1, name.inner_count);
715                let package = read_node(reader)?;
716                assert_eq!(0, package.inner_count);
717                Ok(format!("{}.{}", package.name, name.name))
718            }
719            fn read_type<R: Read + Seek, V>(
720                reader: &mut Context<R, V>,
721            ) -> TResult<PropertyTagDataFull> {
722                let node = read_node(reader)?;
723                Ok(match node.name.as_str() {
724                    "ArrayProperty" => PropertyTagDataFull::Array(read_type(reader)?.into()),
725                    "StructProperty" => {
726                        let struct_type = StructType::from_full(&read_path(reader)?);
727                        let id = match node.inner_count {
728                            1 => Default::default(),
729                            2 => uuid::Uuid::parse_str(&read_node(reader)?.name)?,
730                            _ => unimplemented!(),
731                        };
732                        PropertyTagDataFull::Struct { struct_type, id }
733                    }
734                    "SetProperty" => PropertyTagDataFull::Set {
735                        key_type: read_type(reader)?.into(),
736                    },
737                    "MapProperty" => PropertyTagDataFull::Map {
738                        key_type: read_type(reader)?.into(),
739                        value_type: read_type(reader)?.into(),
740                    },
741                    "ByteProperty" => {
742                        let inner = match node.inner_count {
743                            0 => None,
744                            1 => Some(read_path(reader)?),
745                            _ => unimplemented!(),
746                        };
747                        PropertyTagDataFull::Byte(inner)
748                    }
749                    "EnumProperty" => {
750                        assert_eq!(2, node.inner_count);
751                        let inner = read_path(reader)?;
752                        let container = read_node(reader)?;
753                        assert_eq!(0, container.inner_count);
754                        PropertyTagDataFull::Enum(inner, Some(container.name.to_owned()))
755                    }
756                    "BoolProperty" => PropertyTagDataFull::Bool(false),
757                    other => {
758                        assert_eq!(0, node.inner_count);
759                        PropertyTagDataFull::Other(PropertyType::try_from(other)?)
760                    }
761                })
762            }
763
764            tag.size = reader.read_u32::<LE>()?;
765
766            let flags = EPropertyTagFlags::from_bits(reader.read_u8()?)
767                .ok_or_else(|| error::Error::Other("unknown EPropertyTagFlags bits".into()))?;
768
769            if flags.contains(EPropertyTagFlags::BoolTrue) {
770                if let PropertyTagDataFull::Bool(value) = &mut tag.data {
771                    *value = true
772                }
773            }
774            if flags.contains(EPropertyTagFlags::HasArrayIndex) {
775                tag.index = reader.read_u32::<LE>()?;
776            }
777            if flags.contains(EPropertyTagFlags::HasPropertyGuid) {
778                tag.id = Some(uuid::Uuid::read(reader)?);
779            }
780            if flags.contains(EPropertyTagFlags::HasPropertyExtensions) {
781                unimplemented!();
782            }
783
784            Ok(Some(tag))
785        } else {
786            reader.with_scope(&name.clone(), |reader| {
787                let type_ = PropertyType::read(reader)?;
788                let size = reader.read_u32::<LE>()?;
789                let index = reader.read_u32::<LE>()?;
790                let data = match type_ {
791                    PropertyType::BoolProperty => {
792                        let value = reader.read_u8()? > 0;
793                        PropertyTagDataFull::Bool(value)
794                    }
795                    PropertyType::IntProperty
796                    | PropertyType::Int8Property
797                    | PropertyType::Int16Property
798                    | PropertyType::Int64Property
799                    | PropertyType::UInt8Property
800                    | PropertyType::UInt16Property
801                    | PropertyType::UInt32Property
802                    | PropertyType::UInt64Property
803                    | PropertyType::FloatProperty
804                    | PropertyType::DoubleProperty
805                    | PropertyType::StrProperty
806                    | PropertyType::ObjectProperty
807                    | PropertyType::FieldPathProperty
808                    | PropertyType::SoftObjectProperty
809                    | PropertyType::NameProperty
810                    | PropertyType::TextProperty
811                    | PropertyType::DelegateProperty
812                    | PropertyType::MulticastDelegateProperty
813                    | PropertyType::MulticastInlineDelegateProperty
814                    | PropertyType::MulticastSparseDelegateProperty => {
815                        PropertyTagDataFull::Other(type_)
816                    }
817                    PropertyType::ByteProperty => {
818                        let enum_type = read_string(reader)?;
819                        PropertyTagDataFull::Byte((enum_type != "None").then_some(enum_type))
820                    }
821                    PropertyType::EnumProperty => {
822                        let enum_type = read_string(reader)?;
823                        PropertyTagDataFull::Enum(enum_type, None)
824                    }
825                    PropertyType::ArrayProperty => {
826                        let inner_type = PropertyType::read(reader)?;
827
828                        PropertyTagDataFull::Array(std::boxed::Box::new(
829                            PropertyTagDataFull::from_type(inner_type, None),
830                        ))
831                    }
832                    PropertyType::SetProperty => {
833                        let key_type = PropertyType::read(reader)?;
834                        let key_struct_type = match key_type {
835                            PropertyType::StructProperty => {
836                                Some(reader.get_type_or(&StructType::Guid)?.clone())
837                            }
838                            _ => None,
839                        };
840
841                        let key_type =
842                            PropertyTagDataFull::from_type(key_type, key_struct_type.clone())
843                                .into();
844
845                        PropertyTagDataFull::Set { key_type }
846                    }
847                    PropertyType::MapProperty => {
848                        let key_type = PropertyType::read(reader)?;
849                        let key_struct_type = match key_type {
850                            PropertyType::StructProperty => Some(
851                                reader
852                                    .with_scope("Key", |r| r.get_type_or(&StructType::Guid))?
853                                    .clone(),
854                            ),
855                            _ => None,
856                        };
857                        let value_type = PropertyType::read(reader)?;
858                        let value_struct_type = match value_type {
859                            PropertyType::StructProperty => Some(
860                                reader
861                                    .with_scope("Value", |r| {
862                                        r.get_type_or(&StructType::Struct(None))
863                                    })?
864                                    .clone(),
865                            ),
866                            _ => None,
867                        };
868
869                        let key_type =
870                            PropertyTagDataFull::from_type(key_type, key_struct_type.clone())
871                                .into();
872                        let value_type =
873                            PropertyTagDataFull::from_type(value_type, value_struct_type.clone())
874                                .into();
875
876                        PropertyTagDataFull::Map {
877                            key_type,
878                            value_type,
879                        }
880                    }
881                    PropertyType::StructProperty => {
882                        let struct_type = StructType::read(reader)?;
883                        let struct_id = uuid::Uuid::read(reader)?;
884                        PropertyTagDataFull::Struct {
885                            struct_type,
886                            id: struct_id,
887                        }
888                    }
889                };
890                let id = if reader.version().property_guid() {
891                    read_optional_uuid(reader)?
892                } else {
893                    None
894                };
895                Ok(Some(Self {
896                    name: name.into(),
897                    size,
898                    index,
899                    id,
900                    data,
901                }))
902            })
903        }
904    }
905    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
906        write_string(writer, &self.name)?;
907
908        if writer.version().property_tag() {
909            fn write_node<W: Write, V>(
910                writer: &mut Context<W, V>,
911                name: &str,
912                inner_count: u32,
913            ) -> TResult<()> {
914                write_string(writer, name)?;
915                writer.write_u32::<LE>(inner_count)?;
916                Ok(())
917            }
918            fn write_full_type<W: Write, V>(
919                writer: &mut Context<W, V>,
920                full_type: &str,
921            ) -> TResult<()> {
922                let (a, b) = full_type.split_once('.').unwrap(); // TODO
923                write_node(writer, b, 1)?;
924                write_node(writer, a, 0)?;
925                Ok(())
926            }
927            fn write_nodes<W: Write, V>(
928                writer: &mut Context<W, V>,
929                flags: &mut EPropertyTagFlags,
930                data: &PropertyTagDataFull,
931            ) -> TResult<()> {
932                match data {
933                    PropertyTagDataFull::Array(inner) => {
934                        write_node(writer, "ArrayProperty", 1)?;
935                        write_nodes(writer, flags, inner)?;
936                    }
937                    PropertyTagDataFull::Struct { struct_type, id } => {
938                        write_node(writer, "StructProperty", if id.is_nil() { 1 } else { 2 })?;
939                        match struct_type {
940                            StructType::Struct(Some(_)) => {}
941                            _ => *flags |= EPropertyTagFlags::HasBinaryOrNativeSerialize,
942                        }
943                        write_full_type(writer, struct_type.full_str())?;
944
945                        if !id.is_nil() {
946                            write_node(writer, &id.to_string(), 0)?;
947                        }
948                    }
949                    PropertyTagDataFull::Set { key_type } => {
950                        write_node(writer, "SetProperty", 1)?;
951                        write_nodes(writer, flags, key_type)?;
952                    }
953                    PropertyTagDataFull::Map {
954                        key_type,
955                        value_type,
956                    } => {
957                        write_node(writer, "MapProperty", 2)?;
958                        write_nodes(writer, flags, key_type)?;
959                        write_nodes(writer, flags, value_type)?;
960                    }
961                    PropertyTagDataFull::Byte(enum_type) => {
962                        write_node(
963                            writer,
964                            "ByteProperty",
965                            if enum_type.is_some() { 1 } else { 0 },
966                        )?;
967                        if let Some(enum_type) = enum_type {
968                            write_full_type(writer, enum_type)?;
969                        }
970                    }
971                    PropertyTagDataFull::Enum(enum_type, container) => {
972                        write_node(writer, "EnumProperty", 2)?;
973                        write_full_type(writer, enum_type)?;
974                        write_node(writer, container.as_ref().unwrap(), 0)?;
975                    }
976                    PropertyTagDataFull::Bool(value) => {
977                        if *value {
978                            *flags |= EPropertyTagFlags::BoolTrue;
979                        }
980                        write_node(writer, "BoolProperty", 0)?;
981                    }
982                    PropertyTagDataFull::Other(property_type) => {
983                        write_node(writer, property_type.get_name(), 0)?;
984                    }
985                }
986                Ok(())
987            }
988
989            let mut flags = EPropertyTagFlags::empty();
990            write_nodes(writer, &mut flags, &self.data)?;
991
992            writer.write_u32::<LE>(self.size)?;
993
994            if self.id.is_some() {
995                flags |= EPropertyTagFlags::HasPropertyGuid;
996            }
997
998            writer.write_u8(flags.bits())?;
999        } else {
1000            self.data.basic_type().write(writer)?;
1001            writer.write_u32::<LE>(self.size)?;
1002            writer.write_u32::<LE>(self.index)?;
1003            match &self.data {
1004                PropertyTagDataFull::Array(inner_type) => {
1005                    inner_type.basic_type().write(writer)?;
1006                }
1007                PropertyTagDataFull::Struct { struct_type, id } => {
1008                    struct_type.write(writer)?;
1009                    id.write(writer)?;
1010                }
1011                PropertyTagDataFull::Set { key_type, .. } => {
1012                    key_type.basic_type().write(writer)?;
1013                }
1014                PropertyTagDataFull::Map {
1015                    key_type,
1016                    value_type,
1017                    ..
1018                } => {
1019                    key_type.basic_type().write(writer)?;
1020                    value_type.basic_type().write(writer)?;
1021                }
1022                PropertyTagDataFull::Byte(enum_type) => {
1023                    write_string(writer, enum_type.as_deref().unwrap_or("None"))?;
1024                }
1025                PropertyTagDataFull::Enum(enum_type, _) => {
1026                    write_string(writer, enum_type)?;
1027                }
1028                PropertyTagDataFull::Bool(value) => {
1029                    writer.write_u8(*value as u8)?;
1030                }
1031                PropertyTagDataFull::Other(_) => {}
1032            }
1033            if writer.version().property_guid() {
1034                write_optional_uuid(writer, self.id)?;
1035            }
1036        }
1037        Ok(())
1038    }
1039}
1040
1041#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1042pub enum PropertyType {
1043    IntProperty,
1044    Int8Property,
1045    Int16Property,
1046    Int64Property,
1047    UInt8Property,
1048    UInt16Property,
1049    UInt32Property,
1050    UInt64Property,
1051    FloatProperty,
1052    DoubleProperty,
1053    BoolProperty,
1054    ByteProperty,
1055    EnumProperty,
1056    ArrayProperty,
1057    ObjectProperty,
1058    StrProperty,
1059    FieldPathProperty,
1060    SoftObjectProperty,
1061    NameProperty,
1062    TextProperty,
1063    DelegateProperty,
1064    MulticastDelegateProperty,
1065    MulticastInlineDelegateProperty,
1066    MulticastSparseDelegateProperty,
1067    SetProperty,
1068    MapProperty,
1069    StructProperty,
1070}
1071impl PropertyType {
1072    fn get_name(&self) -> &str {
1073        match &self {
1074            PropertyType::Int8Property => "Int8Property",
1075            PropertyType::Int16Property => "Int16Property",
1076            PropertyType::IntProperty => "IntProperty",
1077            PropertyType::Int64Property => "Int64Property",
1078            PropertyType::UInt8Property => "UInt8Property",
1079            PropertyType::UInt16Property => "UInt16Property",
1080            PropertyType::UInt32Property => "UInt32Property",
1081            PropertyType::UInt64Property => "UInt64Property",
1082            PropertyType::FloatProperty => "FloatProperty",
1083            PropertyType::DoubleProperty => "DoubleProperty",
1084            PropertyType::BoolProperty => "BoolProperty",
1085            PropertyType::ByteProperty => "ByteProperty",
1086            PropertyType::EnumProperty => "EnumProperty",
1087            PropertyType::ArrayProperty => "ArrayProperty",
1088            PropertyType::ObjectProperty => "ObjectProperty",
1089            PropertyType::StrProperty => "StrProperty",
1090            PropertyType::FieldPathProperty => "FieldPathProperty",
1091            PropertyType::SoftObjectProperty => "SoftObjectProperty",
1092            PropertyType::NameProperty => "NameProperty",
1093            PropertyType::TextProperty => "TextProperty",
1094            PropertyType::DelegateProperty => "DelegateProperty",
1095            PropertyType::MulticastDelegateProperty => "MulticastDelegateProperty",
1096            PropertyType::MulticastInlineDelegateProperty => "MulticastInlineDelegateProperty",
1097            PropertyType::MulticastSparseDelegateProperty => "MulticastSparseDelegateProperty",
1098            PropertyType::SetProperty => "SetProperty",
1099            PropertyType::MapProperty => "MapProperty",
1100            PropertyType::StructProperty => "StructProperty",
1101        }
1102    }
1103    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1104        Self::try_from(&read_string(reader)?)
1105    }
1106    fn try_from(name: &str) -> TResult<Self> {
1107        match name {
1108            "Int8Property" => Ok(PropertyType::Int8Property),
1109            "Int16Property" => Ok(PropertyType::Int16Property),
1110            "IntProperty" => Ok(PropertyType::IntProperty),
1111            "Int64Property" => Ok(PropertyType::Int64Property),
1112            "UInt8Property" => Ok(PropertyType::UInt8Property),
1113            "UInt16Property" => Ok(PropertyType::UInt16Property),
1114            "UInt32Property" => Ok(PropertyType::UInt32Property),
1115            "UInt64Property" => Ok(PropertyType::UInt64Property),
1116            "FloatProperty" => Ok(PropertyType::FloatProperty),
1117            "DoubleProperty" => Ok(PropertyType::DoubleProperty),
1118            "BoolProperty" => Ok(PropertyType::BoolProperty),
1119            "ByteProperty" => Ok(PropertyType::ByteProperty),
1120            "EnumProperty" => Ok(PropertyType::EnumProperty),
1121            "ArrayProperty" => Ok(PropertyType::ArrayProperty),
1122            "ObjectProperty" => Ok(PropertyType::ObjectProperty),
1123            "StrProperty" => Ok(PropertyType::StrProperty),
1124            "FieldPathProperty" => Ok(PropertyType::FieldPathProperty),
1125            "SoftObjectProperty" => Ok(PropertyType::SoftObjectProperty),
1126            "NameProperty" => Ok(PropertyType::NameProperty),
1127            "TextProperty" => Ok(PropertyType::TextProperty),
1128            "DelegateProperty" => Ok(PropertyType::DelegateProperty),
1129            "MulticastDelegateProperty" => Ok(PropertyType::MulticastDelegateProperty),
1130            "MulticastInlineDelegateProperty" => Ok(PropertyType::MulticastInlineDelegateProperty),
1131            "MulticastSparseDelegateProperty" => Ok(PropertyType::MulticastSparseDelegateProperty),
1132            "SetProperty" => Ok(PropertyType::SetProperty),
1133            "MapProperty" => Ok(PropertyType::MapProperty),
1134            "StructProperty" => Ok(PropertyType::StructProperty),
1135            _ => Err(Error::UnknownPropertyType(format!("{name:?}"))),
1136        }
1137    }
1138    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1139        write_string(writer, self.get_name())?;
1140        Ok(())
1141    }
1142}
1143
1144#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1145pub enum StructType {
1146    Guid,
1147    DateTime,
1148    Timespan,
1149    Vector2D,
1150    Vector,
1151    IntVector,
1152    Box,
1153    IntPoint,
1154    Quat,
1155    Rotator,
1156    LinearColor,
1157    Color,
1158    SoftObjectPath,
1159    GameplayTagContainer,
1160    UniqueNetIdRepl,
1161    Struct(Option<String>),
1162}
1163impl From<&str> for StructType {
1164    fn from(t: &str) -> Self {
1165        match t {
1166            "Guid" => StructType::Guid,
1167            "DateTime" => StructType::DateTime,
1168            "Timespan" => StructType::Timespan,
1169            "Vector2D" => StructType::Vector2D,
1170            "Vector" => StructType::Vector,
1171            "IntVector" => StructType::IntVector,
1172            "Box" => StructType::Box,
1173            "IntPoint" => StructType::IntPoint,
1174            "Quat" => StructType::Quat,
1175            "Rotator" => StructType::Rotator,
1176            "LinearColor" => StructType::LinearColor,
1177            "Color" => StructType::Color,
1178            "SoftObjectPath" => StructType::SoftObjectPath,
1179            "GameplayTagContainer" => StructType::GameplayTagContainer,
1180            "UniqueNetIdRepl" => StructType::UniqueNetIdRepl,
1181            "Struct" => StructType::Struct(None),
1182            _ => StructType::Struct(Some(t.to_owned())),
1183        }
1184    }
1185}
1186impl From<String> for StructType {
1187    fn from(t: String) -> Self {
1188        match t.as_str() {
1189            "Guid" => StructType::Guid,
1190            "DateTime" => StructType::DateTime,
1191            "Timespan" => StructType::Timespan,
1192            "Vector2D" => StructType::Vector2D,
1193            "Vector" => StructType::Vector,
1194            "IntVector" => StructType::IntVector,
1195            "Box" => StructType::Box,
1196            "IntPoint" => StructType::IntPoint,
1197            "Quat" => StructType::Quat,
1198            "Rotator" => StructType::Rotator,
1199            "LinearColor" => StructType::LinearColor,
1200            "Color" => StructType::Color,
1201            "SoftObjectPath" => StructType::SoftObjectPath,
1202            "GameplayTagContainer" => StructType::GameplayTagContainer,
1203            "UniqueNetIdRepl" => StructType::UniqueNetIdRepl,
1204            "Struct" => StructType::Struct(None),
1205            _ => StructType::Struct(Some(t)),
1206        }
1207    }
1208}
1209impl StructType {
1210    fn from_full(t: &str) -> Self {
1211        match t {
1212            "/Script/CoreUObject.Guid" => StructType::Guid,
1213            "/Script/CoreUObject.DateTime" => StructType::DateTime,
1214            "/Script/CoreUObject.Timespan" => StructType::Timespan,
1215            "/Script/CureUObject.Vector2D" => StructType::Vector2D,
1216            "/Script/CoreUObject.Vector" => StructType::Vector,
1217            "/Script/CureUObject.IntVector" => StructType::IntVector,
1218            "/Script/CoreUObject.Box" => StructType::Box,
1219            "/Script/CoreUObject.IntPoint" => StructType::IntPoint,
1220            "/Script/CoreUObject.Quat" => StructType::Quat,
1221            "/Script/CoreUObject.Rotator" => StructType::Rotator,
1222            "/Script/CoreUObject.LinearColor" => StructType::LinearColor,
1223            "/Script/CoreUObject.Color" => StructType::Color,
1224            "/Script/CoreUObject.SoftObjectPath" => StructType::SoftObjectPath,
1225            "/Script/GameplayTags.GameplayTagContainer" => StructType::GameplayTagContainer,
1226            "/Script/Engine.UniqueNetIdRepl" => StructType::UniqueNetIdRepl,
1227            "/Script/CoreUObject.Struct" => StructType::Struct(None),
1228            _ => StructType::Struct(Some(t.to_owned())),
1229        }
1230    }
1231    fn full_str(&self) -> &str {
1232        match self {
1233            StructType::Guid => "/Script/CoreUObject.Guid",
1234            StructType::DateTime => "/Script/CoreUObject.DateTime",
1235            StructType::Timespan => "/Script/CoreUObject.Timespan",
1236            StructType::Vector2D => "/Script/CoreUObject.Vector2D",
1237            StructType::Vector => "/Script/CoreUObject.Vector",
1238            StructType::IntVector => "/Script/CoreUObject.IntVector",
1239            StructType::Box => "/Script/CoreUObject.Box",
1240            StructType::IntPoint => "/Script/CoreUObject.IntPoint",
1241            StructType::Quat => "/Script/CoreUObject.Quat",
1242            StructType::Rotator => "/Script/CoreUObject.Rotator",
1243            StructType::LinearColor => "/Script/CoreUObject.LinearColor",
1244            StructType::Color => "/Script/CoreUObject.Color",
1245            StructType::SoftObjectPath => "/Script/CoreUObject.SoftObjectPath",
1246            StructType::GameplayTagContainer => "/Script/GameplayTags.GameplayTagContainer",
1247            StructType::UniqueNetIdRepl => "/Script/Engine.UniqueNetIdRepl",
1248            StructType::Struct(Some(t)) => t,
1249            _ => unreachable!(),
1250        }
1251    }
1252    fn as_str(&self) -> &str {
1253        match self {
1254            StructType::Guid => "Guid",
1255            StructType::DateTime => "DateTime",
1256            StructType::Timespan => "Timespan",
1257            StructType::Vector2D => "Vector2D",
1258            StructType::Vector => "Vector",
1259            StructType::IntVector => "IntVector",
1260            StructType::Box => "Box",
1261            StructType::IntPoint => "IntPoint",
1262            StructType::Quat => "Quat",
1263            StructType::Rotator => "Rotator",
1264            StructType::LinearColor => "LinearColor",
1265            StructType::Color => "Color",
1266            StructType::SoftObjectPath => "SoftObjectPath",
1267            StructType::GameplayTagContainer => "GameplayTagContainer",
1268            StructType::UniqueNetIdRepl => "UniqueNetIdRepl",
1269            StructType::Struct(Some(t)) => t,
1270            _ => unreachable!(),
1271        }
1272    }
1273    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1274        Ok(read_string(reader)?.into())
1275    }
1276    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1277        write_string(writer, self.as_str())?;
1278        Ok(())
1279    }
1280}
1281
1282type DateTime = u64;
1283type Timespan = i64;
1284type Int8 = i8;
1285type Int16 = i16;
1286type Int = i32;
1287type Int64 = i64;
1288type UInt8 = u8;
1289type UInt16 = u16;
1290type UInt32 = u32;
1291type UInt64 = u64;
1292type Float = f32;
1293type Double = f64;
1294type Bool = bool;
1295type Enum = String;
1296
1297#[derive(Debug, PartialEq, Serialize, Deserialize)]
1298pub struct MapEntry {
1299    pub key: PropertyValue,
1300    pub value: PropertyValue,
1301}
1302impl MapEntry {
1303    fn read<R: Read + Seek, V: VersionInfo>(
1304        reader: &mut Context<R, V>,
1305        key_type: &PropertyTagDataFull,
1306        value_type: &PropertyTagDataFull,
1307    ) -> TResult<MapEntry> {
1308        let key = PropertyValue::read(reader, key_type)?;
1309        let value = PropertyValue::read(reader, value_type)?;
1310        Ok(Self { key, value })
1311    }
1312    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1313        self.key.write(writer)?;
1314        self.value.write(writer)?;
1315        Ok(())
1316    }
1317}
1318
1319#[derive(Debug, PartialEq, Serialize, Deserialize)]
1320pub struct FieldPath {
1321    path: Vec<String>,
1322    owner: String,
1323}
1324impl FieldPath {
1325    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1326        Ok(Self {
1327            path: read_array(reader.read_u32::<LE>()?, reader, read_string)?,
1328            owner: read_string(reader)?,
1329        })
1330    }
1331    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1332        writer.write_u32::<LE>(self.path.len() as u32)?;
1333        for p in &self.path {
1334            write_string(writer, p)?;
1335        }
1336        write_string(writer, &self.owner)?;
1337        Ok(())
1338    }
1339}
1340
1341#[derive(Debug, PartialEq, Serialize, Deserialize)]
1342pub struct Delegate {
1343    name: String,
1344    path: String,
1345}
1346impl Delegate {
1347    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1348        Ok(Self {
1349            name: read_string(reader)?,
1350            path: read_string(reader)?,
1351        })
1352    }
1353    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1354        write_string(writer, &self.name)?;
1355        write_string(writer, &self.path)?;
1356        Ok(())
1357    }
1358}
1359
1360#[derive(Debug, PartialEq, Serialize, Deserialize)]
1361pub struct MulticastDelegate(Vec<Delegate>);
1362impl MulticastDelegate {
1363    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1364        Ok(Self(read_array(
1365            reader.read_u32::<LE>()?,
1366            reader,
1367            Delegate::read,
1368        )?))
1369    }
1370    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1371        writer.write_u32::<LE>(self.0.len() as u32)?;
1372        for entry in &self.0 {
1373            entry.write(writer)?;
1374        }
1375        Ok(())
1376    }
1377}
1378
1379#[derive(Debug, PartialEq, Serialize, Deserialize)]
1380pub struct MulticastInlineDelegate(Vec<Delegate>);
1381impl MulticastInlineDelegate {
1382    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1383        Ok(Self(read_array(
1384            reader.read_u32::<LE>()?,
1385            reader,
1386            Delegate::read,
1387        )?))
1388    }
1389    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1390        writer.write_u32::<LE>(self.0.len() as u32)?;
1391        for entry in &self.0 {
1392            entry.write(writer)?;
1393        }
1394        Ok(())
1395    }
1396}
1397
1398#[derive(Debug, PartialEq, Serialize, Deserialize)]
1399pub struct MulticastSparseDelegate(Vec<Delegate>);
1400impl MulticastSparseDelegate {
1401    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1402        Ok(Self(read_array(
1403            reader.read_u32::<LE>()?,
1404            reader,
1405            Delegate::read,
1406        )?))
1407    }
1408    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1409        writer.write_u32::<LE>(self.0.len() as u32)?;
1410        for entry in &self.0 {
1411            entry.write(writer)?;
1412        }
1413        Ok(())
1414    }
1415}
1416
1417#[derive(Debug, PartialEq, Serialize, Deserialize)]
1418pub struct LinearColor {
1419    pub r: f32,
1420    pub g: f32,
1421    pub b: f32,
1422    pub a: f32,
1423}
1424impl LinearColor {
1425    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1426        Ok(Self {
1427            r: reader.read_f32::<LE>()?,
1428            g: reader.read_f32::<LE>()?,
1429            b: reader.read_f32::<LE>()?,
1430            a: reader.read_f32::<LE>()?,
1431        })
1432    }
1433    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1434        writer.write_f32::<LE>(self.r)?;
1435        writer.write_f32::<LE>(self.g)?;
1436        writer.write_f32::<LE>(self.b)?;
1437        writer.write_f32::<LE>(self.a)?;
1438        Ok(())
1439    }
1440}
1441#[derive(Debug, PartialEq, Serialize, Deserialize)]
1442pub struct Quat {
1443    pub x: f64,
1444    pub y: f64,
1445    pub z: f64,
1446    pub w: f64,
1447}
1448impl Quat {
1449    fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1450        if reader.version().large_world_coordinates() {
1451            Ok(Self {
1452                x: reader.read_f64::<LE>()?,
1453                y: reader.read_f64::<LE>()?,
1454                z: reader.read_f64::<LE>()?,
1455                w: reader.read_f64::<LE>()?,
1456            })
1457        } else {
1458            Ok(Self {
1459                x: reader.read_f32::<LE>()? as f64,
1460                y: reader.read_f32::<LE>()? as f64,
1461                z: reader.read_f32::<LE>()? as f64,
1462                w: reader.read_f32::<LE>()? as f64,
1463            })
1464        }
1465    }
1466    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1467        if writer.version().large_world_coordinates() {
1468            writer.write_f64::<LE>(self.x)?;
1469            writer.write_f64::<LE>(self.y)?;
1470            writer.write_f64::<LE>(self.z)?;
1471            writer.write_f64::<LE>(self.w)?;
1472        } else {
1473            writer.write_f32::<LE>(self.x as f32)?;
1474            writer.write_f32::<LE>(self.y as f32)?;
1475            writer.write_f32::<LE>(self.z as f32)?;
1476            writer.write_f32::<LE>(self.w as f32)?;
1477        }
1478        Ok(())
1479    }
1480}
1481#[derive(Debug, PartialEq, Serialize, Deserialize)]
1482pub struct Rotator {
1483    pub x: f64,
1484    pub y: f64,
1485    pub z: f64,
1486}
1487impl Rotator {
1488    fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1489        if reader.version().large_world_coordinates() {
1490            Ok(Self {
1491                x: reader.read_f64::<LE>()?,
1492                y: reader.read_f64::<LE>()?,
1493                z: reader.read_f64::<LE>()?,
1494            })
1495        } else {
1496            Ok(Self {
1497                x: reader.read_f32::<LE>()? as f64,
1498                y: reader.read_f32::<LE>()? as f64,
1499                z: reader.read_f32::<LE>()? as f64,
1500            })
1501        }
1502    }
1503    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1504        if writer.version().large_world_coordinates() {
1505            writer.write_f64::<LE>(self.x)?;
1506            writer.write_f64::<LE>(self.y)?;
1507            writer.write_f64::<LE>(self.z)?;
1508        } else {
1509            writer.write_f32::<LE>(self.x as f32)?;
1510            writer.write_f32::<LE>(self.y as f32)?;
1511            writer.write_f32::<LE>(self.z as f32)?;
1512        }
1513        Ok(())
1514    }
1515}
1516#[derive(Debug, PartialEq, Serialize, Deserialize)]
1517pub struct Color {
1518    pub r: u8,
1519    pub g: u8,
1520    pub b: u8,
1521    pub a: u8,
1522}
1523impl Color {
1524    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1525        Ok(Self {
1526            r: reader.read_u8()?,
1527            g: reader.read_u8()?,
1528            b: reader.read_u8()?,
1529            a: reader.read_u8()?,
1530        })
1531    }
1532    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1533        writer.write_u8(self.r)?;
1534        writer.write_u8(self.g)?;
1535        writer.write_u8(self.b)?;
1536        writer.write_u8(self.a)?;
1537        Ok(())
1538    }
1539}
1540#[derive(Debug, PartialEq, Serialize, Deserialize)]
1541pub struct Vector {
1542    pub x: f64,
1543    pub y: f64,
1544    pub z: f64,
1545}
1546impl Vector {
1547    fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1548        if reader.version().large_world_coordinates() {
1549            Ok(Self {
1550                x: reader.read_f64::<LE>()?,
1551                y: reader.read_f64::<LE>()?,
1552                z: reader.read_f64::<LE>()?,
1553            })
1554        } else {
1555            Ok(Self {
1556                x: reader.read_f32::<LE>()? as f64,
1557                y: reader.read_f32::<LE>()? as f64,
1558                z: reader.read_f32::<LE>()? as f64,
1559            })
1560        }
1561    }
1562    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1563        if writer.version().large_world_coordinates() {
1564            writer.write_f64::<LE>(self.x)?;
1565            writer.write_f64::<LE>(self.y)?;
1566            writer.write_f64::<LE>(self.z)?;
1567        } else {
1568            writer.write_f32::<LE>(self.x as f32)?;
1569            writer.write_f32::<LE>(self.y as f32)?;
1570            writer.write_f32::<LE>(self.z as f32)?;
1571        }
1572        Ok(())
1573    }
1574}
1575#[derive(Debug, PartialEq, Serialize, Deserialize)]
1576pub struct Vector2D {
1577    pub x: f64,
1578    pub y: f64,
1579}
1580impl Vector2D {
1581    fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1582        if reader.version().large_world_coordinates() {
1583            Ok(Self {
1584                x: reader.read_f64::<LE>()?,
1585                y: reader.read_f64::<LE>()?,
1586            })
1587        } else {
1588            Ok(Self {
1589                x: reader.read_f32::<LE>()? as f64,
1590                y: reader.read_f32::<LE>()? as f64,
1591            })
1592        }
1593    }
1594    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1595        if writer.version().large_world_coordinates() {
1596            writer.write_f64::<LE>(self.x)?;
1597            writer.write_f64::<LE>(self.y)?;
1598        } else {
1599            writer.write_f32::<LE>(self.x as f32)?;
1600            writer.write_f32::<LE>(self.y as f32)?;
1601        }
1602        Ok(())
1603    }
1604}
1605#[derive(Debug, PartialEq, Serialize, Deserialize)]
1606pub struct IntVector {
1607    pub x: i32,
1608    pub y: i32,
1609    pub z: i32,
1610}
1611impl IntVector {
1612    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1613        Ok(Self {
1614            x: reader.read_i32::<LE>()?,
1615            y: reader.read_i32::<LE>()?,
1616            z: reader.read_i32::<LE>()?,
1617        })
1618    }
1619    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1620        writer.write_i32::<LE>(self.x)?;
1621        writer.write_i32::<LE>(self.y)?;
1622        writer.write_i32::<LE>(self.z)?;
1623        Ok(())
1624    }
1625}
1626#[derive(Debug, PartialEq, Serialize, Deserialize)]
1627pub struct Box {
1628    pub min: Vector,
1629    pub max: Vector,
1630    pub is_valid: bool,
1631}
1632impl Box {
1633    fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1634        Ok(Self {
1635            min: Vector::read(reader)?,
1636            max: Vector::read(reader)?,
1637            is_valid: reader.read_u8()? > 0,
1638        })
1639    }
1640    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1641        self.min.write(writer)?;
1642        self.max.write(writer)?;
1643        writer.write_u8(self.is_valid as u8)?;
1644        Ok(())
1645    }
1646}
1647#[derive(Debug, PartialEq, Serialize, Deserialize)]
1648pub struct IntPoint {
1649    pub x: i32,
1650    pub y: i32,
1651}
1652impl IntPoint {
1653    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1654        Ok(Self {
1655            x: reader.read_i32::<LE>()?,
1656            y: reader.read_i32::<LE>()?,
1657        })
1658    }
1659    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1660        writer.write_i32::<LE>(self.x)?;
1661        writer.write_i32::<LE>(self.y)?;
1662        Ok(())
1663    }
1664}
1665
1666#[derive(Debug, PartialEq, Serialize, Deserialize)]
1667pub enum SoftObjectPath {
1668    Old {
1669        asset_path_name: String,
1670        sub_path_string: String,
1671    },
1672    New {
1673        asset_path_name: String,
1674        package_name: String,
1675        asset_name: String,
1676    },
1677}
1678impl SoftObjectPath {
1679    fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
1680        Ok(if reader.version().remove_asset_path_fnames() {
1681            Self::New {
1682                asset_path_name: read_string(reader)?,
1683                package_name: read_string(reader)?,
1684                asset_name: read_string(reader)?,
1685            }
1686        } else {
1687            Self::Old {
1688                asset_path_name: read_string(reader)?,
1689                sub_path_string: read_string(reader)?,
1690            }
1691        })
1692    }
1693    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1694        match self {
1695            Self::Old {
1696                asset_path_name,
1697                sub_path_string,
1698            } => {
1699                write_string(writer, asset_path_name)?;
1700                write_string(writer, sub_path_string)?;
1701            }
1702            Self::New {
1703                asset_path_name,
1704                package_name,
1705                asset_name,
1706            } => {
1707                write_string(writer, asset_path_name)?;
1708                write_string(writer, package_name)?;
1709                write_string(writer, asset_name)?;
1710            }
1711        }
1712        Ok(())
1713    }
1714}
1715
1716#[derive(Debug, PartialEq, Serialize, Deserialize)]
1717pub struct GameplayTag {
1718    pub name: String,
1719}
1720impl GameplayTag {
1721    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1722        Ok(Self {
1723            name: read_string(reader)?,
1724        })
1725    }
1726    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1727        write_string(writer, &self.name)?;
1728        Ok(())
1729    }
1730}
1731
1732#[derive(Debug, PartialEq, Serialize, Deserialize)]
1733pub struct GameplayTagContainer {
1734    pub gameplay_tags: Vec<GameplayTag>,
1735}
1736impl GameplayTagContainer {
1737    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1738        Ok(Self {
1739            gameplay_tags: read_array(reader.read_u32::<LE>()?, reader, GameplayTag::read)?,
1740        })
1741    }
1742    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1743        writer.write_u32::<LE>(self.gameplay_tags.len() as u32)?;
1744        for entry in &self.gameplay_tags {
1745            entry.write(writer)?;
1746        }
1747        Ok(())
1748    }
1749}
1750
1751#[derive(Debug, PartialEq, Serialize, Deserialize)]
1752pub struct UniqueNetIdRepl {
1753    pub inner: Option<UniqueNetIdReplInner>,
1754}
1755#[derive(Debug, PartialEq, Serialize, Deserialize)]
1756pub struct UniqueNetIdReplInner {
1757    pub size: std::num::NonZeroU32,
1758    pub type_: String,
1759    pub contents: String,
1760}
1761impl UniqueNetIdRepl {
1762    fn read<R: Read + Seek, V>(reader: &mut Context<R, V>) -> TResult<Self> {
1763        let size = reader.read_u32::<LE>()?;
1764        let inner = if let Ok(size) = size.try_into() {
1765            Some(UniqueNetIdReplInner {
1766                size,
1767                type_: read_string(reader)?,
1768                contents: read_string(reader)?,
1769            })
1770        } else {
1771            None
1772        };
1773        Ok(Self { inner })
1774    }
1775    fn write<W: Write, V>(&self, writer: &mut Context<W, V>) -> TResult<()> {
1776        match &self.inner {
1777            Some(inner) => {
1778                writer.write_u32::<LE>(inner.size.into())?;
1779                write_string(writer, &inner.type_)?;
1780                write_string(writer, &inner.contents)?;
1781            }
1782            None => writer.write_u32::<LE>(0)?,
1783        }
1784        Ok(())
1785    }
1786}
1787
1788#[derive(Debug, PartialEq, Serialize, Deserialize)]
1789pub struct FFormatArgumentData {
1790    name: String,
1791    value: FFormatArgumentDataValue,
1792}
1793impl<R: Read + Seek, V> Readable<R, V> for FFormatArgumentData {
1794    fn read(reader: &mut Context<R, V>) -> TResult<Self> {
1795        Ok(Self {
1796            name: read_string(reader)?,
1797            value: FFormatArgumentDataValue::read(reader)?,
1798        })
1799    }
1800}
1801impl<W: Write, V> Writable<W, V> for FFormatArgumentData {
1802    fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
1803        write_string(writer, &self.name)?;
1804        self.value.write(writer)?;
1805        Ok(())
1806    }
1807}
1808// very similar to FFormatArgumentValue but serializes ints as 32 bits (TODO changes to 64 bit
1809// again at some later UE version)
1810#[derive(Debug, PartialEq, Serialize, Deserialize)]
1811pub enum FFormatArgumentDataValue {
1812    Int(i32),
1813    UInt(u32),
1814    Float(f32),
1815    Double(f64),
1816    Text(std::boxed::Box<Text>),
1817    Gender(u64),
1818}
1819impl<R: Read + Seek, V> Readable<R, V> for FFormatArgumentDataValue {
1820    fn read(reader: &mut Context<R, V>) -> TResult<Self> {
1821        let type_ = reader.read_u8()?;
1822        match type_ {
1823            0 => Ok(Self::Int(reader.read_i32::<LE>()?)),
1824            1 => Ok(Self::UInt(reader.read_u32::<LE>()?)),
1825            2 => Ok(Self::Float(reader.read_f32::<LE>()?)),
1826            3 => Ok(Self::Double(reader.read_f64::<LE>()?)),
1827            4 => Ok(Self::Text(std::boxed::Box::new(Text::read(reader)?))),
1828            5 => Ok(Self::Gender(reader.read_u64::<LE>()?)),
1829            _ => Err(Error::Other(format!(
1830                "unimplemented variant for FFormatArgumentDataValue 0x{type_:x}"
1831            ))),
1832        }
1833    }
1834}
1835impl<W: Write, V> Writable<W, V> for FFormatArgumentDataValue {
1836    fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
1837        match self {
1838            Self::Int(value) => {
1839                writer.write_u8(0)?;
1840                writer.write_i32::<LE>(*value)?;
1841            }
1842            Self::UInt(value) => {
1843                writer.write_u8(1)?;
1844                writer.write_u32::<LE>(*value)?;
1845            }
1846            Self::Float(value) => {
1847                writer.write_u8(2)?;
1848                writer.write_f32::<LE>(*value)?;
1849            }
1850            Self::Double(value) => {
1851                writer.write_u8(3)?;
1852                writer.write_f64::<LE>(*value)?;
1853            }
1854            Self::Text(value) => {
1855                writer.write_u8(4)?;
1856                value.write(writer)?;
1857            }
1858            Self::Gender(value) => {
1859                writer.write_u8(5)?;
1860                writer.write_u64::<LE>(*value)?;
1861            }
1862        };
1863        Ok(())
1864    }
1865}
1866
1867#[derive(Debug, PartialEq, Serialize, Deserialize)]
1868pub enum FFormatArgumentValue {
1869    Int(i64),
1870    UInt(u64),
1871    Float(f32),
1872    Double(f64),
1873    Text(std::boxed::Box<Text>),
1874    Gender(u64),
1875}
1876
1877impl<R: Read + Seek, V> Readable<R, V> for FFormatArgumentValue {
1878    fn read(reader: &mut Context<R, V>) -> TResult<Self> {
1879        let type_ = reader.read_u8()?;
1880        match type_ {
1881            0 => Ok(Self::Int(reader.read_i64::<LE>()?)),
1882            1 => Ok(Self::UInt(reader.read_u64::<LE>()?)),
1883            2 => Ok(Self::Float(reader.read_f32::<LE>()?)),
1884            3 => Ok(Self::Double(reader.read_f64::<LE>()?)),
1885            4 => Ok(Self::Text(std::boxed::Box::new(Text::read(reader)?))),
1886            5 => Ok(Self::Gender(reader.read_u64::<LE>()?)),
1887            _ => Err(Error::Other(format!(
1888                "unimplemented variant for FFormatArgumentValue 0x{type_:x}"
1889            ))),
1890        }
1891    }
1892}
1893impl<W: Write, V> Writable<W, V> for FFormatArgumentValue {
1894    fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
1895        match self {
1896            Self::Int(value) => {
1897                writer.write_u8(0)?;
1898                writer.write_i64::<LE>(*value)?;
1899            }
1900            Self::UInt(value) => {
1901                writer.write_u8(1)?;
1902                writer.write_u64::<LE>(*value)?;
1903            }
1904            Self::Float(value) => {
1905                writer.write_u8(2)?;
1906                writer.write_f32::<LE>(*value)?;
1907            }
1908            Self::Double(value) => {
1909                writer.write_u8(3)?;
1910                writer.write_f64::<LE>(*value)?;
1911            }
1912            Self::Text(value) => {
1913                writer.write_u8(4)?;
1914                value.write(writer)?;
1915            }
1916            Self::Gender(value) => {
1917                writer.write_u8(5)?;
1918                writer.write_u64::<LE>(*value)?;
1919            }
1920        };
1921        Ok(())
1922    }
1923}
1924
1925#[derive(Debug, PartialEq, Serialize, Deserialize)]
1926pub struct FNumberFormattingOptions {
1927    always_sign: bool,
1928    use_grouping: bool,
1929    rounding_mode: i8, // TODO enum ERoundingMode
1930    minimum_integral_digits: i32,
1931    maximum_integral_digits: i32,
1932    minimum_fractional_digits: i32,
1933    maximum_fractional_digits: i32,
1934}
1935impl<R: Read + Seek, V> Readable<R, V> for FNumberFormattingOptions {
1936    fn read(reader: &mut Context<R, V>) -> TResult<Self> {
1937        Ok(Self {
1938            always_sign: reader.read_u32::<LE>()? != 0,
1939            use_grouping: reader.read_u32::<LE>()? != 0,
1940            rounding_mode: reader.read_i8()?,
1941            minimum_integral_digits: reader.read_i32::<LE>()?,
1942            maximum_integral_digits: reader.read_i32::<LE>()?,
1943            minimum_fractional_digits: reader.read_i32::<LE>()?,
1944            maximum_fractional_digits: reader.read_i32::<LE>()?,
1945        })
1946    }
1947}
1948impl<W: Write, V> Writable<W, V> for FNumberFormattingOptions {
1949    fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
1950        writer.write_u32::<LE>(self.always_sign as u32)?;
1951        writer.write_u32::<LE>(self.use_grouping as u32)?;
1952        writer.write_i8(self.rounding_mode)?;
1953        writer.write_i32::<LE>(self.minimum_integral_digits)?;
1954        writer.write_i32::<LE>(self.maximum_integral_digits)?;
1955        writer.write_i32::<LE>(self.minimum_fractional_digits)?;
1956        writer.write_i32::<LE>(self.maximum_fractional_digits)?;
1957        Ok(())
1958    }
1959}
1960
1961#[derive(Debug, PartialEq, Serialize, Deserialize)]
1962pub struct Text {
1963    flags: u32,
1964    variant: TextVariant,
1965}
1966#[derive(Debug, PartialEq, Serialize, Deserialize)]
1967pub enum TextVariant {
1968    // -0x1
1969    None {
1970        culture_invariant: Option<String>,
1971    },
1972    // 0x0
1973    Base {
1974        namespace: (String, Vec<u8>),
1975        key: String,
1976        source_string: String,
1977    },
1978    // 0x3
1979    ArgumentFormat {
1980        // aka ArgumentDataFormat
1981        format_text: std::boxed::Box<Text>,
1982        arguments: Vec<FFormatArgumentData>,
1983    },
1984    // 0x4
1985    AsNumber {
1986        source_value: FFormatArgumentValue,
1987        format_options: Option<FNumberFormattingOptions>,
1988        culture_name: String,
1989    },
1990    // 0x7
1991    AsDate {
1992        source_date_time: DateTime,
1993        date_style: i8, // TODO EDateTimeStyle::Type
1994        time_zone: String,
1995        culture_name: String,
1996    },
1997    StringTableEntry {
1998        // 0xb
1999        table: String,
2000        key: String,
2001    },
2002}
2003
2004impl<R: Read + Seek, V> Readable<R, V> for Text {
2005    fn read(reader: &mut Context<R, V>) -> TResult<Self> {
2006        let flags = reader.read_u32::<LE>()?;
2007        let text_history_type = reader.read_i8()?;
2008        let variant = match text_history_type {
2009            -0x1 => Ok(TextVariant::None {
2010                culture_invariant: (reader.read_u32::<LE>()? != 0) // bHasCultureInvariantString
2011                    .then(|| read_string(reader))
2012                    .transpose()?,
2013            }),
2014            0x0 => Ok(TextVariant::Base {
2015                namespace: read_string_trailing(reader)?,
2016                key: read_string(reader)?,
2017                source_string: read_string(reader)?,
2018            }),
2019            0x3 => Ok(TextVariant::ArgumentFormat {
2020                format_text: std::boxed::Box::new(Text::read(reader)?),
2021                arguments: read_array(reader.read_u32::<LE>()?, reader, FFormatArgumentData::read)?,
2022            }),
2023            0x4 => Ok(TextVariant::AsNumber {
2024                source_value: FFormatArgumentValue::read(reader)?,
2025                format_options:
2026                    (reader.read_u32::<LE>()? != 0) // bHasFormatOptions
2027                        .then(|| FNumberFormattingOptions::read(reader))
2028                        .transpose()?,
2029                culture_name: read_string(reader)?,
2030            }),
2031            0x7 => Ok(TextVariant::AsDate {
2032                source_date_time: reader.read_u64::<LE>()?,
2033                date_style: reader.read_i8()?,
2034                time_zone: read_string(reader)?,
2035                culture_name: read_string(reader)?,
2036            }),
2037            0xb => Ok({
2038                TextVariant::StringTableEntry {
2039                    table: read_string(reader)?,
2040                    key: read_string(reader)?,
2041                }
2042            }),
2043            _ => Err(Error::Other(format!(
2044                "unimplemented variant for FTextHistory 0x{text_history_type:x}"
2045            ))),
2046        }?;
2047        Ok(Self { flags, variant })
2048    }
2049}
2050impl<W: Write, V> Writable<W, V> for Text {
2051    fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
2052        writer.write_u32::<LE>(self.flags)?;
2053        match &self.variant {
2054            TextVariant::None { culture_invariant } => {
2055                writer.write_i8(-0x1)?;
2056                writer.write_u32::<LE>(culture_invariant.is_some() as u32)?;
2057                if let Some(culture_invariant) = culture_invariant {
2058                    write_string(writer, culture_invariant)?;
2059                }
2060            }
2061            TextVariant::Base {
2062                namespace,
2063                key,
2064                source_string,
2065            } => {
2066                writer.write_i8(0x0)?;
2067                // This particular string sometimes includes the trailing null byte and sometimes
2068                // does not. To preserve byte-for-byte equality we save the trailing bytes (null or
2069                // not) to the JSON so they can be retored later.
2070                write_string_trailing(writer, &namespace.0, Some(&namespace.1))?;
2071                write_string(writer, key)?;
2072                write_string(writer, source_string)?;
2073            }
2074            TextVariant::ArgumentFormat {
2075                format_text,
2076                arguments,
2077            } => {
2078                writer.write_i8(0x3)?;
2079                format_text.write(writer)?;
2080                writer.write_u32::<LE>(arguments.len() as u32)?;
2081                for a in arguments {
2082                    a.write(writer)?;
2083                }
2084            }
2085            TextVariant::AsNumber {
2086                source_value,
2087                format_options,
2088                culture_name,
2089            } => {
2090                writer.write_i8(0x4)?;
2091                source_value.write(writer)?;
2092                writer.write_u32::<LE>(format_options.is_some() as u32)?;
2093                if let Some(format_options) = format_options {
2094                    format_options.write(writer)?;
2095                }
2096                write_string(writer, culture_name)?;
2097            }
2098            TextVariant::AsDate {
2099                source_date_time,
2100                date_style,
2101                time_zone,
2102                culture_name,
2103            } => {
2104                writer.write_i8(0x7)?;
2105                writer.write_u64::<LE>(*source_date_time)?;
2106                writer.write_i8(*date_style)?;
2107                write_string(writer, time_zone)?;
2108                write_string(writer, culture_name)?;
2109            }
2110            TextVariant::StringTableEntry { table, key } => {
2111                writer.write_i8(0xb)?;
2112                write_string(writer, table)?;
2113                write_string(writer, key)?;
2114            }
2115        }
2116        Ok(())
2117    }
2118}
2119
2120/// Just a plain byte, or an enum in which case the variant will be a String
2121#[derive(Debug, PartialEq, Serialize, Deserialize)]
2122pub enum Byte {
2123    Byte(u8),
2124    Label(String),
2125}
2126/// Vectorized [`Byte`]
2127#[derive(Debug, PartialEq, Serialize, Deserialize)]
2128pub enum ByteArray {
2129    Byte(Vec<u8>),
2130    Label(Vec<String>),
2131}
2132
2133#[derive(Debug, PartialEq, Serialize, Deserialize)]
2134pub enum PropertyValue {
2135    Int(Int),
2136    Int8(Int8),
2137    Int16(Int16),
2138    Int64(Int64),
2139    UInt16(UInt16),
2140    UInt32(UInt32),
2141    Float(Float),
2142    Double(Double),
2143    Bool(Bool),
2144    Byte(Byte),
2145    Enum(Enum),
2146    Name(String),
2147    Str(String),
2148    SoftObject(SoftObjectPath),
2149    SoftObjectPath(SoftObjectPath),
2150    Object(String),
2151    Struct(StructValue),
2152}
2153
2154#[derive(Debug, PartialEq, Serialize, Deserialize)]
2155pub enum StructValue {
2156    Guid(uuid::Uuid),
2157    DateTime(DateTime),
2158    Timespan(Timespan),
2159    Vector2D(Vector2D),
2160    Vector(Vector),
2161    IntVector(IntVector),
2162    Box(Box),
2163    IntPoint(IntPoint),
2164    Quat(Quat),
2165    LinearColor(LinearColor),
2166    Color(Color),
2167    Rotator(Rotator),
2168    SoftObjectPath(SoftObjectPath),
2169    GameplayTagContainer(GameplayTagContainer),
2170    UniqueNetIdRepl(UniqueNetIdRepl),
2171    /// User defined struct which is simply a list of properties
2172    Struct(Properties),
2173}
2174
2175/// Vectorized properties to avoid storing the variant with each value
2176#[derive(Debug, PartialEq, Serialize, Deserialize)]
2177pub enum ValueVec {
2178    Int8(Vec<Int8>),
2179    Int16(Vec<Int16>),
2180    Int(Vec<Int>),
2181    Int64(Vec<Int64>),
2182    UInt8(Vec<UInt8>),
2183    UInt16(Vec<UInt16>),
2184    UInt32(Vec<UInt32>),
2185    UInt64(Vec<UInt64>),
2186    Float(Vec<Float>),
2187    Double(Vec<Double>),
2188    Bool(Vec<bool>),
2189    Byte(ByteArray),
2190    Enum(Vec<Enum>),
2191    Str(Vec<String>),
2192    Text(Vec<Text>),
2193    SoftObject(Vec<(String, String)>),
2194    Name(Vec<String>),
2195    Object(Vec<String>),
2196    Box(Vec<Box>),
2197}
2198
2199/// Encapsulates [`ValueVec`] with a special handling of structs. See also: [`ValueSet`]
2200#[derive(Debug, PartialEq, Serialize, Deserialize)]
2201pub enum ValueArray {
2202    Base(ValueVec),
2203    Struct {
2204        type_: PropertyType,
2205        struct_type: StructType,
2206        id: Option<uuid::Uuid>,
2207        value: Vec<StructValue>,
2208    },
2209}
2210/// Encapsulates [`ValueVec`] with a special handling of structs. See also: [`ValueArray`]
2211#[derive(Debug, PartialEq, Serialize, Deserialize)]
2212pub enum ValueSet {
2213    Base(ValueVec),
2214    Struct(Vec<StructValue>),
2215}
2216
2217impl PropertyValue {
2218    fn read<R: Read + Seek, V: VersionInfo>(
2219        reader: &mut Context<R, V>,
2220        t: &PropertyTagDataFull,
2221    ) -> TResult<PropertyValue> {
2222        Ok(match t {
2223            PropertyTagDataFull::Array(_) => unreachable!(),
2224            PropertyTagDataFull::Struct { struct_type, .. } => {
2225                PropertyValue::Struct(StructValue::read(reader, struct_type)?)
2226            }
2227            PropertyTagDataFull::Set { .. } => unreachable!(),
2228            PropertyTagDataFull::Map { .. } => unreachable!(),
2229            PropertyTagDataFull::Byte(_) => PropertyValue::Byte(Byte::Label(read_string(reader)?)),
2230            PropertyTagDataFull::Enum(_, _) => PropertyValue::Enum(read_string(reader)?),
2231            PropertyTagDataFull::Bool(_) => PropertyValue::Bool(reader.read_u8()? > 0),
2232            PropertyTagDataFull::Other(property_type) => match property_type {
2233                PropertyType::IntProperty => PropertyValue::Int(reader.read_i32::<LE>()?),
2234                PropertyType::Int8Property => PropertyValue::Int8(reader.read_i8()?),
2235                PropertyType::Int16Property => PropertyValue::Int16(reader.read_i16::<LE>()?),
2236                PropertyType::Int64Property => PropertyValue::Int64(reader.read_i64::<LE>()?),
2237                PropertyType::UInt16Property => PropertyValue::UInt16(reader.read_u16::<LE>()?),
2238                PropertyType::UInt32Property => PropertyValue::UInt32(reader.read_u32::<LE>()?),
2239                PropertyType::FloatProperty => PropertyValue::Float(reader.read_f32::<LE>()?),
2240                PropertyType::DoubleProperty => PropertyValue::Double(reader.read_f64::<LE>()?),
2241                PropertyType::NameProperty => PropertyValue::Name(read_string(reader)?),
2242                PropertyType::StrProperty => PropertyValue::Str(read_string(reader)?),
2243                PropertyType::SoftObjectProperty => {
2244                    PropertyValue::SoftObject(SoftObjectPath::read(reader)?)
2245                }
2246                PropertyType::ObjectProperty => PropertyValue::Object(read_string(reader)?),
2247                _ => return Err(Error::Other(format!("unimplemented property {t:?}"))),
2248            },
2249        })
2250    }
2251    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
2252        match &self {
2253            PropertyValue::Int(v) => writer.write_i32::<LE>(*v)?,
2254            PropertyValue::Int8(v) => writer.write_i8(*v)?,
2255            PropertyValue::Int16(v) => writer.write_i16::<LE>(*v)?,
2256            PropertyValue::Int64(v) => writer.write_i64::<LE>(*v)?,
2257            PropertyValue::UInt16(v) => writer.write_u16::<LE>(*v)?,
2258            PropertyValue::UInt32(v) => writer.write_u32::<LE>(*v)?,
2259            PropertyValue::Float(v) => writer.write_f32::<LE>(*v)?,
2260            PropertyValue::Double(v) => writer.write_f64::<LE>(*v)?,
2261            PropertyValue::Bool(v) => writer.write_u8(u8::from(*v))?,
2262            PropertyValue::Name(v) => write_string(writer, v)?,
2263            PropertyValue::Str(v) => write_string(writer, v)?,
2264            PropertyValue::SoftObject(v) => v.write(writer)?,
2265            PropertyValue::SoftObjectPath(v) => v.write(writer)?,
2266            PropertyValue::Object(v) => write_string(writer, v)?,
2267            PropertyValue::Byte(v) => match v {
2268                Byte::Byte(b) => writer.write_u8(*b)?,
2269                Byte::Label(l) => write_string(writer, l)?,
2270            },
2271            PropertyValue::Enum(v) => write_string(writer, v)?,
2272            PropertyValue::Struct(v) => v.write(writer)?,
2273        };
2274        Ok(())
2275    }
2276}
2277impl StructValue {
2278    fn read<R: Read + Seek, V: VersionInfo>(
2279        reader: &mut Context<R, V>,
2280        t: &StructType,
2281    ) -> TResult<StructValue> {
2282        Ok(match t {
2283            StructType::Guid => StructValue::Guid(uuid::Uuid::read(reader)?),
2284            StructType::DateTime => StructValue::DateTime(reader.read_u64::<LE>()?),
2285            StructType::Timespan => StructValue::Timespan(reader.read_i64::<LE>()?),
2286            StructType::Vector2D => StructValue::Vector2D(Vector2D::read(reader)?),
2287            StructType::Vector => StructValue::Vector(Vector::read(reader)?),
2288            StructType::IntVector => StructValue::IntVector(IntVector::read(reader)?),
2289            StructType::Box => StructValue::Box(Box::read(reader)?),
2290            StructType::IntPoint => StructValue::IntPoint(IntPoint::read(reader)?),
2291            StructType::Quat => StructValue::Quat(Quat::read(reader)?),
2292            StructType::LinearColor => StructValue::LinearColor(LinearColor::read(reader)?),
2293            StructType::Color => StructValue::Color(Color::read(reader)?),
2294            StructType::Rotator => StructValue::Rotator(Rotator::read(reader)?),
2295            StructType::SoftObjectPath => {
2296                StructValue::SoftObjectPath(SoftObjectPath::read(reader)?)
2297            }
2298            StructType::GameplayTagContainer => {
2299                StructValue::GameplayTagContainer(GameplayTagContainer::read(reader)?)
2300            }
2301            StructType::UniqueNetIdRepl => {
2302                StructValue::UniqueNetIdRepl(UniqueNetIdRepl::read(reader)?)
2303            }
2304
2305            StructType::Struct(_) => StructValue::Struct(read_properties_until_none(reader)?),
2306        })
2307    }
2308    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
2309        match self {
2310            StructValue::Guid(v) => v.write(writer)?,
2311            StructValue::DateTime(v) => writer.write_u64::<LE>(*v)?,
2312            StructValue::Timespan(v) => writer.write_i64::<LE>(*v)?,
2313            StructValue::Vector2D(v) => v.write(writer)?,
2314            StructValue::Vector(v) => v.write(writer)?,
2315            StructValue::IntVector(v) => v.write(writer)?,
2316            StructValue::Box(v) => v.write(writer)?,
2317            StructValue::IntPoint(v) => v.write(writer)?,
2318            StructValue::Quat(v) => v.write(writer)?,
2319            StructValue::LinearColor(v) => v.write(writer)?,
2320            StructValue::Color(v) => v.write(writer)?,
2321            StructValue::Rotator(v) => v.write(writer)?,
2322            StructValue::SoftObjectPath(v) => v.write(writer)?,
2323            StructValue::GameplayTagContainer(v) => v.write(writer)?,
2324            StructValue::UniqueNetIdRepl(v) => v.write(writer)?,
2325            StructValue::Struct(v) => write_properties_none_terminated(writer, v)?,
2326        }
2327        Ok(())
2328    }
2329}
2330impl ValueVec {
2331    fn read<R: Read + Seek, V>(
2332        reader: &mut Context<R, V>,
2333        t: &PropertyType,
2334        size: u32,
2335        count: u32,
2336    ) -> TResult<ValueVec> {
2337        Ok(match t {
2338            PropertyType::IntProperty => {
2339                ValueVec::Int(read_array(count, reader, |r| Ok(r.read_i32::<LE>()?))?)
2340            }
2341            PropertyType::Int16Property => {
2342                ValueVec::Int16(read_array(count, reader, |r| Ok(r.read_i16::<LE>()?))?)
2343            }
2344            PropertyType::Int64Property => {
2345                ValueVec::Int64(read_array(count, reader, |r| Ok(r.read_i64::<LE>()?))?)
2346            }
2347            PropertyType::UInt16Property => {
2348                ValueVec::UInt16(read_array(count, reader, |r| Ok(r.read_u16::<LE>()?))?)
2349            }
2350            PropertyType::UInt32Property => {
2351                ValueVec::UInt32(read_array(count, reader, |r| Ok(r.read_u32::<LE>()?))?)
2352            }
2353            PropertyType::FloatProperty => {
2354                ValueVec::Float(read_array(count, reader, |r| Ok(r.read_f32::<LE>()?))?)
2355            }
2356            PropertyType::DoubleProperty => {
2357                ValueVec::Double(read_array(count, reader, |r| Ok(r.read_f64::<LE>()?))?)
2358            }
2359            PropertyType::BoolProperty => {
2360                ValueVec::Bool(read_array(count, reader, |r| Ok(r.read_u8()? > 0))?)
2361            }
2362            PropertyType::ByteProperty => {
2363                if size == count {
2364                    ValueVec::Byte(ByteArray::Byte(read_array(count, reader, |r| {
2365                        Ok(r.read_u8()?)
2366                    })?))
2367                } else {
2368                    ValueVec::Byte(ByteArray::Label(read_array(count, reader, |r| {
2369                        read_string(r)
2370                    })?))
2371                }
2372            }
2373            PropertyType::EnumProperty => {
2374                ValueVec::Enum(read_array(count, reader, |r| read_string(r))?)
2375            }
2376            PropertyType::StrProperty => ValueVec::Str(read_array(count, reader, read_string)?),
2377            PropertyType::TextProperty => ValueVec::Text(read_array(count, reader, Text::read)?),
2378            PropertyType::SoftObjectProperty => {
2379                ValueVec::SoftObject(read_array(count, reader, |r| {
2380                    Ok((read_string(r)?, read_string(r)?))
2381                })?)
2382            }
2383            PropertyType::NameProperty => ValueVec::Name(read_array(count, reader, read_string)?),
2384            PropertyType::ObjectProperty => {
2385                ValueVec::Object(read_array(count, reader, read_string)?)
2386            }
2387            _ => return Err(Error::UnknownVecType(format!("{t:?}"))),
2388        })
2389    }
2390    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
2391        match &self {
2392            ValueVec::Int8(v) => {
2393                writer.write_u32::<LE>(v.len() as u32)?;
2394                for i in v {
2395                    writer.write_i8(*i)?;
2396                }
2397            }
2398            ValueVec::Int16(v) => {
2399                writer.write_u32::<LE>(v.len() as u32)?;
2400                for i in v {
2401                    writer.write_i16::<LE>(*i)?;
2402                }
2403            }
2404            ValueVec::Int(v) => {
2405                writer.write_u32::<LE>(v.len() as u32)?;
2406                for i in v {
2407                    writer.write_i32::<LE>(*i)?;
2408                }
2409            }
2410            ValueVec::Int64(v) => {
2411                writer.write_u32::<LE>(v.len() as u32)?;
2412                for i in v {
2413                    writer.write_i64::<LE>(*i)?;
2414                }
2415            }
2416            ValueVec::UInt8(v) => {
2417                writer.write_u32::<LE>(v.len() as u32)?;
2418                for i in v {
2419                    writer.write_u8(*i)?;
2420                }
2421            }
2422            ValueVec::UInt16(v) => {
2423                writer.write_u32::<LE>(v.len() as u32)?;
2424                for i in v {
2425                    writer.write_u16::<LE>(*i)?;
2426                }
2427            }
2428            ValueVec::UInt32(v) => {
2429                writer.write_u32::<LE>(v.len() as u32)?;
2430                for i in v {
2431                    writer.write_u32::<LE>(*i)?;
2432                }
2433            }
2434            ValueVec::UInt64(v) => {
2435                writer.write_u32::<LE>(v.len() as u32)?;
2436                for i in v {
2437                    writer.write_u64::<LE>(*i)?;
2438                }
2439            }
2440            ValueVec::Float(v) => {
2441                writer.write_u32::<LE>(v.len() as u32)?;
2442                for i in v {
2443                    writer.write_f32::<LE>(*i)?;
2444                }
2445            }
2446            ValueVec::Double(v) => {
2447                writer.write_u32::<LE>(v.len() as u32)?;
2448                for i in v {
2449                    writer.write_f64::<LE>(*i)?;
2450                }
2451            }
2452            ValueVec::Bool(v) => {
2453                writer.write_u32::<LE>(v.len() as u32)?;
2454                for b in v {
2455                    writer.write_u8(*b as u8)?;
2456                }
2457            }
2458            ValueVec::Byte(v) => match v {
2459                ByteArray::Byte(b) => {
2460                    writer.write_u32::<LE>(b.len() as u32)?;
2461                    for b in b {
2462                        writer.write_u8(*b)?;
2463                    }
2464                }
2465                ByteArray::Label(l) => {
2466                    writer.write_u32::<LE>(l.len() as u32)?;
2467                    for l in l {
2468                        write_string(writer, l)?;
2469                    }
2470                }
2471            },
2472            ValueVec::Enum(v) => {
2473                writer.write_u32::<LE>(v.len() as u32)?;
2474                for i in v {
2475                    write_string(writer, i)?;
2476                }
2477            }
2478            ValueVec::Str(v) | ValueVec::Object(v) | ValueVec::Name(v) => {
2479                writer.write_u32::<LE>(v.len() as u32)?;
2480                for i in v {
2481                    write_string(writer, i)?;
2482                }
2483            }
2484            ValueVec::Text(v) => {
2485                writer.write_u32::<LE>(v.len() as u32)?;
2486                for i in v {
2487                    i.write(writer)?;
2488                }
2489            }
2490            ValueVec::SoftObject(v) => {
2491                writer.write_u32::<LE>(v.len() as u32)?;
2492                for (a, b) in v {
2493                    write_string(writer, a)?;
2494                    write_string(writer, b)?;
2495                }
2496            }
2497            ValueVec::Box(v) => {
2498                writer.write_u32::<LE>(v.len() as u32)?;
2499                for i in v {
2500                    i.write(writer)?;
2501                }
2502            }
2503        }
2504        Ok(())
2505    }
2506}
2507impl ValueArray {
2508    fn read<R: Read + Seek, V: VersionInfo>(
2509        reader: &mut Context<R, V>,
2510        tag: PropertyTagDataFull,
2511        size: u32,
2512    ) -> TResult<ValueArray> {
2513        let count = reader.read_u32::<LE>()?;
2514        Ok(match tag {
2515            PropertyTagDataFull::Struct { struct_type, id } => {
2516                let (struct_type, id) = if !reader.version().property_tag() {
2517                    if reader.version().array_inner_tag() {
2518                        let tag = PropertyTagFull::read(reader)?.unwrap();
2519                        match tag.data {
2520                            PropertyTagDataFull::Struct { struct_type, id } => (struct_type, id),
2521                            _ => {
2522                                return Err(Error::Other(format!(
2523                                    "expected StructProperty tag, found {tag:?}"
2524                                )))
2525                            }
2526                        }
2527                    } else {
2528                        // TODO prior to 4.12 struct type is unknown so should be able to
2529                        // manually specify like Sets/Maps
2530                        (StructType::Struct(None), Default::default())
2531                    }
2532                } else {
2533                    (struct_type, id)
2534                };
2535
2536                let mut value = vec![];
2537                for _ in 0..count {
2538                    value.push(StructValue::read(reader, &struct_type)?);
2539                }
2540                ValueArray::Struct {
2541                    type_: PropertyType::StructProperty,
2542                    struct_type,
2543                    id: Some(id),
2544                    value,
2545                }
2546            }
2547            _ => ValueArray::Base(ValueVec::read(reader, &tag.basic_type(), size, count)?),
2548        })
2549    }
2550    fn write<W: Write, V: VersionInfo>(
2551        &self,
2552        writer: &mut Context<W, V>,
2553        tag: &PropertyTagFull,
2554    ) -> TResult<()> {
2555        match &self {
2556            ValueArray::Struct {
2557                type_,
2558                struct_type,
2559                id,
2560                value,
2561            } => {
2562                writer.write_u32::<LE>(value.len() as u32)?;
2563
2564                let mut buf = vec![];
2565                for v in value {
2566                    writer.with_stream(&mut buf, |writer| v.write(writer))?;
2567                }
2568
2569                if !writer.version().property_tag() && writer.version().array_inner_tag() {
2570                    write_string(writer, &tag.name)?;
2571                    type_.write(writer)?;
2572                    writer.write_u32::<LE>(buf.len() as u32)?;
2573                    writer.write_u32::<LE>(0)?;
2574                    struct_type.write(writer)?;
2575                    if let Some(id) = id {
2576                        id.write(writer)?;
2577                    }
2578                    writer.write_u8(0)?;
2579                }
2580                writer.write_all(&buf)?;
2581            }
2582            ValueArray::Base(vec) => {
2583                vec.write(writer)?;
2584            }
2585        }
2586        Ok(())
2587    }
2588}
2589impl ValueSet {
2590    fn read<R: Read + Seek, V: VersionInfo>(
2591        reader: &mut Context<R, V>,
2592        t: &PropertyTagDataFull,
2593        size: u32,
2594    ) -> TResult<ValueSet> {
2595        let count = reader.read_u32::<LE>()?;
2596        Ok(match t {
2597            PropertyTagDataFull::Struct { struct_type, .. } => {
2598                ValueSet::Struct(read_array(count, reader, |r| {
2599                    StructValue::read(r, struct_type)
2600                })?)
2601            }
2602            _ => ValueSet::Base(ValueVec::read(reader, &t.basic_type(), size, count)?),
2603        })
2604    }
2605    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
2606        match &self {
2607            ValueSet::Struct(value) => {
2608                writer.write_u32::<LE>(value.len() as u32)?;
2609                for v in value {
2610                    v.write(writer)?;
2611                }
2612            }
2613            ValueSet::Base(vec) => {
2614                vec.write(writer)?;
2615            }
2616        }
2617        Ok(())
2618    }
2619}
2620
2621/// Properties consist of an ID and a value and are present in [`Root`] and [`StructValue::Struct`]
2622#[derive(Debug, PartialEq, Serialize, Deserialize)]
2623pub struct Property {
2624    pub tag: PropertyTagPartial,
2625    #[serde(flatten)]
2626    pub inner: PropertyInner,
2627}
2628
2629/// Properties consist of an ID and a value and are present in [`Root`] and [`StructValue::Struct`]
2630#[derive(Debug, PartialEq, Serialize, Deserialize)]
2631pub enum PropertyInner {
2632    Int8(Int8),
2633    Int16(Int16),
2634    Int(Int),
2635    Int64(Int64),
2636    UInt8(UInt8),
2637    UInt16(UInt16),
2638    UInt32(UInt32),
2639    UInt64(UInt64),
2640    Float(Float),
2641    Double(Double),
2642    Bool(Bool),
2643    Byte(Byte),
2644    Enum(Enum),
2645    Str(String),
2646    FieldPath(FieldPath),
2647    SoftObject(SoftObjectPath),
2648    Name(String),
2649    Object(String),
2650    Text(Text),
2651    Delegate(Delegate),
2652    MulticastDelegate(MulticastDelegate),
2653    MulticastInlineDelegate(MulticastInlineDelegate),
2654    MulticastSparseDelegate(MulticastSparseDelegate),
2655    Set(ValueSet),
2656    Map(Vec<MapEntry>),
2657    Struct(StructValue),
2658    Array(ValueArray),
2659}
2660
2661impl Property {
2662    fn read<R: Read + Seek, V: VersionInfo>(
2663        reader: &mut Context<R, V>,
2664        tag: PropertyTagFull,
2665    ) -> TResult<Property> {
2666        let inner = match &tag.data {
2667            PropertyTagDataFull::Bool(value) => PropertyInner::Bool(*value),
2668            PropertyTagDataFull::Byte(ref enum_type) => {
2669                let value = if enum_type.is_none() {
2670                    Byte::Byte(reader.read_u8()?)
2671                } else {
2672                    Byte::Label(read_string(reader)?)
2673                };
2674                PropertyInner::Byte(value)
2675            }
2676            PropertyTagDataFull::Enum { .. } => PropertyInner::Enum(read_string(reader)?),
2677            PropertyTagDataFull::Set { key_type } => {
2678                reader.read_u32::<LE>()?;
2679                PropertyInner::Set(ValueSet::read(reader, key_type, tag.size - 8)?)
2680            }
2681            PropertyTagDataFull::Map {
2682                key_type,
2683                value_type,
2684            } => {
2685                reader.read_u32::<LE>()?;
2686                let count = reader.read_u32::<LE>()?;
2687                let mut value = vec![];
2688
2689                for _ in 0..count {
2690                    value.push(MapEntry::read(reader, key_type, value_type)?)
2691                }
2692
2693                PropertyInner::Map(value)
2694            }
2695            PropertyTagDataFull::Struct { struct_type, .. } => {
2696                PropertyInner::Struct(StructValue::read(reader, struct_type)?)
2697            }
2698            PropertyTagDataFull::Array(data) => {
2699                PropertyInner::Array(ValueArray::read(reader, *data.clone(), tag.size - 4)?)
2700            }
2701            PropertyTagDataFull::Other(t) => match t {
2702                PropertyType::BoolProperty
2703                | PropertyType::ByteProperty
2704                | PropertyType::EnumProperty
2705                | PropertyType::SetProperty
2706                | PropertyType::MapProperty
2707                | PropertyType::StructProperty
2708                | PropertyType::ArrayProperty => unreachable!(),
2709                PropertyType::Int8Property => PropertyInner::Int8(reader.read_i8()?),
2710                PropertyType::Int16Property => PropertyInner::Int16(reader.read_i16::<LE>()?),
2711                PropertyType::IntProperty => PropertyInner::Int(reader.read_i32::<LE>()?),
2712                PropertyType::Int64Property => PropertyInner::Int64(reader.read_i64::<LE>()?),
2713                PropertyType::UInt8Property => PropertyInner::UInt8(reader.read_u8()?),
2714                PropertyType::UInt16Property => PropertyInner::UInt16(reader.read_u16::<LE>()?),
2715                PropertyType::UInt32Property => PropertyInner::UInt32(reader.read_u32::<LE>()?),
2716                PropertyType::UInt64Property => PropertyInner::UInt64(reader.read_u64::<LE>()?),
2717                PropertyType::FloatProperty => PropertyInner::Float(reader.read_f32::<LE>()?),
2718                PropertyType::DoubleProperty => PropertyInner::Double(reader.read_f64::<LE>()?),
2719                PropertyType::NameProperty => PropertyInner::Name(read_string(reader)?),
2720                PropertyType::StrProperty => PropertyInner::Str(read_string(reader)?),
2721                PropertyType::FieldPathProperty => {
2722                    PropertyInner::FieldPath(FieldPath::read(reader)?)
2723                }
2724                PropertyType::SoftObjectProperty => {
2725                    PropertyInner::SoftObject(SoftObjectPath::read(reader)?)
2726                }
2727                PropertyType::ObjectProperty => PropertyInner::Object(read_string(reader)?),
2728                PropertyType::TextProperty => PropertyInner::Text(Text::read(reader)?),
2729                PropertyType::DelegateProperty => PropertyInner::Delegate(Delegate::read(reader)?),
2730                PropertyType::MulticastDelegateProperty => {
2731                    PropertyInner::MulticastDelegate(MulticastDelegate::read(reader)?)
2732                }
2733                PropertyType::MulticastInlineDelegateProperty => {
2734                    PropertyInner::MulticastInlineDelegate(MulticastInlineDelegate::read(reader)?)
2735                }
2736                PropertyType::MulticastSparseDelegateProperty => {
2737                    PropertyInner::MulticastSparseDelegate(MulticastSparseDelegate::read(reader)?)
2738                }
2739            },
2740        };
2741        Ok(Property {
2742            tag: tag.into_full(),
2743            inner,
2744        })
2745    }
2746    fn write<W: Write, V: VersionInfo>(
2747        &self,
2748        writer: &mut Context<W, V>,
2749        tag: &PropertyTagFull,
2750    ) -> TResult<usize> {
2751        Ok(match &self.inner {
2752            PropertyInner::Int8(value) => {
2753                writer.write_i8(*value)?;
2754                1
2755            }
2756            PropertyInner::Int16(value) => {
2757                writer.write_i16::<LE>(*value)?;
2758                2
2759            }
2760            PropertyInner::Int(value) => {
2761                writer.write_i32::<LE>(*value)?;
2762                4
2763            }
2764            PropertyInner::Int64(value) => {
2765                writer.write_i64::<LE>(*value)?;
2766                8
2767            }
2768            PropertyInner::UInt8(value) => {
2769                writer.write_u8(*value)?;
2770                1
2771            }
2772            PropertyInner::UInt16(value) => {
2773                writer.write_u16::<LE>(*value)?;
2774                2
2775            }
2776            PropertyInner::UInt32(value) => {
2777                writer.write_u32::<LE>(*value)?;
2778                4
2779            }
2780            PropertyInner::UInt64(value) => {
2781                writer.write_u64::<LE>(*value)?;
2782                8
2783            }
2784            PropertyInner::Float(value) => {
2785                writer.write_f32::<LE>(*value)?;
2786                4
2787            }
2788            PropertyInner::Double(value) => {
2789                writer.write_f64::<LE>(*value)?;
2790                8
2791            }
2792            PropertyInner::Bool(_) => 0,
2793            PropertyInner::Byte(value) => match value {
2794                Byte::Byte(b) => {
2795                    writer.write_u8(*b)?;
2796                    1
2797                }
2798                Byte::Label(l) => {
2799                    write_string(writer, l)?;
2800                    l.len() + 5
2801                }
2802            },
2803            PropertyInner::Enum(value) => {
2804                write_string(writer, value)?;
2805                value.len() + 5
2806            }
2807            PropertyInner::Name(value) => {
2808                let mut buf = vec![];
2809                writer.with_stream(&mut buf, |writer| write_string(writer, value))?;
2810                writer.write_all(&buf)?;
2811                buf.len()
2812            }
2813            PropertyInner::Str(value) => {
2814                let mut buf = vec![];
2815                writer.with_stream(&mut buf, |writer| write_string(writer, value))?;
2816                writer.write_all(&buf)?;
2817                buf.len()
2818            }
2819            PropertyInner::FieldPath(value) => {
2820                let mut buf = vec![];
2821                writer.with_stream(&mut buf, |writer| value.write(writer))?;
2822                writer.write_all(&buf)?;
2823                buf.len()
2824            }
2825            PropertyInner::SoftObject(value) => {
2826                let mut buf = vec![];
2827                writer.with_stream(&mut buf, |writer| value.write(writer))?;
2828                writer.write_all(&buf)?;
2829                buf.len()
2830            }
2831            PropertyInner::Object(value) => {
2832                let mut buf = vec![];
2833                writer.with_stream(&mut buf, |writer| write_string(writer, value))?;
2834                writer.write_all(&buf)?;
2835                buf.len()
2836            }
2837            PropertyInner::Text(value) => {
2838                let mut buf = vec![];
2839                writer.with_stream(&mut buf, |writer| value.write(writer))?;
2840                writer.write_all(&buf)?;
2841                buf.len()
2842            }
2843            PropertyInner::Delegate(value) => {
2844                let mut buf = vec![];
2845                writer.with_stream(&mut buf, |writer| value.write(writer))?;
2846                writer.write_all(&buf)?;
2847                buf.len()
2848            }
2849            PropertyInner::MulticastDelegate(value) => {
2850                let mut buf = vec![];
2851                writer.with_stream(&mut buf, |writer| value.write(writer))?;
2852                writer.write_all(&buf)?;
2853                buf.len()
2854            }
2855            PropertyInner::MulticastInlineDelegate(value) => {
2856                let mut buf = vec![];
2857                writer.with_stream(&mut buf, |writer| value.write(writer))?;
2858                writer.write_all(&buf)?;
2859                buf.len()
2860            }
2861            PropertyInner::MulticastSparseDelegate(value) => {
2862                let mut buf = vec![];
2863                writer.with_stream(&mut buf, |writer| value.write(writer))?;
2864                writer.write_all(&buf)?;
2865                buf.len()
2866            }
2867            PropertyInner::Set(value) => {
2868                let mut buf = vec![];
2869                buf.write_u32::<LE>(0)?;
2870                writer.with_stream(&mut buf, |writer| value.write(writer))?;
2871                writer.write_all(&buf)?;
2872                buf.len()
2873            }
2874            PropertyInner::Map(value) => {
2875                let mut buf = vec![];
2876                buf.write_u32::<LE>(0)?;
2877                buf.write_u32::<LE>(value.len() as u32)?;
2878                for v in value {
2879                    writer.with_stream(&mut buf, |writer| v.write(writer))?;
2880                }
2881                writer.write_all(&buf)?;
2882                buf.len()
2883            }
2884            PropertyInner::Struct(value) => {
2885                let mut buf = vec![];
2886                writer.with_stream(&mut buf, |writer| value.write(writer))?;
2887                writer.write_all(&buf)?;
2888                buf.len()
2889            }
2890            PropertyInner::Array(value) => {
2891                let mut buf = vec![];
2892                writer.with_stream(&mut buf, |writer| value.write(writer, tag))?;
2893                writer.write_all(&buf)?;
2894                buf.len()
2895            }
2896        })
2897    }
2898}
2899
2900#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2901pub struct CustomFormatData {
2902    pub id: uuid::Uuid,
2903    pub value: i32,
2904}
2905impl<R: Read + Seek, V> Readable<R, V> for CustomFormatData {
2906    fn read(reader: &mut Context<R, V>) -> TResult<Self> {
2907        Ok(CustomFormatData {
2908            id: uuid::Uuid::read(reader)?,
2909            value: reader.read_i32::<LE>()?,
2910        })
2911    }
2912}
2913impl<W: Write, V> Writable<W, V> for CustomFormatData {
2914    fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
2915        self.id.write(writer)?;
2916        writer.write_i32::<LE>(self.value)?;
2917        Ok(())
2918    }
2919}
2920
2921#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2922pub struct PackageVersion {
2923    ue4: u32,
2924    ue5: Option<u32>,
2925}
2926
2927pub trait VersionInfo {
2928    fn large_world_coordinates(&self) -> bool;
2929    fn property_tag(&self) -> bool;
2930    fn property_guid(&self) -> bool;
2931    fn array_inner_tag(&self) -> bool;
2932    fn remove_asset_path_fnames(&self) -> bool;
2933}
2934
2935#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
2936pub struct Header {
2937    pub magic: u32,
2938    pub save_game_version: u32,
2939    pub package_version: PackageVersion,
2940    pub engine_version_major: u16,
2941    pub engine_version_minor: u16,
2942    pub engine_version_patch: u16,
2943    pub engine_version_build: u32,
2944    pub engine_version: String,
2945    pub custom_version: Option<(u32, Vec<CustomFormatData>)>,
2946}
2947impl VersionInfo for Header {
2948    fn large_world_coordinates(&self) -> bool {
2949        self.engine_version_major >= 5
2950    }
2951    fn property_tag(&self) -> bool {
2952        // PROPERTY_TAG_COMPLETE_TYPE_NAME
2953        (self.engine_version_major, self.engine_version_minor) >= (5, 4)
2954    }
2955    fn property_guid(&self) -> bool {
2956        (self.engine_version_major, self.engine_version_minor) >= (4, 12)
2957        // TODO really should check object version but would break a lot of saves with mangled headers
2958        // self.package_version.ue4 >= 503 // VER_UE4_PROPERTY_GUID_IN_PROPERTY_TAG
2959    }
2960    fn array_inner_tag(&self) -> bool {
2961        // VAR_UE4_ARRAY_PROPERTY_INNER_TAGS
2962        (self.engine_version_major, self.engine_version_minor) >= (4, 12)
2963    }
2964    fn remove_asset_path_fnames(&self) -> bool {
2965        self.package_version
2966            .ue5
2967            .map(|ue5| ue5 >= 1007) // FSOFTOBJECTPATH_REMOVE_ASSET_PATH_FNAMES
2968            .unwrap_or_default()
2969    }
2970}
2971impl<R: Read + Seek, V> Readable<R, V> for Header {
2972    fn read(reader: &mut Context<R, V>) -> TResult<Self> {
2973        let magic = reader.read_u32::<LE>()?;
2974        if reader.log() && magic != u32::from_le_bytes(*b"GVAS") {
2975            eprintln!(
2976                "Found non-standard magic: {:02x?} ({}) expected: GVAS, continuing to parse...",
2977                &magic.to_le_bytes(),
2978                String::from_utf8_lossy(&magic.to_le_bytes())
2979            );
2980        }
2981        let save_game_version = reader.read_u32::<LE>()?;
2982        let package_version = PackageVersion {
2983            ue4: reader.read_u32::<LE>()?,
2984            ue5: (save_game_version >= 3 && save_game_version != 34) // TODO 34 is probably a game specific version
2985                .then(|| reader.read_u32::<LE>())
2986                .transpose()?,
2987        };
2988        let engine_version_major = reader.read_u16::<LE>()?;
2989        let engine_version_minor = reader.read_u16::<LE>()?;
2990        let engine_version_patch = reader.read_u16::<LE>()?;
2991        let engine_version_build = reader.read_u32::<LE>()?;
2992        let engine_version = read_string(reader)?;
2993        let custom_version = if (engine_version_major, engine_version_minor) >= (4, 12) {
2994            Some((
2995                reader.read_u32::<LE>()?,
2996                read_array(reader.read_u32::<LE>()?, reader, CustomFormatData::read)?,
2997            ))
2998        } else {
2999            None
3000        };
3001        Ok(Header {
3002            magic,
3003            save_game_version,
3004            package_version,
3005            engine_version_major,
3006            engine_version_minor,
3007            engine_version_patch,
3008            engine_version_build,
3009            engine_version,
3010            custom_version,
3011        })
3012    }
3013}
3014impl<W: Write, V> Writable<W, V> for Header {
3015    fn write(&self, writer: &mut Context<W, V>) -> TResult<()> {
3016        writer.write_u32::<LE>(self.magic)?;
3017        writer.write_u32::<LE>(self.save_game_version)?;
3018        writer.write_u32::<LE>(self.package_version.ue4)?;
3019        if let Some(ue5) = self.package_version.ue5 {
3020            writer.write_u32::<LE>(ue5)?;
3021        }
3022        writer.write_u16::<LE>(self.engine_version_major)?;
3023        writer.write_u16::<LE>(self.engine_version_minor)?;
3024        writer.write_u16::<LE>(self.engine_version_patch)?;
3025        writer.write_u32::<LE>(self.engine_version_build)?;
3026        write_string(writer, &self.engine_version)?;
3027        if let Some((custom_format_version, custom_format)) = &self.custom_version {
3028            writer.write_u32::<LE>(*custom_format_version)?;
3029            writer.write_u32::<LE>(custom_format.len() as u32)?;
3030            for cf in custom_format {
3031                cf.write(writer)?;
3032            }
3033        }
3034        Ok(())
3035    }
3036}
3037
3038/// Root struct inside a save file which holds both the Unreal Engine class name and list of properties
3039#[derive(Debug, PartialEq, Serialize, Deserialize)]
3040pub struct Root {
3041    pub save_game_type: String,
3042    pub properties: Properties,
3043}
3044impl Root {
3045    fn read<R: Read + Seek, V: VersionInfo>(reader: &mut Context<R, V>) -> TResult<Self> {
3046        let save_game_type = read_string(reader)?;
3047        if reader.version().property_tag() {
3048            reader.read_u8()?;
3049        }
3050        let properties = read_properties_until_none(reader)?;
3051        Ok(Self {
3052            save_game_type,
3053            properties,
3054        })
3055    }
3056    fn write<W: Write, V: VersionInfo>(&self, writer: &mut Context<W, V>) -> TResult<()> {
3057        write_string(writer, &self.save_game_type)?;
3058        if writer.version().property_tag() {
3059            writer.write_u8(0)?;
3060        }
3061        write_properties_none_terminated(writer, &self.properties)?;
3062        Ok(())
3063    }
3064}
3065
3066#[derive(Debug, PartialEq, Serialize, Deserialize)]
3067pub struct Save {
3068    pub header: Header,
3069    pub root: Root,
3070    pub extra: Vec<u8>,
3071}
3072impl Save {
3073    /// Reads save from the given reader
3074    pub fn read<R: Read>(reader: &mut R) -> Result<Self, ParseError> {
3075        Self::read_with_types(reader, &Types::new())
3076    }
3077    /// Reads save from the given reader using the provided [`Types`]
3078    pub fn read_with_types<R: Read>(reader: &mut R, types: &Types) -> Result<Self, ParseError> {
3079        SaveReader::new().types(types).read(reader)
3080    }
3081    pub fn write<W: Write>(&self, writer: &mut W) -> TResult<()> {
3082        Context::run(writer, |writer| {
3083            writer.with_version(&self.header, |writer| {
3084                self.header.write(writer)?;
3085                self.root.write(writer)?;
3086                writer.write_all(&self.extra)?;
3087                Ok(())
3088            })
3089        })
3090    }
3091}
3092
3093pub struct SaveReader<'types> {
3094    log: bool,
3095    types: Option<&'types Types>,
3096}
3097impl Default for SaveReader<'_> {
3098    fn default() -> Self {
3099        Self::new()
3100    }
3101}
3102impl<'types> SaveReader<'types> {
3103    pub fn new() -> Self {
3104        Self {
3105            log: false,
3106            types: None,
3107        }
3108    }
3109    pub fn log(mut self, log: bool) -> Self {
3110        self.log = log;
3111        self
3112    }
3113    pub fn types(mut self, types: &'types Types) -> Self {
3114        self.types = Some(types);
3115        self
3116    }
3117    pub fn read<S: Read>(self, stream: S) -> Result<Save, ParseError> {
3118        let tmp = Types::new();
3119        let types = self.types.unwrap_or(&tmp);
3120
3121        let mut stream = SeekReader::new(stream);
3122        let mut reader = Context {
3123            stream: &mut stream,
3124            state: ContextState {
3125                version: &(),
3126                types,
3127                scope: &Scope::Root,
3128                log: self.log,
3129            },
3130        };
3131
3132        || -> TResult<Save> {
3133            let header = Header::read(&mut reader)?;
3134            let (root, extra) = reader.with_version(&header, |reader| -> TResult<_> {
3135                let root = Root::read(reader)?;
3136                let extra = {
3137                    let mut buf = vec![];
3138                    reader.read_to_end(&mut buf)?;
3139                    if reader.log() && buf != [0; 4] {
3140                        eprintln!(
3141                            "{} extra bytes. Save may not have been parsed completely.",
3142                            buf.len()
3143                        );
3144                    }
3145                    buf
3146                };
3147                Ok((root, extra))
3148            })?;
3149            Ok(Save {
3150                header,
3151                root,
3152                extra,
3153            })
3154        }()
3155        .map_err(|e| error::ParseError {
3156            offset: reader.stream_position().unwrap() as usize, // our own implemenation which cannot fail
3157            error: e,
3158        })
3159    }
3160}