From ceede32fc64cef67e176be4082506d9b7de3039b Mon Sep 17 00:00:00 2001 From: Melody Madeline Lyons Date: Mon, 15 Jul 2024 13:22:22 -0700 Subject: [PATCH 1/7] Conversion that sort of works --- Cargo.lock | 1 + crates/core/src/data_cache.rs | 90 ----------- crates/core/src/data_cache/data_formats.rs | 74 +++++++-- crates/core/src/lib.rs | 2 +- crates/ui/Cargo.toml | 1 + crates/ui/src/windows/config_window.rs | 167 ++++++++++++++++++++- 6 files changed, 225 insertions(+), 110 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a525434..702705ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3260,6 +3260,7 @@ dependencies = [ "camino", "color-eyre", "egui", + "egui-modal", "futures-lite 2.2.0", "futures-util", "indexmap", diff --git a/crates/core/src/data_cache.rs b/crates/core/src/data_cache.rs index c480c2d9..3eb54e03 100644 --- a/crates/core/src/data_cache.rs +++ b/crates/core/src/data_cache.rs @@ -366,96 +366,6 @@ impl Data { } Ok(()) } - - pub fn convert_project( - &mut self, - filesystem: &impl luminol_filesystem::FileSystem, - config: &luminol_config::project::Config, - to: luminol_config::DataFormat, - ) -> color_eyre::Result<()> { - let from_handler = data_formats::Handler::new(config.project.data_format); - let to_handler = data_formats::Handler::new(to); - - let Self::Loaded { - actors, - animations, - armors, - classes, - common_events, - enemies, - items, - map_infos, - scripts, - skills, - states, - system, - tilesets, - troops, - weapons, - .. - } = self - else { - panic!("project not loaded") - }; - - to_handler.write_nil_padded(&actors.get_mut().data, filesystem, "Actors")?; - from_handler.remove_file(filesystem, "Actors")?; - - to_handler.write_nil_padded(&animations.get_mut().data, filesystem, "Animations")?; - from_handler.remove_file(filesystem, "Animations")?; - - to_handler.write_nil_padded(&armors.get_mut().data, filesystem, "Armors")?; - from_handler.remove_file(filesystem, "Armors")?; - - to_handler.write_nil_padded(&classes.get_mut().data, filesystem, "Classes")?; - from_handler.remove_file(filesystem, "Classes")?; - - to_handler.write_nil_padded(&common_events.get_mut().data, filesystem, "CommonEvents")?; - from_handler.remove_file(filesystem, "CommonEvents")?; - - to_handler.write_nil_padded(&enemies.get_mut().data, filesystem, "Enemies")?; - from_handler.remove_file(filesystem, "Enemies")?; - - to_handler.write_nil_padded(&items.get_mut().data, filesystem, "Items")?; - from_handler.remove_file(filesystem, "Items")?; - - to_handler.write_nil_padded(&skills.get_mut().data, filesystem, "Skills")?; - from_handler.remove_file(filesystem, "Skills")?; - - to_handler.write_nil_padded(&states.get_mut().data, filesystem, "States")?; - from_handler.remove_file(filesystem, "States")?; - - to_handler.write_nil_padded(&tilesets.get_mut().data, filesystem, "Tilesets")?; - from_handler.remove_file(filesystem, "Tilesets")?; - - to_handler.write_nil_padded(&troops.get_mut().data, filesystem, "Troops")?; - from_handler.remove_file(filesystem, "Troops")?; - - to_handler.write_nil_padded(&weapons.get_mut().data, filesystem, "Weapons")?; - from_handler.remove_file(filesystem, "Weapons")?; - - // special handling - to_handler.write_data( - &scripts.get_mut().data, - filesystem, - &config.project.scripts_path, - )?; - from_handler.remove_file(filesystem, &config.project.scripts_path)?; - - to_handler.write_data(&system.get_mut(), filesystem, "System")?; - from_handler.remove_file(filesystem, "System")?; - - to_handler.write_data(&map_infos.get_mut().data, filesystem, "MapInfos")?; - from_handler.remove_file(filesystem, "MapInfos")?; - - for id in map_infos.get_mut().data.keys() { - let map: rpg::Map = from_handler.read_data(filesystem, format!("Map{id:0>3}"))?; - to_handler.write_data(&map, filesystem, format!("Map{id:0>3}"))?; - from_handler.remove_file(filesystem, format!("Map{id:0>3}"))?; - } - - Ok(()) - } } macro_rules! nested_ref_getter { diff --git a/crates/core/src/data_cache/data_formats.rs b/crates/core/src/data_cache/data_formats.rs index 37d18722..ba65c29f 100644 --- a/crates/core/src/data_cache/data_formats.rs +++ b/crates/core/src/data_cache/data_formats.rs @@ -36,6 +36,12 @@ impl Handler { Self { format } } + pub fn path_for(self, filename: impl AsRef) -> camino::Utf8PathBuf { + camino::Utf8Path::new("Data") + .join(filename) + .with_extension(self.format.extension()) + } + pub fn read_data( self, filesystem: &impl luminol_filesystem::FileSystem, @@ -45,10 +51,7 @@ impl Handler { T: for<'de> alox_48::Deserialize<'de>, T: ::serde::de::DeserializeOwned, { - let path = camino::Utf8Path::new("Data") - .join(filename) - .with_extension(self.format.extension()); - let data = filesystem.read(path)?; + let data = filesystem.read(self.path_for(filename))?; match self.format { DataFormat::Marshal => { @@ -68,6 +71,29 @@ impl Handler { } } + pub fn read_data_from(self, data: &[u8]) -> color_eyre::Result + where + T: for<'de> alox_48::Deserialize<'de>, + T: ::serde::de::DeserializeOwned, + { + match self.format { + DataFormat::Marshal => { + let mut de = alox_48::Deserializer::new(data)?; + let result = alox_48::path_to_error::deserialize(&mut de); + + result.map_err(|(error, trace)| format_traced_error(error, trace)) + } + DataFormat::Ron => { + let mut de = ron::de::Deserializer::from_bytes(data)?; + serde_path_to_error::deserialize(&mut de).map_err(format_path_to_error) + } + DataFormat::Json => { + let mut de = serde_json::de::Deserializer::from_slice(data); + serde_path_to_error::deserialize(&mut de).map_err(format_path_to_error) + } + } + } + pub fn write_data( self, data: &T, @@ -78,11 +104,8 @@ impl Handler { T: ::serde::Serialize, T: alox_48::Serialize, { - let path = camino::Utf8Path::new("Data") - .join(filename) - .with_extension(self.format.extension()); let mut file = filesystem.open_file( - path, + self.path_for(filename), OpenFlags::Create | OpenFlags::Truncate | OpenFlags::Write, )?; @@ -106,6 +129,31 @@ impl Handler { Ok(()) } + pub fn write_data_to(self, data: &T, buffer: &mut Vec) -> color_eyre::Result<()> + where + T: ::serde::Serialize, + T: alox_48::Serialize, + { + match self.format { + DataFormat::Marshal => { + let mut serializer = alox_48::Serializer::new(); + alox_48::path_to_error::serialize(data, &mut serializer) + .map_err(|(error, trace)| format_traced_error(error, trace))?; + buffer.extend_from_slice(&serializer.output); + } + DataFormat::Ron => { + let mut ser = ron::Serializer::new(buffer, None)?; + serde_path_to_error::serialize(data, &mut ser)?; + } + DataFormat::Json => { + let mut ser = serde_json::Serializer::new(buffer); + serde_path_to_error::serialize(data, &mut ser)?; + } + }; + + Ok(()) + } + pub fn read_nil_padded( self, filesystem: &impl luminol_filesystem::FileSystem, @@ -115,10 +163,7 @@ impl Handler { T: for<'de> alox_48::Deserialize<'de>, T: ::serde::de::DeserializeOwned, { - let path = camino::Utf8Path::new("Data") - .join(filename) - .with_extension(self.format.extension()); - let data = filesystem.read(path)?; + let data = filesystem.read(self.path_for(filename))?; match self.format { DataFormat::Marshal => { @@ -162,11 +207,8 @@ impl Handler { T: ::serde::Serialize, T: alox_48::Serialize, { - let path = camino::Utf8Path::new("Data") - .join(filename) - .with_extension(self.format.extension()); let mut file = filesystem.open_file( - path, + self.path_for(filename), OpenFlags::Create | OpenFlags::Truncate | OpenFlags::Write, )?; diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index de51f24c..17293050 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -46,7 +46,7 @@ pub use project_manager::spawn_future; pub use project_manager::ProjectManager; pub use alox_48; -pub use data_cache::data_formats::format_traced_error; +pub use data_cache::data_formats::{self, format_traced_error}; pub mod prelude { pub use crate::{Modal, Tab, UpdateState, Window}; diff --git a/crates/ui/Cargo.toml b/crates/ui/Cargo.toml index fdaa4326..74373f65 100644 --- a/crates/ui/Cargo.toml +++ b/crates/ui/Cargo.toml @@ -28,6 +28,7 @@ luminol-modals.workspace = true luminol-macros.workspace = true egui.workspace = true +egui-modal = "0.3.6" camino.workspace = true diff --git a/crates/ui/src/windows/config_window.rs b/crates/ui/src/windows/config_window.rs index 7cc2fd38..85c36c19 100644 --- a/crates/ui/src/windows/config_window.rs +++ b/crates/ui/src/windows/config_window.rs @@ -22,21 +22,138 @@ // terms of the Steamworks API by Valve Corporation, the licensors of this // Program grant you additional permission to convey the resulting work. +use async_std::io::{ReadExt, WriteExt}; +use egui::Widget; +use itertools::Itertools; +use luminol_filesystem::{FileSystem, OpenFlags}; +use std::sync::atomic::{AtomicUsize, Ordering}; use strum::IntoEnumIterator; pub struct Window { selected_data_format: luminol_config::DataFormat, + convert: Option, } +struct Convert { + promise: poll_promise::Promise>, + progress: Progress, +} +type Progress = std::sync::Arc<(AtomicUsize, AtomicUsize)>; + impl Window { pub fn new(config: &luminol_config::project::Config) -> Self { Self { selected_data_format: config.project.data_format, + convert: None, } } } -const FORMAT_WARNING: &str = "While the option is provided,\nLuminol cannot convert between formats yet.\nIt can still read other formats, however."; // "Luminol will need to convert your project.\nThis is not 100% safe yet, make backups!\nPress OK to continue."; +const FORMAT_WARNING: &str = "Luminol will need to convert your project.\nThis is not 100% safe yet, make backups!\nPress OK to continue."; + +fn convert_project( + config: &mut luminol_config::project::Config, + selected_data_format: luminol_config::DataFormat, + data_cache: &mut luminol_core::Data, + filesystem: &mut luminol_filesystem::project::FileSystem, + progress: Progress, +) -> color_eyre::Result>> { + let from_handler = luminol_core::data_formats::Handler::new(config.project.data_format); + let to_handler = luminol_core::data_formats::Handler::new(selected_data_format); + + let pretty_config = ron::ser::PrettyConfig::new() + .struct_names(true) + .enumerate_arrays(true); + config.project.data_format = selected_data_format; + let project_config = ron::ser::to_string_pretty(&config.project, pretty_config)?; + filesystem.write(".luminol/config", project_config)?; + + to_handler.write_nil_padded(&data_cache.actors().data, filesystem, "Actors")?; + from_handler.remove_file(filesystem, "Actors")?; + + to_handler.write_nil_padded(&data_cache.animations().data, filesystem, "Animations")?; + from_handler.remove_file(filesystem, "Animations")?; + + to_handler.write_nil_padded(&data_cache.armors().data, filesystem, "Armors")?; + from_handler.remove_file(filesystem, "Armors")?; + + to_handler.write_nil_padded(&data_cache.classes().data, filesystem, "Classes")?; + from_handler.remove_file(filesystem, "Classes")?; + + to_handler.write_nil_padded(&data_cache.common_events().data, filesystem, "CommonEvents")?; + from_handler.remove_file(filesystem, "CommonEvents")?; + + to_handler.write_nil_padded(&data_cache.enemies().data, filesystem, "Enemies")?; + from_handler.remove_file(filesystem, "Enemies")?; + + to_handler.write_nil_padded(&data_cache.items().data, filesystem, "Items")?; + from_handler.remove_file(filesystem, "Items")?; + + to_handler.write_nil_padded(&data_cache.skills().data, filesystem, "Skills")?; + from_handler.remove_file(filesystem, "Skills")?; + + to_handler.write_nil_padded(&data_cache.states().data, filesystem, "States")?; + from_handler.remove_file(filesystem, "States")?; + + to_handler.write_nil_padded(&data_cache.tilesets().data, filesystem, "Tilesets")?; + from_handler.remove_file(filesystem, "Tilesets")?; + + to_handler.write_nil_padded(&data_cache.troops().data, filesystem, "Troops")?; + from_handler.remove_file(filesystem, "Troops")?; + + to_handler.write_nil_padded(&data_cache.weapons().data, filesystem, "Weapons")?; + from_handler.remove_file(filesystem, "Weapons")?; + + // special handling + to_handler.write_data( + &data_cache.scripts().data, + filesystem, + &config.project.scripts_path, + )?; + from_handler.remove_file(filesystem, &config.project.scripts_path)?; + + to_handler.write_data(&*data_cache.system(), filesystem, "System")?; + from_handler.remove_file(filesystem, "System")?; + + let mapinfos = data_cache.map_infos(); + to_handler.write_data(&mapinfos.data, filesystem, "MapInfos")?; + from_handler.remove_file(filesystem, "MapInfos")?; + + let map_ids = mapinfos.data.keys().copied().collect_vec(); + let host = filesystem.host().unwrap(); + + let fut = async move { + let mut read_buf = Vec::new(); + let mut write_buf = Vec::::new(); + for (index, map_id) in map_ids.into_iter().enumerate() { + progress.0.store(index, Ordering::Relaxed); + progress.1.store(map_id, Ordering::Relaxed); + + read_buf.clear(); + write_buf.clear(); + let map_filename = format!("Map{map_id:0>3}"); + + let mut map_file = + host.open_file(from_handler.path_for(&map_filename), OpenFlags::Read)?; + map_file.read_to_end(&mut read_buf).await?; + + let map: luminol_data::rpg::Map = from_handler.read_data_from(&read_buf)?; + + to_handler.write_data_to(&map, &mut write_buf)?; + + let mut map_file = host.open_file( + to_handler.path_for(&map_filename), + OpenFlags::Write | OpenFlags::Truncate | OpenFlags::Create, + )?; + map_file.write_all(&write_buf).await?; + + from_handler.remove_file(&host, &map_filename)?; + } + Ok(()) + }; + + Ok(fut) +} impl luminol_core::Window for Window { fn id(&self) -> egui::Id { @@ -126,8 +243,17 @@ impl luminol_core::Window for Window { ) .clicked(); if clicked { - config.project.data_format = self.selected_data_format; - // TODO add conversion logic + let progress = Progress::default(); + let future = convert_project( + config, + self.selected_data_format, + update_state.data, + update_state.filesystem, + progress.clone(), + ) + .unwrap(); //TODO handle + let promise = poll_promise::Promise::spawn_async(future); + self.convert = Some(Convert { promise, progress }); } } @@ -187,6 +313,41 @@ impl luminol_core::Window for Window { }); }); + if let Some(convert) = self.convert.take() { + let modal = egui_modal::Modal::new(ctx, "converting_project_modal"); + modal.show(|ui| { + modal.title(ui, "Converting Project..."); + + let map_infos = update_state.data.map_infos(); + let map_count = map_infos.data.len(); + + let progress = convert.progress.0.load(Ordering::Relaxed); + let map_id = convert.progress.1.load(Ordering::Relaxed); + + let progress_percent = (progress as f32 + 1.0) / map_count as f32; + ui.label(format!( + "Converting Map{map_id:0>3}.{}", + self.selected_data_format.extension() + )); + egui::ProgressBar::new(progress_percent) + .animate(true) + .ui(ui); + }); + match convert.promise.try_take() { + Ok(Ok(())) => {} + Ok(Err(err)) => { + luminol_core::error!(update_state.toasts, err) + } + Err(promise) => { + modal.open(); + self.convert = Some(Convert { + promise, + progress: convert.progress, + }); + } + } + } + if modified { update_state.modified.set(true); } From ab5b80ca63cc4978a22bfad5b5e3cdef65c8f8d7 Mon Sep 17 00:00:00 2001 From: Melody Madeline Lyons Date: Mon, 15 Jul 2024 14:15:38 -0700 Subject: [PATCH 2/7] Refactor code to be more async --- Cargo.lock | 1 + crates/core/src/data_cache/data_formats.rs | 77 ++++++ crates/filesystem/src/project.rs | 7 + crates/ui/Cargo.toml | 1 + crates/ui/src/windows/config_window.rs | 301 ++++++++++++++------- 5 files changed, 293 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 702705ad..8ea4fd1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3256,6 +3256,7 @@ dependencies = [ name = "luminol-ui" version = "0.4.0" dependencies = [ + "alox-48", "async-std", "camino", "color-eyre", diff --git a/crates/core/src/data_cache/data_formats.rs b/crates/core/src/data_cache/data_formats.rs index ba65c29f..16e306a6 100644 --- a/crates/core/src/data_cache/data_formats.rs +++ b/crates/core/src/data_cache/data_formats.rs @@ -197,6 +197,43 @@ impl Handler { } } + pub fn read_nil_padded_from(self, data: &[u8]) -> color_eyre::Result> + where + T: for<'de> alox_48::Deserialize<'de>, + T: ::serde::de::DeserializeOwned, + { + match self.format { + DataFormat::Marshal => { + let mut de = alox_48::Deserializer::new(data)?; + let mut trace = alox_48::path_to_error::Trace::default(); + let de = alox_48::path_to_error::Deserializer::new(&mut de, &mut trace); + + luminol_data::helpers::nil_padded_alox::deserialize_with(de) + .map_err(|error| format_traced_error(error, trace)) + } + DataFormat::Ron => { + let mut de = ron::de::Deserializer::from_bytes(data)?; + let mut track = serde_path_to_error::Track::new(); + let de = serde_path_to_error::Deserializer::new(&mut de, &mut track); + + luminol_data::helpers::nil_padded_serde::deserialize(de).map_err(|inner| { + let error = serde_path_to_error::Error::new(track.path(), inner); + format_path_to_error(error) + }) + } + DataFormat::Json => { + let mut de = serde_json::de::Deserializer::from_slice(data); + let mut track = serde_path_to_error::Track::new(); + let de = serde_path_to_error::Deserializer::new(&mut de, &mut track); + + luminol_data::helpers::nil_padded_serde::deserialize(de).map_err(|inner| { + let error = serde_path_to_error::Error::new(track.path(), inner); + format_path_to_error(error) + }) + } + } + } + pub fn write_nil_padded( self, data: &[T], @@ -249,6 +286,46 @@ impl Handler { Ok(()) } + pub fn write_nil_padded_to(self, data: &[T], buffer: &mut Vec) -> color_eyre::Result<()> + where + T: ::serde::Serialize, + T: alox_48::Serialize, + { + match self.format { + DataFormat::Marshal => { + let mut trace = alox_48::path_to_error::Trace::new(); + let mut ser = alox_48::Serializer::new(); + let trace_ser = alox_48::path_to_error::Serializer::new(&mut ser, &mut trace); + + luminol_data::helpers::nil_padded_alox::serialize_with(data, trace_ser) + .map_err(|error| format_traced_error(error, trace))?; + buffer.extend_from_slice(&ser.output); + } + DataFormat::Json => { + let mut track = serde_path_to_error::Track::new(); + let mut ser = serde_json::Serializer::new(buffer); + let ser = serde_path_to_error::Serializer::new(&mut ser, &mut track); + + luminol_data::helpers::nil_padded_serde::serialize(data, ser).map_err(|inner| { + let error = serde_path_to_error::Error::new(track.path(), inner); + format_path_to_error(error) + })?; + } + DataFormat::Ron => { + let mut track = serde_path_to_error::Track::new(); + let mut ser = ron::Serializer::new(buffer, None)?; + let ser = serde_path_to_error::Serializer::new(&mut ser, &mut track); + + luminol_data::helpers::nil_padded_serde::serialize(data, ser).map_err(|inner| { + let error = serde_path_to_error::Error::new(track.path(), inner); + format_path_to_error(error) + })?; + } + } + + Ok(()) + } + pub fn remove_file( self, filesystem: &impl luminol_filesystem::FileSystem, diff --git a/crates/filesystem/src/project.rs b/crates/filesystem/src/project.rs index bdb53d07..73d1f39a 100644 --- a/crates/filesystem/src/project.rs +++ b/crates/filesystem/src/project.rs @@ -65,6 +65,13 @@ impl FileSystem { pub fn unload_project(&mut self) { *self = FileSystem::Unloaded; } + + pub fn rebuild_path_cache(&mut self) { + let FileSystem::Loaded { filesystem, .. } = self else { + return; + }; + filesystem.rebuild(); + } } // Not platform specific diff --git a/crates/ui/Cargo.toml b/crates/ui/Cargo.toml index 74373f65..71922831 100644 --- a/crates/ui/Cargo.toml +++ b/crates/ui/Cargo.toml @@ -63,6 +63,7 @@ wgpu.workspace = true murmur3.workspace = true indexmap = "2.2.6" +alox-48.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] luminol-term = { version = "0.4.0", path = "../term/" } diff --git a/crates/ui/src/windows/config_window.rs b/crates/ui/src/windows/config_window.rs index 85c36c19..c86a8c23 100644 --- a/crates/ui/src/windows/config_window.rs +++ b/crates/ui/src/windows/config_window.rs @@ -24,7 +24,8 @@ use async_std::io::{ReadExt, WriteExt}; use egui::Widget; -use itertools::Itertools; +use luminol_core::data_formats::Handler as FormatHandler; +use luminol_data::rpg; use luminol_filesystem::{FileSystem, OpenFlags}; use std::sync::atomic::{AtomicUsize, Ordering}; use strum::IntoEnumIterator; @@ -36,9 +37,8 @@ pub struct Window { struct Convert { promise: poll_promise::Promise>, - progress: Progress, + converting: Converting, } -type Progress = std::sync::Arc<(AtomicUsize, AtomicUsize)>; impl Window { pub fn new(config: &luminol_config::project::Config) -> Self { @@ -49,110 +49,212 @@ impl Window { } } +type Converting = std::sync::Arc<(AtomicUsize, AtomicUsize)>; + +const CONVERTING_ACTORS: usize = 0; +const CONVERTING_ANIMATIONS: usize = 1; +const CONVERTING_ARMORS: usize = 2; +const CONVERTING_CLASSES: usize = 3; +const CONVERTING_COMMON_EVENTS: usize = 4; +const CONVERTING_ENEMIES: usize = 5; +const CONVERTING_ITEMS: usize = 6; +const CONVERTING_SKILLS: usize = 7; +const CONVERTING_STATES: usize = 8; +const CONVERTING_TILESETS: usize = 9; +const CONVERTING_TROOPS: usize = 10; +const CONVERTING_WEAPONS: usize = 11; +const CONVERTING_SCRIPTS: usize = 12; +const CONVERTING_SYSTEM: usize = 13; +const CONVERTING_MAPINFOS: usize = 14; + +fn converting_to_string( + converting: usize, + map_id: usize, + selected_data_format: luminol_config::DataFormat, +) -> String { + let text = match converting { + CONVERTING_ACTORS => "Actors", + CONVERTING_ANIMATIONS => "Animations", + CONVERTING_ARMORS => "Armors", + CONVERTING_CLASSES => "Classes", + CONVERTING_COMMON_EVENTS => "CommonEvents", + CONVERTING_ENEMIES => "Enemies", + CONVERTING_ITEMS => "Items", + CONVERTING_SKILLS => "Skills", + CONVERTING_STATES => "States", + CONVERTING_TILESETS => "Tilesets", + CONVERTING_TROOPS => "Troops", + CONVERTING_WEAPONS => "Weapons", + + CONVERTING_SCRIPTS => "Scripts", + CONVERTING_SYSTEM => "System", + CONVERTING_MAPINFOS => "MapInfos", + _ => { + return format!("Map{map_id:0>3}.{}", selected_data_format.extension()); + } + }; + format!("{}.{}", text, selected_data_format.extension()) +} + const FORMAT_WARNING: &str = "Luminol will need to convert your project.\nThis is not 100% safe yet, make backups!\nPress OK to continue."; +// Mostly async, opening files is not however. +// We should probably provide async fns for that +async fn convert_nil_padded( + from: FormatHandler, + to: FormatHandler, + read_buf: &mut Vec, + write_buf: &mut Vec, + filename: &str, + host: &luminol_filesystem::host::FileSystem, +) -> color_eyre::Result> +where + T: ::serde::de::DeserializeOwned + serde::Serialize, + T: for<'de> alox_48::Deserialize<'de> + alox_48::Serialize, +{ + read_buf.clear(); + write_buf.clear(); + + let mut file = host.open_file(from.path_for(filename), OpenFlags::Read)?; + file.read_to_end(read_buf).await?; + + let data = from.read_nil_padded_from::(read_buf)?; + + to.write_nil_padded_to(&data, write_buf)?; + + let mut file = host.open_file( + to.path_for(filename), + OpenFlags::Write | OpenFlags::Truncate | OpenFlags::Create, + )?; + file.write_all(write_buf).await?; + + from.remove_file(host, filename)?; + + Ok(data) +} + +async fn convert_regular( + from: FormatHandler, + to: FormatHandler, + read_buf: &mut Vec, + write_buf: &mut Vec, + filename: &str, + host: &luminol_filesystem::host::FileSystem, +) -> color_eyre::Result +where + T: ::serde::de::DeserializeOwned + serde::Serialize, + T: for<'de> alox_48::Deserialize<'de> + alox_48::Serialize, +{ + read_buf.clear(); + write_buf.clear(); + + let mut file = host.open_file(from.path_for(filename), OpenFlags::Read)?; + file.read_to_end(read_buf).await?; + + let data = from.read_data_from::(read_buf)?; + + to.write_data_to(&data, write_buf)?; + + let mut map_file = host.open_file( + to.path_for(filename), + OpenFlags::Write | OpenFlags::Truncate | OpenFlags::Create, + )?; + map_file.write_all(write_buf).await?; + + from.remove_file(host, filename)?; + + Ok(data) +} + fn convert_project( config: &mut luminol_config::project::Config, selected_data_format: luminol_config::DataFormat, - data_cache: &mut luminol_core::Data, - filesystem: &mut luminol_filesystem::project::FileSystem, - progress: Progress, -) -> color_eyre::Result>> { - let from_handler = luminol_core::data_formats::Handler::new(config.project.data_format); - let to_handler = luminol_core::data_formats::Handler::new(selected_data_format); + filesystem: &luminol_filesystem::project::FileSystem, + converting: Converting, +) -> impl std::future::Future> { + let from = FormatHandler::new(config.project.data_format); + let to = FormatHandler::new(selected_data_format); + // TODO handle errors let pretty_config = ron::ser::PrettyConfig::new() .struct_names(true) .enumerate_arrays(true); config.project.data_format = selected_data_format; - let project_config = ron::ser::to_string_pretty(&config.project, pretty_config)?; - filesystem.write(".luminol/config", project_config)?; - - to_handler.write_nil_padded(&data_cache.actors().data, filesystem, "Actors")?; - from_handler.remove_file(filesystem, "Actors")?; + let project_config = ron::ser::to_string_pretty(&config.project, pretty_config).unwrap(); + filesystem.write(".luminol/config", project_config).unwrap(); - to_handler.write_nil_padded(&data_cache.animations().data, filesystem, "Animations")?; - from_handler.remove_file(filesystem, "Animations")?; + let host = filesystem.host().unwrap(); // This bypasses the path cache (which is BAD!) so we will need to regen it later + let scripts_filename = config.project.scripts_path.clone(); - to_handler.write_nil_padded(&data_cache.armors().data, filesystem, "Armors")?; - from_handler.remove_file(filesystem, "Armors")?; - - to_handler.write_nil_padded(&data_cache.classes().data, filesystem, "Classes")?; - from_handler.remove_file(filesystem, "Classes")?; + async move { + let mut read_buf = Vec::new(); + let mut write_buf = Vec::::new(); - to_handler.write_nil_padded(&data_cache.common_events().data, filesystem, "CommonEvents")?; - from_handler.remove_file(filesystem, "CommonEvents")?; + let host = &host; + let read_buf = &mut read_buf; + let write_buf = &mut write_buf; - to_handler.write_nil_padded(&data_cache.enemies().data, filesystem, "Enemies")?; - from_handler.remove_file(filesystem, "Enemies")?; + let (converting_progress, converting_map_id) = &*converting; - to_handler.write_nil_padded(&data_cache.items().data, filesystem, "Items")?; - from_handler.remove_file(filesystem, "Items")?; + // FIXME: have some kind of trait system to determine filenames rather than hardcoding them like this + converting_progress.store(CONVERTING_ACTORS, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "Actors", host).await?; - to_handler.write_nil_padded(&data_cache.skills().data, filesystem, "Skills")?; - from_handler.remove_file(filesystem, "Skills")?; + converting_progress.store(CONVERTING_ANIMATIONS, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "Animations", host) + .await?; - to_handler.write_nil_padded(&data_cache.states().data, filesystem, "States")?; - from_handler.remove_file(filesystem, "States")?; + converting_progress.store(CONVERTING_ARMORS, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "Armors", host).await?; - to_handler.write_nil_padded(&data_cache.tilesets().data, filesystem, "Tilesets")?; - from_handler.remove_file(filesystem, "Tilesets")?; + converting_progress.store(CONVERTING_CLASSES, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "Classes", host).await?; - to_handler.write_nil_padded(&data_cache.troops().data, filesystem, "Troops")?; - from_handler.remove_file(filesystem, "Troops")?; + converting_progress.store(CONVERTING_COMMON_EVENTS, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "CommonEvents", host) + .await?; - to_handler.write_nil_padded(&data_cache.weapons().data, filesystem, "Weapons")?; - from_handler.remove_file(filesystem, "Weapons")?; + converting_progress.store(CONVERTING_ENEMIES, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "Enemies", host).await?; - // special handling - to_handler.write_data( - &data_cache.scripts().data, - filesystem, - &config.project.scripts_path, - )?; - from_handler.remove_file(filesystem, &config.project.scripts_path)?; + converting_progress.store(CONVERTING_ITEMS, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "Items", host).await?; - to_handler.write_data(&*data_cache.system(), filesystem, "System")?; - from_handler.remove_file(filesystem, "System")?; + converting_progress.store(CONVERTING_SKILLS, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "Skills", host).await?; - let mapinfos = data_cache.map_infos(); - to_handler.write_data(&mapinfos.data, filesystem, "MapInfos")?; - from_handler.remove_file(filesystem, "MapInfos")?; + converting_progress.store(CONVERTING_STATES, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "States", host).await?; - let map_ids = mapinfos.data.keys().copied().collect_vec(); - let host = filesystem.host().unwrap(); + converting_progress.store(CONVERTING_TILESETS, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "Tilesets", host).await?; - let fut = async move { - let mut read_buf = Vec::new(); - let mut write_buf = Vec::::new(); - for (index, map_id) in map_ids.into_iter().enumerate() { - progress.0.store(index, Ordering::Relaxed); - progress.1.store(map_id, Ordering::Relaxed); + converting_progress.store(CONVERTING_TROOPS, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "Troops", host).await?; - read_buf.clear(); - write_buf.clear(); - let map_filename = format!("Map{map_id:0>3}"); + converting_progress.store(CONVERTING_WEAPONS, Ordering::Relaxed); + convert_nil_padded::(from, to, read_buf, write_buf, "Weapons", host).await?; - let mut map_file = - host.open_file(from_handler.path_for(&map_filename), OpenFlags::Read)?; - map_file.read_to_end(&mut read_buf).await?; + converting_progress.store(CONVERTING_SCRIPTS, Ordering::Relaxed); + convert_regular::>(from, to, read_buf, write_buf, &scripts_filename, host) + .await?; - let map: luminol_data::rpg::Map = from_handler.read_data_from(&read_buf)?; + converting_progress.store(CONVERTING_SYSTEM, Ordering::Relaxed); + convert_regular::(from, to, read_buf, write_buf, "System", host).await?; - to_handler.write_data_to(&map, &mut write_buf)?; + converting_progress.store(CONVERTING_MAPINFOS, Ordering::Relaxed); + let mapinfos: std::collections::HashMap = + convert_regular(from, to, read_buf, write_buf, "MapInfos", host).await?; - let mut map_file = host.open_file( - to_handler.path_for(&map_filename), - OpenFlags::Write | OpenFlags::Truncate | OpenFlags::Create, - )?; - map_file.write_all(&write_buf).await?; + for (index, map_id) in mapinfos.keys().copied().enumerate() { + converting_progress.store(CONVERTING_MAPINFOS + index, Ordering::Relaxed); + converting_map_id.store(map_id, Ordering::Relaxed); - from_handler.remove_file(&host, &map_filename)?; + let map_filename = format!("Map{map_id:0>3}"); + convert_regular::(from, to, read_buf, write_buf, &map_filename, host).await?; } Ok(()) - }; - - Ok(fut) + } } impl luminol_core::Window for Window { @@ -243,17 +345,18 @@ impl luminol_core::Window for Window { ) .clicked(); if clicked { - let progress = Progress::default(); + let converting = Converting::default(); let future = convert_project( config, self.selected_data_format, - update_state.data, update_state.filesystem, - progress.clone(), - ) - .unwrap(); //TODO handle + converting.clone(), + ); let promise = poll_promise::Promise::spawn_async(future); - self.convert = Some(Convert { promise, progress }); + self.convert = Some(Convert { + promise, + converting, + }); } } @@ -321,29 +424,39 @@ impl luminol_core::Window for Window { let map_infos = update_state.data.map_infos(); let map_count = map_infos.data.len(); - let progress = convert.progress.0.load(Ordering::Relaxed); - let map_id = convert.progress.1.load(Ordering::Relaxed); + let current_progress = convert.converting.0.load(Ordering::Relaxed); + let current_map_id = convert.converting.1.load(Ordering::Relaxed); + + let total = CONVERTING_MAPINFOS + map_count + 1; + let progress = (current_progress + 2) as f32 / total as f32; + + let current_text = converting_to_string( + current_progress, + current_map_id, + self.selected_data_format, + ); - let progress_percent = (progress as f32 + 1.0) / map_count as f32; ui.label(format!( - "Converting Map{map_id:0>3}.{}", - self.selected_data_format.extension() + "Converting {current_text} {}/{total}", + current_progress + 2 )); - egui::ProgressBar::new(progress_percent) - .animate(true) - .ui(ui); + egui::ProgressBar::new(progress).animate(true).ui(ui); }); match convert.promise.try_take() { - Ok(Ok(())) => {} + Ok(Ok(())) => { + // we've drastically edited the data folder, so the path cache needs to be rebuilt + update_state.filesystem.rebuild_path_cache(); + } Ok(Err(err)) => { - luminol_core::error!(update_state.toasts, err) + luminol_core::error!(update_state.toasts, err); + luminol_core::warn!( + update_state.toasts, + "WARNING: Your project may be corrupted!" + ); } Err(promise) => { modal.open(); - self.convert = Some(Convert { - promise, - progress: convert.progress, - }); + self.convert = Some(Convert { promise, ..convert }); } } } From 34dacf15635c499daef689bd67d69fe681927d55 Mon Sep 17 00:00:00 2001 From: Melody Madeline Lyons Date: Mon, 15 Jul 2024 14:29:39 -0700 Subject: [PATCH 3/7] Fix wasm compile error --- .cargo/config.toml | 3 +++ .cargo/config.toml.bak | 29 ++++++++++++++++++++++++++ crates/ui/src/windows/config_window.rs | 3 +++ 3 files changed, 35 insertions(+) create mode 100644 .cargo/config.toml.bak diff --git a/.cargo/config.toml b/.cargo/config.toml index 3df6fe5c..a4d4454a 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -27,3 +27,6 @@ rustflags = [ [env] LUMINOL_ASSETS_PATH = { value = "assets", relative = true } +LUMINOL_VERSION = { value = "ab5b80ca-modified", force = true } +[unstable] +build-std = ["std", "panic_abort"] diff --git a/.cargo/config.toml.bak b/.cargo/config.toml.bak new file mode 100644 index 00000000..3df6fe5c --- /dev/null +++ b/.cargo/config.toml.bak @@ -0,0 +1,29 @@ +# Possibly enable -Zshare-generics=y? + +[target.x86_64-pc-windows-msvc] +linker = "rust-lld" +rustflags = ["-Z", "threads=8"] + +[target.x86_64-unknown-linux-gnu] +rustflags = [ + "-C", + "linker=clang", + "-C", + "link-arg=-fuse-ld=mold", + "-Z", + "threads=8", +] + +[target.'cfg(target_arch = "wasm32")'] +rustflags = [ + "--cfg=web_sys_unstable_apis", + "-C", + "target-feature=+atomics,+bulk-memory,+mutable-globals", + "-C", + "link-arg=--max-memory=4294967296", + "-Z", + "threads=8", +] + +[env] +LUMINOL_ASSETS_PATH = { value = "assets", relative = true } diff --git a/crates/ui/src/windows/config_window.rs b/crates/ui/src/windows/config_window.rs index c86a8c23..eda1d14b 100644 --- a/crates/ui/src/windows/config_window.rs +++ b/crates/ui/src/windows/config_window.rs @@ -352,7 +352,10 @@ impl luminol_core::Window for Window { update_state.filesystem, converting.clone(), ); + #[cfg(not(target_arch = "wasm32"))] let promise = poll_promise::Promise::spawn_async(future); + #[cfg(target_arch = "wasm32")] + let promise = poll_promise::Promise::spawn_local(future); self.convert = Some(Convert { promise, converting, From 07a13ece19dc95dd3574ac332973426dcc753f3e Mon Sep 17 00:00:00 2001 From: Melody Madeline Lyons Date: Mon, 15 Jul 2024 14:39:33 -0700 Subject: [PATCH 4/7] Oops --- .cargo/config.toml | 3 --- .cargo/config.toml.bak | 29 ----------------------------- 2 files changed, 32 deletions(-) delete mode 100644 .cargo/config.toml.bak diff --git a/.cargo/config.toml b/.cargo/config.toml index a4d4454a..3df6fe5c 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -27,6 +27,3 @@ rustflags = [ [env] LUMINOL_ASSETS_PATH = { value = "assets", relative = true } -LUMINOL_VERSION = { value = "ab5b80ca-modified", force = true } -[unstable] -build-std = ["std", "panic_abort"] diff --git a/.cargo/config.toml.bak b/.cargo/config.toml.bak deleted file mode 100644 index 3df6fe5c..00000000 --- a/.cargo/config.toml.bak +++ /dev/null @@ -1,29 +0,0 @@ -# Possibly enable -Zshare-generics=y? - -[target.x86_64-pc-windows-msvc] -linker = "rust-lld" -rustflags = ["-Z", "threads=8"] - -[target.x86_64-unknown-linux-gnu] -rustflags = [ - "-C", - "linker=clang", - "-C", - "link-arg=-fuse-ld=mold", - "-Z", - "threads=8", -] - -[target.'cfg(target_arch = "wasm32")'] -rustflags = [ - "--cfg=web_sys_unstable_apis", - "-C", - "target-feature=+atomics,+bulk-memory,+mutable-globals", - "-C", - "link-arg=--max-memory=4294967296", - "-Z", - "threads=8", -] - -[env] -LUMINOL_ASSETS_PATH = { value = "assets", relative = true } From e7b88665700b435e7d370ef044377eaa1e6d4b85 Mon Sep 17 00:00:00 2001 From: Melody Madeline Lyons Date: Mon, 15 Jul 2024 14:50:22 -0700 Subject: [PATCH 5/7] Actually deserialize/serialize parameter type now --- crates/data/src/helpers/parameter_type.rs | 47 +++++++++++++++++++---- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/crates/data/src/helpers/parameter_type.rs b/crates/data/src/helpers/parameter_type.rs index 169cf2e0..48fc206b 100644 --- a/crates/data/src/helpers/parameter_type.rs +++ b/crates/data/src/helpers/parameter_type.rs @@ -22,6 +22,8 @@ // terms of the Steamworks API by Valve Corporation, the licensors of this // Program grant you additional permission to convey the resulting work. +use alox_48::Value; + use crate::rgss_structs::{Color, Tone}; use crate::shared::{AudioFile, MoveCommand, MoveRoute}; @@ -36,7 +38,7 @@ pub enum ParameterType { Color(Color), Tone(Tone), AudioFile(AudioFile), - Float(f32), + Float(f64), MoveRoute(MoveRoute), MoveCommand(MoveCommand), Array(Vec), @@ -48,15 +50,46 @@ pub enum ParameterType { // FIXME this really should be try_from and try_into impl From for ParameterType { - // This is a massive sore spot right now, so I'm not even bothering... - fn from(_value: alox_48::Value) -> Self { - ParameterType::None + fn from(value: alox_48::Value) -> Self { + match value { + Value::Nil => Self::None, + Value::Integer(v) => Self::Integer(v), + Value::Float(v) => Self::Float(v), + Value::String(v) => Self::String(String::from_utf8(v.data).unwrap()), + Value::Array(v) => Self::Array(v.into_iter().map(|v| v.into()).collect()), + Value::Bool(v) => Self::Bool(v), + Value::Userdata(userdata) => match userdata.class.as_str() { + "Color" => Self::Color(Color::from(userdata)), + "Tone" => Self::Tone(Tone::from(userdata)), + _ => panic!("Unsupported userdata type: {:#?}", userdata), + }, + Value::Object(alox_48::Object { ref class, .. }) => match class.as_str() { + "RPG::AudioFile" => Self::AudioFile(alox_48::from_value(&value).unwrap()), + "RPG::MoveRoute" => Self::MoveRoute(alox_48::from_value(&value).unwrap()), + "RPG::MoveCommand" => Self::MoveCommand(alox_48::from_value(&value).unwrap()), + _ => panic!("Unsupported object type: {:#?}", value), + }, + Value::Instance(i) => (*i.value).into(), + _ => panic!("Unsupported value type: {:#?}", value), + } } } impl From for alox_48::Value { - fn from(_value: ParameterType) -> Self { - alox_48::Value::Nil + fn from(value: ParameterType) -> Self { + match value { + ParameterType::None => Value::Nil, + ParameterType::Integer(v) => Value::Integer(v), + ParameterType::Float(v) => Value::Float(v), + ParameterType::String(v) => Value::String(v.into()), + ParameterType::Array(v) => Value::Array(v.into_iter().map(|v| v.into()).collect()), + ParameterType::Bool(v) => Value::Bool(v), + ParameterType::Color(v) => Value::Userdata(v.into()), + ParameterType::Tone(v) => Value::Userdata(v.into()), + ParameterType::AudioFile(v) => alox_48::to_value(v).unwrap(), + ParameterType::MoveRoute(v) => alox_48::to_value(v).unwrap(), + ParameterType::MoveCommand(v) => alox_48::to_value(v).unwrap(), + } } } @@ -153,7 +186,7 @@ variant_impl! { Color, Color, Tone, Tone, AudioFile, AudioFile, - Float, f32, + Float, f64, MoveRoute, MoveRoute, MoveCommand, MoveCommand, Array, Vec, From be5d04a05d91b3c81770590faeac5910b90c22e4 Mon Sep 17 00:00:00 2001 From: Melody Madeline Lyons Date: Mon, 15 Jul 2024 15:02:45 -0700 Subject: [PATCH 6/7] Add pretty print support --- crates/config/src/lib.rs | 8 +- crates/core/src/data_cache/data_formats.rs | 122 ++++++++++++++------- crates/ui/src/windows/config_window.rs | 5 + 3 files changed, 93 insertions(+), 42 deletions(-) diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index bc93daf9..e872cb17 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -29,17 +29,17 @@ pub enum DataFormat { #[strum(to_string = "Ruby Marshal")] Marshal, #[strum(to_string = "RON")] - Ron, + Ron { pretty: bool }, #[strum(to_string = "JSON")] - Json, + Json { pretty: bool }, } impl DataFormat { pub fn extension(self) -> &'static str { match self { Self::Marshal => "rxdata", - Self::Ron => "ron", - Self::Json => "json", + Self::Ron { .. } => "ron", + Self::Json { .. } => "json", } } } diff --git a/crates/core/src/data_cache/data_formats.rs b/crates/core/src/data_cache/data_formats.rs index 16e306a6..b60dd778 100644 --- a/crates/core/src/data_cache/data_formats.rs +++ b/crates/core/src/data_cache/data_formats.rs @@ -60,11 +60,11 @@ impl Handler { result.map_err(|(error, trace)| format_traced_error(error, trace)) } - DataFormat::Ron => { + DataFormat::Ron { .. } => { let mut de = ron::de::Deserializer::from_bytes(&data)?; serde_path_to_error::deserialize(&mut de).map_err(format_path_to_error) } - DataFormat::Json => { + DataFormat::Json { .. } => { let mut de = serde_json::de::Deserializer::from_slice(&data); serde_path_to_error::deserialize(&mut de).map_err(format_path_to_error) } @@ -83,11 +83,11 @@ impl Handler { result.map_err(|(error, trace)| format_traced_error(error, trace)) } - DataFormat::Ron => { + DataFormat::Ron { .. } => { let mut de = ron::de::Deserializer::from_bytes(data)?; serde_path_to_error::deserialize(&mut de).map_err(format_path_to_error) } - DataFormat::Json => { + DataFormat::Json { .. } => { let mut de = serde_json::de::Deserializer::from_slice(data); serde_path_to_error::deserialize(&mut de).map_err(format_path_to_error) } @@ -116,13 +116,20 @@ impl Handler { .map_err(|(error, trace)| format_traced_error(error, trace))?; file.write_all(&serializer.output)?; } - DataFormat::Ron => { - let mut ser = ron::Serializer::new(&mut file, None)?; + DataFormat::Ron { pretty } => { + let config = pretty.then(|| ron::ser::PrettyConfig::new().struct_names(true)); + let mut ser = + ron::Serializer::with_options(&mut file, config, ron::Options::default())?; serde_path_to_error::serialize(data, &mut ser)?; } - DataFormat::Json => { - let mut ser = serde_json::Serializer::new(&mut file); - serde_path_to_error::serialize(data, &mut ser)?; + DataFormat::Json { pretty } => { + if pretty { + let mut ser = serde_json::Serializer::pretty(&mut file); + serde_path_to_error::serialize(data, &mut ser)?; + } else { + let mut ser = serde_json::Serializer::new(&mut file); + serde_path_to_error::serialize(data, &mut ser)?; + } } }; @@ -141,13 +148,20 @@ impl Handler { .map_err(|(error, trace)| format_traced_error(error, trace))?; buffer.extend_from_slice(&serializer.output); } - DataFormat::Ron => { - let mut ser = ron::Serializer::new(buffer, None)?; + DataFormat::Ron { pretty } => { + let config = pretty.then(|| ron::ser::PrettyConfig::new().struct_names(true)); + let mut ser = + ron::Serializer::with_options(buffer, config, ron::Options::default())?; serde_path_to_error::serialize(data, &mut ser)?; } - DataFormat::Json => { - let mut ser = serde_json::Serializer::new(buffer); - serde_path_to_error::serialize(data, &mut ser)?; + DataFormat::Json { pretty } => { + if pretty { + let mut ser = serde_json::Serializer::pretty(buffer); + serde_path_to_error::serialize(data, &mut ser)?; + } else { + let mut ser = serde_json::Serializer::new(buffer); + serde_path_to_error::serialize(data, &mut ser)?; + } } }; @@ -174,7 +188,7 @@ impl Handler { luminol_data::helpers::nil_padded_alox::deserialize_with(de) .map_err(|error| format_traced_error(error, trace)) } - DataFormat::Ron => { + DataFormat::Ron { .. } => { let mut de = ron::de::Deserializer::from_bytes(&data)?; let mut track = serde_path_to_error::Track::new(); let de = serde_path_to_error::Deserializer::new(&mut de, &mut track); @@ -184,7 +198,7 @@ impl Handler { format_path_to_error(error) }) } - DataFormat::Json => { + DataFormat::Json { .. } => { let mut de = serde_json::de::Deserializer::from_slice(&data); let mut track = serde_path_to_error::Track::new(); let de = serde_path_to_error::Deserializer::new(&mut de, &mut track); @@ -211,7 +225,7 @@ impl Handler { luminol_data::helpers::nil_padded_alox::deserialize_with(de) .map_err(|error| format_traced_error(error, trace)) } - DataFormat::Ron => { + DataFormat::Ron { .. } => { let mut de = ron::de::Deserializer::from_bytes(data)?; let mut track = serde_path_to_error::Track::new(); let de = serde_path_to_error::Deserializer::new(&mut de, &mut track); @@ -221,7 +235,7 @@ impl Handler { format_path_to_error(error) }) } - DataFormat::Json => { + DataFormat::Json { .. } => { let mut de = serde_json::de::Deserializer::from_slice(data); let mut track = serde_path_to_error::Track::new(); let de = serde_path_to_error::Deserializer::new(&mut de, &mut track); @@ -259,19 +273,35 @@ impl Handler { .map_err(|error| format_traced_error(error, trace))?; file.write_all(&ser.output)?; } - DataFormat::Json => { + DataFormat::Json { pretty } => { let mut track = serde_path_to_error::Track::new(); - let mut ser = serde_json::Serializer::new(&mut file); - let ser = serde_path_to_error::Serializer::new(&mut ser, &mut track); - - luminol_data::helpers::nil_padded_serde::serialize(data, ser).map_err(|inner| { - let error = serde_path_to_error::Error::new(track.path(), inner); - format_path_to_error(error) - })?; + if pretty { + let mut ser = serde_json::Serializer::pretty(&mut file); + let ser = serde_path_to_error::Serializer::new(&mut ser, &mut track); + + luminol_data::helpers::nil_padded_serde::serialize(data, ser).map_err( + |inner| { + let error = serde_path_to_error::Error::new(track.path(), inner); + format_path_to_error(error) + }, + )?; + } else { + let mut ser = serde_json::Serializer::new(&mut file); + let ser = serde_path_to_error::Serializer::new(&mut ser, &mut track); + + luminol_data::helpers::nil_padded_serde::serialize(data, ser).map_err( + |inner| { + let error = serde_path_to_error::Error::new(track.path(), inner); + format_path_to_error(error) + }, + )?; + } } - DataFormat::Ron => { + DataFormat::Ron { pretty } => { let mut track = serde_path_to_error::Track::new(); - let mut ser = ron::Serializer::new(&mut file, None)?; + let config = pretty.then(|| ron::ser::PrettyConfig::new().struct_names(true)); + let mut ser = + ron::Serializer::with_options(&mut file, config, ron::Options::default())?; let ser = serde_path_to_error::Serializer::new(&mut ser, &mut track); luminol_data::helpers::nil_padded_serde::serialize(data, ser).map_err(|inner| { @@ -301,19 +331,35 @@ impl Handler { .map_err(|error| format_traced_error(error, trace))?; buffer.extend_from_slice(&ser.output); } - DataFormat::Json => { + DataFormat::Json { pretty } => { let mut track = serde_path_to_error::Track::new(); - let mut ser = serde_json::Serializer::new(buffer); - let ser = serde_path_to_error::Serializer::new(&mut ser, &mut track); - - luminol_data::helpers::nil_padded_serde::serialize(data, ser).map_err(|inner| { - let error = serde_path_to_error::Error::new(track.path(), inner); - format_path_to_error(error) - })?; + if pretty { + let mut ser = serde_json::Serializer::pretty(buffer); + let ser = serde_path_to_error::Serializer::new(&mut ser, &mut track); + + luminol_data::helpers::nil_padded_serde::serialize(data, ser).map_err( + |inner| { + let error = serde_path_to_error::Error::new(track.path(), inner); + format_path_to_error(error) + }, + )?; + } else { + let mut ser = serde_json::Serializer::new(buffer); + let ser = serde_path_to_error::Serializer::new(&mut ser, &mut track); + + luminol_data::helpers::nil_padded_serde::serialize(data, ser).map_err( + |inner| { + let error = serde_path_to_error::Error::new(track.path(), inner); + format_path_to_error(error) + }, + )?; + } } - DataFormat::Ron => { + DataFormat::Ron { pretty } => { let mut track = serde_path_to_error::Track::new(); - let mut ser = ron::Serializer::new(buffer, None)?; + let config = pretty.then(|| ron::ser::PrettyConfig::new().struct_names(true)); + let mut ser = + ron::Serializer::with_options(buffer, config, ron::Options::default())?; let ser = serde_path_to_error::Serializer::new(&mut ser, &mut track); luminol_data::helpers::nil_padded_serde::serialize(data, ser).map_err(|inner| { diff --git a/crates/ui/src/windows/config_window.rs b/crates/ui/src/windows/config_window.rs index eda1d14b..16e0b6ce 100644 --- a/crates/ui/src/windows/config_window.rs +++ b/crates/ui/src/windows/config_window.rs @@ -315,6 +315,11 @@ impl luminol_core::Window for Window { .changed(); } }); + if let luminol_config::DataFormat::Json { pretty } + | luminol_config::DataFormat::Ron { pretty } = &mut self.selected_data_format + { + ui.checkbox(pretty, "Pretty Print").on_hover_text("This will make the data files human-readable, but significantly larger!"); + } if self.selected_data_format != config.project.data_format { // add warning message about needing to edit every single data file From 436a648bee1af4db24f9d5565e388f8646f8bfaf Mon Sep 17 00:00:00 2001 From: Melody Madeline Lyons Date: Mon, 15 Jul 2024 19:27:39 -0700 Subject: [PATCH 7/7] Flush files --- crates/ui/src/windows/config_window.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/ui/src/windows/config_window.rs b/crates/ui/src/windows/config_window.rs index 16e0b6ce..405ae163 100644 --- a/crates/ui/src/windows/config_window.rs +++ b/crates/ui/src/windows/config_window.rs @@ -127,6 +127,7 @@ where OpenFlags::Write | OpenFlags::Truncate | OpenFlags::Create, )?; file.write_all(write_buf).await?; + file.flush().await?; from.remove_file(host, filename)?; @@ -155,11 +156,12 @@ where to.write_data_to(&data, write_buf)?; - let mut map_file = host.open_file( + let mut file = host.open_file( to.path_for(filename), OpenFlags::Write | OpenFlags::Truncate | OpenFlags::Create, )?; - map_file.write_all(write_buf).await?; + file.write_all(write_buf).await?; + file.flush().await?; from.remove_file(host, filename)?;