diff --git a/Cargo.lock b/Cargo.lock index 5e2e403..05d44a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,6 +159,54 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "arboard" version = "3.3.2" @@ -636,6 +684,46 @@ dependencies = [ "libc", ] +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.57", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + [[package]] name = "clipboard-win" version = "5.3.0" @@ -691,6 +779,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "com" version = "0.6.0" @@ -1440,6 +1534,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -1531,6 +1631,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "jni" version = "0.21.1" @@ -1611,7 +1717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.4", ] [[package]] @@ -1799,7 +1905,10 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" name = "nostalgaia-save-editor" version = "0.1.0" dependencies = [ + "clap", "eframe", + "serde", + "serde_json", ] [[package]] @@ -2259,6 +2368,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + [[package]] name = "same-file" version = "1.0.6" @@ -2313,6 +2428,17 @@ dependencies = [ "syn 2.0.57", ] +[[package]] +name = "serde_json" +version = "1.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "serde_repr" version = "0.1.18" @@ -2450,6 +2576,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "syn" version = "1.0.109" @@ -2694,6 +2826,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index c4bf55e..c95d81d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,6 @@ edition = "2021" [dependencies] eframe = "0.27.1" +serde = { version = "1.0.197", features = ["derive"] } +clap = { version = "4.5.4", features = ["derive"] } +serde_json = "1.0.115" diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..e7c7d8b --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,10 @@ +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(author, version, about, name = "Nostalgaia Save Editor")] +pub(crate) struct Options { + pub(crate) save_file: String, + + #[arg(short, long)] + pub(crate) gui: bool, +} diff --git a/src/data/area_config.rs b/src/data/area_config.rs new file mode 100644 index 0000000..ee60b30 --- /dev/null +++ b/src/data/area_config.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize,Debug, Default)] +pub(crate) struct AreaConfig { + #[serde(rename = "killedEnemies")] + pub killed_enemies: Vec, + #[serde(rename = "destructableObjects")] + pub destructable_objects: Vec, + #[serde(rename = "customObjects")] + pub custom_objects: Vec, + #[serde(rename = "customBeaconResetables")] + pub custom_beacon_resetables: Vec, + #[serde(rename = "visibilityBitMask")] + pub visibility_bit_mask: i64, +} \ No newline at end of file diff --git a/src/data/game_config.rs b/src/data/game_config.rs new file mode 100644 index 0000000..cccedba --- /dev/null +++ b/src/data/game_config.rs @@ -0,0 +1,48 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub(crate) struct GameConfig { + pub previous_saveindex: i64, + pub automatically_select_next_target: bool, + pub freeze_time_on_hit: bool, + pub close_menu_when_attacked: bool, + pub controller_vibration: f64, + pub invert_camera_x: bool, + pub invert_camera_y: bool, + pub lock_camera_rotation: bool, + pub camera_speed: f64, + pub use_custom_camera_pitch: bool, + pub custom_camera_pitch_speed: f64, + pub offline_mode: bool, + pub hide_messages: bool, + pub subtitles: bool, + pub dialogue_auto_progress: bool, + #[serde(rename = "volume_Music")] + pub volume_music: f64, + #[serde(rename = "volume_SFX")] + pub volume_sfx: f64, + #[serde(rename = "volume_Voice")] + pub volume_voice: f64, + pub light_shadow_quality: i64, + pub light_shadow_distance: f64, + pub is_windowed: bool, + pub resolution: Vec, + pub refresh_rate: i64, + pub brightness: f64, + pub anti_aliasing: bool, + pub volume_lighting: bool, + pub shadow_quality: i64, + pub vsync: bool, + pub vsync_count: i64, + pub low_quality_mode: bool, + #[serde(rename = "mouse_Sensitivity")] + pub mouse_sensitivity: f64, + #[serde(rename = "mouse_InvertX")] + pub mouse_invert_x: bool, + #[serde(rename = "mouse_InvertY")] + pub mouse_invert_y: bool, + pub toggle_sprint: bool, + pub hold_roll_to_sprint: bool, + pub current_language: i64, +} diff --git a/src/data/mod.rs b/src/data/mod.rs new file mode 100644 index 0000000..c91aa35 --- /dev/null +++ b/src/data/mod.rs @@ -0,0 +1,87 @@ +mod game_config; +mod area_config; +mod quest_config; +mod world_config; +mod player_config; + +use std::collections::VecDeque; +use std::error::Error; +use std::fs; +use std::path::Path; +use game_config::GameConfig; +use area_config::AreaConfig; +use quest_config::QuestConfig; +use player_config::PlayerConfig; +use world_config::WorldConfig; + +#[derive(Debug)] +pub(crate) struct CoreConfig { + game_config: GameConfig, + player_config: PlayerConfig, + world_config: WorldConfig, + quest_config: QuestConfig, + area_configs: Vec, +} + +const SETTINGS_SPLIT: &str = "~SettingsSplit~"; + +impl CoreConfig { + pub(crate) fn parse_file(path: impl AsRef) -> Result> { + let content = fs::read_to_string(path)?; + + let Some((raw_game_config, rest_config)) = content.split_once(SETTINGS_SPLIT) else { + return Err(Box::from("Error parsing config")); + }; + + let game_config: GameConfig = serde_json::from_str(&raw_game_config)?; + + // This assumes that there are never any semicolons elsewhere! + let mut rest: VecDeque<&str> = rest_config.split(";").collect(); + + let player_config: PlayerConfig = serde_json::from_str(rest.pop_front().ok_or("No Player Config")?)?; + let world_config: WorldConfig = serde_json::from_str(rest.pop_front().ok_or("No World Config")?)?; + let quest_config: QuestConfig = serde_json::from_str(rest.pop_front().ok_or("No Quest Config")?)?; + + let area_configs: Vec = rest.iter() + .map(|s| serde_json::from_str(s)) + .filter_map(|s| s.ok()) + .collect(); + + if rest.len() != area_configs.len() { + return Err("Failed Parsing Area Configs".into()); + } + + Ok(CoreConfig { + game_config, + player_config, + world_config, + quest_config, + area_configs, + }) + } + + pub(crate) fn to_string(&self) -> Result> { + let game_config = serde_json::to_string(&self.game_config)?; + + let area_config: Vec = self.area_configs + .iter() + .map(|a| serde_json::to_string(a)) + .filter_map(|a| a.ok()) + .collect(); + + let rest_config = [ + serde_json::to_string(&self.player_config)?, + serde_json::to_string(&self.player_config)?, + serde_json::to_string(&self.world_config)?, + serde_json::to_string(&self.quest_config)?, + area_config.join(";"), + ].join(";"); + + let full_config = [ + game_config, + rest_config, + ].join(SETTINGS_SPLIT); + + Ok(full_config) + } +} \ No newline at end of file diff --git a/src/data/player_config.rs b/src/data/player_config.rs new file mode 100644 index 0000000..84dc4b2 --- /dev/null +++ b/src/data/player_config.rs @@ -0,0 +1,212 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +struct InventoryWeapon { + #[serde(rename = "GUID")] + pub guid: String, + #[serde(rename = "isAwake")] + pub is_awake: bool, + #[serde(rename = "hasSeen")] + pub has_seen: bool, + #[serde(rename = "isHoovered")] + pub is_hoovered: bool, + #[serde(rename = "instanceIDOnCreation")] + pub instance_idon_creation: String, + pub level: i64, + #[serde(rename = "newGamePlusCount")] + pub new_game_plus_count: i64, + #[serde(rename = "infusionType")] + pub infusion_type: i64, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +struct InventoryItem { + #[serde(rename = "GUID")] + pub guid: String, + pub uses: i64, + #[serde(rename = "isAwake")] + pub is_awake: bool, + #[serde(rename = "isHoovered")] + pub is_hoovered: bool, + #[serde(rename = "hasSeen")] + pub has_seen: bool, + #[serde(rename = "instanceIDOnCreation")] + pub instance_idon_creation: String, + #[serde(rename = "newGamePlusCount")] + pub new_game_plus_count: i64, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +struct LoadedRegion { + pub name: String, + #[serde(rename = "usingLOD")] + pub using_lod: bool, + #[serde(rename = "lodIndex")] + pub lod_index: i64, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +struct Rotation { + pub x: f64, + pub y: f64, + pub z: f64, + pub w: f64, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +struct Position { + pub x: f64, + pub y: f64, + pub z: f64, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +pub(crate) struct PlayerConfig { + #[serde(rename = "newGamePlusCount")] + pub new_game_plus_count: i64, + pub accomplishments: Vec, + pub achievements: Vec, + #[serde(rename = "easyModeTutorials")] + pub easy_mode_tutorials: Vec, + #[serde(rename = "wakeUpTutorialStage")] + pub wake_up_tutorial_stage: i64, + #[serde(rename = "hasSeenFlatCounterTutorial")] + pub has_seen_flat_counter_tutorial: bool, + #[serde(rename = "playerClass")] + pub player_class: i64, + pub position: Position, + pub rotation: Rotation, + pub health: f64, + pub memory: i64, + #[serde(rename = "totalMemorySinceStart")] + pub total_memory_since_start: i64, + #[serde(rename = "levelsUpToHoover")] + pub levels_up_to_hoover: i64, + #[serde(rename = "itemsRemembered")] + pub items_remembered: i64, + #[serde(rename = "DLCItemsRemembered")] + pub dlcitems_remembered: i64, + #[serde(rename = "itemsHoovered")] + pub items_hoovered: i64, + #[serde(rename = "easyMode")] + pub easy_mode: bool, + #[serde(rename = "canAccrueSins")] + pub can_accrue_sins: bool, + #[serde(rename = "hooverCanHoover")] + pub hoover_can_hoover: bool, + #[serde(rename = "hooverCanLevelUp")] + pub hoover_can_level_up: bool, + #[serde(rename = "hasHooveredFirstItem")] + pub has_hoovered_first_item: bool, + #[serde(rename = "hasSeenHooverTutorial")] + pub has_seen_hoover_tutorial: bool, + #[serde(rename = "hasSeenMartyrTutorial")] + pub has_seen_martyr_tutorial: bool, + #[serde(rename = "hasHeardWunderBark")] + pub has_heard_wunder_bark: bool, + #[serde(rename = "hooverSins")] + pub hoover_sins: i64, + #[serde(rename = "truthFidelity")] + pub truth_fidelity: i64, + #[serde(rename = "truthPixelation")] + pub truth_pixelation: i64, + pub name: String, + pub guid: String, + #[serde(rename = "beaconIDToLoadAt")] + pub beacon_idto_load_at: String, + #[serde(rename = "tetheredBeaconID")] + pub tethered_beacon_id: String, + #[serde(rename = "hasDoneInitialAcheivementFixCheck")] + pub has_done_initial_acheivement_fix_check: bool, + #[serde(rename = "rememberedGUIDs")] + pub remembered_guids: Vec, + #[serde(rename = "hooveredGUIDs")] + pub hoovered_guids: Vec, + pub _region: String, + #[serde(rename = "regionDisplayName")] + pub region_display_name: String, + #[serde(rename = "discoveredRegions")] + pub discovered_regions: Vec, + #[serde(rename = "loadedRegions")] + pub loaded_regions: Vec, + #[serde(rename = "regionsIWantToLoad")] + pub regions_iwant_to_load: i64, + pub inventory: Vec, + #[serde(rename = "inventoryWeapons")] + pub inventory_weapons: Vec, + pub storage: Vec, + #[serde(rename = "equipedConsumables")] + pub equiped_consumables: Vec, + #[serde(rename = "equipedRings")] + pub equiped_rings: Vec, + #[serde(rename = "droppedSpecialItems")] + pub dropped_special_items: Vec, + #[serde(rename = "rightHandEquipIndex")] + pub right_hand_equip_index: i64, + #[serde(rename = "leftHandEquipIndex")] + pub left_hand_equip_index: i64, + #[serde(rename = "slottedRightHands")] + pub slotted_right_hands: Vec, + #[serde(rename = "slottedLeftHands")] + pub slotted_left_hands: Vec, + #[serde(rename = "initRightHandGUID")] + pub init_right_hand_guid: String, + #[serde(rename = "initLeftHandGUID")] + pub init_left_hand_guid: String, + #[serde(rename = "equipedHelm")] + pub equiped_helm: String, + #[serde(rename = "equipedTorso")] + pub equiped_torso: String, + #[serde(rename = "equipedArms")] + pub equiped_arms: String, + #[serde(rename = "equipedLegs")] + pub equiped_legs: String, + #[serde(rename = "selectedConsumableIndex")] + pub selected_consumable_index: i64, + #[serde(rename = "expToNextLevel")] + pub exp_to_next_level: i64, + pub level: i64, + #[serde(rename = "maxIconUses")] + pub max_icon_uses: i64, + #[serde(rename = "hasBeenBit")] + pub has_been_bit: bool, + pub deaths: i64, + #[serde(rename = "rebuffCount")] + pub rebuff_count: i64, + #[serde(rename = "reposteCount")] + pub reposte_count: i64, + #[serde(rename = "backstabCount")] + pub backstab_count: i64, + pub _stat_vitality: i64, + pub _stat_stamina: i64, + #[serde(rename = "_stat_equipLoad")] + pub _stat_equip_load: i64, + pub _stat_strength: i64, + pub _stat_dexterity: i64, + pub _stat_attunement: i64, + pub _stat_luck: i64, + #[serde(rename = "numberOfDeaths")] + pub number_of_deaths: i64, + #[serde(rename = "savedAtDeath")] + pub saved_at_death: bool, + #[serde(rename = "hasCTH")] + pub has_cth: bool, + #[serde(rename = "hasGoFlat")] + pub has_go_flat: bool, + #[serde(rename = "hasDepthHand")] + pub has_depth_hand: bool, + #[serde(rename = "canAttackSpirit")] + pub can_attack_spirit: bool, + #[serde(rename = "plotThreadsCut")] + pub plot_threads_cut: bool, + #[serde(rename = "hooverInWell")] + pub hoover_in_well: bool, + #[serde(rename = "herosSpiritInWell")] + pub heros_spirit_in_well: bool, + #[serde(rename = "innocentSacrificed")] + pub innocent_sacrificed: bool, + #[serde(rename = "hooverDead")] + pub hoover_dead: bool, + #[serde(rename = "regionName")] + pub region_name: String, +} \ No newline at end of file diff --git a/src/data/quest_config.rs b/src/data/quest_config.rs new file mode 100644 index 0000000..1e476e3 --- /dev/null +++ b/src/data/quest_config.rs @@ -0,0 +1,105 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +pub(crate) struct QuestConfig { + #[serde(rename = "friendlyNPCsKilled")] + pub friendly_npcs_killed: Vec, + #[serde(rename = "storyProgressStage")] + pub story_progress_stage: i64, + #[serde(rename = "storyProgressStage_DLC1_Lower")] + pub story_progress_stage_dlc1_lower: i64, + #[serde(rename = "storyProgressStage_DLC1_Upper")] + pub story_progress_stage_dlc1_upper: i64, + #[serde(rename = "hooverConversationIndex")] + pub hoover_conversation_index: i64, + #[serde(rename = "hooverTalkConversationIndex")] + pub hoover_talk_conversation_index: i64, + #[serde(rename = "scoFrickinCursedUsOut")] + pub sco_frickin_cursed_us_out: bool, + #[serde(rename = "blacksmithFirstLinesSpoken")] + pub blacksmith_first_lines_spoken: Vec, + #[serde(rename = "blacksmithHasSaidEndGame")] + pub blacksmith_has_said_end_game: bool, + #[serde(rename = "blacksmithGenericTalkIndex")] + pub blacksmith_generic_talk_index: i64, + #[serde(rename = "hasSpawnedBridge")] + pub has_spawned_bridge: bool, + #[serde(rename = "DLC_FailedOldManQuestLine")] + pub dlc_failed_old_man_quest_line: bool, + #[serde(rename = "DLC_OldManStartedInSewers")] + pub dlc_old_man_started_in_sewers: bool, + #[serde(rename = "DLC_OldManSecondLocaltionInSewers")] + pub dlc_old_man_second_localtion_in_sewers: bool, + #[serde(rename = "DLC_OldManInitialConversation")] + pub dlc_old_man_initial_conversation: bool, + #[serde(rename = "DLC_OldManSecondConversation")] + pub dlc_old_man_second_conversation: bool, + #[serde(rename = "DLC_OldManEnteredSTown")] + pub dlc_old_man_entered_stown: bool, + #[serde(rename = "DLC_OldManEnteredCave")] + pub dlc_old_man_entered_cave: bool, + #[serde(rename = "DLC_OldManTalkedFirstItem")] + pub dlc_old_man_talked_first_item: bool, + #[serde(rename = "DLC_OldManTalkedSecondItem")] + pub dlc_old_man_talked_second_item: bool, + #[serde(rename = "DLC_KilledEve")] + pub dlc_killed_eve: bool, + #[serde(rename = "DLC_KilledLiuvani")] + pub dlc_killed_liuvani: bool, + #[serde(rename = "DLC_KilledLiuvaniFirst")] + pub dlc_killed_liuvani_first: bool, + #[serde(rename = "DLC_KilledOldMan")] + pub dlc_killed_old_man: bool, + #[serde(rename = "DLC_HasFoughtOldManOnce")] + pub dlc_has_fought_old_man_once: bool, + #[serde(rename = "DLC_HasSeenOldmanFightIntro")] + pub dlc_has_seen_oldman_fight_intro: bool, + #[serde(rename = "DLC_HadFinalOldManConvo")] + pub dlc_had_final_old_man_convo: bool, + #[serde(rename = "DLC_OldManItemsOwned")] + pub dlc_old_man_items_owned: i64, + #[serde(rename = "DLC_OldManHasArmour")] + pub dlc_old_man_has_armour: bool, + #[serde(rename = "DLC_LastBossAttemptDamage")] + pub dlc_last_boss_attempt_damage: i64, + #[serde(rename = "DLC_LastBossConvoIndex1")] + pub dlc_last_boss_convo_index1: i64, + #[serde(rename = "DLC_LastBossConvoIndex2")] + pub dlc_last_boss_convo_index2: i64, + #[serde(rename = "DLC_LastBossConvoIndex3")] + pub dlc_last_boss_convo_index3: i64, + #[serde(rename = "DLC_LastBossConvoIndex4")] + pub dlc_last_boss_convo_index4: i64, + #[serde(rename = "DLC_MadeFinalFormJoke")] + pub dlc_made_final_form_joke: bool, + #[serde(rename = "DLC_HasAttemptedLastBoss")] + pub dlc_has_attempted_last_boss: bool, + #[serde(rename = "DLC_HasTalkedToBlacksmithAboutArmour")] + pub dlc_has_talked_to_blacksmith_about_armour: bool, + #[serde(rename = "DLC_HasTalkedToBlacksmithAfterForging")] + pub dlc_has_talked_to_blacksmith_after_forging: bool, + #[serde(rename = "questStage_OldMan")] + pub quest_stage_old_man: i64, + #[serde(rename = "questStage_Heir")] + pub quest_stage_heir: i64, + #[serde(rename = "questStage_Nameless")] + pub quest_stage_nameless: i64, + #[serde(rename = "questStage_Sco")] + pub quest_stage_sco: i64, + #[serde(rename = "questStage_Innocent")] + pub quest_stage_innocent: i64, + #[serde(rename = "questStage_Maiden")] + pub quest_stage_maiden: i64, + #[serde(rename = "questStage_Hoover")] + pub quest_stage_hoover: i64, + #[serde(rename = "questStage_TheSmith")] + pub quest_stage_the_smith: i64, + #[serde(rename = "questStage_Shopkeeper")] + pub quest_stage_shopkeeper: i64, + #[serde(rename = "questStage_Sando")] + pub quest_stage_sando: i64, + #[serde(rename = "questStage_ChainedHero")] + pub quest_stage_chained_hero: i64, + #[serde(rename = "questStage_BrendenMerkle")] + pub quest_stage_brenden_merkle: i64, +} \ No newline at end of file diff --git a/src/data/world_config.rs b/src/data/world_config.rs new file mode 100644 index 0000000..bb175b2 --- /dev/null +++ b/src/data/world_config.rs @@ -0,0 +1,86 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Default)] +struct CorpseLocation { + pub x: f64, + pub y: f64, + pub z: f64, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +pub(crate) struct WorldConfig { + #[serde(rename = "isCorpseOnField")] + pub is_corpse_on_field: bool, + #[serde(rename = "savedMemoryOnDeath")] + pub saved_memory_on_death: bool, + #[serde(rename = "corpseLocation")] + pub corpse_location: CorpseLocation, + #[serde(rename = "corpseMemroy")] + pub corpse_memroy: i64, + #[serde(rename = "usingVerboseItemDetail")] + pub using_verbose_item_detail: bool, + #[serde(rename = "hooverBonusDisplay")] + pub hoover_bonus_display: bool, + #[serde(rename = "forgesLit")] + pub forges_lit: i64, + #[serde(rename = "ambientEventName")] + pub ambient_event_name: String, + #[serde(rename = "litBeacons")] + pub lit_beacons: Vec, + #[serde(rename = "activeFidelityPoint")] + pub active_fidelity_point: String, + #[serde(rename = "messagesRated")] + pub messages_rated: Vec, + #[serde(rename = "myMessages")] + pub my_messages: Vec, + #[serde(rename = "collectionDropIndexes")] + pub collection_drop_indexes: Vec, + #[serde(rename = "openBackDoors")] + pub open_back_doors: Vec, + #[serde(rename = "playTime")] + pub play_time: f64, + #[serde(rename = "timeAtLastSaveOrLoad")] + pub time_at_last_save_or_load: f64, + #[serde(rename = "bossFightAssistances")] + pub boss_fight_assistances: i64, + #[serde(rename = "shrineBGLerpAMount")] + pub shrine_bglerp_amount: f64, + #[serde(rename = "UpperDBGLerpAmount")] + pub upper_dbglerp_amount: f64, + #[serde(rename = "MansionBGLerpAmount")] + pub mansion_bglerp_amount: f64, + #[serde(rename = "NobleWoodBGLerpAmount")] + pub noble_wood_bglerp_amount: f64, + #[serde(rename = "NobleWoodBGGeoLerpAmount")] + pub noble_wood_bggeo_lerp_amount: f64, + #[serde(rename = "HiddenVBGLerpAmount")] + pub hidden_vbglerp_amount: f64, + #[serde(rename = "MoatBGLerpAmount")] + pub moat_bglerp_amount: f64, + #[serde(rename = "MoatBGGeoLerpAmount")] + pub moat_bggeo_lerp_amount: f64, + #[serde(rename = "VCInteriorBGLerpAmount")] + pub vcinterior_bglerp_amount: f64, + #[serde(rename = "trailMarkers")] + pub trail_markers: Vec, + #[serde(rename = "customObjects")] + pub custom_objects: Vec, + #[serde(rename = "rehabilitationTorchesLit")] + pub rehabilitation_torches_lit: i64, + #[serde(rename = "sewerTownTorchesLit")] + pub sewer_town_torches_lit: i64, + #[serde(rename = "unlockedShopkeeperExtraInventory_1")] + pub unlocked_shopkeeper_extra_inventory_1: bool, + #[serde(rename = "unlockedShopkeeperExtraInventory_2")] + pub unlocked_shopkeeper_extra_inventory_2: bool, + #[serde(rename = "unlockedShopkeeperExtraInventory_3")] + pub unlocked_shopkeeper_extra_inventory_3: bool, + #[serde(rename = "hasEndedGameAlready")] + pub has_ended_game_already: bool, + #[serde(rename = "HV_Water_Volume")] + pub hv_water_volume: f64, + #[serde(rename = "HV_Water_ControlType")] + pub hv_water_control_type: i64, + #[serde(rename = "HV_Water_LerpIndex")] + pub hv_water_lerp_index: i64, +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 4dbba16..7461f3d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,24 @@ +mod cli; +mod data; + +use std::error::Error; +use clap::Parser; use eframe; use eframe::egui; +use crate::cli::Options; -fn main() -> Result<(), eframe::Error> { - run_gui() +fn main() -> Result<(), Box> { + let options = Options::parse(); + + let save_data = data::CoreConfig::parse_file(options.save_file)?; + + println!("{}", save_data.to_string()?); + + if options.gui { + run_gui()?; + } + + Ok(()) } fn run_gui() -> Result<(), eframe::Error> { @@ -18,13 +34,13 @@ fn run_gui() -> Result<(), eframe::Error> { struct SaveEditor {} impl SaveEditor { - fn new(cc: &eframe::CreationContext) -> Self { + fn new(_cc: &eframe::CreationContext) -> Self { Self::default() } } impl eframe::App for SaveEditor { - fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { egui::CentralPanel::default().show(ctx, |ui| ui.heading("Hello World!")); } }