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());
let field_tokens = field.to_token_stream();
let new_field_token_stream = quote! {
#[br(parse_with = crate::structs::read_struct_field, args(#our_custom_name))]
#[bw(write_with = crate::structs::write_struct_field, args(#our_custom_name))]
#[br(parse_with = crate::structure::read_struct_field, args(#our_custom_name))]
#[bw(write_with = crate::structure::write_struct_field, args(#our_custom_name))]
#field_tokens
};
let buffer = ::syn::parse::Parser::parse2(
@ -54,8 +54,8 @@ pub fn serialized_struct(_metadata: TokenStream, input: TokenStream)
// Add "None" field
let none_field_stream = quote! {
#[br(temp)]
#[bw(calc = crate::structs::GenericProperty { property_name: "None".to_string(), type_name: "".to_string(), key: None } )]
none_field: crate::structs::GenericProperty
#[bw(calc = crate::property::generic_property::GenericProperty { property_name: "None".to_string(), type_name: "".to_string(), key: None } )]
none_field: crate::property::generic_property::GenericProperty
};
let buffer = ::syn::parse::Parser::parse2(
syn::Field::parse_named,
@ -75,7 +75,7 @@ pub fn serialized_struct(_metadata: TokenStream, input: TokenStream)
#input
#[automatically_derived]
impl crate::structs::PropertyBase for #id {
impl crate::property::PropertyBase for #id {
fn type_name() -> &'static str {
return "StructProperty";
}
@ -85,7 +85,7 @@ pub fn serialized_struct(_metadata: TokenStream, input: TokenStream)
}
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 ireko::{CompressedSaveFile, GenericTaggedObject};
use ireko::CompressedSaveFile;
use ireko::save_object::generic::GenericTaggedObject;
use std::env;
use std::io::Cursor;

View file

@ -1,155 +1,15 @@
pub mod array_property;
pub mod bool_property;
mod build_data;
mod common;
mod da_assemble_id_data;
mod da_customize_asset_id;
mod da_humanoid_coloring_data;
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;
pub mod property;
pub mod save_object;
pub mod structure;
use binrw::helpers::until_eof;
use std::fs::write;
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 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]
#[derive(Debug)]
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 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 {
// TODO: blah, needs to take into account everything before the first item
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 {
"ArrayProperty"
}
@ -83,7 +90,7 @@ fn calc_size_in_bytes(prop: &ArrayProperty) -> u32 {
for entry in &prop.entries {
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) => {
crate::common::size_of_string_with_length(&string_map_key.value)
}
@ -158,7 +165,6 @@ pub struct ArrayProperty {
#[cfg(test)]
mod tests {
use super::*;
use crate::map_property::StringMapKey;
use binrw::{BinRead, BinWrite};
use std::io::Cursor;

View file

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

View file

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

View file

@ -1,5 +1,7 @@
use binrw::binrw;
use super::PropertyBase;
#[binrw]
#[derive(Debug)]
pub struct FloatProperty {
@ -9,7 +11,7 @@ pub struct FloatProperty {
pub value: f32,
}
impl crate::structs::PropertyBase for FloatProperty {
impl PropertyBase for FloatProperty {
fn type_name() -> &'static str {
"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 super::PropertyBase;
#[binrw]
#[derive(Debug)]
pub struct IntProperty {
@ -9,7 +11,7 @@ pub struct IntProperty {
pub value: u32,
}
impl crate::structs::PropertyBase for IntProperty {
impl PropertyBase for IntProperty {
fn type_name() -> &'static str {
"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 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
#[binrw::parser(reader, endian)]
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.struct_name)
+ 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) => {
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.struct_name)
+ 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::SoftObjectProperty(string_map_key) => {
@ -292,7 +293,7 @@ pub struct MapProperty {
pub entries: Vec<MapEntry>,
}
impl crate::structs::PropertyBase for MapProperty {
impl PropertyBase for MapProperty {
fn type_name() -> &'static str {
"MapProperty"
}
@ -310,7 +311,6 @@ impl crate::structs::PropertyBase for MapProperty {
#[cfg(test)]
mod tests {
use super::*;
use crate::map_property::MabSubProperty::{Int, String};
use binrw::{BinRead, BinWrite};
use std::io::Cursor;
@ -333,7 +333,7 @@ mod tests {
let MapKeyProperty::String(key_property) = &decoded.entries.first().unwrap().key else {
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!")
};
assert_eq!(key_property.value, "AR0XJGFWA6HNIQ1AAUJ9UR828");
@ -359,7 +359,7 @@ mod tests {
key: MapKeyProperty::String(StringMapKey {
value: "AR0XJGFWA6HNIQ1AAUJ9UR828".to_string(),
}),
value: String(MapSubStrProperty {
value: MabSubProperty::String(MapSubStrProperty {
value: "NAME 1".to_string(),
}),
}],
@ -403,7 +403,7 @@ mod tests {
let MapKeyProperty::Enum(key_property) = &decoded.entries.first().unwrap().key else {
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!")
};
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 binrw::binrw;
use super::PropertyBase;
#[binrw]
#[derive(Debug)]
pub struct NameProperty {
@ -14,7 +16,7 @@ pub struct NameProperty {
pub value: String,
}
impl crate::structs::PropertyBase for NameProperty {
impl PropertyBase for NameProperty {
fn type_name() -> &'static str {
"NameProperty"
}

View file

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

View file

@ -1,6 +1,8 @@
use crate::common::{read_string_with_length, write_string_with_length};
use binrw::binrw;
use super::PropertyBase;
#[binrw]
#[derive(Debug)]
pub struct StrProperty {
@ -14,7 +16,7 @@ pub struct StrProperty {
pub value: String,
}
impl crate::structs::PropertyBase for StrProperty {
impl PropertyBase for StrProperty {
fn type_name() -> &'static str {
"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,
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::{
array_property::ArrayProperty, bool_property::BoolProperty, build_data::DABuildDataStruct, da_tuning_point_data::DATuningPointData, int_property::IntProperty,
map_property::MapProperty, name_property::NameProperty,
set_property::SetProperty, str_property::StrProperty, transform::TransformStruct,
property::{
array_property::ArrayProperty, bool_property::BoolProperty, int_property::IntProperty,
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")]
@ -97,3 +105,11 @@ pub struct Persistent {
#[paramacro::serialized_field = "bUseSaveSlot"]
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::{
bool_property::BoolProperty, da_load_option::DALoadOptionStruct, datetime::DateTimeStruct,
float_property::FloatProperty, int_property::IntProperty,
name_property::NameProperty, save_slot_info::SaveSlotInfoStruct, str_property::StrProperty,
property::{
bool_property::BoolProperty, float_property::FloatProperty, int_property::IntProperty,
name_property::NameProperty, str_property::StrProperty,
},
structure::{
da_load_option::DALoadOptionStruct, datetime::DateTimeStruct,
save_slot_info::SaveSlotInfoStruct,
},
};
#[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 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")]
#[derive(Debug)]
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")]
#[derive(Debug)]

View file

@ -1,5 +1,7 @@
use crate::{
bool_property::BoolProperty, da_humanoid_coloring_data::DAHumanoidColoringDataStruct,
use crate::property::bool_property::BoolProperty;
use super::{
da_humanoid_coloring_data::DAHumanoidColoringDataStruct,
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")]
#[derive(Debug)]

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,27 +1,53 @@
use crate::build_data::DABuildDataStruct;
use crate::common::{read_string_with_length, write_string_with_length};
use crate::da_assemble_id_data::DAAssembleIdDataStruct;
use crate::da_customize_asset_id::DACustomizeAssetIdDataStruct;
use crate::da_humanoid_coloring_data::DAHumanoidColoringDataStruct;
use crate::da_humanoid_figure_data::DAHumanoidFigureData;
use crate::da_load_option::DALoadOptionStruct;
use crate::da_machine_coloring_data::DAMachineColoringDataStruct;
use crate::da_module_color::DAModuleColorStruct;
use crate::da_module_item_data::DAModuleItemDataStruct;
use crate::da_trigger_data::DATriggerDataStruct;
use crate::da_tuning_data::DATuningDataStruct;
use crate::da_tuning_point_data::DATuningPointData;
use crate::datetime::DateTimeStruct;
use crate::guid::Guid;
use crate::linear_color::LinearColorStruct;
use crate::primary_asset_id::PrimaryAssetIdStruct;
use crate::primary_asset_type::PrimaryAssetTypeStruct;
use crate::quat::QuatStruct;
use crate::save_slot_info::SaveSlotInfoStruct;
use crate::structs::PropertyBase;
use crate::transform::TransformStruct;
use crate::vector::VectorStruct;
use binrw::binrw;
use binrw::{BinRead, BinResult, BinWrite, binrw};
use build_data::DABuildDataStruct;
use da_assemble_id_data::DAAssembleIdDataStruct;
use da_customize_asset_id::DACustomizeAssetIdDataStruct;
use da_humanoid_coloring_data::DAHumanoidColoringDataStruct;
use da_humanoid_figure_data::DAHumanoidFigureData;
use da_load_option::DALoadOptionStruct;
use da_machine_coloring_data::DAMachineColoringDataStruct;
use da_module_color::DAModuleColorStruct;
use da_module_item_data::DAModuleItemDataStruct;
use da_trigger_data::DATriggerDataStruct;
use da_tuning_data::DATuningDataStruct;
use da_tuning_point_data::DATuningPointData;
use datetime::DateTimeStruct;
use guid::Guid;
use linear_color::LinearColorStruct;
use primary_asset_id::PrimaryAssetIdStruct;
use primary_asset_type::PrimaryAssetTypeStruct;
use quat::QuatStruct;
use save_slot_info::SaveSlotInfoStruct;
use std::fmt::Debug;
use transform::TransformStruct;
use vector::VectorStruct;
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]
#[derive(Debug)]
@ -114,13 +140,84 @@ pub(crate) fn calc_size_in_bytes(r#struct: &Struct) -> u32 {
#[binrw]
#[derive(Debug)]
pub struct StructProperty {
pub unk: u32,
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,
#[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")]
#[derive(Debug)]

View file

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

View file

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

View file

@ -1,8 +1,9 @@
use crate::{
array_property::ArrayProperty, datetime::DateTimeStruct, name_property::NameProperty,
str_property::StrProperty,
use crate::property::{
array_property::ArrayProperty, name_property::NameProperty, str_property::StrProperty,
};
use super::datetime::DateTimeStruct;
#[paramacro::serialized_struct("SaveSlotInfo")]
#[derive(Debug)]
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")]
#[derive(Debug)]

View file

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

View file

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