Various set and map fixes, add structured object support
This commit is contained in:
parent
0b461c5b86
commit
d622799cfa
8 changed files with 245 additions and 48 deletions
|
@ -1,5 +1,5 @@
|
||||||
use binrw::BinRead;
|
use binrw::BinRead;
|
||||||
use ireko::CompressedSaveFile;
|
use ireko::{CompressedSaveFile, GenericTaggedObject};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
@ -8,8 +8,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
let mut data = Cursor::new(std::fs::read(&args[1])?);
|
let mut data = Cursor::new(std::fs::read(&args[1])?);
|
||||||
|
|
||||||
let compressed = CompressedSaveFile::read_le(&mut data)?;
|
let compressed = CompressedSaveFile::<GenericTaggedObject>::read_le(&mut data)?;
|
||||||
println!("{:#?}", compressed);
|
println!("{:#?}", compressed);
|
||||||
|
|
||||||
|
// useful for creating new structed objs
|
||||||
|
/*for object in &compressed.value.objs {
|
||||||
|
println!("NEW OBJ");
|
||||||
|
for entry in &object.entries {
|
||||||
|
println!("#[paramacro::serialized_field = {:#?}]", entry.name);
|
||||||
|
println!("unknown: {}", entry.type_name);
|
||||||
|
println!("");
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
63
src/lib.rs
63
src/lib.rs
|
@ -19,13 +19,16 @@ pub mod float_property;
|
||||||
mod guid;
|
mod guid;
|
||||||
pub mod int_property;
|
pub mod int_property;
|
||||||
mod linear_color;
|
mod linear_color;
|
||||||
|
mod localprofile;
|
||||||
pub mod map_property;
|
pub mod map_property;
|
||||||
mod name_property;
|
mod name_property;
|
||||||
|
mod persistent;
|
||||||
mod primary_asset_id;
|
mod primary_asset_id;
|
||||||
mod primary_asset_type;
|
mod primary_asset_type;
|
||||||
mod quat;
|
mod quat;
|
||||||
mod save_slot_info;
|
mod save_slot_info;
|
||||||
pub mod set_property;
|
pub mod set_property;
|
||||||
|
mod slot;
|
||||||
pub mod str_property;
|
pub mod str_property;
|
||||||
pub mod struct_property;
|
pub mod struct_property;
|
||||||
mod structs;
|
mod structs;
|
||||||
|
@ -71,10 +74,7 @@ pub enum Property {
|
||||||
#[br(pre_assert("MapProperty" == magic))]
|
#[br(pre_assert("MapProperty" == magic))]
|
||||||
Map(MapProperty),
|
Map(MapProperty),
|
||||||
#[br(pre_assert("SetProperty" == magic))]
|
#[br(pre_assert("SetProperty" == magic))]
|
||||||
Set {
|
Set(SetProperty),
|
||||||
#[br(args(name))]
|
|
||||||
value: SetProperty,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
|
@ -126,34 +126,24 @@ fn custom_tagged_object_writer(entries: &Vec<Entry>) -> BinResult<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw::parser(reader, endian)]
|
|
||||||
fn custom_parser(size_in_bytes: u32) -> BinResult<Vec<TaggedObject>> {
|
|
||||||
let mut result = Vec::<TaggedObject>::new();
|
|
||||||
|
|
||||||
let mut current = reader.stream_position()?;
|
|
||||||
let end = current + size_in_bytes as u64;
|
|
||||||
|
|
||||||
while current < end {
|
|
||||||
let obj = TaggedObject::read_options(reader, endian, ())?;
|
|
||||||
if obj.size_in_bytes == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result.push(obj);
|
|
||||||
current = reader.stream_position()?;
|
|
||||||
}
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TaggedObject {
|
pub struct GenericTaggedObject {
|
||||||
pub size_in_bytes: u32,
|
pub size_in_bytes: u32,
|
||||||
#[br(parse_with = custom_tagged_object_parser, args(size_in_bytes))]
|
#[br(parse_with = custom_tagged_object_parser, args(size_in_bytes))]
|
||||||
#[bw(write_with = custom_tagged_object_writer)]
|
#[bw(write_with = custom_tagged_object_writer)]
|
||||||
pub entries: Vec<Entry>,
|
pub entries: Vec<Entry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaggedObject {
|
#[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> {
|
pub fn entry(&self, key: &str) -> Option<&Entry> {
|
||||||
let entries: Vec<&Entry> = self.entries.iter().filter(|e| e.name == key).collect();
|
let entries: Vec<&Entry> = self.entries.iter().filter(|e| e.name == key).collect();
|
||||||
entries.first().copied()
|
entries.first().copied()
|
||||||
|
@ -162,10 +152,13 @@ impl TaggedObject {
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TaggedSerialization {
|
pub struct TaggedSerialization<T>
|
||||||
|
where
|
||||||
|
for<'a> T: BinRead<Args<'a> = ()> + 'a,
|
||||||
|
for<'a> T: BinWrite<Args<'a> = ()> + 'a,
|
||||||
|
{
|
||||||
pub size_in_bytes: u32,
|
pub size_in_bytes: u32,
|
||||||
#[br(parse_with = custom_parser, args(size_in_bytes))]
|
pub objs: T,
|
||||||
pub objs: Vec<TaggedObject>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw::parser(reader, endian)]
|
#[binrw::parser(reader, endian)]
|
||||||
|
@ -183,14 +176,18 @@ fn read_compressed_data(compressed_size: u64, uncompressed_size: u64) -> BinResu
|
||||||
|
|
||||||
// TODO: there's no point in using a parser, we should just use map()
|
// TODO: there's no point in using a parser, we should just use map()
|
||||||
#[binrw::parser(reader, endian)]
|
#[binrw::parser(reader, endian)]
|
||||||
fn read_tagged_data(data_blocks: &Vec<CompressedBlock>) -> BinResult<TaggedSerialization> {
|
fn read_tagged_data<T>(data_blocks: &Vec<CompressedBlock>) -> BinResult<TaggedSerialization<T>>
|
||||||
|
where
|
||||||
|
for<'a> T: BinRead<Args<'a> = ()> + 'a,
|
||||||
|
for<'a> T: BinWrite<Args<'a> = ()> + 'a,
|
||||||
|
{
|
||||||
let data_vecs: Vec<Vec<u8>> = data_blocks.iter().map(|x| x.data.clone()).collect();
|
let data_vecs: Vec<Vec<u8>> = data_blocks.iter().map(|x| x.data.clone()).collect();
|
||||||
let combined_data = data_vecs.concat();
|
let combined_data = data_vecs.concat();
|
||||||
write("output.bin", &combined_data);
|
write("output.bin", &combined_data);
|
||||||
|
|
||||||
let mut cursor = Cursor::new(&combined_data);
|
let mut cursor = Cursor::new(&combined_data);
|
||||||
|
|
||||||
TaggedSerialization::read_le(&mut cursor)
|
TaggedSerialization::<T>::read_le(&mut cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
|
@ -210,11 +207,15 @@ pub struct CompressedBlock {
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CompressedSaveFile {
|
pub struct CompressedSaveFile<T>
|
||||||
|
where
|
||||||
|
for<'a> T: BinRead<Args<'a> = ()> + 'a,
|
||||||
|
for<'a> T: BinWrite<Args<'a> = ()> + 'a,
|
||||||
|
{
|
||||||
#[br(parse_with = until_eof)]
|
#[br(parse_with = until_eof)]
|
||||||
#[br(temp)]
|
#[br(temp)]
|
||||||
#[bw(ignore)]
|
#[bw(ignore)]
|
||||||
pub data: Vec<CompressedBlock>,
|
pub data: Vec<CompressedBlock>,
|
||||||
#[br(parse_with = read_tagged_data, args(&data))]
|
#[br(parse_with = read_tagged_data, args(&data))]
|
||||||
pub value: TaggedSerialization,
|
pub value: TaggedSerialization<T>,
|
||||||
}
|
}
|
||||||
|
|
23
src/localprofile.rs
Normal file
23
src/localprofile.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use crate::{
|
||||||
|
bool_property::BoolProperty, int_property::IntProperty, map_property::MapProperty,
|
||||||
|
str_property::StrProperty,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[paramacro::serialized_struct("Transform")]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LocalProfile {
|
||||||
|
#[paramacro::serialized_field = "SavedDataVersion"]
|
||||||
|
version: IntProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "bDemoVersion"]
|
||||||
|
demo: BoolProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "RegisteredNameList"]
|
||||||
|
name_list: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "SaveGameName"]
|
||||||
|
name: StrProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "bUseSaveSlot"]
|
||||||
|
use_save_slot: BoolProperty,
|
||||||
|
}
|
|
@ -13,6 +13,9 @@ fn cc() -> BinResult<Vec<GenericProperty>> {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Ok(str) = GenericProperty::read_options(reader, endian, ()) {
|
if let Ok(str) = GenericProperty::read_options(reader, endian, ()) {
|
||||||
|
if str.property_name == "None" {
|
||||||
|
break;
|
||||||
|
}
|
||||||
result.push(str);
|
result.push(str);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -47,6 +50,10 @@ pub struct StructMaybeKey {
|
||||||
#[br(args { magic: &struct_name })]
|
#[br(args { magic: &struct_name })]
|
||||||
#[brw(pad_before = 17)]
|
#[brw(pad_before = 17)]
|
||||||
pub r#struct: Struct,
|
pub r#struct: Struct,
|
||||||
|
|
||||||
|
#[br(parse_with = cc)]
|
||||||
|
#[br(dbg)]
|
||||||
|
extra_fields: Vec<GenericProperty>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
|
|
101
src/persistent.rs
Normal file
101
src/persistent.rs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
use crate::{
|
||||||
|
array_property::ArrayProperty, bool_property::BoolProperty, build_data::DABuildDataStruct,
|
||||||
|
da_load_option::DALoadOptionStruct, da_tuning_point_data::DATuningPointData,
|
||||||
|
datetime::DateTimeStruct, float_property::FloatProperty, int_property::IntProperty,
|
||||||
|
map_property::MapProperty, name_property::NameProperty, save_slot_info::SaveSlotInfoStruct,
|
||||||
|
set_property::SetProperty, str_property::StrProperty, transform::TransformStruct,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[paramacro::serialized_struct("Transform")]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Persistent {
|
||||||
|
#[paramacro::serialized_field = "SavedDataVersion"]
|
||||||
|
version: IntProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "bDemoVersion"]
|
||||||
|
demo_version: BoolProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "Money"]
|
||||||
|
money: IntProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "ObtainedItems"]
|
||||||
|
obtained_items: SetProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "ItemSlots"]
|
||||||
|
item_slots: ArrayProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "CurrentItemSlotNum"]
|
||||||
|
current_item_slot: IntProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "NormalItemInventory"]
|
||||||
|
normal_item_inventory: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "ModuleInventory"]
|
||||||
|
module_inventory: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "PartsInventory"]
|
||||||
|
parts_inventory: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "CurrentBuildData"]
|
||||||
|
current_build_data: DABuildDataStruct,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "SavedBuildData"]
|
||||||
|
saved_build_data: ArrayProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "Palettes"]
|
||||||
|
palettes: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "TuningPointData"]
|
||||||
|
tuning_point_data: DATuningPointData,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "EventParams"]
|
||||||
|
event_params: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "ReachedDistricts"]
|
||||||
|
reached_districts: SetProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "ShopBoughtCount"]
|
||||||
|
shop_bought_count: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "AcquiredItemBoxIds"]
|
||||||
|
acquired_item_box_ids: SetProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "OpenedStrongBoxIds"]
|
||||||
|
opened_strong_box_ids: SetProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "RegressionPlayerStartTag"]
|
||||||
|
regression_player_start_tag: NameProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "RegressionLevelName"]
|
||||||
|
regression_level_name: NameProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "bStartFromRegressionPoint"]
|
||||||
|
start_from_regression_point: BoolProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "ReleasedCheckpoints"]
|
||||||
|
released_checkpoints: SetProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "SuspendTransform"]
|
||||||
|
suspend_transform: TransformStruct,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "CharacterPersistentDataList"]
|
||||||
|
character_persistent_data_list: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "BossStates"]
|
||||||
|
boss_states: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "NPCStates"]
|
||||||
|
npc_states: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "ReadDialogues"]
|
||||||
|
read_dialogues: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "ReadDialogueChains"]
|
||||||
|
read_dialogue_chains: MapProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "SaveGameName"]
|
||||||
|
save_game_name: StrProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "bUseSaveSlot"]
|
||||||
|
use_save_slot: BoolProperty,
|
||||||
|
}
|
|
@ -10,6 +10,9 @@ fn cc() -> BinResult<Vec<GenericProperty>> {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Ok(str) = GenericProperty::read_options(reader, endian, ()) {
|
if let Ok(str) = GenericProperty::read_options(reader, endian, ()) {
|
||||||
|
if str.property_name == "None" {
|
||||||
|
break;
|
||||||
|
}
|
||||||
result.push(str);
|
result.push(str);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -20,32 +23,36 @@ fn cc() -> BinResult<Vec<GenericProperty>> {
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[br(import { magic: &str, name: &str })]
|
#[br(import { magic: &str, key_type: &KeyType })]
|
||||||
pub enum SetValue {
|
pub enum SetValue {
|
||||||
// NOTE: the name checking is just a temporary workaround
|
#[br(pre_assert("StructProperty" == magic && *key_type != KeyType::Unknown && *key_type != KeyType::EnumAgain))]
|
||||||
#[br(pre_assert("StructProperty" == magic && name != "OpenedStrongBoxIds" && name != "AcquiredItemBoxIds"))]
|
|
||||||
Struct {
|
Struct {
|
||||||
#[br(parse_with = cc)]
|
#[br(parse_with = cc)]
|
||||||
fields: Vec<GenericProperty>,
|
fields: Vec<GenericProperty>,
|
||||||
},
|
},
|
||||||
#[br(pre_assert("StringProperty" == magic || "NameProperty" == magic))]
|
#[br(pre_assert("StringProperty" == magic || "NameProperty" == magic))]
|
||||||
String(MapSubStrProperty),
|
String(MapSubStrProperty),
|
||||||
#[br(pre_assert("StructProperty" == magic && name == "AcquiredItemBoxIds"))]
|
#[br(pre_assert("StructProperty" == magic && *key_type == KeyType::Unknown))]
|
||||||
Unknown { unk: [u8; 736] },
|
Unknown { unk: [u8; 736] },
|
||||||
#[br(pre_assert("StructProperty" == magic && name == "OpenedStrongBoxIds"))]
|
#[br(pre_assert("StructProperty" == magic && *key_type == KeyType::EnumAgain))]
|
||||||
Unknown2 { unk: [u8; 64] },
|
Unknown2 { unk: [u8; 64] },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[br(import(value_type: &str, key_type: &str))]
|
#[br(import(value_type: &str, key_type: &KeyType))]
|
||||||
pub struct SetEntry {
|
pub struct SetEntry {
|
||||||
#[br(args { magic: value_type, name: key_type })]
|
#[br(args { magic: value_type, key_type })]
|
||||||
|
#[br(dbg)]
|
||||||
pub key: SetValue,
|
pub key: SetValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw::parser(reader, endian)]
|
#[binrw::parser(reader, endian)]
|
||||||
fn custom_parser(size_in_bytes: u32, value_type: &str, key_type: &str) -> BinResult<Vec<SetEntry>> {
|
fn custom_parser(
|
||||||
|
size_in_bytes: u32,
|
||||||
|
value_type: &str,
|
||||||
|
key_type: &KeyType,
|
||||||
|
) -> BinResult<Vec<SetEntry>> {
|
||||||
let mut result = Vec::<SetEntry>::new();
|
let mut result = Vec::<SetEntry>::new();
|
||||||
|
|
||||||
let mut current = reader.stream_position()?;
|
let mut current = reader.stream_position()?;
|
||||||
|
@ -64,22 +71,34 @@ fn custom_parser(size_in_bytes: u32, value_type: &str, key_type: &str) -> BinRes
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[br(import(name: &str))]
|
|
||||||
pub struct SetProperty {
|
pub struct SetProperty {
|
||||||
pub size_in_bytes: u32,
|
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)]
|
||||||
|
#[br(dbg)]
|
||||||
pub key_name: String,
|
pub key_name: String,
|
||||||
|
|
||||||
#[brw(pad_before = 5)]
|
#[brw(pad_before = 5)]
|
||||||
|
#[br(dbg)]
|
||||||
pub key_type: KeyType,
|
pub key_type: KeyType,
|
||||||
|
|
||||||
#[br(parse_with = custom_parser, args(size_in_bytes, &key_name, name))]
|
#[br(parse_with = custom_parser, args(size_in_bytes, &key_name, &key_type))]
|
||||||
pub entries: Vec<SetEntry>,
|
pub entries: Vec<SetEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::structs::PropertyBase for SetProperty {
|
||||||
|
fn type_name() -> &'static str {
|
||||||
|
"SetProperty"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_in_bytes(&self) -> u32 {
|
||||||
|
// todo
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
36
src/slot.rs
Normal file
36
src/slot.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use crate::{
|
||||||
|
bool_property::BoolProperty, da_load_option::DALoadOptionStruct, datetime::DateTimeStruct,
|
||||||
|
float_property::FloatProperty, int_property::IntProperty, map_property::MapProperty,
|
||||||
|
name_property::NameProperty, save_slot_info::SaveSlotInfoStruct, str_property::StrProperty,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[paramacro::serialized_struct("Transform")]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Slot {
|
||||||
|
#[paramacro::serialized_field = "SavedDataVersion"]
|
||||||
|
version: IntProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "bDemoVersion"]
|
||||||
|
demo: BoolProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "CreatedTimeStamp"]
|
||||||
|
created_timestamp: DateTimeStruct,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "PlayTime"]
|
||||||
|
playtime: FloatProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "RegisteredName"]
|
||||||
|
name: StrProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "LoadOption"]
|
||||||
|
load_option: DALoadOptionStruct,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "DistrictTag"]
|
||||||
|
district_tag: NameProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "CycleCount"]
|
||||||
|
cycle_count: IntProperty,
|
||||||
|
|
||||||
|
#[paramacro::serialized_field = "SlotInfo"]
|
||||||
|
slot_info: SaveSlotInfoStruct,
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
use binrw::{BinRead, BinWrite};
|
use binrw::{BinRead, BinWrite};
|
||||||
use ireko::TaggedSerialization;
|
use ireko::{GenericTaggedObject, TaggedSerialization};
|
||||||
use std::fs::read;
|
use std::fs::read;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -13,8 +13,8 @@ fn roundtrip_localprofile() {
|
||||||
let mut data = read(d).unwrap();
|
let mut data = read(d).unwrap();
|
||||||
let mut cursor = Cursor::new(&mut data);
|
let mut cursor = Cursor::new(&mut data);
|
||||||
|
|
||||||
let local_profile = TaggedSerialization::read_le(&mut cursor).unwrap();
|
let local_profile = TaggedSerialization::<GenericTaggedObject>::read_le(&mut cursor).unwrap();
|
||||||
let tagged_object = &local_profile.objs[0];
|
let tagged_object = &local_profile.objs;
|
||||||
assert_eq!(tagged_object.size_in_bytes, 339);
|
assert_eq!(tagged_object.size_in_bytes, 339);
|
||||||
|
|
||||||
tagged_object.entry("SavedDataVersion").unwrap();
|
tagged_object.entry("SavedDataVersion").unwrap();
|
||||||
|
@ -41,8 +41,8 @@ fn roundtrip_slot() {
|
||||||
let mut data = read(d).unwrap();
|
let mut data = read(d).unwrap();
|
||||||
let mut cursor = Cursor::new(&mut data);
|
let mut cursor = Cursor::new(&mut data);
|
||||||
|
|
||||||
let local_profile = TaggedSerialization::read_le(&mut cursor).unwrap();
|
let local_profile = TaggedSerialization::<GenericTaggedObject>::read_le(&mut cursor).unwrap();
|
||||||
let tagged_object = &local_profile.objs[0];
|
let tagged_object = &local_profile.objs;
|
||||||
assert_eq!(tagged_object.size_in_bytes, 900);
|
assert_eq!(tagged_object.size_in_bytes, 900);
|
||||||
|
|
||||||
tagged_object.entry("PlayTime").unwrap();
|
tagged_object.entry("PlayTime").unwrap();
|
||||||
|
|
Loading…
Add table
Reference in a new issue