From 892f9139003e50db041c5d17d61d8e11cc48cfed Mon Sep 17 00:00:00 2001 From: poly000 <1348292515@qq.com> Date: Fri, 25 Nov 2022 23:02:42 +0800 Subject: [PATCH] todo: web support --- Cargo.lock | 4 +- Cargo.toml | 2 +- src/app.rs | 179 ++++++++++++++++++++++++++++++++++++++-------------- src/lib.rs | 2 +- src/main.rs | 6 +- 5 files changed, 140 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e794e0..1b24024 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,9 +158,9 @@ dependencies = [ [[package]] name = "cavestory-save-lib" -version = "2.4.2" +version = "2.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86161fdb51dae6a160b22144d4ab4b29619145c1306282db3b674d48557a82" +checksum = "b13889eb4d7829c7cbc3822ac63fd6a4df4af1f8b5cf19d753dab01c70979bcd" dependencies = [ "strum", ] diff --git a/Cargo.toml b/Cargo.toml index 2a23eb3..51e765d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ rust-version = "1.60" [dependencies] egui = "0.19.0" eframe = { version = "0.19.0", features = [] } -cavestory-save-lib = "2.4.1" +cavestory-save-lib = "2.4.4" rfd = "0.10.0" strum = "0.24.1" diff --git a/src/app.rs b/src/app.rs index 0d82f6f..9124b4a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,3 +1,4 @@ +#[cfg(not(target_arch = "wasm32"))] use std::{fs, path::PathBuf}; use cavestory_save::{GameProfile, Profile}; @@ -5,7 +6,9 @@ use cavestory_save::{GameProfile, Profile}; use cavestory_save::items::*; use strum::IntoEnumIterator; -pub struct App { +use egui::{DragValue, Slider}; + +pub struct MainApp { #[cfg(not(target_arch = "wasm32"))] path: Option, profile: Option, @@ -13,7 +16,8 @@ pub struct App { weapon_num: usize, } -impl Default for App { +impl Default for MainApp { + #[cfg(not(target_arch = "wasm32"))] fn default() -> Self { Self { path: None, @@ -22,13 +26,38 @@ impl Default for App { weapon_num: 0, } } + #[cfg(target_arch = "wasm32")] + fn default() -> Self { + Self { + profile: None, + raw_profile: None, + weapon_num: 0, + } + } } -impl App { +impl MainApp { pub fn new(_cc: &eframe::CreationContext<'_>) -> Self { Default::default() } + fn verify_and_init(&mut self, data: Profile) -> bool { + if data.verify() { + self.profile = Some(GameProfile::dump(&data)); + self.raw_profile = Some(data); + self.weapon_num = self.count_weapon().unwrap(); + true + } else { + use rfd::{MessageDialog, MessageLevel}; + MessageDialog::new() + .set_level(MessageLevel::Error) + .set_title("Load Error") + .set_description("Profile.dat head not equal to \"Do041220\"") + .show(); + false + } + } + fn count_weapon(&self) -> Option { self.profile.and_then(|p| { Some( @@ -41,7 +70,7 @@ impl App { } } -impl eframe::App for App { +impl eframe::App for MainApp { /// Called by the frame work to save state before shutdown. fn save(&mut self, _storage: &mut dyn eframe::Storage) {} @@ -56,28 +85,17 @@ impl eframe::App for App { #[cfg(not(target_arch = "wasm32"))] egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { use rfd::FileDialog; - use rfd::{MessageDialog, MessageLevel}; egui::menu::bar(ui, |ui| { ui.menu_button("File", |ui| { if ui.button("Open").clicked() { let path = FileDialog::default() .add_filter("Profile", &["dat"]) .set_title("Pick your game profile") - .pick_file(); // this file is guranteed availiable to read + .pick_file(); if let Some(path) = path { let data: Profile = fs::read(&path).unwrap().into(); - if data.verify() { + if self.verify_and_init(data) { self.path = Some(path); - - self.profile = Some(GameProfile::dump(&data)); - self.raw_profile = Some(data); - self.weapon_num = self.count_weapon().unwrap(); - } else { - MessageDialog::new() - .set_level(MessageLevel::Error) - .set_title("Load Error") - .set_description("Profile.dat head not equal to \"Do041220\"") - .show(); } } } @@ -89,44 +107,96 @@ impl eframe::App for App { }); egui::CentralPanel::default().show(ctx, |ui| { - #[cfg(target_arch = "wasm32")] - if false {} // todo: pick/save file on web - if let Some(profile) = &mut self.profile { - ui.label("Heal"); - ui.add(egui::Slider::new(&mut profile.health, -1..=50)); + egui::Window::new("Basic").show(ctx, |ui| { + ui.add(DragValue::new(&mut profile.health).prefix("heal: ")); + ui.add(DragValue::new(&mut profile.max_health).prefix("max heal: ")); - ui.label("Weapons"); - ui.horizontal(|ui| { - for (i, weapon) in profile.weapon[..self.weapon_num].iter_mut().enumerate() { - ui.vertical(|ui| { - egui::ComboBox::new(format!("weapontype-box-{i}"), format!("slot {i}")) - .selected_text(weapon.classification.to_string()) - .show_ui(ui, |ui| { - for model in WeaponType::iter() { - ui.selectable_value( - &mut weapon.classification, - model, - model.to_string(), + ui.label("BGM"); + egui::ComboBox::new("background_music", "") + .selected_text(profile.music.to_string()) + .width(200.) + .show_ui(ui, |ui| { + for bg_music in Song::iter() { + ui.selectable_value( + &mut profile.music, + bg_music, + bg_music.to_string(), + ); + } + }); + + ui.label("Map"); + egui::ComboBox::new("map", "") + .selected_text(profile.map.to_string()) + .width(200.) + .show_ui(ui, |ui| { + for map in Map::iter() { + ui.selectable_value(&mut profile.map, map, map.to_string()); + } + }); + + ui.label("Position"); + ui.horizontal(|ui| { + ui.add(DragValue::new(&mut profile.position.x).prefix("x: ")); + ui.add(DragValue::new(&mut profile.position.y).prefix("y: ")); + }); + }); + egui::Window::new("Weapons").show(ctx, |ui| { + ui.horizontal(|ui| { + // do not set the 8th weapon, you may go into issue. + if ui.button(" + ").clicked() && self.weapon_num < 7 { + self.weapon_num += 1 + } + if ui.button(" - ").clicked() && self.weapon_num > 0 { + self.weapon_num -= 1; + profile.weapon[self.weapon_num] = Weapon::default(); + } + }); + + ui.separator(); + + for (chunk_i, chunk) in + profile.weapon[..self.weapon_num].chunks_mut(3).enumerate() + { + ui.horizontal(|ui| { + for (i, weapon) in chunk.iter_mut().enumerate() { + ui.vertical(|ui| { + egui::ComboBox::new( + format!("weapontype-box-{}", chunk_i * 3 + i), + "", + ) + .width(150.) + .selected_text(weapon.classification.to_string()) + .show_ui(ui, |ui| { + for model in WeaponType::iter() { + ui.selectable_value( + &mut weapon.classification, + model, + model.to_string(), + ); + } + }); + if weapon.classification != WeaponType::None { + // attributes here + + ui.label("level"); + ui.add(Slider::new(&mut weapon.level, 0..=3)); + + ui.add(DragValue::new(&mut weapon.ammo).prefix("ammo: ")); + ui.add( + DragValue::new(&mut weapon.max_ammo) + .prefix("max ammo: "), ); + ui.add(DragValue::new(&mut weapon.exp).prefix("exp: ")); } }); - if weapon.classification != WeaponType::None { - // attributes here - ui.label("test"); } }); } - - // do not set the 8th weapon, you may go into issue. - if self.weapon_num < 7 && ui.button("add").clicked() { - self.weapon_num += 1 - } - if self.weapon_num > 0 && ui.button("del").clicked() { - self.weapon_num -= 1; - profile.weapon[self.weapon_num] = Weapon::default(); - } }); + } else { + ui.label("Please load profile.dat"); } ui.horizontal(|ui| { @@ -135,6 +205,23 @@ impl eframe::App for App { self.profile = Some(GameProfile::dump(raw)); self.weapon_num = self.count_weapon().unwrap(); } + + #[cfg(not(target_arch = "wasm32"))] + if ui.button("Save").clicked() { + let mut raw = raw.clone(); + if let Some(path) = &self.path { + self.profile.unwrap().write(&mut raw); + let bytes: Vec = raw.into(); + if let Err(e) = fs::write(path, bytes) { + use rfd::{MessageDialog, MessageLevel}; + MessageDialog::new() + .set_level(MessageLevel::Error) + .set_description(&e.to_string()) + .set_title("Error occured while saving!") + .show(); + } + } + } } }); diff --git a/src/lib.rs b/src/lib.rs index 27de78f..a8a98c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ #![warn(clippy::all, rust_2018_idioms)] mod app; -pub use app::App; +pub use app::MainApp; diff --git a/src/main.rs b/src/main.rs index ab85500..fdfe06a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,8 +3,8 @@ // When compiling natively: #[cfg(not(target_arch = "wasm32"))] -use eframe::NativeOptions; fn main() { + use eframe::NativeOptions; // Log to stdout (if you run with `RUST_LOG=debug`). tracing_subscriber::fmt::init(); @@ -12,7 +12,7 @@ fn main() { eframe::run_native( "CaveStory Save Editor", native_options, - Box::new(|cc| Box::new(doukutsu_save_editor::App::new(cc))), + Box::new(|cc| Box::new(doukutsu_save_editor::MainApp::new(cc))), ); } @@ -29,7 +29,7 @@ fn main() { eframe::start_web( "the_canvas_id", // hardcode it web_options, - Box::new(|cc| Box::new(eframe_template::App::new(cc))), + Box::new(|cc| Box::new(doukutsu_save_editor::MainApp::new(cc))), ) .expect("failed to start eframe"); }