Reorganize the entire project

This commit is contained in:
Joshua Goins 2025-03-02 17:00:33 -05:00
parent 53aba498d1
commit 3b26da6b57
44 changed files with 424 additions and 359 deletions

View file

@ -40,8 +40,8 @@ pub fn serialized_struct(_metadata: TokenStream, input: TokenStream)
field_names.push(our_custom_name.clone()); field_names.push(our_custom_name.clone());
let field_tokens = field.to_token_stream(); let field_tokens = field.to_token_stream();
let new_field_token_stream = quote! { let new_field_token_stream = quote! {
#[br(parse_with = crate::structs::read_struct_field, args(#our_custom_name))] #[br(parse_with = crate::structure::read_struct_field, args(#our_custom_name))]
#[bw(write_with = crate::structs::write_struct_field, args(#our_custom_name))] #[bw(write_with = crate::structure::write_struct_field, args(#our_custom_name))]
#field_tokens #field_tokens
}; };
let buffer = ::syn::parse::Parser::parse2( let buffer = ::syn::parse::Parser::parse2(
@ -54,8 +54,8 @@ pub fn serialized_struct(_metadata: TokenStream, input: TokenStream)
// Add "None" field // Add "None" field
let none_field_stream = quote! { let none_field_stream = quote! {
#[br(temp)] #[br(temp)]
#[bw(calc = crate::structs::GenericProperty { property_name: "None".to_string(), type_name: "".to_string(), key: None } )] #[bw(calc = crate::property::generic_property::GenericProperty { property_name: "None".to_string(), type_name: "".to_string(), key: None } )]
none_field: crate::structs::GenericProperty none_field: crate::property::generic_property::GenericProperty
}; };
let buffer = ::syn::parse::Parser::parse2( let buffer = ::syn::parse::Parser::parse2(
syn::Field::parse_named, syn::Field::parse_named,
@ -75,7 +75,7 @@ pub fn serialized_struct(_metadata: TokenStream, input: TokenStream)
#input #input
#[automatically_derived] #[automatically_derived]
impl crate::structs::PropertyBase for #id { impl crate::property::PropertyBase for #id {
fn type_name() -> &'static str { fn type_name() -> &'static str {
return "StructProperty"; return "StructProperty";
} }
@ -85,7 +85,7 @@ pub fn serialized_struct(_metadata: TokenStream, input: TokenStream)
} }
fn size_in_bytes(&self) -> u32 { fn size_in_bytes(&self) -> u32 {
#( #field_types::size_in_bytes(&self.#field_idents) )+* + #( (crate::structs::calc_struct_field_prelude_byte_size(stringify!(#field_types), #field_names, #field_types::struct_name()) ) )+* + 9 // for "none" field #( #field_types::size_in_bytes(&self.#field_idents) )+* + #( (crate::structure::calc_struct_field_prelude_byte_size(stringify!(#field_types), #field_names, #field_types::struct_name()) ) )+* + 9 // for "none" field
} }
} }
}; };

View file

@ -1,5 +1,6 @@
use binrw::BinRead; use binrw::BinRead;
use ireko::{CompressedSaveFile, GenericTaggedObject}; use ireko::CompressedSaveFile;
use ireko::save_object::generic::GenericTaggedObject;
use std::env; use std::env;
use std::io::Cursor; use std::io::Cursor;

View file

@ -1,155 +1,15 @@
pub mod array_property;
pub mod bool_property;
mod build_data;
mod common; mod common;
mod da_assemble_id_data; pub mod property;
mod da_customize_asset_id; pub mod save_object;
mod da_humanoid_coloring_data; pub mod structure;
mod da_humanoid_figure_data;
mod da_load_option;
mod da_machine_coloring_data;
mod da_module_color;
mod da_module_item_data;
mod da_trigger_data;
mod da_tuning_data;
mod da_tuning_point_data;
mod datetime;
mod enum_property;
pub mod float_property;
mod guid;
pub mod int_property;
mod linear_color;
mod localprofile;
pub mod map_property;
mod name_property;
mod persistent;
mod primary_asset_id;
mod primary_asset_type;
mod quat;
mod save_slot_info;
pub mod set_property;
mod slot;
pub mod str_property;
pub mod struct_property;
mod structs;
mod transform;
mod vector;
use binrw::helpers::until_eof; use binrw::helpers::until_eof;
use std::fs::write; use std::fs::write;
use std::io::{Cursor, Read}; use std::io::{Cursor, Read};
use crate::array_property::ArrayProperty;
use crate::bool_property::BoolProperty;
use crate::common::{read_string_with_length, write_string_with_length};
use crate::float_property::FloatProperty;
use crate::int_property::IntProperty;
use crate::map_property::MapProperty;
use crate::name_property::NameProperty;
use crate::set_property::SetProperty;
use crate::str_property::StrProperty;
use crate::struct_property::StructProperty;
use binrw::{BinRead, BinResult, BinWrite, binrw}; use binrw::{BinRead, BinResult, BinWrite, binrw};
use flate2::bufread::ZlibDecoder; use flate2::bufread::ZlibDecoder;
// Used in ArrayProperty exclusively, but could be used instead of magic above
#[binrw]
#[derive(Debug)]
#[br(import { magic: &str, name: &str })]
pub enum Property {
#[br(pre_assert("NameProperty" == magic))]
Name(NameProperty),
#[br(pre_assert("StructProperty" == magic))]
Struct(StructProperty),
#[br(pre_assert("FloatProperty" == magic))]
Float(FloatProperty),
#[br(pre_assert("StrProperty" == magic))]
String(StrProperty),
#[br(pre_assert("BoolProperty" == magic))]
Bool(BoolProperty),
#[br(pre_assert("IntProperty" == magic))]
Int(IntProperty),
#[br(pre_assert("ArrayProperty" == magic))]
Array(ArrayProperty),
#[br(pre_assert("MapProperty" == magic))]
Map(MapProperty),
#[br(pre_assert("SetProperty" == magic))]
Set(SetProperty),
}
#[binrw]
#[derive(Debug)]
pub struct Entry {
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
pub name: String,
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
#[br(if(name != "None"))]
pub type_name: String,
#[br(if(name != "None"), args { magic: &type_name, name: &name })]
pub r#type: Option<Property>,
}
#[binrw::parser(reader, endian)]
fn custom_tagged_object_parser(size_in_bytes: u32) -> BinResult<Vec<Entry>> {
let mut result = Vec::<Entry>::new();
let mut current = reader.stream_position()?;
let end = current + size_in_bytes as u64 - 4; // for the size bits
while current < end {
let entry = Entry::read_options(reader, endian, ())?;
if entry.name == "None" {
break;
}
result.push(entry);
current = reader.stream_position()?;
}
Ok(result)
}
#[binrw::writer(writer, endian)]
fn custom_tagged_object_writer(entries: &Vec<Entry>) -> BinResult<()> {
for entry in entries {
entry.write_options(writer, endian, ())?
}
// Write "none" entry at the end
let none_entry = Entry {
name: "None".to_string(),
type_name: "".to_string(),
r#type: None,
};
none_entry.write_options(writer, endian, ())?;
Ok(())
}
#[binrw]
#[derive(Debug)]
pub struct GenericTaggedObject {
pub size_in_bytes: u32,
#[br(parse_with = custom_tagged_object_parser, args(size_in_bytes))]
#[bw(write_with = custom_tagged_object_writer)]
pub entries: Vec<Entry>,
}
#[binrw]
#[derive(Debug)]
pub struct PersistentObject {
pub size_in_bytes: u32,
#[br(pad_after = 4)]
pub profile: persistent::Persistent,
}
impl GenericTaggedObject {
pub fn entry(&self, key: &str) -> Option<&Entry> {
let entries: Vec<&Entry> = self.entries.iter().filter(|e| e.name == key).collect();
entries.first().copied()
}
}
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]
pub struct TaggedSerialization<T> pub struct TaggedSerialization<T>

View file

@ -1,8 +1,15 @@
use crate::common::{read_string_with_length, write_string_with_length};
use crate::map_property::{KeyType, StringMapKey};
use crate::struct_property::Struct;
use binrw::{BinRead, BinResult, binrw}; use binrw::{BinRead, BinResult, binrw};
use crate::{
common::{read_string_with_length, write_string_with_length},
structure::Struct,
};
use super::{
PropertyBase,
map_property::{KeyType, StringMapKey},
};
fn calculate_header_size(key_name: &str, array_key_data: &ArrayKeyData) -> u64 { fn calculate_header_size(key_name: &str, array_key_data: &ArrayKeyData) -> u64 {
// TODO: blah, needs to take into account everything before the first item // TODO: blah, needs to take into account everything before the first item
match array_key_data { match array_key_data {
@ -19,7 +26,7 @@ fn calculate_header_size(key_name: &str, array_key_data: &ArrayKeyData) -> u64 {
} }
} }
impl crate::structs::PropertyBase for ArrayProperty { impl PropertyBase for ArrayProperty {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"ArrayProperty" "ArrayProperty"
} }
@ -83,7 +90,7 @@ fn calc_size_in_bytes(prop: &ArrayProperty) -> u32 {
for entry in &prop.entries { for entry in &prop.entries {
size += match &entry.key { size += match &entry.key {
ArrayValue::Struct { r#struct } => crate::struct_property::calc_size_in_bytes(r#struct), ArrayValue::Struct { r#struct } => crate::structure::calc_size_in_bytes(r#struct),
ArrayValue::String(string_map_key) => { ArrayValue::String(string_map_key) => {
crate::common::size_of_string_with_length(&string_map_key.value) crate::common::size_of_string_with_length(&string_map_key.value)
} }
@ -158,7 +165,6 @@ pub struct ArrayProperty {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::map_property::StringMapKey;
use binrw::{BinRead, BinWrite}; use binrw::{BinRead, BinWrite};
use std::io::Cursor; use std::io::Cursor;

View file

@ -1,6 +1,8 @@
use crate::common::{read_bool_from, write_bool_as}; use crate::common::{read_bool_from, write_bool_as};
use binrw::binrw; use binrw::binrw;
use super::PropertyBase;
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]
pub struct BoolProperty { pub struct BoolProperty {
@ -10,7 +12,7 @@ pub struct BoolProperty {
pub value: bool, pub value: bool,
} }
impl crate::structs::PropertyBase for BoolProperty { impl PropertyBase for BoolProperty {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"IntProperty" "IntProperty"
} }

View file

@ -1,6 +1,8 @@
use crate::common::{read_string_with_length, write_string_with_length}; use crate::common::{read_string_with_length, write_string_with_length};
use binrw::binrw; use binrw::binrw;
use super::PropertyBase;
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]
pub struct EnumProperty { pub struct EnumProperty {
@ -15,7 +17,7 @@ pub struct EnumProperty {
pub value: String, pub value: String,
} }
impl crate::structs::PropertyBase for EnumProperty { impl PropertyBase for EnumProperty {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"EnumProperty" "EnumProperty"
} }

View file

@ -1,5 +1,7 @@
use binrw::binrw; use binrw::binrw;
use super::PropertyBase;
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]
pub struct FloatProperty { pub struct FloatProperty {
@ -9,7 +11,7 @@ pub struct FloatProperty {
pub value: f32, pub value: f32,
} }
impl crate::structs::PropertyBase for FloatProperty { impl PropertyBase for FloatProperty {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"FloatProperty" "FloatProperty"
} }

View file

@ -0,0 +1,23 @@
use binrw::binrw;
use crate::{
common::{read_string_with_length, write_string_with_length},
save_object::generic::Property,
};
#[binrw]
#[derive(Debug)]
pub struct GenericProperty {
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
pub property_name: String,
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
#[br(if(property_name != "None"))]
pub type_name: String,
#[br(if(property_name != "None"))]
#[br(args { magic: &type_name, name: &property_name})]
pub key: Option<Box<Property>>,
}

View file

@ -1,5 +1,7 @@
use binrw::binrw; use binrw::binrw;
use super::PropertyBase;
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]
pub struct IntProperty { pub struct IntProperty {
@ -9,7 +11,7 @@ pub struct IntProperty {
pub value: u32, pub value: u32,
} }
impl crate::structs::PropertyBase for IntProperty { impl PropertyBase for IntProperty {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"IntProperty" "IntProperty"
} }

View file

@ -1,11 +1,12 @@
use crate::common::{
read_bool_from, read_string_with_length, write_bool_as, write_string_with_length,
};
use crate::guid::Guid;
use crate::struct_property::Struct;
use crate::structs::{GenericProperty, PropertyBase};
use binrw::{BinRead, BinResult, binrw}; use binrw::{BinRead, BinResult, binrw};
use crate::{
common::{read_bool_from, read_string_with_length, write_bool_as, write_string_with_length},
structure::{Struct, guid::Guid},
};
use super::{PropertyBase, generic_property::GenericProperty};
// parse until we can't parse no more. kind of a hack for how we run into the end of Persistent.Sav // parse until we can't parse no more. kind of a hack for how we run into the end of Persistent.Sav
#[binrw::parser(reader, endian)] #[binrw::parser(reader, endian)]
fn cc() -> BinResult<Vec<GenericProperty>> { fn cc() -> BinResult<Vec<GenericProperty>> {
@ -225,7 +226,7 @@ fn calc_entry_size_in_bytes(prop: &MapProperty) -> u32 {
+ crate::common::size_of_string_with_length(&struct_maybe_key.unk_type) + crate::common::size_of_string_with_length(&struct_maybe_key.unk_type)
+ crate::common::size_of_string_with_length(&struct_maybe_key.struct_name) + crate::common::size_of_string_with_length(&struct_maybe_key.struct_name)
+ 17 + 17
+ crate::struct_property::calc_size_in_bytes(&struct_maybe_key.r#struct) + crate::structure::calc_size_in_bytes(&struct_maybe_key.r#struct)
} }
MapKeyProperty::Enum(map_sub_enum_property) => { MapKeyProperty::Enum(map_sub_enum_property) => {
crate::common::size_of_string_with_length(&map_sub_enum_property.value) crate::common::size_of_string_with_length(&map_sub_enum_property.value)
@ -242,7 +243,7 @@ fn calc_entry_size_in_bytes(prop: &MapProperty) -> u32 {
+ crate::common::size_of_string_with_length(&struct_maybe_key.unk_type) + crate::common::size_of_string_with_length(&struct_maybe_key.unk_type)
+ crate::common::size_of_string_with_length(&struct_maybe_key.struct_name) + crate::common::size_of_string_with_length(&struct_maybe_key.struct_name)
+ 17 + 17
+ crate::struct_property::calc_size_in_bytes(&struct_maybe_key.r#struct) + crate::structure::calc_size_in_bytes(&struct_maybe_key.r#struct)
} }
MapKeyProperty::SomeID3(guid) => guid.size_in_bytes(), MapKeyProperty::SomeID3(guid) => guid.size_in_bytes(),
MapKeyProperty::SoftObjectProperty(string_map_key) => { MapKeyProperty::SoftObjectProperty(string_map_key) => {
@ -292,7 +293,7 @@ pub struct MapProperty {
pub entries: Vec<MapEntry>, pub entries: Vec<MapEntry>,
} }
impl crate::structs::PropertyBase for MapProperty { impl PropertyBase for MapProperty {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"MapProperty" "MapProperty"
} }
@ -310,7 +311,6 @@ impl crate::structs::PropertyBase for MapProperty {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::map_property::MabSubProperty::{Int, String};
use binrw::{BinRead, BinWrite}; use binrw::{BinRead, BinWrite};
use std::io::Cursor; use std::io::Cursor;
@ -333,7 +333,7 @@ mod tests {
let MapKeyProperty::String(key_property) = &decoded.entries.first().unwrap().key else { let MapKeyProperty::String(key_property) = &decoded.entries.first().unwrap().key else {
panic!("StrProperty!") panic!("StrProperty!")
}; };
let String(value_property) = &decoded.entries.first().unwrap().value else { let MabSubProperty::String(value_property) = &decoded.entries.first().unwrap().value else {
panic!("StrProperty!") panic!("StrProperty!")
}; };
assert_eq!(key_property.value, "AR0XJGFWA6HNIQ1AAUJ9UR828"); assert_eq!(key_property.value, "AR0XJGFWA6HNIQ1AAUJ9UR828");
@ -359,7 +359,7 @@ mod tests {
key: MapKeyProperty::String(StringMapKey { key: MapKeyProperty::String(StringMapKey {
value: "AR0XJGFWA6HNIQ1AAUJ9UR828".to_string(), value: "AR0XJGFWA6HNIQ1AAUJ9UR828".to_string(),
}), }),
value: String(MapSubStrProperty { value: MabSubProperty::String(MapSubStrProperty {
value: "NAME 1".to_string(), value: "NAME 1".to_string(),
}), }),
}], }],
@ -403,7 +403,7 @@ mod tests {
let MapKeyProperty::Enum(key_property) = &decoded.entries.first().unwrap().key else { let MapKeyProperty::Enum(key_property) = &decoded.entries.first().unwrap().key else {
panic!("Name!") panic!("Name!")
}; };
let Int(value_property) = &decoded.entries.first().unwrap().value else { let MabSubProperty::Int(value_property) = &decoded.entries.first().unwrap().value else {
panic!("Int!") panic!("Int!")
}; };
assert_eq!(key_property.value, "SelectedMachine"); assert_eq!(key_property.value, "SelectedMachine");

22
src/property/mod.rs Normal file
View file

@ -0,0 +1,22 @@
pub mod array_property;
pub mod bool_property;
pub mod enum_property;
pub mod float_property;
pub mod generic_property;
pub mod int_property;
pub mod map_property;
pub mod name_property;
pub mod set_property;
pub mod str_property;
pub mod struct_property;
pub(crate) trait PropertyBase {
fn type_name() -> &'static str;
fn size_in_bytes(&self) -> u32;
// these are only relevant for structs:
// FIXME: this isn't great'
fn struct_name() -> Option<&'static str> {
None
}
}

View file

@ -1,6 +1,8 @@
use crate::common::{read_string_with_length, write_string_with_length}; use crate::common::{read_string_with_length, write_string_with_length};
use binrw::binrw; use binrw::binrw;
use super::PropertyBase;
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]
pub struct NameProperty { pub struct NameProperty {
@ -14,7 +16,7 @@ pub struct NameProperty {
pub value: String, pub value: String,
} }
impl crate::structs::PropertyBase for NameProperty { impl PropertyBase for NameProperty {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"NameProperty" "NameProperty"
} }

View file

@ -1,8 +1,12 @@
use crate::common::{read_string_with_length, write_string_with_length}; use crate::common::{read_string_with_length, write_string_with_length};
use crate::map_property::{KeyType, MapSubStrProperty};
use crate::structs::GenericProperty;
use binrw::{BinRead, BinResult, binrw}; use binrw::{BinRead, BinResult, binrw};
use super::{
PropertyBase,
generic_property::GenericProperty,
map_property::{KeyType, MapSubStrProperty},
};
// hack, we should be checking for "none" instead // hack, we should be checking for "none" instead
#[binrw::parser(reader, endian)] #[binrw::parser(reader, endian)]
fn cc() -> BinResult<Vec<GenericProperty>> { fn cc() -> BinResult<Vec<GenericProperty>> {
@ -88,7 +92,7 @@ pub struct SetProperty {
pub entries: Vec<SetEntry>, pub entries: Vec<SetEntry>,
} }
impl crate::structs::PropertyBase for SetProperty { impl PropertyBase for SetProperty {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"SetProperty" "SetProperty"
} }

View file

@ -1,6 +1,8 @@
use crate::common::{read_string_with_length, write_string_with_length}; use crate::common::{read_string_with_length, write_string_with_length};
use binrw::binrw; use binrw::binrw;
use super::PropertyBase;
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]
pub struct StrProperty { pub struct StrProperty {
@ -14,7 +16,7 @@ pub struct StrProperty {
pub value: String, pub value: String,
} }
impl crate::structs::PropertyBase for StrProperty { impl PropertyBase for StrProperty {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"StrProperty" "StrProperty"
} }

View file

@ -0,0 +1,18 @@
use crate::{
common::{read_string_with_length, write_string_with_length},
structure::Struct,
};
use binrw::binrw;
#[binrw]
#[derive(Debug)]
pub struct StructProperty {
pub unk: u32,
#[brw(pad_before = 4)]
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
pub struct_name: String,
#[br(args { magic: &struct_name })]
#[brw(pad_before = 17)]
pub r#struct: Struct,
}

100
src/save_object/generic.rs Normal file
View file

@ -0,0 +1,100 @@
use binrw::{BinRead, BinResult, BinWrite, binrw};
use crate::{
common::{read_string_with_length, write_string_with_length},
property::{
array_property::ArrayProperty, bool_property::BoolProperty, float_property::FloatProperty,
int_property::IntProperty, map_property::MapProperty, name_property::NameProperty,
set_property::SetProperty, str_property::StrProperty, struct_property::StructProperty,
},
};
// Used in ArrayProperty exclusively, but could be used instead of magic above
#[binrw]
#[derive(Debug)]
#[br(import { magic: &str, name: &str })]
pub enum Property {
#[br(pre_assert("NameProperty" == magic))]
Name(NameProperty),
#[br(pre_assert("StructProperty" == magic))]
Struct(StructProperty),
#[br(pre_assert("FloatProperty" == magic))]
Float(FloatProperty),
#[br(pre_assert("StrProperty" == magic))]
String(StrProperty),
#[br(pre_assert("BoolProperty" == magic))]
Bool(BoolProperty),
#[br(pre_assert("IntProperty" == magic))]
Int(IntProperty),
#[br(pre_assert("ArrayProperty" == magic))]
Array(ArrayProperty),
#[br(pre_assert("MapProperty" == magic))]
Map(MapProperty),
#[br(pre_assert("SetProperty" == magic))]
Set(SetProperty),
}
#[binrw]
#[derive(Debug)]
pub struct Entry {
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
pub name: String,
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
#[br(if(name != "None"))]
pub type_name: String,
#[br(if(name != "None"), args { magic: &type_name, name: &name })]
pub r#type: Option<Property>,
}
#[binrw::parser(reader, endian)]
fn custom_tagged_object_parser(size_in_bytes: u32) -> BinResult<Vec<Entry>> {
let mut result = Vec::<Entry>::new();
let mut current = reader.stream_position()?;
let end = current + size_in_bytes as u64 - 4; // for the size bits
while current < end {
let entry = Entry::read_options(reader, endian, ())?;
if entry.name == "None" {
break;
}
result.push(entry);
current = reader.stream_position()?;
}
Ok(result)
}
#[binrw::writer(writer, endian)]
fn custom_tagged_object_writer(entries: &Vec<Entry>) -> BinResult<()> {
for entry in entries {
entry.write_options(writer, endian, ())?
}
// Write "none" entry at the end
let none_entry = Entry {
name: "None".to_string(),
type_name: "".to_string(),
r#type: None,
};
none_entry.write_options(writer, endian, ())?;
Ok(())
}
#[binrw]
#[derive(Debug)]
pub struct GenericTaggedObject {
pub size_in_bytes: u32,
#[br(parse_with = custom_tagged_object_parser, args(size_in_bytes))]
#[bw(write_with = custom_tagged_object_writer)]
pub entries: Vec<Entry>,
}
impl GenericTaggedObject {
pub fn entry(&self, key: &str) -> Option<&Entry> {
let entries: Vec<&Entry> = self.entries.iter().filter(|e| e.name == key).collect();
entries.first().copied()
}
}

View file

@ -1,4 +1,4 @@
use crate::{ use crate::property::{
bool_property::BoolProperty, int_property::IntProperty, map_property::MapProperty, bool_property::BoolProperty, int_property::IntProperty, map_property::MapProperty,
str_property::StrProperty, str_property::StrProperty,
}; };

4
src/save_object/mod.rs Normal file
View file

@ -0,0 +1,4 @@
pub mod generic;
pub mod localprofile;
pub mod persistent;
pub mod slot;

View file

@ -1,7 +1,15 @@
use binrw::binrw;
use crate::{ use crate::{
array_property::ArrayProperty, bool_property::BoolProperty, build_data::DABuildDataStruct, da_tuning_point_data::DATuningPointData, int_property::IntProperty, property::{
map_property::MapProperty, name_property::NameProperty, array_property::ArrayProperty, bool_property::BoolProperty, int_property::IntProperty,
set_property::SetProperty, str_property::StrProperty, transform::TransformStruct, map_property::MapProperty, name_property::NameProperty, set_property::SetProperty,
str_property::StrProperty,
},
structure::{
build_data::DABuildDataStruct, da_tuning_point_data::DATuningPointData,
transform::TransformStruct,
},
}; };
#[paramacro::serialized_struct("Transform")] #[paramacro::serialized_struct("Transform")]
@ -97,3 +105,11 @@ pub struct Persistent {
#[paramacro::serialized_field = "bUseSaveSlot"] #[paramacro::serialized_field = "bUseSaveSlot"]
use_save_slot: BoolProperty, use_save_slot: BoolProperty,
} }
#[binrw]
#[derive(Debug)]
pub struct PersistentObject {
pub size_in_bytes: u32,
#[br(pad_after = 4)]
pub profile: Persistent,
}

View file

@ -1,7 +1,12 @@
use crate::{ use crate::{
bool_property::BoolProperty, da_load_option::DALoadOptionStruct, datetime::DateTimeStruct, property::{
float_property::FloatProperty, int_property::IntProperty, bool_property::BoolProperty, float_property::FloatProperty, int_property::IntProperty,
name_property::NameProperty, save_slot_info::SaveSlotInfoStruct, str_property::StrProperty, name_property::NameProperty, str_property::StrProperty,
},
structure::{
da_load_option::DALoadOptionStruct, datetime::DateTimeStruct,
save_slot_info::SaveSlotInfoStruct,
},
}; };
#[paramacro::serialized_struct("Transform")] #[paramacro::serialized_struct("Transform")]

View file

@ -1,116 +0,0 @@
use crate::Property;
use crate::common::{read_string_with_length, write_string_with_length};
use binrw::{BinRead, BinResult, BinWrite, binrw};
use std::fmt::Debug;
#[binrw]
#[derive(Debug)]
pub struct GenericProperty {
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
pub property_name: String,
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
#[br(if(property_name != "None"))]
pub type_name: String,
#[br(if(property_name != "None"))]
#[br(args { magic: &type_name, name: &property_name})]
pub key: Option<Box<Property>>,
}
#[binrw]
#[derive(Debug)]
pub struct StructFieldPrelude {
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
pub property_name: String,
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
pub type_name: String,
}
#[binrw]
#[derive(Debug)]
pub struct StructPrelude {
pub size_in_bytes: u32,
#[brw(pad_before = 4)]
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
#[brw(pad_after = 17)]
pub struct_name: String,
}
#[binrw::parser(reader, endian)]
pub(crate) fn read_struct_field<T: BinRead<Args<'static> = ()> + Debug>(
name: &str,
) -> BinResult<T> {
let prelude = StructFieldPrelude::read_le(reader)?;
if prelude.property_name != name {
panic!(
"Property name doesn't match! Is supposed to be {} but is actually {}",
name, prelude.property_name
);
}
// TODO: type check with type_name()
if prelude.type_name == "StructProperty" {
StructPrelude::read_le(reader)?;
}
let val = T::read_options(reader, endian, ())?;
Ok(val)
}
pub(crate) trait PropertyBase {
fn type_name() -> &'static str;
fn size_in_bytes(&self) -> u32;
// these are only relevant for structs:
// FIXME: this isn't great'
fn struct_name() -> Option<&'static str> {
None
}
}
#[binrw::writer(writer, endian)]
pub(crate) fn write_struct_field<T: PropertyBase + BinWrite<Args<'static> = ()> + Debug>(
structure: &T,
name: &str,
) -> BinResult<()> {
let prelude = StructFieldPrelude {
property_name: name.to_string(),
type_name: T::type_name().to_string(),
};
prelude.write_le(writer)?;
if T::type_name() == "StructProperty" {
let struct_prelude = StructPrelude {
size_in_bytes: T::size_in_bytes(structure),
struct_name: T::struct_name().unwrap().to_string(),
};
struct_prelude.write_le(writer)?;
}
structure.write_options(writer, endian, ())?;
Ok(())
}
pub(crate) fn calc_struct_field_prelude_byte_size(
type_name: &str,
field_name: &str,
struct_name: Option<&str>,
) -> u32 {
let mut base_size = crate::common::size_of_string_with_length(field_name);
// This is an easy way to detect properties that are actually structs
if struct_name.is_some() {
base_size += crate::common::size_of_string_with_length("StructProperty")
+ crate::common::size_of_string_with_length(struct_name.unwrap())
+ 4
+ 17
+ 4; // see struct prelude
} else {
base_size += crate::common::size_of_string_with_length(type_name);
}
base_size
}

View file

@ -1,10 +1,13 @@
use crate::da_assemble_id_data::DAAssembleIdDataStruct;
use crate::da_customize_asset_id::DACustomizeAssetIdDataStruct;
use crate::da_trigger_data::DATriggerDataStruct;
use crate::da_tuning_data::DATuningDataStruct;
use crate::str_property::StrProperty;
use std::fmt::Debug; use std::fmt::Debug;
use crate::property::str_property::StrProperty;
use super::{
da_assemble_id_data::DAAssembleIdDataStruct,
da_customize_asset_id::DACustomizeAssetIdDataStruct, da_trigger_data::DATriggerDataStruct,
da_tuning_data::DATuningDataStruct,
};
#[paramacro::serialized_struct("DABuildData")] #[paramacro::serialized_struct("DABuildData")]
#[derive(Debug)] #[derive(Debug)]
pub struct DABuildDataStruct { pub struct DABuildDataStruct {

View file

@ -1,4 +1,4 @@
use crate::{da_machine_coloring_data::DAMachineColoringDataStruct, guid::Guid}; use super::{da_machine_coloring_data::DAMachineColoringDataStruct, guid::Guid};
#[paramacro::serialized_struct("DAAssembleIdData")] #[paramacro::serialized_struct("DAAssembleIdData")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,5 +1,7 @@
use crate::{ use crate::property::bool_property::BoolProperty;
bool_property::BoolProperty, da_humanoid_coloring_data::DAHumanoidColoringDataStruct,
use super::{
da_humanoid_coloring_data::DAHumanoidColoringDataStruct,
da_humanoid_figure_data::DAHumanoidFigureData, primary_asset_id::PrimaryAssetIdStruct, da_humanoid_figure_data::DAHumanoidFigureData, primary_asset_id::PrimaryAssetIdStruct,
}; };

View file

@ -1,4 +1,4 @@
use crate::linear_color::LinearColorStruct; use super::linear_color::LinearColorStruct;
#[paramacro::serialized_struct("DAHumanoidColoringData")] #[paramacro::serialized_struct("DAHumanoidColoringData")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,4 +1,4 @@
use crate::float_property::FloatProperty; use crate::property::float_property::FloatProperty;
#[paramacro::serialized_struct("DAHumanoidFigureData")] #[paramacro::serialized_struct("DAHumanoidFigureData")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,4 +1,4 @@
use crate::int_property::IntProperty; use crate::property::int_property::IntProperty;
#[paramacro::serialized_struct("DALoadOption")] #[paramacro::serialized_struct("DALoadOption")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,4 +1,4 @@
use crate::da_module_color::DAModuleColorStruct; use super::da_module_color::DAModuleColorStruct;
#[paramacro::serialized_struct("DAMachineColoringData")] #[paramacro::serialized_struct("DAMachineColoringData")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,4 +1,4 @@
use crate::linear_color::LinearColorStruct; use super::linear_color::LinearColorStruct;
#[paramacro::serialized_struct("DAModuleColor")] #[paramacro::serialized_struct("DAModuleColor")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,4 +1,4 @@
use crate::int_property::IntProperty; use crate::property::int_property::IntProperty;
#[paramacro::serialized_struct("DAModuleItemData")] #[paramacro::serialized_struct("DAModuleItemData")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,4 +1,4 @@
use crate::enum_property::EnumProperty; use crate::property::enum_property::EnumProperty;
#[paramacro::serialized_struct("DATriggerData")] #[paramacro::serialized_struct("DATriggerData")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,4 +1,4 @@
use crate::map_property::MapProperty; use crate::property::map_property::MapProperty;
#[paramacro::serialized_struct("DATuningData")] #[paramacro::serialized_struct("DATuningData")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,4 +1,4 @@
use crate::int_property::IntProperty; use crate::property::int_property::IntProperty;
#[paramacro::serialized_struct("DATuningPointData")] #[paramacro::serialized_struct("DATuningPointData")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,6 +1,6 @@
use binrw::binrw; use binrw::binrw;
use crate::structs::PropertyBase; use crate::property::PropertyBase;
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,6 +1,8 @@
use binrw::binrw; use binrw::binrw;
use std::fmt; use std::fmt;
use crate::property::PropertyBase;
// See https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/Misc/FGuid // See https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/Misc/FGuid
#[binrw] #[binrw]
pub struct Guid { pub struct Guid {
@ -10,7 +12,7 @@ pub struct Guid {
pub d: u32, pub d: u32,
} }
impl crate::structs::PropertyBase for Guid { impl PropertyBase for Guid {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"StructProperty" "StructProperty"
} }

View file

@ -1,5 +1,7 @@
use binrw::binrw; use binrw::binrw;
use crate::property::PropertyBase;
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]
pub struct LinearColorStruct { pub struct LinearColorStruct {
@ -9,7 +11,7 @@ pub struct LinearColorStruct {
pub a: f32, pub a: f32,
} }
impl crate::structs::PropertyBase for LinearColorStruct { impl PropertyBase for LinearColorStruct {
fn type_name() -> &'static str { fn type_name() -> &'static str {
"StructProperty" "StructProperty"
} }

View file

@ -1,27 +1,53 @@
use crate::build_data::DABuildDataStruct; use binrw::{BinRead, BinResult, BinWrite, binrw};
use crate::common::{read_string_with_length, write_string_with_length}; use build_data::DABuildDataStruct;
use crate::da_assemble_id_data::DAAssembleIdDataStruct; use da_assemble_id_data::DAAssembleIdDataStruct;
use crate::da_customize_asset_id::DACustomizeAssetIdDataStruct; use da_customize_asset_id::DACustomizeAssetIdDataStruct;
use crate::da_humanoid_coloring_data::DAHumanoidColoringDataStruct; use da_humanoid_coloring_data::DAHumanoidColoringDataStruct;
use crate::da_humanoid_figure_data::DAHumanoidFigureData; use da_humanoid_figure_data::DAHumanoidFigureData;
use crate::da_load_option::DALoadOptionStruct; use da_load_option::DALoadOptionStruct;
use crate::da_machine_coloring_data::DAMachineColoringDataStruct; use da_machine_coloring_data::DAMachineColoringDataStruct;
use crate::da_module_color::DAModuleColorStruct; use da_module_color::DAModuleColorStruct;
use crate::da_module_item_data::DAModuleItemDataStruct; use da_module_item_data::DAModuleItemDataStruct;
use crate::da_trigger_data::DATriggerDataStruct; use da_trigger_data::DATriggerDataStruct;
use crate::da_tuning_data::DATuningDataStruct; use da_tuning_data::DATuningDataStruct;
use crate::da_tuning_point_data::DATuningPointData; use da_tuning_point_data::DATuningPointData;
use crate::datetime::DateTimeStruct; use datetime::DateTimeStruct;
use crate::guid::Guid; use guid::Guid;
use crate::linear_color::LinearColorStruct; use linear_color::LinearColorStruct;
use crate::primary_asset_id::PrimaryAssetIdStruct; use primary_asset_id::PrimaryAssetIdStruct;
use crate::primary_asset_type::PrimaryAssetTypeStruct; use primary_asset_type::PrimaryAssetTypeStruct;
use crate::quat::QuatStruct; use quat::QuatStruct;
use crate::save_slot_info::SaveSlotInfoStruct; use save_slot_info::SaveSlotInfoStruct;
use crate::structs::PropertyBase; use std::fmt::Debug;
use crate::transform::TransformStruct; use transform::TransformStruct;
use crate::vector::VectorStruct; use vector::VectorStruct;
use binrw::binrw;
use crate::{
common::{read_string_with_length, write_string_with_length},
property::PropertyBase,
};
pub mod build_data;
pub mod da_assemble_id_data;
pub mod da_customize_asset_id;
pub mod da_humanoid_coloring_data;
pub mod da_humanoid_figure_data;
pub mod da_load_option;
pub mod da_machine_coloring_data;
pub mod da_module_color;
pub mod da_module_item_data;
pub mod da_trigger_data;
pub mod da_tuning_data;
pub mod da_tuning_point_data;
pub mod datetime;
pub mod guid;
pub mod linear_color;
pub mod primary_asset_id;
pub mod primary_asset_type;
pub mod quat;
pub mod save_slot_info;
pub mod transform;
pub mod vector;
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]
@ -114,13 +140,84 @@ pub(crate) fn calc_size_in_bytes(r#struct: &Struct) -> u32 {
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]
pub struct StructProperty { pub struct StructFieldPrelude {
pub unk: u32, #[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
pub property_name: String,
#[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)]
pub type_name: String,
}
#[binrw]
#[derive(Debug)]
pub struct StructPrelude {
pub size_in_bytes: u32,
#[brw(pad_before = 4)] #[brw(pad_before = 4)]
#[br(parse_with = read_string_with_length)] #[br(parse_with = read_string_with_length)]
#[bw(write_with = write_string_with_length)] #[bw(write_with = write_string_with_length)]
#[brw(pad_after = 17)]
pub struct_name: String, pub struct_name: String,
#[br(args { magic: &struct_name })] }
#[brw(pad_before = 17)]
pub r#struct: Struct, #[binrw::parser(reader, endian)]
pub(crate) fn read_struct_field<T: BinRead<Args<'static> = ()> + Debug>(
name: &str,
) -> BinResult<T> {
let prelude = StructFieldPrelude::read_le(reader)?;
if prelude.property_name != name {
panic!(
"Property name doesn't match! Is supposed to be {} but is actually {}",
name, prelude.property_name
);
}
// TODO: type check with type_name()
if prelude.type_name == "StructProperty" {
StructPrelude::read_le(reader)?;
}
let val = T::read_options(reader, endian, ())?;
Ok(val)
}
#[binrw::writer(writer, endian)]
pub(crate) fn write_struct_field<T: PropertyBase + BinWrite<Args<'static> = ()> + Debug>(
structure: &T,
name: &str,
) -> BinResult<()> {
let prelude = StructFieldPrelude {
property_name: name.to_string(),
type_name: T::type_name().to_string(),
};
prelude.write_le(writer)?;
if T::type_name() == "StructProperty" {
let struct_prelude = StructPrelude {
size_in_bytes: T::size_in_bytes(structure),
struct_name: T::struct_name().unwrap().to_string(),
};
struct_prelude.write_le(writer)?;
}
structure.write_options(writer, endian, ())?;
Ok(())
}
pub(crate) fn calc_struct_field_prelude_byte_size(
type_name: &str,
field_name: &str,
struct_name: Option<&str>,
) -> u32 {
let mut base_size = crate::common::size_of_string_with_length(field_name);
// This is an easy way to detect properties that are actually structs
if struct_name.is_some() {
base_size += crate::common::size_of_string_with_length("StructProperty")
+ crate::common::size_of_string_with_length(struct_name.unwrap())
+ 4
+ 17
+ 4; // see struct prelude
} else {
base_size += crate::common::size_of_string_with_length(type_name);
}
base_size
} }

View file

@ -1,4 +1,6 @@
use crate::{name_property::NameProperty, primary_asset_type::PrimaryAssetTypeStruct}; use crate::property::name_property::NameProperty;
use super::primary_asset_type::PrimaryAssetTypeStruct;
#[paramacro::serialized_struct("PrimaryAssetId")] #[paramacro::serialized_struct("PrimaryAssetId")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,4 +1,4 @@
use crate::name_property::NameProperty; use crate::property::name_property::NameProperty;
#[paramacro::serialized_struct("PrimaryAssetType")] #[paramacro::serialized_struct("PrimaryAssetType")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,6 +1,6 @@
use binrw::binrw; use binrw::binrw;
use crate::structs::PropertyBase; use crate::property::PropertyBase;
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,8 +1,9 @@
use crate::{ use crate::property::{
array_property::ArrayProperty, datetime::DateTimeStruct, name_property::NameProperty, array_property::ArrayProperty, name_property::NameProperty, str_property::StrProperty,
str_property::StrProperty,
}; };
use super::datetime::DateTimeStruct;
#[paramacro::serialized_struct("SaveSlotInfo")] #[paramacro::serialized_struct("SaveSlotInfo")]
#[derive(Debug)] #[derive(Debug)]
pub struct SaveSlotInfoStruct { pub struct SaveSlotInfoStruct {

View file

@ -1,4 +1,4 @@
use crate::{quat::QuatStruct, vector::VectorStruct}; use super::{quat::QuatStruct, vector::VectorStruct};
#[paramacro::serialized_struct("Transform")] #[paramacro::serialized_struct("Transform")]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,6 +1,6 @@
use binrw::binrw; use binrw::binrw;
use crate::structs::PropertyBase; use crate::property::PropertyBase;
#[binrw] #[binrw]
#[derive(Debug)] #[derive(Debug)]

View file

@ -1,5 +1,6 @@
use binrw::{BinRead, BinWrite}; use binrw::{BinRead, BinWrite};
use ireko::{GenericTaggedObject, TaggedSerialization}; use ireko::TaggedSerialization;
use ireko::save_object::generic::GenericTaggedObject;
use std::fs::read; use std::fs::read;
use std::io::Cursor; use std::io::Cursor;
use std::path::PathBuf; use std::path::PathBuf;