Expose save slot info (like playtime) in GUI
This commit is contained in:
parent
d1e9a8d57a
commit
dc40526c33
5 changed files with 120 additions and 35 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -620,6 +620,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clipboard-win"
|
name = "clipboard-win"
|
||||||
version = "5.4.0"
|
version = "5.4.0"
|
||||||
|
@ -1565,6 +1574,7 @@ name = "ireko"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"binrw",
|
"binrw",
|
||||||
|
"chrono",
|
||||||
"eframe",
|
"eframe",
|
||||||
"flate2",
|
"flate2",
|
||||||
"paramacro",
|
"paramacro",
|
||||||
|
|
|
@ -8,3 +8,4 @@ flate2 = { version = "1.0", features = ["zlib-ng"], default-features = false }
|
||||||
binrw = { version = "0.14", features = ["std"], default-features = false }
|
binrw = { version = "0.14", features = ["std"], default-features = false }
|
||||||
paramacro = { path = "paramacro" }
|
paramacro = { path = "paramacro" }
|
||||||
eframe = { version= "0.31" }
|
eframe = { version= "0.31" }
|
||||||
|
chrono = { version = "0.4", default-features = false }
|
||||||
|
|
115
src/bin/gui.rs
115
src/bin/gui.rs
|
@ -3,7 +3,18 @@ use std::{env, io::Cursor};
|
||||||
use binrw::BinRead;
|
use binrw::BinRead;
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use ireko::{
|
use ireko::{
|
||||||
property::{array_property::ArrayValue, map_property::{MabSubProperty, MapKeyProperty}}, save_object::{generic::Property, LocalProfileObject, PersistentObject}, structure::{DAAssembleIdDataStruct, DABuildDataStruct, DACustomizeAssetIdDataStruct, DAHumanoidColoringDataStruct, DAHumanoidFigureData, DAMachineColoringDataStruct, DAModuleColorStruct, DATriggerDataStruct, DATuningDataStruct, Guid, LinearColorStruct, PrimaryAssetIdStruct, Struct}, CompressedSaveFile
|
CompressedSaveFile,
|
||||||
|
property::{
|
||||||
|
array_property::ArrayValue,
|
||||||
|
map_property::{MabSubProperty, MapKeyProperty},
|
||||||
|
},
|
||||||
|
save_object::{LocalProfileObject, PersistentObject, SlotObject, generic::Property},
|
||||||
|
structure::{
|
||||||
|
DAAssembleIdDataStruct, DABuildDataStruct, DACustomizeAssetIdDataStruct,
|
||||||
|
DAHumanoidColoringDataStruct, DAHumanoidFigureData, DAMachineColoringDataStruct,
|
||||||
|
DAModuleColorStruct, DATriggerDataStruct, DATuningDataStruct, Guid, LinearColorStruct,
|
||||||
|
PrimaryAssetIdStruct, Struct,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() -> eframe::Result {
|
fn main() -> eframe::Result {
|
||||||
|
@ -39,7 +50,7 @@ fn main() -> eframe::Result {
|
||||||
ModuleInventory,
|
ModuleInventory,
|
||||||
PartsInventory,
|
PartsInventory,
|
||||||
Build,
|
Build,
|
||||||
Presets
|
Presets,
|
||||||
};
|
};
|
||||||
let mut tab = Tab::General;
|
let mut tab = Tab::General;
|
||||||
|
|
||||||
|
@ -67,7 +78,29 @@ fn main() -> eframe::Result {
|
||||||
panic!("Expected a stirng!");
|
panic!("Expected a stirng!");
|
||||||
};
|
};
|
||||||
|
|
||||||
if ui.button(&name.value).clicked() {
|
let slot_path = format!("{save_dir}/{}/Slot.sav", id.value);
|
||||||
|
|
||||||
|
let mut slot_data = Cursor::new(std::fs::read(&slot_path).unwrap());
|
||||||
|
|
||||||
|
let slot = CompressedSaveFile::<SlotObject>::read_le(&mut slot_data).unwrap();
|
||||||
|
|
||||||
|
let playtime = chrono::NaiveTime::from_num_seconds_from_midnight_opt(
|
||||||
|
slot.value.objs.playtime.value.round() as u32,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let last_checkpoint = slot.value.objs.district_tag.value;
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.button(&format!(
|
||||||
|
"{} {} {} {}",
|
||||||
|
name.value,
|
||||||
|
slot.value.objs.slot_info.timestamp.to_datetime(),
|
||||||
|
playtime,
|
||||||
|
last_checkpoint
|
||||||
|
))
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
let persistent_path = format!("{save_dir}/{}/Persistent.sav", id.value);
|
let persistent_path = format!("{save_dir}/{}/Persistent.sav", id.value);
|
||||||
|
|
||||||
let mut persistent_data =
|
let mut persistent_data =
|
||||||
|
@ -116,15 +149,20 @@ fn main() -> eframe::Result {
|
||||||
ui.checkbox(&mut persistent.demo_version.value, "Demo Version");
|
ui.checkbox(&mut persistent.demo_version.value, "Demo Version");
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add(egui::DragValue::new(&mut persistent.money.value).suffix(" cell"));
|
ui.add(
|
||||||
|
egui::DragValue::new(&mut persistent.money.value).suffix(" cell"),
|
||||||
|
);
|
||||||
ui.label("Money")
|
ui.label("Money")
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add(egui::DragValue::new(&mut persistent.current_item_slot.value).range(0..=5));
|
ui.add(
|
||||||
|
egui::DragValue::new(&mut persistent.current_item_slot.value)
|
||||||
|
.range(0..=5),
|
||||||
|
);
|
||||||
ui.label("Selected Item");
|
ui.label("Selected Item");
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
Tab::ItemWheel => {
|
Tab::ItemWheel => {
|
||||||
for (i, item) in persistent.item_slots.entries.iter_mut().enumerate() {
|
for (i, item) in persistent.item_slots.entries.iter_mut().enumerate() {
|
||||||
let ArrayValue::Struct { ref mut r#struct } = item.key else {
|
let ArrayValue::Struct { ref mut r#struct } = item.key else {
|
||||||
|
@ -140,14 +178,16 @@ fn main() -> eframe::Result {
|
||||||
ui.label(format!("{i:02}"));
|
ui.label(format!("{i:02}"));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Tab::ItemInventory => {
|
Tab::ItemInventory => {
|
||||||
for item in &mut persistent.normal_item_inventory.entries {
|
for item in &mut persistent.normal_item_inventory.entries {
|
||||||
let MapKeyProperty::StructMaybe(ref key) = item.key else {
|
let MapKeyProperty::StructMaybe(ref key) = item.key else {
|
||||||
panic!("Expecting a struct!");
|
panic!("Expecting a struct!");
|
||||||
};
|
};
|
||||||
|
|
||||||
let Property::Name(ref name) = **(key.extra_fields[0].key.as_ref().unwrap()) else {
|
let Property::Name(ref name) =
|
||||||
|
**(key.extra_fields[0].key.as_ref().unwrap())
|
||||||
|
else {
|
||||||
panic!("Expecting a name property!");
|
panic!("Expecting a name property!");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -155,11 +195,15 @@ fn main() -> eframe::Result {
|
||||||
panic!("Expecting a struct!");
|
panic!("Expecting a struct!");
|
||||||
};
|
};
|
||||||
|
|
||||||
let Property::Int(ref carry_count) = **(value.fields[0].key.as_ref().unwrap()) else {
|
let Property::Int(ref carry_count) =
|
||||||
|
**(value.fields[0].key.as_ref().unwrap())
|
||||||
|
else {
|
||||||
panic!("Expecting an int!");
|
panic!("Expecting an int!");
|
||||||
};
|
};
|
||||||
|
|
||||||
let Property::Int(ref store_count) = **(value.fields[1].key.as_ref().unwrap()) else {
|
let Property::Int(ref store_count) =
|
||||||
|
**(value.fields[1].key.as_ref().unwrap())
|
||||||
|
else {
|
||||||
panic!("Expecting an int!");
|
panic!("Expecting an int!");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -169,7 +213,7 @@ fn main() -> eframe::Result {
|
||||||
ui.label(format!("store: {}", store_count.value));
|
ui.label(format!("store: {}", store_count.value));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Tab::ModuleInventory => {
|
Tab::ModuleInventory => {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if ui.button("Mobility").clicked() {
|
if ui.button("Mobility").clicked() {
|
||||||
|
@ -208,8 +252,12 @@ fn main() -> eframe::Result {
|
||||||
|
|
||||||
let matches = match module {
|
let matches = match module {
|
||||||
ModuleType::Mobility => key.value == "EDAModuleItemType::Mobility",
|
ModuleType::Mobility => key.value == "EDAModuleItemType::Mobility",
|
||||||
ModuleType::FrontWeapon => key.value == "EDAModuleItemType::FrontWeapon",
|
ModuleType::FrontWeapon => {
|
||||||
ModuleType::RearWeapon => key.value == "EDAModuleItemType::RearWeapon",
|
key.value == "EDAModuleItemType::FrontWeapon"
|
||||||
|
}
|
||||||
|
ModuleType::RearWeapon => {
|
||||||
|
key.value == "EDAModuleItemType::RearWeapon"
|
||||||
|
}
|
||||||
ModuleType::Hanger => key.value == "EDAModuleItemType::Hanger",
|
ModuleType::Hanger => key.value == "EDAModuleItemType::Hanger",
|
||||||
ModuleType::Utility => key.value == "EDAModuleItemType::Utility",
|
ModuleType::Utility => key.value == "EDAModuleItemType::Utility",
|
||||||
ModuleType::Thruster => key.value == "EDAModuleItemType::Thruster",
|
ModuleType::Thruster => key.value == "EDAModuleItemType::Thruster",
|
||||||
|
@ -221,7 +269,9 @@ fn main() -> eframe::Result {
|
||||||
panic!("Expecting struct value!");
|
panic!("Expecting struct value!");
|
||||||
};
|
};
|
||||||
|
|
||||||
let Property::Map(ref mut map) = **value.fields[0].key.as_mut().unwrap() else {
|
let Property::Map(ref mut map) =
|
||||||
|
**value.fields[0].key.as_mut().unwrap()
|
||||||
|
else {
|
||||||
panic!("Expecting map!");
|
panic!("Expecting map!");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -236,11 +286,14 @@ fn main() -> eframe::Result {
|
||||||
panic!("Expecting struct value!");
|
panic!("Expecting struct value!");
|
||||||
};
|
};
|
||||||
|
|
||||||
let Property::Struct(ref asset_id) = **value.fields[0].key.as_mut().unwrap() else {
|
let Property::Struct(ref asset_id) =
|
||||||
|
**value.fields[0].key.as_mut().unwrap()
|
||||||
|
else {
|
||||||
panic!("Expecting struct!");
|
panic!("Expecting struct!");
|
||||||
};
|
};
|
||||||
|
|
||||||
let Struct::PrimaryAssetId(ref asset_id) = asset_id.r#struct else {
|
let Struct::PrimaryAssetId(ref asset_id) = asset_id.r#struct
|
||||||
|
else {
|
||||||
panic!("Expecting primary asset id!");
|
panic!("Expecting primary asset id!");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -253,23 +306,24 @@ fn main() -> eframe::Result {
|
||||||
};*/
|
};*/
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label(format!("{:#?} {} level", key, asset_id.primary_asset_name.value));
|
ui.label(format!(
|
||||||
|
"{:#?} {} level",
|
||||||
|
key, asset_id.primary_asset_name.value
|
||||||
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//println!("{:#?}", persistent.module_inventory);
|
//println!("{:#?}", persistent.module_inventory);
|
||||||
},
|
}
|
||||||
Tab::PartsInventory => {
|
Tab::PartsInventory => {
|
||||||
println!("{:#?}", persistent.parts_inventory);
|
println!("{:#?}", persistent.parts_inventory);
|
||||||
},
|
}
|
||||||
Tab::Build => {
|
Tab::Build => {
|
||||||
edit_build_data(ui, &mut persistent.current_build_data);
|
edit_build_data(ui, &mut persistent.current_build_data);
|
||||||
},
|
}
|
||||||
Tab::Presets => {
|
Tab::Presets => {}
|
||||||
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -322,8 +376,14 @@ fn edit_customize_data(ui: &mut egui::Ui, customize: &mut DACustomizeAssetIdData
|
||||||
edit_humanoid_figure(ui, &mut customize.figure_data);
|
edit_humanoid_figure(ui, &mut customize.figure_data);
|
||||||
|
|
||||||
ui.checkbox(&mut customize.inverse_face_mesh.value, "Inverse Face");
|
ui.checkbox(&mut customize.inverse_face_mesh.value, "Inverse Face");
|
||||||
ui.checkbox(&mut customize.inverse_front_hair_mesh.value, "Inverse Front Hair");
|
ui.checkbox(
|
||||||
ui.checkbox(&mut customize.inverse_back_hair_mesh.value, "Inverse Back Hair");
|
&mut customize.inverse_front_hair_mesh.value,
|
||||||
|
"Inverse Front Hair",
|
||||||
|
);
|
||||||
|
ui.checkbox(
|
||||||
|
&mut customize.inverse_back_hair_mesh.value,
|
||||||
|
"Inverse Back Hair",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn edit_humanoid_figure(ui: &mut egui::Ui, figure_data: &mut DAHumanoidFigureData) {
|
fn edit_humanoid_figure(ui: &mut egui::Ui, figure_data: &mut DAHumanoidFigureData) {
|
||||||
|
@ -348,7 +408,10 @@ fn edit_humanoid_figure(ui: &mut egui::Ui, figure_data: &mut DAHumanoidFigureDat
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add(egui::Slider::new(&mut figure_data.waist_up.value, 0.0..=1.0));
|
ui.add(egui::Slider::new(
|
||||||
|
&mut figure_data.waist_up.value,
|
||||||
|
0.0..=1.0,
|
||||||
|
));
|
||||||
ui.label("Waist");
|
ui.label("Waist");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,29 +8,29 @@ use crate::{
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SlotObject {
|
pub struct SlotObject {
|
||||||
#[paramacro::serialized_field = "SavedDataVersion"]
|
#[paramacro::serialized_field = "SavedDataVersion"]
|
||||||
version: IntProperty,
|
pub version: IntProperty,
|
||||||
|
|
||||||
#[paramacro::serialized_field = "bDemoVersion"]
|
#[paramacro::serialized_field = "bDemoVersion"]
|
||||||
demo: BoolProperty,
|
pub demo: BoolProperty,
|
||||||
|
|
||||||
#[paramacro::serialized_field = "CreatedTimeStamp"]
|
#[paramacro::serialized_field = "CreatedTimeStamp"]
|
||||||
created_timestamp: DateTimeStruct,
|
pub created_timestamp: DateTimeStruct,
|
||||||
|
|
||||||
#[paramacro::serialized_field = "PlayTime"]
|
#[paramacro::serialized_field = "PlayTime"]
|
||||||
playtime: FloatProperty,
|
pub playtime: FloatProperty,
|
||||||
|
|
||||||
#[paramacro::serialized_field = "RegisteredName"]
|
#[paramacro::serialized_field = "RegisteredName"]
|
||||||
name: StrProperty,
|
pub name: StrProperty,
|
||||||
|
|
||||||
#[paramacro::serialized_field = "LoadOption"]
|
#[paramacro::serialized_field = "LoadOption"]
|
||||||
load_option: DALoadOptionStruct,
|
pub load_option: DALoadOptionStruct,
|
||||||
|
|
||||||
#[paramacro::serialized_field = "DistrictTag"]
|
#[paramacro::serialized_field = "DistrictTag"]
|
||||||
district_tag: NameProperty,
|
pub district_tag: NameProperty,
|
||||||
|
|
||||||
#[paramacro::serialized_field = "CycleCount"]
|
#[paramacro::serialized_field = "CycleCount"]
|
||||||
cycle_count: IntProperty,
|
pub cycle_count: IntProperty,
|
||||||
|
|
||||||
#[paramacro::serialized_field = "SlotInfo"]
|
#[paramacro::serialized_field = "SlotInfo"]
|
||||||
slot_info: SaveSlotInfoStruct,
|
pub slot_info: SaveSlotInfoStruct,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use binrw::binrw;
|
use binrw::binrw;
|
||||||
|
use chrono::Datelike;
|
||||||
|
|
||||||
use crate::property::PropertyBase;
|
use crate::property::PropertyBase;
|
||||||
|
|
||||||
|
@ -26,3 +27,13 @@ impl PropertyBase for DateTimeStruct {
|
||||||
8
|
8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DateTimeStruct {
|
||||||
|
pub fn to_datetime(&self) -> chrono::NaiveDateTime {
|
||||||
|
let datetime = chrono::NaiveDate::from_ymd_opt(1, 1, 1).unwrap();
|
||||||
|
let datetime = chrono::NaiveDateTime::from(datetime);
|
||||||
|
datetime
|
||||||
|
.checked_add_signed(chrono::TimeDelta::microseconds(self.ticks / 10))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue