From 88f182fc1bffcd157bdda3ad2de2f13f5bc37828 Mon Sep 17 00:00:00 2001 From: 1borgy <149747415+1borgy@users.noreply.github.com> Date: Fri, 27 Jun 2025 13:04:02 -0400 Subject: [PATCH 01/23] update --- Cargo.toml | 3 +- crates/cascade-app/Cargo.toml | 2 +- crates/cascade-app/src/dashboard.rs | 44 +++++++++---- crates/cascade-app/src/theme/combo_box.rs | 5 ++ crates/cascade-app/src/theme/menu.rs | 33 ++++++++++ crates/cascade-app/src/theme/mod.rs | 4 ++ crates/cascade-app/src/theme/text_input.rs | 67 +++++++++++++++++++ crates/cascade-backend/Cargo.toml | 7 ++ crates/cascade-backend/src/lib.rs | 19 ++++++ crates/cascade-cli/Cargo.toml | 2 + crates/cascade-cli/src/main.rs | 46 ++++++++++++- crates/cascade-dump/src/lib.rs | 7 +- crates/cascade-qb/src/structure.rs | 2 +- crates/cascade-qb/src/value.rs | 2 +- crates/cascade-thugpro/Cargo.toml | 1 + crates/cascade-thugpro/src/backend.rs | 44 +++++++++++++ crates/cascade-thugpro/src/cas.rs | 57 +++++++--------- crates/cascade-thugpro/src/lib.rs | 1 + crates/cascade-thugpro/src/random.rs | 4 +- crates/cascade-wad/Cargo.toml | 9 +++ crates/cascade-wad/src/hed.rs | 76 ++++++++++++++++++++++ crates/cascade-wad/src/lib.rs | 20 ++++++ crates/cascade-wad/src/wad.rs | 43 ++++++++++++ 23 files changed, 440 insertions(+), 58 deletions(-) create mode 100644 crates/cascade-app/src/theme/combo_box.rs create mode 100644 crates/cascade-app/src/theme/menu.rs create mode 100644 crates/cascade-app/src/theme/text_input.rs create mode 100644 crates/cascade-backend/Cargo.toml create mode 100644 crates/cascade-backend/src/lib.rs create mode 100644 crates/cascade-thugpro/src/backend.rs create mode 100644 crates/cascade-wad/Cargo.toml create mode 100644 crates/cascade-wad/src/hed.rs create mode 100644 crates/cascade-wad/src/lib.rs create mode 100644 crates/cascade-wad/src/wad.rs diff --git a/Cargo.toml b/Cargo.toml index 6356128..0c5b943 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ cascade-lut = { path = "crates/cascade-lut" } cascade-qb = { path = "crates/cascade-qb" } cascade-save = { path = "crates/cascade-save" } cascade-thugpro = { path = "crates/cascade-thugpro" } +cascade-wad = { path = "crates/cascade-wad" } byteorder = "1.4.3" clap = { version = "4.5.16", features = ["derive"] } @@ -19,9 +20,9 @@ crc = "3.0.1" directories = "5.0.1" encoding_rs = "0.8.35" enum-iterator = "1.4.1" +env_logger = "0.11.6" fern = { version = "0.6.2", features = ["colored"] } filetime = "0.2.21" -hex-literal = "0.4.1" image = "0.24.0" indexmap = "2.7.0" log = "0.4.20" diff --git a/crates/cascade-app/Cargo.toml b/crates/cascade-app/Cargo.toml index 6e8850a..36debc4 100644 --- a/crates/cascade-app/Cargo.toml +++ b/crates/cascade-app/Cargo.toml @@ -8,6 +8,7 @@ name = "cascade" path = "src/main.rs" [dependencies] +cascade-backend = { workspace = true } cascade-qb = { workspace = true } cascade-save = { workspace = true } cascade-thugpro = { workspace = true } @@ -16,7 +17,6 @@ clap = { workspace = true } directories = { workspace = true } enum-iterator = { workspace = true } fern = { workspace = true } -hex-literal = { workspace = true } image = { workspace = true } indexmap = { workspace = true } log = { workspace = true } diff --git a/crates/cascade-app/src/dashboard.rs b/crates/cascade-app/src/dashboard.rs index 02460f6..e74f254 100644 --- a/crates/cascade-app/src/dashboard.rs +++ b/crates/cascade-app/src/dashboard.rs @@ -12,7 +12,7 @@ use cascade_thugpro as thugpro; use iced::{ alignment::Vertical, font::Weight, - widget::{button, checkbox, container, scrollable, text, tooltip}, + widget::{button, checkbox, combo_box, container, scrollable, text, tooltip}, Font, Length, Task, }; use indexmap::IndexMap; @@ -93,6 +93,8 @@ pub enum Message { Start, PreProcessDone(Result<(Arc, PathBuf)>), EntryProcessed(thugpro::Entry, Result<()>), + + ComboBoxSelected(String), } #[derive(Debug, Clone)] @@ -119,6 +121,9 @@ pub struct Dashboard { queue: IndexMap, warning_message: Option, + + combo_box_state: combo_box::State, + combo_box_selection: Option, } impl Dashboard { @@ -157,6 +162,8 @@ impl Dashboard { default_selection, components: Components { scales, trickset }, warning_message: None, + combo_box_state: combo_box::State::new(Vec::new()), + combo_box_selection: None, }; (dashboard, tasks) @@ -211,18 +218,21 @@ impl Dashboard { self.notify(format!("error loading source: {}", err)); (Task::none(), None) } - Message::LoadedCandidates(Ok(entries)) => { self.candidates = entries; + self.combo_box_state = combo_box::State::new( + self.candidates + .iter() + .map(|(entry, _)| entry.name.clone()) + .collect(), + ); (Task::none(), None) } Message::LoadedCandidates(Err(err)) => { self.notify(format!("error loading selections: {}", err)); (Task::none(), None) } - Message::PickSource => (Task::perform(pick_source(), Message::SourcePicked), None), - Message::SourcePicked(Some(path)) => match thugpro::Entry::at_path(path.clone()) { Ok(entry) => { self.source_entry = Some(entry.clone()); @@ -237,7 +247,6 @@ impl Dashboard { } }, Message::SourcePicked(None) => (Task::none(), None), - Message::ToggleSelectAll => { self.default_selection = !self.default_selection; @@ -253,24 +262,20 @@ impl Dashboard { )), ) } - Message::ToggleSelection(entry) => { if let Some(selected) = self.candidates.get_mut(&entry) { *selected = !*selected; } (Task::none(), Some(Event::SetSelections(self.selections()))) } - Message::ToggleTricksetComponent(selected) => { self.components.trickset = selected; (Task::none(), Some(Event::SetTrickset(selected))) } - Message::ToggleScalesComponent(selected) => { self.components.scales = selected; (Task::none(), Some(Event::SetScales(selected))) } - Message::Start => match &self.source { Some(source) => { if self.candidates.values().any(|selected| *selected) { @@ -362,6 +367,10 @@ impl Dashboard { (Task::none(), None) } + Message::ComboBoxSelected(value) => { + self.combo_box_selection = Some(value); + (Task::none(), None) + } } } @@ -470,7 +479,20 @@ impl Dashboard { .on_press_maybe(self.enabled.then_some(Message::PickSource)), ) .push(heading("from")) - .push(self.view_source_info()), + // .push(self.view_source_info()) + .push( + combo_box( + &self.combo_box_state, + "select a cas...", + self.combo_box_selection.as_ref(), + Message::ComboBoxSelected, + ) + .input_style(match &self.combo_box_selection { + Some(_) => theme::text_input::primary, + None => theme::text_input::error, + }) + .padding(10), + ), ) .push( checkbox("trickset", self.components.trickset) @@ -556,7 +578,7 @@ async fn pick_source() -> Option { async fn _load_source(entry: thugpro::Entry) -> Result { let save = save::Save::read(&mut entry.reader()?)?; - let cas = thugpro::Cas::try_from(save)?; + let cas = thugpro::Cas::try_from(&save)?; Ok(cas) } diff --git a/crates/cascade-app/src/theme/combo_box.rs b/crates/cascade-app/src/theme/combo_box.rs new file mode 100644 index 0000000..d46ae98 --- /dev/null +++ b/crates/cascade-app/src/theme/combo_box.rs @@ -0,0 +1,5 @@ +use iced::widget::combo_box::Catalog; + +use crate::Theme; + +impl Catalog for Theme {} diff --git a/crates/cascade-app/src/theme/menu.rs b/crates/cascade-app/src/theme/menu.rs new file mode 100644 index 0000000..eb0813a --- /dev/null +++ b/crates/cascade-app/src/theme/menu.rs @@ -0,0 +1,33 @@ +pub use iced::widget::overlay::menu::Style; +use iced::{ + widget::overlay::menu::{Catalog, StyleFn}, + Background, Border, +}; + +use crate::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> StyleFn<'a, Self> { + Box::new(primary) + } + + fn style(&self, class: &StyleFn<'_, Self>) -> Style { + class(self) + } +} + +pub fn primary(theme: &Theme) -> Style { + Style { + text_color: theme.text, + background: Background::Color(theme.background), + border: Border { + width: 1.0, + radius: 4.0.into(), + color: theme.secondary, + }, + selected_text_color: theme.text, + selected_background: Background::Color(theme.secondary.scale_alpha(0.4)), + } +} diff --git a/crates/cascade-app/src/theme/mod.rs b/crates/cascade-app/src/theme/mod.rs index 50ef0d8..366b5cf 100644 --- a/crates/cascade-app/src/theme/mod.rs +++ b/crates/cascade-app/src/theme/mod.rs @@ -1,6 +1,10 @@ pub mod button; pub mod checkbox; +pub mod combo_box; pub mod container; +pub mod menu; pub mod scrollable; pub mod slider; pub mod text; +pub mod text_input; + diff --git a/crates/cascade-app/src/theme/text_input.rs b/crates/cascade-app/src/theme/text_input.rs new file mode 100644 index 0000000..f016faf --- /dev/null +++ b/crates/cascade-app/src/theme/text_input.rs @@ -0,0 +1,67 @@ +use iced::{ + widget::text_input::{Catalog, Status, Style, StyleFn}, + Background, Border, Color, +}; + +use crate::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(primary) + } + + fn style(&self, class: &Self::Class<'_>, status: Status) -> Style { + class(self, status) + } +} + +pub fn primary(theme: &Theme, status: Status) -> Style { + let active = Style { + background: Background::Color(theme.secondary.scale_alpha(0.4)), + border: Border { + radius: 4.0.into(), + width: 1.0, + color: theme.secondary, + }, + icon: theme.primary, + placeholder: theme.text.scale_alpha(0.5), + value: theme.text, + selection: theme.primary.scale_alpha(0.4), + }; + + match status { + Status::Active | Status::Hovered | Status::Focused { .. } => active, + Status::Disabled => Style { + background: Background::Color(theme.secondary.scale_alpha(0.4)), + placeholder: Color { + a: 0.4, + ..theme.secondary + }, + border: Border { + radius: 4.0.into(), + width: 0.0, + color: Color::TRANSPARENT, + // XXX Not currently displayed in application. + }, + ..active + }, + } +} + +pub fn error(theme: &Theme, status: Status) -> Style { + let primary = primary(theme, status); + + match status { + Status::Active | Status::Hovered | Status::Focused { .. } => Style { + border: Border { + radius: 4.0.into(), + width: 1.0, + color: theme.danger, + }, + ..primary + }, + Status::Disabled => primary, + } +} diff --git a/crates/cascade-backend/Cargo.toml b/crates/cascade-backend/Cargo.toml new file mode 100644 index 0000000..4bdb68f --- /dev/null +++ b/crates/cascade-backend/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "cascade-backend" +version = "0.0.1" +edition = "2024" + +[dependencies] +cascade-save = { workspace = true } diff --git a/crates/cascade-backend/src/lib.rs b/crates/cascade-backend/src/lib.rs new file mode 100644 index 0000000..8aa38b6 --- /dev/null +++ b/crates/cascade-backend/src/lib.rs @@ -0,0 +1,19 @@ +use cascade_save as save; + +pub trait Target { + type Entry; + type Error; + + fn name(&self, entry: &Self::Entry) -> impl AsRef; + fn list(&self) -> Result, Self::Error>; + fn read(&self, entry: &Self::Entry) -> Result; + fn write(&self, entry: &Self::Entry, save: &save::Save) -> Result<(), Self::Error>; +} + +pub trait Structure { + type Parsed; + type Error; + + fn parse(&self, save: &save::Save) -> Result; + fn modify(&self, save: &mut save::Save, transform: Self::Parsed) -> Result<(), Self::Error>; +} diff --git a/crates/cascade-cli/Cargo.toml b/crates/cascade-cli/Cargo.toml index 451b6b5..63c4c12 100644 --- a/crates/cascade-cli/Cargo.toml +++ b/crates/cascade-cli/Cargo.toml @@ -9,10 +9,12 @@ cascade-lut = { workspace = true } cascade-qb = { workspace = true } cascade-save = { workspace = true } cascade-thugpro = { workspace = true, features = ["serde"] } +cascade-wad = { workspace = true } clap = { workspace = true } color-eyre = { workspace = true } encoding_rs = { workspace = true } +env_logger = { workspace = true } rand = { workspace = true } ron = { workspace = true } serde = { workspace = true } diff --git a/crates/cascade-cli/src/main.rs b/crates/cascade-cli/src/main.rs index f342d3f..f19a992 100644 --- a/crates/cascade-cli/src/main.rs +++ b/crates/cascade-cli/src/main.rs @@ -1,9 +1,15 @@ -use std::{fmt::Debug, fs::File, io::Write, path::PathBuf}; +use std::{ + fmt::Debug, + fs::{self, File}, + io::{BufReader, Write}, + path::PathBuf, +}; use cascade_dump as dump; use cascade_lut::{self as lut, Lut}; use cascade_save::Save; use cascade_thugpro as thugpro; +use cascade_wad::{hed, wad}; use clap::{Args, Parser, Subcommand}; #[derive(Parser, Debug)] @@ -51,19 +57,34 @@ enum Command { #[arg(long)] female: bool, }, + Hed { + #[arg(long)] + input: PathBuf, + }, + Wad { + #[arg(long)] + hed: PathBuf, + + #[arg(long)] + wad: PathBuf, + + #[arg(long)] + output: PathBuf, + }, } #[derive(Debug, Args)] struct GlobalOpts {} fn main() -> color_eyre::Result<()> { - color_eyre::install()?; - let App { global: _global, command, } = App::parse(); + color_eyre::install()?; + env_logger::init(); + match command { Command::Dump { input, output } => { let entry = thugpro::Entry::at_path(&input)?; @@ -101,6 +122,25 @@ fn main() -> color_eyre::Result<()> { let entries = thugpro::entry::find_entries(input_dir).unwrap(); thugpro::random::randomize_bulk(&entries, output_dir, number, female)?; + Ok(()) + } + Command::Hed { input } => { + let file = fs::File::open(input)?; + let mut reader = BufReader::new(file); + + let file = hed::File::read(&mut reader)?; + for entry in file.entries { + println!("{:?}", entry); + } + + Ok(()) + } + Command::Wad { hed, wad, output } => { + let hed = hed::File::read(&mut BufReader::new(fs::File::open(hed)?))?; + let mut wad = fs::File::open(wad)?; + + wad::extract(hed, &mut wad, output)?; + Ok(()) } } diff --git a/crates/cascade-dump/src/lib.rs b/crates/cascade-dump/src/lib.rs index d684894..6851e63 100644 --- a/crates/cascade-dump/src/lib.rs +++ b/crates/cascade-dump/src/lib.rs @@ -4,9 +4,6 @@ use cascade_save as save; use encoding_rs::WINDOWS_1252; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] -pub struct Kind(); - #[derive(Serialize, Deserialize)] pub enum Id { None, @@ -82,7 +79,7 @@ impl Value { pub struct Symbol { #[serde(skip_serializing_if = "Option::is_none")] pub name: Option, - pub id: Id, + pub id: qb::Id, pub value: Value, } @@ -95,7 +92,7 @@ impl Symbol { qb::Id::Compress8(v) => lut.compress.lookup8(v).cloned(), qb::Id::Compress16(v) => lut.compress.lookup16(v).cloned(), }, - id: symbol.id.into(), + id: symbol.id.clone(), value: Value::new(&symbol.value, lut), } } diff --git a/crates/cascade-qb/src/structure.rs b/crates/cascade-qb/src/structure.rs index 6ccb104..dbc0d58 100644 --- a/crates/cascade-qb/src/structure.rs +++ b/crates/cascade-qb/src/structure.rs @@ -14,7 +14,7 @@ impl Structure { Self(symbols) } - pub fn read(reader: &mut impl Read) -> Result { + pub fn read(reader: &mut impl Read) -> Result { let mut symbols = vec![]; while { diff --git a/crates/cascade-qb/src/value.rs b/crates/cascade-qb/src/value.rs index 663c5da..a8209df 100644 --- a/crates/cascade-qb/src/value.rs +++ b/crates/cascade-qb/src/value.rs @@ -134,7 +134,7 @@ impl Value { Ok(()) } - pub fn try_as_structure(self) -> Result, Error> { + pub fn try_as_structure(&self) -> Result<&Box, Error> { match self { Value::Structure(value) => Ok(value), value => Err(Error::ExpectedValueType( diff --git a/crates/cascade-thugpro/Cargo.toml b/crates/cascade-thugpro/Cargo.toml index 7103f74..aa5e72b 100644 --- a/crates/cascade-thugpro/Cargo.toml +++ b/crates/cascade-thugpro/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.1" edition = "2024" [dependencies] +cascade-backend = { workspace = true } cascade-crc = { workspace = true } cascade-dump = { workspace = true } cascade-lut = { workspace = true } diff --git a/crates/cascade-thugpro/src/backend.rs b/crates/cascade-thugpro/src/backend.rs new file mode 100644 index 0000000..72cb340 --- /dev/null +++ b/crates/cascade-thugpro/src/backend.rs @@ -0,0 +1,44 @@ +use std::path::PathBuf; + +use cascade_backend as backend; +use cascade_save as save; + +use crate::{Cas, Entry, Error, entry::find_entries}; + +pub struct Backend { + saves_dir: PathBuf, +} + +impl backend::Target for Backend { + type Entry = Entry; + type Error = Error; + + fn list(&self) -> Result, Self::Error> { + find_entries(&self.saves_dir) + } + + fn name(&self, entry: &Self::Entry) -> impl AsRef { + &entry.name + } + + fn read(&self, entry: &Self::Entry) -> Result { + Ok(save::Save::read(&mut entry.reader()?)?) + } + + fn write(&self, entry: &Self::Entry, save: &save::Save) -> Result<(), Self::Error> { + Ok(save.write(&mut entry.writer()?)?) + } +} + +impl backend::Structure for Backend { + type Parsed = Cas; + type Error = Error; + + fn parse(&self, save: &save::Save) -> Result { + Ok(Cas::try_from(save)?) + } + + fn modify(&self, save: &mut save::Save, transform: Self::Parsed) -> Result<(), Self::Error> { + Ok(transform.modify(save)?) + } +} diff --git a/crates/cascade-thugpro/src/cas.rs b/crates/cascade-thugpro/src/cas.rs index c6f4568..0a8655b 100644 --- a/crates/cascade-thugpro/src/cas.rs +++ b/crates/cascade-thugpro/src/cas.rs @@ -3,8 +3,8 @@ use cascade_save as save; use crate::{Error, Result, id}; -fn expect_symbol(parent: &Box, id: qb::Id) -> Result { - Ok(parent.get(id).ok_or(Error::SymbolNotFound(id))?.clone()) +fn expect_symbol(parent: &Box, id: qb::Id) -> Result<&qb::Symbol> { + Ok(parent.get(id).ok_or(Error::SymbolNotFound(id))?) } fn expect_symbol_mut(parent: &mut Box, id: qb::Id) -> Result<&mut qb::Symbol> { @@ -12,7 +12,7 @@ fn expect_symbol_mut(parent: &mut Box, id: qb::Id) -> Result<&mut } // expect symbol and expect structure -fn expect_structure(parent: Box, id: qb::Id) -> Result> { +fn expect_structure(parent: &Box, id: qb::Id) -> Result<&Box> { let symbol = expect_symbol(&parent, id)?; Ok(symbol.value.try_as_structure()?) } @@ -73,13 +73,13 @@ pub struct Cas { pub data: Data, } -impl TryFrom for Cas { +impl TryFrom<&save::Save> for Cas { type Error = Error; - fn try_from(save: save::Save) -> Result { + fn try_from(save: &save::Save) -> Result { Ok(Self { - summary: Summary::try_from(save.summary)?, - data: Data::try_from(save.data)?, + summary: Summary::try_from(&save.summary)?, + data: Data::try_from(&save.data)?, }) } } @@ -119,10 +119,10 @@ impl Summary { } } -impl TryFrom> for Summary { +impl TryFrom<&Box> for Summary { type Error = Error; - fn try_from(summary: Box) -> Result { + fn try_from(summary: &Box) -> Result { Ok(Self { total_goals_complete: summary.get(id::TOTAL_GOALS_COMPLETE).cloned().into(), total_goals_possible: summary.get(id::TOTAL_GOALS_POSSIBLE).cloned().into(), @@ -142,19 +142,13 @@ pub struct Data { pub story_skater: StorySkater, } -impl TryFrom> for Data { +impl TryFrom<&Box> for Data { type Error = Error; - fn try_from(data: Box) -> Result { + fn try_from(data: &Box) -> Result { Ok(Self { - custom_skater: CustomSkater::try_from(expect_structure( - Box::clone(&data), - id::CUSTOM_SKATER, - )?)?, - story_skater: StorySkater::try_from(expect_structure( - Box::clone(&data), - id::STORY_SKATER, - )?)?, + custom_skater: CustomSkater::try_from(expect_structure(data, id::CUSTOM_SKATER)?)?, + story_skater: StorySkater::try_from(expect_structure(data, id::STORY_SKATER)?)?, }) } } @@ -177,10 +171,10 @@ pub struct CustomSkater { pub custom: Custom, } -impl TryFrom> for CustomSkater { +impl TryFrom<&Box> for CustomSkater { type Error = Error; - fn try_from(custom_skater: Box) -> Result { + fn try_from(custom_skater: &Box) -> Result { Ok(Self { custom: Custom::try_from(expect_structure(custom_skater, id::CUSTOM)?)?, }) @@ -202,15 +196,12 @@ pub struct Custom { pub info: Info, } -impl TryFrom> for Custom { +impl TryFrom<&Box> for Custom { type Error = Error; - fn try_from(custom: Box) -> Result { + fn try_from(custom: &Box) -> Result { Ok(Self { - appearance: Appearance::try_from(expect_structure( - Box::clone(&custom), - id::APPEARANCE, - )?)?, + appearance: Appearance::try_from(expect_structure(custom, id::APPEARANCE)?)?, info: Info::try_from(expect_structure(custom, id::INFO)?)?, }) } @@ -233,10 +224,10 @@ pub struct Info { pub specials: Item, } -impl TryFrom> for Info { +impl TryFrom<&Box> for Info { type Error = Error; - fn try_from(info: Box) -> Result { + fn try_from(info: &Box) -> Result { Ok(Self { trick_mapping: info.get(id::TRICK_MAPPING).cloned().into(), specials: info.get(id::SPECIALS).cloned().into(), @@ -420,10 +411,10 @@ impl Appearance { } } -impl TryFrom> for Appearance { +impl TryFrom<&Box> for Appearance { type Error = Error; - fn try_from(structure: Box) -> Result { + fn try_from(structure: &Box) -> Result { Ok(Self { body_shape: structure.get(id::BODY_SHAPE).cloned().into(), body: structure.get(id::BODY).cloned().into(), @@ -498,10 +489,10 @@ pub struct StorySkater { pub tricks: Item, } -impl TryFrom> for StorySkater { +impl TryFrom<&Box> for StorySkater { type Error = Error; - fn try_from(structure: Box) -> Result { + fn try_from(structure: &Box) -> Result { Ok(Self { tricks: structure.get(id::TRICKS).cloned().into(), }) diff --git a/crates/cascade-thugpro/src/lib.rs b/crates/cascade-thugpro/src/lib.rs index f0a699b..b8231b9 100644 --- a/crates/cascade-thugpro/src/lib.rs +++ b/crates/cascade-thugpro/src/lib.rs @@ -1,3 +1,4 @@ +pub mod backend; pub mod cas; pub mod entry; pub mod error; diff --git a/crates/cascade-thugpro/src/random.rs b/crates/cascade-thugpro/src/random.rs index 6b0d593..e22ab59 100644 --- a/crates/cascade-thugpro/src/random.rs +++ b/crates/cascade-thugpro/src/random.rs @@ -23,7 +23,7 @@ pub fn randomize( let base_entry = entries.choose(&mut rng).unwrap().clone(); let mut base_save = save::Save::read(&mut base_entry.reader()?)?; - let base_cas = Cas::try_from(base_save.clone())?; + let base_cas = Cas::try_from(&base_save)?; let cases = entries .into_iter() @@ -33,7 +33,7 @@ pub fn randomize( .ok() .and_then(|mut reader| save::Save::read(&mut reader).ok()) }) - .filter_map(|save| Cas::try_from(save).ok()) + .filter_map(|save| Cas::try_from(&save).ok()) .filter(|save| match save.summary.is_male { // Female cas cas::Item::Present(qb::Symbol { diff --git a/crates/cascade-wad/Cargo.toml b/crates/cascade-wad/Cargo.toml new file mode 100644 index 0000000..9cd6f8d --- /dev/null +++ b/crates/cascade-wad/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "cascade-wad" +version = "0.0.1" +edition = "2024" + +[dependencies] +byteorder = { workspace = true } +log = { workspace = true } +thiserror = { workspace = true } diff --git a/crates/cascade-wad/src/hed.rs b/crates/cascade-wad/src/hed.rs new file mode 100644 index 0000000..47faad4 --- /dev/null +++ b/crates/cascade-wad/src/hed.rs @@ -0,0 +1,76 @@ +use std::{fmt, io::Read}; + +use byteorder::{LittleEndian, ReadBytesExt}; + +use crate::Result; + +pub struct Entry { + pub offset: u32, + pub size: u32, + pub path: String, +} + +impl fmt::Debug for Entry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Entry {{ offset={:#08x}, size={:#04x}, path=\"{}\" }}", + self.offset, self.size, self.path + ) + } +} + +#[derive(Debug)] +pub struct File { + pub entries: Vec, +} + +impl File { + pub fn read(reader: &mut impl Read) -> Result { + let mut entries = Vec::new(); + + while { + match Entry::read(reader)? { + Some(entry) => { + entries.push(entry); + true + } + None => false, + } + } {} + + Ok(Self { entries }) + } +} + +impl Entry { + pub fn read(reader: &mut impl Read) -> Result> { + let offset = reader.read_u32::()?; + if offset == 0xFFFFFFFF { + Ok(None) + } else { + let size = reader.read_u32::()?; + + let path = Self::read_path(reader)?; + Ok(Some(Self { offset, size, path })) + } + } + + fn read_path(reader: &mut impl Read) -> Result { + let mut path = Vec::new(); + + while { + let mut buffer = [0; 4]; + reader.read_exact(&mut buffer)?; + + let path_bytes: Vec = buffer.into_iter().filter(|byte| *byte != 0).collect(); + let any_bytes_0 = path_bytes.len() < 4; + + path.extend(path_bytes); + + !any_bytes_0 + } {} + + Ok(str::from_utf8(&path[..])?.to_string()) + } +} diff --git a/crates/cascade-wad/src/lib.rs b/crates/cascade-wad/src/lib.rs new file mode 100644 index 0000000..6f0d373 --- /dev/null +++ b/crates/cascade-wad/src/lib.rs @@ -0,0 +1,20 @@ +use std::{io, result, str::Utf8Error}; +pub mod hed; +pub mod wad; + +#[derive(thiserror::Error, Debug, Clone)] +pub enum Error { + #[error("io error: {0}")] + Io(io::ErrorKind), + + #[error("utf8 error: {0}")] + Utf8(#[from] Utf8Error), +} + +impl From for Error { + fn from(value: io::Error) -> Self { + Self::Io(value.kind()) + } +} + +pub type Result = result::Result; diff --git a/crates/cascade-wad/src/wad.rs b/crates/cascade-wad/src/wad.rs new file mode 100644 index 0000000..1745e28 --- /dev/null +++ b/crates/cascade-wad/src/wad.rs @@ -0,0 +1,43 @@ +use std::{ + fs, + io::{Read, Seek, SeekFrom, Write}, + path::Path, +}; + +use crate::{Result, hed}; + +pub fn extract(hed: hed::File, wad: &mut fs::File, output_dir: impl AsRef) -> Result<()> { + let output_dir = output_dir.as_ref(); + fs::create_dir_all(output_dir)?; + + for entry in hed.entries { + match extract_entry(&entry, wad, output_dir) { + Ok(_) => { + log::info!("extracted entry {}", &entry.path); + } + Err(err) => { + log::warn!("error extracting entry {}: {}", &entry.path, err); + } + } + } + + Ok(()) +} + +fn extract_entry( + entry: &hed::Entry, + wad: &mut fs::File, + output_dir: impl AsRef, +) -> Result<()> { + let output_dir = output_dir.as_ref(); + let entry_path = output_dir.join(&entry.path); + let mut entry_file = fs::File::create(entry_path)?; + + let mut buf = vec![0; entry.size as usize]; + wad.seek(SeekFrom::Start(entry.offset as u64))?; + wad.read_exact(&mut buf)?; + + entry_file.write_all(&buf)?; + + Ok(()) +} From a8f78bb80a6d6456587a689fc45913a4a0874b5a Mon Sep 17 00:00:00 2001 From: ellie <149747415+1borgy@users.noreply.github.com> Date: Tue, 29 Jul 2025 18:35:25 -0400 Subject: [PATCH 02/23] fixup! update --- Cargo.toml | 3 ++ assets/lut/compress-thps4.ron | 1 + assets/lut/compress-thug.ron | 1 + crates/cascade-cli/Cargo.toml | 6 ++- crates/cascade-cli/src/main.rs | 67 ++++++++++++++++++++++++++++-- crates/cascade-thps4/Cargo.toml | 7 ++++ crates/cascade-thps4/src/lib.rs | 1 + crates/cascade-thps4/src/lut.rs | 7 ++++ crates/cascade-thug/Cargo.toml | 7 ++++ crates/cascade-thug/src/lib.rs | 1 + crates/cascade-thug/src/lut.rs | 7 ++++ crates/cascade-thugpro/src/dump.rs | 0 12 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 assets/lut/compress-thps4.ron create mode 100644 assets/lut/compress-thug.ron create mode 100644 crates/cascade-thps4/Cargo.toml create mode 100644 crates/cascade-thps4/src/lib.rs create mode 100644 crates/cascade-thps4/src/lut.rs create mode 100644 crates/cascade-thug/Cargo.toml create mode 100644 crates/cascade-thug/src/lib.rs create mode 100644 crates/cascade-thug/src/lut.rs delete mode 100644 crates/cascade-thugpro/src/dump.rs diff --git a/Cargo.toml b/Cargo.toml index 0c5b943..6c8ea40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,8 @@ cascade-dump = { path = "crates/cascade-dump" } cascade-lut = { path = "crates/cascade-lut" } cascade-qb = { path = "crates/cascade-qb" } cascade-save = { path = "crates/cascade-save" } +cascade-thps4 = { path = "crates/cascade-thps4" } +cascade-thug = { path = "crates/cascade-thug" } cascade-thugpro = { path = "crates/cascade-thugpro" } cascade-wad = { path = "crates/cascade-wad" } @@ -31,6 +33,7 @@ rfd = "0.12.1" ron = "0.8.1" serde = { version = "1.0.190", features = ["rc", "derive"] } serde_json = "1.0.140" +suppaftp = "^6" thiserror = "1.0.50" time = { version = "0.3.30", features = ["local-offset", "formatting"] } tokio = { version = "1.40.0", features = ["fs", "io-util"] } diff --git a/assets/lut/compress-thps4.ron b/assets/lut/compress-thps4.ron new file mode 100644 index 0000000..1236005 --- /dev/null +++ b/assets/lut/compress-thps4.ron @@ -0,0 +1 @@ +(compress8:["body_type","head","hat","hair","jaw","glasses","torso","legs","kneepads","elbowpads","backpack","shoes","boardup","boarddown","helmet","hat_logo","helmet_logo","front_logo","back_logo","accessories","chest_tattoo","back_tattoo","left_arm_tattoo","right_arm_tattoo","socks","left_leg_tattoo","right_leg_tattoo","special_item","special_item_2","skin","value","desc","h","s","v","use_default_hsv","height_scale","weight_scale","scale","scaling_mode","display_name","stance","pushstyle","profile","name","trickstyle","age","is_pro","hometown","is_locked","is_head_locked","points_available","air","hangtime","ollie","speed","spin","switch","rail_balance","lip_balance","manual_balance","sponsors","trick_mapping","default_trick_mapping","max_specials","specials","Air_CircleD","Air_CircleDL","Air_CircleDR","Air_CircleL","Air_CircleR","Air_CircleU","Air_CircleUL","Air_CircleUR","Air_D_D_Circle","Air_D_D_Square","Air_L_L_Circle","Air_L_L_Square","Air_R_R_Circle","Air_R_R_Square","Air_SquareD","Air_SquareDL","Air_SquareDR","Air_SquareL","Air_SquareR","Air_SquareU","Air_SquareUL","Air_SquareUR","Air_U_U_Circle","Air_U_U_Square","ExtraSlot1","ExtraSlot2","JumpSlot","Lip_TriangleD","Lip_TriangleDL","Lip_TriangleDL","Lip_TriangleDR","Lip_TriangleDR","Lip_TriangleL","Lip_TriangleR","Lip_TriangleU","Lip_TriangleUL","Lip_TriangleUL","Lip_TriangleUR","Lip_TriangleUR","SpAir_D_L_Circle","SpAir_D_L_Square","SpAir_D_R_Circle","SpAir_D_R_Square","SpAir_D_U_Circle","SpAir_D_U_Square","SpAir_L_D_Circle","SpAir_L_D_Square","SpAir_L_R_Circle","SpAir_L_R_Square","SpAir_L_U_Circle","SpAir_L_U_Square","SpAir_R_D_Circle","SpAir_R_D_Square","SpAir_R_L_Circle","SpAir_R_L_Square","SpAir_R_U_Circle","SpAir_R_U_Square","SpAir_U_D_Circle","SpAir_U_D_Square","SpAir_U_L_Circle","SpAir_U_L_Square","SpAir_U_R_Circle","SpAir_U_R_Square","SpGrind_D_L_Triangle","SpGrind_D_R_Triangle","SpGrind_D_U_Triangle","SpGrind_L_D_Triangle","SpGrind_L_R_Triangle","SpGrind_L_U_Triangle","SpGrind_R_D_Triangle","SpGrind_R_L_Triangle","SpGrind_R_U_Triangle","SpGrind_U_D_Triangle","SpGrind_U_L_Triangle","SpGrind_U_R_Triangle","SpLip_D_L_Triangle","SpLip_D_R_Triangle","SpLip_D_U_Triangle","SpLip_L_D_Triangle","SpLip_L_R_Triangle","SpLip_L_U_Triangle","SpLip_R_D_Triangle","SpLip_R_L_Triangle","SpLip_R_U_Triangle","SpLip_U_D_Triangle","SpLip_U_L_Triangle","SpLip_U_R_Triangle","SpLip_U_U_Triangle","SpMan_D_L_Triangle","SpMan_D_R_Triangle","SpMan_D_U_Triangle","SpMan_L_D_Triangle","SpMan_L_R_Triangle","SpMan_L_U_Triangle","SpMan_R_D_Triangle","SpMan_R_L_Triangle","SpMan_R_U_Triangle","SpMan_U_D_Triangle","SpMan_U_L_Triangle","SpMan_U_R_Triangle"],compress16:[]) diff --git a/assets/lut/compress-thug.ron b/assets/lut/compress-thug.ron new file mode 100644 index 0000000..85a296b --- /dev/null +++ b/assets/lut/compress-thug.ron @@ -0,0 +1 @@ +(compress8:["body_type","skater_m_head","skater_m_torso","skater_m_legs","skater_m_hair","skater_m_backpack","skater_m_jaw","kneepads","skater_m_socks","elbowpads","skater_f_head","skater_f_torso","skater_f_legs","skater_f_hair","skater_f_backpack","skater_f_kneepads","skater_f_socks","skater_f_elbowpads","part","accessories","chest_tattoo","back_tattoo","left_forearm_tattoo","right_forearm_tattoo","left_bicep_tattoo","left_leg_tattoo","right_leg_tattoo","use_default_scale","right_bicep_tattoo","skin","value","desc_id","h","s","v","use_default_hsv","height_scale","weight_scale","scale","scaling_mode","display_name","stance","pushstyle","profile","name","trickstyle","age","is_pro","hometown","is_locked","is_head_locked","points_available","air","run","ollie","speed","spin","switch","rail_balance","lip_balance","manual_balance","sponsors","trick_mapping","default_trick_mapping","max_specials","specials","Air_CircleD","Air_CircleDL","Air_CircleDR","Air_CircleL","Air_CircleR","Air_CircleU","Air_CircleUL","Air_CircleUR","Air_D_D_Circle","Air_D_D_Square","Air_L_L_Circle","Air_L_L_Square","Air_R_R_Circle","Air_R_R_Square","Air_SquareD","Air_SquareDL","Air_SquareDR","Air_SquareL","Air_SquareR","Air_SquareU","Air_SquareUL","Air_SquareUR","Air_U_U_Circle","Air_U_U_Square","ExtraSlot1","ExtraSlot2","JumpSlot","Lip_TriangleD","Lip_TriangleDL","Lip_TriangleDL","Lip_TriangleDR","Lip_TriangleDR","Lip_TriangleL","Lip_TriangleR","Lip_TriangleU","Lip_TriangleUL","Lip_TriangleUL","Lip_TriangleUR","Lip_TriangleUR","SpAir_D_L_Circle","SpAir_D_L_Square","SpAir_D_R_Circle","SpAir_D_R_Square","SpAir_D_U_Circle","SpAir_D_U_Square","SpAir_L_D_Circle","SpAir_L_D_Square","SpAir_L_R_Circle","SpAir_L_R_Square","SpAir_L_U_Circle","SpAir_L_U_Square","SpAir_R_D_Circle","SpAir_R_D_Square","SpAir_R_L_Circle","SpAir_R_L_Square","SpAir_R_U_Circle","SpAir_R_U_Square","SpAir_U_D_Circle","SpAir_U_D_Square","SpAir_U_L_Circle","SpAir_U_L_Square","SpAir_U_R_Circle","SpAir_U_R_Square","SpGrind_D_L_Triangle","SpGrind_D_R_Triangle","SpGrind_D_U_Triangle","SpGrind_L_D_Triangle","SpGrind_L_R_Triangle","SpGrind_L_U_Triangle","SpGrind_R_D_Triangle","SpGrind_R_L_Triangle","SpGrind_R_U_Triangle","SpGrind_U_D_Triangle","SpGrind_U_L_Triangle","SpGrind_U_R_Triangle","SpLip_D_L_Triangle","SpLip_D_R_Triangle","SpLip_D_U_Triangle","SpLip_L_D_Triangle","SpLip_L_R_Triangle","SpLip_L_U_Triangle","SpLip_R_D_Triangle","SpLip_R_L_Triangle","SpLip_R_U_Triangle","SpLip_U_D_Triangle","SpLip_U_L_Triangle","SpLip_U_R_Triangle","SpLip_U_U_Triangle","SpMan_D_L_Triangle","SpMan_D_R_Triangle","SpMan_D_U_Triangle","SpMan_L_D_Triangle","SpMan_L_R_Triangle","SpMan_L_U_Triangle","SpMan_R_D_Triangle","SpMan_R_L_Triangle","SpMan_R_U_Triangle","SpMan_U_D_Triangle","SpMan_U_L_Triangle","SpMan_U_R_Triangle","X","Y","Z","trickSlot","trickName","unassigned","uv_scale","uv_rot","uv_u","uv_v","sleeves","shoes","front_logo","back_logo","glasses","hat","helmet","accessories","hat_logo","helmet_logo","board","griptape","deck_graphic","cad_graphic","deck_layer1","deck_layer2","deck_layer3","deck_layer4","deck_layer5","head_tattoo","custom","headtop_bone_group","jaw_bone_group","nose_bone_group","head_bone_group","torso_bone_group","stomach_bone_group","upper_arm_bone_group","lower_arm_bone_group","hands_bone_group","upper_left_bone_group","lower_leg_bone_group","feet_bone_group","board_bone_group","object_scaling","regular","goofy","never_mongo","mongo_when_switch","always_mongo","street","vert","first_name","skater_index","default_appearance","is_male","flip_speed","on","trick","dur","Blend","from","percent","trickType","idletime","start","order","hold","backwards","deg_dir","left_eye","right_eye","nose","lips","width","height","GapName","GapCount","GapScore","SkaterStartPos","SkaterStartDir","level","valid","value","number","initials","win_record"],compress16:[]) diff --git a/crates/cascade-cli/Cargo.toml b/crates/cascade-cli/Cargo.toml index 63c4c12..31ac763 100644 --- a/crates/cascade-cli/Cargo.toml +++ b/crates/cascade-cli/Cargo.toml @@ -8,15 +8,19 @@ cascade-dump = { workspace = true } cascade-lut = { workspace = true } cascade-qb = { workspace = true } cascade-save = { workspace = true } -cascade-thugpro = { workspace = true, features = ["serde"] } +cascade-thug = { workspace = true } +cascade-thps4 = { workspace = true } +cascade-thugpro = { workspace = true } cascade-wad = { workspace = true } clap = { workspace = true } color-eyre = { workspace = true } encoding_rs = { workspace = true } +log = { workspace = true } env_logger = { workspace = true } rand = { workspace = true } ron = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } +suppaftp = { workspace = true } thiserror = { workspace = true } diff --git a/crates/cascade-cli/src/main.rs b/crates/cascade-cli/src/main.rs index f19a992..933300c 100644 --- a/crates/cascade-cli/src/main.rs +++ b/crates/cascade-cli/src/main.rs @@ -1,16 +1,22 @@ use std::{ fmt::Debug, fs::{self, File}, - io::{BufReader, Write}, + io::{BufReader, Read, Write}, path::PathBuf, + time::Duration, }; use cascade_dump as dump; use cascade_lut::{self as lut, Lut}; use cascade_save::Save; +use cascade_thps4 as thps4; +use cascade_thug as thug; use cascade_thugpro as thugpro; use cascade_wad::{hed, wad}; use clap::{Args, Parser, Subcommand}; +use color_eyre::install; +use serde::Serialize; +use suppaftp::FtpStream; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -22,6 +28,15 @@ struct App { command: Command, } +#[derive(clap::ValueEnum, Clone, Default, Debug, Serialize)] +#[serde(rename_all = "kebab-case")] +enum Game { + Thps4, + Thug, + #[default] + Thugpro, +} + #[derive(Debug, Subcommand)] enum Command { Dump { @@ -30,6 +45,9 @@ enum Command { #[arg(short, long)] output: PathBuf, + + #[arg(short, long)] + game: Game, }, Randomize { #[arg(long)] @@ -71,6 +89,10 @@ enum Command { #[arg(long)] output: PathBuf, }, + Ftp { + #[arg(long)] + host: String, + }, } #[derive(Debug, Args)] @@ -86,12 +108,20 @@ fn main() -> color_eyre::Result<()> { env_logger::init(); match command { - Command::Dump { input, output } => { + Command::Dump { + input, + output, + game, + } => { let entry = thugpro::Entry::at_path(&input)?; let save = Save::read(&mut entry.reader()?)?; let lut = Lut { checksum: lut::Checksum::load()?, - compress: thugpro::lut::load_compress()?, + compress: match game { + Game::Thps4 => thps4::lut::load_compress()?, + Game::Thug => thug::lut::load_compress()?, + Game::Thugpro => thugpro::lut::load_compress()?, + }, }; let dump = dump::Save::new(&save, &lut); @@ -141,6 +171,37 @@ fn main() -> color_eyre::Result<()> { wad::extract(hed, &mut wad, output)?; + Ok(()) + } + Command::Ftp { host } => { + fn list(ftp_stream: &mut FtpStream) -> color_eyre::Result> { + let output = ftp_stream.list(None)?; + log::info!("{}", output.join("\n")); + + let files: Vec = output + .iter() + .filter_map(|line| suppaftp::list::File::try_from(line.as_str()).ok()) + .collect(); + + for file in files.iter() { + log::info!("{:?}", file); + } + + Ok(files) + } + + let game_id = "BASLUS-20731"; + let mc_path = "/mc/0"; + let mut ftp_stream = FtpStream::connect(host)?; + ftp_stream.login("anonymous", "")?; + ftp_stream.cwd(mc_path)?; + + let files = list(&mut ftp_stream)?; + for file in files.iter().filter(|file| file.name().starts_with(game_id)) { + ftp_stream.cwd(format!("{}/{}", mc_path, file.name()))?; + list(&mut ftp_stream)?; + } + Ok(()) } } diff --git a/crates/cascade-thps4/Cargo.toml b/crates/cascade-thps4/Cargo.toml new file mode 100644 index 0000000..411d682 --- /dev/null +++ b/crates/cascade-thps4/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "cascade-thps4" +version = "0.0.1" +edition = "2024" + +[dependencies] +cascade-lut = { workspace = true } diff --git a/crates/cascade-thps4/src/lib.rs b/crates/cascade-thps4/src/lib.rs new file mode 100644 index 0000000..5189cd9 --- /dev/null +++ b/crates/cascade-thps4/src/lib.rs @@ -0,0 +1 @@ +pub mod lut; diff --git a/crates/cascade-thps4/src/lut.rs b/crates/cascade-thps4/src/lut.rs new file mode 100644 index 0000000..9d30e31 --- /dev/null +++ b/crates/cascade-thps4/src/lut.rs @@ -0,0 +1,7 @@ +use cascade_lut as lut; + +const COMPRESS_LUT_BYTES: &[u8] = include_bytes!("../../../assets/lut/compress-thps4.ron"); + +pub fn load_compress() -> lut::Result { + lut::Compress::from_bytes(COMPRESS_LUT_BYTES) +} diff --git a/crates/cascade-thug/Cargo.toml b/crates/cascade-thug/Cargo.toml new file mode 100644 index 0000000..6ce271c --- /dev/null +++ b/crates/cascade-thug/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "cascade-thug" +version = "0.0.1" +edition = "2024" + +[dependencies] +cascade-lut = { workspace = true } diff --git a/crates/cascade-thug/src/lib.rs b/crates/cascade-thug/src/lib.rs new file mode 100644 index 0000000..5189cd9 --- /dev/null +++ b/crates/cascade-thug/src/lib.rs @@ -0,0 +1 @@ +pub mod lut; diff --git a/crates/cascade-thug/src/lut.rs b/crates/cascade-thug/src/lut.rs new file mode 100644 index 0000000..9c0a9e4 --- /dev/null +++ b/crates/cascade-thug/src/lut.rs @@ -0,0 +1,7 @@ +use cascade_lut as lut; + +const COMPRESS_LUT_BYTES: &[u8] = include_bytes!("../../../assets/lut/compress-thug.ron"); + +pub fn load_compress() -> lut::Result { + lut::Compress::from_bytes(COMPRESS_LUT_BYTES) +} diff --git a/crates/cascade-thugpro/src/dump.rs b/crates/cascade-thugpro/src/dump.rs deleted file mode 100644 index e69de29..0000000 From 48bca7a86fa7ae786e131edc6fb0fac81251b894 Mon Sep 17 00:00:00 2001 From: ellie <149747415+1borgy@users.noreply.github.com> Date: Sat, 16 Aug 2025 13:05:52 -0400 Subject: [PATCH 03/23] fixup! fixup! update --- Cargo.toml | 2 + assets/lut/compress-thaw.ron | 1 + assets/saves/{ => thugpro}/2414.SKA | Bin assets/saves/{ => thugpro}/4fantasy.SKA | Bin assets/saves/{ => thugpro}/80thugg.SKA | Bin assets/saves/{ => thugpro}/999.SKA | Bin assets/saves/{ => thugpro}/AfroSpidey.SKA | Bin assets/saves/{ => thugpro}/ClassicGreen.SKA | Bin assets/saves/{ => thugpro}/Cus.SKA | Bin assets/saves/{ => thugpro}/Cust.SKA | Bin assets/saves/{ => thugpro}/Custo111.SKA | Bin assets/saves/{ => thugpro}/Custom 123.SKA | Bin assets/saves/{ => thugpro}/Custom Ska.SKA | Bin assets/saves/{ => thugpro}/Custom Skater1.SKA | Bin .../saves/{ => thugpro}/Custom Skater11.SKA | Bin .../saves/{ => thugpro}/Custom Skater12.SKA | Bin .../saves/{ => thugpro}/Custom Skater13.SKA | Bin .../saves/{ => thugpro}/Custom Skater15.SKA | Bin assets/saves/{ => thugpro}/Custom.SKA | Bin assets/saves/{ => thugpro}/Custom1.SKA | Bin assets/saves/{ => thugpro}/Custom111.SKA | Bin assets/saves/{ => thugpro}/Custom11111.SKA | Bin .../saves/{ => thugpro}/Custom111111111.SKA | Bin assets/saves/{ => thugpro}/Custom22222.SKA | Bin .../saves/{ => thugpro}/Custom_Skater13.SKA | Bin assets/saves/{ => thugpro}/DraKcula.SKA | Bin assets/saves/{ => thugpro}/Draco.SKA | Bin assets/saves/{ => thugpro}/Draco05.SKA | Bin assets/saves/{ => thugpro}/Draco5.SKA | Bin assets/saves/{ => thugpro}/Draco55.SKA | Bin assets/saves/{ => thugpro}/Drago.tLT.SKA | Bin assets/saves/{ => thugpro}/Dragon.eXtLT.SKA | Bin assets/saves/{ => thugpro}/DreamY.SKA | Bin assets/saves/{ => thugpro}/Drizzteatthis.SKA | Bin assets/saves/{ => thugpro}/George.SKA | Bin assets/saves/{ => thugpro}/Ghostface.SKA | Bin assets/saves/{ => thugpro}/GhostsDraco.SKA | Bin assets/saves/{ => thugpro}/J1221.SKA | Bin assets/saves/{ => thugpro}/J3.SKA | Bin assets/saves/{ => thugpro}/JEHCPHUN3.SKA | Bin assets/saves/{ => thugpro}/Jaycee 24.SKA | Bin .../saves/{ => thugpro}/Jaycee111111111.SKA | Bin assets/saves/{ => thugpro}/Jayceehoodie.SKA | Bin .../saves/{ => thugpro}/Jayceetekcolors.SKA | Bin assets/saves/{ => thugpro}/JehCPHUN.SKA | Bin assets/saves/{ => thugpro}/JoePro.SKA | Bin .../saves/{ => thugpro}/JoeProGreenLon2.SKA | Bin assets/saves/{ => thugpro}/JoeProPirate2.SKA | Bin assets/saves/{ => thugpro}/KskoutLT.SKA | Bin assets/saves/{ => thugpro}/LilThotties.SKA | Bin assets/saves/{ => thugpro}/MYRAGE.SKA | Bin .../saves/{ => thugpro}/MyraGe.hOt._NM1.SKA | Bin assets/saves/{ => thugpro}/Nacho6.SKA | Bin .../saves/{ => thugpro}/Ned the Cyclops.SKA | Bin .../saves/{ => thugpro}/Ned_the_Cyclops.SKA | Bin assets/saves/{ => thugpro}/Neon.SKA | Bin assets/saves/{ => thugpro}/RegularScuba.SKA | Bin assets/saves/{ => thugpro}/SiltLT.SKA | Bin assets/saves/{ => thugpro}/TEKREMAKE.SKA | Bin assets/saves/{ => thugpro}/afrojaycee.SKA | Bin assets/saves/{ => thugpro}/afrospideyy.SKA | Bin assets/saves/{ => thugpro}/alivegudephun.SKA | Bin assets/saves/{ => thugpro}/alivesunhat.SKA | Bin assets/saves/{ => thugpro}/alivesunhat1.SKA | Bin .../saves/{ => thugpro}/allblackhellmet.SKA | Bin .../saves/{ => thugpro}/altblackhellmet.SKA | Bin assets/saves/{ => thugpro}/altskel.SKA | Bin .../saves/{ => thugpro}/anderson cowboy.SKA | Bin assets/saves/{ => thugpro}/astrovan.SKA | Bin assets/saves/{ => thugpro}/b2.SKA | Bin assets/saves/{ => thugpro}/bace.SKA | Bin assets/saves/{ => thugpro}/bacelec.SKA | Bin assets/saves/{ => thugpro}/bacetltv2.SKA | Bin assets/saves/{ => thugpro}/bacetlv22.SKA | Bin assets/saves/{ => thugpro}/badacehood.SKA | Bin assets/saves/{ => thugpro}/bigpimpin.SKA | Bin assets/saves/{ => thugpro}/bigpimpin1.SKA | Bin assets/saves/{ => thugpro}/bitch69.SKA | Bin assets/saves/{ => thugpro}/blacknyello.SKA | Bin .../saves/{ => thugpro}/blackvestupsend.SKA | Bin assets/saves/{ => thugpro}/blu sunhat.SKA | Bin assets/saves/{ => thugpro}/blur.SKA | Bin assets/saves/{ => thugpro}/blurnewog.SKA | Bin assets/saves/{ => thugpro}/blursmgvid2.SKA | Bin assets/saves/{ => thugpro}/boiiwonda.SKA | Bin assets/saves/{ => thugpro}/bootsss.SKA | Bin assets/saves/{ => thugpro}/c4Carl Johnson.SKA | Bin assets/saves/{ => thugpro}/c7pink.SKA | Bin assets/saves/{ => thugpro}/cWalkertStyle.SKA | Bin assets/saves/{ => thugpro}/camosunhat.SKA | Bin assets/saves/{ => thugpro}/cbeanie.SKA | Bin assets/saves/{ => thugpro}/ccowboy.SKA | Bin assets/saves/{ => thugpro}/cdasendah.SKA | Bin assets/saves/{ => thugpro}/cdoc.SKA | Bin assets/saves/{ => thugpro}/cdot r y afro.SKA | Bin assets/saves/{ => thugpro}/cdot.SKA | Bin assets/saves/{ => thugpro}/cdot2.SKA | Bin assets/saves/{ => thugpro}/cdot3.SKA | Bin assets/saves/{ => thugpro}/cdot4.SKA | Bin assets/saves/{ => thugpro}/cdotccandy.SKA | Bin assets/saves/{ => thugpro}/cdotcdot.SKA | Bin .../saves/{ => thugpro}/cdotgreenhelmet.SKA | Bin assets/saves/{ => thugpro}/cdotgrenwhite.SKA | Bin assets/saves/{ => thugpro}/cdotpink.SKA | Bin assets/saves/{ => thugpro}/cdotslime.SKA | Bin .../saves/{ => thugpro}/cdotsmokescales.SKA | Bin assets/saves/{ => thugpro}/cdotxxxposed.SKA | Bin assets/saves/{ => thugpro}/conad.SKA | Bin assets/saves/{ => thugpro}/conad2.SKA | Bin assets/saves/{ => thugpro}/cotton_candy.SKA | Bin assets/saves/{ => thugpro}/cotton_candy2.SKA | Bin assets/saves/{ => thugpro}/cottoncandymf.SKA | Bin assets/saves/{ => thugpro}/crim.SKA | Bin assets/saves/{ => thugpro}/crimm.SKA | Bin assets/saves/{ => thugpro}/cthotSantaHoe.SKA | Bin assets/saves/{ => thugpro}/cthotremake.SKA | Bin assets/saves/{ => thugpro}/cthottie.SKA | Bin assets/saves/{ => thugpro}/cthotv2.SKA | Bin assets/saves/{ => thugpro}/curtskater2.SKA | Bin assets/saves/{ => thugpro}/daman.SKA | Bin assets/saves/{ => thugpro}/ded.SKA | Bin assets/saves/{ => thugpro}/ded1.SKA | Bin assets/saves/{ => thugpro}/dns.SKA | Bin assets/saves/{ => thugpro}/draco1017.SKA | Bin assets/saves/{ => thugpro}/draco11.SKA | Bin assets/saves/{ => thugpro}/draghost.SKA | Bin assets/saves/{ => thugpro}/dragon.SKA | Bin assets/saves/{ => thugpro}/dragontlt1.SKA | Bin assets/saves/{ => thugpro}/drakcdot.SKA | Bin assets/saves/{ => thugpro}/drakcdot1.SKA | Bin assets/saves/{ => thugpro}/eG2.SKA | Bin assets/saves/{ => thugpro}/edem 22.SKA | Bin assets/saves/{ => thugpro}/elecbright.SKA | Bin assets/saves/{ => thugpro}/evilsanjfixed.SKA | Bin assets/saves/{ => thugpro}/fayteish.SKA | Bin assets/saves/{ => thugpro}/faytejersey.SKA | Bin assets/saves/{ => thugpro}/fayteptcelec.SKA | Bin assets/saves/{ => thugpro}/fazo.SKA | Bin assets/saves/{ => thugpro}/fireboy69.SKA | Bin assets/saves/{ => thugpro}/forcdot.SKA | Bin assets/saves/{ => thugpro}/freddy.SKA | Bin assets/saves/{ => thugpro}/fuxwitit.SKA | Bin assets/saves/{ => thugpro}/george11111.SKA | Bin assets/saves/{ => thugpro}/georgetlt.SKA | Bin assets/saves/{ => thugpro}/ghostpurple.SKA | Bin assets/saves/{ => thugpro}/ghostyellow.SKA | Bin assets/saves/{ => thugpro}/gonz0.SKA | Bin assets/saves/{ => thugpro}/goz.SKA | Bin .../saves/{ => thugpro}/greenjerseyafro.SKA | Bin assets/saves/{ => thugpro}/greenwhitedot.SKA | Bin assets/saves/{ => thugpro}/gurl.SKA | Bin assets/saves/{ => thugpro}/gurlive.SKA | Bin assets/saves/{ => thugpro}/hippie.SKA | Bin assets/saves/{ => thugpro}/hippiecdot.SKA | Bin assets/saves/{ => thugpro}/hoe.SKA | Bin assets/saves/{ => thugpro}/icey.SKA | Bin assets/saves/{ => thugpro}/idkaman4.SKA | Bin assets/saves/{ => thugpro}/j5 test.SKA | Bin assets/saves/{ => thugpro}/j5.SKA | Bin assets/saves/{ => thugpro}/jaycee.SKA | Bin assets/saves/{ => thugpro}/jayceetek.SKA | Bin assets/saves/{ => thugpro}/jehcc.SKA | Bin assets/saves/{ => thugpro}/jinzo.SKA | Bin assets/saves/{ => thugpro}/jokerdotty.SKA | Bin assets/saves/{ => thugpro}/jokrdot.SKA | Bin assets/saves/{ => thugpro}/jolly22.SKA | Bin assets/saves/{ => thugpro}/jona.SKA | Bin assets/saves/{ => thugpro}/jonathek.SKA | Bin assets/saves/{ => thugpro}/konek3.SKA | Bin assets/saves/{ => thugpro}/konekL.SKA | Bin assets/saves/{ => thugpro}/ksk.SKA | Bin assets/saves/{ => thugpro}/ksksk.SKA | Bin assets/saves/{ => thugpro}/maxfli1.SKA | Bin assets/saves/{ => thugpro}/maxfli2.SKA | Bin assets/saves/{ => thugpro}/maxflilike.SKA | Bin assets/saves/{ => thugpro}/mf2smg1.SKA | Bin assets/saves/{ => thugpro}/mikeghost3.SKA | Bin assets/saves/{ => thugpro}/mista2.SKA | Bin assets/saves/{ => thugpro}/mont.SKA | Bin assets/saves/{ => thugpro}/montbombs.SKA | Bin assets/saves/{ => thugpro}/myoldcas.SKA | Bin assets/saves/{ => thugpro}/ness.SKA | Bin assets/saves/{ => thugpro}/newcas.SKA | Bin assets/saves/{ => thugpro}/newtek.SKA | Bin assets/saves/{ => thugpro}/o.SKA | Bin assets/saves/{ => thugpro}/og.SKA | Bin assets/saves/{ => thugpro}/oldfaytecas1.SKA | Bin assets/saves/{ => thugpro}/oldmecas.SKA | Bin assets/saves/{ => thugpro}/oldogcas.SKA | Bin assets/saves/{ => thugpro}/oldogcas1.SKA | Bin assets/saves/{ => thugpro}/paggreensunhat.SKA | Bin assets/saves/{ => thugpro}/pagsunhat.SKA | Bin assets/saves/{ => thugpro}/pagsunhat1.SKA | Bin assets/saves/{ => thugpro}/pants.SKA | Bin assets/saves/{ => thugpro}/paperhat.SKA | Bin assets/saves/{ => thugpro}/pink.SKA | Bin assets/saves/{ => thugpro}/pinkblack.SKA | Bin assets/saves/{ => thugpro}/pinkdread.SKA | Bin assets/saves/{ => thugpro}/pinklikecamron.SKA | Bin assets/saves/{ => thugpro}/pinkmohawk.SKA | Bin assets/saves/{ => thugpro}/ravneww.SKA | Bin assets/saves/{ => thugpro}/rb1.SKA | Bin assets/saves/{ => thugpro}/realdraco.SKA | Bin assets/saves/{ => thugpro}/remake2.SKA | Bin assets/saves/{ => thugpro}/russian.SKA | Bin assets/saves/{ => thugpro}/russianjacket.SKA | Bin assets/saves/{ => thugpro}/sandwhich bag.SKA | Bin assets/saves/{ => thugpro}/santa.SKA | Bin assets/saves/{ => thugpro}/silent.SKA | Bin assets/saves/{ => thugpro}/slimehoodie.SKA | Bin assets/saves/{ => thugpro}/smg2pizza.SKA | Bin assets/saves/{ => thugpro}/smoke.SKA | Bin assets/saves/{ => thugpro}/somewhatfayte.SKA | Bin assets/saves/{ => thugpro}/sonics.SKA | Bin assets/saves/{ => thugpro}/spbobsmg.SKA | Bin assets/saves/{ => thugpro}/spooker.SKA | Bin assets/saves/{ => thugpro}/sunhatscales.SKA | Bin assets/saves/{ => thugpro}/thiccboi.SKA | Bin assets/saves/{ => thugpro}/thugg.SKA | Bin assets/saves/{ => thugpro}/thugg_2.SKA | Bin assets/saves/{ => thugpro}/thuggcrazy.SKA | Bin assets/saves/{ => thugpro}/tlt22222.SKA | Bin assets/saves/{ => thugpro}/tltv5faytelec.SKA | Bin assets/saves/{ => thugpro}/uhhh_hmm.SKA | Bin assets/saves/{ => thugpro}/v1c.SKA | Bin assets/saves/{ => thugpro}/vegasmg2.SKA | Bin assets/saves/{ => thugpro}/velho.SKA | Bin assets/saves/{ => thugpro}/vestupson.SKA | Bin assets/saves/{ => thugpro}/vestupwbeanie.SKA | Bin assets/saves/{ => thugpro}/vicphun.SKA | Bin assets/saves/{ => thugpro}/viking.SKA | Bin assets/saves/{ => thugpro}/whitepink.SKA | Bin assets/saves/{ => thugpro}/wormgurl.SKA | Bin assets/saves/{ => thugpro}/wormgurlbw.SKA | Bin assets/saves/{ => thugpro}/wormslime.SKA | Bin assets/saves/{ => thugpro}/wormsmonkknk.SKA | Bin assets/saves/{ => thugpro}/x3og.SKA | Bin assets/saves/{ => thugpro}/zoo.SKA | Bin crates/cascade-app/src/dashboard.rs | 2 +- crates/cascade-backend/src/lib.rs | 41 ++- crates/cascade-cli/Cargo.toml | 3 + crates/cascade-cli/src/main.rs | 242 ++++++++++++- crates/cascade-qb/Cargo.toml | 2 +- crates/cascade-rethawed/Cargo.toml | 21 ++ crates/cascade-rethawed/src/backend.rs | 236 +++++++++++++ crates/cascade-rethawed/src/cas.rs | 328 ++++++++++++++++++ crates/cascade-rethawed/src/chunk.rs | 77 ++++ crates/cascade-rethawed/src/dump.rs | 59 ++++ crates/cascade-rethawed/src/entry.rs | 123 +++++++ crates/cascade-rethawed/src/error.rs | 41 +++ crates/cascade-rethawed/src/id.rs | 31 ++ crates/cascade-rethawed/src/lib.rs | 11 + crates/cascade-rethawed/src/save.rs | 97 ++++++ crates/cascade-save/src/save.rs | 1 + crates/cascade-thaw/Cargo.toml | 7 + crates/cascade-thaw/src/lib.rs | 1 + crates/cascade-thaw/src/lut.rs | 7 + crates/cascade-thugpro/Cargo.toml | 1 - crates/cascade-thugpro/src/backend.rs | 184 ++++++++-- crates/cascade-thugpro/src/entry.rs | 160 +++------ crates/cascade-thugpro/src/error.rs | 3 - crates/cascade-thugpro/src/random.rs | 2 +- 262 files changed, 1524 insertions(+), 159 deletions(-) create mode 100644 assets/lut/compress-thaw.ron rename assets/saves/{ => thugpro}/2414.SKA (100%) rename assets/saves/{ => thugpro}/4fantasy.SKA (100%) rename assets/saves/{ => thugpro}/80thugg.SKA (100%) rename assets/saves/{ => thugpro}/999.SKA (100%) rename assets/saves/{ => thugpro}/AfroSpidey.SKA (100%) rename assets/saves/{ => thugpro}/ClassicGreen.SKA (100%) rename assets/saves/{ => thugpro}/Cus.SKA (100%) rename assets/saves/{ => thugpro}/Cust.SKA (100%) rename assets/saves/{ => thugpro}/Custo111.SKA (100%) rename assets/saves/{ => thugpro}/Custom 123.SKA (100%) rename assets/saves/{ => thugpro}/Custom Ska.SKA (100%) rename assets/saves/{ => thugpro}/Custom Skater1.SKA (100%) rename assets/saves/{ => thugpro}/Custom Skater11.SKA (100%) rename assets/saves/{ => thugpro}/Custom Skater12.SKA (100%) rename assets/saves/{ => thugpro}/Custom Skater13.SKA (100%) rename assets/saves/{ => thugpro}/Custom Skater15.SKA (100%) rename assets/saves/{ => thugpro}/Custom.SKA (100%) rename assets/saves/{ => thugpro}/Custom1.SKA (100%) rename assets/saves/{ => thugpro}/Custom111.SKA (100%) rename assets/saves/{ => thugpro}/Custom11111.SKA (100%) rename assets/saves/{ => thugpro}/Custom111111111.SKA (100%) rename assets/saves/{ => thugpro}/Custom22222.SKA (100%) rename assets/saves/{ => thugpro}/Custom_Skater13.SKA (100%) rename assets/saves/{ => thugpro}/DraKcula.SKA (100%) rename assets/saves/{ => thugpro}/Draco.SKA (100%) rename assets/saves/{ => thugpro}/Draco05.SKA (100%) rename assets/saves/{ => thugpro}/Draco5.SKA (100%) rename assets/saves/{ => thugpro}/Draco55.SKA (100%) rename assets/saves/{ => thugpro}/Drago.tLT.SKA (100%) rename assets/saves/{ => thugpro}/Dragon.eXtLT.SKA (100%) rename assets/saves/{ => thugpro}/DreamY.SKA (100%) rename assets/saves/{ => thugpro}/Drizzteatthis.SKA (100%) rename assets/saves/{ => thugpro}/George.SKA (100%) rename assets/saves/{ => thugpro}/Ghostface.SKA (100%) rename assets/saves/{ => thugpro}/GhostsDraco.SKA (100%) rename assets/saves/{ => thugpro}/J1221.SKA (100%) rename assets/saves/{ => thugpro}/J3.SKA (100%) rename assets/saves/{ => thugpro}/JEHCPHUN3.SKA (100%) rename assets/saves/{ => thugpro}/Jaycee 24.SKA (100%) rename assets/saves/{ => thugpro}/Jaycee111111111.SKA (100%) rename assets/saves/{ => thugpro}/Jayceehoodie.SKA (100%) rename assets/saves/{ => thugpro}/Jayceetekcolors.SKA (100%) rename assets/saves/{ => thugpro}/JehCPHUN.SKA (100%) rename assets/saves/{ => thugpro}/JoePro.SKA (100%) rename assets/saves/{ => thugpro}/JoeProGreenLon2.SKA (100%) rename assets/saves/{ => thugpro}/JoeProPirate2.SKA (100%) rename assets/saves/{ => thugpro}/KskoutLT.SKA (100%) rename assets/saves/{ => thugpro}/LilThotties.SKA (100%) rename assets/saves/{ => thugpro}/MYRAGE.SKA (100%) rename assets/saves/{ => thugpro}/MyraGe.hOt._NM1.SKA (100%) rename assets/saves/{ => thugpro}/Nacho6.SKA (100%) rename assets/saves/{ => thugpro}/Ned the Cyclops.SKA (100%) rename assets/saves/{ => thugpro}/Ned_the_Cyclops.SKA (100%) rename assets/saves/{ => thugpro}/Neon.SKA (100%) rename assets/saves/{ => thugpro}/RegularScuba.SKA (100%) rename assets/saves/{ => thugpro}/SiltLT.SKA (100%) rename assets/saves/{ => thugpro}/TEKREMAKE.SKA (100%) rename assets/saves/{ => thugpro}/afrojaycee.SKA (100%) rename assets/saves/{ => thugpro}/afrospideyy.SKA (100%) rename assets/saves/{ => thugpro}/alivegudephun.SKA (100%) rename assets/saves/{ => thugpro}/alivesunhat.SKA (100%) rename assets/saves/{ => thugpro}/alivesunhat1.SKA (100%) rename assets/saves/{ => thugpro}/allblackhellmet.SKA (100%) rename assets/saves/{ => thugpro}/altblackhellmet.SKA (100%) rename assets/saves/{ => thugpro}/altskel.SKA (100%) rename assets/saves/{ => thugpro}/anderson cowboy.SKA (100%) rename assets/saves/{ => thugpro}/astrovan.SKA (100%) rename assets/saves/{ => thugpro}/b2.SKA (100%) rename assets/saves/{ => thugpro}/bace.SKA (100%) rename assets/saves/{ => thugpro}/bacelec.SKA (100%) rename assets/saves/{ => thugpro}/bacetltv2.SKA (100%) rename assets/saves/{ => thugpro}/bacetlv22.SKA (100%) rename assets/saves/{ => thugpro}/badacehood.SKA (100%) rename assets/saves/{ => thugpro}/bigpimpin.SKA (100%) rename assets/saves/{ => thugpro}/bigpimpin1.SKA (100%) rename assets/saves/{ => thugpro}/bitch69.SKA (100%) rename assets/saves/{ => thugpro}/blacknyello.SKA (100%) rename assets/saves/{ => thugpro}/blackvestupsend.SKA (100%) rename assets/saves/{ => thugpro}/blu sunhat.SKA (100%) rename assets/saves/{ => thugpro}/blur.SKA (100%) rename assets/saves/{ => thugpro}/blurnewog.SKA (100%) rename assets/saves/{ => thugpro}/blursmgvid2.SKA (100%) rename assets/saves/{ => thugpro}/boiiwonda.SKA (100%) rename assets/saves/{ => thugpro}/bootsss.SKA (100%) rename assets/saves/{ => thugpro}/c4Carl Johnson.SKA (100%) rename assets/saves/{ => thugpro}/c7pink.SKA (100%) rename assets/saves/{ => thugpro}/cWalkertStyle.SKA (100%) rename assets/saves/{ => thugpro}/camosunhat.SKA (100%) rename assets/saves/{ => thugpro}/cbeanie.SKA (100%) rename assets/saves/{ => thugpro}/ccowboy.SKA (100%) rename assets/saves/{ => thugpro}/cdasendah.SKA (100%) rename assets/saves/{ => thugpro}/cdoc.SKA (100%) rename assets/saves/{ => thugpro}/cdot r y afro.SKA (100%) rename assets/saves/{ => thugpro}/cdot.SKA (100%) rename assets/saves/{ => thugpro}/cdot2.SKA (100%) rename assets/saves/{ => thugpro}/cdot3.SKA (100%) rename assets/saves/{ => thugpro}/cdot4.SKA (100%) rename assets/saves/{ => thugpro}/cdotccandy.SKA (100%) rename assets/saves/{ => thugpro}/cdotcdot.SKA (100%) rename assets/saves/{ => thugpro}/cdotgreenhelmet.SKA (100%) rename assets/saves/{ => thugpro}/cdotgrenwhite.SKA (100%) rename assets/saves/{ => thugpro}/cdotpink.SKA (100%) rename assets/saves/{ => thugpro}/cdotslime.SKA (100%) rename assets/saves/{ => thugpro}/cdotsmokescales.SKA (100%) rename assets/saves/{ => thugpro}/cdotxxxposed.SKA (100%) rename assets/saves/{ => thugpro}/conad.SKA (100%) rename assets/saves/{ => thugpro}/conad2.SKA (100%) rename assets/saves/{ => thugpro}/cotton_candy.SKA (100%) rename assets/saves/{ => thugpro}/cotton_candy2.SKA (100%) rename assets/saves/{ => thugpro}/cottoncandymf.SKA (100%) rename assets/saves/{ => thugpro}/crim.SKA (100%) rename assets/saves/{ => thugpro}/crimm.SKA (100%) rename assets/saves/{ => thugpro}/cthotSantaHoe.SKA (100%) rename assets/saves/{ => thugpro}/cthotremake.SKA (100%) rename assets/saves/{ => thugpro}/cthottie.SKA (100%) rename assets/saves/{ => thugpro}/cthotv2.SKA (100%) rename assets/saves/{ => thugpro}/curtskater2.SKA (100%) rename assets/saves/{ => thugpro}/daman.SKA (100%) rename assets/saves/{ => thugpro}/ded.SKA (100%) rename assets/saves/{ => thugpro}/ded1.SKA (100%) rename assets/saves/{ => thugpro}/dns.SKA (100%) rename assets/saves/{ => thugpro}/draco1017.SKA (100%) rename assets/saves/{ => thugpro}/draco11.SKA (100%) rename assets/saves/{ => thugpro}/draghost.SKA (100%) rename assets/saves/{ => thugpro}/dragon.SKA (100%) rename assets/saves/{ => thugpro}/dragontlt1.SKA (100%) rename assets/saves/{ => thugpro}/drakcdot.SKA (100%) rename assets/saves/{ => thugpro}/drakcdot1.SKA (100%) rename assets/saves/{ => thugpro}/eG2.SKA (100%) rename assets/saves/{ => thugpro}/edem 22.SKA (100%) rename assets/saves/{ => thugpro}/elecbright.SKA (100%) rename assets/saves/{ => thugpro}/evilsanjfixed.SKA (100%) rename assets/saves/{ => thugpro}/fayteish.SKA (100%) rename assets/saves/{ => thugpro}/faytejersey.SKA (100%) rename assets/saves/{ => thugpro}/fayteptcelec.SKA (100%) rename assets/saves/{ => thugpro}/fazo.SKA (100%) rename assets/saves/{ => thugpro}/fireboy69.SKA (100%) rename assets/saves/{ => thugpro}/forcdot.SKA (100%) rename assets/saves/{ => thugpro}/freddy.SKA (100%) rename assets/saves/{ => thugpro}/fuxwitit.SKA (100%) rename assets/saves/{ => thugpro}/george11111.SKA (100%) rename assets/saves/{ => thugpro}/georgetlt.SKA (100%) rename assets/saves/{ => thugpro}/ghostpurple.SKA (100%) rename assets/saves/{ => thugpro}/ghostyellow.SKA (100%) rename assets/saves/{ => thugpro}/gonz0.SKA (100%) rename assets/saves/{ => thugpro}/goz.SKA (100%) rename assets/saves/{ => thugpro}/greenjerseyafro.SKA (100%) rename assets/saves/{ => thugpro}/greenwhitedot.SKA (100%) rename assets/saves/{ => thugpro}/gurl.SKA (100%) rename assets/saves/{ => thugpro}/gurlive.SKA (100%) rename assets/saves/{ => thugpro}/hippie.SKA (100%) rename assets/saves/{ => thugpro}/hippiecdot.SKA (100%) rename assets/saves/{ => thugpro}/hoe.SKA (100%) rename assets/saves/{ => thugpro}/icey.SKA (100%) rename assets/saves/{ => thugpro}/idkaman4.SKA (100%) rename assets/saves/{ => thugpro}/j5 test.SKA (100%) rename assets/saves/{ => thugpro}/j5.SKA (100%) rename assets/saves/{ => thugpro}/jaycee.SKA (100%) rename assets/saves/{ => thugpro}/jayceetek.SKA (100%) rename assets/saves/{ => thugpro}/jehcc.SKA (100%) rename assets/saves/{ => thugpro}/jinzo.SKA (100%) rename assets/saves/{ => thugpro}/jokerdotty.SKA (100%) rename assets/saves/{ => thugpro}/jokrdot.SKA (100%) rename assets/saves/{ => thugpro}/jolly22.SKA (100%) rename assets/saves/{ => thugpro}/jona.SKA (100%) rename assets/saves/{ => thugpro}/jonathek.SKA (100%) rename assets/saves/{ => thugpro}/konek3.SKA (100%) rename assets/saves/{ => thugpro}/konekL.SKA (100%) rename assets/saves/{ => thugpro}/ksk.SKA (100%) rename assets/saves/{ => thugpro}/ksksk.SKA (100%) rename assets/saves/{ => thugpro}/maxfli1.SKA (100%) rename assets/saves/{ => thugpro}/maxfli2.SKA (100%) rename assets/saves/{ => thugpro}/maxflilike.SKA (100%) rename assets/saves/{ => thugpro}/mf2smg1.SKA (100%) rename assets/saves/{ => thugpro}/mikeghost3.SKA (100%) rename assets/saves/{ => thugpro}/mista2.SKA (100%) rename assets/saves/{ => thugpro}/mont.SKA (100%) rename assets/saves/{ => thugpro}/montbombs.SKA (100%) rename assets/saves/{ => thugpro}/myoldcas.SKA (100%) rename assets/saves/{ => thugpro}/ness.SKA (100%) rename assets/saves/{ => thugpro}/newcas.SKA (100%) rename assets/saves/{ => thugpro}/newtek.SKA (100%) rename assets/saves/{ => thugpro}/o.SKA (100%) rename assets/saves/{ => thugpro}/og.SKA (100%) rename assets/saves/{ => thugpro}/oldfaytecas1.SKA (100%) rename assets/saves/{ => thugpro}/oldmecas.SKA (100%) rename assets/saves/{ => thugpro}/oldogcas.SKA (100%) rename assets/saves/{ => thugpro}/oldogcas1.SKA (100%) rename assets/saves/{ => thugpro}/paggreensunhat.SKA (100%) rename assets/saves/{ => thugpro}/pagsunhat.SKA (100%) rename assets/saves/{ => thugpro}/pagsunhat1.SKA (100%) rename assets/saves/{ => thugpro}/pants.SKA (100%) rename assets/saves/{ => thugpro}/paperhat.SKA (100%) rename assets/saves/{ => thugpro}/pink.SKA (100%) rename assets/saves/{ => thugpro}/pinkblack.SKA (100%) rename assets/saves/{ => thugpro}/pinkdread.SKA (100%) rename assets/saves/{ => thugpro}/pinklikecamron.SKA (100%) rename assets/saves/{ => thugpro}/pinkmohawk.SKA (100%) rename assets/saves/{ => thugpro}/ravneww.SKA (100%) rename assets/saves/{ => thugpro}/rb1.SKA (100%) rename assets/saves/{ => thugpro}/realdraco.SKA (100%) rename assets/saves/{ => thugpro}/remake2.SKA (100%) rename assets/saves/{ => thugpro}/russian.SKA (100%) rename assets/saves/{ => thugpro}/russianjacket.SKA (100%) rename assets/saves/{ => thugpro}/sandwhich bag.SKA (100%) rename assets/saves/{ => thugpro}/santa.SKA (100%) rename assets/saves/{ => thugpro}/silent.SKA (100%) rename assets/saves/{ => thugpro}/slimehoodie.SKA (100%) rename assets/saves/{ => thugpro}/smg2pizza.SKA (100%) rename assets/saves/{ => thugpro}/smoke.SKA (100%) rename assets/saves/{ => thugpro}/somewhatfayte.SKA (100%) rename assets/saves/{ => thugpro}/sonics.SKA (100%) rename assets/saves/{ => thugpro}/spbobsmg.SKA (100%) rename assets/saves/{ => thugpro}/spooker.SKA (100%) rename assets/saves/{ => thugpro}/sunhatscales.SKA (100%) rename assets/saves/{ => thugpro}/thiccboi.SKA (100%) rename assets/saves/{ => thugpro}/thugg.SKA (100%) rename assets/saves/{ => thugpro}/thugg_2.SKA (100%) rename assets/saves/{ => thugpro}/thuggcrazy.SKA (100%) rename assets/saves/{ => thugpro}/tlt22222.SKA (100%) rename assets/saves/{ => thugpro}/tltv5faytelec.SKA (100%) rename assets/saves/{ => thugpro}/uhhh_hmm.SKA (100%) rename assets/saves/{ => thugpro}/v1c.SKA (100%) rename assets/saves/{ => thugpro}/vegasmg2.SKA (100%) rename assets/saves/{ => thugpro}/velho.SKA (100%) rename assets/saves/{ => thugpro}/vestupson.SKA (100%) rename assets/saves/{ => thugpro}/vestupwbeanie.SKA (100%) rename assets/saves/{ => thugpro}/vicphun.SKA (100%) rename assets/saves/{ => thugpro}/viking.SKA (100%) rename assets/saves/{ => thugpro}/whitepink.SKA (100%) rename assets/saves/{ => thugpro}/wormgurl.SKA (100%) rename assets/saves/{ => thugpro}/wormgurlbw.SKA (100%) rename assets/saves/{ => thugpro}/wormslime.SKA (100%) rename assets/saves/{ => thugpro}/wormsmonkknk.SKA (100%) rename assets/saves/{ => thugpro}/x3og.SKA (100%) rename assets/saves/{ => thugpro}/zoo.SKA (100%) create mode 100644 crates/cascade-rethawed/Cargo.toml create mode 100644 crates/cascade-rethawed/src/backend.rs create mode 100644 crates/cascade-rethawed/src/cas.rs create mode 100644 crates/cascade-rethawed/src/chunk.rs create mode 100644 crates/cascade-rethawed/src/dump.rs create mode 100644 crates/cascade-rethawed/src/entry.rs create mode 100644 crates/cascade-rethawed/src/error.rs create mode 100644 crates/cascade-rethawed/src/id.rs create mode 100644 crates/cascade-rethawed/src/lib.rs create mode 100644 crates/cascade-rethawed/src/save.rs create mode 100644 crates/cascade-thaw/Cargo.toml create mode 100644 crates/cascade-thaw/src/lib.rs create mode 100644 crates/cascade-thaw/src/lut.rs diff --git a/Cargo.toml b/Cargo.toml index 6c8ea40..cf6c4b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,9 @@ cascade-crc = { path = "crates/cascade-crc" } cascade-dump = { path = "crates/cascade-dump" } cascade-lut = { path = "crates/cascade-lut" } cascade-qb = { path = "crates/cascade-qb" } +cascade-rethawed = { path = "crates/cascade-rethawed" } cascade-save = { path = "crates/cascade-save" } +cascade-thaw = { path = "crates/cascade-thaw" } cascade-thps4 = { path = "crates/cascade-thps4" } cascade-thug = { path = "crates/cascade-thug" } cascade-thugpro = { path = "crates/cascade-thugpro" } diff --git a/assets/lut/compress-thaw.ron b/assets/lut/compress-thaw.ron new file mode 100644 index 0000000..dedd4ee --- /dev/null +++ b/assets/lut/compress-thaw.ron @@ -0,0 +1 @@ +(compress8:["skater_m_lower_legs","skater_m_head","skater_m_torso","skater_m_legs","skater_m_hair","skater_m_backpack","skater_m_jaw","kneepads","socks","elbowpads","skater_f_head","skater_f_torso","skater_f_legs","skater_f_hair","skater_f_backpack","skater_m_lower_legs","skater_m_hat_hair","part","skater_m_hands","chest_tattoo","back_tattoo","left_forearm_tattoo","right_forearm_tattoo","left_bicep_tattoo","left_leg_tattoo","right_leg_tattoo","use_default_scale","right_bicep_tattoo","Skin","value","desc_id","h","s","v","use_default_hsv","skater_f_lower_legs","skater_f_hat_hair","Scale","skater_f_hands","display_name","stance","pushstyle","profile","name","trickstyle","age","is_pro","hometown","is_locked","is_head_locked","points_available","Air","run","ollie","Speed","spin","Switch","rail_balance","lip_balance","manual_balance","sponsors","trick_mapping","default_trick_mapping","max_specials","specials","Air_CircleD","Air_CircleDL","Air_CircleDR","Air_CircleL","Air_CircleR","Air_CircleU","Air_CircleUL","Air_CircleUR","Air_D_D_Circle","Air_D_D_Square","Air_L_L_Circle","Air_L_L_Square","Air_R_R_Circle","Air_R_R_Square","Air_SquareD","Air_SquareDL","Air_SquareDR","Air_SquareL","Air_SquareR","Air_SquareU","Air_SquareUL","Air_SquareUR","Air_U_U_Circle","Air_U_U_Square","ExtraSlot1","ExtraSlot2","JumpSlot","Lip_TriangleD","Lip_TriangleDL","Lip_TriangleDL","Lip_TriangleDR","Lip_TriangleDR","Lip_TriangleL","Lip_TriangleR","Lip_TriangleU","Lip_TriangleUL","Lip_TriangleUL","Lip_TriangleUR","Lip_TriangleUR","SpAir_D_L_Circle","SpAir_D_L_Square","SpAir_D_R_Circle","SpAir_D_R_Square","SpAir_D_U_Circle","SpAir_D_U_Square","SpAir_L_D_Circle","SpAir_L_D_Square","SpAir_L_R_Circle","SpAir_L_R_Square","SpAir_L_U_Circle","SpAir_L_U_Square","SpAir_R_D_Circle","SpAir_R_D_Square","SpAir_R_L_Circle","SpAir_R_L_Square","SpAir_R_U_Circle","SpAir_R_U_Square","SpAir_U_D_Circle","SpAir_U_D_Square","SpAir_U_L_Circle","SpAir_U_L_Square","SpAir_U_R_Circle","SpAir_U_R_Square","SpGrind_D_L_Triangle","SpGrind_D_R_Triangle","SpGrind_D_U_Triangle","SpGrind_L_D_Triangle","SpGrind_L_R_Triangle","SpGrind_L_U_Triangle","SpGrind_R_D_Triangle","SpGrind_R_L_Triangle","SpGrind_R_U_Triangle","SpGrind_U_D_Triangle","SpGrind_U_L_Triangle","SpGrind_U_R_Triangle","SpLip_D_L_Triangle","SpLip_D_R_Triangle","SpLip_D_U_Triangle","SpLip_L_D_Triangle","SpLip_L_R_Triangle","SpLip_L_U_Triangle","SpLip_R_D_Triangle","SpLip_R_L_Triangle","SpLip_R_U_Triangle","SpLip_U_D_Triangle","SpLip_U_L_Triangle","SpLip_U_R_Triangle","SpLip_U_U_Triangle","SpMan_D_L_Triangle","SpMan_D_R_Triangle","SpMan_D_U_Triangle","SpMan_L_D_Triangle","SpMan_L_R_Triangle","SpMan_L_U_Triangle","SpMan_R_D_Triangle","SpMan_R_L_Triangle","SpMan_R_U_Triangle","SpMan_U_D_Triangle","SpMan_U_L_Triangle","SpMan_U_R_Triangle","x","y","z","trickslot","trickname","Unassigned","uv_scale","uv_rot","uv_u","uv_v","sleeves","shoes","front_logo","back_logo","glasses","Hat","helmet","Accessories","hat_logo","helmet_logo","board","griptape","deck_graphic","accessory1","accessory2","accessory3","shoe_laces","bare_torso","hasBeaten","head_tattoo","custom","headtop_bone_group","jaw_bone_group","nose_bone_group","head_bone_group","torso_bone_group","stomach_bone_group","upper_arm_bone_group","lower_arm_bone_group","hands_bone_group","upper_left_bone_group","lower_leg_bone_group","feet_bone_group","board_bone_group","object_scaling","regular","goofy","never_mongo","mongo_when_switch","always_mongo","street","vert","first_name","skater_index","default_appearance","is_male","flip_speed","on","Trick","dur","Blend","from","percent","trickType","idletime","start","order","hold","backwards","deg_dir","left_eye","right_eye","nose","lips","width","height","GapName","GapCount","GapScore","SkaterStartPos","SkaterStartDir","level","valid","value","number","initials","win_record",],compress16:[]) diff --git a/assets/saves/2414.SKA b/assets/saves/thugpro/2414.SKA similarity index 100% rename from assets/saves/2414.SKA rename to assets/saves/thugpro/2414.SKA diff --git a/assets/saves/4fantasy.SKA b/assets/saves/thugpro/4fantasy.SKA similarity index 100% rename from assets/saves/4fantasy.SKA rename to assets/saves/thugpro/4fantasy.SKA diff --git a/assets/saves/80thugg.SKA b/assets/saves/thugpro/80thugg.SKA similarity index 100% rename from assets/saves/80thugg.SKA rename to assets/saves/thugpro/80thugg.SKA diff --git a/assets/saves/999.SKA b/assets/saves/thugpro/999.SKA similarity index 100% rename from assets/saves/999.SKA rename to assets/saves/thugpro/999.SKA diff --git a/assets/saves/AfroSpidey.SKA b/assets/saves/thugpro/AfroSpidey.SKA similarity index 100% rename from assets/saves/AfroSpidey.SKA rename to assets/saves/thugpro/AfroSpidey.SKA diff --git a/assets/saves/ClassicGreen.SKA b/assets/saves/thugpro/ClassicGreen.SKA similarity index 100% rename from assets/saves/ClassicGreen.SKA rename to assets/saves/thugpro/ClassicGreen.SKA diff --git a/assets/saves/Cus.SKA b/assets/saves/thugpro/Cus.SKA similarity index 100% rename from assets/saves/Cus.SKA rename to assets/saves/thugpro/Cus.SKA diff --git a/assets/saves/Cust.SKA b/assets/saves/thugpro/Cust.SKA similarity index 100% rename from assets/saves/Cust.SKA rename to assets/saves/thugpro/Cust.SKA diff --git a/assets/saves/Custo111.SKA b/assets/saves/thugpro/Custo111.SKA similarity index 100% rename from assets/saves/Custo111.SKA rename to assets/saves/thugpro/Custo111.SKA diff --git a/assets/saves/Custom 123.SKA b/assets/saves/thugpro/Custom 123.SKA similarity index 100% rename from assets/saves/Custom 123.SKA rename to assets/saves/thugpro/Custom 123.SKA diff --git a/assets/saves/Custom Ska.SKA b/assets/saves/thugpro/Custom Ska.SKA similarity index 100% rename from assets/saves/Custom Ska.SKA rename to assets/saves/thugpro/Custom Ska.SKA diff --git a/assets/saves/Custom Skater1.SKA b/assets/saves/thugpro/Custom Skater1.SKA similarity index 100% rename from assets/saves/Custom Skater1.SKA rename to assets/saves/thugpro/Custom Skater1.SKA diff --git a/assets/saves/Custom Skater11.SKA b/assets/saves/thugpro/Custom Skater11.SKA similarity index 100% rename from assets/saves/Custom Skater11.SKA rename to assets/saves/thugpro/Custom Skater11.SKA diff --git a/assets/saves/Custom Skater12.SKA b/assets/saves/thugpro/Custom Skater12.SKA similarity index 100% rename from assets/saves/Custom Skater12.SKA rename to assets/saves/thugpro/Custom Skater12.SKA diff --git a/assets/saves/Custom Skater13.SKA b/assets/saves/thugpro/Custom Skater13.SKA similarity index 100% rename from assets/saves/Custom Skater13.SKA rename to assets/saves/thugpro/Custom Skater13.SKA diff --git a/assets/saves/Custom Skater15.SKA b/assets/saves/thugpro/Custom Skater15.SKA similarity index 100% rename from assets/saves/Custom Skater15.SKA rename to assets/saves/thugpro/Custom Skater15.SKA diff --git a/assets/saves/Custom.SKA b/assets/saves/thugpro/Custom.SKA similarity index 100% rename from assets/saves/Custom.SKA rename to assets/saves/thugpro/Custom.SKA diff --git a/assets/saves/Custom1.SKA b/assets/saves/thugpro/Custom1.SKA similarity index 100% rename from assets/saves/Custom1.SKA rename to assets/saves/thugpro/Custom1.SKA diff --git a/assets/saves/Custom111.SKA b/assets/saves/thugpro/Custom111.SKA similarity index 100% rename from assets/saves/Custom111.SKA rename to assets/saves/thugpro/Custom111.SKA diff --git a/assets/saves/Custom11111.SKA b/assets/saves/thugpro/Custom11111.SKA similarity index 100% rename from assets/saves/Custom11111.SKA rename to assets/saves/thugpro/Custom11111.SKA diff --git a/assets/saves/Custom111111111.SKA b/assets/saves/thugpro/Custom111111111.SKA similarity index 100% rename from assets/saves/Custom111111111.SKA rename to assets/saves/thugpro/Custom111111111.SKA diff --git a/assets/saves/Custom22222.SKA b/assets/saves/thugpro/Custom22222.SKA similarity index 100% rename from assets/saves/Custom22222.SKA rename to assets/saves/thugpro/Custom22222.SKA diff --git a/assets/saves/Custom_Skater13.SKA b/assets/saves/thugpro/Custom_Skater13.SKA similarity index 100% rename from assets/saves/Custom_Skater13.SKA rename to assets/saves/thugpro/Custom_Skater13.SKA diff --git a/assets/saves/DraKcula.SKA b/assets/saves/thugpro/DraKcula.SKA similarity index 100% rename from assets/saves/DraKcula.SKA rename to assets/saves/thugpro/DraKcula.SKA diff --git a/assets/saves/Draco.SKA b/assets/saves/thugpro/Draco.SKA similarity index 100% rename from assets/saves/Draco.SKA rename to assets/saves/thugpro/Draco.SKA diff --git a/assets/saves/Draco05.SKA b/assets/saves/thugpro/Draco05.SKA similarity index 100% rename from assets/saves/Draco05.SKA rename to assets/saves/thugpro/Draco05.SKA diff --git a/assets/saves/Draco5.SKA b/assets/saves/thugpro/Draco5.SKA similarity index 100% rename from assets/saves/Draco5.SKA rename to assets/saves/thugpro/Draco5.SKA diff --git a/assets/saves/Draco55.SKA b/assets/saves/thugpro/Draco55.SKA similarity index 100% rename from assets/saves/Draco55.SKA rename to assets/saves/thugpro/Draco55.SKA diff --git a/assets/saves/Drago.tLT.SKA b/assets/saves/thugpro/Drago.tLT.SKA similarity index 100% rename from assets/saves/Drago.tLT.SKA rename to assets/saves/thugpro/Drago.tLT.SKA diff --git a/assets/saves/Dragon.eXtLT.SKA b/assets/saves/thugpro/Dragon.eXtLT.SKA similarity index 100% rename from assets/saves/Dragon.eXtLT.SKA rename to assets/saves/thugpro/Dragon.eXtLT.SKA diff --git a/assets/saves/DreamY.SKA b/assets/saves/thugpro/DreamY.SKA similarity index 100% rename from assets/saves/DreamY.SKA rename to assets/saves/thugpro/DreamY.SKA diff --git a/assets/saves/Drizzteatthis.SKA b/assets/saves/thugpro/Drizzteatthis.SKA similarity index 100% rename from assets/saves/Drizzteatthis.SKA rename to assets/saves/thugpro/Drizzteatthis.SKA diff --git a/assets/saves/George.SKA b/assets/saves/thugpro/George.SKA similarity index 100% rename from assets/saves/George.SKA rename to assets/saves/thugpro/George.SKA diff --git a/assets/saves/Ghostface.SKA b/assets/saves/thugpro/Ghostface.SKA similarity index 100% rename from assets/saves/Ghostface.SKA rename to assets/saves/thugpro/Ghostface.SKA diff --git a/assets/saves/GhostsDraco.SKA b/assets/saves/thugpro/GhostsDraco.SKA similarity index 100% rename from assets/saves/GhostsDraco.SKA rename to assets/saves/thugpro/GhostsDraco.SKA diff --git a/assets/saves/J1221.SKA b/assets/saves/thugpro/J1221.SKA similarity index 100% rename from assets/saves/J1221.SKA rename to assets/saves/thugpro/J1221.SKA diff --git a/assets/saves/J3.SKA b/assets/saves/thugpro/J3.SKA similarity index 100% rename from assets/saves/J3.SKA rename to assets/saves/thugpro/J3.SKA diff --git a/assets/saves/JEHCPHUN3.SKA b/assets/saves/thugpro/JEHCPHUN3.SKA similarity index 100% rename from assets/saves/JEHCPHUN3.SKA rename to assets/saves/thugpro/JEHCPHUN3.SKA diff --git a/assets/saves/Jaycee 24.SKA b/assets/saves/thugpro/Jaycee 24.SKA similarity index 100% rename from assets/saves/Jaycee 24.SKA rename to assets/saves/thugpro/Jaycee 24.SKA diff --git a/assets/saves/Jaycee111111111.SKA b/assets/saves/thugpro/Jaycee111111111.SKA similarity index 100% rename from assets/saves/Jaycee111111111.SKA rename to assets/saves/thugpro/Jaycee111111111.SKA diff --git a/assets/saves/Jayceehoodie.SKA b/assets/saves/thugpro/Jayceehoodie.SKA similarity index 100% rename from assets/saves/Jayceehoodie.SKA rename to assets/saves/thugpro/Jayceehoodie.SKA diff --git a/assets/saves/Jayceetekcolors.SKA b/assets/saves/thugpro/Jayceetekcolors.SKA similarity index 100% rename from assets/saves/Jayceetekcolors.SKA rename to assets/saves/thugpro/Jayceetekcolors.SKA diff --git a/assets/saves/JehCPHUN.SKA b/assets/saves/thugpro/JehCPHUN.SKA similarity index 100% rename from assets/saves/JehCPHUN.SKA rename to assets/saves/thugpro/JehCPHUN.SKA diff --git a/assets/saves/JoePro.SKA b/assets/saves/thugpro/JoePro.SKA similarity index 100% rename from assets/saves/JoePro.SKA rename to assets/saves/thugpro/JoePro.SKA diff --git a/assets/saves/JoeProGreenLon2.SKA b/assets/saves/thugpro/JoeProGreenLon2.SKA similarity index 100% rename from assets/saves/JoeProGreenLon2.SKA rename to assets/saves/thugpro/JoeProGreenLon2.SKA diff --git a/assets/saves/JoeProPirate2.SKA b/assets/saves/thugpro/JoeProPirate2.SKA similarity index 100% rename from assets/saves/JoeProPirate2.SKA rename to assets/saves/thugpro/JoeProPirate2.SKA diff --git a/assets/saves/KskoutLT.SKA b/assets/saves/thugpro/KskoutLT.SKA similarity index 100% rename from assets/saves/KskoutLT.SKA rename to assets/saves/thugpro/KskoutLT.SKA diff --git a/assets/saves/LilThotties.SKA b/assets/saves/thugpro/LilThotties.SKA similarity index 100% rename from assets/saves/LilThotties.SKA rename to assets/saves/thugpro/LilThotties.SKA diff --git a/assets/saves/MYRAGE.SKA b/assets/saves/thugpro/MYRAGE.SKA similarity index 100% rename from assets/saves/MYRAGE.SKA rename to assets/saves/thugpro/MYRAGE.SKA diff --git a/assets/saves/MyraGe.hOt._NM1.SKA b/assets/saves/thugpro/MyraGe.hOt._NM1.SKA similarity index 100% rename from assets/saves/MyraGe.hOt._NM1.SKA rename to assets/saves/thugpro/MyraGe.hOt._NM1.SKA diff --git a/assets/saves/Nacho6.SKA b/assets/saves/thugpro/Nacho6.SKA similarity index 100% rename from assets/saves/Nacho6.SKA rename to assets/saves/thugpro/Nacho6.SKA diff --git a/assets/saves/Ned the Cyclops.SKA b/assets/saves/thugpro/Ned the Cyclops.SKA similarity index 100% rename from assets/saves/Ned the Cyclops.SKA rename to assets/saves/thugpro/Ned the Cyclops.SKA diff --git a/assets/saves/Ned_the_Cyclops.SKA b/assets/saves/thugpro/Ned_the_Cyclops.SKA similarity index 100% rename from assets/saves/Ned_the_Cyclops.SKA rename to assets/saves/thugpro/Ned_the_Cyclops.SKA diff --git a/assets/saves/Neon.SKA b/assets/saves/thugpro/Neon.SKA similarity index 100% rename from assets/saves/Neon.SKA rename to assets/saves/thugpro/Neon.SKA diff --git a/assets/saves/RegularScuba.SKA b/assets/saves/thugpro/RegularScuba.SKA similarity index 100% rename from assets/saves/RegularScuba.SKA rename to assets/saves/thugpro/RegularScuba.SKA diff --git a/assets/saves/SiltLT.SKA b/assets/saves/thugpro/SiltLT.SKA similarity index 100% rename from assets/saves/SiltLT.SKA rename to assets/saves/thugpro/SiltLT.SKA diff --git a/assets/saves/TEKREMAKE.SKA b/assets/saves/thugpro/TEKREMAKE.SKA similarity index 100% rename from assets/saves/TEKREMAKE.SKA rename to assets/saves/thugpro/TEKREMAKE.SKA diff --git a/assets/saves/afrojaycee.SKA b/assets/saves/thugpro/afrojaycee.SKA similarity index 100% rename from assets/saves/afrojaycee.SKA rename to assets/saves/thugpro/afrojaycee.SKA diff --git a/assets/saves/afrospideyy.SKA b/assets/saves/thugpro/afrospideyy.SKA similarity index 100% rename from assets/saves/afrospideyy.SKA rename to assets/saves/thugpro/afrospideyy.SKA diff --git a/assets/saves/alivegudephun.SKA b/assets/saves/thugpro/alivegudephun.SKA similarity index 100% rename from assets/saves/alivegudephun.SKA rename to assets/saves/thugpro/alivegudephun.SKA diff --git a/assets/saves/alivesunhat.SKA b/assets/saves/thugpro/alivesunhat.SKA similarity index 100% rename from assets/saves/alivesunhat.SKA rename to assets/saves/thugpro/alivesunhat.SKA diff --git a/assets/saves/alivesunhat1.SKA b/assets/saves/thugpro/alivesunhat1.SKA similarity index 100% rename from assets/saves/alivesunhat1.SKA rename to assets/saves/thugpro/alivesunhat1.SKA diff --git a/assets/saves/allblackhellmet.SKA b/assets/saves/thugpro/allblackhellmet.SKA similarity index 100% rename from assets/saves/allblackhellmet.SKA rename to assets/saves/thugpro/allblackhellmet.SKA diff --git a/assets/saves/altblackhellmet.SKA b/assets/saves/thugpro/altblackhellmet.SKA similarity index 100% rename from assets/saves/altblackhellmet.SKA rename to assets/saves/thugpro/altblackhellmet.SKA diff --git a/assets/saves/altskel.SKA b/assets/saves/thugpro/altskel.SKA similarity index 100% rename from assets/saves/altskel.SKA rename to assets/saves/thugpro/altskel.SKA diff --git a/assets/saves/anderson cowboy.SKA b/assets/saves/thugpro/anderson cowboy.SKA similarity index 100% rename from assets/saves/anderson cowboy.SKA rename to assets/saves/thugpro/anderson cowboy.SKA diff --git a/assets/saves/astrovan.SKA b/assets/saves/thugpro/astrovan.SKA similarity index 100% rename from assets/saves/astrovan.SKA rename to assets/saves/thugpro/astrovan.SKA diff --git a/assets/saves/b2.SKA b/assets/saves/thugpro/b2.SKA similarity index 100% rename from assets/saves/b2.SKA rename to assets/saves/thugpro/b2.SKA diff --git a/assets/saves/bace.SKA b/assets/saves/thugpro/bace.SKA similarity index 100% rename from assets/saves/bace.SKA rename to assets/saves/thugpro/bace.SKA diff --git a/assets/saves/bacelec.SKA b/assets/saves/thugpro/bacelec.SKA similarity index 100% rename from assets/saves/bacelec.SKA rename to assets/saves/thugpro/bacelec.SKA diff --git a/assets/saves/bacetltv2.SKA b/assets/saves/thugpro/bacetltv2.SKA similarity index 100% rename from assets/saves/bacetltv2.SKA rename to assets/saves/thugpro/bacetltv2.SKA diff --git a/assets/saves/bacetlv22.SKA b/assets/saves/thugpro/bacetlv22.SKA similarity index 100% rename from assets/saves/bacetlv22.SKA rename to assets/saves/thugpro/bacetlv22.SKA diff --git a/assets/saves/badacehood.SKA b/assets/saves/thugpro/badacehood.SKA similarity index 100% rename from assets/saves/badacehood.SKA rename to assets/saves/thugpro/badacehood.SKA diff --git a/assets/saves/bigpimpin.SKA b/assets/saves/thugpro/bigpimpin.SKA similarity index 100% rename from assets/saves/bigpimpin.SKA rename to assets/saves/thugpro/bigpimpin.SKA diff --git a/assets/saves/bigpimpin1.SKA b/assets/saves/thugpro/bigpimpin1.SKA similarity index 100% rename from assets/saves/bigpimpin1.SKA rename to assets/saves/thugpro/bigpimpin1.SKA diff --git a/assets/saves/bitch69.SKA b/assets/saves/thugpro/bitch69.SKA similarity index 100% rename from assets/saves/bitch69.SKA rename to assets/saves/thugpro/bitch69.SKA diff --git a/assets/saves/blacknyello.SKA b/assets/saves/thugpro/blacknyello.SKA similarity index 100% rename from assets/saves/blacknyello.SKA rename to assets/saves/thugpro/blacknyello.SKA diff --git a/assets/saves/blackvestupsend.SKA b/assets/saves/thugpro/blackvestupsend.SKA similarity index 100% rename from assets/saves/blackvestupsend.SKA rename to assets/saves/thugpro/blackvestupsend.SKA diff --git a/assets/saves/blu sunhat.SKA b/assets/saves/thugpro/blu sunhat.SKA similarity index 100% rename from assets/saves/blu sunhat.SKA rename to assets/saves/thugpro/blu sunhat.SKA diff --git a/assets/saves/blur.SKA b/assets/saves/thugpro/blur.SKA similarity index 100% rename from assets/saves/blur.SKA rename to assets/saves/thugpro/blur.SKA diff --git a/assets/saves/blurnewog.SKA b/assets/saves/thugpro/blurnewog.SKA similarity index 100% rename from assets/saves/blurnewog.SKA rename to assets/saves/thugpro/blurnewog.SKA diff --git a/assets/saves/blursmgvid2.SKA b/assets/saves/thugpro/blursmgvid2.SKA similarity index 100% rename from assets/saves/blursmgvid2.SKA rename to assets/saves/thugpro/blursmgvid2.SKA diff --git a/assets/saves/boiiwonda.SKA b/assets/saves/thugpro/boiiwonda.SKA similarity index 100% rename from assets/saves/boiiwonda.SKA rename to assets/saves/thugpro/boiiwonda.SKA diff --git a/assets/saves/bootsss.SKA b/assets/saves/thugpro/bootsss.SKA similarity index 100% rename from assets/saves/bootsss.SKA rename to assets/saves/thugpro/bootsss.SKA diff --git a/assets/saves/c4Carl Johnson.SKA b/assets/saves/thugpro/c4Carl Johnson.SKA similarity index 100% rename from assets/saves/c4Carl Johnson.SKA rename to assets/saves/thugpro/c4Carl Johnson.SKA diff --git a/assets/saves/c7pink.SKA b/assets/saves/thugpro/c7pink.SKA similarity index 100% rename from assets/saves/c7pink.SKA rename to assets/saves/thugpro/c7pink.SKA diff --git a/assets/saves/cWalkertStyle.SKA b/assets/saves/thugpro/cWalkertStyle.SKA similarity index 100% rename from assets/saves/cWalkertStyle.SKA rename to assets/saves/thugpro/cWalkertStyle.SKA diff --git a/assets/saves/camosunhat.SKA b/assets/saves/thugpro/camosunhat.SKA similarity index 100% rename from assets/saves/camosunhat.SKA rename to assets/saves/thugpro/camosunhat.SKA diff --git a/assets/saves/cbeanie.SKA b/assets/saves/thugpro/cbeanie.SKA similarity index 100% rename from assets/saves/cbeanie.SKA rename to assets/saves/thugpro/cbeanie.SKA diff --git a/assets/saves/ccowboy.SKA b/assets/saves/thugpro/ccowboy.SKA similarity index 100% rename from assets/saves/ccowboy.SKA rename to assets/saves/thugpro/ccowboy.SKA diff --git a/assets/saves/cdasendah.SKA b/assets/saves/thugpro/cdasendah.SKA similarity index 100% rename from assets/saves/cdasendah.SKA rename to assets/saves/thugpro/cdasendah.SKA diff --git a/assets/saves/cdoc.SKA b/assets/saves/thugpro/cdoc.SKA similarity index 100% rename from assets/saves/cdoc.SKA rename to assets/saves/thugpro/cdoc.SKA diff --git a/assets/saves/cdot r y afro.SKA b/assets/saves/thugpro/cdot r y afro.SKA similarity index 100% rename from assets/saves/cdot r y afro.SKA rename to assets/saves/thugpro/cdot r y afro.SKA diff --git a/assets/saves/cdot.SKA b/assets/saves/thugpro/cdot.SKA similarity index 100% rename from assets/saves/cdot.SKA rename to assets/saves/thugpro/cdot.SKA diff --git a/assets/saves/cdot2.SKA b/assets/saves/thugpro/cdot2.SKA similarity index 100% rename from assets/saves/cdot2.SKA rename to assets/saves/thugpro/cdot2.SKA diff --git a/assets/saves/cdot3.SKA b/assets/saves/thugpro/cdot3.SKA similarity index 100% rename from assets/saves/cdot3.SKA rename to assets/saves/thugpro/cdot3.SKA diff --git a/assets/saves/cdot4.SKA b/assets/saves/thugpro/cdot4.SKA similarity index 100% rename from assets/saves/cdot4.SKA rename to assets/saves/thugpro/cdot4.SKA diff --git a/assets/saves/cdotccandy.SKA b/assets/saves/thugpro/cdotccandy.SKA similarity index 100% rename from assets/saves/cdotccandy.SKA rename to assets/saves/thugpro/cdotccandy.SKA diff --git a/assets/saves/cdotcdot.SKA b/assets/saves/thugpro/cdotcdot.SKA similarity index 100% rename from assets/saves/cdotcdot.SKA rename to assets/saves/thugpro/cdotcdot.SKA diff --git a/assets/saves/cdotgreenhelmet.SKA b/assets/saves/thugpro/cdotgreenhelmet.SKA similarity index 100% rename from assets/saves/cdotgreenhelmet.SKA rename to assets/saves/thugpro/cdotgreenhelmet.SKA diff --git a/assets/saves/cdotgrenwhite.SKA b/assets/saves/thugpro/cdotgrenwhite.SKA similarity index 100% rename from assets/saves/cdotgrenwhite.SKA rename to assets/saves/thugpro/cdotgrenwhite.SKA diff --git a/assets/saves/cdotpink.SKA b/assets/saves/thugpro/cdotpink.SKA similarity index 100% rename from assets/saves/cdotpink.SKA rename to assets/saves/thugpro/cdotpink.SKA diff --git a/assets/saves/cdotslime.SKA b/assets/saves/thugpro/cdotslime.SKA similarity index 100% rename from assets/saves/cdotslime.SKA rename to assets/saves/thugpro/cdotslime.SKA diff --git a/assets/saves/cdotsmokescales.SKA b/assets/saves/thugpro/cdotsmokescales.SKA similarity index 100% rename from assets/saves/cdotsmokescales.SKA rename to assets/saves/thugpro/cdotsmokescales.SKA diff --git a/assets/saves/cdotxxxposed.SKA b/assets/saves/thugpro/cdotxxxposed.SKA similarity index 100% rename from assets/saves/cdotxxxposed.SKA rename to assets/saves/thugpro/cdotxxxposed.SKA diff --git a/assets/saves/conad.SKA b/assets/saves/thugpro/conad.SKA similarity index 100% rename from assets/saves/conad.SKA rename to assets/saves/thugpro/conad.SKA diff --git a/assets/saves/conad2.SKA b/assets/saves/thugpro/conad2.SKA similarity index 100% rename from assets/saves/conad2.SKA rename to assets/saves/thugpro/conad2.SKA diff --git a/assets/saves/cotton_candy.SKA b/assets/saves/thugpro/cotton_candy.SKA similarity index 100% rename from assets/saves/cotton_candy.SKA rename to assets/saves/thugpro/cotton_candy.SKA diff --git a/assets/saves/cotton_candy2.SKA b/assets/saves/thugpro/cotton_candy2.SKA similarity index 100% rename from assets/saves/cotton_candy2.SKA rename to assets/saves/thugpro/cotton_candy2.SKA diff --git a/assets/saves/cottoncandymf.SKA b/assets/saves/thugpro/cottoncandymf.SKA similarity index 100% rename from assets/saves/cottoncandymf.SKA rename to assets/saves/thugpro/cottoncandymf.SKA diff --git a/assets/saves/crim.SKA b/assets/saves/thugpro/crim.SKA similarity index 100% rename from assets/saves/crim.SKA rename to assets/saves/thugpro/crim.SKA diff --git a/assets/saves/crimm.SKA b/assets/saves/thugpro/crimm.SKA similarity index 100% rename from assets/saves/crimm.SKA rename to assets/saves/thugpro/crimm.SKA diff --git a/assets/saves/cthotSantaHoe.SKA b/assets/saves/thugpro/cthotSantaHoe.SKA similarity index 100% rename from assets/saves/cthotSantaHoe.SKA rename to assets/saves/thugpro/cthotSantaHoe.SKA diff --git a/assets/saves/cthotremake.SKA b/assets/saves/thugpro/cthotremake.SKA similarity index 100% rename from assets/saves/cthotremake.SKA rename to assets/saves/thugpro/cthotremake.SKA diff --git a/assets/saves/cthottie.SKA b/assets/saves/thugpro/cthottie.SKA similarity index 100% rename from assets/saves/cthottie.SKA rename to assets/saves/thugpro/cthottie.SKA diff --git a/assets/saves/cthotv2.SKA b/assets/saves/thugpro/cthotv2.SKA similarity index 100% rename from assets/saves/cthotv2.SKA rename to assets/saves/thugpro/cthotv2.SKA diff --git a/assets/saves/curtskater2.SKA b/assets/saves/thugpro/curtskater2.SKA similarity index 100% rename from assets/saves/curtskater2.SKA rename to assets/saves/thugpro/curtskater2.SKA diff --git a/assets/saves/daman.SKA b/assets/saves/thugpro/daman.SKA similarity index 100% rename from assets/saves/daman.SKA rename to assets/saves/thugpro/daman.SKA diff --git a/assets/saves/ded.SKA b/assets/saves/thugpro/ded.SKA similarity index 100% rename from assets/saves/ded.SKA rename to assets/saves/thugpro/ded.SKA diff --git a/assets/saves/ded1.SKA b/assets/saves/thugpro/ded1.SKA similarity index 100% rename from assets/saves/ded1.SKA rename to assets/saves/thugpro/ded1.SKA diff --git a/assets/saves/dns.SKA b/assets/saves/thugpro/dns.SKA similarity index 100% rename from assets/saves/dns.SKA rename to assets/saves/thugpro/dns.SKA diff --git a/assets/saves/draco1017.SKA b/assets/saves/thugpro/draco1017.SKA similarity index 100% rename from assets/saves/draco1017.SKA rename to assets/saves/thugpro/draco1017.SKA diff --git a/assets/saves/draco11.SKA b/assets/saves/thugpro/draco11.SKA similarity index 100% rename from assets/saves/draco11.SKA rename to assets/saves/thugpro/draco11.SKA diff --git a/assets/saves/draghost.SKA b/assets/saves/thugpro/draghost.SKA similarity index 100% rename from assets/saves/draghost.SKA rename to assets/saves/thugpro/draghost.SKA diff --git a/assets/saves/dragon.SKA b/assets/saves/thugpro/dragon.SKA similarity index 100% rename from assets/saves/dragon.SKA rename to assets/saves/thugpro/dragon.SKA diff --git a/assets/saves/dragontlt1.SKA b/assets/saves/thugpro/dragontlt1.SKA similarity index 100% rename from assets/saves/dragontlt1.SKA rename to assets/saves/thugpro/dragontlt1.SKA diff --git a/assets/saves/drakcdot.SKA b/assets/saves/thugpro/drakcdot.SKA similarity index 100% rename from assets/saves/drakcdot.SKA rename to assets/saves/thugpro/drakcdot.SKA diff --git a/assets/saves/drakcdot1.SKA b/assets/saves/thugpro/drakcdot1.SKA similarity index 100% rename from assets/saves/drakcdot1.SKA rename to assets/saves/thugpro/drakcdot1.SKA diff --git a/assets/saves/eG2.SKA b/assets/saves/thugpro/eG2.SKA similarity index 100% rename from assets/saves/eG2.SKA rename to assets/saves/thugpro/eG2.SKA diff --git a/assets/saves/edem 22.SKA b/assets/saves/thugpro/edem 22.SKA similarity index 100% rename from assets/saves/edem 22.SKA rename to assets/saves/thugpro/edem 22.SKA diff --git a/assets/saves/elecbright.SKA b/assets/saves/thugpro/elecbright.SKA similarity index 100% rename from assets/saves/elecbright.SKA rename to assets/saves/thugpro/elecbright.SKA diff --git a/assets/saves/evilsanjfixed.SKA b/assets/saves/thugpro/evilsanjfixed.SKA similarity index 100% rename from assets/saves/evilsanjfixed.SKA rename to assets/saves/thugpro/evilsanjfixed.SKA diff --git a/assets/saves/fayteish.SKA b/assets/saves/thugpro/fayteish.SKA similarity index 100% rename from assets/saves/fayteish.SKA rename to assets/saves/thugpro/fayteish.SKA diff --git a/assets/saves/faytejersey.SKA b/assets/saves/thugpro/faytejersey.SKA similarity index 100% rename from assets/saves/faytejersey.SKA rename to assets/saves/thugpro/faytejersey.SKA diff --git a/assets/saves/fayteptcelec.SKA b/assets/saves/thugpro/fayteptcelec.SKA similarity index 100% rename from assets/saves/fayteptcelec.SKA rename to assets/saves/thugpro/fayteptcelec.SKA diff --git a/assets/saves/fazo.SKA b/assets/saves/thugpro/fazo.SKA similarity index 100% rename from assets/saves/fazo.SKA rename to assets/saves/thugpro/fazo.SKA diff --git a/assets/saves/fireboy69.SKA b/assets/saves/thugpro/fireboy69.SKA similarity index 100% rename from assets/saves/fireboy69.SKA rename to assets/saves/thugpro/fireboy69.SKA diff --git a/assets/saves/forcdot.SKA b/assets/saves/thugpro/forcdot.SKA similarity index 100% rename from assets/saves/forcdot.SKA rename to assets/saves/thugpro/forcdot.SKA diff --git a/assets/saves/freddy.SKA b/assets/saves/thugpro/freddy.SKA similarity index 100% rename from assets/saves/freddy.SKA rename to assets/saves/thugpro/freddy.SKA diff --git a/assets/saves/fuxwitit.SKA b/assets/saves/thugpro/fuxwitit.SKA similarity index 100% rename from assets/saves/fuxwitit.SKA rename to assets/saves/thugpro/fuxwitit.SKA diff --git a/assets/saves/george11111.SKA b/assets/saves/thugpro/george11111.SKA similarity index 100% rename from assets/saves/george11111.SKA rename to assets/saves/thugpro/george11111.SKA diff --git a/assets/saves/georgetlt.SKA b/assets/saves/thugpro/georgetlt.SKA similarity index 100% rename from assets/saves/georgetlt.SKA rename to assets/saves/thugpro/georgetlt.SKA diff --git a/assets/saves/ghostpurple.SKA b/assets/saves/thugpro/ghostpurple.SKA similarity index 100% rename from assets/saves/ghostpurple.SKA rename to assets/saves/thugpro/ghostpurple.SKA diff --git a/assets/saves/ghostyellow.SKA b/assets/saves/thugpro/ghostyellow.SKA similarity index 100% rename from assets/saves/ghostyellow.SKA rename to assets/saves/thugpro/ghostyellow.SKA diff --git a/assets/saves/gonz0.SKA b/assets/saves/thugpro/gonz0.SKA similarity index 100% rename from assets/saves/gonz0.SKA rename to assets/saves/thugpro/gonz0.SKA diff --git a/assets/saves/goz.SKA b/assets/saves/thugpro/goz.SKA similarity index 100% rename from assets/saves/goz.SKA rename to assets/saves/thugpro/goz.SKA diff --git a/assets/saves/greenjerseyafro.SKA b/assets/saves/thugpro/greenjerseyafro.SKA similarity index 100% rename from assets/saves/greenjerseyafro.SKA rename to assets/saves/thugpro/greenjerseyafro.SKA diff --git a/assets/saves/greenwhitedot.SKA b/assets/saves/thugpro/greenwhitedot.SKA similarity index 100% rename from assets/saves/greenwhitedot.SKA rename to assets/saves/thugpro/greenwhitedot.SKA diff --git a/assets/saves/gurl.SKA b/assets/saves/thugpro/gurl.SKA similarity index 100% rename from assets/saves/gurl.SKA rename to assets/saves/thugpro/gurl.SKA diff --git a/assets/saves/gurlive.SKA b/assets/saves/thugpro/gurlive.SKA similarity index 100% rename from assets/saves/gurlive.SKA rename to assets/saves/thugpro/gurlive.SKA diff --git a/assets/saves/hippie.SKA b/assets/saves/thugpro/hippie.SKA similarity index 100% rename from assets/saves/hippie.SKA rename to assets/saves/thugpro/hippie.SKA diff --git a/assets/saves/hippiecdot.SKA b/assets/saves/thugpro/hippiecdot.SKA similarity index 100% rename from assets/saves/hippiecdot.SKA rename to assets/saves/thugpro/hippiecdot.SKA diff --git a/assets/saves/hoe.SKA b/assets/saves/thugpro/hoe.SKA similarity index 100% rename from assets/saves/hoe.SKA rename to assets/saves/thugpro/hoe.SKA diff --git a/assets/saves/icey.SKA b/assets/saves/thugpro/icey.SKA similarity index 100% rename from assets/saves/icey.SKA rename to assets/saves/thugpro/icey.SKA diff --git a/assets/saves/idkaman4.SKA b/assets/saves/thugpro/idkaman4.SKA similarity index 100% rename from assets/saves/idkaman4.SKA rename to assets/saves/thugpro/idkaman4.SKA diff --git a/assets/saves/j5 test.SKA b/assets/saves/thugpro/j5 test.SKA similarity index 100% rename from assets/saves/j5 test.SKA rename to assets/saves/thugpro/j5 test.SKA diff --git a/assets/saves/j5.SKA b/assets/saves/thugpro/j5.SKA similarity index 100% rename from assets/saves/j5.SKA rename to assets/saves/thugpro/j5.SKA diff --git a/assets/saves/jaycee.SKA b/assets/saves/thugpro/jaycee.SKA similarity index 100% rename from assets/saves/jaycee.SKA rename to assets/saves/thugpro/jaycee.SKA diff --git a/assets/saves/jayceetek.SKA b/assets/saves/thugpro/jayceetek.SKA similarity index 100% rename from assets/saves/jayceetek.SKA rename to assets/saves/thugpro/jayceetek.SKA diff --git a/assets/saves/jehcc.SKA b/assets/saves/thugpro/jehcc.SKA similarity index 100% rename from assets/saves/jehcc.SKA rename to assets/saves/thugpro/jehcc.SKA diff --git a/assets/saves/jinzo.SKA b/assets/saves/thugpro/jinzo.SKA similarity index 100% rename from assets/saves/jinzo.SKA rename to assets/saves/thugpro/jinzo.SKA diff --git a/assets/saves/jokerdotty.SKA b/assets/saves/thugpro/jokerdotty.SKA similarity index 100% rename from assets/saves/jokerdotty.SKA rename to assets/saves/thugpro/jokerdotty.SKA diff --git a/assets/saves/jokrdot.SKA b/assets/saves/thugpro/jokrdot.SKA similarity index 100% rename from assets/saves/jokrdot.SKA rename to assets/saves/thugpro/jokrdot.SKA diff --git a/assets/saves/jolly22.SKA b/assets/saves/thugpro/jolly22.SKA similarity index 100% rename from assets/saves/jolly22.SKA rename to assets/saves/thugpro/jolly22.SKA diff --git a/assets/saves/jona.SKA b/assets/saves/thugpro/jona.SKA similarity index 100% rename from assets/saves/jona.SKA rename to assets/saves/thugpro/jona.SKA diff --git a/assets/saves/jonathek.SKA b/assets/saves/thugpro/jonathek.SKA similarity index 100% rename from assets/saves/jonathek.SKA rename to assets/saves/thugpro/jonathek.SKA diff --git a/assets/saves/konek3.SKA b/assets/saves/thugpro/konek3.SKA similarity index 100% rename from assets/saves/konek3.SKA rename to assets/saves/thugpro/konek3.SKA diff --git a/assets/saves/konekL.SKA b/assets/saves/thugpro/konekL.SKA similarity index 100% rename from assets/saves/konekL.SKA rename to assets/saves/thugpro/konekL.SKA diff --git a/assets/saves/ksk.SKA b/assets/saves/thugpro/ksk.SKA similarity index 100% rename from assets/saves/ksk.SKA rename to assets/saves/thugpro/ksk.SKA diff --git a/assets/saves/ksksk.SKA b/assets/saves/thugpro/ksksk.SKA similarity index 100% rename from assets/saves/ksksk.SKA rename to assets/saves/thugpro/ksksk.SKA diff --git a/assets/saves/maxfli1.SKA b/assets/saves/thugpro/maxfli1.SKA similarity index 100% rename from assets/saves/maxfli1.SKA rename to assets/saves/thugpro/maxfli1.SKA diff --git a/assets/saves/maxfli2.SKA b/assets/saves/thugpro/maxfli2.SKA similarity index 100% rename from assets/saves/maxfli2.SKA rename to assets/saves/thugpro/maxfli2.SKA diff --git a/assets/saves/maxflilike.SKA b/assets/saves/thugpro/maxflilike.SKA similarity index 100% rename from assets/saves/maxflilike.SKA rename to assets/saves/thugpro/maxflilike.SKA diff --git a/assets/saves/mf2smg1.SKA b/assets/saves/thugpro/mf2smg1.SKA similarity index 100% rename from assets/saves/mf2smg1.SKA rename to assets/saves/thugpro/mf2smg1.SKA diff --git a/assets/saves/mikeghost3.SKA b/assets/saves/thugpro/mikeghost3.SKA similarity index 100% rename from assets/saves/mikeghost3.SKA rename to assets/saves/thugpro/mikeghost3.SKA diff --git a/assets/saves/mista2.SKA b/assets/saves/thugpro/mista2.SKA similarity index 100% rename from assets/saves/mista2.SKA rename to assets/saves/thugpro/mista2.SKA diff --git a/assets/saves/mont.SKA b/assets/saves/thugpro/mont.SKA similarity index 100% rename from assets/saves/mont.SKA rename to assets/saves/thugpro/mont.SKA diff --git a/assets/saves/montbombs.SKA b/assets/saves/thugpro/montbombs.SKA similarity index 100% rename from assets/saves/montbombs.SKA rename to assets/saves/thugpro/montbombs.SKA diff --git a/assets/saves/myoldcas.SKA b/assets/saves/thugpro/myoldcas.SKA similarity index 100% rename from assets/saves/myoldcas.SKA rename to assets/saves/thugpro/myoldcas.SKA diff --git a/assets/saves/ness.SKA b/assets/saves/thugpro/ness.SKA similarity index 100% rename from assets/saves/ness.SKA rename to assets/saves/thugpro/ness.SKA diff --git a/assets/saves/newcas.SKA b/assets/saves/thugpro/newcas.SKA similarity index 100% rename from assets/saves/newcas.SKA rename to assets/saves/thugpro/newcas.SKA diff --git a/assets/saves/newtek.SKA b/assets/saves/thugpro/newtek.SKA similarity index 100% rename from assets/saves/newtek.SKA rename to assets/saves/thugpro/newtek.SKA diff --git a/assets/saves/o.SKA b/assets/saves/thugpro/o.SKA similarity index 100% rename from assets/saves/o.SKA rename to assets/saves/thugpro/o.SKA diff --git a/assets/saves/og.SKA b/assets/saves/thugpro/og.SKA similarity index 100% rename from assets/saves/og.SKA rename to assets/saves/thugpro/og.SKA diff --git a/assets/saves/oldfaytecas1.SKA b/assets/saves/thugpro/oldfaytecas1.SKA similarity index 100% rename from assets/saves/oldfaytecas1.SKA rename to assets/saves/thugpro/oldfaytecas1.SKA diff --git a/assets/saves/oldmecas.SKA b/assets/saves/thugpro/oldmecas.SKA similarity index 100% rename from assets/saves/oldmecas.SKA rename to assets/saves/thugpro/oldmecas.SKA diff --git a/assets/saves/oldogcas.SKA b/assets/saves/thugpro/oldogcas.SKA similarity index 100% rename from assets/saves/oldogcas.SKA rename to assets/saves/thugpro/oldogcas.SKA diff --git a/assets/saves/oldogcas1.SKA b/assets/saves/thugpro/oldogcas1.SKA similarity index 100% rename from assets/saves/oldogcas1.SKA rename to assets/saves/thugpro/oldogcas1.SKA diff --git a/assets/saves/paggreensunhat.SKA b/assets/saves/thugpro/paggreensunhat.SKA similarity index 100% rename from assets/saves/paggreensunhat.SKA rename to assets/saves/thugpro/paggreensunhat.SKA diff --git a/assets/saves/pagsunhat.SKA b/assets/saves/thugpro/pagsunhat.SKA similarity index 100% rename from assets/saves/pagsunhat.SKA rename to assets/saves/thugpro/pagsunhat.SKA diff --git a/assets/saves/pagsunhat1.SKA b/assets/saves/thugpro/pagsunhat1.SKA similarity index 100% rename from assets/saves/pagsunhat1.SKA rename to assets/saves/thugpro/pagsunhat1.SKA diff --git a/assets/saves/pants.SKA b/assets/saves/thugpro/pants.SKA similarity index 100% rename from assets/saves/pants.SKA rename to assets/saves/thugpro/pants.SKA diff --git a/assets/saves/paperhat.SKA b/assets/saves/thugpro/paperhat.SKA similarity index 100% rename from assets/saves/paperhat.SKA rename to assets/saves/thugpro/paperhat.SKA diff --git a/assets/saves/pink.SKA b/assets/saves/thugpro/pink.SKA similarity index 100% rename from assets/saves/pink.SKA rename to assets/saves/thugpro/pink.SKA diff --git a/assets/saves/pinkblack.SKA b/assets/saves/thugpro/pinkblack.SKA similarity index 100% rename from assets/saves/pinkblack.SKA rename to assets/saves/thugpro/pinkblack.SKA diff --git a/assets/saves/pinkdread.SKA b/assets/saves/thugpro/pinkdread.SKA similarity index 100% rename from assets/saves/pinkdread.SKA rename to assets/saves/thugpro/pinkdread.SKA diff --git a/assets/saves/pinklikecamron.SKA b/assets/saves/thugpro/pinklikecamron.SKA similarity index 100% rename from assets/saves/pinklikecamron.SKA rename to assets/saves/thugpro/pinklikecamron.SKA diff --git a/assets/saves/pinkmohawk.SKA b/assets/saves/thugpro/pinkmohawk.SKA similarity index 100% rename from assets/saves/pinkmohawk.SKA rename to assets/saves/thugpro/pinkmohawk.SKA diff --git a/assets/saves/ravneww.SKA b/assets/saves/thugpro/ravneww.SKA similarity index 100% rename from assets/saves/ravneww.SKA rename to assets/saves/thugpro/ravneww.SKA diff --git a/assets/saves/rb1.SKA b/assets/saves/thugpro/rb1.SKA similarity index 100% rename from assets/saves/rb1.SKA rename to assets/saves/thugpro/rb1.SKA diff --git a/assets/saves/realdraco.SKA b/assets/saves/thugpro/realdraco.SKA similarity index 100% rename from assets/saves/realdraco.SKA rename to assets/saves/thugpro/realdraco.SKA diff --git a/assets/saves/remake2.SKA b/assets/saves/thugpro/remake2.SKA similarity index 100% rename from assets/saves/remake2.SKA rename to assets/saves/thugpro/remake2.SKA diff --git a/assets/saves/russian.SKA b/assets/saves/thugpro/russian.SKA similarity index 100% rename from assets/saves/russian.SKA rename to assets/saves/thugpro/russian.SKA diff --git a/assets/saves/russianjacket.SKA b/assets/saves/thugpro/russianjacket.SKA similarity index 100% rename from assets/saves/russianjacket.SKA rename to assets/saves/thugpro/russianjacket.SKA diff --git a/assets/saves/sandwhich bag.SKA b/assets/saves/thugpro/sandwhich bag.SKA similarity index 100% rename from assets/saves/sandwhich bag.SKA rename to assets/saves/thugpro/sandwhich bag.SKA diff --git a/assets/saves/santa.SKA b/assets/saves/thugpro/santa.SKA similarity index 100% rename from assets/saves/santa.SKA rename to assets/saves/thugpro/santa.SKA diff --git a/assets/saves/silent.SKA b/assets/saves/thugpro/silent.SKA similarity index 100% rename from assets/saves/silent.SKA rename to assets/saves/thugpro/silent.SKA diff --git a/assets/saves/slimehoodie.SKA b/assets/saves/thugpro/slimehoodie.SKA similarity index 100% rename from assets/saves/slimehoodie.SKA rename to assets/saves/thugpro/slimehoodie.SKA diff --git a/assets/saves/smg2pizza.SKA b/assets/saves/thugpro/smg2pizza.SKA similarity index 100% rename from assets/saves/smg2pizza.SKA rename to assets/saves/thugpro/smg2pizza.SKA diff --git a/assets/saves/smoke.SKA b/assets/saves/thugpro/smoke.SKA similarity index 100% rename from assets/saves/smoke.SKA rename to assets/saves/thugpro/smoke.SKA diff --git a/assets/saves/somewhatfayte.SKA b/assets/saves/thugpro/somewhatfayte.SKA similarity index 100% rename from assets/saves/somewhatfayte.SKA rename to assets/saves/thugpro/somewhatfayte.SKA diff --git a/assets/saves/sonics.SKA b/assets/saves/thugpro/sonics.SKA similarity index 100% rename from assets/saves/sonics.SKA rename to assets/saves/thugpro/sonics.SKA diff --git a/assets/saves/spbobsmg.SKA b/assets/saves/thugpro/spbobsmg.SKA similarity index 100% rename from assets/saves/spbobsmg.SKA rename to assets/saves/thugpro/spbobsmg.SKA diff --git a/assets/saves/spooker.SKA b/assets/saves/thugpro/spooker.SKA similarity index 100% rename from assets/saves/spooker.SKA rename to assets/saves/thugpro/spooker.SKA diff --git a/assets/saves/sunhatscales.SKA b/assets/saves/thugpro/sunhatscales.SKA similarity index 100% rename from assets/saves/sunhatscales.SKA rename to assets/saves/thugpro/sunhatscales.SKA diff --git a/assets/saves/thiccboi.SKA b/assets/saves/thugpro/thiccboi.SKA similarity index 100% rename from assets/saves/thiccboi.SKA rename to assets/saves/thugpro/thiccboi.SKA diff --git a/assets/saves/thugg.SKA b/assets/saves/thugpro/thugg.SKA similarity index 100% rename from assets/saves/thugg.SKA rename to assets/saves/thugpro/thugg.SKA diff --git a/assets/saves/thugg_2.SKA b/assets/saves/thugpro/thugg_2.SKA similarity index 100% rename from assets/saves/thugg_2.SKA rename to assets/saves/thugpro/thugg_2.SKA diff --git a/assets/saves/thuggcrazy.SKA b/assets/saves/thugpro/thuggcrazy.SKA similarity index 100% rename from assets/saves/thuggcrazy.SKA rename to assets/saves/thugpro/thuggcrazy.SKA diff --git a/assets/saves/tlt22222.SKA b/assets/saves/thugpro/tlt22222.SKA similarity index 100% rename from assets/saves/tlt22222.SKA rename to assets/saves/thugpro/tlt22222.SKA diff --git a/assets/saves/tltv5faytelec.SKA b/assets/saves/thugpro/tltv5faytelec.SKA similarity index 100% rename from assets/saves/tltv5faytelec.SKA rename to assets/saves/thugpro/tltv5faytelec.SKA diff --git a/assets/saves/uhhh_hmm.SKA b/assets/saves/thugpro/uhhh_hmm.SKA similarity index 100% rename from assets/saves/uhhh_hmm.SKA rename to assets/saves/thugpro/uhhh_hmm.SKA diff --git a/assets/saves/v1c.SKA b/assets/saves/thugpro/v1c.SKA similarity index 100% rename from assets/saves/v1c.SKA rename to assets/saves/thugpro/v1c.SKA diff --git a/assets/saves/vegasmg2.SKA b/assets/saves/thugpro/vegasmg2.SKA similarity index 100% rename from assets/saves/vegasmg2.SKA rename to assets/saves/thugpro/vegasmg2.SKA diff --git a/assets/saves/velho.SKA b/assets/saves/thugpro/velho.SKA similarity index 100% rename from assets/saves/velho.SKA rename to assets/saves/thugpro/velho.SKA diff --git a/assets/saves/vestupson.SKA b/assets/saves/thugpro/vestupson.SKA similarity index 100% rename from assets/saves/vestupson.SKA rename to assets/saves/thugpro/vestupson.SKA diff --git a/assets/saves/vestupwbeanie.SKA b/assets/saves/thugpro/vestupwbeanie.SKA similarity index 100% rename from assets/saves/vestupwbeanie.SKA rename to assets/saves/thugpro/vestupwbeanie.SKA diff --git a/assets/saves/vicphun.SKA b/assets/saves/thugpro/vicphun.SKA similarity index 100% rename from assets/saves/vicphun.SKA rename to assets/saves/thugpro/vicphun.SKA diff --git a/assets/saves/viking.SKA b/assets/saves/thugpro/viking.SKA similarity index 100% rename from assets/saves/viking.SKA rename to assets/saves/thugpro/viking.SKA diff --git a/assets/saves/whitepink.SKA b/assets/saves/thugpro/whitepink.SKA similarity index 100% rename from assets/saves/whitepink.SKA rename to assets/saves/thugpro/whitepink.SKA diff --git a/assets/saves/wormgurl.SKA b/assets/saves/thugpro/wormgurl.SKA similarity index 100% rename from assets/saves/wormgurl.SKA rename to assets/saves/thugpro/wormgurl.SKA diff --git a/assets/saves/wormgurlbw.SKA b/assets/saves/thugpro/wormgurlbw.SKA similarity index 100% rename from assets/saves/wormgurlbw.SKA rename to assets/saves/thugpro/wormgurlbw.SKA diff --git a/assets/saves/wormslime.SKA b/assets/saves/thugpro/wormslime.SKA similarity index 100% rename from assets/saves/wormslime.SKA rename to assets/saves/thugpro/wormslime.SKA diff --git a/assets/saves/wormsmonkknk.SKA b/assets/saves/thugpro/wormsmonkknk.SKA similarity index 100% rename from assets/saves/wormsmonkknk.SKA rename to assets/saves/thugpro/wormsmonkknk.SKA diff --git a/assets/saves/x3og.SKA b/assets/saves/thugpro/x3og.SKA similarity index 100% rename from assets/saves/x3og.SKA rename to assets/saves/thugpro/x3og.SKA diff --git a/assets/saves/zoo.SKA b/assets/saves/thugpro/zoo.SKA similarity index 100% rename from assets/saves/zoo.SKA rename to assets/saves/thugpro/zoo.SKA diff --git a/crates/cascade-app/src/dashboard.rs b/crates/cascade-app/src/dashboard.rs index e74f254..9af6fae 100644 --- a/crates/cascade-app/src/dashboard.rs +++ b/crates/cascade-app/src/dashboard.rs @@ -745,7 +745,7 @@ async fn process_entry>( log::info!("overwrote save at {:?}", filepath); - entry.overwrite_metadata()?; + entry.rewrite_metadata()?; Ok(()) } diff --git a/crates/cascade-backend/src/lib.rs b/crates/cascade-backend/src/lib.rs index 8aa38b6..0f1f460 100644 --- a/crates/cascade-backend/src/lib.rs +++ b/crates/cascade-backend/src/lib.rs @@ -1,19 +1,34 @@ -use cascade_save as save; +use std::io::{Read, Seek, Write}; -pub trait Target { - type Entry; - type Error; +// pub trait Parser { +// type Save: Sized; +// type Transform: Sized; +// type Error: Send + Sync + std::error::Error; +// +// fn read(&self, reader: &mut impl Read) -> Result; +// fn write(&self, save: &Self::Save, writer: &mut impl Write) -> Result<(), Self::Error>; +// fn parse(&self, save: &Self::Save) -> Result; +// fn modify(&self, save: &mut Self::Save, transform: Self::Transform) -> Result<(), Self::Error>; +// } - fn name(&self, entry: &Self::Entry) -> impl AsRef; - fn list(&self) -> Result, Self::Error>; - fn read(&self, entry: &Self::Entry) -> Result; - fn write(&self, entry: &Self::Entry, save: &save::Save) -> Result<(), Self::Error>; +pub trait Explorer { + fn list(&self) -> Result, Error>; + fn reader(&self, entry: &Entry) -> Result; + fn writer(&self, entry: &Entry) -> Result; + fn name(&self, entry: &Entry) -> String; + fn rewrite_metadata(&self, entry: &Entry) -> Result<(), Error>; } -pub trait Structure { - type Parsed; - type Error; +pub struct Flags { + pub summary: bool, + pub trickset: bool, + pub scales: bool, +} - fn parse(&self, save: &save::Save) -> Result; - fn modify(&self, save: &mut save::Save, transform: Self::Parsed) -> Result<(), Self::Error>; +pub trait Parser { + fn read(&self, reader: &mut (impl Read + Seek)) -> Result; + fn write(&self, save: &Save, writer: &mut impl Write) -> Result<(), Error>; + fn parse(&self, save: &Save) -> Result; + fn mask(&self, cas: Cas, flags: Flags) -> Cas; + fn modify(&self, save: &mut Save, cas: &Cas) -> Result<(), Error>; } diff --git a/crates/cascade-cli/Cargo.toml b/crates/cascade-cli/Cargo.toml index 31ac763..cffae9e 100644 --- a/crates/cascade-cli/Cargo.toml +++ b/crates/cascade-cli/Cargo.toml @@ -4,10 +4,13 @@ version = "0.0.1" edition = "2024" [dependencies] +cascade-backend = { workspace = true } cascade-dump = { workspace = true } cascade-lut = { workspace = true } cascade-qb = { workspace = true } +cascade-rethawed = { workspace = true, features = ["serde"] } cascade-save = { workspace = true } +cascade-thaw = { workspace = true } cascade-thug = { workspace = true } cascade-thps4 = { workspace = true } cascade-thugpro = { workspace = true } diff --git a/crates/cascade-cli/src/main.rs b/crates/cascade-cli/src/main.rs index 933300c..26414a2 100644 --- a/crates/cascade-cli/src/main.rs +++ b/crates/cascade-cli/src/main.rs @@ -1,20 +1,21 @@ use std::{ fmt::Debug, fs::{self, File}, - io::{BufReader, Read, Write}, + io::{self, BufReader, BufWriter, Write}, path::PathBuf, - time::Duration, }; +use cascade_backend::{self as backend}; use cascade_dump as dump; use cascade_lut::{self as lut, Lut}; +use cascade_rethawed as rethawed; use cascade_save::Save; +use cascade_thaw as thaw; use cascade_thps4 as thps4; use cascade_thug as thug; use cascade_thugpro as thugpro; use cascade_wad::{hed, wad}; use clap::{Args, Parser, Subcommand}; -use color_eyre::install; use serde::Serialize; use suppaftp::FtpStream; @@ -34,7 +35,9 @@ enum Game { Thps4, Thug, #[default] - Thugpro, + Thug2, + Thaw, + Rethawed, } #[derive(Debug, Subcommand)] @@ -49,6 +52,48 @@ enum Command { #[arg(short, long)] game: Game, }, + RoundTrip { + #[arg(short, long)] + input: PathBuf, + + #[arg(short, long)] + output: PathBuf, + + #[arg(short, long)] + game: Game, + }, + Modify { + #[arg(long)] + from: PathBuf, + + #[arg(long)] + to: PathBuf, + + #[arg(long)] + game: Game, + + #[arg(long)] + scales: bool, + + #[arg(long)] + trickset: bool, + }, + ModifyBulk { + #[arg(long)] + from: PathBuf, + + #[arg(long)] + to_dir: PathBuf, + + #[arg(long)] + game: Game, + + #[arg(long)] + scales: bool, + + #[arg(long)] + trickset: bool, + }, Randomize { #[arg(long)] input_dir: PathBuf, @@ -95,6 +140,12 @@ enum Command { }, } +#[derive(serde::Serialize, serde::Deserialize)] +enum Dump { + Neversoft(dump::Save), + Rethawed(rethawed::dump::Save), +} + #[derive(Debug, Args)] struct GlobalOpts {} @@ -113,17 +164,27 @@ fn main() -> color_eyre::Result<()> { output, game, } => { - let entry = thugpro::Entry::at_path(&input)?; - let save = Save::read(&mut entry.reader()?)?; + let entry = thugpro::Entry::create(&input)?; let lut = Lut { checksum: lut::Checksum::load()?, compress: match game { Game::Thps4 => thps4::lut::load_compress()?, Game::Thug => thug::lut::load_compress()?, - Game::Thugpro => thugpro::lut::load_compress()?, + Game::Thug2 => thugpro::lut::load_compress()?, + Game::Thaw => thaw::lut::load_compress()?, + Game::Rethawed => rethawed::lut::load_compress()?, }, }; - let dump = dump::Save::new(&save, &lut); + let dump = match game { + Game::Thps4 | Game::Thug | Game::Thug2 | Game::Thaw => { + let save = Save::read(&mut entry.reader()?)?; + Dump::Neversoft(dump::Save::new(&save, &lut)) + } + Game::Rethawed => { + let save = rethawed::save::Save::read(&mut entry.reader()?)?; + Dump::Rethawed(rethawed::dump::Save::new(&save, &lut)) + } + }; let mut file = File::create(output).unwrap(); let contents = @@ -132,6 +193,99 @@ fn main() -> color_eyre::Result<()> { Ok(()) } + Command::RoundTrip { + input, + output, + game, + } => { + fn round_trip( + input: &PathBuf, + output: &PathBuf, + parser: impl backend::Parser, + ) -> Result<(), E> + where + E: From, + { + let file = fs::File::open(&input)?; + let mut reader = BufReader::new(file); + let mut save = parser.read(&mut reader)?; + + let parsed = parser.parse(&save)?; + parser.modify(&mut save, &parsed)?; + + let file = fs::File::create(&output)?; + let mut writer = BufWriter::new(file); + parser.write(&save, &mut writer)?; + + Ok(()) + } + + match game { + Game::Thug2 => round_trip(&input, &output, thugpro::backend::Parser {})?, + Game::Rethawed => round_trip(&input, &output, rethawed::backend::Parser {})?, + Game::Thps4 => todo!(), + Game::Thug => todo!(), + Game::Thaw => todo!(), + } + + Ok(()) + } + Command::Modify { + from, + to, + game, + scales, + trickset, + } => { + let flags = backend::Flags { + trickset, + scales, + summary: false, + }; + + match game { + Game::Thug2 => modify(&from, &to, thugpro::backend::Parser {}, flags)?, + Game::Rethawed => modify(&from, &to, rethawed::backend::Parser {}, flags)?, + Game::Thps4 => todo!(), + Game::Thug => todo!(), + Game::Thaw => todo!(), + } + + Ok(()) + } + Command::ModifyBulk { + from, + to_dir, + game, + scales, + trickset, + } => { + let flags = backend::Flags { + trickset, + scales, + summary: false, + }; + + match game { + Game::Thps4 => todo!(), + Game::Thug => todo!(), + Game::Thug2 => modify_bulk( + &from, + thugpro::backend::Explorer::new(to_dir), + thugpro::backend::Parser {}, + flags, + )?, + Game::Thaw => todo!(), + Game::Rethawed => modify_bulk( + &from, + rethawed::backend::Explorer::new(to_dir), + rethawed::backend::Parser {}, + flags, + )?, + } + + Ok(()) + } Command::Randomize { input_dir, output_dir, @@ -206,3 +360,75 @@ fn main() -> color_eyre::Result<()> { } } } + +fn modify( + from: &PathBuf, + to: &PathBuf, + parser: impl backend::Parser, + flags: backend::Flags, +) -> Result<(), E> +where + E: From, +{ + let from_file = fs::File::open(&from)?; + let mut from_reader = BufReader::new(from_file); + let from_save = parser.read(&mut from_reader)?; + + let to_file = fs::File::open(&to)?; + let mut to_reader = BufReader::new(to_file); + let mut to_save = parser.read(&mut to_reader)?; + + let from_parsed = parser.parse(&from_save)?; + let from_parsed = parser.mask(from_parsed, flags); + parser.modify(&mut to_save, &from_parsed)?; + + let to_file = fs::File::create(&to)?; + let mut writer = BufWriter::new(to_file); + parser.write(&to_save, &mut writer)?; + + Ok(()) +} + +fn modify_bulk( + from: &PathBuf, + explorer: impl backend::Explorer, + parser: impl backend::Parser, + flags: backend::Flags, +) -> Result<(), Error> +where + Error: From + Debug, +{ + fn modify_one( + entry: &Entry, + transform: &Cas, + explorer: &impl backend::Explorer, + parser: &impl backend::Parser, + ) -> Result<(), Error> { + let mut reader = explorer.reader(&entry)?; + let mut save = parser.read(&mut reader)?; + parser.modify(&mut save, &transform)?; + let mut writer = explorer.writer(&entry)?; + parser.write(&save, &mut writer)?; + Ok(()) + } + + let from_file = fs::File::open(&from)?; + let mut from_reader = BufReader::new(from_file); + let from_save = parser.read(&mut from_reader)?; + let from_parsed = parser.parse(&from_save)?; + let transform = parser.mask(from_parsed, flags); + + for entry in explorer.list()? { + let name = explorer.name(&entry); + match modify_one(&entry, &transform, &explorer, &parser) { + Ok(_) => { + println!("successfully copied {}", name) + } + Err(e) => { + println!("error copying {}: {:?}", name, e) + } + } + } + + Ok(()) +} diff --git a/crates/cascade-qb/Cargo.toml b/crates/cascade-qb/Cargo.toml index 8a11d94..9f13b97 100644 --- a/crates/cascade-qb/Cargo.toml +++ b/crates/cascade-qb/Cargo.toml @@ -6,8 +6,8 @@ edition = "2021" [dependencies] byteorder = { workspace = true } count-write = { workspace = true } -thiserror = { workspace = true } serde = { workspace = true, optional = true } +thiserror = { workspace = true } [features] serde = ["dep:serde"] diff --git a/crates/cascade-rethawed/Cargo.toml b/crates/cascade-rethawed/Cargo.toml new file mode 100644 index 0000000..516c13c --- /dev/null +++ b/crates/cascade-rethawed/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "cascade-rethawed" +version = "0.0.1" +edition = "2024" + +[dependencies] +cascade-backend = { workspace = true } +cascade-dump = { workspace = true } +cascade-lut = { workspace = true } +cascade-save = { workspace = true } +cascade-thaw = { workspace = true } +cascade-qb = { workspace = true } + +byteorder = { workspace = true } +filetime = { workspace = true } +log = { workspace = true } +serde = { workspace = true, optional = true } +thiserror = { workspace = true } + +[features] +serde = ["dep:serde"] diff --git a/crates/cascade-rethawed/src/backend.rs b/crates/cascade-rethawed/src/backend.rs new file mode 100644 index 0000000..97acb17 --- /dev/null +++ b/crates/cascade-rethawed/src/backend.rs @@ -0,0 +1,236 @@ +use std::{ + io::{Read, Seek}, + path::PathBuf, +}; + +use cascade_backend as backend; + +use crate::{ + Error, + cas::{self, Cas}, + entry::{self, Entry}, + save::Save, +}; + +pub struct Explorer { + cwd: PathBuf, +} + +impl Explorer { + pub fn new(cwd: PathBuf) -> Self { + Self { cwd } + } +} + +impl backend::Explorer for Explorer { + fn list(&self) -> Result, Error> { + entry::find_entries(&self.cwd).map(|entries| entries.into_iter()) + } + + fn reader(&self, entry: &Entry) -> Result { + entry.reader() + } + + fn writer(&self, entry: &Entry) -> Result { + entry.writer() + } + + fn name(&self, entry: &Entry) -> String { + entry.filename.clone() + } + + fn rewrite_metadata(&self, entry: &Entry) -> Result<(), Error> { + entry.rewrite_metadata() + } +} + +pub struct Parser {} + +impl backend::Parser for Parser { + fn read(&self, reader: &mut (impl Read + Seek)) -> Result { + Save::read(reader) + } + + fn write(&self, save: &Save, writer: &mut impl std::io::Write) -> Result<(), Error> { + save.write(writer) + } + + fn parse(&self, save: &Save) -> Result { + Cas::try_from(save) + } + + fn modify(&self, save: &mut Save, transform: &Cas) -> Result<(), Error> { + transform.modify(save) + } + + fn mask(&self, cas: Cas, flags: backend::Flags) -> Cas { + Cas { + summary: flags.summary.then_some(cas.summary).unwrap_or_default(), + data: cas::Data { + custom_skater: cas::CustomSkater { + custom_classic: cas::CustomClassic { + info: cas::Info { + trick_mapping: flags + .trickset + .then_some(cas.data.custom_skater.custom_classic.info.trick_mapping) + .unwrap_or_default(), + specials: flags + .trickset + .then_some(cas.data.custom_skater.custom_classic.info.specials) + .unwrap_or_default(), + }, + appearance: cas::Appearance { + board_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .board_bone_group, + ) + .unwrap_or_default(), + feet_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .feet_bone_group, + ) + .unwrap_or_default(), + hands_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .hands_bone_group, + ) + .unwrap_or_default(), + head_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .head_bone_group, + ) + .unwrap_or_default(), + headtop_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .headtop_bone_group, + ) + .unwrap_or_default(), + jaw_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .jaw_bone_group, + ) + .unwrap_or_default(), + lower_arm_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .lower_arm_bone_group, + ) + .unwrap_or_default(), + lower_leg_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .lower_leg_bone_group, + ) + .unwrap_or_default(), + nose_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .nose_bone_group, + ) + .unwrap_or_default(), + object_scaling: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .object_scaling, + ) + .unwrap_or_default(), + stomach_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .stomach_bone_group, + ) + .unwrap_or_default(), + torso_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .torso_bone_group, + ) + .unwrap_or_default(), + upper_arm_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .upper_arm_bone_group, + ) + .unwrap_or_default(), + upper_leg_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom_classic + .appearance + .upper_leg_bone_group, + ) + .unwrap_or_default(), + ..Default::default() + }, + }, + }, + story_skater: cas::StorySkater { + tricks: flags + .trickset + .then_some(cas.data.story_skater.tricks) + .unwrap_or_default(), + }, + }, + } + } +} diff --git a/crates/cascade-rethawed/src/cas.rs b/crates/cascade-rethawed/src/cas.rs new file mode 100644 index 0000000..8891721 --- /dev/null +++ b/crates/cascade-rethawed/src/cas.rs @@ -0,0 +1,328 @@ +use cascade_qb as qb; + +use crate::{Error, Result, chunk, id, save::Save}; + +fn expect_symbol(parent: &Box, id: qb::Id) -> Result<&qb::Symbol> { + Ok(parent.get(id).ok_or(Error::SymbolNotFound(id))?) +} + +fn expect_symbol_mut(parent: &mut Box, id: qb::Id) -> Result<&mut qb::Symbol> { + Ok(parent.get_mut(id).ok_or(Error::SymbolNotFound(id))?) +} + +// expect symbol and expect structure +fn expect_structure(parent: &Box, id: qb::Id) -> Result<&Box> { + let symbol = expect_symbol(&parent, id)?; + Ok(symbol.value.try_as_structure()?) +} + +fn expect_structure_mut( + parent: &mut Box, + id: qb::Id, +) -> Result<&mut Box> { + let symbol = expect_symbol_mut(parent, id)?; + Ok(symbol.value.try_as_structure_mut()?) +} + +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum Item { + /// Require a symbol to be present. + Present(qb::Symbol), + /// Require a symbol to be vacant (remove if present). + Vacant, + /// No modification. + #[default] + Ignore, +} + +impl Item { + pub fn modify(&self, structure: &mut qb::Structure, id: qb::Id) { + match self { + Item::Present(symbol) => { + structure.insert(symbol.clone()); + } + Item::Vacant => { + structure.remove(id); + } + Item::Ignore => (), + } + } +} + +impl From for Item { + fn from(value: qb::Symbol) -> Self { + Self::Present(value) + } +} + +impl From> for Item { + fn from(value: Option) -> Self { + match value { + Some(symbol) => Self::from(symbol), + None => Self::Vacant, + } + } +} + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Debug, Clone, Default)] +pub struct Cas { + pub summary: Summary, + pub data: Data, +} + +impl TryFrom<&Save> for Cas { + type Error = Error; + + fn try_from(save: &Save) -> Result { + match save { + Save::Thaw(save) => Ok(Self { + summary: Summary::try_from(&save.summary)?, + data: Data::try_from(&save.data)?, + }), + Save::Rethawed(save) => Ok(Self { + summary: Summary::try_from(&save.try_get_chunk(chunk::Magic::Summary)?.structure)?, + data: Data::try_from(&save.try_get_chunk(chunk::Magic::Data)?.structure)?, + }), + } + } +} + +impl Cas { + pub fn modify(&self, save: &mut Save) -> Result<()> { + self.summary.modify(match save { + Save::Thaw(save) => &mut save.summary, + Save::Rethawed(save) => &mut save.try_get_chunk_mut(chunk::Magic::Summary)?.structure, + }); + self.data.modify(match save { + Save::Thaw(save) => &mut save.data, + Save::Rethawed(save) => &mut save.try_get_chunk_mut(chunk::Magic::Data)?.structure, + })?; + Ok(()) + } +} + +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Summary { + pub filename: Item, +} + +impl Summary { + pub fn modify(&self, summary: &mut Box) { + self.filename.modify(summary, id::FILENAME); + } +} + +impl TryFrom<&Box> for Summary { + type Error = Error; + + fn try_from(summary: &Box) -> Result { + Ok(Self { + filename: summary.get(id::FILENAME).cloned().into(), + }) + } +} + +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Data { + pub custom_skater: CustomSkater, + pub story_skater: StorySkater, +} + +impl TryFrom<&Box> for Data { + type Error = Error; + + fn try_from(data: &Box) -> Result { + Ok(Self { + custom_skater: CustomSkater::try_from(expect_structure(data, id::CUSTOM_SKATER)?)?, + story_skater: StorySkater::try_from(expect_structure(data, id::STORY_SKATER)?)?, + }) + } +} + +impl Data { + pub fn modify(&self, data: &mut Box) -> Result<()> { + self.custom_skater + .modify(expect_structure_mut(data, id::CUSTOM_SKATER)?)?; + + self.story_skater + .modify(expect_structure_mut(data, id::STORY_SKATER)?); + + Ok(()) + } +} + +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct CustomSkater { + pub custom_classic: CustomClassic, +} + +impl TryFrom<&Box> for CustomSkater { + type Error = Error; + + fn try_from(custom_skater: &Box) -> Result { + Ok(Self { + custom_classic: CustomClassic::try_from(expect_structure( + custom_skater, + id::CUSTOM_CLASSIC, + )?)?, + }) + } +} + +impl CustomSkater { + pub fn modify(&self, custom_skater: &mut Box) -> Result<()> { + self.custom_classic + .modify(expect_structure_mut(custom_skater, id::CUSTOM_CLASSIC)?)?; + Ok(()) + } +} + +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct CustomClassic { + pub appearance: Appearance, + pub info: Info, +} + +impl TryFrom<&Box> for CustomClassic { + type Error = Error; + + fn try_from(custom: &Box) -> Result { + Ok(Self { + appearance: Appearance::try_from(expect_structure(custom, id::APPEARANCE)?)?, + info: Info::try_from(expect_structure(custom, id::INFO)?)?, + }) + } +} + +impl CustomClassic { + pub fn modify(&self, custom: &mut Box) -> Result<()> { + self.appearance + .modify(expect_structure_mut(custom, id::APPEARANCE)?); + self.info.modify(expect_structure_mut(custom, id::INFO)?); + + Ok(()) + } +} + +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Info { + pub trick_mapping: Item, + pub specials: Item, +} + +impl TryFrom<&Box> for Info { + type Error = Error; + + fn try_from(info: &Box) -> Result { + Ok(Self { + trick_mapping: info.get(id::TRICK_MAPPING).cloned().into(), + specials: info.get(id::SPECIALS).cloned().into(), + }) + } +} + +impl Info { + pub fn modify(&self, info: &mut qb::Structure) { + self.trick_mapping.modify(info, id::TRICK_MAPPING); + self.specials.modify(info, id::SPECIALS); + } +} + +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Appearance { + pub board_bone_group: Item, + pub feet_bone_group: Item, + pub hands_bone_group: Item, + pub head_bone_group: Item, + pub headtop_bone_group: Item, + pub jaw_bone_group: Item, + pub lower_arm_bone_group: Item, + pub lower_leg_bone_group: Item, + pub nose_bone_group: Item, + pub object_scaling: Item, + pub stomach_bone_group: Item, + pub torso_bone_group: Item, + pub upper_arm_bone_group: Item, + pub upper_leg_bone_group: Item, +} + +impl Appearance { + pub fn modify(&self, appearance: &mut qb::Structure) { + self.board_bone_group + .modify(appearance, id::BOARD_BONE_GROUP); + self.feet_bone_group.modify(appearance, id::FEET_BONE_GROUP); + self.hands_bone_group + .modify(appearance, id::HANDS_BONE_GROUP); + self.head_bone_group.modify(appearance, id::HEAD_BONE_GROUP); + self.headtop_bone_group + .modify(appearance, id::HEADTOP_BONE_GROUP); + self.jaw_bone_group.modify(appearance, id::JAW_BONE_GROUP); + self.lower_arm_bone_group + .modify(appearance, id::LOWER_ARM_BONE_GROUP); + self.lower_leg_bone_group + .modify(appearance, id::LOWER_LEG_BONE_GROUP); + self.nose_bone_group.modify(appearance, id::NOSE_BONE_GROUP); + self.object_scaling.modify(appearance, id::OBJECT_SCALING); + self.stomach_bone_group + .modify(appearance, id::STOMACH_BONE_GROUP); + self.torso_bone_group + .modify(appearance, id::TORSO_BONE_GROUP); + self.upper_arm_bone_group + .modify(appearance, id::UPPER_ARM_BONE_GROUP); + self.upper_leg_bone_group + .modify(appearance, id::UPPER_LEG_BONE_GROUP); + } +} + +impl TryFrom<&Box> for Appearance { + type Error = Error; + + fn try_from(structure: &Box) -> Result { + Ok(Self { + board_bone_group: structure.get(id::BOARD_BONE_GROUP).cloned().into(), + feet_bone_group: structure.get(id::FEET_BONE_GROUP).cloned().into(), + hands_bone_group: structure.get(id::HANDS_BONE_GROUP).cloned().into(), + head_bone_group: structure.get(id::HEAD_BONE_GROUP).cloned().into(), + headtop_bone_group: structure.get(id::HEADTOP_BONE_GROUP).cloned().into(), + jaw_bone_group: structure.get(id::JAW_BONE_GROUP).cloned().into(), + lower_arm_bone_group: structure.get(id::LOWER_ARM_BONE_GROUP).cloned().into(), + lower_leg_bone_group: structure.get(id::LOWER_LEG_BONE_GROUP).cloned().into(), + nose_bone_group: structure.get(id::NOSE_BONE_GROUP).cloned().into(), + object_scaling: structure.get(id::OBJECT_SCALING).cloned().into(), + stomach_bone_group: structure.get(id::STOMACH_BONE_GROUP).cloned().into(), + torso_bone_group: structure.get(id::TORSO_BONE_GROUP).cloned().into(), + upper_arm_bone_group: structure.get(id::UPPER_ARM_BONE_GROUP).cloned().into(), + upper_leg_bone_group: structure.get(id::UPPER_LEG_BONE_GROUP).cloned().into(), + }) + } +} + +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct StorySkater { + pub tricks: Item, +} + +impl TryFrom<&Box> for StorySkater { + type Error = Error; + + fn try_from(structure: &Box) -> Result { + Ok(Self { + tricks: structure.get(id::TRICKS).cloned().into(), + }) + } +} + +impl StorySkater { + pub fn modify(&self, story_skater: &mut Box) { + self.tricks.modify(story_skater, id::TRICKS); + } +} diff --git a/crates/cascade-rethawed/src/chunk.rs b/crates/cascade-rethawed/src/chunk.rs new file mode 100644 index 0000000..2b3d18d --- /dev/null +++ b/crates/cascade-rethawed/src/chunk.rs @@ -0,0 +1,77 @@ +use std::{ + fmt, + io::{Read, Write}, +}; + +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use cascade_qb as qb; + +use crate::{Error, Result}; + +pub const MAGIC_DATA: u32 = 0x39137FE5; +pub const MAGIC_SUMMARY: u32 = 0x31D7999C; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum Magic { + Data, // "MEMCARDSTUFF" + Summary, +} + +impl fmt::Display for Magic { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl TryFrom for Magic { + type Error = Error; + + fn try_from(value: u32) -> Result { + match value { + MAGIC_DATA => Ok(Magic::Data), + MAGIC_SUMMARY => Ok(Magic::Summary), + _ => Err(Error::UnknownChunkMagic(value)), + } + } +} +impl Into for Magic { + fn into(self) -> u32 { + match self { + Magic::Data => MAGIC_DATA, + Magic::Summary => MAGIC_SUMMARY, + } + } +} + +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Chunk { + pub magic: Magic, + pub size: u32, + pub structure: Box, +} + +impl Chunk { + pub fn read(reader: &mut impl Read) -> Result { + let magic = reader.read_u32::()?.try_into()?; + let size = reader.read_u32::()?; + let structure = Box::new(qb::Structure::read(reader)?); + // TODO: use size? + // let mut data = vec![0; size as usize]; + // reader.read_exact(&mut data)?; + + Ok(Self { + magic, + size, + structure, + }) + } + + pub fn write(&self, writer: &mut impl Write) -> Result<()> { + writer.write_u32::(self.magic.into())?; + writer.write_u32::(self.size)?; + self.structure.write(writer)?; + Ok(()) + } +} diff --git a/crates/cascade-rethawed/src/dump.rs b/crates/cascade-rethawed/src/dump.rs new file mode 100644 index 0000000..52e5a05 --- /dev/null +++ b/crates/cascade-rethawed/src/dump.rs @@ -0,0 +1,59 @@ +use cascade_dump as dump; +use cascade_lut::Lut; + +use crate::{chunk, save}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Rethawed { + magic: u32, + version: u32, + chunk_count: u32, + chunks: Vec, +} + +impl Rethawed { + pub fn new(save: &save::Rethawed, lut: &Lut) -> Self { + Self { + magic: save.magic, + version: save.version, + chunk_count: save.chunk_count, + chunks: save + .chunks + .iter() + .map(|chunk| Chunk::new(chunk, lut)) + .collect(), + } + } +} + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum Save { + Thaw(dump::Save), + Rethawed(Rethawed), +} + +impl Save { + pub fn new(save: &save::Save, lut: &Lut) -> Self { + match save { + save::Save::Thaw(save) => Self::Thaw(dump::Save::new(save, lut)), + save::Save::Rethawed(save) => Self::Rethawed(Rethawed::new(save, lut)), + } + } +} + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Chunk { + magic: chunk::Magic, + size: u32, + structure: dump::Structure, +} + +impl Chunk { + pub fn new(chunk: &chunk::Chunk, lut: &Lut) -> Self { + Self { + magic: chunk.magic, + size: chunk.size, + structure: dump::Structure::new(&chunk.structure, lut), + } + } +} diff --git a/crates/cascade-rethawed/src/entry.rs b/crates/cascade-rethawed/src/entry.rs new file mode 100644 index 0000000..4ecbe68 --- /dev/null +++ b/crates/cascade-rethawed/src/entry.rs @@ -0,0 +1,123 @@ +use std::{ + fs::{self}, + hash::{Hash, Hasher}, + io::{BufReader, BufWriter, Read, Seek, Write}, + path::{Path, PathBuf}, +}; + +use crate::{Error, Result}; + +#[derive(Debug, Clone)] +pub struct Entry { + pub path: PathBuf, + pub dir: PathBuf, + pub filename: String, + pub metadata: Option, +} + +impl Hash for Entry { + fn hash(&self, state: &mut H) { + self.path.hash(state); + } +} + +impl PartialEq for Entry { + fn eq(&self, other: &Self) -> bool { + // TODO: store filepath in entry + self.path == other.path + } +} + +impl Eq for Entry {} + +impl Entry { + pub fn create(path: impl AsRef) -> Result { + let path = path.as_ref(); + + let metadata = fs::metadata(path).ok(); + let filename = path + .file_name() + .map(|s| s.to_string_lossy().into()) + .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(path)))?; + + let dir = path + .parent() + .map(PathBuf::from) + .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(path)))?; + + Ok(Self { + path: PathBuf::from(path), + dir, + filename, + metadata, + }) + } + + pub fn reader(&self) -> Result { + let file = fs::File::open(&self.path)?; + Ok(BufReader::new(file)) + } + + pub fn writer(&self) -> Result { + let file = fs::File::create(&self.path)?; + Ok(BufWriter::new(file)) + } + + pub fn rewrite_metadata(&self) -> Result<()> { + if let Some(metadata) = &self.metadata { + let filepath = &self.path; + + // TODO: this should probably be configurable + let original_mod_time = filetime::FileTime::from_last_modification_time(metadata); + + // TODO: how tf do i format this + log::info!( + "setting file modification time for {:?} to {:?}", + filepath, + original_mod_time + ); + filetime::set_file_mtime(&filepath, original_mod_time)?; + } + + Ok(()) + } +} + +pub fn find_entries(dir: impl AsRef) -> Result> { + let dir = PathBuf::from(dir.as_ref()); + + dir.is_dir() + .then(|| ()) + .ok_or_else(|| Error::NoSuchDirectory(dir.clone()))?; + + log::info!("finding entries in {:?}", dir); + + Ok(dir + .read_dir()? + .filter_map(|file| file.ok()) + .filter_map(|file| { + let filepath = file.path(); + log::info!("found file at {:?}", filepath); + + // oops i should probably make this cleaner + if let Some(filename) = filepath.file_name() { + if filename.to_string_lossy().ends_with("-Progress") { + match Entry::create(&filepath) { + Ok(save) => { + log::info!("found entry {:?}", filepath); + Some(save) + } + Err(e) => { + log::warn!("error loading entry {:?}: {}", filepath, e); + None + } + } + } else { + None + } + } else { + None + } + }) + .collect()) +} diff --git a/crates/cascade-rethawed/src/error.rs b/crates/cascade-rethawed/src/error.rs new file mode 100644 index 0000000..1ca8a54 --- /dev/null +++ b/crates/cascade-rethawed/src/error.rs @@ -0,0 +1,41 @@ +use std::{io, path::PathBuf, result}; + +use cascade_qb as qb; +use cascade_save as save; + +use crate::chunk; + +#[derive(thiserror::Error, Debug, Clone)] +pub enum Error { + #[error("io error: {0}")] + Io(io::ErrorKind), + + #[error("qb error: {0}")] + Qb(#[from] qb::Error), + + #[error("save error: {0}")] + Save(#[from] save::Error), + + #[error("unknown chunk magic: {0}")] + UnknownChunkMagic(u32), + + #[error("symbol not found: {0}")] + SymbolNotFound(qb::Id), + + #[error("chunk not found: {0}")] + ChunkNotFound(chunk::Magic), + + #[error("no such directory: \"{0}\"")] + NoSuchDirectory(PathBuf), + + #[error("invalid save file path: \"{0}\"")] + InvalidSaveFilePath(PathBuf), +} + +impl From for Error { + fn from(value: io::Error) -> Self { + Self::Io(value.kind()) + } +} + +pub type Result = result::Result; diff --git a/crates/cascade-rethawed/src/id.rs b/crates/cascade-rethawed/src/id.rs new file mode 100644 index 0000000..09e71c5 --- /dev/null +++ b/crates/cascade-rethawed/src/id.rs @@ -0,0 +1,31 @@ +use cascade_qb as qb; + +pub const FILENAME: qb::Id = qb::Id::Checksum(3287553690); + +pub const CUSTOM_SKATER: qb::Id = qb::Id::Checksum(314551426); +pub const STORY_SKATER: qb::Id = qb::Id::Checksum(234026056); + +pub const CUSTOM_CLASSIC: qb::Id = qb::Id::Checksum(1263122335); + +pub const APPEARANCE: qb::Id = qb::Id::Checksum(1431076207); +pub const INFO: qb::Id = qb::Id::Checksum(880201384); + +pub const TRICK_MAPPING: qb::Id = qb::Id::Compress8(61); +pub const SPECIALS: qb::Id = qb::Id::Compress8(64); + +pub const BOARD_BONE_GROUP: qb::Id = qb::Id::Compress8(208); +pub const FEET_BONE_GROUP: qb::Id = qb::Id::Compress8(207); +pub const HANDS_BONE_GROUP: qb::Id = qb::Id::Compress8(204); +pub const HEAD_BONE_GROUP: qb::Id = qb::Id::Compress8(199); +pub const HEADTOP_BONE_GROUP: qb::Id = qb::Id::Compress8(196); +pub const JAW_BONE_GROUP: qb::Id = qb::Id::Compress8(197); +pub const LOWER_ARM_BONE_GROUP: qb::Id = qb::Id::Compress8(203); +pub const LOWER_LEG_BONE_GROUP: qb::Id = qb::Id::Compress8(206); +pub const NOSE_BONE_GROUP: qb::Id = qb::Id::Compress8(198); +pub const OBJECT_SCALING: qb::Id = qb::Id::Compress8(209); +pub const STOMACH_BONE_GROUP: qb::Id = qb::Id::Compress8(201); +pub const TORSO_BONE_GROUP: qb::Id = qb::Id::Compress8(200); +pub const UPPER_ARM_BONE_GROUP: qb::Id = qb::Id::Compress8(202); +pub const UPPER_LEG_BONE_GROUP: qb::Id = qb::Id::Checksum(3191687513); + +pub const TRICKS: qb::Id = qb::Id::Checksum(505871678); diff --git a/crates/cascade-rethawed/src/lib.rs b/crates/cascade-rethawed/src/lib.rs new file mode 100644 index 0000000..be77595 --- /dev/null +++ b/crates/cascade-rethawed/src/lib.rs @@ -0,0 +1,11 @@ +pub use cascade_thaw::lut; +pub mod backend; +pub mod cas; +mod chunk; +pub mod dump; +mod entry; +mod error; +mod id; +pub mod save; + +pub use error::{Error, Result}; diff --git a/crates/cascade-rethawed/src/save.rs b/crates/cascade-rethawed/src/save.rs new file mode 100644 index 0000000..52f2473 --- /dev/null +++ b/crates/cascade-rethawed/src/save.rs @@ -0,0 +1,97 @@ +use std::io::{Read, Seek, SeekFrom, Write}; + +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use cascade_save as save; + +use crate::{ + Error, Result, + chunk::{self, Chunk}, +}; + +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Rethawed { + pub magic: u32, + pub version: u32, + pub chunk_count: u32, + pub chunks: Vec, +} + +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum Save { + Thaw(save::Save), + Rethawed(Rethawed), +} + +impl Save { + pub fn read(reader: &mut (impl Read + Seek)) -> Result { + let magic = reader.read_u32::()?; + reader.seek(SeekFrom::Start(0))?; + + match magic { + // "RTHW" + 0x57485452 => Ok(Save::Rethawed(Rethawed::read(reader)?)), + _ => Ok(Save::Thaw(save::Save::read(reader)?)), + } + } + + pub fn write(&self, writer: &mut impl Write) -> Result<()> { + match self { + Save::Thaw(save) => Ok(save.write(writer)?), + Save::Rethawed(save) => Ok(save.write(writer)?), + } + } +} + +impl Rethawed { + pub fn read(reader: &mut impl Read) -> Result { + let magic = reader.read_u32::()?; + let version = reader.read_u32::()?; + let chunk_count = reader.read_u32::()?; + + let mut chunks = Vec::with_capacity(chunk_count as usize); + for _ in 0..chunk_count { + chunks.push(Chunk::read(reader)?); + } + + Ok(Self { + magic, + version, + chunk_count, + chunks, + }) + } + + pub fn write(&self, writer: &mut impl Write) -> Result<()> { + writer.write_u32::(self.magic)?; + writer.write_u32::(self.version)?; + writer.write_u32::(self.chunk_count)?; + + for chunk in self.chunks.iter() { + chunk.write(writer)?; + } + + Ok(()) + } + + // the following methods assume each type of chunk only exists once per save + + pub fn get_chunk(&self, magic: chunk::Magic) -> Option<&Chunk> { + self.chunks.iter().find(|chunk| chunk.magic == magic) + } + + pub fn try_get_chunk(&self, magic: chunk::Magic) -> Result<&Chunk> { + self.get_chunk(magic) + .ok_or_else(|| Error::ChunkNotFound(magic)) + } + + pub fn get_chunk_mut(&mut self, magic: chunk::Magic) -> Option<&mut Chunk> { + self.chunks.iter_mut().find(|chunk| chunk.magic == magic) + } + + pub fn try_get_chunk_mut(&mut self, magic: chunk::Magic) -> Result<&mut Chunk> { + self.get_chunk_mut(magic) + .ok_or_else(|| Error::ChunkNotFound(magic)) + } +} diff --git a/crates/cascade-save/src/save.rs b/crates/cascade-save/src/save.rs index c63809c..0376520 100644 --- a/crates/cascade-save/src/save.rs +++ b/crates/cascade-save/src/save.rs @@ -55,6 +55,7 @@ impl Header { } #[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Save { pub header: Header, diff --git a/crates/cascade-thaw/Cargo.toml b/crates/cascade-thaw/Cargo.toml new file mode 100644 index 0000000..6f51844 --- /dev/null +++ b/crates/cascade-thaw/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "cascade-thaw" +version = "0.0.1" +edition = "2024" + +[dependencies] +cascade-lut = { workspace = true } diff --git a/crates/cascade-thaw/src/lib.rs b/crates/cascade-thaw/src/lib.rs new file mode 100644 index 0000000..5189cd9 --- /dev/null +++ b/crates/cascade-thaw/src/lib.rs @@ -0,0 +1 @@ +pub mod lut; diff --git a/crates/cascade-thaw/src/lut.rs b/crates/cascade-thaw/src/lut.rs new file mode 100644 index 0000000..cec7ada --- /dev/null +++ b/crates/cascade-thaw/src/lut.rs @@ -0,0 +1,7 @@ +use cascade_lut as lut; + +const COMPRESS_LUT_BYTES: &[u8] = include_bytes!("../../../assets/lut/compress-thaw.ron"); + +pub fn load_compress() -> lut::Result { + lut::Compress::from_bytes(COMPRESS_LUT_BYTES) +} diff --git a/crates/cascade-thugpro/Cargo.toml b/crates/cascade-thugpro/Cargo.toml index aa5e72b..63537ac 100644 --- a/crates/cascade-thugpro/Cargo.toml +++ b/crates/cascade-thugpro/Cargo.toml @@ -6,7 +6,6 @@ edition = "2024" [dependencies] cascade-backend = { workspace = true } cascade-crc = { workspace = true } -cascade-dump = { workspace = true } cascade-lut = { workspace = true } cascade-qb = { workspace = true } cascade-save = { workspace = true } diff --git a/crates/cascade-thugpro/src/backend.rs b/crates/cascade-thugpro/src/backend.rs index 72cb340..b162703 100644 --- a/crates/cascade-thugpro/src/backend.rs +++ b/crates/cascade-thugpro/src/backend.rs @@ -1,44 +1,186 @@ -use std::path::PathBuf; +use std::{ + io::{Read, Seek}, + path::PathBuf, +}; use cascade_backend as backend; -use cascade_save as save; +use cascade_save::Save; -use crate::{Cas, Entry, Error, entry::find_entries}; +use crate::{ + Error, + cas::{self, Cas}, + entry::{self, Entry}, +}; -pub struct Backend { - saves_dir: PathBuf, +pub struct Explorer { + cwd: PathBuf, } -impl backend::Target for Backend { - type Entry = Entry; - type Error = Error; +impl Explorer { + pub fn new(cwd: PathBuf) -> Self { + Self { cwd } + } +} - fn list(&self) -> Result, Self::Error> { - find_entries(&self.saves_dir) +impl backend::Explorer for Explorer { + fn list(&self) -> Result, Error> { + entry::find_entries(&self.cwd).map(|entries| entries.into_iter()) } - fn name(&self, entry: &Self::Entry) -> impl AsRef { - &entry.name + fn reader(&self, entry: &Entry) -> Result { + entry.reader() } - fn read(&self, entry: &Self::Entry) -> Result { - Ok(save::Save::read(&mut entry.reader()?)?) + fn writer(&self, entry: &Entry) -> Result { + entry.writer() } - fn write(&self, entry: &Self::Entry, save: &save::Save) -> Result<(), Self::Error> { - Ok(save.write(&mut entry.writer()?)?) + fn name(&self, entry: &Entry) -> String { + entry.filename.clone() + } + + fn rewrite_metadata(&self, entry: &Entry) -> Result<(), Error> { + entry.rewrite_metadata() } } -impl backend::Structure for Backend { - type Parsed = Cas; - type Error = Error; +pub struct Parser; + +impl backend::Parser for Parser { + fn read(&self, reader: &mut impl Read) -> Result { + Ok(Save::read(reader)?) + } + + fn write(&self, save: &Save, writer: &mut impl std::io::Write) -> Result<(), Error> { + Ok(save.write(writer)?) + } - fn parse(&self, save: &save::Save) -> Result { + fn parse(&self, save: &Save) -> Result { Ok(Cas::try_from(save)?) } - fn modify(&self, save: &mut save::Save, transform: Self::Parsed) -> Result<(), Self::Error> { + fn modify(&self, save: &mut Save, transform: &Cas) -> Result<(), Error> { Ok(transform.modify(save)?) } + + fn mask(&self, cas: Cas, flags: backend::Flags) -> Cas { + Cas { + summary: flags.summary.then_some(cas.summary).unwrap_or_default(), + data: cas::Data { + custom_skater: cas::CustomSkater { + custom: cas::Custom { + info: cas::Info { + trick_mapping: flags + .trickset + .then_some(cas.data.custom_skater.custom.info.trick_mapping) + .unwrap_or_default(), + specials: flags + .trickset + .then_some(cas.data.custom_skater.custom.info.specials) + .unwrap_or_default(), + }, + appearance: cas::Appearance { + board_bone_group: flags + .scales + .then_some( + cas.data.custom_skater.custom.appearance.board_bone_group, + ) + .unwrap_or_default(), + feet_bone_group: flags + .scales + .then_some(cas.data.custom_skater.custom.appearance.feet_bone_group) + .unwrap_or_default(), + hands_bone_group: flags + .scales + .then_some( + cas.data.custom_skater.custom.appearance.hands_bone_group, + ) + .unwrap_or_default(), + head_bone_group: flags + .scales + .then_some(cas.data.custom_skater.custom.appearance.head_bone_group) + .unwrap_or_default(), + headtop_bone_group: flags + .scales + .then_some( + cas.data.custom_skater.custom.appearance.headtop_bone_group, + ) + .unwrap_or_default(), + jaw_bone_group: flags + .scales + .then_some(cas.data.custom_skater.custom.appearance.jaw_bone_group) + .unwrap_or_default(), + lower_arm_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom + .appearance + .lower_arm_bone_group, + ) + .unwrap_or_default(), + lower_leg_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom + .appearance + .lower_leg_bone_group, + ) + .unwrap_or_default(), + nose_bone_group: flags + .scales + .then_some(cas.data.custom_skater.custom.appearance.nose_bone_group) + .unwrap_or_default(), + object_scaling: flags + .scales + .then_some(cas.data.custom_skater.custom.appearance.object_scaling) + .unwrap_or_default(), + stomach_bone_group: flags + .scales + .then_some( + cas.data.custom_skater.custom.appearance.stomach_bone_group, + ) + .unwrap_or_default(), + torso_bone_group: flags + .scales + .then_some( + cas.data.custom_skater.custom.appearance.torso_bone_group, + ) + .unwrap_or_default(), + upper_arm_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom + .appearance + .upper_arm_bone_group, + ) + .unwrap_or_default(), + upper_leg_bone_group: flags + .scales + .then_some( + cas.data + .custom_skater + .custom + .appearance + .upper_leg_bone_group, + ) + .unwrap_or_default(), + ..Default::default() + }, + }, + }, + story_skater: cas::StorySkater { + tricks: flags + .trickset + .then_some(cas.data.story_skater.tricks) + .unwrap_or_default(), + }, + }, + } + } } diff --git a/crates/cascade-thugpro/src/entry.rs b/crates/cascade-thugpro/src/entry.rs index 98dec49..d014b50 100644 --- a/crates/cascade-thugpro/src/entry.rs +++ b/crates/cascade-thugpro/src/entry.rs @@ -1,151 +1,81 @@ use std::{ - fmt, fs::{self}, hash::{Hash, Hasher}, - io::{BufReader, BufWriter, Read, Write}, + io::{BufReader, BufWriter, Read, Seek, Write}, path::{Path, PathBuf}, }; use crate::{Error, Result}; -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum Extension { - SKA, -} - -impl TryFrom<&str> for Extension { - type Error = Error; - - fn try_from(value: &str) -> Result { - match value { - "SKA" => Ok(Extension::SKA), - _ => Err(Error::UnknownFileExtension(value.to_string())), - } - } -} - -impl fmt::Display for Extension { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}", - match self { - Extension::SKA => "SKA", - } - ) - } -} - #[derive(Debug, Clone)] pub struct Entry { + pub path: PathBuf, pub dir: PathBuf, - pub name: String, - pub extension: Extension, - pub metadata: fs::Metadata, + pub filename: String, + pub metadata: Option, } impl Hash for Entry { fn hash(&self, state: &mut H) { - self.filepath().hash(state); + self.path.hash(state); } } impl PartialEq for Entry { fn eq(&self, other: &Self) -> bool { // TODO: store filepath in entry - self.filepath() == other.filepath() + self.path == other.path } } impl Eq for Entry {} impl Entry { - pub fn at_path>(filepath: P) -> Result { - let metadata = fs::metadata(&filepath)?; - - let extension = Extension::try_from( - filepath - .as_ref() - .extension() - .and_then(|name| name.to_str()) - .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(filepath.as_ref())))?, - )?; - - let name = filepath - .as_ref() - .with_extension("") + pub fn create(path: impl AsRef) -> Result { + let path = path.as_ref(); + + let metadata = fs::metadata(path).ok(); + let filename = path .file_name() - .and_then(|name| name.to_str()) - .map(|name| name.to_string()) - .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(filepath.as_ref())))?; + .map(|s| s.to_string_lossy().into()) + .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(path)))?; - let dir = filepath - .as_ref() + let dir = path .parent() - .map(|dir| PathBuf::from(dir)) - .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(filepath.as_ref())))?; + .map(PathBuf::from) + .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(path)))?; Ok(Self { + path: PathBuf::from(path), dir, - name, - extension, + filename, metadata, }) } - pub fn with_dir>(&self, dir: P) -> Self { - Self { - dir: PathBuf::from(dir.as_ref()), - name: self.name.clone(), - extension: self.extension, - metadata: self.metadata.clone(), - } - } - - pub fn with_name(&self, name: impl ToString) -> Self { - Self { - dir: self.dir.clone(), - name: name.to_string(), - extension: self.extension, - metadata: self.metadata.clone(), - } - } - - pub fn filename(&self) -> String { - format!("{}.{}", self.name, self.extension) - } - - pub fn filepath(&self) -> PathBuf { - self.dir.join(self.filename()) - } - - pub fn metadata(&self) -> &fs::Metadata { - &self.metadata - } - - pub fn reader(&self) -> Result { - let file = fs::File::open(&self.filepath())?; + pub fn reader(&self) -> Result { + let file = fs::File::open(&self.path)?; Ok(BufReader::new(file)) } pub fn writer(&self) -> Result { - let file = fs::File::create(&self.filepath())?; + let file = fs::File::create(&self.path)?; Ok(BufWriter::new(file)) } - pub fn overwrite_metadata(&self) -> Result<()> { - let filepath = self.filepath(); + pub fn rewrite_metadata(&self) -> Result<()> { + if let Some(metadata) = &self.metadata { + let filepath = &self.path; - // TODO: this should probably be configurable - let original_mod_time = filetime::FileTime::from_last_modification_time(&self.metadata); + let original_mod_time = filetime::FileTime::from_last_modification_time(metadata); - // TODO: how tf do i format this - log::info!( - "setting file modification time for {:?} to {:?}", - filepath, - original_mod_time - ); - filetime::set_file_mtime(&filepath, original_mod_time)?; + log::info!( + "setting file modification time for {:?} to {:?}", + filepath, + original_mod_time + ); + filetime::set_file_mtime(&filepath, original_mod_time)?; + } Ok(()) } @@ -165,16 +95,26 @@ pub fn find_entries(dir: impl AsRef) -> Result> { .filter_map(|file| file.ok()) .filter_map(|file| { let filepath = file.path(); - - match Entry::at_path(&filepath) { - Ok(save) => { - log::info!("found entry {:?}", filepath); - Some(save) - } - Err(e) => { - log::warn!("error loading entry {:?}: {}", filepath, e); + log::info!("found file at {:?}", filepath); + + // oops i should probably make this cleaner + if let Some(filename) = filepath.file_name() { + if filename.to_string_lossy().ends_with(".SKA") { + match Entry::create(&filepath) { + Ok(save) => { + log::info!("found entry {:?}", filepath); + Some(save) + } + Err(e) => { + log::warn!("error loading entry {:?}: {}", filepath, e); + None + } + } + } else { None } + } else { + None } }) .collect()) diff --git a/crates/cascade-thugpro/src/error.rs b/crates/cascade-thugpro/src/error.rs index 664db3b..9295e97 100644 --- a/crates/cascade-thugpro/src/error.rs +++ b/crates/cascade-thugpro/src/error.rs @@ -20,9 +20,6 @@ pub enum Error { #[error("symbol not found: {0}")] SymbolNotFound(qb::Id), - #[error("symbol not found: {0}")] - ExpectedStructure(String, qb::Value), - #[error("directory \"{0}\" was not found")] NoSuchDirectory(PathBuf), diff --git a/crates/cascade-thugpro/src/random.rs b/crates/cascade-thugpro/src/random.rs index e22ab59..4b1fd88 100644 --- a/crates/cascade-thugpro/src/random.rs +++ b/crates/cascade-thugpro/src/random.rs @@ -156,7 +156,7 @@ pub fn randomize( let output_path = PathBuf::from(output_dir).join(format!("{}.SKA", name)); fs::File::create(&output_path)?; - let output_entry = Entry::at_path(&output_path)?; + let output_entry = Entry::create(&output_path)?; base_save.write(&mut output_entry.writer()?)?; Ok(()) From ffcf13614c6b5127e3858e0d818d07b1d4c223ec Mon Sep 17 00:00:00 2001 From: ellie <149747415+1borgy@users.noreply.github.com> Date: Sat, 16 Aug 2025 13:46:56 -0400 Subject: [PATCH 04/23] fixup! fixup! fixup! update --- crates/cascade-rethawed/src/chunk.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/cascade-rethawed/src/chunk.rs b/crates/cascade-rethawed/src/chunk.rs index 2b3d18d..3710082 100644 --- a/crates/cascade-rethawed/src/chunk.rs +++ b/crates/cascade-rethawed/src/chunk.rs @@ -69,8 +69,9 @@ impl Chunk { } pub fn write(&self, writer: &mut impl Write) -> Result<()> { + let chunk_size = self.structure.raw_bytes()?.len(); writer.write_u32::(self.magic.into())?; - writer.write_u32::(self.size)?; + writer.write_u32::(chunk_size as u32)?; self.structure.write(writer)?; Ok(()) } From 9382c3a3dc4bfa0eaba4bdd4011a25906086447a Mon Sep 17 00:00:00 2001 From: ellie <149747415+1borgy@users.noreply.github.com> Date: Mon, 25 Aug 2025 10:10:51 -0400 Subject: [PATCH 05/23] fixup! fixup! fixup! fixup! update --- Cargo.toml | 3 +- crates/cascade-app/Cargo.toml | 4 +- crates/cascade-app/src/app.rs | 16 +- crates/cascade-app/src/dashboard.rs | 16 +- crates/cascade-app/src/main.rs | 14 +- crates/cascade-cli/Cargo.toml | 16 +- crates/cascade-cli/src/main.rs | 64 +++-- .../Cargo.toml | 3 +- .../src/lib.rs | 11 - crates/cascade-lut/src/lib.rs | 4 +- crates/cascade-rethawed/Cargo.toml | 21 -- crates/cascade-rethawed/src/lib.rs | 11 - crates/cascade-thaw/Cargo.toml | 13 + .../src/cas.rs | 0 .../src/chunk.rs | 2 +- .../backend.rs => cascade-thaw/src/core.rs} | 8 +- .../src/dump.rs | 0 .../src/entry.rs | 0 .../src/error.rs | 0 .../src/id.rs | 0 crates/cascade-thaw/src/lib.rs | 10 + crates/cascade-thaw/src/lut.rs | 254 ++++++++++++++++++ .../src/save.rs | 0 crates/cascade-thugpro/Cargo.toml | 2 +- .../src/{backend.rs => core.rs} | 8 +- crates/cascade-thugpro/src/lib.rs | 2 +- 26 files changed, 360 insertions(+), 122 deletions(-) rename crates/{cascade-backend => cascade-core}/Cargo.toml (50%) rename crates/{cascade-backend => cascade-core}/src/lib.rs (63%) delete mode 100644 crates/cascade-rethawed/Cargo.toml delete mode 100644 crates/cascade-rethawed/src/lib.rs rename crates/{cascade-rethawed => cascade-thaw}/src/cas.rs (100%) rename crates/{cascade-rethawed => cascade-thaw}/src/chunk.rs (98%) rename crates/{cascade-rethawed/src/backend.rs => cascade-thaw/src/core.rs} (97%) rename crates/{cascade-rethawed => cascade-thaw}/src/dump.rs (100%) rename crates/{cascade-rethawed => cascade-thaw}/src/entry.rs (100%) rename crates/{cascade-rethawed => cascade-thaw}/src/error.rs (100%) rename crates/{cascade-rethawed => cascade-thaw}/src/id.rs (100%) rename crates/{cascade-rethawed => cascade-thaw}/src/save.rs (100%) rename crates/cascade-thugpro/src/{backend.rs => core.rs} (97%) diff --git a/Cargo.toml b/Cargo.toml index cf6c4b3..075cc98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,12 +3,11 @@ members = ["crates/*"] resolver = "2" [workspace.dependencies] -cascade-backend = { path = "crates/cascade-backend" } +cascade-core = { path = "crates/cascade-core" } cascade-crc = { path = "crates/cascade-crc" } cascade-dump = { path = "crates/cascade-dump" } cascade-lut = { path = "crates/cascade-lut" } cascade-qb = { path = "crates/cascade-qb" } -cascade-rethawed = { path = "crates/cascade-rethawed" } cascade-save = { path = "crates/cascade-save" } cascade-thaw = { path = "crates/cascade-thaw" } cascade-thps4 = { path = "crates/cascade-thps4" } diff --git a/crates/cascade-app/Cargo.toml b/crates/cascade-app/Cargo.toml index 36debc4..e1e1c1b 100644 --- a/crates/cascade-app/Cargo.toml +++ b/crates/cascade-app/Cargo.toml @@ -8,12 +8,12 @@ name = "cascade" path = "src/main.rs" [dependencies] -cascade-backend = { workspace = true } +cascade-core = { workspace = true } cascade-qb = { workspace = true } cascade-save = { workspace = true } cascade-thugpro = { workspace = true } +cascade-thaw = { workspace = true } -clap = { workspace = true } directories = { workspace = true } enum-iterator = { workspace = true } fern = { workspace = true } diff --git a/crates/cascade-app/src/app.rs b/crates/cascade-app/src/app.rs index 7e5d469..7fa55bf 100644 --- a/crates/cascade-app/src/app.rs +++ b/crates/cascade-app/src/app.rs @@ -27,15 +27,14 @@ pub struct Cascade { selections_path: PathBuf, config: Config, - debug: bool, theme: Theme, dashboard: dashboard::Dashboard, } impl Cascade { - pub fn new(flags: (PathBuf, Config, Selections, Theme, bool)) -> (Self, Task) { - let (cascade_dir, config, selections, theme, debug) = flags; + pub fn new(flags: (PathBuf, Config, Selections, Theme)) -> (Self, Task) { + let (cascade_dir, config, selections, theme) = flags; let backup_dir = paths::backup_dir(&cascade_dir); let (dashboard, dashboard_command) = dashboard::Dashboard::new( @@ -57,7 +56,6 @@ impl Cascade { selections_path, theme, config, - debug, dashboard, }, dashboard_command.map(Message::Dashboard), @@ -191,10 +189,12 @@ impl Cascade { .padding(Padding::new(20.)) .into(); - match self.debug { - true => content.explain(iced::Color::WHITE), - false => content, - } + content + + // match self.debug { + // true => content.explain(iced::Color::WHITE), + // false => content, + // } } pub fn subscription(&self) -> Subscription { diff --git a/crates/cascade-app/src/dashboard.rs b/crates/cascade-app/src/dashboard.rs index 9af6fae..193df06 100644 --- a/crates/cascade-app/src/dashboard.rs +++ b/crates/cascade-app/src/dashboard.rs @@ -7,7 +7,9 @@ use std::{ sync::Arc, }; +use cascade_core as core; use cascade_save as save; +use cascade_thaw as thaw; use cascade_thugpro as thugpro; use iced::{ alignment::Vertical, @@ -107,18 +109,22 @@ pub enum Event { SetScales(bool), } -pub struct Dashboard { +pub struct Dashboard +where + Entry: Sized, + Error: Sized, +{ backup_dir: PathBuf, saves_dir: Option, default_selection: bool, enabled: bool, - source_entry: Option, - source: Option, + source_entry: Option, + explorer: Box>, - candidates: IndexMap, + candidates: IndexMap, components: Components, - queue: IndexMap, + queue: IndexMap, warning_message: Option, diff --git a/crates/cascade-app/src/main.rs b/crates/cascade-app/src/main.rs index 0730cda..940b6bd 100644 --- a/crates/cascade-app/src/main.rs +++ b/crates/cascade-app/src/main.rs @@ -1,10 +1,9 @@ #![cfg_attr(target_os = "windows", windows_subsystem = "windows")] -#![feature(error_generic_member_access, path_add_extension)] +#![feature(error_generic_member_access)] use std::{io, path::Path, result}; use app::Cascade; -use clap::Parser; use config::{Config, Selections}; use fern::colors::{Color, ColoredLevelConfig}; use iced::{window, Size}; @@ -50,13 +49,6 @@ pub enum Error { type Result = result::Result; -#[derive(Parser, Debug)] -#[command(version, about, long_about = None)] -struct Args { - #[arg(short, long, default_value_t = false)] - debug: bool, -} - fn configure_logging(path: impl AsRef) -> Result<()> { let colors = ColoredLevelConfig::new().info(Color::Green); @@ -92,8 +84,6 @@ fn configure_logging(path: impl AsRef) -> Result<()> { } fn main() -> Result<()> { - let Args { debug } = Args::parse(); - let cascade_dir = paths::cascade_dir().expect("could not determine cascade dir"); configure_logging(paths::log(&cascade_dir))?; @@ -118,7 +108,7 @@ fn main() -> Result<()> { .font(fonts::ICONS_FONT_BYTES) .scale_factor(Cascade::scale_factor) .subscription(Cascade::subscription) - .run_with(move || Cascade::new((cascade_dir, config, selections, theme, debug)))?; + .run_with(move || Cascade::new((cascade_dir, config, selections, theme)))?; Ok(()) } diff --git a/crates/cascade-cli/Cargo.toml b/crates/cascade-cli/Cargo.toml index cffae9e..8e4bf6c 100644 --- a/crates/cascade-cli/Cargo.toml +++ b/crates/cascade-cli/Cargo.toml @@ -4,13 +4,12 @@ version = "0.0.1" edition = "2024" [dependencies] -cascade-backend = { workspace = true } -cascade-dump = { workspace = true } -cascade-lut = { workspace = true } +cascade-core = { workspace = true } +cascade-dump = { workspace = true, optional = true } +cascade-lut = { workspace = true, optional = true } cascade-qb = { workspace = true } -cascade-rethawed = { workspace = true, features = ["serde"] } cascade-save = { workspace = true } -cascade-thaw = { workspace = true } +cascade-thaw = { workspace = true, features = ["serde"] } cascade-thug = { workspace = true } cascade-thps4 = { workspace = true } cascade-thugpro = { workspace = true } @@ -25,5 +24,10 @@ rand = { workspace = true } ron = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } -suppaftp = { workspace = true } +suppaftp = { workspace = true, optional = true } thiserror = { workspace = true } + +[features] +default = [] +dump = ["dep:cascade-lut", "dep:cascade-dump"] +ftp = ["dep:suppaftp"] diff --git a/crates/cascade-cli/src/main.rs b/crates/cascade-cli/src/main.rs index 26414a2..046cc2c 100644 --- a/crates/cascade-cli/src/main.rs +++ b/crates/cascade-cli/src/main.rs @@ -1,22 +1,21 @@ use std::{ fmt::Debug, - fs::{self, File}, - io::{self, BufReader, BufWriter, Write}, + fs, + io::{self, BufReader, BufWriter}, path::PathBuf, }; -use cascade_backend::{self as backend}; +use cascade_core::{self as core}; +#[cfg(feature = "dump")] use cascade_dump as dump; +#[cfg(feature = "dump")] use cascade_lut::{self as lut, Lut}; -use cascade_rethawed as rethawed; -use cascade_save::Save; use cascade_thaw as thaw; -use cascade_thps4 as thps4; -use cascade_thug as thug; use cascade_thugpro as thugpro; use cascade_wad::{hed, wad}; use clap::{Args, Parser, Subcommand}; use serde::Serialize; +#[cfg(feature = "ftp")] use suppaftp::FtpStream; #[derive(Parser, Debug)] @@ -42,6 +41,7 @@ enum Game { #[derive(Debug, Subcommand)] enum Command { + #[cfg(feature = "dump")] Dump { #[arg(short, long)] input: PathBuf, @@ -52,6 +52,7 @@ enum Command { #[arg(short, long)] game: Game, }, + #[cfg(feature = "dump")] RoundTrip { #[arg(short, long)] input: PathBuf, @@ -134,16 +135,18 @@ enum Command { #[arg(long)] output: PathBuf, }, + #[cfg(feature = "ftp")] Ftp { #[arg(long)] host: String, }, } +#[cfg(feature = "dump")] #[derive(serde::Serialize, serde::Deserialize)] enum Dump { Neversoft(dump::Save), - Rethawed(rethawed::dump::Save), + Rethawed(thaw::dump::Save), } #[derive(Debug, Args)] @@ -159,6 +162,7 @@ fn main() -> color_eyre::Result<()> { env_logger::init(); match command { + #[cfg(feature = "dump")] Command::Dump { input, output, @@ -172,7 +176,7 @@ fn main() -> color_eyre::Result<()> { Game::Thug => thug::lut::load_compress()?, Game::Thug2 => thugpro::lut::load_compress()?, Game::Thaw => thaw::lut::load_compress()?, - Game::Rethawed => rethawed::lut::load_compress()?, + Game::Rethawed => thaw::lut::load_compress()?, }, }; let dump = match game { @@ -181,8 +185,8 @@ fn main() -> color_eyre::Result<()> { Dump::Neversoft(dump::Save::new(&save, &lut)) } Game::Rethawed => { - let save = rethawed::save::Save::read(&mut entry.reader()?)?; - Dump::Rethawed(rethawed::dump::Save::new(&save, &lut)) + let save = thaw::save::Save::read(&mut entry.reader()?)?; + Dump::Rethawed(thaw::dump::Save::new(&save, &lut)) } }; @@ -193,6 +197,7 @@ fn main() -> color_eyre::Result<()> { Ok(()) } + #[cfg(feature = "dump")] Command::RoundTrip { input, output, @@ -201,7 +206,7 @@ fn main() -> color_eyre::Result<()> { fn round_trip( input: &PathBuf, output: &PathBuf, - parser: impl backend::Parser, + parser: impl core::Parser, ) -> Result<(), E> where E: From, @@ -221,8 +226,8 @@ fn main() -> color_eyre::Result<()> { } match game { - Game::Thug2 => round_trip(&input, &output, thugpro::backend::Parser {})?, - Game::Rethawed => round_trip(&input, &output, rethawed::backend::Parser {})?, + Game::Thug2 => round_trip(&input, &output, thugpro::core::Parser {})?, + Game::Rethawed => round_trip(&input, &output, thaw::core::Parser {})?, Game::Thps4 => todo!(), Game::Thug => todo!(), Game::Thaw => todo!(), @@ -237,15 +242,15 @@ fn main() -> color_eyre::Result<()> { scales, trickset, } => { - let flags = backend::Flags { + let flags = core::Flags { trickset, scales, summary: false, }; match game { - Game::Thug2 => modify(&from, &to, thugpro::backend::Parser {}, flags)?, - Game::Rethawed => modify(&from, &to, rethawed::backend::Parser {}, flags)?, + Game::Thug2 => modify(&from, &to, thugpro::core::Parser {}, flags)?, + Game::Rethawed => modify(&from, &to, thaw::core::Parser {}, flags)?, Game::Thps4 => todo!(), Game::Thug => todo!(), Game::Thaw => todo!(), @@ -260,7 +265,7 @@ fn main() -> color_eyre::Result<()> { scales, trickset, } => { - let flags = backend::Flags { + let flags = core::Flags { trickset, scales, summary: false, @@ -271,15 +276,15 @@ fn main() -> color_eyre::Result<()> { Game::Thug => todo!(), Game::Thug2 => modify_bulk( &from, - thugpro::backend::Explorer::new(to_dir), - thugpro::backend::Parser {}, + thugpro::core::Explorer::new(to_dir), + thugpro::core::Parser {}, flags, )?, Game::Thaw => todo!(), Game::Rethawed => modify_bulk( &from, - rethawed::backend::Explorer::new(to_dir), - rethawed::backend::Parser {}, + thaw::core::Explorer::new(to_dir), + thaw::core::Parser {}, flags, )?, } @@ -327,6 +332,7 @@ fn main() -> color_eyre::Result<()> { Ok(()) } + #[cfg(feature = "ftp")] Command::Ftp { host } => { fn list(ftp_stream: &mut FtpStream) -> color_eyre::Result> { let output = ftp_stream.list(None)?; @@ -364,8 +370,8 @@ fn main() -> color_eyre::Result<()> { fn modify( from: &PathBuf, to: &PathBuf, - parser: impl backend::Parser, - flags: backend::Flags, + parser: impl core::Parser, + flags: core::Flags, ) -> Result<(), E> where E: From, @@ -391,9 +397,9 @@ where fn modify_bulk( from: &PathBuf, - explorer: impl backend::Explorer, - parser: impl backend::Parser, - flags: backend::Flags, + explorer: impl core::Explorer, + parser: impl core::Parser, + flags: core::Flags, ) -> Result<(), Error> where Error: From + Debug, @@ -401,8 +407,8 @@ where fn modify_one( entry: &Entry, transform: &Cas, - explorer: &impl backend::Explorer, - parser: &impl backend::Parser, + explorer: &impl core::Explorer, + parser: &impl core::Parser, ) -> Result<(), Error> { let mut reader = explorer.reader(&entry)?; let mut save = parser.read(&mut reader)?; diff --git a/crates/cascade-backend/Cargo.toml b/crates/cascade-core/Cargo.toml similarity index 50% rename from crates/cascade-backend/Cargo.toml rename to crates/cascade-core/Cargo.toml index 4bdb68f..2821259 100644 --- a/crates/cascade-backend/Cargo.toml +++ b/crates/cascade-core/Cargo.toml @@ -1,7 +1,6 @@ [package] -name = "cascade-backend" +name = "cascade-core" version = "0.0.1" edition = "2024" [dependencies] -cascade-save = { workspace = true } diff --git a/crates/cascade-backend/src/lib.rs b/crates/cascade-core/src/lib.rs similarity index 63% rename from crates/cascade-backend/src/lib.rs rename to crates/cascade-core/src/lib.rs index 0f1f460..966fc4a 100644 --- a/crates/cascade-backend/src/lib.rs +++ b/crates/cascade-core/src/lib.rs @@ -1,16 +1,5 @@ use std::io::{Read, Seek, Write}; -// pub trait Parser { -// type Save: Sized; -// type Transform: Sized; -// type Error: Send + Sync + std::error::Error; -// -// fn read(&self, reader: &mut impl Read) -> Result; -// fn write(&self, save: &Self::Save, writer: &mut impl Write) -> Result<(), Self::Error>; -// fn parse(&self, save: &Self::Save) -> Result; -// fn modify(&self, save: &mut Self::Save, transform: Self::Transform) -> Result<(), Self::Error>; -// } - pub trait Explorer { fn list(&self) -> Result, Error>; fn reader(&self, entry: &Entry) -> Result; diff --git a/crates/cascade-lut/src/lib.rs b/crates/cascade-lut/src/lib.rs index 09d9326..e7d3a26 100644 --- a/crates/cascade-lut/src/lib.rs +++ b/crates/cascade-lut/src/lib.rs @@ -47,8 +47,8 @@ impl Checksum { #[derive(Serialize, Deserialize)] pub struct Compress { - compress8: Vec, - compress16: Vec, + pub compress8: Vec, + pub compress16: Vec, } impl Compress { diff --git a/crates/cascade-rethawed/Cargo.toml b/crates/cascade-rethawed/Cargo.toml deleted file mode 100644 index 516c13c..0000000 --- a/crates/cascade-rethawed/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "cascade-rethawed" -version = "0.0.1" -edition = "2024" - -[dependencies] -cascade-backend = { workspace = true } -cascade-dump = { workspace = true } -cascade-lut = { workspace = true } -cascade-save = { workspace = true } -cascade-thaw = { workspace = true } -cascade-qb = { workspace = true } - -byteorder = { workspace = true } -filetime = { workspace = true } -log = { workspace = true } -serde = { workspace = true, optional = true } -thiserror = { workspace = true } - -[features] -serde = ["dep:serde"] diff --git a/crates/cascade-rethawed/src/lib.rs b/crates/cascade-rethawed/src/lib.rs deleted file mode 100644 index be77595..0000000 --- a/crates/cascade-rethawed/src/lib.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub use cascade_thaw::lut; -pub mod backend; -pub mod cas; -mod chunk; -pub mod dump; -mod entry; -mod error; -mod id; -pub mod save; - -pub use error::{Error, Result}; diff --git a/crates/cascade-thaw/Cargo.toml b/crates/cascade-thaw/Cargo.toml index 6f51844..84584dd 100644 --- a/crates/cascade-thaw/Cargo.toml +++ b/crates/cascade-thaw/Cargo.toml @@ -4,4 +4,17 @@ version = "0.0.1" edition = "2024" [dependencies] +cascade-core = { workspace = true } +cascade-dump = { workspace = true } cascade-lut = { workspace = true } +cascade-save = { workspace = true } +cascade-qb = { workspace = true } + +byteorder = { workspace = true } +filetime = { workspace = true } +log = { workspace = true } +serde = { workspace = true, optional = true } +thiserror = { workspace = true } + +[features] +serde = ["dep:serde"] diff --git a/crates/cascade-rethawed/src/cas.rs b/crates/cascade-thaw/src/cas.rs similarity index 100% rename from crates/cascade-rethawed/src/cas.rs rename to crates/cascade-thaw/src/cas.rs diff --git a/crates/cascade-rethawed/src/chunk.rs b/crates/cascade-thaw/src/chunk.rs similarity index 98% rename from crates/cascade-rethawed/src/chunk.rs rename to crates/cascade-thaw/src/chunk.rs index 3710082..7a3c3db 100644 --- a/crates/cascade-rethawed/src/chunk.rs +++ b/crates/cascade-thaw/src/chunk.rs @@ -14,7 +14,7 @@ pub const MAGIC_SUMMARY: u32 = 0x31D7999C; #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Magic { - Data, // "MEMCARDSTUFF" + Data, // aka "MEMCARDSTUFF" Summary, } diff --git a/crates/cascade-rethawed/src/backend.rs b/crates/cascade-thaw/src/core.rs similarity index 97% rename from crates/cascade-rethawed/src/backend.rs rename to crates/cascade-thaw/src/core.rs index 97acb17..a83a1c2 100644 --- a/crates/cascade-rethawed/src/backend.rs +++ b/crates/cascade-thaw/src/core.rs @@ -3,7 +3,7 @@ use std::{ path::PathBuf, }; -use cascade_backend as backend; +use cascade_core as core; use crate::{ Error, @@ -22,7 +22,7 @@ impl Explorer { } } -impl backend::Explorer for Explorer { +impl core::Explorer for Explorer { fn list(&self) -> Result, Error> { entry::find_entries(&self.cwd).map(|entries| entries.into_iter()) } @@ -46,7 +46,7 @@ impl backend::Explorer for Explorer { pub struct Parser {} -impl backend::Parser for Parser { +impl core::Parser for Parser { fn read(&self, reader: &mut (impl Read + Seek)) -> Result { Save::read(reader) } @@ -63,7 +63,7 @@ impl backend::Parser for Parser { transform.modify(save) } - fn mask(&self, cas: Cas, flags: backend::Flags) -> Cas { + fn mask(&self, cas: Cas, flags: core::Flags) -> Cas { Cas { summary: flags.summary.then_some(cas.summary).unwrap_or_default(), data: cas::Data { diff --git a/crates/cascade-rethawed/src/dump.rs b/crates/cascade-thaw/src/dump.rs similarity index 100% rename from crates/cascade-rethawed/src/dump.rs rename to crates/cascade-thaw/src/dump.rs diff --git a/crates/cascade-rethawed/src/entry.rs b/crates/cascade-thaw/src/entry.rs similarity index 100% rename from crates/cascade-rethawed/src/entry.rs rename to crates/cascade-thaw/src/entry.rs diff --git a/crates/cascade-rethawed/src/error.rs b/crates/cascade-thaw/src/error.rs similarity index 100% rename from crates/cascade-rethawed/src/error.rs rename to crates/cascade-thaw/src/error.rs diff --git a/crates/cascade-rethawed/src/id.rs b/crates/cascade-thaw/src/id.rs similarity index 100% rename from crates/cascade-rethawed/src/id.rs rename to crates/cascade-thaw/src/id.rs diff --git a/crates/cascade-thaw/src/lib.rs b/crates/cascade-thaw/src/lib.rs index 5189cd9..052a51a 100644 --- a/crates/cascade-thaw/src/lib.rs +++ b/crates/cascade-thaw/src/lib.rs @@ -1 +1,11 @@ +pub mod cas; +mod chunk; +pub mod core; +pub mod dump; +pub mod entry; +mod error; +mod id; pub mod lut; +pub mod save; + +pub use error::{Error, Result}; diff --git a/crates/cascade-thaw/src/lut.rs b/crates/cascade-thaw/src/lut.rs index cec7ada..f3f14f5 100644 --- a/crates/cascade-thaw/src/lut.rs +++ b/crates/cascade-thaw/src/lut.rs @@ -1,6 +1,260 @@ use cascade_lut as lut; const COMPRESS_LUT_BYTES: &[u8] = include_bytes!("../../../assets/lut/compress-thaw.ron"); +pub static COMPRESS_8: [&str; 252] = [ + "skater_m_lower_legs", + "skater_m_head", + "skater_m_torso", + "skater_m_legs", + "skater_m_hair", + "skater_m_backpack", + "skater_m_jaw", + "kneepads", + "socks", + "elbowpads", + "skater_f_head", + "skater_f_torso", + "skater_f_legs", + "skater_f_hair", + "skater_f_backpack", + "skater_m_lower_legs", + "skater_m_hat_hair", + "part", + "skater_m_hands", + "chest_tattoo", + "back_tattoo", + "left_forearm_tattoo", + "right_forearm_tattoo", + "left_bicep_tattoo", + "left_leg_tattoo", + "right_leg_tattoo", + "use_default_scale", + "right_bicep_tattoo", + "Skin", + "value", + "desc_id", + "h", + "s", + "v", + "use_default_hsv", + "skater_f_lower_legs", + "skater_f_hat_hair", + "Scale", + "skater_f_hands", + "display_name", + "stance", + "pushstyle", + "profile", + "name", + "trickstyle", + "age", + "is_pro", + "hometown", + "is_locked", + "is_head_locked", + "points_available", + "Air", + "run", + "ollie", + "Speed", + "spin", + "Switch", + "rail_balance", + "lip_balance", + "manual_balance", + "sponsors", + "trick_mapping", + "default_trick_mapping", + "max_specials", + "specials", + "Air_CircleD", + "Air_CircleDL", + "Air_CircleDR", + "Air_CircleL", + "Air_CircleR", + "Air_CircleU", + "Air_CircleUL", + "Air_CircleUR", + "Air_D_D_Circle", + "Air_D_D_Square", + "Air_L_L_Circle", + "Air_L_L_Square", + "Air_R_R_Circle", + "Air_R_R_Square", + "Air_SquareD", + "Air_SquareDL", + "Air_SquareDR", + "Air_SquareL", + "Air_SquareR", + "Air_SquareU", + "Air_SquareUL", + "Air_SquareUR", + "Air_U_U_Circle", + "Air_U_U_Square", + "ExtraSlot1", + "ExtraSlot2", + "JumpSlot", + "Lip_TriangleD", + "Lip_TriangleDL", + "Lip_TriangleDL", + "Lip_TriangleDR", + "Lip_TriangleDR", + "Lip_TriangleL", + "Lip_TriangleR", + "Lip_TriangleU", + "Lip_TriangleUL", + "Lip_TriangleUL", + "Lip_TriangleUR", + "Lip_TriangleUR", + "SpAir_D_L_Circle", + "SpAir_D_L_Square", + "SpAir_D_R_Circle", + "SpAir_D_R_Square", + "SpAir_D_U_Circle", + "SpAir_D_U_Square", + "SpAir_L_D_Circle", + "SpAir_L_D_Square", + "SpAir_L_R_Circle", + "SpAir_L_R_Square", + "SpAir_L_U_Circle", + "SpAir_L_U_Square", + "SpAir_R_D_Circle", + "SpAir_R_D_Square", + "SpAir_R_L_Circle", + "SpAir_R_L_Square", + "SpAir_R_U_Circle", + "SpAir_R_U_Square", + "SpAir_U_D_Circle", + "SpAir_U_D_Square", + "SpAir_U_L_Circle", + "SpAir_U_L_Square", + "SpAir_U_R_Circle", + "SpAir_U_R_Square", + "SpGrind_D_L_Triangle", + "SpGrind_D_R_Triangle", + "SpGrind_D_U_Triangle", + "SpGrind_L_D_Triangle", + "SpGrind_L_R_Triangle", + "SpGrind_L_U_Triangle", + "SpGrind_R_D_Triangle", + "SpGrind_R_L_Triangle", + "SpGrind_R_U_Triangle", + "SpGrind_U_D_Triangle", + "SpGrind_U_L_Triangle", + "SpGrind_U_R_Triangle", + "SpLip_D_L_Triangle", + "SpLip_D_R_Triangle", + "SpLip_D_U_Triangle", + "SpLip_L_D_Triangle", + "SpLip_L_R_Triangle", + "SpLip_L_U_Triangle", + "SpLip_R_D_Triangle", + "SpLip_R_L_Triangle", + "SpLip_R_U_Triangle", + "SpLip_U_D_Triangle", + "SpLip_U_L_Triangle", + "SpLip_U_R_Triangle", + "SpLip_U_U_Triangle", + "SpMan_D_L_Triangle", + "SpMan_D_R_Triangle", + "SpMan_D_U_Triangle", + "SpMan_L_D_Triangle", + "SpMan_L_R_Triangle", + "SpMan_L_U_Triangle", + "SpMan_R_D_Triangle", + "SpMan_R_L_Triangle", + "SpMan_R_U_Triangle", + "SpMan_U_D_Triangle", + "SpMan_U_L_Triangle", + "SpMan_U_R_Triangle", + "x", + "y", + "z", + "trickslot", + "trickname", + "Unassigned", + "uv_scale", + "uv_rot", + "uv_u", + "uv_v", + "sleeves", + "shoes", + "front_logo", + "back_logo", + "glasses", + "Hat", + "helmet", + "Accessories", + "hat_logo", + "helmet_logo", + "board", + "griptape", + "deck_graphic", + "accessory1", + "accessory2", + "accessory3", + "shoe_laces", + "bare_torso", + "hasBeaten", + "head_tattoo", + "custom", + "headtop_bone_group", + "jaw_bone_group", + "nose_bone_group", + "head_bone_group", + "torso_bone_group", + "stomach_bone_group", + "upper_arm_bone_group", + "lower_arm_bone_group", + "hands_bone_group", + "upper_left_bone_group", + "lower_leg_bone_group", + "feet_bone_group", + "board_bone_group", + "object_scaling", + "regular", + "goofy", + "never_mongo", + "mongo_when_switch", + "always_mongo", + "street", + "vert", + "first_name", + "skater_index", + "default_appearance", + "is_male", + "flip_speed", + "on", + "Trick", + "dur", + "Blend", + "from", + "percent", + "trickType", + "idletime", + "start", + "order", + "hold", + "backwards", + "deg_dir", + "left_eye", + "right_eye", + "nose", + "lips", + "width", + "height", + "GapName", + "GapCount", + "GapScore", + "SkaterStartPos", + "SkaterStartDir", + "level", + "valid", + "value", + "number", + "initials", + "win_record", +]; pub fn load_compress() -> lut::Result { lut::Compress::from_bytes(COMPRESS_LUT_BYTES) diff --git a/crates/cascade-rethawed/src/save.rs b/crates/cascade-thaw/src/save.rs similarity index 100% rename from crates/cascade-rethawed/src/save.rs rename to crates/cascade-thaw/src/save.rs diff --git a/crates/cascade-thugpro/Cargo.toml b/crates/cascade-thugpro/Cargo.toml index 63537ac..de1d508 100644 --- a/crates/cascade-thugpro/Cargo.toml +++ b/crates/cascade-thugpro/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.1" edition = "2024" [dependencies] -cascade-backend = { workspace = true } +cascade-core = { workspace = true } cascade-crc = { workspace = true } cascade-lut = { workspace = true } cascade-qb = { workspace = true } diff --git a/crates/cascade-thugpro/src/backend.rs b/crates/cascade-thugpro/src/core.rs similarity index 97% rename from crates/cascade-thugpro/src/backend.rs rename to crates/cascade-thugpro/src/core.rs index b162703..b2f553b 100644 --- a/crates/cascade-thugpro/src/backend.rs +++ b/crates/cascade-thugpro/src/core.rs @@ -3,7 +3,7 @@ use std::{ path::PathBuf, }; -use cascade_backend as backend; +use cascade_core as core; use cascade_save::Save; use crate::{ @@ -22,7 +22,7 @@ impl Explorer { } } -impl backend::Explorer for Explorer { +impl core::Explorer for Explorer { fn list(&self) -> Result, Error> { entry::find_entries(&self.cwd).map(|entries| entries.into_iter()) } @@ -46,7 +46,7 @@ impl backend::Explorer for Explorer { pub struct Parser; -impl backend::Parser for Parser { +impl core::Parser for Parser { fn read(&self, reader: &mut impl Read) -> Result { Ok(Save::read(reader)?) } @@ -63,7 +63,7 @@ impl backend::Parser for Parser { Ok(transform.modify(save)?) } - fn mask(&self, cas: Cas, flags: backend::Flags) -> Cas { + fn mask(&self, cas: Cas, flags: core::Flags) -> Cas { Cas { summary: flags.summary.then_some(cas.summary).unwrap_or_default(), data: cas::Data { diff --git a/crates/cascade-thugpro/src/lib.rs b/crates/cascade-thugpro/src/lib.rs index b8231b9..55410d4 100644 --- a/crates/cascade-thugpro/src/lib.rs +++ b/crates/cascade-thugpro/src/lib.rs @@ -1,4 +1,4 @@ -pub mod backend; +pub mod core; pub mod cas; pub mod entry; pub mod error; From 9cdd30c9877f4ef504c720609ef91a9506e0ef5b Mon Sep 17 00:00:00 2001 From: ellie <149747415+1borgy@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:12:05 -0400 Subject: [PATCH 06/23] fixup! fixup! fixup! fixup! fixup! update --- crates/cascade-core/src/cas.rs | 10 ++++++++++ crates/cascade-core/src/entry.rs | 15 +++++++++++++++ crates/cascade-core/src/lib.rs | 13 +++++++++++++ crates/cascade-core/src/save.rs | 11 +++++++++++ 4 files changed, 49 insertions(+) create mode 100644 crates/cascade-core/src/cas.rs create mode 100644 crates/cascade-core/src/entry.rs create mode 100644 crates/cascade-core/src/save.rs diff --git a/crates/cascade-core/src/cas.rs b/crates/cascade-core/src/cas.rs new file mode 100644 index 0000000..b002b78 --- /dev/null +++ b/crates/cascade-core/src/cas.rs @@ -0,0 +1,10 @@ +use crate::{Flags, save}; + +pub trait Cas +where + Save: save::Save, +{ + fn parse(save: &Save) -> Result, Error>; + fn modify(&self, save: &mut Save) -> Result<(), Error>; + fn mask(self, flags: Flags) -> Self; +} diff --git a/crates/cascade-core/src/entry.rs b/crates/cascade-core/src/entry.rs new file mode 100644 index 0000000..1d2996c --- /dev/null +++ b/crates/cascade-core/src/entry.rs @@ -0,0 +1,15 @@ +use std::io::{Read, Seek, Write}; + +pub trait Entry { + fn reader(&self) -> Result + where + R: Read + Seek; + + fn writer(&self) -> Result + where + W: Write + Seek; + + fn name(&self) -> String; + + fn rewrite_metadata(&self) -> Result<(), Error>; +} diff --git a/crates/cascade-core/src/lib.rs b/crates/cascade-core/src/lib.rs index 966fc4a..0ff4e70 100644 --- a/crates/cascade-core/src/lib.rs +++ b/crates/cascade-core/src/lib.rs @@ -1,5 +1,9 @@ use std::io::{Read, Seek, Write}; +pub mod cas; +pub mod entry; +pub mod save; + pub trait Explorer { fn list(&self) -> Result, Error>; fn reader(&self, entry: &Entry) -> Result; @@ -21,3 +25,12 @@ pub trait Parser { fn mask(&self, cas: Cas, flags: Flags) -> Cas; fn modify(&self, save: &mut Save, cas: &Cas) -> Result<(), Error>; } + +pub trait Core +where + Entry: entry::Entry, + Save: save::Save, + Cas: cas::Cas, +{ + fn list_entries() -> Result, Error>; +} diff --git a/crates/cascade-core/src/save.rs b/crates/cascade-core/src/save.rs new file mode 100644 index 0000000..5e1e57f --- /dev/null +++ b/crates/cascade-core/src/save.rs @@ -0,0 +1,11 @@ +use std::io::{Read, Seek, Write}; + +pub trait Save { + fn read(&self, reader: &mut R) -> Result, Error> + where + R: Read + Seek; + + fn write(&self, writer: &mut W) -> Result<(), Error> + where + W: Write + Seek; +} From ddddbf91573c949087b302a4f594e65bbf886cff Mon Sep 17 00:00:00 2001 From: ellie <149747415+1borgy@users.noreply.github.com> Date: Tue, 26 Aug 2025 15:44:28 -0400 Subject: [PATCH 07/23] fixup! fixup! fixup! fixup! fixup! fixup! update --- Cargo.toml | 2 +- crates/cascade-app/Cargo.toml | 2 +- crates/cascade-app/src/dashboard.rs | 54 ++--- crates/cascade-cli/Cargo.toml | 5 +- crates/cascade-cli/src/main.rs | 31 +-- crates/cascade-core/src/cas.rs | 20 +- crates/cascade-core/src/entry.rs | 15 +- crates/cascade-core/src/lib.rs | 44 ++--- crates/cascade-core/src/save.rs | 11 +- crates/cascade-save/Cargo.toml | 1 + crates/cascade-save/src/save.rs | 16 +- .../Cargo.toml | 2 +- .../src/cas.rs | 144 +++++++++++++- crates/cascade-thug2/src/core.rs | 30 +++ .../src/entry.rs | 57 ++++-- .../src/error.rs | 0 .../src/id.rs | 0 .../src/lib.rs | 0 .../src/lut.rs | 0 .../src/random.rs | 0 .../tests/common/mod.rs | 6 +- .../tests/round_trip.rs | 8 +- crates/cascade-thugpro/src/core.rs | 186 ------------------ 23 files changed, 311 insertions(+), 323 deletions(-) rename crates/{cascade-thugpro => cascade-thug2}/Cargo.toml (95%) rename crates/{cascade-thugpro => cascade-thug2}/src/cas.rs (74%) create mode 100644 crates/cascade-thug2/src/core.rs rename crates/{cascade-thugpro => cascade-thug2}/src/entry.rs (84%) rename crates/{cascade-thugpro => cascade-thug2}/src/error.rs (100%) rename crates/{cascade-thugpro => cascade-thug2}/src/id.rs (100%) rename crates/{cascade-thugpro => cascade-thug2}/src/lib.rs (100%) rename crates/{cascade-thugpro => cascade-thug2}/src/lut.rs (100%) rename crates/{cascade-thugpro => cascade-thug2}/src/random.rs (100%) rename crates/{cascade-thugpro => cascade-thug2}/tests/common/mod.rs (77%) rename crates/{cascade-thugpro => cascade-thug2}/tests/round_trip.rs (88%) delete mode 100644 crates/cascade-thugpro/src/core.rs diff --git a/Cargo.toml b/Cargo.toml index 075cc98..977b1b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ cascade-save = { path = "crates/cascade-save" } cascade-thaw = { path = "crates/cascade-thaw" } cascade-thps4 = { path = "crates/cascade-thps4" } cascade-thug = { path = "crates/cascade-thug" } -cascade-thugpro = { path = "crates/cascade-thugpro" } +cascade-thug2 = { path = "crates/cascade-thug2" } cascade-wad = { path = "crates/cascade-wad" } byteorder = "1.4.3" diff --git a/crates/cascade-app/Cargo.toml b/crates/cascade-app/Cargo.toml index e1e1c1b..0872e65 100644 --- a/crates/cascade-app/Cargo.toml +++ b/crates/cascade-app/Cargo.toml @@ -11,7 +11,7 @@ path = "src/main.rs" cascade-core = { workspace = true } cascade-qb = { workspace = true } cascade-save = { workspace = true } -cascade-thugpro = { workspace = true } +cascade-thug2 = { workspace = true } cascade-thaw = { workspace = true } directories = { workspace = true } diff --git a/crates/cascade-app/src/dashboard.rs b/crates/cascade-app/src/dashboard.rs index 193df06..34840ca 100644 --- a/crates/cascade-app/src/dashboard.rs +++ b/crates/cascade-app/src/dashboard.rs @@ -10,7 +10,7 @@ use std::{ use cascade_core as core; use cascade_save as save; use cascade_thaw as thaw; -use cascade_thugpro as thugpro; +use cascade_thug2 as thug2; use iced::{ alignment::Vertical, font::Weight, @@ -39,8 +39,8 @@ pub enum Error { #[error("tasks error: {0}")] Tasks(#[from] tasks::Error), - #[error("thug pro error: {0}")] - ThugPro(#[from] thugpro::Error), + #[error("thug2 error: {0}")] + Thug2(#[from] thug2::Error), #[error("save error: {0}")] Save(#[from] save::Error), @@ -77,8 +77,8 @@ pub struct Components { #[derive(Debug, Clone)] pub enum Message { - LoadedCandidates(Result>), - LoadedSource(Result), + LoadedCandidates(Result>), + LoadedSource(Result), PickSource, SourcePicked(Option), @@ -88,13 +88,13 @@ pub enum Message { ClosedSavesDirDialog, ToggleSelectAll, - ToggleSelection(thugpro::Entry), + ToggleSelection(thug2::Entry), ToggleTricksetComponent(bool), ToggleScalesComponent(bool), Start, - PreProcessDone(Result<(Arc, PathBuf)>), - EntryProcessed(thugpro::Entry, Result<()>), + PreProcessDone(Result<(Arc, PathBuf)>), + EntryProcessed(thug2::Entry, Result<()>), ComboBoxSelected(String), } @@ -143,7 +143,7 @@ impl Dashboard { scales: bool, ) -> (Self, Task) { let source_entry = source_path - .map(|path| thugpro::Entry::at_path(path).ok()) + .map(|path| thug2::Entry::at_path(path).ok()) .flatten(); let tasks = Task::batch(vec![ @@ -239,7 +239,7 @@ impl Dashboard { (Task::none(), None) } Message::PickSource => (Task::perform(pick_source(), Message::SourcePicked), None), - Message::SourcePicked(Some(path)) => match thugpro::Entry::at_path(path.clone()) { + Message::SourcePicked(Some(path)) => match thug2::Entry::at_path(path.clone()) { Ok(entry) => { self.source_entry = Some(entry.clone()); ( @@ -582,14 +582,14 @@ async fn pick_source() -> Option { ) } -async fn _load_source(entry: thugpro::Entry) -> Result { +async fn _load_source(entry: thug2::Entry) -> Result { let save = save::Save::read(&mut entry.reader()?)?; - let cas = thugpro::Cas::try_from(&save)?; + let cas = thug2::Cas::try_from(&save)?; Ok(cas) } -async fn load_source(entry: thugpro::Entry) -> Result { +async fn load_source(entry: thug2::Entry) -> Result { let source = tokio::spawn(async move { _load_source(entry).await }) .await .map_err(|_| Error::Task)?; @@ -601,9 +601,9 @@ async fn load_candidates( saves_dir: Option>, selections: Selections, default_selection: bool, -) -> Result> { +) -> Result> { let saves_dir = saves_dir.ok_or(Error::NoSavesDir)?; - let entries = thugpro::entry::find_entries(saves_dir)?; + let entries = thug2::entry::find_entries(saves_dir)?; log::info!("found {} saves", entries.len()); @@ -620,16 +620,16 @@ async fn load_candidates( Ok(candidates) } -fn make_transform(source: &thugpro::cas::Cas, components: Components) -> thugpro::cas::Cas { +fn make_transform(source: &thug2::cas::Cas, components: Components) -> thug2::cas::Cas { let info = &source.data.custom_skater.custom.info; let appearance = &source.data.custom_skater.custom.appearance; - thugpro::cas::Cas { + thug2::cas::Cas { summary: source.summary.clone(), - data: thugpro::cas::Data { - custom_skater: thugpro::cas::CustomSkater { - custom: thugpro::cas::Custom { - info: thugpro::cas::Info { + data: thug2::cas::Data { + custom_skater: thug2::cas::CustomSkater { + custom: thug2::cas::Custom { + info: thug2::cas::Info { trick_mapping: components .trickset .then_some(info.trick_mapping.clone()) @@ -639,7 +639,7 @@ fn make_transform(source: &thugpro::cas::Cas, components: Components) -> thugpro .then_some(info.specials.clone()) .unwrap_or_default(), }, - appearance: thugpro::cas::Appearance { + appearance: thug2::cas::Appearance { board_bone_group: components .scales .then_some(appearance.board_bone_group.clone()) @@ -700,7 +700,7 @@ fn make_transform(source: &thugpro::cas::Cas, components: Components) -> thugpro }, }, }, - story_skater: thugpro::cas::StorySkater { + story_skater: thug2::cas::StorySkater { tricks: components .trickset .then_some(source.data.story_skater.tricks.clone()) @@ -712,9 +712,9 @@ fn make_transform(source: &thugpro::cas::Cas, components: Components) -> thugpro async fn pre_process>( backup_dir: P, - source: thugpro::Cas, + source: thug2::Cas, components: Components, -) -> Result<(Arc, PathBuf)> { +) -> Result<(Arc, PathBuf)> { let backup_dir = backup_dir.as_ref(); fs::create_dir_all(backup_dir).await?; let transform = Arc::new(make_transform(&source, components)); @@ -730,9 +730,9 @@ async fn pre_process>( } async fn process_entry>( - entry: thugpro::Entry, + entry: thug2::Entry, backup_dir: P, - transform: Arc, + transform: Arc, ) -> Result<()> { let backup_dir = backup_dir.as_ref(); diff --git a/crates/cascade-cli/Cargo.toml b/crates/cascade-cli/Cargo.toml index 8e4bf6c..0fa6745 100644 --- a/crates/cascade-cli/Cargo.toml +++ b/crates/cascade-cli/Cargo.toml @@ -12,8 +12,8 @@ cascade-save = { workspace = true } cascade-thaw = { workspace = true, features = ["serde"] } cascade-thug = { workspace = true } cascade-thps4 = { workspace = true } -cascade-thugpro = { workspace = true } -cascade-wad = { workspace = true } +cascade-thug2 = { workspace = true } +cascade-wad = { workspace = true, optional = true } clap = { workspace = true } color-eyre = { workspace = true } @@ -31,3 +31,4 @@ thiserror = { workspace = true } default = [] dump = ["dep:cascade-lut", "dep:cascade-dump"] ftp = ["dep:suppaftp"] +wad = ["dep:cascade-wad"] diff --git a/crates/cascade-cli/src/main.rs b/crates/cascade-cli/src/main.rs index 046cc2c..e6b7291 100644 --- a/crates/cascade-cli/src/main.rs +++ b/crates/cascade-cli/src/main.rs @@ -5,13 +5,14 @@ use std::{ path::PathBuf, }; -use cascade_core::{self as core}; +use cascade_core as core; #[cfg(feature = "dump")] use cascade_dump as dump; #[cfg(feature = "dump")] use cascade_lut::{self as lut, Lut}; use cascade_thaw as thaw; -use cascade_thugpro as thugpro; +use cascade_thug2 as thug2; +#[cfg(feature = "wad")] use cascade_wad::{hed, wad}; use clap::{Args, Parser, Subcommand}; use serde::Serialize; @@ -52,7 +53,6 @@ enum Command { #[arg(short, long)] game: Game, }, - #[cfg(feature = "dump")] RoundTrip { #[arg(short, long)] input: PathBuf, @@ -121,10 +121,12 @@ enum Command { #[arg(long)] female: bool, }, + #[cfg(feature = "wad")] Hed { #[arg(long)] input: PathBuf, }, + #[cfg(feature = "wad")] Wad { #[arg(long)] hed: PathBuf, @@ -168,13 +170,13 @@ fn main() -> color_eyre::Result<()> { output, game, } => { - let entry = thugpro::Entry::create(&input)?; + let entry = thug2::Entry::create(&input)?; let lut = Lut { checksum: lut::Checksum::load()?, compress: match game { Game::Thps4 => thps4::lut::load_compress()?, Game::Thug => thug::lut::load_compress()?, - Game::Thug2 => thugpro::lut::load_compress()?, + Game::Thug2 => thug2::lut::load_compress()?, Game::Thaw => thaw::lut::load_compress()?, Game::Rethawed => thaw::lut::load_compress()?, }, @@ -197,7 +199,6 @@ fn main() -> color_eyre::Result<()> { Ok(()) } - #[cfg(feature = "dump")] Command::RoundTrip { input, output, @@ -226,7 +227,7 @@ fn main() -> color_eyre::Result<()> { } match game { - Game::Thug2 => round_trip(&input, &output, thugpro::core::Parser {})?, + Game::Thug2 => round_trip(&input, &output, thug2::core::Parser {})?, Game::Rethawed => round_trip(&input, &output, thaw::core::Parser {})?, Game::Thps4 => todo!(), Game::Thug => todo!(), @@ -249,7 +250,7 @@ fn main() -> color_eyre::Result<()> { }; match game { - Game::Thug2 => modify(&from, &to, thugpro::core::Parser {}, flags)?, + Game::Thug2 => modify(&from, &to, thug2::core::Parser {}, flags)?, Game::Rethawed => modify(&from, &to, thaw::core::Parser {}, flags)?, Game::Thps4 => todo!(), Game::Thug => todo!(), @@ -276,8 +277,8 @@ fn main() -> color_eyre::Result<()> { Game::Thug => todo!(), Game::Thug2 => modify_bulk( &from, - thugpro::core::Explorer::new(to_dir), - thugpro::core::Parser {}, + thug2::core::Explorer::new(to_dir), + thug2::core::Parser {}, flags, )?, Game::Thaw => todo!(), @@ -297,8 +298,8 @@ fn main() -> color_eyre::Result<()> { name, female, } => { - let entries = thugpro::entry::find_entries(input_dir).unwrap(); - thugpro::random::randomize(&entries, output_dir, name, female)?; + let entries = thug2::entry::find_entries(input_dir).unwrap(); + thug2::random::randomize(&entries, output_dir, name, female)?; Ok(()) } @@ -308,11 +309,12 @@ fn main() -> color_eyre::Result<()> { number, female, } => { - let entries = thugpro::entry::find_entries(input_dir).unwrap(); - thugpro::random::randomize_bulk(&entries, output_dir, number, female)?; + let entries = thug2::entry::find_entries(input_dir).unwrap(); + thug2::random::randomize_bulk(&entries, output_dir, number, female)?; Ok(()) } + #[cfg(feature = "wad")] Command::Hed { input } => { let file = fs::File::open(input)?; let mut reader = BufReader::new(file); @@ -324,6 +326,7 @@ fn main() -> color_eyre::Result<()> { Ok(()) } + #[cfg(feature = "wad")] Command::Wad { hed, wad, output } => { let hed = hed::File::read(&mut BufReader::new(fs::File::open(hed)?))?; let mut wad = fs::File::open(wad)?; diff --git a/crates/cascade-core/src/cas.rs b/crates/cascade-core/src/cas.rs index b002b78..4d7b75c 100644 --- a/crates/cascade-core/src/cas.rs +++ b/crates/cascade-core/src/cas.rs @@ -1,10 +1,16 @@ -use crate::{Flags, save}; +use crate::save; -pub trait Cas -where - Save: save::Save, -{ - fn parse(save: &Save) -> Result, Error>; - fn modify(&self, save: &mut Save) -> Result<(), Error>; +pub struct Flags { + pub summary: bool, + pub trickset: bool, + pub scales: bool, +} + +pub trait Cas: Sized { + type Error; + type Save: save::Save; + + fn parse(save: &Self::Save) -> Result; fn mask(self, flags: Flags) -> Self; + fn modify(&self, save: &mut Self::Save) -> Result<(), Self::Error>; } diff --git a/crates/cascade-core/src/entry.rs b/crates/cascade-core/src/entry.rs index 1d2996c..ba504d8 100644 --- a/crates/cascade-core/src/entry.rs +++ b/crates/cascade-core/src/entry.rs @@ -1,15 +1,10 @@ use std::io::{Read, Seek, Write}; -pub trait Entry { - fn reader(&self) -> Result - where - R: Read + Seek; - - fn writer(&self) -> Result - where - W: Write + Seek; +pub trait Entry { + type Error; + fn reader(&self) -> Result; + fn writer(&self) -> Result; fn name(&self) -> String; - - fn rewrite_metadata(&self) -> Result<(), Error>; + fn rewrite_metadata(&self) -> Result<(), Self::Error>; } diff --git a/crates/cascade-core/src/lib.rs b/crates/cascade-core/src/lib.rs index 0ff4e70..1a2702a 100644 --- a/crates/cascade-core/src/lib.rs +++ b/crates/cascade-core/src/lib.rs @@ -1,36 +1,16 @@ -use std::io::{Read, Seek, Write}; +mod cas; +mod entry; +mod save; -pub mod cas; -pub mod entry; -pub mod save; +pub use cas::{Cas, Flags}; +pub use entry::Entry; +pub use save::Save; -pub trait Explorer { - fn list(&self) -> Result, Error>; - fn reader(&self, entry: &Entry) -> Result; - fn writer(&self, entry: &Entry) -> Result; - fn name(&self, entry: &Entry) -> String; - fn rewrite_metadata(&self, entry: &Entry) -> Result<(), Error>; -} - -pub struct Flags { - pub summary: bool, - pub trickset: bool, - pub scales: bool, -} - -pub trait Parser { - fn read(&self, reader: &mut (impl Read + Seek)) -> Result; - fn write(&self, save: &Save, writer: &mut impl Write) -> Result<(), Error>; - fn parse(&self, save: &Save) -> Result; - fn mask(&self, cas: Cas, flags: Flags) -> Cas; - fn modify(&self, save: &mut Save, cas: &Cas) -> Result<(), Error>; -} +pub trait Core { + type Entry: entry::Entry; + type Save: save::Save; + type Cas: cas::Cas; + type Error; -pub trait Core -where - Entry: entry::Entry, - Save: save::Save, - Cas: cas::Cas, -{ - fn list_entries() -> Result, Error>; + fn list_entries(&self) -> Result, Self::Error>; } diff --git a/crates/cascade-core/src/save.rs b/crates/cascade-core/src/save.rs index 5e1e57f..d6e8f09 100644 --- a/crates/cascade-core/src/save.rs +++ b/crates/cascade-core/src/save.rs @@ -1,11 +1,8 @@ use std::io::{Read, Seek, Write}; -pub trait Save { - fn read(&self, reader: &mut R) -> Result, Error> - where - R: Read + Seek; +pub trait Save: Sized { + type Error; - fn write(&self, writer: &mut W) -> Result<(), Error> - where - W: Write + Seek; + fn read(reader: &mut (impl Read + Seek)) -> Result; + fn write(&self, writer: &mut (impl Write + Seek)) -> Result<(), Self::Error>; } diff --git a/crates/cascade-save/Cargo.toml b/crates/cascade-save/Cargo.toml index cba1f8a..b40538a 100644 --- a/crates/cascade-save/Cargo.toml +++ b/crates/cascade-save/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] cascade-crc = { workspace = true } cascade-qb = { workspace = true } +cascade-core = { workspace = true } byteorder = { workspace = true } count-write = { workspace = true } diff --git a/crates/cascade-save/src/save.rs b/crates/cascade-save/src/save.rs index 0376520..0b2137f 100644 --- a/crates/cascade-save/src/save.rs +++ b/crates/cascade-save/src/save.rs @@ -1,11 +1,11 @@ -use std::io::{Read, Write}; +use std::io::{Read, Seek, Write}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use cascade_crc as crc; use cascade_qb as qb; use count_write::CountWrite; -use crate::Result; +use crate::{Error, Result}; const SAVE_FILE_SIZE: usize = 90112; const PADDING_BYTE: u8 = 0x69; @@ -63,8 +63,10 @@ pub struct Save { pub data: Box, } -impl Save { - pub fn read(reader: &mut impl Read) -> Result { +impl cascade_core::save::Save for Save { + type Error = Error; + + fn read(reader: &mut (impl Read + Seek)) -> Result { Ok(Self { header: Header::read(reader)?, summary: Box::new(qb::Structure::read(reader)?), @@ -72,10 +74,9 @@ impl Save { }) } - pub fn write(&self, writer: &mut W) -> Result<()> { + fn write(&self, writer: &mut (impl Write + Seek)) -> Result<()> { let mut count_writer = CountWrite::from(writer); - // TODO fix this let header = self.calculate_header()?; header.write(&mut count_writer)?; @@ -97,8 +98,11 @@ impl Save { Ok(()) } +} +impl Save { fn calculate_header(&self) -> Result
{ + // TODO use seek instead of serializing save twice let mut summary_bytes = self.summary.raw_bytes()?; let mut data_bytes = self.data.raw_bytes()?; diff --git a/crates/cascade-thugpro/Cargo.toml b/crates/cascade-thug2/Cargo.toml similarity index 95% rename from crates/cascade-thugpro/Cargo.toml rename to crates/cascade-thug2/Cargo.toml index de1d508..6f21b63 100644 --- a/crates/cascade-thugpro/Cargo.toml +++ b/crates/cascade-thug2/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cascade-thugpro" +name = "cascade-thug2" version = "0.0.1" edition = "2024" diff --git a/crates/cascade-thugpro/src/cas.rs b/crates/cascade-thug2/src/cas.rs similarity index 74% rename from crates/cascade-thugpro/src/cas.rs rename to crates/cascade-thug2/src/cas.rs index 0a8655b..e28650c 100644 --- a/crates/cascade-thugpro/src/cas.rs +++ b/crates/cascade-thug2/src/cas.rs @@ -1,5 +1,5 @@ use cascade_qb as qb; -use cascade_save as save; +use cascade_save::{self as save}; use crate::{Error, Result, id}; @@ -66,13 +66,153 @@ impl From> for Item { } } -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Cas { pub summary: Summary, pub data: Data, } +impl cascade_core::cas::Cas for Cas { + type Error = Error; + type Save = save::Save; + + fn parse(save: &save::Save) -> std::result::Result { + Ok(Cas::try_from(save)?) + } + + fn mask(self, flags: cascade_core::Flags) -> Self { + Cas { + summary: flags.summary.then_some(self.summary).unwrap_or_default(), + data: Data { + custom_skater: CustomSkater { + custom: Custom { + info: Info { + trick_mapping: flags + .trickset + .then_some(self.data.custom_skater.custom.info.trick_mapping) + .unwrap_or_default(), + specials: flags + .trickset + .then_some(self.data.custom_skater.custom.info.specials) + .unwrap_or_default(), + }, + appearance: Appearance { + board_bone_group: flags + .scales + .then_some( + self.data.custom_skater.custom.appearance.board_bone_group, + ) + .unwrap_or_default(), + feet_bone_group: flags + .scales + .then_some( + self.data.custom_skater.custom.appearance.feet_bone_group, + ) + .unwrap_or_default(), + hands_bone_group: flags + .scales + .then_some( + self.data.custom_skater.custom.appearance.hands_bone_group, + ) + .unwrap_or_default(), + head_bone_group: flags + .scales + .then_some( + self.data.custom_skater.custom.appearance.head_bone_group, + ) + .unwrap_or_default(), + headtop_bone_group: flags + .scales + .then_some( + self.data.custom_skater.custom.appearance.headtop_bone_group, + ) + .unwrap_or_default(), + jaw_bone_group: flags + .scales + .then_some(self.data.custom_skater.custom.appearance.jaw_bone_group) + .unwrap_or_default(), + lower_arm_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom + .appearance + .lower_arm_bone_group, + ) + .unwrap_or_default(), + lower_leg_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom + .appearance + .lower_leg_bone_group, + ) + .unwrap_or_default(), + nose_bone_group: flags + .scales + .then_some( + self.data.custom_skater.custom.appearance.nose_bone_group, + ) + .unwrap_or_default(), + object_scaling: flags + .scales + .then_some(self.data.custom_skater.custom.appearance.object_scaling) + .unwrap_or_default(), + stomach_bone_group: flags + .scales + .then_some( + self.data.custom_skater.custom.appearance.stomach_bone_group, + ) + .unwrap_or_default(), + torso_bone_group: flags + .scales + .then_some( + self.data.custom_skater.custom.appearance.torso_bone_group, + ) + .unwrap_or_default(), + upper_arm_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom + .appearance + .upper_arm_bone_group, + ) + .unwrap_or_default(), + upper_leg_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom + .appearance + .upper_leg_bone_group, + ) + .unwrap_or_default(), + ..Default::default() + }, + }, + }, + story_skater: StorySkater { + tricks: flags + .trickset + .then_some(self.data.story_skater.tricks) + .unwrap_or_default(), + }, + }, + } + } + + fn modify(&self, save: &mut save::Save) -> std::result::Result<(), Self::Error> { + Ok(self.modify(save)?) + } +} + impl TryFrom<&save::Save> for Cas { type Error = Error; diff --git a/crates/cascade-thug2/src/core.rs b/crates/cascade-thug2/src/core.rs new file mode 100644 index 0000000..c277f22 --- /dev/null +++ b/crates/cascade-thug2/src/core.rs @@ -0,0 +1,30 @@ +use std::path::PathBuf; + +use cascade_save::Save; + +use crate::{ + Error, Result, + cas::Cas, + entry::{Entry, find_entries}, +}; + +pub struct Core { + cwd: PathBuf, +} + +impl Core { + pub fn new(cwd: PathBuf) -> Self { + Self { cwd } + } +} + +impl cascade_core::Core for Core { + type Entry = Entry; + type Save = Save; + type Cas = Cas; + type Error = Error; + + fn list_entries(&self) -> Result> { + find_entries(&self.cwd) + } +} diff --git a/crates/cascade-thugpro/src/entry.rs b/crates/cascade-thug2/src/entry.rs similarity index 84% rename from crates/cascade-thugpro/src/entry.rs rename to crates/cascade-thug2/src/entry.rs index d014b50..f2bcfd9 100644 --- a/crates/cascade-thugpro/src/entry.rs +++ b/crates/cascade-thug2/src/entry.rs @@ -15,6 +15,41 @@ pub struct Entry { pub metadata: Option, } +impl cascade_core::Entry for Entry { + type Error = Error; + + fn reader(&self) -> Result { + let file = fs::File::open(&self.path)?; + Ok(BufReader::new(file)) + } + + fn writer(&self) -> Result { + let file = fs::File::create(&self.path)?; + Ok(BufWriter::new(file)) + } + + fn name(&self) -> String { + self.filename.clone() + } + + fn rewrite_metadata(&self) -> Result<()> { + if let Some(metadata) = &self.metadata { + let filepath = &self.path; + + let original_mod_time = filetime::FileTime::from_last_modification_time(metadata); + + log::info!( + "setting file modification time for {:?} to {:?}", + filepath, + original_mod_time + ); + filetime::set_file_mtime(&filepath, original_mod_time)?; + } + + Ok(()) + } +} + impl Hash for Entry { fn hash(&self, state: &mut H) { self.path.hash(state); @@ -62,26 +97,9 @@ impl Entry { let file = fs::File::create(&self.path)?; Ok(BufWriter::new(file)) } - - pub fn rewrite_metadata(&self) -> Result<()> { - if let Some(metadata) = &self.metadata { - let filepath = &self.path; - - let original_mod_time = filetime::FileTime::from_last_modification_time(metadata); - - log::info!( - "setting file modification time for {:?} to {:?}", - filepath, - original_mod_time - ); - filetime::set_file_mtime(&filepath, original_mod_time)?; - } - - Ok(()) - } } -pub fn find_entries(dir: impl AsRef) -> Result> { +pub fn find_entries(dir: impl AsRef) -> Result> { let dir = PathBuf::from(dir.as_ref()); dir.is_dir() @@ -116,6 +134,5 @@ pub fn find_entries(dir: impl AsRef) -> Result> { } else { None } - }) - .collect()) + })) } diff --git a/crates/cascade-thugpro/src/error.rs b/crates/cascade-thug2/src/error.rs similarity index 100% rename from crates/cascade-thugpro/src/error.rs rename to crates/cascade-thug2/src/error.rs diff --git a/crates/cascade-thugpro/src/id.rs b/crates/cascade-thug2/src/id.rs similarity index 100% rename from crates/cascade-thugpro/src/id.rs rename to crates/cascade-thug2/src/id.rs diff --git a/crates/cascade-thugpro/src/lib.rs b/crates/cascade-thug2/src/lib.rs similarity index 100% rename from crates/cascade-thugpro/src/lib.rs rename to crates/cascade-thug2/src/lib.rs diff --git a/crates/cascade-thugpro/src/lut.rs b/crates/cascade-thug2/src/lut.rs similarity index 100% rename from crates/cascade-thugpro/src/lut.rs rename to crates/cascade-thug2/src/lut.rs diff --git a/crates/cascade-thugpro/src/random.rs b/crates/cascade-thug2/src/random.rs similarity index 100% rename from crates/cascade-thugpro/src/random.rs rename to crates/cascade-thug2/src/random.rs diff --git a/crates/cascade-thugpro/tests/common/mod.rs b/crates/cascade-thug2/tests/common/mod.rs similarity index 77% rename from crates/cascade-thugpro/tests/common/mod.rs rename to crates/cascade-thug2/tests/common/mod.rs index 865c911..e327d72 100644 --- a/crates/cascade-thugpro/tests/common/mod.rs +++ b/crates/cascade-thug2/tests/common/mod.rs @@ -1,6 +1,6 @@ use std::{env, fs, path::PathBuf}; -use cascade_thugpro as thugpro; +use cascade_thug2 as thug2; pub fn output_dir() -> PathBuf { let temp_dir = env::temp_dir(); @@ -16,7 +16,7 @@ pub fn output_dir() -> PathBuf { output_dir } -pub fn entries() -> Vec { +pub fn entries() -> Vec { let cwd = env::current_dir().expect("could not get cwd"); let saves_dir = PathBuf::from(cwd) @@ -25,5 +25,5 @@ pub fn entries() -> Vec { .join("assets") .join("saves"); - thugpro::entry::find_entries(&saves_dir).expect("could not find saves directory") + thug2::entry::find_entries(&saves_dir).expect("could not find saves directory") } diff --git a/crates/cascade-thugpro/tests/round_trip.rs b/crates/cascade-thug2/tests/round_trip.rs similarity index 88% rename from crates/cascade-thugpro/tests/round_trip.rs rename to crates/cascade-thug2/tests/round_trip.rs index a5e1d6b..df89407 100644 --- a/crates/cascade-thugpro/tests/round_trip.rs +++ b/crates/cascade-thug2/tests/round_trip.rs @@ -5,10 +5,10 @@ use std::{ }; use cascade_save as save; -use cascade_thugpro as thugpro; +use cascade_thug2 as thug2; mod common; -fn read_entry_bytes(save: &thugpro::Entry) -> Vec { +fn read_entry_bytes(save: &thug2::Entry) -> Vec { let filepath = save.filepath(); let mut file = fs::File::open(&filepath).expect("could not open file for reading"); @@ -18,7 +18,7 @@ fn read_entry_bytes(save: &thugpro::Entry) -> Vec { bytes } -fn diff_save_files(input_entry: &thugpro::Entry, output_entry: &thugpro::Entry) -> bool { +fn diff_save_files(input_entry: &thug2::Entry, output_entry: &thug2::Entry) -> bool { let input_bytes = read_entry_bytes(&input_entry); let output_bytes = read_entry_bytes(&output_entry); @@ -56,7 +56,7 @@ fn diff_save_files(input_entry: &thugpro::Entry, output_entry: &thugpro::Entry) } } -fn round_trip_save_file(input_entry: &thugpro::Entry, output_entry: &thugpro::Entry) -> bool { +fn round_trip_save_file(input_entry: &thug2::Entry, output_entry: &thug2::Entry) -> bool { let mut input_reader = input_entry.reader().unwrap(); let input_save = save::Save::read(&mut input_reader).expect("could not load input save"); diff --git a/crates/cascade-thugpro/src/core.rs b/crates/cascade-thugpro/src/core.rs deleted file mode 100644 index b2f553b..0000000 --- a/crates/cascade-thugpro/src/core.rs +++ /dev/null @@ -1,186 +0,0 @@ -use std::{ - io::{Read, Seek}, - path::PathBuf, -}; - -use cascade_core as core; -use cascade_save::Save; - -use crate::{ - Error, - cas::{self, Cas}, - entry::{self, Entry}, -}; - -pub struct Explorer { - cwd: PathBuf, -} - -impl Explorer { - pub fn new(cwd: PathBuf) -> Self { - Self { cwd } - } -} - -impl core::Explorer for Explorer { - fn list(&self) -> Result, Error> { - entry::find_entries(&self.cwd).map(|entries| entries.into_iter()) - } - - fn reader(&self, entry: &Entry) -> Result { - entry.reader() - } - - fn writer(&self, entry: &Entry) -> Result { - entry.writer() - } - - fn name(&self, entry: &Entry) -> String { - entry.filename.clone() - } - - fn rewrite_metadata(&self, entry: &Entry) -> Result<(), Error> { - entry.rewrite_metadata() - } -} - -pub struct Parser; - -impl core::Parser for Parser { - fn read(&self, reader: &mut impl Read) -> Result { - Ok(Save::read(reader)?) - } - - fn write(&self, save: &Save, writer: &mut impl std::io::Write) -> Result<(), Error> { - Ok(save.write(writer)?) - } - - fn parse(&self, save: &Save) -> Result { - Ok(Cas::try_from(save)?) - } - - fn modify(&self, save: &mut Save, transform: &Cas) -> Result<(), Error> { - Ok(transform.modify(save)?) - } - - fn mask(&self, cas: Cas, flags: core::Flags) -> Cas { - Cas { - summary: flags.summary.then_some(cas.summary).unwrap_or_default(), - data: cas::Data { - custom_skater: cas::CustomSkater { - custom: cas::Custom { - info: cas::Info { - trick_mapping: flags - .trickset - .then_some(cas.data.custom_skater.custom.info.trick_mapping) - .unwrap_or_default(), - specials: flags - .trickset - .then_some(cas.data.custom_skater.custom.info.specials) - .unwrap_or_default(), - }, - appearance: cas::Appearance { - board_bone_group: flags - .scales - .then_some( - cas.data.custom_skater.custom.appearance.board_bone_group, - ) - .unwrap_or_default(), - feet_bone_group: flags - .scales - .then_some(cas.data.custom_skater.custom.appearance.feet_bone_group) - .unwrap_or_default(), - hands_bone_group: flags - .scales - .then_some( - cas.data.custom_skater.custom.appearance.hands_bone_group, - ) - .unwrap_or_default(), - head_bone_group: flags - .scales - .then_some(cas.data.custom_skater.custom.appearance.head_bone_group) - .unwrap_or_default(), - headtop_bone_group: flags - .scales - .then_some( - cas.data.custom_skater.custom.appearance.headtop_bone_group, - ) - .unwrap_or_default(), - jaw_bone_group: flags - .scales - .then_some(cas.data.custom_skater.custom.appearance.jaw_bone_group) - .unwrap_or_default(), - lower_arm_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom - .appearance - .lower_arm_bone_group, - ) - .unwrap_or_default(), - lower_leg_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom - .appearance - .lower_leg_bone_group, - ) - .unwrap_or_default(), - nose_bone_group: flags - .scales - .then_some(cas.data.custom_skater.custom.appearance.nose_bone_group) - .unwrap_or_default(), - object_scaling: flags - .scales - .then_some(cas.data.custom_skater.custom.appearance.object_scaling) - .unwrap_or_default(), - stomach_bone_group: flags - .scales - .then_some( - cas.data.custom_skater.custom.appearance.stomach_bone_group, - ) - .unwrap_or_default(), - torso_bone_group: flags - .scales - .then_some( - cas.data.custom_skater.custom.appearance.torso_bone_group, - ) - .unwrap_or_default(), - upper_arm_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom - .appearance - .upper_arm_bone_group, - ) - .unwrap_or_default(), - upper_leg_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom - .appearance - .upper_leg_bone_group, - ) - .unwrap_or_default(), - ..Default::default() - }, - }, - }, - story_skater: cas::StorySkater { - tricks: flags - .trickset - .then_some(cas.data.story_skater.tricks) - .unwrap_or_default(), - }, - }, - } - } -} From e088ac67e30b3d27cde6bf3f2f38053ccee3572b Mon Sep 17 00:00:00 2001 From: ellie <149747415+1borgy@users.noreply.github.com> Date: Wed, 27 Aug 2025 18:13:53 -0400 Subject: [PATCH 08/23] fixup! fixup! fixup! fixup! fixup! fixup! fixup! update --- crates/cascade-cli/Cargo.toml | 4 +- crates/cascade-cli/src/main.rs | 282 ++++++++++++------------------- crates/cascade-core/src/cas.rs | 2 +- crates/cascade-save/src/save.rs | 2 +- crates/cascade-thaw/Cargo.toml | 3 +- crates/cascade-thaw/src/cas.rs | 186 ++++++++++++++++++++ crates/cascade-thaw/src/core.rs | 233 ++----------------------- crates/cascade-thaw/src/entry.rs | 71 ++++---- crates/cascade-thaw/src/lib.rs | 15 +- crates/cascade-thaw/src/save.rs | 64 +++---- crates/cascade-thug2/Cargo.toml | 6 +- crates/cascade-thug2/src/cas.rs | 25 ++- crates/cascade-thug2/src/core.rs | 8 +- crates/cascade-thug2/src/lib.rs | 17 +- crates/cascade-thug2/src/save.rs | 31 ++++ rust-toolchain.toml | 1 + 16 files changed, 457 insertions(+), 493 deletions(-) create mode 100644 crates/cascade-thug2/src/save.rs diff --git a/crates/cascade-cli/Cargo.toml b/crates/cascade-cli/Cargo.toml index 0fa6745..7bc4428 100644 --- a/crates/cascade-cli/Cargo.toml +++ b/crates/cascade-cli/Cargo.toml @@ -12,7 +12,7 @@ cascade-save = { workspace = true } cascade-thaw = { workspace = true, features = ["serde"] } cascade-thug = { workspace = true } cascade-thps4 = { workspace = true } -cascade-thug2 = { workspace = true } +cascade-thug2 = { workspace = true, features = ["serde"] } cascade-wad = { workspace = true, optional = true } clap = { workspace = true } @@ -29,6 +29,6 @@ thiserror = { workspace = true } [features] default = [] -dump = ["dep:cascade-lut", "dep:cascade-dump"] +dump = ["dep:cascade-lut", "dep:cascade-dump", "cascade-thaw/lut", "cascade-thug2/lut"] ftp = ["dep:suppaftp"] wad = ["dep:cascade-wad"] diff --git a/crates/cascade-cli/src/main.rs b/crates/cascade-cli/src/main.rs index e6b7291..1af7377 100644 --- a/crates/cascade-cli/src/main.rs +++ b/crates/cascade-cli/src/main.rs @@ -5,7 +5,7 @@ use std::{ path::PathBuf, }; -use cascade_core as core; +use cascade_core; #[cfg(feature = "dump")] use cascade_dump as dump; #[cfg(feature = "dump")] @@ -14,17 +14,15 @@ use cascade_thaw as thaw; use cascade_thug2 as thug2; #[cfg(feature = "wad")] use cascade_wad::{hed, wad}; -use clap::{Args, Parser, Subcommand}; +use clap::{Parser, Subcommand}; use serde::Serialize; #[cfg(feature = "ftp")] use suppaftp::FtpStream; +/// A CLI-only version of cascade. #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct App { - #[clap(flatten)] - global: GlobalOpts, - #[clap(subcommand)] command: Command, } @@ -32,12 +30,9 @@ struct App { #[derive(clap::ValueEnum, Clone, Default, Debug, Serialize)] #[serde(rename_all = "kebab-case")] enum Game { - Thps4, - Thug, #[default] Thug2, Thaw, - Rethawed, } #[derive(Debug, Subcommand)] @@ -53,74 +48,76 @@ enum Command { #[arg(short, long)] game: Game, }, - RoundTrip { - #[arg(short, long)] - input: PathBuf, - - #[arg(short, long)] - output: PathBuf, - - #[arg(short, long)] - game: Game, - }, + /// Perform a single modification. Modify { + /// Path to the save file to copy from. #[arg(long)] from: PathBuf, + /// Path to the save file to copy to. #[arg(long)] to: PathBuf, + /// Which game the saves are for. #[arg(long)] game: Game, + /// If specified, copy scales. #[arg(long)] scales: bool, + /// If specified, copy trickset. #[arg(long)] trickset: bool, }, + /// Perform a modification in bulk (i.e. all saves in a directory). ModifyBulk { + /// Path to the save file to copy from. #[arg(long)] from: PathBuf, + /// Path to the directory containing all save files to copy to. #[arg(long)] to_dir: PathBuf, + /// Which game the saves are for. #[arg(long)] game: Game, + /// If specified, copy scales. #[arg(long)] scales: bool, + /// If specified, copy trickset. #[arg(long)] trickset: bool, }, - Randomize { - #[arg(long)] - input_dir: PathBuf, - - #[arg(long)] - output_dir: PathBuf, - - #[arg(long, short)] - name: String, - - #[arg(long)] - female: bool, - }, - RandomizeBulk { - #[arg(long)] - input_dir: PathBuf, - - #[arg(long)] - output_dir: PathBuf, - - #[arg(long, short)] - number: usize, - - #[arg(long)] - female: bool, - }, + // Randomize { + // #[arg(long)] + // input_dir: PathBuf, + // + // #[arg(long)] + // output_dir: PathBuf, + // + // #[arg(long, short)] + // name: String, + // + // #[arg(long)] + // female: bool, + // }, + // RandomizeBulk { + // #[arg(long)] + // input_dir: PathBuf, + // + // #[arg(long)] + // output_dir: PathBuf, + // + // #[arg(long, short)] + // number: usize, + // + // #[arg(long)] + // female: bool, + // }, #[cfg(feature = "wad")] Hed { #[arg(long)] @@ -151,17 +148,13 @@ enum Dump { Rethawed(thaw::dump::Save), } -#[derive(Debug, Args)] -struct GlobalOpts {} - fn main() -> color_eyre::Result<()> { - let App { - global: _global, - command, - } = App::parse(); + let App { command } = App::parse(); color_eyre::install()?; - env_logger::init(); + env_logger::Builder::new() + .filter(None, log::LevelFilter::Info) + .init(); match command { #[cfg(feature = "dump")] @@ -170,72 +163,34 @@ fn main() -> color_eyre::Result<()> { output, game, } => { + use std::io::Write; + let entry = thug2::Entry::create(&input)?; let lut = Lut { checksum: lut::Checksum::load()?, compress: match game { - Game::Thps4 => thps4::lut::load_compress()?, - Game::Thug => thug::lut::load_compress()?, Game::Thug2 => thug2::lut::load_compress()?, Game::Thaw => thaw::lut::load_compress()?, - Game::Rethawed => thaw::lut::load_compress()?, }, }; let dump = match game { - Game::Thps4 | Game::Thug | Game::Thug2 | Game::Thaw => { - let save = Save::read(&mut entry.reader()?)?; + Game::Thug2 => { + let save = cascade_save::Save::read(&mut entry.reader()?)?; Dump::Neversoft(dump::Save::new(&save, &lut)) } - Game::Rethawed => { - let save = thaw::save::Save::read(&mut entry.reader()?)?; + Game::Thaw => { + let save = thaw::Save::read(&mut entry.reader()?)?; Dump::Rethawed(thaw::dump::Save::new(&save, &lut)) } }; - let mut file = File::create(output).unwrap(); + let mut file = fs::File::create(output).unwrap(); let contents = ron::ser::to_string_pretty(&dump, ron::ser::PrettyConfig::new()).unwrap(); file.write(contents.as_bytes()).unwrap(); Ok(()) } - Command::RoundTrip { - input, - output, - game, - } => { - fn round_trip( - input: &PathBuf, - output: &PathBuf, - parser: impl core::Parser, - ) -> Result<(), E> - where - E: From, - { - let file = fs::File::open(&input)?; - let mut reader = BufReader::new(file); - let mut save = parser.read(&mut reader)?; - - let parsed = parser.parse(&save)?; - parser.modify(&mut save, &parsed)?; - - let file = fs::File::create(&output)?; - let mut writer = BufWriter::new(file); - parser.write(&save, &mut writer)?; - - Ok(()) - } - - match game { - Game::Thug2 => round_trip(&input, &output, thug2::core::Parser {})?, - Game::Rethawed => round_trip(&input, &output, thaw::core::Parser {})?, - Game::Thps4 => todo!(), - Game::Thug => todo!(), - Game::Thaw => todo!(), - } - - Ok(()) - } Command::Modify { from, to, @@ -243,20 +198,23 @@ fn main() -> color_eyre::Result<()> { scales, trickset, } => { - let flags = core::Flags { + let flags = cascade_core::Flags { trickset, scales, summary: false, }; + if !scales && !trickset { + log::warn!("neither `--scales` nor `--trickset` are specified; expect no changes") + } + match game { - Game::Thug2 => modify(&from, &to, thug2::core::Parser {}, flags)?, - Game::Rethawed => modify(&from, &to, thaw::core::Parser {}, flags)?, - Game::Thps4 => todo!(), - Game::Thug => todo!(), - Game::Thaw => todo!(), + Game::Thug2 => modify::(&from, &to, flags)?, + Game::Thaw => modify::(&from, &to, flags)?, } + log::info!("successfully copied to {}", to.display()); + Ok(()) } Command::ModifyBulk { @@ -266,51 +224,20 @@ fn main() -> color_eyre::Result<()> { scales, trickset, } => { - let flags = core::Flags { + let flags = cascade_core::Flags { trickset, scales, summary: false, }; - match game { - Game::Thps4 => todo!(), - Game::Thug => todo!(), - Game::Thug2 => modify_bulk( - &from, - thug2::core::Explorer::new(to_dir), - thug2::core::Parser {}, - flags, - )?, - Game::Thaw => todo!(), - Game::Rethawed => modify_bulk( - &from, - thaw::core::Explorer::new(to_dir), - thaw::core::Parser {}, - flags, - )?, + if !scales && !trickset { + log::warn!("neither `--scales` nor `--trickset` are specified; expect no changes") } - Ok(()) - } - Command::Randomize { - input_dir, - output_dir, - name, - female, - } => { - let entries = thug2::entry::find_entries(input_dir).unwrap(); - thug2::random::randomize(&entries, output_dir, name, female)?; - - Ok(()) - } - Command::RandomizeBulk { - input_dir, - output_dir, - number, - female, - } => { - let entries = thug2::entry::find_entries(input_dir).unwrap(); - thug2::random::randomize_bulk(&entries, output_dir, number, female)?; + match game { + Game::Thug2 => modify_bulk(&from, thug2::Core::new(to_dir), flags)?, + Game::Thaw => modify_bulk(&from, thaw::Core::new(to_dir), flags)?, + } Ok(()) } @@ -370,71 +297,78 @@ fn main() -> color_eyre::Result<()> { } } -fn modify( +fn modify( from: &PathBuf, to: &PathBuf, - parser: impl core::Parser, - flags: core::Flags, -) -> Result<(), E> + flags: cascade_core::Flags, +) -> Result<(), Error> where - E: From, + Save: cascade_core::Save, + Cas: cascade_core::Cas, + Error: From + Debug, { let from_file = fs::File::open(&from)?; let mut from_reader = BufReader::new(from_file); - let from_save = parser.read(&mut from_reader)?; + let from_save = Save::read(&mut from_reader)?; let to_file = fs::File::open(&to)?; let mut to_reader = BufReader::new(to_file); - let mut to_save = parser.read(&mut to_reader)?; + let mut to_save = Save::read(&mut to_reader)?; - let from_parsed = parser.parse(&from_save)?; - let from_parsed = parser.mask(from_parsed, flags); - parser.modify(&mut to_save, &from_parsed)?; + let from_parsed = Cas::parse(&from_save)?; + let transform = from_parsed.mask(flags); + transform.modify(&mut to_save)?; let to_file = fs::File::create(&to)?; let mut writer = BufWriter::new(to_file); - parser.write(&to_save, &mut writer)?; + to_save.write(&mut writer)?; Ok(()) } fn modify_bulk( from: &PathBuf, - explorer: impl core::Explorer, - parser: impl core::Parser, - flags: core::Flags, + core: impl cascade_core::Core, + flags: cascade_core::Flags, ) -> Result<(), Error> where + Entry: cascade_core::Entry, + Save: cascade_core::Save, + Cas: cascade_core::Cas, Error: From + Debug, { - fn modify_one( - entry: &Entry, - transform: &Cas, - explorer: &impl core::Explorer, - parser: &impl core::Parser, - ) -> Result<(), Error> { - let mut reader = explorer.reader(&entry)?; - let mut save = parser.read(&mut reader)?; - parser.modify(&mut save, &transform)?; - let mut writer = explorer.writer(&entry)?; - parser.write(&save, &mut writer)?; + fn modify_one(entry: &Entry, transform: &Cas) -> Result<(), Error> + where + Entry: cascade_core::Entry, + Save: cascade_core::Save, + Cas: cascade_core::Cas, + Error: From + Debug, + { + let mut reader = entry.reader()?; + let mut save = Save::read(&mut reader)?; + + transform.modify(&mut save)?; + + let mut writer = entry.writer()?; + save.write(&mut writer)?; + Ok(()) } let from_file = fs::File::open(&from)?; let mut from_reader = BufReader::new(from_file); - let from_save = parser.read(&mut from_reader)?; - let from_parsed = parser.parse(&from_save)?; - let transform = parser.mask(from_parsed, flags); + let from_save = Save::read(&mut from_reader)?; + let from_parsed = Cas::parse(&from_save)?; + let transform = from_parsed.mask(flags); - for entry in explorer.list()? { - let name = explorer.name(&entry); - match modify_one(&entry, &transform, &explorer, &parser) { + for entry in core.list_entries()? { + let name = entry.name(); + match modify_one(&entry, &transform) { Ok(_) => { - println!("successfully copied {}", name) + log::info!("successfully copied to {}", name) } Err(e) => { - println!("error copying {}: {:?}", name, e) + log::info!("error copying to {}: {:?}", name, e) } } } diff --git a/crates/cascade-core/src/cas.rs b/crates/cascade-core/src/cas.rs index 4d7b75c..dcb6f5e 100644 --- a/crates/cascade-core/src/cas.rs +++ b/crates/cascade-core/src/cas.rs @@ -11,6 +11,6 @@ pub trait Cas: Sized { type Save: save::Save; fn parse(save: &Self::Save) -> Result; - fn mask(self, flags: Flags) -> Self; fn modify(&self, save: &mut Self::Save) -> Result<(), Self::Error>; + fn mask(self, flags: Flags) -> Self; } diff --git a/crates/cascade-save/src/save.rs b/crates/cascade-save/src/save.rs index 0b2137f..5fbd749 100644 --- a/crates/cascade-save/src/save.rs +++ b/crates/cascade-save/src/save.rs @@ -63,7 +63,7 @@ pub struct Save { pub data: Box, } -impl cascade_core::save::Save for Save { +impl cascade_core::Save for Save { type Error = Error; fn read(reader: &mut (impl Read + Seek)) -> Result { diff --git a/crates/cascade-thaw/Cargo.toml b/crates/cascade-thaw/Cargo.toml index 84584dd..5ecfd0c 100644 --- a/crates/cascade-thaw/Cargo.toml +++ b/crates/cascade-thaw/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] cascade-core = { workspace = true } cascade-dump = { workspace = true } -cascade-lut = { workspace = true } +cascade-lut = { workspace = true, optional = true } cascade-save = { workspace = true } cascade-qb = { workspace = true } @@ -18,3 +18,4 @@ thiserror = { workspace = true } [features] serde = ["dep:serde"] +lut = ["dep:cascade-lut"] diff --git a/crates/cascade-thaw/src/cas.rs b/crates/cascade-thaw/src/cas.rs index 8891721..988fccc 100644 --- a/crates/cascade-thaw/src/cas.rs +++ b/crates/cascade-thaw/src/cas.rs @@ -72,6 +72,192 @@ pub struct Cas { pub data: Data, } +impl cascade_core::Cas for Cas { + type Error = Error; + type Save = Save; + + fn parse(save: &Self::Save) -> Result { + Self::try_from(save) + } + + fn modify(&self, save: &mut Self::Save) -> Result<()> { + self.modify(save) + } + + fn mask(self, flags: cascade_core::Flags) -> Self { + Cas { + summary: flags.summary.then_some(self.summary).unwrap_or_default(), + data: Data { + custom_skater: CustomSkater { + custom_classic: CustomClassic { + info: Info { + trick_mapping: flags + .trickset + .then_some( + self.data.custom_skater.custom_classic.info.trick_mapping, + ) + .unwrap_or_default(), + specials: flags + .trickset + .then_some(self.data.custom_skater.custom_classic.info.specials) + .unwrap_or_default(), + }, + appearance: Appearance { + board_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .board_bone_group, + ) + .unwrap_or_default(), + feet_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .feet_bone_group, + ) + .unwrap_or_default(), + hands_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .hands_bone_group, + ) + .unwrap_or_default(), + head_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .head_bone_group, + ) + .unwrap_or_default(), + headtop_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .headtop_bone_group, + ) + .unwrap_or_default(), + jaw_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .jaw_bone_group, + ) + .unwrap_or_default(), + lower_arm_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .lower_arm_bone_group, + ) + .unwrap_or_default(), + lower_leg_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .lower_leg_bone_group, + ) + .unwrap_or_default(), + nose_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .nose_bone_group, + ) + .unwrap_or_default(), + object_scaling: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .object_scaling, + ) + .unwrap_or_default(), + stomach_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .stomach_bone_group, + ) + .unwrap_or_default(), + torso_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .torso_bone_group, + ) + .unwrap_or_default(), + upper_arm_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .upper_arm_bone_group, + ) + .unwrap_or_default(), + upper_leg_bone_group: flags + .scales + .then_some( + self.data + .custom_skater + .custom_classic + .appearance + .upper_leg_bone_group, + ) + .unwrap_or_default(), + ..Default::default() + }, + }, + }, + story_skater: StorySkater { + tricks: flags + .trickset + .then_some(self.data.story_skater.tricks) + .unwrap_or_default(), + }, + }, + } + } +} + impl TryFrom<&Save> for Cas { type Error = Error; diff --git a/crates/cascade-thaw/src/core.rs b/crates/cascade-thaw/src/core.rs index a83a1c2..7525bb0 100644 --- a/crates/cascade-thaw/src/core.rs +++ b/crates/cascade-thaw/src/core.rs @@ -1,236 +1,29 @@ -use std::{ - io::{Read, Seek}, - path::PathBuf, -}; - -use cascade_core as core; +use std::path::PathBuf; use crate::{ - Error, - cas::{self, Cas}, - entry::{self, Entry}, + Error, Result, + cas::Cas, + entry::{Entry, find_entries}, save::Save, }; -pub struct Explorer { +pub struct Core { cwd: PathBuf, } -impl Explorer { +impl Core { pub fn new(cwd: PathBuf) -> Self { Self { cwd } } } -impl core::Explorer for Explorer { - fn list(&self) -> Result, Error> { - entry::find_entries(&self.cwd).map(|entries| entries.into_iter()) - } - - fn reader(&self, entry: &Entry) -> Result { - entry.reader() - } - - fn writer(&self, entry: &Entry) -> Result { - entry.writer() - } - - fn name(&self, entry: &Entry) -> String { - entry.filename.clone() - } - - fn rewrite_metadata(&self, entry: &Entry) -> Result<(), Error> { - entry.rewrite_metadata() - } -} - -pub struct Parser {} - -impl core::Parser for Parser { - fn read(&self, reader: &mut (impl Read + Seek)) -> Result { - Save::read(reader) - } - - fn write(&self, save: &Save, writer: &mut impl std::io::Write) -> Result<(), Error> { - save.write(writer) - } - - fn parse(&self, save: &Save) -> Result { - Cas::try_from(save) - } - - fn modify(&self, save: &mut Save, transform: &Cas) -> Result<(), Error> { - transform.modify(save) - } +impl cascade_core::Core for Core { + type Entry = Entry; + type Save = Save; + type Cas = Cas; + type Error = Error; - fn mask(&self, cas: Cas, flags: core::Flags) -> Cas { - Cas { - summary: flags.summary.then_some(cas.summary).unwrap_or_default(), - data: cas::Data { - custom_skater: cas::CustomSkater { - custom_classic: cas::CustomClassic { - info: cas::Info { - trick_mapping: flags - .trickset - .then_some(cas.data.custom_skater.custom_classic.info.trick_mapping) - .unwrap_or_default(), - specials: flags - .trickset - .then_some(cas.data.custom_skater.custom_classic.info.specials) - .unwrap_or_default(), - }, - appearance: cas::Appearance { - board_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .board_bone_group, - ) - .unwrap_or_default(), - feet_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .feet_bone_group, - ) - .unwrap_or_default(), - hands_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .hands_bone_group, - ) - .unwrap_or_default(), - head_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .head_bone_group, - ) - .unwrap_or_default(), - headtop_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .headtop_bone_group, - ) - .unwrap_or_default(), - jaw_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .jaw_bone_group, - ) - .unwrap_or_default(), - lower_arm_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .lower_arm_bone_group, - ) - .unwrap_or_default(), - lower_leg_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .lower_leg_bone_group, - ) - .unwrap_or_default(), - nose_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .nose_bone_group, - ) - .unwrap_or_default(), - object_scaling: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .object_scaling, - ) - .unwrap_or_default(), - stomach_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .stomach_bone_group, - ) - .unwrap_or_default(), - torso_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .torso_bone_group, - ) - .unwrap_or_default(), - upper_arm_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .upper_arm_bone_group, - ) - .unwrap_or_default(), - upper_leg_bone_group: flags - .scales - .then_some( - cas.data - .custom_skater - .custom_classic - .appearance - .upper_leg_bone_group, - ) - .unwrap_or_default(), - ..Default::default() - }, - }, - }, - story_skater: cas::StorySkater { - tricks: flags - .trickset - .then_some(cas.data.story_skater.tricks) - .unwrap_or_default(), - }, - }, - } + fn list_entries(&self) -> Result> { + find_entries(&self.cwd) } } diff --git a/crates/cascade-thaw/src/entry.rs b/crates/cascade-thaw/src/entry.rs index 4ecbe68..8971dcf 100644 --- a/crates/cascade-thaw/src/entry.rs +++ b/crates/cascade-thaw/src/entry.rs @@ -15,6 +15,43 @@ pub struct Entry { pub metadata: Option, } +impl cascade_core::Entry for Entry { + type Error = Error; + + fn reader(&self) -> Result { + let file = fs::File::open(&self.path)?; + Ok(BufReader::new(file)) + } + + fn writer(&self) -> std::result::Result { + let file = fs::File::create(&self.path)?; + Ok(BufWriter::new(file)) + } + + fn name(&self) -> String { + self.filename.clone() + } + + fn rewrite_metadata(&self) -> std::result::Result<(), Self::Error> { + if let Some(metadata) = &self.metadata { + let filepath = &self.path; + + // TODO: this should probably be configurable + let original_mod_time = filetime::FileTime::from_last_modification_time(metadata); + + // TODO: how tf do i format this + log::info!( + "setting file modification time for {:?} to {:?}", + filepath, + original_mod_time + ); + filetime::set_file_mtime(&filepath, original_mod_time)?; + } + + Ok(()) + } +} + impl Hash for Entry { fn hash(&self, state: &mut H) { self.path.hash(state); @@ -52,38 +89,9 @@ impl Entry { metadata, }) } - - pub fn reader(&self) -> Result { - let file = fs::File::open(&self.path)?; - Ok(BufReader::new(file)) - } - - pub fn writer(&self) -> Result { - let file = fs::File::create(&self.path)?; - Ok(BufWriter::new(file)) - } - - pub fn rewrite_metadata(&self) -> Result<()> { - if let Some(metadata) = &self.metadata { - let filepath = &self.path; - - // TODO: this should probably be configurable - let original_mod_time = filetime::FileTime::from_last_modification_time(metadata); - - // TODO: how tf do i format this - log::info!( - "setting file modification time for {:?} to {:?}", - filepath, - original_mod_time - ); - filetime::set_file_mtime(&filepath, original_mod_time)?; - } - - Ok(()) - } } -pub fn find_entries(dir: impl AsRef) -> Result> { +pub fn find_entries(dir: impl AsRef) -> Result> { let dir = PathBuf::from(dir.as_ref()); dir.is_dir() @@ -118,6 +126,5 @@ pub fn find_entries(dir: impl AsRef) -> Result> { } else { None } - }) - .collect()) + })) } diff --git a/crates/cascade-thaw/src/lib.rs b/crates/cascade-thaw/src/lib.rs index 052a51a..bbbe56d 100644 --- a/crates/cascade-thaw/src/lib.rs +++ b/crates/cascade-thaw/src/lib.rs @@ -1,11 +1,18 @@ -pub mod cas; +mod cas; mod chunk; -pub mod core; +mod core; +#[cfg(feature = "lut")] pub mod dump; -pub mod entry; +mod entry; mod error; mod id; +#[cfg(feature = "lut")] pub mod lut; -pub mod save; +mod save; +pub use core::Core; + +pub use cas::Cas; +pub use entry::Entry; pub use error::{Error, Result}; +pub use save::Save; diff --git a/crates/cascade-thaw/src/save.rs b/crates/cascade-thaw/src/save.rs index 52f2473..15f873d 100644 --- a/crates/cascade-thaw/src/save.rs +++ b/crates/cascade-thaw/src/save.rs @@ -17,35 +17,10 @@ pub struct Rethawed { pub chunks: Vec, } -#[derive(Debug)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub enum Save { - Thaw(save::Save), - Rethawed(Rethawed), -} - -impl Save { - pub fn read(reader: &mut (impl Read + Seek)) -> Result { - let magic = reader.read_u32::()?; - reader.seek(SeekFrom::Start(0))?; - - match magic { - // "RTHW" - 0x57485452 => Ok(Save::Rethawed(Rethawed::read(reader)?)), - _ => Ok(Save::Thaw(save::Save::read(reader)?)), - } - } +impl cascade_core::Save for Rethawed { + type Error = Error; - pub fn write(&self, writer: &mut impl Write) -> Result<()> { - match self { - Save::Thaw(save) => Ok(save.write(writer)?), - Save::Rethawed(save) => Ok(save.write(writer)?), - } - } -} - -impl Rethawed { - pub fn read(reader: &mut impl Read) -> Result { + fn read(reader: &mut (impl Read + Seek)) -> Result { let magic = reader.read_u32::()?; let version = reader.read_u32::()?; let chunk_count = reader.read_u32::()?; @@ -63,7 +38,7 @@ impl Rethawed { }) } - pub fn write(&self, writer: &mut impl Write) -> Result<()> { + fn write(&self, writer: &mut (impl Write + Seek)) -> Result<()> { writer.write_u32::(self.magic)?; writer.write_u32::(self.version)?; writer.write_u32::(self.chunk_count)?; @@ -74,7 +49,9 @@ impl Rethawed { Ok(()) } +} +impl Rethawed { // the following methods assume each type of chunk only exists once per save pub fn get_chunk(&self, magic: chunk::Magic) -> Option<&Chunk> { @@ -95,3 +72,32 @@ impl Rethawed { .ok_or_else(|| Error::ChunkNotFound(magic)) } } + +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum Save { + Thaw(save::Save), + Rethawed(Rethawed), +} + +impl cascade_core::Save for Save { + type Error = Error; + + fn read(reader: &mut (impl Read + Seek)) -> Result { + let magic = reader.read_u32::()?; + reader.seek(SeekFrom::Start(0))?; + + match magic { + // "RTHW" + 0x57485452 => Ok(Save::Rethawed(Rethawed::read(reader)?)), + _ => Ok(Save::Thaw(save::Save::read(reader)?)), + } + } + + fn write(&self, writer: &mut (impl Write + Seek)) -> Result<()> { + match self { + Save::Thaw(save) => Ok(save.write(writer)?), + Save::Rethawed(save) => Ok(save.write(writer)?), + } + } +} diff --git a/crates/cascade-thug2/Cargo.toml b/crates/cascade-thug2/Cargo.toml index 6f21b63..b04bc75 100644 --- a/crates/cascade-thug2/Cargo.toml +++ b/crates/cascade-thug2/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] cascade-core = { workspace = true } cascade-crc = { workspace = true } -cascade-lut = { workspace = true } +cascade-lut = { workspace = true, optional = true } cascade-qb = { workspace = true } cascade-save = { workspace = true } @@ -15,10 +15,10 @@ count-write = { workspace = true } encoding_rs = { workspace = true } filetime = { workspace = true } log = { workspace = true } +serde = { workspace = true, optional = true } rand = { workspace = true } thiserror = { workspace = true } -serde = { workspace = true, optional = true } - [features] serde = ["dep:serde", "cascade-qb/serde", "cascade-save/serde"] +lut = ["dep:cascade-lut"] diff --git a/crates/cascade-thug2/src/cas.rs b/crates/cascade-thug2/src/cas.rs index e28650c..e845a31 100644 --- a/crates/cascade-thug2/src/cas.rs +++ b/crates/cascade-thug2/src/cas.rs @@ -1,7 +1,6 @@ use cascade_qb as qb; -use cascade_save::{self as save}; -use crate::{Error, Result, id}; +use crate::{Error, Result, Save, id}; fn expect_symbol(parent: &Box, id: qb::Id) -> Result<&qb::Symbol> { Ok(parent.get(id).ok_or(Error::SymbolNotFound(id))?) @@ -73,12 +72,16 @@ pub struct Cas { pub data: Data, } -impl cascade_core::cas::Cas for Cas { +impl cascade_core::Cas for Cas { type Error = Error; - type Save = save::Save; + type Save = Save; - fn parse(save: &save::Save) -> std::result::Result { - Ok(Cas::try_from(save)?) + fn parse(save: &Save) -> Result { + Self::try_from(save) + } + + fn modify(&self, save: &mut Save) -> Result<()> { + Ok(self.modify(save)?) } fn mask(self, flags: cascade_core::Flags) -> Self { @@ -207,16 +210,12 @@ impl cascade_core::cas::Cas for Cas { }, } } - - fn modify(&self, save: &mut save::Save) -> std::result::Result<(), Self::Error> { - Ok(self.modify(save)?) - } } -impl TryFrom<&save::Save> for Cas { +impl TryFrom<&Save> for Cas { type Error = Error; - fn try_from(save: &save::Save) -> Result { + fn try_from(save: &Save) -> Result { Ok(Self { summary: Summary::try_from(&save.summary)?, data: Data::try_from(&save.data)?, @@ -225,7 +224,7 @@ impl TryFrom<&save::Save> for Cas { } impl Cas { - pub fn modify(&self, save: &mut save::Save) -> Result<()> { + pub fn modify(&self, save: &mut Save) -> Result<()> { self.summary.modify(&mut save.summary); self.data.modify(&mut save.data)?; Ok(()) diff --git a/crates/cascade-thug2/src/core.rs b/crates/cascade-thug2/src/core.rs index c277f22..c3f7649 100644 --- a/crates/cascade-thug2/src/core.rs +++ b/crates/cascade-thug2/src/core.rs @@ -1,12 +1,6 @@ use std::path::PathBuf; -use cascade_save::Save; - -use crate::{ - Error, Result, - cas::Cas, - entry::{Entry, find_entries}, -}; +use crate::{Cas, Entry, Error, Result, Save, entry::find_entries}; pub struct Core { cwd: PathBuf, diff --git a/crates/cascade-thug2/src/lib.rs b/crates/cascade-thug2/src/lib.rs index 55410d4..2f08136 100644 --- a/crates/cascade-thug2/src/lib.rs +++ b/crates/cascade-thug2/src/lib.rs @@ -1,11 +1,16 @@ -pub mod core; -pub mod cas; -pub mod entry; -pub mod error; -pub mod id; +mod cas; +mod core; +mod entry; +mod error; +mod id; +#[cfg(feature = "lut")] pub mod lut; -pub mod random; +mod save; +// pub mod random; + +pub use core::Core; pub use cas::Cas; pub use entry::Entry; pub use error::{Error, Result}; +pub use save::Save; diff --git a/crates/cascade-thug2/src/save.rs b/crates/cascade-thug2/src/save.rs new file mode 100644 index 0000000..a16974c --- /dev/null +++ b/crates/cascade-thug2/src/save.rs @@ -0,0 +1,31 @@ +use std::io::{Read, Seek, Write}; + +use crate::{Error, Result}; + +pub struct Save(cascade_save::Save); + +impl cascade_core::Save for Save { + type Error = Error; + + fn read(reader: &mut (impl Read + Seek)) -> Result { + Ok(Self(cascade_save::Save::read(reader)?)) + } + + fn write(&self, writer: &mut (impl Write + Seek)) -> Result<()> { + Ok(self.0.write(writer)?) + } +} + +impl std::ops::Deref for Save { + type Target = cascade_save::Save; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::ops::DerefMut for Save { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5d56faf..809fc0a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,3 @@ [toolchain] channel = "nightly" +targets = ["x86_64-pc-windows-gnu"] From 1e66af0750e076918c3fb9a87aba8d817daa9ede Mon Sep 17 00:00:00 2001 From: ellie <149747415+1borgy@users.noreply.github.com> Date: Tue, 28 Oct 2025 18:37:22 -0400 Subject: [PATCH 09/23] fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! update --- Cargo.toml | 2 +- crates/cascade-app/Cargo.toml | 3 +- crates/cascade-app/src/app.rs | 217 ++----- crates/cascade-app/src/dashboard.rs | 748 ++-------------------- crates/cascade-app/src/dashboard_old.rs | 733 +++++++++++++++++++++ crates/cascade-app/src/error.rs | 26 + crates/cascade-app/src/fonts.rs | 17 - crates/cascade-app/src/main.rs | 45 +- crates/cascade-app/src/paths.rs | 34 + crates/cascade-app/src/state.rs | 134 ++++ crates/cascade-app/src/tasks.rs | 37 +- crates/cascade-app/src/theme/mod.rs | 2 +- crates/cascade-app/src/theme/pick_list.rs | 40 ++ crates/cascade-cli/src/main.rs | 2 +- crates/cascade-core/Cargo.toml | 4 + crates/cascade-core/src/cas.rs | 2 + crates/cascade-core/src/lib.rs | 2 +- crates/cascade-thaw/src/core.rs | 2 +- crates/cascade-thug2/src/core.rs | 2 +- 19 files changed, 1126 insertions(+), 926 deletions(-) create mode 100644 crates/cascade-app/src/dashboard_old.rs create mode 100644 crates/cascade-app/src/error.rs create mode 100644 crates/cascade-app/src/state.rs create mode 100644 crates/cascade-app/src/theme/pick_list.rs diff --git a/Cargo.toml b/Cargo.toml index 977b1b8..e1ff60c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ env_logger = "0.11.6" fern = { version = "0.6.2", features = ["colored"] } filetime = "0.2.21" image = "0.24.0" -indexmap = "2.7.0" +indexmap = { version = "2.7.0", features = ["serde"] } log = "0.4.20" rand = "0.9.1" rfd = "0.12.1" diff --git a/crates/cascade-app/Cargo.toml b/crates/cascade-app/Cargo.toml index 0872e65..5a5fb84 100644 --- a/crates/cascade-app/Cargo.toml +++ b/crates/cascade-app/Cargo.toml @@ -8,7 +8,7 @@ name = "cascade" path = "src/main.rs" [dependencies] -cascade-core = { workspace = true } +cascade-core = { workspace = true, features = ["serde"] } cascade-qb = { workspace = true } cascade-save = { workspace = true } cascade-thug2 = { workspace = true } @@ -27,6 +27,7 @@ thiserror = { workspace = true } time = { workspace = true } tokio = { workspace = true } toml = { workspace = true } +color-eyre.workspace = true [dependencies.iced] version = "0.13.1" diff --git a/crates/cascade-app/src/app.rs b/crates/cascade-app/src/app.rs index 7fa55bf..0623bd2 100644 --- a/crates/cascade-app/src/app.rs +++ b/crates/cascade-app/src/app.rs @@ -3,85 +3,62 @@ use std::path::PathBuf; use iced::{ event, keyboard::{self, key}, - widget::container, + widget::{container, pick_list}, Event, Length, Padding, Subscription, Task, }; +use serde::Serialize; use crate::{ - config::{Config, Format, Selections}, - dashboard, paths, tasks, Element, Theme, + paths::Paths, + state::{Game, State}, + tasks, Element, Result, Theme, }; #[derive(Debug, Clone)] pub enum Message { - Dashboard(dashboard::Message), - - WroteConfig(Result), - WroteSelections(Result), - + GameSelected(Game), EventOccurred(Event), + + WroteFile(Result), } pub struct Cascade { - config_path: PathBuf, - selections_path: PathBuf, - - config: Config, + paths: Paths, theme: Theme, - - dashboard: dashboard::Dashboard, + state: State, } impl Cascade { - pub fn new(flags: (PathBuf, Config, Selections, Theme)) -> (Self, Task) { - let (cascade_dir, config, selections, theme) = flags; - let backup_dir = paths::backup_dir(&cascade_dir); - - let (dashboard, dashboard_command) = dashboard::Dashboard::new( - config.source_path.clone(), - config.saves_dir.clone(), - backup_dir, - config.default_selection, - selections, - config.trickset, - config.scales, - ); - - let config_path = paths::config(&cascade_dir); - let selections_path = paths::selections(&cascade_dir); - + pub fn new(paths: Paths, theme: Theme, state: State) -> (Self, Task) { ( Cascade { - config_path, - selections_path, + paths, theme, - config, - dashboard, + state, }, - dashboard_command.map(Message::Dashboard), + Task::none(), ) } - fn write_config(&self) -> Task { - Task::perform( - tasks::write(self.config.clone(), self.config_path.clone(), Format::Toml), - Message::WroteConfig, - ) + fn write_state(&self, obj: impl Serialize + Send + 'static, to: PathBuf) -> Task { + Task::perform(tasks::write_ron(obj, to), Message::WroteFile) } - fn write_selections(&self, selections: Selections) -> Task { - Task::perform( - tasks::write( - selections.clone(), - self.selections_path.clone(), - Format::Ron, - ), - Message::WroteSelections, - ) + fn write_app_state(&self) -> Task { + self.write_state(self.state.app.clone(), self.paths.app.clone()) + } + + fn write_game_state(&self) -> Task { + match self.state.app.game { + Game::Thug2 => { + self.write_state(self.state.game.thug2.clone(), self.paths.thug2.clone()) + } + Game::Thaw => self.write_state(self.state.game.thaw.clone(), self.paths.thaw.clone()), + } } pub fn scale_factor(&self) -> f64 { - self.config.scale_factor + self.state.app.scale_factor } pub fn theme(&self) -> Theme { @@ -90,111 +67,57 @@ impl Cascade { pub fn update(&mut self, message: Message) -> Task { match message { - Message::Dashboard(message) => { - let (command, event) = self.dashboard.update(message); - - Task::batch(vec![ - command.map(Message::Dashboard), - match event { - Some(dashboard::Event::SetSavesDir(saves_dir)) => { - self.config.saves_dir = Some(saves_dir.clone()); - - Task::batch(vec![ - self.dashboard - .set_saves_dir(saves_dir) - .map(Message::Dashboard), - self.write_config(), - ]) - } - Some(dashboard::Event::SetSelections(selections)) => { - self.write_selections(selections) - } - Some(dashboard::Event::SetDefaultSelection( - default_selection, - selections, - )) => { - self.config.default_selection = default_selection; - - Task::batch(vec![ - self.write_config(), - self.write_selections(selections), - ]) - } - - Some(dashboard::Event::SetSourcePath(path)) => { - self.config.source_path = Some(path); - self.write_config() - } - - Some(dashboard::Event::SetTrickset(value)) => { - self.config.trickset = value; - self.write_config() - } - - Some(dashboard::Event::SetScales(value)) => { - self.config.scales = value; - self.write_config() - } - - None => Task::none(), - }, - ]) - } - Message::WroteConfig(Ok(_)) | Message::WroteSelections(Ok(_)) => Task::none(), - Message::WroteConfig(Err(err)) => { - log::info!("error writing config: {:?}", err); + Message::GameSelected(game) => { + self.state.app.game = game; Task::none() } - Message::WroteSelections(Err(err)) => { - log::info!("error writing selections: {:?}", err); + // Ctrl+= + Message::EventOccurred(Event::Keyboard(keyboard::Event::KeyPressed { + physical_key: key::Physical::Code(key::Code::Equal), + modifiers: keyboard::Modifiers::CTRL, + .. + })) => { + if self.state.app.scale_factor < 5. { + self.state.app.scale_factor += 0.1; + self.write_app_state() + } else { + Task::none() + } + } + // Ctrl+- + Message::EventOccurred(Event::Keyboard(keyboard::Event::KeyPressed { + physical_key: key::Physical::Code(key::Code::Minus), + modifiers: keyboard::Modifiers::CTRL, + .. + })) => { + if self.state.app.scale_factor > 0.2 { + self.state.app.scale_factor -= 0.1; + self.write_app_state() + } else { + Task::none() + } + } + Message::EventOccurred(_) => Task::none(), + Message::WroteFile(Ok(_)) => Task::none(), + Message::WroteFile(Err(err)) => { + log::error!("error writing file: {}", err); Task::none() } - Message::EventOccurred(event) => match event { - Event::Keyboard(event) => match event { - keyboard::Event::KeyPressed { - physical_key: key::Physical::Code(key::Code::Equal), - modifiers: keyboard::Modifiers::CTRL, - .. - } => { - if self.config.scale_factor < 5. { - self.config.scale_factor += 0.1; - self.write_config() - } else { - Task::none() - } - } - keyboard::Event::KeyPressed { - physical_key: key::Physical::Code(key::Code::Minus), - modifiers: keyboard::Modifiers::CTRL, - .. - } => { - if self.config.scale_factor > 0.2 { - self.config.scale_factor -= 0.1; - self.write_config() - } else { - Task::none() - } - } - _ => Task::none(), - }, - _ => Task::none(), - }, } } - pub fn view(&self) -> Element { - let content: Element = container(self.dashboard.view().map(Message::Dashboard)) - .width(Length::Fill) - .height(Length::Fill) - .padding(Padding::new(20.)) - .into(); + pub fn view(&self) -> Element<'_, Message> { + let content: Element = container(pick_list( + Game::ALL, + Some(self.state.app.game), + Message::GameSelected, + )) + .width(Length::Fill) + .height(Length::Fill) + .padding(Padding::new(20.)) + .into(); content - - // match self.debug { - // true => content.explain(iced::Color::WHITE), - // false => content, - // } } pub fn subscription(&self) -> Subscription { diff --git a/crates/cascade-app/src/dashboard.rs b/crates/cascade-app/src/dashboard.rs index 34840ca..d19c1ca 100644 --- a/crates/cascade-app/src/dashboard.rs +++ b/crates/cascade-app/src/dashboard.rs @@ -1,32 +1,19 @@ use std::{ - collections::HashMap, + borrow::Cow, fmt::Debug, - io, + fs, io, path::{Path, PathBuf}, result, - sync::Arc, }; -use cascade_core as core; use cascade_save as save; -use cascade_thaw as thaw; use cascade_thug2 as thug2; -use iced::{ - alignment::Vertical, - font::Weight, - widget::{button, checkbox, combo_box, container, scrollable, text, tooltip}, - Font, Length, Task, -}; +use iced::Task; use indexmap::IndexMap; -use rfd::AsyncFileDialog; -use tokio::fs; +use ron::de::SpannedError; +use serde::{Deserialize, Serialize}; -use crate::{ - config::Selections, - fonts, paths, tasks, theme, - widget::{self, heading}, - Column, Element, Row, -}; +use crate::{paths, tasks, Element, Row}; #[derive(thiserror::Error, Debug, Clone)] pub enum Error { @@ -50,6 +37,9 @@ pub enum Error { #[error("no saves dir set")] NoSavesDir, + + #[error("ron deserialization error: {0}")] + Ron(#[from] SpannedError), } impl From for Error { @@ -61,701 +51,73 @@ impl From for Error { pub type Result = result::Result; #[derive(Debug, Clone)] -enum Status { - // i.e. last known status of processing an entry - InProgress, - Success, - #[expect(dead_code)] - Error(Error), -} - -#[derive(Debug, Default, Clone, Copy)] -pub struct Components { - trickset: bool, - scales: bool, -} - -#[derive(Debug, Clone)] -pub enum Message { - LoadedCandidates(Result>), - LoadedSource(Result), - - PickSource, - SourcePicked(Option), - - PickSavesDir, - SavesDirChanged(PathBuf), - ClosedSavesDirDialog, - - ToggleSelectAll, - ToggleSelection(thug2::Entry), - ToggleTricksetComponent(bool), - ToggleScalesComponent(bool), - - Start, - PreProcessDone(Result<(Arc, PathBuf)>), - EntryProcessed(thug2::Entry, Result<()>), - - ComboBoxSelected(String), -} - -#[derive(Debug, Clone)] -pub enum Event { - SetSavesDir(PathBuf), - SetSourcePath(PathBuf), - SetDefaultSelection(bool, Selections), - SetSelections(Selections), - SetTrickset(bool), - SetScales(bool), -} - -pub struct Dashboard -where - Entry: Sized, - Error: Sized, -{ - backup_dir: PathBuf, - saves_dir: Option, +pub enum Message {} + +#[derive(Debug, Deserialize)] +struct State<'a> { + from: Option, + to_dir: Option, + #[serde(borrow)] + selections: IndexMap, bool>, + flags: cascade_core::Flags, default_selection: bool, - enabled: bool, - - source_entry: Option, - explorer: Box>, - - candidates: IndexMap, - components: Components, - queue: IndexMap, - - warning_message: Option, - - combo_box_state: combo_box::State, - combo_box_selection: Option, } -impl Dashboard { - pub fn new( - source_path: Option, - saves_dir: Option, - backup_dir: PathBuf, - default_selection: bool, - selections: Selections, - trickset: bool, - scales: bool, - ) -> (Self, Task) { - let source_entry = source_path - .map(|path| thug2::Entry::at_path(path).ok()) - .flatten(); - - let tasks = Task::batch(vec![ - match &source_entry { - Some(entry) => Task::perform(load_source(entry.clone()), Message::LoadedSource), - None => Task::none(), - }, - Task::perform( - load_candidates(saves_dir.clone(), selections, default_selection), - Message::LoadedCandidates, - ), - ]); - - let dashboard = Dashboard { - enabled: true, - backup_dir, - source_entry, - source: None, - saves_dir, - candidates: IndexMap::new(), - queue: IndexMap::new(), - default_selection, - components: Components { scales, trickset }, - warning_message: None, - combo_box_state: combo_box::State::new(Vec::new()), - combo_box_selection: None, - }; - - (dashboard, tasks) - } - - fn selections(&self) -> Selections { - self.candidates - .iter() - .map(|(entry, selected)| (entry.name.clone(), *selected)) - .collect::>() - .into() - } - - pub fn set_saves_dir(&mut self, saves_dir: impl AsRef) -> Task { - self.saves_dir = Some(saves_dir.as_ref().into()); - - Task::perform( - load_candidates( - self.saves_dir.clone(), - self.selections(), - self.default_selection, - ), - Message::LoadedCandidates, - ) - } - - fn notify(&mut self, msg: impl Into) { - let msg = msg.into(); - log::warn!("{}", msg); - self.warning_message = Some(msg); - } - - pub fn update(&mut self, message: Message) -> (Task, Option) { - match message { - Message::PickSavesDir => ( - Task::perform(pick_saves_dir(), |dir| { - dir.map(|dir| Message::SavesDirChanged(dir)) - .unwrap_or(Message::ClosedSavesDirDialog) - }), - None, - ), - Message::ClosedSavesDirDialog => (Task::none(), None), - Message::SavesDirChanged(saves_dir) => { - self.saves_dir = Some(saves_dir.clone()); - (Task::none(), Some(Event::SetSavesDir(saves_dir.clone()))) - } - Message::LoadedSource(Ok(content)) => { - self.source = Some(content); - (Task::none(), None) - } - Message::LoadedSource(Err(err)) => { - self.notify(format!("error loading source: {}", err)); - (Task::none(), None) - } - Message::LoadedCandidates(Ok(entries)) => { - self.candidates = entries; - self.combo_box_state = combo_box::State::new( - self.candidates - .iter() - .map(|(entry, _)| entry.name.clone()) - .collect(), - ); - (Task::none(), None) - } - Message::LoadedCandidates(Err(err)) => { - self.notify(format!("error loading selections: {}", err)); - (Task::none(), None) - } - Message::PickSource => (Task::perform(pick_source(), Message::SourcePicked), None), - Message::SourcePicked(Some(path)) => match thug2::Entry::at_path(path.clone()) { - Ok(entry) => { - self.source_entry = Some(entry.clone()); - ( - Task::perform(load_source(entry), Message::LoadedSource), - Some(Event::SetSourcePath(path)), - ) - } - Err(err) => { - self.notify(format!("error picking source: {err}")); - (Task::none(), None) - } - }, - Message::SourcePicked(None) => (Task::none(), None), - Message::ToggleSelectAll => { - self.default_selection = !self.default_selection; - - for selected in self.candidates.values_mut() { - *selected = self.default_selection; - } - - ( - Task::none(), - Some(Event::SetDefaultSelection( - self.default_selection, - self.selections(), - )), - ) - } - Message::ToggleSelection(entry) => { - if let Some(selected) = self.candidates.get_mut(&entry) { - *selected = !*selected; - } - (Task::none(), Some(Event::SetSelections(self.selections()))) - } - Message::ToggleTricksetComponent(selected) => { - self.components.trickset = selected; - (Task::none(), Some(Event::SetTrickset(selected))) - } - Message::ToggleScalesComponent(selected) => { - self.components.scales = selected; - (Task::none(), Some(Event::SetScales(selected))) - } - Message::Start => match &self.source { - Some(source) => { - if self.candidates.values().any(|selected| *selected) { - self.enabled = false; - - let datetime = time::OffsetDateTime::now_local() - .unwrap_or(time::OffsetDateTime::now_utc()); - - let backup_dir = self.backup_dir.join(format!( - "{:04}-{:02}-{:02}T{:02}-{:02}-{:02}", - datetime.year(), - u8::from(datetime.month()), - datetime.day(), - datetime.hour(), - datetime.minute(), - datetime.second() - )); - - ( - Task::perform( - pre_process(backup_dir, source.clone(), self.components), - Message::PreProcessDone, - ), - None, - ) - } else { - (Task::none(), None) - } - } - None => (Task::none(), None), - }, - Message::PreProcessDone(Ok((transform, backup_dir))) => { - let selected_entries = self - .candidates - .iter() - .filter_map(|(entry, selected)| selected.then_some(entry.clone())) - .collect::>(); - - self.queue = selected_entries - .iter() - .map(|entry| (entry.clone(), Status::InProgress)) - .collect::>(); - - ( - Task::batch( - selected_entries - .iter() - .map(|entry| { - let entry = entry.clone(); - Task::perform( - process_entry( - entry.clone(), - backup_dir.clone(), - Arc::clone(&transform), - ), - move |result| Message::EntryProcessed(entry.clone(), result), - ) - }) - .collect::>(), - ), - None, - ) - } - Message::PreProcessDone(Err(err)) => { - self.enabled = true; - self.notify(format!("error during pre-process: {}", err)); - - (Task::none(), None) - } - Message::EntryProcessed(entry, result) => { - let new_status = match result { - Ok(_) => Status::Success, - Err(err) => { - self.notify(format!("error for entry {}: {:?}", entry.name, err)); - Status::Error(err) - } - }; - - self.queue.entry(entry).and_modify(|status| { - *status = new_status; - }); - - if self.queue.values().all(|entry| match entry { - Status::InProgress => false, - Status::Success | Status::Error(_) => true, - }) { - self.enabled = true; - } - - (Task::none(), None) - } - Message::ComboBoxSelected(value) => { - self.combo_box_selection = Some(value); - (Task::none(), None) - } - } - } - - fn view_source_info(&self) -> Element { - if let Some(entry) = &self.source_entry { - tooltip( - container(text(entry.filename())) - .style(theme::container::monobox) - .padding(10) - .align_y(Vertical::Center), - container(text(entry.filepath().display().to_string())) - .padding(10) - .align_y(Vertical::Center), - tooltip::Position::Bottom, - ) - .gap(10) - .style(theme::container::bordered) - .into() - } else { - container(text("(none)")) - .style(theme::container::monobox) - .padding(10) - .align_y(Vertical::Center) - .into() +impl Default for State<'_> { + fn default() -> Self { + Self { + from: Default::default(), + to_dir: Default::default(), + selections: Default::default(), + flags: Default::default(), + default_selection: Default::default(), } } - - fn view_saves_dir(&self) -> Element { - // :( - if let Some(dir) = &self.saves_dir { - if let Some(name) = dir.file_name() { - if let Some(name) = name.to_str() { - return tooltip( - container(text(name)) - .style(theme::container::monobox) - .padding(10) - .align_y(Vertical::Center), - container(text(dir.display().to_string())) - .padding(10) - .align_y(Vertical::Center), - tooltip::Position::Bottom, - ) - .gap(10) - .style(theme::container::bordered) - .into(); - } - } - } - container(text("(none)")) - .style(theme::container::monobox) - .padding(10) - .align_y(Vertical::Center) - .into() - } - - fn view_entries(&self) -> Element { - self.candidates - .iter() - .fold(Column::new().spacing(2), |column, (entry, selected)| { - column.push(widget::entry::selectable( - &entry.name, - *selected, - self.enabled - .then_some(Message::ToggleSelection(entry.clone())), - )) - }) - .into() - } - - fn view_queue(&self) -> Element { - scrollable( - self.candidates - .iter() - .filter(|(_, selected)| **selected) - .fold(Column::new().spacing(2), |column, (entry, _)| { - let style = match self.queue.get(entry) { - Some(Status::InProgress) => theme::button::entry_warning, - Some(Status::Success) => theme::button::entry_success, - Some(Status::Error(_)) => theme::button::entry_danger, - None => theme::button::entry_queued, - }; - column.push( - button(text(entry.name.clone())) - .style(style) - .on_press_maybe( - self.enabled - .then_some(Message::ToggleSelection(entry.clone())), - ) - .width(Length::Fill), - ) - }), - ) - .into() - } - - fn view_left(&self) -> Column { - Column::new() - .spacing(10) - .push( - Row::new() - .spacing(10) - .align_y(Vertical::Center) - .height(Length::Shrink) - .push( - button(text("\u{E802}").font(fonts::ICONS_FONT)) - .on_press_maybe(self.enabled.then_some(Message::PickSource)), - ) - .push(heading("from")) - // .push(self.view_source_info()) - .push( - combo_box( - &self.combo_box_state, - "select a cas...", - self.combo_box_selection.as_ref(), - Message::ComboBoxSelected, - ) - .input_style(match &self.combo_box_selection { - Some(_) => theme::text_input::primary, - None => theme::text_input::error, - }) - .padding(10), - ), - ) - .push( - checkbox("trickset", self.components.trickset) - .on_toggle_maybe(self.enabled.then_some(Message::ToggleTricksetComponent)), - ) - .push( - checkbox("scales", self.components.scales) - .on_toggle_maybe(self.enabled.then_some(Message::ToggleScalesComponent)), - ) - .push(Row::new().height(Length::Fill).align_y(Vertical::Bottom)) - } - - fn view_center(&self) -> Column { - Column::new() - .spacing(10) - .push( - Row::new() - .spacing(10) - .align_y(Vertical::Center) - .height(Length::Shrink) - .push( - button(text("\u{E802}").font(fonts::ICONS_FONT)) - .on_press_maybe(self.enabled.then_some(Message::PickSavesDir)), - ) - .push(heading("to")) - .push(self.view_saves_dir()), - ) - .push( - button( - text(match self.default_selection { - true => "deselect all", - false => "select all", - }) - .font(Font { - weight: Weight::Semibold, - ..Default::default() - }), - ) - .style(theme::button::secondary) - .on_press_maybe(self.enabled.then_some(Message::ToggleSelectAll)) - .width(Length::Fill), - ) - .push(scrollable(self.view_entries())) - } - - fn view_right(&self) -> Column { - Column::new() - .spacing(10) - .push( - Row::new() - .spacing(10) - .align_y(Vertical::Center) - .push( - button(text("\u{E803}").font(fonts::ICONS_FONT)) - .on_press_maybe(self.enabled.then_some(Message::Start)), - ) - .push(heading("queue")), - ) - .push(self.view_queue()) - } - - pub fn view(&self) -> Element { - Row::new() - .push(self.view_left().width(Length::Fill)) - .push(self.view_center().width(Length::Fill)) - .push(self.view_right().width(Length::Fill)) - .width(Length::Fill) - .spacing(10) - .into() - } } -async fn pick_source() -> Option { - Some( - AsyncFileDialog::new() - .add_filter("CAS file (.SKA)", &["SKA"]) - .pick_file() - .await? - .path() - .into(), - ) -} +impl<'a> State<'a> { + fn read(path: &'a Path) -> Result { + let file = fs::File::open(&path)?; -async fn _load_source(entry: thug2::Entry) -> Result { - let save = save::Save::read(&mut entry.reader()?)?; - let cas = thug2::Cas::try_from(&save)?; + log::info!("reading state from {:?}", path); - Ok(cas) -} + let contents = io::read_to_string(file)?; -async fn load_source(entry: thug2::Entry) -> Result { - let source = tokio::spawn(async move { _load_source(entry).await }) - .await - .map_err(|_| Error::Task)?; + let config = ron::from_str(contents.as_str())?; - source + Ok(config) + } } -async fn load_candidates( - saves_dir: Option>, - selections: Selections, - default_selection: bool, -) -> Result> { - let saves_dir = saves_dir.ok_or(Error::NoSavesDir)?; - let entries = thug2::entry::find_entries(saves_dir)?; - - log::info!("found {} saves", entries.len()); - - let candidates = entries - .into_iter() - .map(|entry| { - ( - entry.clone(), - *selections.get(&entry.name).unwrap_or(&default_selection), - ) - }) - .collect::>(); - - Ok(candidates) +struct StateHandle<'a> { + state: State<'a>, + path: &'a Path, } -fn make_transform(source: &thug2::cas::Cas, components: Components) -> thug2::cas::Cas { - let info = &source.data.custom_skater.custom.info; - let appearance = &source.data.custom_skater.custom.appearance; - - thug2::cas::Cas { - summary: source.summary.clone(), - data: thug2::cas::Data { - custom_skater: thug2::cas::CustomSkater { - custom: thug2::cas::Custom { - info: thug2::cas::Info { - trick_mapping: components - .trickset - .then_some(info.trick_mapping.clone()) - .unwrap_or_default(), - specials: components - .trickset - .then_some(info.specials.clone()) - .unwrap_or_default(), - }, - appearance: thug2::cas::Appearance { - board_bone_group: components - .scales - .then_some(appearance.board_bone_group.clone()) - .unwrap_or_default(), - feet_bone_group: components - .scales - .then_some(appearance.feet_bone_group.clone()) - .unwrap_or_default(), - hands_bone_group: components - .scales - .then_some(appearance.hands_bone_group.clone()) - .unwrap_or_default(), - head_bone_group: components - .scales - .then_some(appearance.head_bone_group.clone()) - .unwrap_or_default(), - headtop_bone_group: components - .scales - .then_some(appearance.headtop_bone_group.clone()) - .unwrap_or_default(), - jaw_bone_group: components - .scales - .then_some(appearance.jaw_bone_group.clone()) - .unwrap_or_default(), - lower_arm_bone_group: components - .scales - .then_some(appearance.lower_arm_bone_group.clone()) - .unwrap_or_default(), - lower_leg_bone_group: components - .scales - .then_some(appearance.lower_leg_bone_group.clone()) - .unwrap_or_default(), - nose_bone_group: components - .scales - .then_some(appearance.nose_bone_group.clone()) - .unwrap_or_default(), - object_scaling: components - .scales - .then_some(appearance.object_scaling.clone()) - .unwrap_or_default(), - stomach_bone_group: components - .scales - .then_some(appearance.stomach_bone_group.clone()) - .unwrap_or_default(), - torso_bone_group: components - .scales - .then_some(appearance.torso_bone_group.clone()) - .unwrap_or_default(), - upper_arm_bone_group: components - .scales - .then_some(appearance.upper_arm_bone_group.clone()) - .unwrap_or_default(), - upper_leg_bone_group: components - .scales - .then_some(appearance.upper_leg_bone_group.clone()) - .unwrap_or_default(), - ..Default::default() - }, - }, - }, - story_skater: thug2::cas::StorySkater { - tricks: components - .trickset - .then_some(source.data.story_skater.tricks.clone()) - .unwrap_or_default(), - }, - }, +impl<'a> StateHandle<'a> { + fn load(path: impl AsRef) -> Result { + let path = path.as_ref(); } } -async fn pre_process>( - backup_dir: P, - source: thug2::Cas, - components: Components, -) -> Result<(Arc, PathBuf)> { - let backup_dir = backup_dir.as_ref(); - fs::create_dir_all(backup_dir).await?; - let transform = Arc::new(make_transform(&source, components)); - - // tasks::write( - // Arc::clone(&transform), - // backup_dir.join("transform.ron"), - // Format::Ron, - // ) - // .await?; - - Ok((Arc::clone(&transform), PathBuf::from(backup_dir))) +#[derive(Debug)] +struct States<'a> { + thug2: State<'a>, + thaw: State<'a>, } -async fn process_entry>( - entry: thug2::Entry, - backup_dir: P, - transform: Arc, -) -> Result<()> { - let backup_dir = backup_dir.as_ref(); - - let backup_entry = entry.with_dir(backup_dir); - let backup_filepath = backup_entry.filepath(); +pub struct Dashboard {} - let filepath = entry.filepath(); - - log::info!("backing up {:?} to {:?}", filepath, backup_filepath); - fs::copy(&filepath, &backup_filepath).await?; - - let mut save = save::Save::read(&mut entry.reader()?)?; - - transform.modify(&mut save)?; - save.write(&mut entry.writer()?)?; - - log::info!("overwrote save at {:?}", filepath); - - entry.rewrite_metadata()?; +impl Dashboard { + pub fn new() -> Self { + Dashboard {} + } - Ok(()) -} + pub fn update(&mut self, message: Message) -> Task { + match message {} + } -async fn pick_saves_dir() -> Option { - Some(AsyncFileDialog::new().pick_folder().await?.path().into()) + pub fn view(&self) -> Element<'_, Message> { + Row::new().into() + } } diff --git a/crates/cascade-app/src/dashboard_old.rs b/crates/cascade-app/src/dashboard_old.rs new file mode 100644 index 0000000..02460f6 --- /dev/null +++ b/crates/cascade-app/src/dashboard_old.rs @@ -0,0 +1,733 @@ +use std::{ + collections::HashMap, + fmt::Debug, + io, + path::{Path, PathBuf}, + result, + sync::Arc, +}; + +use cascade_save as save; +use cascade_thugpro as thugpro; +use iced::{ + alignment::Vertical, + font::Weight, + widget::{button, checkbox, container, scrollable, text, tooltip}, + Font, Length, Task, +}; +use indexmap::IndexMap; +use rfd::AsyncFileDialog; +use tokio::fs; + +use crate::{ + config::Selections, + fonts, paths, tasks, theme, + widget::{self, heading}, + Column, Element, Row, +}; + +#[derive(thiserror::Error, Debug, Clone)] +pub enum Error { + #[error("io error: {0}")] + Io(io::ErrorKind), + + #[error("paths error: {0}")] + Path(#[from] paths::Error), + + #[error("tasks error: {0}")] + Tasks(#[from] tasks::Error), + + #[error("thug pro error: {0}")] + ThugPro(#[from] thugpro::Error), + + #[error("save error: {0}")] + Save(#[from] save::Error), + + #[error("error spawning task")] + Task, + + #[error("no saves dir set")] + NoSavesDir, +} + +impl From for Error { + fn from(value: io::Error) -> Self { + Self::Io(value.kind()) + } +} + +pub type Result = result::Result; + +#[derive(Debug, Clone)] +enum Status { + // i.e. last known status of processing an entry + InProgress, + Success, + #[expect(dead_code)] + Error(Error), +} + +#[derive(Debug, Default, Clone, Copy)] +pub struct Components { + trickset: bool, + scales: bool, +} + +#[derive(Debug, Clone)] +pub enum Message { + LoadedCandidates(Result>), + LoadedSource(Result), + + PickSource, + SourcePicked(Option), + + PickSavesDir, + SavesDirChanged(PathBuf), + ClosedSavesDirDialog, + + ToggleSelectAll, + ToggleSelection(thugpro::Entry), + ToggleTricksetComponent(bool), + ToggleScalesComponent(bool), + + Start, + PreProcessDone(Result<(Arc, PathBuf)>), + EntryProcessed(thugpro::Entry, Result<()>), +} + +#[derive(Debug, Clone)] +pub enum Event { + SetSavesDir(PathBuf), + SetSourcePath(PathBuf), + SetDefaultSelection(bool, Selections), + SetSelections(Selections), + SetTrickset(bool), + SetScales(bool), +} + +pub struct Dashboard { + backup_dir: PathBuf, + saves_dir: Option, + default_selection: bool, + enabled: bool, + + source_entry: Option, + source: Option, + + candidates: IndexMap, + components: Components, + queue: IndexMap, + + warning_message: Option, +} + +impl Dashboard { + pub fn new( + source_path: Option, + saves_dir: Option, + backup_dir: PathBuf, + default_selection: bool, + selections: Selections, + trickset: bool, + scales: bool, + ) -> (Self, Task) { + let source_entry = source_path + .map(|path| thugpro::Entry::at_path(path).ok()) + .flatten(); + + let tasks = Task::batch(vec![ + match &source_entry { + Some(entry) => Task::perform(load_source(entry.clone()), Message::LoadedSource), + None => Task::none(), + }, + Task::perform( + load_candidates(saves_dir.clone(), selections, default_selection), + Message::LoadedCandidates, + ), + ]); + + let dashboard = Dashboard { + enabled: true, + backup_dir, + source_entry, + source: None, + saves_dir, + candidates: IndexMap::new(), + queue: IndexMap::new(), + default_selection, + components: Components { scales, trickset }, + warning_message: None, + }; + + (dashboard, tasks) + } + + fn selections(&self) -> Selections { + self.candidates + .iter() + .map(|(entry, selected)| (entry.name.clone(), *selected)) + .collect::>() + .into() + } + + pub fn set_saves_dir(&mut self, saves_dir: impl AsRef) -> Task { + self.saves_dir = Some(saves_dir.as_ref().into()); + + Task::perform( + load_candidates( + self.saves_dir.clone(), + self.selections(), + self.default_selection, + ), + Message::LoadedCandidates, + ) + } + + fn notify(&mut self, msg: impl Into) { + let msg = msg.into(); + log::warn!("{}", msg); + self.warning_message = Some(msg); + } + + pub fn update(&mut self, message: Message) -> (Task, Option) { + match message { + Message::PickSavesDir => ( + Task::perform(pick_saves_dir(), |dir| { + dir.map(|dir| Message::SavesDirChanged(dir)) + .unwrap_or(Message::ClosedSavesDirDialog) + }), + None, + ), + Message::ClosedSavesDirDialog => (Task::none(), None), + Message::SavesDirChanged(saves_dir) => { + self.saves_dir = Some(saves_dir.clone()); + (Task::none(), Some(Event::SetSavesDir(saves_dir.clone()))) + } + Message::LoadedSource(Ok(content)) => { + self.source = Some(content); + (Task::none(), None) + } + Message::LoadedSource(Err(err)) => { + self.notify(format!("error loading source: {}", err)); + (Task::none(), None) + } + + Message::LoadedCandidates(Ok(entries)) => { + self.candidates = entries; + (Task::none(), None) + } + Message::LoadedCandidates(Err(err)) => { + self.notify(format!("error loading selections: {}", err)); + (Task::none(), None) + } + + Message::PickSource => (Task::perform(pick_source(), Message::SourcePicked), None), + + Message::SourcePicked(Some(path)) => match thugpro::Entry::at_path(path.clone()) { + Ok(entry) => { + self.source_entry = Some(entry.clone()); + ( + Task::perform(load_source(entry), Message::LoadedSource), + Some(Event::SetSourcePath(path)), + ) + } + Err(err) => { + self.notify(format!("error picking source: {err}")); + (Task::none(), None) + } + }, + Message::SourcePicked(None) => (Task::none(), None), + + Message::ToggleSelectAll => { + self.default_selection = !self.default_selection; + + for selected in self.candidates.values_mut() { + *selected = self.default_selection; + } + + ( + Task::none(), + Some(Event::SetDefaultSelection( + self.default_selection, + self.selections(), + )), + ) + } + + Message::ToggleSelection(entry) => { + if let Some(selected) = self.candidates.get_mut(&entry) { + *selected = !*selected; + } + (Task::none(), Some(Event::SetSelections(self.selections()))) + } + + Message::ToggleTricksetComponent(selected) => { + self.components.trickset = selected; + (Task::none(), Some(Event::SetTrickset(selected))) + } + + Message::ToggleScalesComponent(selected) => { + self.components.scales = selected; + (Task::none(), Some(Event::SetScales(selected))) + } + + Message::Start => match &self.source { + Some(source) => { + if self.candidates.values().any(|selected| *selected) { + self.enabled = false; + + let datetime = time::OffsetDateTime::now_local() + .unwrap_or(time::OffsetDateTime::now_utc()); + + let backup_dir = self.backup_dir.join(format!( + "{:04}-{:02}-{:02}T{:02}-{:02}-{:02}", + datetime.year(), + u8::from(datetime.month()), + datetime.day(), + datetime.hour(), + datetime.minute(), + datetime.second() + )); + + ( + Task::perform( + pre_process(backup_dir, source.clone(), self.components), + Message::PreProcessDone, + ), + None, + ) + } else { + (Task::none(), None) + } + } + None => (Task::none(), None), + }, + Message::PreProcessDone(Ok((transform, backup_dir))) => { + let selected_entries = self + .candidates + .iter() + .filter_map(|(entry, selected)| selected.then_some(entry.clone())) + .collect::>(); + + self.queue = selected_entries + .iter() + .map(|entry| (entry.clone(), Status::InProgress)) + .collect::>(); + + ( + Task::batch( + selected_entries + .iter() + .map(|entry| { + let entry = entry.clone(); + Task::perform( + process_entry( + entry.clone(), + backup_dir.clone(), + Arc::clone(&transform), + ), + move |result| Message::EntryProcessed(entry.clone(), result), + ) + }) + .collect::>(), + ), + None, + ) + } + Message::PreProcessDone(Err(err)) => { + self.enabled = true; + self.notify(format!("error during pre-process: {}", err)); + + (Task::none(), None) + } + Message::EntryProcessed(entry, result) => { + let new_status = match result { + Ok(_) => Status::Success, + Err(err) => { + self.notify(format!("error for entry {}: {:?}", entry.name, err)); + Status::Error(err) + } + }; + + self.queue.entry(entry).and_modify(|status| { + *status = new_status; + }); + + if self.queue.values().all(|entry| match entry { + Status::InProgress => false, + Status::Success | Status::Error(_) => true, + }) { + self.enabled = true; + } + + (Task::none(), None) + } + } + } + + fn view_source_info(&self) -> Element { + if let Some(entry) = &self.source_entry { + tooltip( + container(text(entry.filename())) + .style(theme::container::monobox) + .padding(10) + .align_y(Vertical::Center), + container(text(entry.filepath().display().to_string())) + .padding(10) + .align_y(Vertical::Center), + tooltip::Position::Bottom, + ) + .gap(10) + .style(theme::container::bordered) + .into() + } else { + container(text("(none)")) + .style(theme::container::monobox) + .padding(10) + .align_y(Vertical::Center) + .into() + } + } + + fn view_saves_dir(&self) -> Element { + // :( + if let Some(dir) = &self.saves_dir { + if let Some(name) = dir.file_name() { + if let Some(name) = name.to_str() { + return tooltip( + container(text(name)) + .style(theme::container::monobox) + .padding(10) + .align_y(Vertical::Center), + container(text(dir.display().to_string())) + .padding(10) + .align_y(Vertical::Center), + tooltip::Position::Bottom, + ) + .gap(10) + .style(theme::container::bordered) + .into(); + } + } + } + container(text("(none)")) + .style(theme::container::monobox) + .padding(10) + .align_y(Vertical::Center) + .into() + } + + fn view_entries(&self) -> Element { + self.candidates + .iter() + .fold(Column::new().spacing(2), |column, (entry, selected)| { + column.push(widget::entry::selectable( + &entry.name, + *selected, + self.enabled + .then_some(Message::ToggleSelection(entry.clone())), + )) + }) + .into() + } + + fn view_queue(&self) -> Element { + scrollable( + self.candidates + .iter() + .filter(|(_, selected)| **selected) + .fold(Column::new().spacing(2), |column, (entry, _)| { + let style = match self.queue.get(entry) { + Some(Status::InProgress) => theme::button::entry_warning, + Some(Status::Success) => theme::button::entry_success, + Some(Status::Error(_)) => theme::button::entry_danger, + None => theme::button::entry_queued, + }; + column.push( + button(text(entry.name.clone())) + .style(style) + .on_press_maybe( + self.enabled + .then_some(Message::ToggleSelection(entry.clone())), + ) + .width(Length::Fill), + ) + }), + ) + .into() + } + + fn view_left(&self) -> Column { + Column::new() + .spacing(10) + .push( + Row::new() + .spacing(10) + .align_y(Vertical::Center) + .height(Length::Shrink) + .push( + button(text("\u{E802}").font(fonts::ICONS_FONT)) + .on_press_maybe(self.enabled.then_some(Message::PickSource)), + ) + .push(heading("from")) + .push(self.view_source_info()), + ) + .push( + checkbox("trickset", self.components.trickset) + .on_toggle_maybe(self.enabled.then_some(Message::ToggleTricksetComponent)), + ) + .push( + checkbox("scales", self.components.scales) + .on_toggle_maybe(self.enabled.then_some(Message::ToggleScalesComponent)), + ) + .push(Row::new().height(Length::Fill).align_y(Vertical::Bottom)) + } + + fn view_center(&self) -> Column { + Column::new() + .spacing(10) + .push( + Row::new() + .spacing(10) + .align_y(Vertical::Center) + .height(Length::Shrink) + .push( + button(text("\u{E802}").font(fonts::ICONS_FONT)) + .on_press_maybe(self.enabled.then_some(Message::PickSavesDir)), + ) + .push(heading("to")) + .push(self.view_saves_dir()), + ) + .push( + button( + text(match self.default_selection { + true => "deselect all", + false => "select all", + }) + .font(Font { + weight: Weight::Semibold, + ..Default::default() + }), + ) + .style(theme::button::secondary) + .on_press_maybe(self.enabled.then_some(Message::ToggleSelectAll)) + .width(Length::Fill), + ) + .push(scrollable(self.view_entries())) + } + + fn view_right(&self) -> Column { + Column::new() + .spacing(10) + .push( + Row::new() + .spacing(10) + .align_y(Vertical::Center) + .push( + button(text("\u{E803}").font(fonts::ICONS_FONT)) + .on_press_maybe(self.enabled.then_some(Message::Start)), + ) + .push(heading("queue")), + ) + .push(self.view_queue()) + } + + pub fn view(&self) -> Element { + Row::new() + .push(self.view_left().width(Length::Fill)) + .push(self.view_center().width(Length::Fill)) + .push(self.view_right().width(Length::Fill)) + .width(Length::Fill) + .spacing(10) + .into() + } +} + +async fn pick_source() -> Option { + Some( + AsyncFileDialog::new() + .add_filter("CAS file (.SKA)", &["SKA"]) + .pick_file() + .await? + .path() + .into(), + ) +} + +async fn _load_source(entry: thugpro::Entry) -> Result { + let save = save::Save::read(&mut entry.reader()?)?; + let cas = thugpro::Cas::try_from(save)?; + + Ok(cas) +} + +async fn load_source(entry: thugpro::Entry) -> Result { + let source = tokio::spawn(async move { _load_source(entry).await }) + .await + .map_err(|_| Error::Task)?; + + source +} + +async fn load_candidates( + saves_dir: Option>, + selections: Selections, + default_selection: bool, +) -> Result> { + let saves_dir = saves_dir.ok_or(Error::NoSavesDir)?; + let entries = thugpro::entry::find_entries(saves_dir)?; + + log::info!("found {} saves", entries.len()); + + let candidates = entries + .into_iter() + .map(|entry| { + ( + entry.clone(), + *selections.get(&entry.name).unwrap_or(&default_selection), + ) + }) + .collect::>(); + + Ok(candidates) +} + +fn make_transform(source: &thugpro::cas::Cas, components: Components) -> thugpro::cas::Cas { + let info = &source.data.custom_skater.custom.info; + let appearance = &source.data.custom_skater.custom.appearance; + + thugpro::cas::Cas { + summary: source.summary.clone(), + data: thugpro::cas::Data { + custom_skater: thugpro::cas::CustomSkater { + custom: thugpro::cas::Custom { + info: thugpro::cas::Info { + trick_mapping: components + .trickset + .then_some(info.trick_mapping.clone()) + .unwrap_or_default(), + specials: components + .trickset + .then_some(info.specials.clone()) + .unwrap_or_default(), + }, + appearance: thugpro::cas::Appearance { + board_bone_group: components + .scales + .then_some(appearance.board_bone_group.clone()) + .unwrap_or_default(), + feet_bone_group: components + .scales + .then_some(appearance.feet_bone_group.clone()) + .unwrap_or_default(), + hands_bone_group: components + .scales + .then_some(appearance.hands_bone_group.clone()) + .unwrap_or_default(), + head_bone_group: components + .scales + .then_some(appearance.head_bone_group.clone()) + .unwrap_or_default(), + headtop_bone_group: components + .scales + .then_some(appearance.headtop_bone_group.clone()) + .unwrap_or_default(), + jaw_bone_group: components + .scales + .then_some(appearance.jaw_bone_group.clone()) + .unwrap_or_default(), + lower_arm_bone_group: components + .scales + .then_some(appearance.lower_arm_bone_group.clone()) + .unwrap_or_default(), + lower_leg_bone_group: components + .scales + .then_some(appearance.lower_leg_bone_group.clone()) + .unwrap_or_default(), + nose_bone_group: components + .scales + .then_some(appearance.nose_bone_group.clone()) + .unwrap_or_default(), + object_scaling: components + .scales + .then_some(appearance.object_scaling.clone()) + .unwrap_or_default(), + stomach_bone_group: components + .scales + .then_some(appearance.stomach_bone_group.clone()) + .unwrap_or_default(), + torso_bone_group: components + .scales + .then_some(appearance.torso_bone_group.clone()) + .unwrap_or_default(), + upper_arm_bone_group: components + .scales + .then_some(appearance.upper_arm_bone_group.clone()) + .unwrap_or_default(), + upper_leg_bone_group: components + .scales + .then_some(appearance.upper_leg_bone_group.clone()) + .unwrap_or_default(), + ..Default::default() + }, + }, + }, + story_skater: thugpro::cas::StorySkater { + tricks: components + .trickset + .then_some(source.data.story_skater.tricks.clone()) + .unwrap_or_default(), + }, + }, + } +} + +async fn pre_process>( + backup_dir: P, + source: thugpro::Cas, + components: Components, +) -> Result<(Arc, PathBuf)> { + let backup_dir = backup_dir.as_ref(); + fs::create_dir_all(backup_dir).await?; + let transform = Arc::new(make_transform(&source, components)); + + // tasks::write( + // Arc::clone(&transform), + // backup_dir.join("transform.ron"), + // Format::Ron, + // ) + // .await?; + + Ok((Arc::clone(&transform), PathBuf::from(backup_dir))) +} + +async fn process_entry>( + entry: thugpro::Entry, + backup_dir: P, + transform: Arc, +) -> Result<()> { + let backup_dir = backup_dir.as_ref(); + + let backup_entry = entry.with_dir(backup_dir); + let backup_filepath = backup_entry.filepath(); + + let filepath = entry.filepath(); + + log::info!("backing up {:?} to {:?}", filepath, backup_filepath); + fs::copy(&filepath, &backup_filepath).await?; + + let mut save = save::Save::read(&mut entry.reader()?)?; + + transform.modify(&mut save)?; + save.write(&mut entry.writer()?)?; + + log::info!("overwrote save at {:?}", filepath); + + entry.overwrite_metadata()?; + + Ok(()) +} + +async fn pick_saves_dir() -> Option { + Some(AsyncFileDialog::new().pick_folder().await?.path().into()) +} diff --git a/crates/cascade-app/src/error.rs b/crates/cascade-app/src/error.rs new file mode 100644 index 0000000..1544f93 --- /dev/null +++ b/crates/cascade-app/src/error.rs @@ -0,0 +1,26 @@ +use std::{io, result}; + +use ron::de::SpannedError; + +#[derive(thiserror::Error, Debug, Clone)] +pub enum Error { + #[error("io error: {0}")] + Io(io::ErrorKind), + + #[error("ron deserialization error: {0}")] + RonDe(#[from] SpannedError), + + #[error("ron serialization error: {0}")] + RonSer(#[from] ron::Error), + + #[error("toml deserialization error: {0}")] + Toml(#[from] toml::de::Error), +} + +impl From for Error { + fn from(value: io::Error) -> Self { + Self::Io(value.kind()) + } +} + +pub type Result = result::Result; diff --git a/crates/cascade-app/src/fonts.rs b/crates/cascade-app/src/fonts.rs index 70b826e..7d24c4b 100644 --- a/crates/cascade-app/src/fonts.rs +++ b/crates/cascade-app/src/fonts.rs @@ -1,20 +1,3 @@ -//pub const IOSEVKA_REGULAR_BYTES: &[u8] = -// include_bytes!("../../assets/IosevkaNerdFont-Regular.ttf"); -//pub const IOSEVKA_BOLD_BYTES: &[u8] = -// include_bytes!("../../assets/IosevkaNerdFont-Bold.ttf"); - -//pub static IOSEVKA_REGULAR: Font = Font { -// family: Family::Name("Iosevka Nerd Font"), -// weight: Weight::Normal, -// stretch: Stretch::Normal, -// style: Style::Normal, -//}; -//pub static IOSEVKA_BOLD: Font = Font { -// family: Family::Name("Iosevka Nerd Font"), -// weight: Weight::Bold, -// stretch: Stretch::Normal, -// style: Style::Normal, -//}; use iced::{ font::{Family, Stretch, Style, Weight}, Font, diff --git a/crates/cascade-app/src/main.rs b/crates/cascade-app/src/main.rs index 940b6bd..58e8a44 100644 --- a/crates/cascade-app/src/main.rs +++ b/crates/cascade-app/src/main.rs @@ -1,24 +1,30 @@ #![cfg_attr(target_os = "windows", windows_subsystem = "windows")] #![feature(error_generic_member_access)] -use std::{io, path::Path, result}; +use std::{io, path::Path}; use app::Cascade; -use config::{Config, Selections}; use fern::colors::{Color, ColoredLevelConfig}; use iced::{window, Size}; use time::{format_description::well_known::Rfc3339, OffsetDateTime}; mod app; mod config; -mod dashboard; +mod error; mod fonts; mod paths; +mod state; mod tasks; mod theme; mod widget; pub use config::Theme; +pub use error::{Error, Result}; + +use crate::{ + paths::Paths, + state::{AppState, GameStates, State}, +}; pub type Renderer = iced::Renderer; pub type Element<'a, Message> = iced::Element<'a, Message, Theme, Renderer>; @@ -32,24 +38,7 @@ pub type Button<'a, Message> = iced::widget::Button<'a, Message, Theme>; const CASCADE_ICON_BYTES: &[u8] = include_bytes!("../../../assets/cascade.ico"); -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("an io error occurred: {0}")] - Io(#[from] io::Error), - - #[error("an logging error occurred: {0}")] - Log(#[from] log::SetLoggerError), - - #[error("a gui error occurred: {0}")] - Gui(#[from] iced::Error), - - #[error("a path error occurred: {0}")] - Paths(#[from] paths::Error), -} - -type Result = result::Result; - -fn configure_logging(path: impl AsRef) -> Result<()> { +fn configure_logging(path: impl AsRef) -> color_eyre::Result<()> { let colors = ColoredLevelConfig::new().info(Color::Green); fern::Dispatch::new() @@ -83,19 +72,17 @@ fn configure_logging(path: impl AsRef) -> Result<()> { Ok(()) } -fn main() -> Result<()> { +fn main() -> color_eyre::Result<()> { let cascade_dir = paths::cascade_dir().expect("could not determine cascade dir"); configure_logging(paths::log(&cascade_dir))?; - let config = Config::load(paths::config(&cascade_dir)).unwrap_or_default(); - log::info!("loaded config: {:?}", config); - - let selections = Selections::load(paths::selections(&cascade_dir)).unwrap_or_default(); - log::info!("loaded selections: {:?}", selections); - + let paths = Paths::new(&cascade_dir); + log::info!("paths: {:?}", paths); let theme = Theme::load(paths::theme(&cascade_dir)).unwrap_or_default(); log::info!("loaded theme: {:?}", theme); + let state = State::load(&paths); + log::info!("loaded state: {:?}", state); iced::application("cascade", Cascade::update, Cascade::view) .theme(Cascade::theme) @@ -108,7 +95,7 @@ fn main() -> Result<()> { .font(fonts::ICONS_FONT_BYTES) .scale_factor(Cascade::scale_factor) .subscription(Cascade::subscription) - .run_with(move || Cascade::new((cascade_dir, config, selections, theme)))?; + .run_with(move || Cascade::new(paths, theme, state))?; Ok(()) } diff --git a/crates/cascade-app/src/paths.rs b/crates/cascade-app/src/paths.rs index eb0577a..4eb7747 100644 --- a/crates/cascade-app/src/paths.rs +++ b/crates/cascade-app/src/paths.rs @@ -4,6 +4,7 @@ use std::{ result, }; +const STATE_FILENAME: &'static str = "state.ron"; const CONFIG_FILENAME: &'static str = "cascade.toml"; const SELECTIONS_FILENAME: &'static str = "selections.ron"; const THEME_FILENAME: &'static str = "theme.toml"; @@ -117,7 +118,40 @@ pub fn theme(cascade_dir: impl AsRef) -> PathBuf { cascade_dir.as_ref().join(THEME_FILENAME) } +pub fn app_state(cascade_dir: impl AsRef) -> PathBuf { + // %localappdata%/cascade/state.ron + cascade_dir.as_ref().join(STATE_FILENAME) +} + +pub fn thug2_state(cascade_dir: impl AsRef) -> PathBuf { + // %localappdata%/cascade/thug2.ron + cascade_dir.as_ref().join("thug2.ron") +} + +pub fn thaw_state(cascade_dir: impl AsRef) -> PathBuf { + // %localappdata%/cascade/thaw.ron + cascade_dir.as_ref().join("thaw.ron") +} + pub fn log(cascade_dir: impl AsRef) -> PathBuf { // %localappdata%/cascade/cascade.log cascade_dir.as_ref().join(LOG_FILENAME) } + +// TODO: replace all above +#[derive(Debug)] +pub struct Paths { + pub app: PathBuf, + pub thug2: PathBuf, + pub thaw: PathBuf, +} + +impl Paths { + pub fn new(data_dir: &PathBuf) -> Self { + Self { + app: data_dir.join("cascade.ron"), + thug2: data_dir.join("thug2.ron"), + thaw: data_dir.join("thaw.ron"), + } + } +} diff --git a/crates/cascade-app/src/state.rs b/crates/cascade-app/src/state.rs new file mode 100644 index 0000000..550d975 --- /dev/null +++ b/crates/cascade-app/src/state.rs @@ -0,0 +1,134 @@ +use std::{ + collections::HashMap, + fmt::Display, + fs, io, + path::{Path, PathBuf}, +}; + +use serde::{Deserialize, Serialize}; + +use crate::{ + paths::{self, Paths}, + Result, +}; + +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +pub enum Game { + #[default] + Thug2, + Thaw, +} + +impl Display for Game { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Game::Thug2 => "thug2", + Game::Thaw => "thaw", + } + ) + } +} + +impl Game { + pub const ALL: &'static [Self] = &[Self::Thug2, Self::Thaw]; +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AppState { + #[serde(default = "default_scale_factor")] + pub scale_factor: f64, + #[serde(default)] + pub game: Game, +} + +impl Default for AppState { + fn default() -> Self { + Self { + scale_factor: 1., + game: Default::default(), + } + } +} + +impl AppState { + pub fn load(path: impl AsRef) -> Result { + let file = fs::File::open(&path)?; + + log::info!("reading app state from {:?}", path.as_ref()); + + let contents = io::read_to_string(file)?; + + let config = ron::from_str(contents.as_str())?; + + Ok(config) + } +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct Selections(HashMap); + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct GameState { + #[serde(default)] + pub from: Option, + #[serde(default)] + pub to_dir: Option, + #[serde(default)] + pub scales: bool, + #[serde(default)] + pub trickset: bool, + #[serde(default)] + pub default_selection: bool, + #[serde(default)] + pub selections: Selections, +} +fn default_scale_factor() -> f64 { + 1. +} + +impl GameState { + pub fn load(path: impl AsRef) -> Result { + let file = fs::File::open(&path)?; + + log::info!("reading game state from {:?}", path.as_ref()); + + let contents = io::read_to_string(file)?; + + let config = toml::from_str(contents.as_str())?; + + Ok(config) + } +} + +#[derive(Debug)] +pub struct GameStates { + pub thug2: GameState, + pub thaw: GameState, +} + +impl GameStates { + pub fn load(paths: &Paths) -> Self { + let thug2 = GameState::load(&paths.thug2).unwrap_or_default(); + let thaw = GameState::load(&paths.thaw).unwrap_or_default(); + + Self { thug2, thaw } + } +} + +#[derive(Debug)] +pub struct State { + pub app: AppState, + pub game: GameStates, +} + +impl State { + pub fn load(paths: &Paths) -> Self { + let app = AppState::load(&paths.app).unwrap_or_default(); + let game = GameStates::load(paths); + + Self { app, game } + } +} diff --git a/crates/cascade-app/src/tasks.rs b/crates/cascade-app/src/tasks.rs index 6140684..92534a1 100644 --- a/crates/cascade-app/src/tasks.rs +++ b/crates/cascade-app/src/tasks.rs @@ -1,43 +1,14 @@ -use std::{io, path::Path}; +use std::path::Path; -use ron::de::SpannedError; use serde::Serialize; use tokio::{fs, io::AsyncWriteExt}; -use crate::config::Format; +use crate::Result; -#[derive(thiserror::Error, Debug, Clone)] -pub enum Error { - #[error("io error: {0}")] - Io(io::ErrorKind), - - #[error("ron serialization error: {0}")] - Ron(#[from] ron::Error), - - #[error("toml serialization error: {0}")] - Toml(#[from] toml::ser::Error), - - #[error("ron deserialization error: {0}")] - Spanned(#[from] SpannedError), -} - -impl From for Error { - fn from(value: io::Error) -> Self { - Self::Io(value.kind()) - } -} - -pub async fn write( - obj: impl Serialize, - to: impl AsRef, - format: Format, -) -> Result { +pub async fn write_ron(obj: impl Serialize, to: impl AsRef) -> Result { let mut file = fs::File::create(&to).await?; - let contents = match format { - Format::Ron => ron::ser::to_string(&obj)?, - Format::Toml => toml::ser::to_string_pretty(&obj)?, - }; + let contents = ron::ser::to_string(&obj)?; let bytes = file.write(&contents.as_bytes()).await?; diff --git a/crates/cascade-app/src/theme/mod.rs b/crates/cascade-app/src/theme/mod.rs index 366b5cf..44dac11 100644 --- a/crates/cascade-app/src/theme/mod.rs +++ b/crates/cascade-app/src/theme/mod.rs @@ -3,8 +3,8 @@ pub mod checkbox; pub mod combo_box; pub mod container; pub mod menu; +pub mod pick_list; pub mod scrollable; pub mod slider; pub mod text; pub mod text_input; - diff --git a/crates/cascade-app/src/theme/pick_list.rs b/crates/cascade-app/src/theme/pick_list.rs new file mode 100644 index 0000000..ca926f3 --- /dev/null +++ b/crates/cascade-app/src/theme/pick_list.rs @@ -0,0 +1,40 @@ +use iced::{ + widget::pick_list::{Catalog, Status, Style, StyleFn}, + Background, Border, Color, +}; + +use crate::Theme; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Theme>; + + fn default<'a>() -> StyleFn<'a, Self> { + Box::new(default) + } + + fn style(&self, class: &StyleFn<'_, Self>, status: Status) -> Style { + class(self, status) + } +} + +fn default(theme: &Theme, status: Status) -> Style { + primary(theme, status) +} + +fn primary(theme: &Theme, status: Status) -> Style { + let active = Style { + background: Background::Color(theme.background), + text_color: theme.text, + placeholder_color: theme.text.scale_alpha(0.5), + handle_color: theme.primary, + border: Border { + radius: 4.0.into(), + width: 1.0, + color: theme.secondary, + }, + }; + + match status { + Status::Active | Status::Hovered | Status::Opened { .. } => active, + } +} diff --git a/crates/cascade-cli/src/main.rs b/crates/cascade-cli/src/main.rs index 1af7377..bd2e60d 100644 --- a/crates/cascade-cli/src/main.rs +++ b/crates/cascade-cli/src/main.rs @@ -361,7 +361,7 @@ where let from_parsed = Cas::parse(&from_save)?; let transform = from_parsed.mask(flags); - for entry in core.list_entries()? { + for entry in core.entries()? { let name = entry.name(); match modify_one(&entry, &transform) { Ok(_) => { diff --git a/crates/cascade-core/Cargo.toml b/crates/cascade-core/Cargo.toml index 2821259..269466e 100644 --- a/crates/cascade-core/Cargo.toml +++ b/crates/cascade-core/Cargo.toml @@ -4,3 +4,7 @@ version = "0.0.1" edition = "2024" [dependencies] +serde = { workspace = true, optional = true } + +[features] +serde = ["dep:serde"] diff --git a/crates/cascade-core/src/cas.rs b/crates/cascade-core/src/cas.rs index dcb6f5e..8022bc2 100644 --- a/crates/cascade-core/src/cas.rs +++ b/crates/cascade-core/src/cas.rs @@ -1,5 +1,7 @@ use crate::save; +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Flags { pub summary: bool, pub trickset: bool, diff --git a/crates/cascade-core/src/lib.rs b/crates/cascade-core/src/lib.rs index 1a2702a..1645376 100644 --- a/crates/cascade-core/src/lib.rs +++ b/crates/cascade-core/src/lib.rs @@ -12,5 +12,5 @@ pub trait Core { type Cas: cas::Cas; type Error; - fn list_entries(&self) -> Result, Self::Error>; + fn entries(&self) -> Result, Self::Error>; } diff --git a/crates/cascade-thaw/src/core.rs b/crates/cascade-thaw/src/core.rs index 7525bb0..a24313c 100644 --- a/crates/cascade-thaw/src/core.rs +++ b/crates/cascade-thaw/src/core.rs @@ -23,7 +23,7 @@ impl cascade_core::Core for Core { type Cas = Cas; type Error = Error; - fn list_entries(&self) -> Result> { + fn entries(&self) -> Result> { find_entries(&self.cwd) } } diff --git a/crates/cascade-thug2/src/core.rs b/crates/cascade-thug2/src/core.rs index c3f7649..612e197 100644 --- a/crates/cascade-thug2/src/core.rs +++ b/crates/cascade-thug2/src/core.rs @@ -18,7 +18,7 @@ impl cascade_core::Core for Core { type Cas = Cas; type Error = Error; - fn list_entries(&self) -> Result> { + fn entries(&self) -> Result> { find_entries(&self.cwd) } } From 7970e849eae080242c9ef673b09b6e9d509ed127 Mon Sep 17 00:00:00 2001 From: ellie <149747415+1borgy@users.noreply.github.com> Date: Mon, 29 Jun 2026 11:12:06 -0400 Subject: [PATCH 10/23] saving progress... glhf --- Cargo.toml | 6 + crates/cascade-app/Cargo.toml | 2 +- crates/cascade-app/src/app.rs | 333 ++++++++++++++++++++-- crates/cascade-app/src/config/mod.rs | 8 - crates/cascade-app/src/main.rs | 9 +- crates/cascade-app/src/paths.rs | 33 --- crates/cascade-app/src/state.rs | 15 +- crates/cascade-app/src/theme/container.rs | 2 +- crates/cascade-app/src/theme/pick_list.rs | 2 +- crates/cascade-cli/Cargo.toml | 2 +- crates/cascade-core/Cargo.toml | 2 +- crates/cascade-core/src/lib.rs | 9 +- crates/cascade-crc/Cargo.toml | 2 +- crates/cascade-dump/Cargo.toml | 2 +- crates/cascade-lut/Cargo.toml | 2 +- crates/cascade-qb/Cargo.toml | 2 +- crates/cascade-save/Cargo.toml | 2 +- crates/cascade-thaw/Cargo.toml | 2 +- crates/cascade-thaw/src/core.rs | 16 +- crates/cascade-thps4/Cargo.toml | 2 +- crates/cascade-thug/Cargo.toml | 2 +- crates/cascade-thug2/Cargo.toml | 2 +- crates/cascade-thug2/src/core.rs | 16 +- crates/cascade-thug2/src/lib.rs | 2 +- crates/cascade-thug2/tests/common/mod.rs | 4 +- crates/cascade-wad/Cargo.toml | 2 +- 26 files changed, 358 insertions(+), 123 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e1ff60c..8d857a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,12 @@ members = ["crates/*"] resolver = "2" +[workspace.package] +edition = "2024" +rust-version = "1.88" +repository = "https://github.com/1borgy/cascade" +license = "MIT" + [workspace.dependencies] cascade-core = { path = "crates/cascade-core" } cascade-crc = { path = "crates/cascade-crc" } diff --git a/crates/cascade-app/Cargo.toml b/crates/cascade-app/Cargo.toml index 5a5fb84..3df12ac 100644 --- a/crates/cascade-app/Cargo.toml +++ b/crates/cascade-app/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-app" version = "0.3.0" -edition = "2021" +edition = { workspace = true } [[bin]] name = "cascade" diff --git a/crates/cascade-app/src/app.rs b/crates/cascade-app/src/app.rs index 0623bd2..8c35a29 100644 --- a/crates/cascade-app/src/app.rs +++ b/crates/cascade-app/src/app.rs @@ -1,40 +1,119 @@ use std::path::PathBuf; +use cascade_core::Entry; use iced::{ + Event, Font, Length, Padding, Subscription, Task, + alignment::Vertical, event, + font::Weight, keyboard::{self, key}, - widget::{container, pick_list}, - Event, Length, Padding, Subscription, Task, + widget::{Column, Row, button, checkbox, container, pick_list, text, tooltip}, }; +use rfd::AsyncFileDialog; use serde::Serialize; use crate::{ + Element, Result, Theme, fonts, paths::Paths, - state::{Game, State}, - tasks, Element, Result, Theme, + state::{Game, GameState, State}, + tasks, theme, + widget::{self, heading}, }; #[derive(Debug, Clone)] pub enum Message { - GameSelected(Game), EventOccurred(Event), + SetTricksetFlag(bool), + SetScalesFlag(bool), + GameSelected(Game), + + PickFrom, + SetFrom(Option), + + PickToDir, + SetToDir(Option), + + ToggleDefaultSelection, + ToggleSelection(String), + + Start, + WroteFile(Result), } +struct Context { + state_path: PathBuf, + state: GameState, + core: Core, + entries: Vec, +} + +impl Context { + pub fn new(state_path: PathBuf, state: GameState, core: Core) -> Self { + let mut slf = Self { + state_path, + state, + core, + entries: Vec::new(), + }; + slf.refresh(); + slf + } + + pub fn refresh(&mut self) { + if let Some(to_dir) = &self.state.to_dir { + match self.core.entries(to_dir) { + Ok(entries) => self.entries = entries.collect(), + Err(err) => log::warn!("error refreshing entries: {}", err), + }; + } + } + + pub fn write(&mut self) -> Task { + Task::perform( + tasks::write_ron(self.state.clone(), self.state_path.clone()), + Message::WroteFile, + ) + } +} + +impl Contexts { + pub fn new(state: &State, paths: &Paths) -> Contexts { + Self { + thug2: Context::new( + paths.thug2.clone(), + state.game.thug2.clone(), + cascade_thug2::Core {}, + ), + thaw: Context::new( + paths.thaw.clone(), + state.game.thaw.clone(), + cascade_thaw::Core {}, + ), + } + } +} + pub struct Cascade { paths: Paths, theme: Theme, state: State, + contexts: Contexts, + + enabled: bool, } impl Cascade { pub fn new(paths: Paths, theme: Theme, state: State) -> (Self, Task) { + let contexts = Contexts::new(&state, &paths); ( Cascade { paths, theme, state, + contexts, + enabled: true, }, Task::none(), ) @@ -48,12 +127,29 @@ impl Cascade { self.write_state(self.state.app.clone(), self.paths.app.clone()) } - fn write_game_state(&self) -> Task { + fn context(&self) -> &Context { + match self.state.app.game { + Game::Thug2 => &self.contexts.thug2, + Game::Thaw => &self.contexts.thaw, + } + } + + fn with_context_mut(&mut self, f: impl FnOnce(&mut GameState), refresh: bool) -> Task { match self.state.app.game { Game::Thug2 => { - self.write_state(self.state.game.thug2.clone(), self.paths.thug2.clone()) + f(&mut self.contexts.thug2.state); + if refresh { + self.contexts.thug2.refresh(); + } + self.contexts.thug2.write() + } + Game::Thaw => { + f(&mut self.contexts.thaw.state); + if refresh { + self.contexts.thaw.refresh(); + } + self.contexts.thaw.write() } - Game::Thaw => self.write_state(self.state.game.thaw.clone(), self.paths.thaw.clone()), } } @@ -67,11 +163,6 @@ impl Cascade { pub fn update(&mut self, message: Message) -> Task { match message { - Message::GameSelected(game) => { - self.state.app.game = game; - Task::none() - } - // Ctrl+= Message::EventOccurred(Event::Keyboard(keyboard::Event::KeyPressed { physical_key: key::Physical::Code(key::Code::Equal), modifiers: keyboard::Modifiers::CTRL, @@ -84,7 +175,6 @@ impl Cascade { Task::none() } } - // Ctrl+- Message::EventOccurred(Event::Keyboard(keyboard::Event::KeyPressed { physical_key: key::Physical::Code(key::Code::Minus), modifiers: keyboard::Modifiers::CTRL, @@ -103,24 +193,219 @@ impl Cascade { log::error!("error writing file: {}", err); Task::none() } + Message::PickFrom => Task::perform(pick_source(), Message::SetFrom), + Message::SetFrom(path) => match path { + Some(path) => self.with_context_mut(|s| s.from = Some(path), false), + None => Task::none(), + }, + Message::PickToDir => Task::perform(pick_to_dir(), Message::SetToDir), + Message::SetToDir(dir) => match dir { + Some(dir) => self.with_context_mut(|s| s.to_dir = Some(dir), true), + None => Task::none(), + }, + Message::SetTricksetFlag(selected) => { + self.with_context_mut(|s| s.trickset = selected, false) + } + Message::SetScalesFlag(selected) => { + self.with_context_mut(|s| s.scales = selected, false) + } + Message::GameSelected(game) => { + self.state.app.game = game; + self.write_app_state() + } + Message::ToggleDefaultSelection => { + self.with_context_mut(|s| s.default_selection = !s.default_selection, false) + } + Message::Start => Task::none(), + Message::ToggleSelection(_) => todo!(), } } pub fn view(&self) -> Element<'_, Message> { - let content: Element = container(pick_list( - Game::ALL, - Some(self.state.app.game), - Message::GameSelected, - )) - .width(Length::Fill) - .height(Length::Fill) - .padding(Padding::new(20.)) - .into(); + let current_game = self.context(); + Row::new() + .push(self.view_left(current_game)) + .push(self.view_center(current_game)) + .push(self.view_right()) + .width(Length::Fill) + .spacing(10) + .padding(Padding::new(20.)) + .into() + } + + pub fn view_left(&self, game_state: &GameState) -> Element<'_, Message> { + Column::new() + .spacing(10) + .push( + Row::new() + .spacing(10) + .align_y(Vertical::Center) + .height(Length::Shrink) + .push( + button(text("\u{E802}").font(fonts::ICONS_FONT)) + .on_press_maybe(self.enabled.then_some(Message::PickFrom)), + ) + .push(heading("from")) + .push(self.view_path(&game_state.from)), + ) + .push( + checkbox("trickset", game_state.trickset) + .on_toggle_maybe(self.enabled.then_some(Message::SetTricksetFlag)), + ) + .push( + checkbox("scales", game_state.scales) + .on_toggle_maybe(self.enabled.then_some(Message::SetScalesFlag)), + ) + .push(pick_list( + Game::ALL, + Some(self.state.app.game), + Message::GameSelected, + )) + .push(Row::new().height(Length::Fill).align_y(Vertical::Bottom)) + .width(Length::Fill) + .into() + } - content + fn view_center(&self, game_state: &GameState) -> Element<'_, Message> { + Column::new() + .spacing(10) + .push( + Row::new() + .spacing(10) + .align_y(Vertical::Center) + .height(Length::Shrink) + .push( + button(text("\u{E802}").font(fonts::ICONS_FONT)) + .on_press_maybe(self.enabled.then_some(Message::PickToDir)), + ) + .push(heading("to")) + .push(self.view_path(&game_state.to_dir)), + ) + .push( + button( + text(match game_state.default_selection { + true => "deselect all", + false => "select all", + }) + .font(Font { + weight: Weight::Semibold, + ..Default::default() + }), + ) + .style(theme::button::secondary) + .on_press_maybe(self.enabled.then_some(Message::ToggleDefaultSelection)) + .width(Length::Fill), + ) + .width(Length::Fill) + // TODO: + // .push(scrollable(self.view_entries())) + .into() + } + + fn view_entries(&self) -> Element { + let context: &Context = self.context(); + context + .entries + .iter() + .fold(Column::new().spacing(2), |column, entry| { + let name = entry.name(); + let selected = context + .state + .selections + .get(&name) + .unwrap_or(&context.state.default_selection); + + column.push(widget::entry::selectable( + name, + *selected, + self.enabled + .then_some(Message::ToggleSelection(entry.name().clone())), + )) + }) + .into() + } + + fn view_path(&self, path: &Option) -> Element<'_, Message> { + if let Some(path) = &path { + let filepath = format!("{}", path.display()); + let filename = path + .file_name() + .and_then(|s| s.to_str()) + .unwrap_or("(invalid path)") + .to_string(); + + tooltip( + container(text(filename)) + .style(theme::container::monobox) + .padding(10) + .align_y(Vertical::Center), + container(text(filepath)) + .padding(10) + .align_y(Vertical::Center), + tooltip::Position::Bottom, + ) + .gap(10) + .style(theme::container::bordered) + .into() + } else { + tooltip( + container(text("(none)")) + .style(theme::container::monobox) + .padding(10) + .align_y(Vertical::Center), + container(text("please select a path")) + .padding(10) + .align_y(Vertical::Center), + tooltip::Position::Bottom, + ) + .gap(10) + .style(theme::container::bordered) + .into() + } + } + + fn view_right(&self) -> Element<'_, Message> { + Column::new() + .spacing(10) + .push( + Row::new() + .spacing(10) + .align_y(Vertical::Center) + .push( + button(text("\u{E803}").font(fonts::ICONS_FONT)) + .on_press_maybe(self.enabled.then_some(Message::Start)), + ) + .push(heading("queue")), + ) + // TODO: + // .push(self.view_queue()) + .width(Length::Fill) + .into() } pub fn subscription(&self) -> Subscription { event::listen().map(Message::EventOccurred) } } + +async fn pick_source() -> Option { + // TODO: Change to -Progress for THAW + Some( + AsyncFileDialog::new() + .add_filter("CAS file (.SKA)", &["SKA"]) + .add_filter("Any file", &[""]) + .pick_file() + .await? + .path() + .into(), + ) +} + +async fn pick_to_dir() -> Option { + Some(AsyncFileDialog::new().pick_folder().await?.path().into()) +} + +struct Contexts { + thug2: Context, + thaw: Context, +} diff --git a/crates/cascade-app/src/config/mod.rs b/crates/cascade-app/src/config/mod.rs index 93689b8..792a757 100644 --- a/crates/cascade-app/src/config/mod.rs +++ b/crates/cascade-app/src/config/mod.rs @@ -9,16 +9,8 @@ pub mod options; pub mod selections; pub mod theme; -pub use options::Config; -pub use selections::Selections; pub use theme::Theme; -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Format { - Ron, - Toml, -} - #[derive(thiserror::Error, Debug, Clone)] pub enum Error { #[error("io error: {0}")] diff --git a/crates/cascade-app/src/main.rs b/crates/cascade-app/src/main.rs index 58e8a44..b4f1543 100644 --- a/crates/cascade-app/src/main.rs +++ b/crates/cascade-app/src/main.rs @@ -5,8 +5,8 @@ use std::{io, path::Path}; use app::Cascade; use fern::colors::{Color, ColoredLevelConfig}; -use iced::{window, Size}; -use time::{format_description::well_known::Rfc3339, OffsetDateTime}; +use iced::{Size, window}; +use time::{OffsetDateTime, format_description::well_known::Rfc3339}; mod app; mod config; @@ -21,10 +21,7 @@ mod widget; pub use config::Theme; pub use error::{Error, Result}; -use crate::{ - paths::Paths, - state::{AppState, GameStates, State}, -}; +use crate::{paths::Paths, state::State}; pub type Renderer = iced::Renderer; pub type Element<'a, Message> = iced::Element<'a, Message, Theme, Renderer>; diff --git a/crates/cascade-app/src/paths.rs b/crates/cascade-app/src/paths.rs index 4eb7747..f9d7558 100644 --- a/crates/cascade-app/src/paths.rs +++ b/crates/cascade-app/src/paths.rs @@ -4,9 +4,7 @@ use std::{ result, }; -const STATE_FILENAME: &'static str = "state.ron"; const CONFIG_FILENAME: &'static str = "cascade.toml"; -const SELECTIONS_FILENAME: &'static str = "selections.ron"; const THEME_FILENAME: &'static str = "theme.toml"; const LOG_FILENAME: &'static str = "cascade.log"; @@ -97,42 +95,11 @@ pub fn cascade_dir() -> Result { None => default_cascade_dir().or_else(|_| cwd()), } } - -pub fn backup_dir(cascade_dir: impl AsRef) -> PathBuf { - // %localappdata%/cascade/backup/ - cascade_dir.as_ref().join("backup") -} - -pub fn config(cascade_dir: impl AsRef) -> PathBuf { - // %localappdata%/cascade/cascade.toml - cascade_dir.as_ref().join(CONFIG_FILENAME) -} - -pub fn selections(cascade_dir: impl AsRef) -> PathBuf { - // %localappdata%/cascade/selections.ron - cascade_dir.as_ref().join(SELECTIONS_FILENAME) -} - pub fn theme(cascade_dir: impl AsRef) -> PathBuf { // %localappdata%/cascade/theme.toml cascade_dir.as_ref().join(THEME_FILENAME) } -pub fn app_state(cascade_dir: impl AsRef) -> PathBuf { - // %localappdata%/cascade/state.ron - cascade_dir.as_ref().join(STATE_FILENAME) -} - -pub fn thug2_state(cascade_dir: impl AsRef) -> PathBuf { - // %localappdata%/cascade/thug2.ron - cascade_dir.as_ref().join("thug2.ron") -} - -pub fn thaw_state(cascade_dir: impl AsRef) -> PathBuf { - // %localappdata%/cascade/thaw.ron - cascade_dir.as_ref().join("thaw.ron") -} - pub fn log(cascade_dir: impl AsRef) -> PathBuf { // %localappdata%/cascade/cascade.log cascade_dir.as_ref().join(LOG_FILENAME) diff --git a/crates/cascade-app/src/state.rs b/crates/cascade-app/src/state.rs index 550d975..ad2acd6 100644 --- a/crates/cascade-app/src/state.rs +++ b/crates/cascade-app/src/state.rs @@ -7,10 +7,7 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{ - paths::{self, Paths}, - Result, -}; +use crate::{Result, paths::Paths}; #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum Game { @@ -25,8 +22,8 @@ impl Display for Game { f, "{}", match self { - Game::Thug2 => "thug2", - Game::Thaw => "thaw", + Game::Thug2 => "THUG2", + Game::Thaw => "THAW", } ) } @@ -67,8 +64,8 @@ impl AppState { } } -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct Selections(HashMap); +// #[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub type Selections = HashMap; #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct GameState { @@ -97,7 +94,7 @@ impl GameState { let contents = io::read_to_string(file)?; - let config = toml::from_str(contents.as_str())?; + let config = ron::from_str(contents.as_str())?; Ok(config) } diff --git a/crates/cascade-app/src/theme/container.rs b/crates/cascade-app/src/theme/container.rs index 20fe2ca..41de861 100644 --- a/crates/cascade-app/src/theme/container.rs +++ b/crates/cascade-app/src/theme/container.rs @@ -1,6 +1,6 @@ use iced::{ - widget::container::{transparent, Catalog, Style, StyleFn}, Background, Border, + widget::container::{Catalog, Style, StyleFn, transparent}, }; use crate::Theme; diff --git a/crates/cascade-app/src/theme/pick_list.rs b/crates/cascade-app/src/theme/pick_list.rs index ca926f3..521b7f3 100644 --- a/crates/cascade-app/src/theme/pick_list.rs +++ b/crates/cascade-app/src/theme/pick_list.rs @@ -1,6 +1,6 @@ use iced::{ + Background, Border, widget::pick_list::{Catalog, Status, Style, StyleFn}, - Background, Border, Color, }; use crate::Theme; diff --git a/crates/cascade-cli/Cargo.toml b/crates/cascade-cli/Cargo.toml index 7bc4428..ba2fc64 100644 --- a/crates/cascade-cli/Cargo.toml +++ b/crates/cascade-cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-cli" version = "0.0.1" -edition = "2024" +edition = { workspace = true } [dependencies] cascade-core = { workspace = true } diff --git a/crates/cascade-core/Cargo.toml b/crates/cascade-core/Cargo.toml index 269466e..87608e7 100644 --- a/crates/cascade-core/Cargo.toml +++ b/crates/cascade-core/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-core" version = "0.0.1" -edition = "2024" +edition = { workspace = true } [dependencies] serde = { workspace = true, optional = true } diff --git a/crates/cascade-core/src/lib.rs b/crates/cascade-core/src/lib.rs index 1645376..0014ed1 100644 --- a/crates/cascade-core/src/lib.rs +++ b/crates/cascade-core/src/lib.rs @@ -2,6 +2,8 @@ mod cas; mod entry; mod save; +use std::{fmt::Display, path::Path}; + pub use cas::{Cas, Flags}; pub use entry::Entry; pub use save::Save; @@ -10,7 +12,10 @@ pub trait Core { type Entry: entry::Entry; type Save: save::Save; type Cas: cas::Cas; - type Error; + type Error: Display; - fn entries(&self) -> Result, Self::Error>; + fn entries( + &self, + dir: impl AsRef, + ) -> Result, Self::Error>; } diff --git a/crates/cascade-crc/Cargo.toml b/crates/cascade-crc/Cargo.toml index d4c9841..28ad493 100644 --- a/crates/cascade-crc/Cargo.toml +++ b/crates/cascade-crc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-crc" version = "0.0.1" -edition = "2024" +edition = { workspace = true } [dependencies] crc = { workspace = true } diff --git a/crates/cascade-dump/Cargo.toml b/crates/cascade-dump/Cargo.toml index 969f017..88486b5 100644 --- a/crates/cascade-dump/Cargo.toml +++ b/crates/cascade-dump/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-dump" version = "0.0.1" -edition = "2024" +edition = { workspace = true } [dependencies] cascade-lut = { workspace = true } diff --git a/crates/cascade-lut/Cargo.toml b/crates/cascade-lut/Cargo.toml index 4570e81..5382630 100644 --- a/crates/cascade-lut/Cargo.toml +++ b/crates/cascade-lut/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-lut" version = "0.0.1" -edition = "2024" +edition = { workspace = true } [dependencies] cascade-qb = { workspace = true } diff --git a/crates/cascade-qb/Cargo.toml b/crates/cascade-qb/Cargo.toml index 9f13b97..f2e6024 100644 --- a/crates/cascade-qb/Cargo.toml +++ b/crates/cascade-qb/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-qb" version = "0.0.1" -edition = "2021" +edition = { workspace = true } [dependencies] byteorder = { workspace = true } diff --git a/crates/cascade-save/Cargo.toml b/crates/cascade-save/Cargo.toml index b40538a..3121c9a 100644 --- a/crates/cascade-save/Cargo.toml +++ b/crates/cascade-save/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-save" version = "0.0.1" -edition = "2024" +edition = { workspace = true } [dependencies] cascade-crc = { workspace = true } diff --git a/crates/cascade-thaw/Cargo.toml b/crates/cascade-thaw/Cargo.toml index 5ecfd0c..2700ab2 100644 --- a/crates/cascade-thaw/Cargo.toml +++ b/crates/cascade-thaw/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-thaw" version = "0.0.1" -edition = "2024" +edition = { workspace = true } [dependencies] cascade-core = { workspace = true } diff --git a/crates/cascade-thaw/src/core.rs b/crates/cascade-thaw/src/core.rs index a24313c..829cf81 100644 --- a/crates/cascade-thaw/src/core.rs +++ b/crates/cascade-thaw/src/core.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::path::Path; use crate::{ Error, Result, @@ -7,15 +7,7 @@ use crate::{ save::Save, }; -pub struct Core { - cwd: PathBuf, -} - -impl Core { - pub fn new(cwd: PathBuf) -> Self { - Self { cwd } - } -} +pub struct Core {} impl cascade_core::Core for Core { type Entry = Entry; @@ -23,7 +15,7 @@ impl cascade_core::Core for Core { type Cas = Cas; type Error = Error; - fn entries(&self) -> Result> { - find_entries(&self.cwd) + fn entries(&self, dir: impl AsRef) -> Result> { + find_entries(dir) } } diff --git a/crates/cascade-thps4/Cargo.toml b/crates/cascade-thps4/Cargo.toml index 411d682..757071c 100644 --- a/crates/cascade-thps4/Cargo.toml +++ b/crates/cascade-thps4/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-thps4" version = "0.0.1" -edition = "2024" +edition = { workspace = true } [dependencies] cascade-lut = { workspace = true } diff --git a/crates/cascade-thug/Cargo.toml b/crates/cascade-thug/Cargo.toml index 6ce271c..da9351f 100644 --- a/crates/cascade-thug/Cargo.toml +++ b/crates/cascade-thug/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-thug" version = "0.0.1" -edition = "2024" +edition = { workspace = true } [dependencies] cascade-lut = { workspace = true } diff --git a/crates/cascade-thug2/Cargo.toml b/crates/cascade-thug2/Cargo.toml index b04bc75..6fc2c9d 100644 --- a/crates/cascade-thug2/Cargo.toml +++ b/crates/cascade-thug2/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-thug2" version = "0.0.1" -edition = "2024" +edition = { workspace = true } [dependencies] cascade-core = { workspace = true } diff --git a/crates/cascade-thug2/src/core.rs b/crates/cascade-thug2/src/core.rs index 612e197..09f68ec 100644 --- a/crates/cascade-thug2/src/core.rs +++ b/crates/cascade-thug2/src/core.rs @@ -1,16 +1,8 @@ -use std::path::PathBuf; +use std::path::Path; use crate::{Cas, Entry, Error, Result, Save, entry::find_entries}; -pub struct Core { - cwd: PathBuf, -} - -impl Core { - pub fn new(cwd: PathBuf) -> Self { - Self { cwd } - } -} +pub struct Core {} impl cascade_core::Core for Core { type Entry = Entry; @@ -18,7 +10,7 @@ impl cascade_core::Core for Core { type Cas = Cas; type Error = Error; - fn entries(&self) -> Result> { - find_entries(&self.cwd) + fn entries(&self, dir: impl AsRef) -> Result> { + find_entries(dir) } } diff --git a/crates/cascade-thug2/src/lib.rs b/crates/cascade-thug2/src/lib.rs index 2f08136..62fcd43 100644 --- a/crates/cascade-thug2/src/lib.rs +++ b/crates/cascade-thug2/src/lib.rs @@ -11,6 +11,6 @@ mod save; pub use core::Core; pub use cas::Cas; -pub use entry::Entry; +pub use entry::{Entry, find_entries}; pub use error::{Error, Result}; pub use save::Save; diff --git a/crates/cascade-thug2/tests/common/mod.rs b/crates/cascade-thug2/tests/common/mod.rs index e327d72..2182509 100644 --- a/crates/cascade-thug2/tests/common/mod.rs +++ b/crates/cascade-thug2/tests/common/mod.rs @@ -25,5 +25,7 @@ pub fn entries() -> Vec { .join("assets") .join("saves"); - thug2::entry::find_entries(&saves_dir).expect("could not find saves directory") + thug2::find_entries(&saves_dir) + .expect("could not find saves directory") + .collect() } diff --git a/crates/cascade-wad/Cargo.toml b/crates/cascade-wad/Cargo.toml index 9cd6f8d..3fb1a0a 100644 --- a/crates/cascade-wad/Cargo.toml +++ b/crates/cascade-wad/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "cascade-wad" version = "0.0.1" -edition = "2024" +edition = { workspace = true } [dependencies] byteorder = { workspace = true } From 0a7ed8fe422a49e505c7617f42970ce7d70a9b65 Mon Sep 17 00:00:00 2001 From: ellie <149747415+1borgy@users.noreply.github.com> Date: Mon, 6 Jul 2026 09:51:02 -0400 Subject: [PATCH 11/23] kinda stable --- crates/cascade-app/src/app.rs | 341 ++++++++++++++---- crates/cascade-app/src/config/mod.rs | 29 -- crates/cascade-app/src/config/options.rs | 68 ---- crates/cascade-app/src/config/selections.rs | 36 -- crates/cascade-app/src/config/theme.rs | 6 +- crates/cascade-app/src/error.rs | 3 + crates/cascade-app/src/paths.rs | 34 +- crates/cascade-app/src/state.rs | 31 +- crates/cascade-cli/src/main.rs | 50 +-- crates/cascade-core/Cargo.toml | 6 + crates/cascade-core/src/cas.rs | 9 +- crates/cascade-core/src/entry.rs | 90 ++++- .../src/error.rs | 16 +- crates/cascade-core/src/lib.rs | 13 +- crates/cascade-core/src/save.rs | 8 +- crates/cascade-save/Cargo.toml | 1 - crates/cascade-save/src/save.rs | 12 +- crates/cascade-thaw/src/cas.rs | 69 ++-- crates/cascade-thaw/src/chunk.rs | 12 +- crates/cascade-thaw/src/core.rs | 21 -- crates/cascade-thaw/src/entry.rs | 161 ++------- crates/cascade-thaw/src/lib.rs | 7 +- crates/cascade-thaw/src/save.rs | 25 +- crates/cascade-thug2/src/cas.rs | 69 ++-- crates/cascade-thug2/src/core.rs | 16 - crates/cascade-thug2/src/entry.rs | 169 ++------- crates/cascade-thug2/src/error.rs | 36 -- crates/cascade-thug2/src/lib.rs | 7 +- crates/cascade-thug2/src/save.rs | 4 +- 29 files changed, 609 insertions(+), 740 deletions(-) delete mode 100644 crates/cascade-app/src/config/options.rs delete mode 100644 crates/cascade-app/src/config/selections.rs rename crates/{cascade-thaw => cascade-core}/src/error.rs (70%) delete mode 100644 crates/cascade-thaw/src/core.rs delete mode 100644 crates/cascade-thug2/src/core.rs delete mode 100644 crates/cascade-thug2/src/error.rs diff --git a/crates/cascade-app/src/app.rs b/crates/cascade-app/src/app.rs index 8c35a29..6b75a5c 100644 --- a/crates/cascade-app/src/app.rs +++ b/crates/cascade-app/src/app.rs @@ -1,19 +1,23 @@ -use std::path::PathBuf; +use std::{ + collections::hash_map, + path::{Path, PathBuf}, + sync::Arc, +}; -use cascade_core::Entry; use iced::{ Event, Font, Length, Padding, Subscription, Task, alignment::Vertical, event, font::Weight, keyboard::{self, key}, - widget::{Column, Row, button, checkbox, container, pick_list, text, tooltip}, + widget::{Column, Row, button, checkbox, container, pick_list, scrollable, text, tooltip}, }; +use indexmap::IndexMap; use rfd::AsyncFileDialog; use serde::Serialize; use crate::{ - Element, Result, Theme, fonts, + Element, Error, Result, Theme, fonts, paths::Paths, state::{Game, GameState, State}, tasks, theme, @@ -37,24 +41,28 @@ pub enum Message { ToggleDefaultSelection, ToggleSelection(String), - Start, + Run, + EntryProcessed(String, Result<()>), WroteFile(Result), } -struct Context { +type LoadEntries = Box Vec>; +// type LoadEntries = fn(&PathBuf) -> Vec; + +struct Context { state_path: PathBuf, state: GameState, - core: Core, - entries: Vec, + load_entries: LoadEntries, + entries: Vec, } -impl Context { - pub fn new(state_path: PathBuf, state: GameState, core: Core) -> Self { +impl Context { + pub fn new(state_path: PathBuf, state: GameState, load_entries: LoadEntries) -> Self { let mut slf = Self { state_path, state, - core, + load_entries, entries: Vec::new(), }; slf.refresh(); @@ -63,10 +71,10 @@ impl Context { pub fn refresh(&mut self) { if let Some(to_dir) = &self.state.to_dir { - match self.core.entries(to_dir) { - Ok(entries) => self.entries = entries.collect(), - Err(err) => log::warn!("error refreshing entries: {}", err), - }; + let entries = (self.load_entries)(to_dir); + if entries.len() > 0 { + self.entries = entries; + } } } @@ -78,41 +86,59 @@ impl Context { } } +struct Contexts { + thug2: Context, + thaw: Context, +} + impl Contexts { pub fn new(state: &State, paths: &Paths) -> Contexts { Self { thug2: Context::new( paths.thug2.clone(), state.game.thug2.clone(), - cascade_thug2::Core {}, + Box::new(cascade_thug2::find_entries), ), thaw: Context::new( paths.thaw.clone(), state.game.thaw.clone(), - cascade_thaw::Core {}, + Box::new(cascade_thaw::find_entries), ), } } } +#[derive(Debug, Clone)] +enum Status { + // i.e. last known status of processing an entry + InProgress, + Success, + #[expect(dead_code)] + Error(Error), +} + pub struct Cascade { paths: Paths, theme: Theme, state: State, contexts: Contexts, + queue: IndexMap, + enabled: bool, } impl Cascade { pub fn new(paths: Paths, theme: Theme, state: State) -> (Self, Task) { let contexts = Contexts::new(&state, &paths); + let queue = IndexMap::new(); ( Cascade { paths, theme, state, contexts, + queue, enabled: true, }, Task::none(), @@ -127,32 +153,26 @@ impl Cascade { self.write_state(self.state.app.clone(), self.paths.app.clone()) } - fn context(&self) -> &Context { + fn context(&self) -> &Context { match self.state.app.game { Game::Thug2 => &self.contexts.thug2, Game::Thaw => &self.contexts.thaw, } } - fn with_context_mut(&mut self, f: impl FnOnce(&mut GameState), refresh: bool) -> Task { + fn context_mut(&mut self) -> &mut Context { match self.state.app.game { - Game::Thug2 => { - f(&mut self.contexts.thug2.state); - if refresh { - self.contexts.thug2.refresh(); - } - self.contexts.thug2.write() - } - Game::Thaw => { - f(&mut self.contexts.thaw.state); - if refresh { - self.contexts.thaw.refresh(); - } - self.contexts.thaw.write() - } + Game::Thug2 => &mut self.contexts.thug2, + Game::Thaw => &mut self.contexts.thaw, } } + fn with_context_mut(&mut self, f: impl FnOnce(&mut Context)) -> Task { + let context = self.context_mut(); + f(context); + context.write() + } + pub fn scale_factor(&self) -> f64 { self.state.app.scale_factor } @@ -195,29 +215,135 @@ impl Cascade { } Message::PickFrom => Task::perform(pick_source(), Message::SetFrom), Message::SetFrom(path) => match path { - Some(path) => self.with_context_mut(|s| s.from = Some(path), false), + Some(path) => self.with_context_mut(|context| context.state.from = Some(path)), None => Task::none(), }, Message::PickToDir => Task::perform(pick_to_dir(), Message::SetToDir), Message::SetToDir(dir) => match dir { - Some(dir) => self.with_context_mut(|s| s.to_dir = Some(dir), true), + Some(dir) => self.with_context_mut(|context| context.state.to_dir = Some(dir)), None => Task::none(), }, Message::SetTricksetFlag(selected) => { - self.with_context_mut(|s| s.trickset = selected, false) + self.with_context_mut(|context| context.state.trickset = selected) } Message::SetScalesFlag(selected) => { - self.with_context_mut(|s| s.scales = selected, false) + self.with_context_mut(|context| context.state.scales = selected) } Message::GameSelected(game) => { self.state.app.game = game; self.write_app_state() } - Message::ToggleDefaultSelection => { - self.with_context_mut(|s| s.default_selection = !s.default_selection, false) + Message::ToggleDefaultSelection => self.with_context_mut(|context| { + context.state.default_selection = !context.state.default_selection; + context.state.selections.clear(); + }), + Message::ToggleSelection(name) => self.with_context_mut(|context| { + match context.state.selections.entry(name) { + // If occupied, remove to use default selection + hash_map::Entry::Occupied(entry) => { + entry.remove(); + } + // If vacant, insert since no longer using default selection + hash_map::Entry::Vacant(entry) => { + entry.insert(!context.state.default_selection); + } + } + }), + Message::Run => self.run().unwrap_or_else(|err| { + log::error!("runtime error: {}", err); + Task::none() + }), + Message::EntryProcessed(name, result) => { + let new_status = match result { + Ok(_) => Status::Success, + Err(err) => { + log::error!("error for entry {}: {:?}", name, err); + Status::Error(err) + } + }; + + self.queue.entry(name).and_modify(|status| { + *status = new_status; + }); + + if self.queue.values().all(|entry| match entry { + Status::InProgress => false, + Status::Success | Status::Error(_) => true, + }) { + self.enabled = true; + } + + Task::none() + } + } + } + + fn selected_entries<'a>( + &self, + context: &'a Context, + ) -> impl Iterator { + context.entries.iter().filter(|entry| { + *context + .state + .selections + .get(entry.name()) + .unwrap_or(&context.state.default_selection) + }) + } + + fn run(&mut self) -> Result> { + let datetime = time::OffsetDateTime::now_local().unwrap_or(time::OffsetDateTime::now_utc()); + + let backup_dir = self.paths.backup.join(format!( + "{:04}-{:02}-{:02}T{:02}-{:02}-{:02}", + datetime.year(), + u8::from(datetime.month()), + datetime.day(), + datetime.hour(), + datetime.minute(), + datetime.second() + )); + + // TODO: async? + log::info!("backing up to {:?}", backup_dir); + std::fs::create_dir_all(&backup_dir)?; + + self.queue = self + .selected_entries(self.context()) + .map(|entry| (entry.name().clone(), Status::InProgress)) + .collect::>(); + + self.enabled = false; + let context = self.context(); + match &context.state.from { + Some(from) => { + let from_entry = cascade_core::Entry::create(from)?; + let flags = cascade_core::Flags { + summary: false, + trickset: context.state.trickset, + scales: context.state.scales, + }; + + match self.state.app.game { + Game::Thug2 => run::( + from_entry, + context.entries.iter().cloned(), + &backup_dir, + flags, + ), + Game::Thaw => run::( + from_entry, + context.entries.iter().cloned(), + &backup_dir, + flags, + ), + } + } + None => { + self.enabled = true; + log::info!("cannot run with no 'from' entry"); + Ok(Task::none()) } - Message::Start => Task::none(), - Message::ToggleSelection(_) => todo!(), } } @@ -233,7 +359,7 @@ impl Cascade { .into() } - pub fn view_left(&self, game_state: &GameState) -> Element<'_, Message> { + fn view_left(&self, context: &Context) -> Element<'_, Message> { Column::new() .spacing(10) .push( @@ -246,14 +372,14 @@ impl Cascade { .on_press_maybe(self.enabled.then_some(Message::PickFrom)), ) .push(heading("from")) - .push(self.view_path(&game_state.from)), + .push(self.view_path(&context.state.from)), ) .push( - checkbox("trickset", game_state.trickset) + checkbox("trickset", context.state.trickset) .on_toggle_maybe(self.enabled.then_some(Message::SetTricksetFlag)), ) .push( - checkbox("scales", game_state.scales) + checkbox("scales", context.state.scales) .on_toggle_maybe(self.enabled.then_some(Message::SetScalesFlag)), ) .push(pick_list( @@ -266,7 +392,7 @@ impl Cascade { .into() } - fn view_center(&self, game_state: &GameState) -> Element<'_, Message> { + fn view_center(&self, context: &Context) -> Element<'_, Message> { Column::new() .spacing(10) .push( @@ -279,11 +405,11 @@ impl Cascade { .on_press_maybe(self.enabled.then_some(Message::PickToDir)), ) .push(heading("to")) - .push(self.view_path(&game_state.to_dir)), + .push(self.view_path(&context.state.to_dir)), ) .push( button( - text(match game_state.default_selection { + text(match context.state.default_selection { true => "deselect all", false => "select all", }) @@ -298,12 +424,31 @@ impl Cascade { ) .width(Length::Fill) // TODO: - // .push(scrollable(self.view_entries())) + .push(scrollable(self.view_entries())) + .into() + } + + fn view_right(&self) -> Element<'_, Message> { + Column::new() + .spacing(10) + .push( + Row::new() + .spacing(10) + .align_y(Vertical::Center) + .push( + button(text("\u{E803}").font(fonts::ICONS_FONT)) + .on_press_maybe(self.enabled.then_some(Message::Run)), + ) + .push(heading("queue")), + ) + // TODO: + .push(self.view_queue()) + .width(Length::Fill) .into() } - fn view_entries(&self) -> Element { - let context: &Context = self.context(); + fn view_entries(&self) -> Element<'_, Message> { + let context: &Context = self.context(); context .entries .iter() @@ -312,7 +457,7 @@ impl Cascade { let selected = context .state .selections - .get(&name) + .get(name) .unwrap_or(&context.state.default_selection); column.push(widget::entry::selectable( @@ -364,23 +509,30 @@ impl Cascade { } } - fn view_right(&self) -> Element<'_, Message> { - Column::new() - .spacing(10) - .push( - Row::new() - .spacing(10) - .align_y(Vertical::Center) - .push( - button(text("\u{E803}").font(fonts::ICONS_FONT)) - .on_press_maybe(self.enabled.then_some(Message::Start)), - ) - .push(heading("queue")), - ) - // TODO: - // .push(self.view_queue()) - .width(Length::Fill) - .into() + fn view_queue(&self) -> Element<'_, Message> { + let context = self.context(); + scrollable(self.selected_entries(context).fold( + Column::new().spacing(2), + |column, entry| { + let name = entry.name(); + let style = match self.queue.get(name) { + Some(Status::InProgress) => theme::button::entry_warning, + Some(Status::Success) => theme::button::entry_success, + Some(Status::Error(_)) => theme::button::entry_danger, + None => theme::button::entry_queued, + }; + column.push( + button(text(name)) + .style(style) + .on_press_maybe( + self.enabled + .then_some(Message::ToggleSelection(name.clone())), + ) + .width(Length::Fill), + ) + }, + )) + .into() } pub fn subscription(&self) -> Subscription { @@ -405,7 +557,52 @@ async fn pick_to_dir() -> Option { Some(AsyncFileDialog::new().pick_folder().await?.path().into()) } -struct Contexts { - thug2: Context, - thaw: Context, +fn run( + from: cascade_core::Entry, + to: impl IntoIterator, + backup_dir: &PathBuf, + flags: cascade_core::Flags, +) -> Result> +where + Save: cascade_core::Save + 'static, + Cas: cascade_core::Cas + 'static, +{ + let transform = Arc::new(Cas::parse(&Save::read(&mut from.reader()?)?)?.mask(flags)); + + Ok(Task::batch(to.into_iter().map(|entry| { + Task::perform( + process_entry(entry.clone(), backup_dir.clone(), Arc::clone(&transform)), + move |result| Message::EntryProcessed(entry.name().clone(), result), + ) + }))) +} + +async fn process_entry( + entry: cascade_core::Entry, + backup_dir: impl AsRef, + transform: Arc, +) -> Result<()> +where + Save: cascade_core::Save, + Cas: cascade_core::Cas, +{ + let backup_dir = backup_dir.as_ref(); + + let backup_entry = entry.with_dir(backup_dir); + let backup_path = backup_entry.path(); + + let path = entry.path(); + + log::info!("backing up {:?} to {:?}", path, backup_path); + tokio::fs::copy(&path, &backup_path).await?; + + let mut save = Save::read(&mut entry.reader()?)?; + + transform.modify(&mut save)?; + save.write(&mut entry.writer()?)?; + entry.rewrite_metadata()?; + + log::info!("overwrote save at {:?}", path); + + Ok(()) } diff --git a/crates/cascade-app/src/config/mod.rs b/crates/cascade-app/src/config/mod.rs index 792a757..9460ea6 100644 --- a/crates/cascade-app/src/config/mod.rs +++ b/crates/cascade-app/src/config/mod.rs @@ -1,33 +1,4 @@ -use std::io; - -use ron::de::SpannedError; - -use crate::paths; - pub mod frappe; -pub mod options; -pub mod selections; pub mod theme; pub use theme::Theme; - -#[derive(thiserror::Error, Debug, Clone)] -pub enum Error { - #[error("io error: {0}")] - Io(io::ErrorKind), - - #[error("paths error: {0}")] - Paths(#[from] paths::Error), - - #[error("ron deserialization error: {0}")] - Ron(#[from] SpannedError), - - #[error("toml deserialization error: {0}")] - Toml(#[from] toml::de::Error), -} - -impl From for Error { - fn from(value: io::Error) -> Self { - Self::Io(value.kind()) - } -} diff --git a/crates/cascade-app/src/config/options.rs b/crates/cascade-app/src/config/options.rs deleted file mode 100644 index 58713af..0000000 --- a/crates/cascade-app/src/config/options.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::{ - fs, io, - path::{Path, PathBuf}, -}; - -use serde::{Deserialize, Serialize}; - -use crate::{config::Error, paths}; - -fn default_scale_factor() -> f64 { - 1. -} - -fn default_saves_dir() -> Option { - match paths::default_saves_dir() { - Ok(dir) => { - log::info!("autodetected thug pro saves dir at {:?}", dir); - Some(dir) - } - Err(err) => { - log::warn!("could not autodetect thug pro saves dir: {}", err); - None - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Config { - #[serde(default)] - pub saves_dir: Option, - #[serde(default)] - pub source_path: Option, - #[serde(default = "default_scale_factor")] - pub scale_factor: f64, - #[serde(default)] - pub default_selection: bool, - #[serde(default)] - pub scales: bool, - #[serde(default)] - pub trickset: bool, -} - -impl Default for Config { - fn default() -> Self { - Self { - saves_dir: default_saves_dir(), - source_path: None, - scale_factor: 1., - default_selection: true, - scales: false, - trickset: false, - } - } -} - -impl Config { - pub fn load(path: impl AsRef) -> Result { - let file = fs::File::open(&path)?; - - log::info!("reading config from {:?}", path.as_ref()); - - let contents = io::read_to_string(file)?; - - let config = toml::from_str(contents.as_str())?; - - Ok(config) - } -} diff --git a/crates/cascade-app/src/config/selections.rs b/crates/cascade-app/src/config/selections.rs deleted file mode 100644 index 753aa30..0000000 --- a/crates/cascade-app/src/config/selections.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::{collections::HashMap, fs, io, ops::Deref, path::Path}; - -use serde::{Deserialize, Serialize}; - -use crate::config::Error; - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct Selections(HashMap); - -impl Selections { - pub fn load(path: impl AsRef) -> Result { - let file = fs::File::open(&path)?; - - log::info!("reading selections from {:?}", path.as_ref()); - - let contents = io::read_to_string(file)?; - - let config = ron::from_str(contents.as_str())?; - - Ok(config) - } -} - -impl From> for Selections { - fn from(value: HashMap) -> Self { - Self(value) - } -} - -impl Deref for Selections { - type Target = HashMap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} diff --git a/crates/cascade-app/src/config/theme.rs b/crates/cascade-app/src/config/theme.rs index 19ac9c6..de25bbc 100644 --- a/crates/cascade-app/src/config/theme.rs +++ b/crates/cascade-app/src/config/theme.rs @@ -1,9 +1,9 @@ use std::{fs, io, path::Path}; -use iced::{application, Color}; +use iced::{Color, application}; use serde::{Deserialize, Serialize}; -use crate::config::{frappe, Error}; +use crate::{Result, config::frappe}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Theme { @@ -41,7 +41,7 @@ impl Default for Theme { } impl Theme { - pub fn load(path: impl AsRef) -> Result { + pub fn load(path: impl AsRef) -> Result { let file = fs::File::open(&path)?; log::info!("reading theme from {:?}", path.as_ref()); diff --git a/crates/cascade-app/src/error.rs b/crates/cascade-app/src/error.rs index 1544f93..e3c87de 100644 --- a/crates/cascade-app/src/error.rs +++ b/crates/cascade-app/src/error.rs @@ -15,6 +15,9 @@ pub enum Error { #[error("toml deserialization error: {0}")] Toml(#[from] toml::de::Error), + + #[error("core error: {0}")] + Core(#[from] cascade_core::Error), } impl From for Error { diff --git a/crates/cascade-app/src/paths.rs b/crates/cascade-app/src/paths.rs index f9d7558..c419fff 100644 --- a/crates/cascade-app/src/paths.rs +++ b/crates/cascade-app/src/paths.rs @@ -16,12 +16,6 @@ pub enum Error { #[error("no home directory was found")] NoHomeDir, - #[error("no thug pro directory was found")] - NoThugProDir, - - #[error("no thug pro saves directory was found")] - NoThugProSavesDir, - #[error("could not determine cwd")] Cwd, } @@ -43,23 +37,15 @@ fn local_appdata_dir() -> Result { } } -pub fn default_thugpro_dir() -> Result { - // %localappdata%/THUG Pro/ - let path = local_appdata_dir().map(|dir| dir.join("THUG Pro"))?; - - match path.is_dir() { - true => Ok(path), - false => Err(Error::NoThugProDir), - } -} - -pub fn default_saves_dir() -> Result { +pub fn detect_thugpro_dir() -> Option { // %localappdata%/THUG Pro/Save/ - let path = default_thugpro_dir().map(|dir| dir.join("Save"))?; - - match path.is_dir() { - true => Ok(path), - false => Err(Error::NoThugProSavesDir), + if let Some(path) = local_appdata_dir() + .map(|dir| dir.join("THUG Pro").join("Save")) + .ok() + { + if path.is_dir() { Some(path) } else { None } + } else { + None } } @@ -111,14 +97,16 @@ pub struct Paths { pub app: PathBuf, pub thug2: PathBuf, pub thaw: PathBuf, + pub backup: PathBuf, } impl Paths { pub fn new(data_dir: &PathBuf) -> Self { Self { - app: data_dir.join("cascade.ron"), + app: data_dir.join("app.ron"), thug2: data_dir.join("thug2.ron"), thaw: data_dir.join("thaw.ron"), + backup: data_dir.join("backup"), } } } diff --git a/crates/cascade-app/src/state.rs b/crates/cascade-app/src/state.rs index ad2acd6..93b5c63 100644 --- a/crates/cascade-app/src/state.rs +++ b/crates/cascade-app/src/state.rs @@ -7,7 +7,10 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{Result, paths::Paths}; +use crate::{ + Result, + paths::{self, Paths}, +}; #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub enum Game { @@ -41,6 +44,10 @@ pub struct AppState { pub game: Game, } +fn default_scale_factor() -> f64 { + 1. +} + impl Default for AppState { fn default() -> Self { Self { @@ -64,9 +71,6 @@ impl AppState { } } -// #[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub type Selections = HashMap; - #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct GameState { #[serde(default)] @@ -80,10 +84,7 @@ pub struct GameState { #[serde(default)] pub default_selection: bool, #[serde(default)] - pub selections: Selections, -} -fn default_scale_factor() -> f64 { - 1. + pub selections: HashMap, } impl GameState { @@ -98,6 +99,17 @@ impl GameState { Ok(config) } + + pub fn detect(default_dir: Option) -> Self { + if let Some(to_dir) = paths::detect_thugpro_dir() { + Self { + to_dir: Some(to_dir), + ..Default::default() + } + } else { + Default::default() + } + } } #[derive(Debug)] @@ -108,7 +120,8 @@ pub struct GameStates { impl GameStates { pub fn load(paths: &Paths) -> Self { - let thug2 = GameState::load(&paths.thug2).unwrap_or_default(); + let thug2 = + GameState::load(&paths.thug2).unwrap_or(GameState::detect(paths::detect_thugpro_dir())); let thaw = GameState::load(&paths.thaw).unwrap_or_default(); Self { thug2, thaw } diff --git a/crates/cascade-cli/src/main.rs b/crates/cascade-cli/src/main.rs index bd2e60d..f69f5d6 100644 --- a/crates/cascade-cli/src/main.rs +++ b/crates/cascade-cli/src/main.rs @@ -1,7 +1,7 @@ use std::{ fmt::Debug, fs, - io::{self, BufReader, BufWriter}, + io::{BufReader, BufWriter}, path::PathBuf, }; @@ -209,8 +209,8 @@ fn main() -> color_eyre::Result<()> { } match game { - Game::Thug2 => modify::(&from, &to, flags)?, - Game::Thaw => modify::(&from, &to, flags)?, + Game::Thug2 => modify::(&from, &to, flags)?, + Game::Thaw => modify::(&from, &to, flags)?, } log::info!("successfully copied to {}", to.display()); @@ -235,8 +235,14 @@ fn main() -> color_eyre::Result<()> { } match game { - Game::Thug2 => modify_bulk(&from, thug2::Core::new(to_dir), flags)?, - Game::Thaw => modify_bulk(&from, thaw::Core::new(to_dir), flags)?, + Game::Thug2 => modify_bulk::( + &from, + thug2::find_entries(&to_dir), + flags, + )?, + Game::Thaw => { + modify_bulk::(&from, thaw::find_entries(&to_dir), flags)? + } } Ok(()) @@ -297,15 +303,14 @@ fn main() -> color_eyre::Result<()> { } } -fn modify( +fn modify( from: &PathBuf, to: &PathBuf, flags: cascade_core::Flags, -) -> Result<(), Error> +) -> Result<(), cascade_core::Error> where - Save: cascade_core::Save, - Cas: cascade_core::Cas, - Error: From + Debug, + Save: cascade_core::Save, + Cas: cascade_core::Cas, { let from_file = fs::File::open(&from)?; let mut from_reader = BufReader::new(from_file); @@ -326,23 +331,22 @@ where Ok(()) } -fn modify_bulk( +fn modify_bulk( from: &PathBuf, - core: impl cascade_core::Core, + to_entries: Vec, flags: cascade_core::Flags, -) -> Result<(), Error> +) -> cascade_core::Result<()> where - Entry: cascade_core::Entry, - Save: cascade_core::Save, - Cas: cascade_core::Cas, - Error: From + Debug, + Save: cascade_core::Save, + Cas: cascade_core::Cas, { - fn modify_one(entry: &Entry, transform: &Cas) -> Result<(), Error> + fn modify_one( + entry: &cascade_core::Entry, + transform: &Cas, + ) -> cascade_core::Result<()> where - Entry: cascade_core::Entry, - Save: cascade_core::Save, - Cas: cascade_core::Cas, - Error: From + Debug, + Save: cascade_core::Save, + Cas: cascade_core::Cas, { let mut reader = entry.reader()?; let mut save = Save::read(&mut reader)?; @@ -361,7 +365,7 @@ where let from_parsed = Cas::parse(&from_save)?; let transform = from_parsed.mask(flags); - for entry in core.entries()? { + for entry in to_entries { let name = entry.name(); match modify_one(&entry, &transform) { Ok(_) => { diff --git a/crates/cascade-core/Cargo.toml b/crates/cascade-core/Cargo.toml index 87608e7..09a27d8 100644 --- a/crates/cascade-core/Cargo.toml +++ b/crates/cascade-core/Cargo.toml @@ -4,7 +4,13 @@ version = "0.0.1" edition = { workspace = true } [dependencies] +cascade-qb = { workspace = true } +cascade-save = { workspace = true } + +filetime = { workspace = true } +log = { workspace = true } serde = { workspace = true, optional = true } +thiserror = { workspace = true } [features] serde = ["dep:serde"] diff --git a/crates/cascade-core/src/cas.rs b/crates/cascade-core/src/cas.rs index 8022bc2..ce53938 100644 --- a/crates/cascade-core/src/cas.rs +++ b/crates/cascade-core/src/cas.rs @@ -1,4 +1,4 @@ -use crate::save; +use crate::{Result, save}; #[derive(Debug, Clone, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -8,11 +8,10 @@ pub struct Flags { pub scales: bool, } -pub trait Cas: Sized { - type Error; +pub trait Cas: Sized + Send + Sync { type Save: save::Save; - fn parse(save: &Self::Save) -> Result; - fn modify(&self, save: &mut Self::Save) -> Result<(), Self::Error>; + fn parse(save: &Self::Save) -> Result; + fn modify(&self, save: &mut Self::Save) -> Result<()>; fn mask(self, flags: Flags) -> Self; } diff --git a/crates/cascade-core/src/entry.rs b/crates/cascade-core/src/entry.rs index ba504d8..7831ea3 100644 --- a/crates/cascade-core/src/entry.rs +++ b/crates/cascade-core/src/entry.rs @@ -1,10 +1,86 @@ -use std::io::{Read, Seek, Write}; +use std::{ + fs, + io::{BufReader, BufWriter, Read, Seek, Write}, + path::{Path, PathBuf}, +}; -pub trait Entry { - type Error; +use crate::{Error, Result}; - fn reader(&self) -> Result; - fn writer(&self) -> Result; - fn name(&self) -> String; - fn rewrite_metadata(&self) -> Result<(), Self::Error>; +#[derive(Debug, Clone)] +pub struct Entry { + pub path: PathBuf, + pub dir: PathBuf, + pub filename: String, + pub metadata: Option, +} + +impl Entry { + pub fn create(path: impl AsRef) -> Result { + let path = path.as_ref(); + + let metadata = fs::metadata(path).ok(); + let filename = path + .file_name() + .map(|s| s.to_string_lossy().into()) + .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(path)))?; + + let dir = path + .parent() + .map(PathBuf::from) + .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(path)))?; + + Ok(Self { + path: PathBuf::from(path), + dir, + filename, + metadata, + }) + } + + pub fn with_dir>(&self, dir: P) -> Self { + let dir = PathBuf::from(dir.as_ref()); + Self { + path: dir.join(&self.filename), + dir: PathBuf::from(dir), + filename: self.filename.clone(), + metadata: self.metadata.clone(), + } + } + + pub fn path(&self) -> &PathBuf { + &self.path + } + + pub fn reader(&self) -> Result { + let file = fs::File::open(&self.path)?; + Ok(BufReader::new(file)) + } + + pub fn writer(&self) -> Result { + let file = fs::File::create(&self.path)?; + Ok(BufWriter::new(file)) + } + + pub fn name(&self) -> &String { + &self.filename + } + + pub fn rewrite_metadata(&self) -> Result<()> { + if let Some(metadata) = &self.metadata { + let filepath = &self.path; + + // TODO: this should probably be configurable + let original_mod_time = filetime::FileTime::from_last_modification_time(metadata); + + // TODO: how tf do i format this + log::info!( + "setting file modification time for {:?} to {:?}", + filepath, + original_mod_time + ); + filetime::set_file_mtime(&filepath, original_mod_time)?; + } + + Ok(()) + } } diff --git a/crates/cascade-thaw/src/error.rs b/crates/cascade-core/src/error.rs similarity index 70% rename from crates/cascade-thaw/src/error.rs rename to crates/cascade-core/src/error.rs index 1ca8a54..1cbc7b8 100644 --- a/crates/cascade-thaw/src/error.rs +++ b/crates/cascade-core/src/error.rs @@ -1,32 +1,24 @@ use std::{io, path::PathBuf, result}; -use cascade_qb as qb; -use cascade_save as save; - -use crate::chunk; - #[derive(thiserror::Error, Debug, Clone)] pub enum Error { #[error("io error: {0}")] Io(io::ErrorKind), #[error("qb error: {0}")] - Qb(#[from] qb::Error), + Qb(#[from] cascade_qb::Error), #[error("save error: {0}")] - Save(#[from] save::Error), + Save(#[from] cascade_save::Error), #[error("unknown chunk magic: {0}")] UnknownChunkMagic(u32), #[error("symbol not found: {0}")] - SymbolNotFound(qb::Id), + SymbolNotFound(cascade_qb::Id), #[error("chunk not found: {0}")] - ChunkNotFound(chunk::Magic), - - #[error("no such directory: \"{0}\"")] - NoSuchDirectory(PathBuf), + ChunkNotFound(String), #[error("invalid save file path: \"{0}\"")] InvalidSaveFilePath(PathBuf), diff --git a/crates/cascade-core/src/lib.rs b/crates/cascade-core/src/lib.rs index 0014ed1..a0b0c64 100644 --- a/crates/cascade-core/src/lib.rs +++ b/crates/cascade-core/src/lib.rs @@ -1,21 +1,14 @@ mod cas; mod entry; +mod error; mod save; -use std::{fmt::Display, path::Path}; - pub use cas::{Cas, Flags}; -pub use entry::Entry; +pub use entry::Entry as Entry; +pub use error::{Error, Result}; pub use save::Save; pub trait Core { - type Entry: entry::Entry; type Save: save::Save; type Cas: cas::Cas; - type Error: Display; - - fn entries( - &self, - dir: impl AsRef, - ) -> Result, Self::Error>; } diff --git a/crates/cascade-core/src/save.rs b/crates/cascade-core/src/save.rs index d6e8f09..3706c9e 100644 --- a/crates/cascade-core/src/save.rs +++ b/crates/cascade-core/src/save.rs @@ -1,8 +1,8 @@ use std::io::{Read, Seek, Write}; -pub trait Save: Sized { - type Error; +use crate::Result; - fn read(reader: &mut (impl Read + Seek)) -> Result; - fn write(&self, writer: &mut (impl Write + Seek)) -> Result<(), Self::Error>; +pub trait Save: Sized { + fn read(reader: &mut (impl Read + Seek)) -> Result; + fn write(&self, writer: &mut (impl Write + Seek)) -> Result<()>; } diff --git a/crates/cascade-save/Cargo.toml b/crates/cascade-save/Cargo.toml index 3121c9a..6394bd0 100644 --- a/crates/cascade-save/Cargo.toml +++ b/crates/cascade-save/Cargo.toml @@ -6,7 +6,6 @@ edition = { workspace = true } [dependencies] cascade-crc = { workspace = true } cascade-qb = { workspace = true } -cascade-core = { workspace = true } byteorder = { workspace = true } count-write = { workspace = true } diff --git a/crates/cascade-save/src/save.rs b/crates/cascade-save/src/save.rs index 5fbd749..3afc795 100644 --- a/crates/cascade-save/src/save.rs +++ b/crates/cascade-save/src/save.rs @@ -5,7 +5,7 @@ use cascade_crc as crc; use cascade_qb as qb; use count_write::CountWrite; -use crate::{Error, Result}; +use crate::Result; const SAVE_FILE_SIZE: usize = 90112; const PADDING_BYTE: u8 = 0x69; @@ -63,10 +63,10 @@ pub struct Save { pub data: Box, } -impl cascade_core::Save for Save { - type Error = Error; +impl Save { + // type Error = Error; - fn read(reader: &mut (impl Read + Seek)) -> Result { + pub fn read(reader: &mut (impl Read + Seek)) -> Result { Ok(Self { header: Header::read(reader)?, summary: Box::new(qb::Structure::read(reader)?), @@ -74,7 +74,7 @@ impl cascade_core::Save for Save { }) } - fn write(&self, writer: &mut (impl Write + Seek)) -> Result<()> { + pub fn write(&self, writer: &mut (impl Write + Seek)) -> Result<()> { let mut count_writer = CountWrite::from(writer); let header = self.calculate_header()?; @@ -98,9 +98,7 @@ impl cascade_core::Save for Save { Ok(()) } -} -impl Save { fn calculate_header(&self) -> Result
{ // TODO use seek instead of serializing save twice let mut summary_bytes = self.summary.raw_bytes()?; diff --git a/crates/cascade-thaw/src/cas.rs b/crates/cascade-thaw/src/cas.rs index 988fccc..2371cbe 100644 --- a/crates/cascade-thaw/src/cas.rs +++ b/crates/cascade-thaw/src/cas.rs @@ -1,17 +1,27 @@ use cascade_qb as qb; -use crate::{Error, Result, chunk, id, save::Save}; +use crate::{chunk, id, save::Save}; -fn expect_symbol(parent: &Box, id: qb::Id) -> Result<&qb::Symbol> { - Ok(parent.get(id).ok_or(Error::SymbolNotFound(id))?) +fn expect_symbol(parent: &Box, id: qb::Id) -> cascade_core::Result<&qb::Symbol> { + Ok(parent + .get(id) + .ok_or(cascade_core::Error::SymbolNotFound(id))?) } -fn expect_symbol_mut(parent: &mut Box, id: qb::Id) -> Result<&mut qb::Symbol> { - Ok(parent.get_mut(id).ok_or(Error::SymbolNotFound(id))?) +fn expect_symbol_mut( + parent: &mut Box, + id: qb::Id, +) -> cascade_core::Result<&mut qb::Symbol> { + Ok(parent + .get_mut(id) + .ok_or(cascade_core::Error::SymbolNotFound(id))?) } // expect symbol and expect structure -fn expect_structure(parent: &Box, id: qb::Id) -> Result<&Box> { +fn expect_structure( + parent: &Box, + id: qb::Id, +) -> cascade_core::Result<&Box> { let symbol = expect_symbol(&parent, id)?; Ok(symbol.value.try_as_structure()?) } @@ -19,7 +29,7 @@ fn expect_structure(parent: &Box, id: qb::Id) -> Result<&Box, id: qb::Id, -) -> Result<&mut Box> { +) -> cascade_core::Result<&mut Box> { let symbol = expect_symbol_mut(parent, id)?; Ok(symbol.value.try_as_structure_mut()?) } @@ -73,14 +83,13 @@ pub struct Cas { } impl cascade_core::Cas for Cas { - type Error = Error; type Save = Save; - fn parse(save: &Self::Save) -> Result { + fn parse(save: &Self::Save) -> cascade_core::Result { Self::try_from(save) } - fn modify(&self, save: &mut Self::Save) -> Result<()> { + fn modify(&self, save: &mut Self::Save) -> cascade_core::Result<()> { self.modify(save) } @@ -259,9 +268,9 @@ impl cascade_core::Cas for Cas { } impl TryFrom<&Save> for Cas { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(save: &Save) -> Result { + fn try_from(save: &Save) -> cascade_core::Result { match save { Save::Thaw(save) => Ok(Self { summary: Summary::try_from(&save.summary)?, @@ -276,7 +285,7 @@ impl TryFrom<&Save> for Cas { } impl Cas { - pub fn modify(&self, save: &mut Save) -> Result<()> { + pub fn modify(&self, save: &mut Save) -> cascade_core::Result<()> { self.summary.modify(match save { Save::Thaw(save) => &mut save.summary, Save::Rethawed(save) => &mut save.try_get_chunk_mut(chunk::Magic::Summary)?.structure, @@ -302,9 +311,9 @@ impl Summary { } impl TryFrom<&Box> for Summary { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(summary: &Box) -> Result { + fn try_from(summary: &Box) -> cascade_core::Result { Ok(Self { filename: summary.get(id::FILENAME).cloned().into(), }) @@ -319,9 +328,9 @@ pub struct Data { } impl TryFrom<&Box> for Data { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(data: &Box) -> Result { + fn try_from(data: &Box) -> cascade_core::Result { Ok(Self { custom_skater: CustomSkater::try_from(expect_structure(data, id::CUSTOM_SKATER)?)?, story_skater: StorySkater::try_from(expect_structure(data, id::STORY_SKATER)?)?, @@ -330,7 +339,7 @@ impl TryFrom<&Box> for Data { } impl Data { - pub fn modify(&self, data: &mut Box) -> Result<()> { + pub fn modify(&self, data: &mut Box) -> cascade_core::Result<()> { self.custom_skater .modify(expect_structure_mut(data, id::CUSTOM_SKATER)?)?; @@ -348,9 +357,9 @@ pub struct CustomSkater { } impl TryFrom<&Box> for CustomSkater { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(custom_skater: &Box) -> Result { + fn try_from(custom_skater: &Box) -> cascade_core::Result { Ok(Self { custom_classic: CustomClassic::try_from(expect_structure( custom_skater, @@ -361,7 +370,7 @@ impl TryFrom<&Box> for CustomSkater { } impl CustomSkater { - pub fn modify(&self, custom_skater: &mut Box) -> Result<()> { + pub fn modify(&self, custom_skater: &mut Box) -> cascade_core::Result<()> { self.custom_classic .modify(expect_structure_mut(custom_skater, id::CUSTOM_CLASSIC)?)?; Ok(()) @@ -376,9 +385,9 @@ pub struct CustomClassic { } impl TryFrom<&Box> for CustomClassic { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(custom: &Box) -> Result { + fn try_from(custom: &Box) -> cascade_core::Result { Ok(Self { appearance: Appearance::try_from(expect_structure(custom, id::APPEARANCE)?)?, info: Info::try_from(expect_structure(custom, id::INFO)?)?, @@ -387,7 +396,7 @@ impl TryFrom<&Box> for CustomClassic { } impl CustomClassic { - pub fn modify(&self, custom: &mut Box) -> Result<()> { + pub fn modify(&self, custom: &mut Box) -> cascade_core::Result<()> { self.appearance .modify(expect_structure_mut(custom, id::APPEARANCE)?); self.info.modify(expect_structure_mut(custom, id::INFO)?); @@ -404,9 +413,9 @@ pub struct Info { } impl TryFrom<&Box> for Info { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(info: &Box) -> Result { + fn try_from(info: &Box) -> cascade_core::Result { Ok(Self { trick_mapping: info.get(id::TRICK_MAPPING).cloned().into(), specials: info.get(id::SPECIALS).cloned().into(), @@ -469,9 +478,9 @@ impl Appearance { } impl TryFrom<&Box> for Appearance { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(structure: &Box) -> Result { + fn try_from(structure: &Box) -> cascade_core::Result { Ok(Self { board_bone_group: structure.get(id::BOARD_BONE_GROUP).cloned().into(), feet_bone_group: structure.get(id::FEET_BONE_GROUP).cloned().into(), @@ -498,9 +507,9 @@ pub struct StorySkater { } impl TryFrom<&Box> for StorySkater { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(structure: &Box) -> Result { + fn try_from(structure: &Box) -> cascade_core::Result { Ok(Self { tricks: structure.get(id::TRICKS).cloned().into(), }) diff --git a/crates/cascade-thaw/src/chunk.rs b/crates/cascade-thaw/src/chunk.rs index 7a3c3db..e9146c7 100644 --- a/crates/cascade-thaw/src/chunk.rs +++ b/crates/cascade-thaw/src/chunk.rs @@ -6,8 +6,6 @@ use std::{ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use cascade_qb as qb; -use crate::{Error, Result}; - pub const MAGIC_DATA: u32 = 0x39137FE5; pub const MAGIC_SUMMARY: u32 = 0x31D7999C; @@ -25,13 +23,13 @@ impl fmt::Display for Magic { } impl TryFrom for Magic { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(value: u32) -> Result { + fn try_from(value: u32) -> cascade_core::Result { match value { MAGIC_DATA => Ok(Magic::Data), MAGIC_SUMMARY => Ok(Magic::Summary), - _ => Err(Error::UnknownChunkMagic(value)), + _ => Err(cascade_core::Error::UnknownChunkMagic(value)), } } } @@ -53,7 +51,7 @@ pub struct Chunk { } impl Chunk { - pub fn read(reader: &mut impl Read) -> Result { + pub fn read(reader: &mut impl Read) -> cascade_core::Result { let magic = reader.read_u32::()?.try_into()?; let size = reader.read_u32::()?; let structure = Box::new(qb::Structure::read(reader)?); @@ -68,7 +66,7 @@ impl Chunk { }) } - pub fn write(&self, writer: &mut impl Write) -> Result<()> { + pub fn write(&self, writer: &mut impl Write) -> cascade_core::Result<()> { let chunk_size = self.structure.raw_bytes()?.len(); writer.write_u32::(self.magic.into())?; writer.write_u32::(chunk_size as u32)?; diff --git a/crates/cascade-thaw/src/core.rs b/crates/cascade-thaw/src/core.rs deleted file mode 100644 index 829cf81..0000000 --- a/crates/cascade-thaw/src/core.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::path::Path; - -use crate::{ - Error, Result, - cas::Cas, - entry::{Entry, find_entries}, - save::Save, -}; - -pub struct Core {} - -impl cascade_core::Core for Core { - type Entry = Entry; - type Save = Save; - type Cas = Cas; - type Error = Error; - - fn entries(&self, dir: impl AsRef) -> Result> { - find_entries(dir) - } -} diff --git a/crates/cascade-thaw/src/entry.rs b/crates/cascade-thaw/src/entry.rs index 8971dcf..89a0d0d 100644 --- a/crates/cascade-thaw/src/entry.rs +++ b/crates/cascade-thaw/src/entry.rs @@ -1,130 +1,39 @@ -use std::{ - fs::{self}, - hash::{Hash, Hasher}, - io::{BufReader, BufWriter, Read, Seek, Write}, - path::{Path, PathBuf}, -}; - -use crate::{Error, Result}; - -#[derive(Debug, Clone)] -pub struct Entry { - pub path: PathBuf, - pub dir: PathBuf, - pub filename: String, - pub metadata: Option, -} - -impl cascade_core::Entry for Entry { - type Error = Error; - - fn reader(&self) -> Result { - let file = fs::File::open(&self.path)?; - Ok(BufReader::new(file)) - } - - fn writer(&self) -> std::result::Result { - let file = fs::File::create(&self.path)?; - Ok(BufWriter::new(file)) - } - - fn name(&self) -> String { - self.filename.clone() - } - - fn rewrite_metadata(&self) -> std::result::Result<(), Self::Error> { - if let Some(metadata) = &self.metadata { - let filepath = &self.path; - - // TODO: this should probably be configurable - let original_mod_time = filetime::FileTime::from_last_modification_time(metadata); - - // TODO: how tf do i format this - log::info!( - "setting file modification time for {:?} to {:?}", - filepath, - original_mod_time - ); - filetime::set_file_mtime(&filepath, original_mod_time)?; - } - - Ok(()) - } -} - -impl Hash for Entry { - fn hash(&self, state: &mut H) { - self.path.hash(state); - } -} - -impl PartialEq for Entry { - fn eq(&self, other: &Self) -> bool { - // TODO: store filepath in entry - self.path == other.path - } -} - -impl Eq for Entry {} - -impl Entry { - pub fn create(path: impl AsRef) -> Result { - let path = path.as_ref(); - - let metadata = fs::metadata(path).ok(); - let filename = path - .file_name() - .map(|s| s.to_string_lossy().into()) - .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(path)))?; - - let dir = path - .parent() - .map(PathBuf::from) - .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(path)))?; - - Ok(Self { - path: PathBuf::from(path), - dir, - filename, - metadata, - }) - } -} - -pub fn find_entries(dir: impl AsRef) -> Result> { - let dir = PathBuf::from(dir.as_ref()); - - dir.is_dir() - .then(|| ()) - .ok_or_else(|| Error::NoSuchDirectory(dir.clone()))?; - - log::info!("finding entries in {:?}", dir); - - Ok(dir - .read_dir()? - .filter_map(|file| file.ok()) - .filter_map(|file| { - let filepath = file.path(); - log::info!("found file at {:?}", filepath); - - // oops i should probably make this cleaner - if let Some(filename) = filepath.file_name() { - if filename.to_string_lossy().ends_with("-Progress") { - match Entry::create(&filepath) { - Ok(save) => { - log::info!("found entry {:?}", filepath); - Some(save) - } - Err(e) => { - log::warn!("error loading entry {:?}: {}", filepath, e); +use std::path::PathBuf; + +pub fn find_entries(dir: &PathBuf) -> Vec { + match dir.read_dir() { + Ok(dir) => { + log::info!("finding entries in {:?}", dir); + dir.filter_map(|file| file.ok()) + .filter_map(|file| { + let filepath = file.path(); + log::info!("found file at {:?}", filepath); + + // oops i should probably make this cleaner + if let Some(filename) = filepath.file_name() { + if filename.to_string_lossy().ends_with("-Progress") { + match cascade_core::Entry::create(&filepath) { + Ok(save) => { + log::info!("found entry {:?}", filepath); + Some(save) + } + Err(e) => { + log::warn!("error loading entry {:?}: {}", filepath, e); + None + } + } + } else { None } + } else { + None } - } else { - None - } - } else { - None - } - })) + }) + .collect() + } + Err(err) => { + log::error!("error reading directory {:?}: {}", dir, err); + Vec::new() + } + } } diff --git a/crates/cascade-thaw/src/lib.rs b/crates/cascade-thaw/src/lib.rs index bbbe56d..c3c7b9c 100644 --- a/crates/cascade-thaw/src/lib.rs +++ b/crates/cascade-thaw/src/lib.rs @@ -1,18 +1,13 @@ mod cas; mod chunk; -mod core; #[cfg(feature = "lut")] pub mod dump; mod entry; -mod error; mod id; #[cfg(feature = "lut")] pub mod lut; mod save; -pub use core::Core; - pub use cas::Cas; -pub use entry::Entry; -pub use error::{Error, Result}; +pub use entry::find_entries; pub use save::Save; diff --git a/crates/cascade-thaw/src/save.rs b/crates/cascade-thaw/src/save.rs index 15f873d..183b4ae 100644 --- a/crates/cascade-thaw/src/save.rs +++ b/crates/cascade-thaw/src/save.rs @@ -3,10 +3,7 @@ use std::io::{Read, Seek, SeekFrom, Write}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use cascade_save as save; -use crate::{ - Error, Result, - chunk::{self, Chunk}, -}; +use crate::chunk::{self, Chunk}; #[derive(Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -18,9 +15,7 @@ pub struct Rethawed { } impl cascade_core::Save for Rethawed { - type Error = Error; - - fn read(reader: &mut (impl Read + Seek)) -> Result { + fn read(reader: &mut (impl Read + Seek)) -> cascade_core::Result { let magic = reader.read_u32::()?; let version = reader.read_u32::()?; let chunk_count = reader.read_u32::()?; @@ -38,7 +33,7 @@ impl cascade_core::Save for Rethawed { }) } - fn write(&self, writer: &mut (impl Write + Seek)) -> Result<()> { + fn write(&self, writer: &mut (impl Write + Seek)) -> cascade_core::Result<()> { writer.write_u32::(self.magic)?; writer.write_u32::(self.version)?; writer.write_u32::(self.chunk_count)?; @@ -58,18 +53,18 @@ impl Rethawed { self.chunks.iter().find(|chunk| chunk.magic == magic) } - pub fn try_get_chunk(&self, magic: chunk::Magic) -> Result<&Chunk> { + pub fn try_get_chunk(&self, magic: chunk::Magic) -> cascade_core::Result<&Chunk> { self.get_chunk(magic) - .ok_or_else(|| Error::ChunkNotFound(magic)) + .ok_or_else(|| cascade_core::Error::ChunkNotFound(format!("{}", magic))) } pub fn get_chunk_mut(&mut self, magic: chunk::Magic) -> Option<&mut Chunk> { self.chunks.iter_mut().find(|chunk| chunk.magic == magic) } - pub fn try_get_chunk_mut(&mut self, magic: chunk::Magic) -> Result<&mut Chunk> { + pub fn try_get_chunk_mut(&mut self, magic: chunk::Magic) -> cascade_core::Result<&mut Chunk> { self.get_chunk_mut(magic) - .ok_or_else(|| Error::ChunkNotFound(magic)) + .ok_or_else(|| cascade_core::Error::ChunkNotFound(format!("{}", magic))) } } @@ -81,9 +76,7 @@ pub enum Save { } impl cascade_core::Save for Save { - type Error = Error; - - fn read(reader: &mut (impl Read + Seek)) -> Result { + fn read(reader: &mut (impl Read + Seek)) -> cascade_core::Result { let magic = reader.read_u32::()?; reader.seek(SeekFrom::Start(0))?; @@ -94,7 +87,7 @@ impl cascade_core::Save for Save { } } - fn write(&self, writer: &mut (impl Write + Seek)) -> Result<()> { + fn write(&self, writer: &mut (impl Write + Seek)) -> cascade_core::Result<()> { match self { Save::Thaw(save) => Ok(save.write(writer)?), Save::Rethawed(save) => Ok(save.write(writer)?), diff --git a/crates/cascade-thug2/src/cas.rs b/crates/cascade-thug2/src/cas.rs index e845a31..708d93f 100644 --- a/crates/cascade-thug2/src/cas.rs +++ b/crates/cascade-thug2/src/cas.rs @@ -1,17 +1,27 @@ use cascade_qb as qb; -use crate::{Error, Result, Save, id}; +use crate::{Save, id}; -fn expect_symbol(parent: &Box, id: qb::Id) -> Result<&qb::Symbol> { - Ok(parent.get(id).ok_or(Error::SymbolNotFound(id))?) +fn expect_symbol(parent: &Box, id: qb::Id) -> cascade_core::Result<&qb::Symbol> { + Ok(parent + .get(id) + .ok_or(cascade_core::Error::SymbolNotFound(id))?) } -fn expect_symbol_mut(parent: &mut Box, id: qb::Id) -> Result<&mut qb::Symbol> { - Ok(parent.get_mut(id).ok_or(Error::SymbolNotFound(id))?) +fn expect_symbol_mut( + parent: &mut Box, + id: qb::Id, +) -> cascade_core::Result<&mut qb::Symbol> { + Ok(parent + .get_mut(id) + .ok_or(cascade_core::Error::SymbolNotFound(id))?) } // expect symbol and expect structure -fn expect_structure(parent: &Box, id: qb::Id) -> Result<&Box> { +fn expect_structure( + parent: &Box, + id: qb::Id, +) -> cascade_core::Result<&Box> { let symbol = expect_symbol(&parent, id)?; Ok(symbol.value.try_as_structure()?) } @@ -19,7 +29,7 @@ fn expect_structure(parent: &Box, id: qb::Id) -> Result<&Box, id: qb::Id, -) -> Result<&mut Box> { +) -> cascade_core::Result<&mut Box> { let symbol = expect_symbol_mut(parent, id)?; Ok(symbol.value.try_as_structure_mut()?) } @@ -73,14 +83,13 @@ pub struct Cas { } impl cascade_core::Cas for Cas { - type Error = Error; type Save = Save; - fn parse(save: &Save) -> Result { + fn parse(save: &Save) -> cascade_core::Result { Self::try_from(save) } - fn modify(&self, save: &mut Save) -> Result<()> { + fn modify(&self, save: &mut Save) -> cascade_core::Result<()> { Ok(self.modify(save)?) } @@ -213,9 +222,9 @@ impl cascade_core::Cas for Cas { } impl TryFrom<&Save> for Cas { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(save: &Save) -> Result { + fn try_from(save: &Save) -> cascade_core::Result { Ok(Self { summary: Summary::try_from(&save.summary)?, data: Data::try_from(&save.data)?, @@ -224,7 +233,7 @@ impl TryFrom<&Save> for Cas { } impl Cas { - pub fn modify(&self, save: &mut Save) -> Result<()> { + pub fn modify(&self, save: &mut Save) -> cascade_core::Result<()> { self.summary.modify(&mut save.summary); self.data.modify(&mut save.data)?; Ok(()) @@ -259,9 +268,9 @@ impl Summary { } impl TryFrom<&Box> for Summary { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(summary: &Box) -> Result { + fn try_from(summary: &Box) -> cascade_core::Result { Ok(Self { total_goals_complete: summary.get(id::TOTAL_GOALS_COMPLETE).cloned().into(), total_goals_possible: summary.get(id::TOTAL_GOALS_POSSIBLE).cloned().into(), @@ -282,9 +291,9 @@ pub struct Data { } impl TryFrom<&Box> for Data { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(data: &Box) -> Result { + fn try_from(data: &Box) -> cascade_core::Result { Ok(Self { custom_skater: CustomSkater::try_from(expect_structure(data, id::CUSTOM_SKATER)?)?, story_skater: StorySkater::try_from(expect_structure(data, id::STORY_SKATER)?)?, @@ -293,7 +302,7 @@ impl TryFrom<&Box> for Data { } impl Data { - pub fn modify(&self, data: &mut Box) -> Result<()> { + pub fn modify(&self, data: &mut Box) -> cascade_core::Result<()> { self.custom_skater .modify(expect_structure_mut(data, id::CUSTOM_SKATER)?)?; @@ -311,9 +320,9 @@ pub struct CustomSkater { } impl TryFrom<&Box> for CustomSkater { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(custom_skater: &Box) -> Result { + fn try_from(custom_skater: &Box) -> cascade_core::Result { Ok(Self { custom: Custom::try_from(expect_structure(custom_skater, id::CUSTOM)?)?, }) @@ -321,7 +330,7 @@ impl TryFrom<&Box> for CustomSkater { } impl CustomSkater { - pub fn modify(&self, custom_skater: &mut Box) -> Result<()> { + pub fn modify(&self, custom_skater: &mut Box) -> cascade_core::Result<()> { self.custom .modify(expect_structure_mut(custom_skater, id::CUSTOM)?)?; Ok(()) @@ -336,9 +345,9 @@ pub struct Custom { } impl TryFrom<&Box> for Custom { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(custom: &Box) -> Result { + fn try_from(custom: &Box) -> cascade_core::Result { Ok(Self { appearance: Appearance::try_from(expect_structure(custom, id::APPEARANCE)?)?, info: Info::try_from(expect_structure(custom, id::INFO)?)?, @@ -347,7 +356,7 @@ impl TryFrom<&Box> for Custom { } impl Custom { - pub fn modify(&self, custom: &mut Box) -> Result<()> { + pub fn modify(&self, custom: &mut Box) -> cascade_core::Result<()> { self.appearance .modify(expect_structure_mut(custom, id::APPEARANCE)?); self.info.modify(expect_structure_mut(custom, id::INFO)?); @@ -364,9 +373,9 @@ pub struct Info { } impl TryFrom<&Box> for Info { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(info: &Box) -> Result { + fn try_from(info: &Box) -> cascade_core::Result { Ok(Self { trick_mapping: info.get(id::TRICK_MAPPING).cloned().into(), specials: info.get(id::SPECIALS).cloned().into(), @@ -551,9 +560,9 @@ impl Appearance { } impl TryFrom<&Box> for Appearance { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(structure: &Box) -> Result { + fn try_from(structure: &Box) -> cascade_core::Result { Ok(Self { body_shape: structure.get(id::BODY_SHAPE).cloned().into(), body: structure.get(id::BODY).cloned().into(), @@ -629,9 +638,9 @@ pub struct StorySkater { } impl TryFrom<&Box> for StorySkater { - type Error = Error; + type Error = cascade_core::Error; - fn try_from(structure: &Box) -> Result { + fn try_from(structure: &Box) -> cascade_core::Result { Ok(Self { tricks: structure.get(id::TRICKS).cloned().into(), }) diff --git a/crates/cascade-thug2/src/core.rs b/crates/cascade-thug2/src/core.rs deleted file mode 100644 index 09f68ec..0000000 --- a/crates/cascade-thug2/src/core.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::path::Path; - -use crate::{Cas, Entry, Error, Result, Save, entry::find_entries}; - -pub struct Core {} - -impl cascade_core::Core for Core { - type Entry = Entry; - type Save = Save; - type Cas = Cas; - type Error = Error; - - fn entries(&self, dir: impl AsRef) -> Result> { - find_entries(dir) - } -} diff --git a/crates/cascade-thug2/src/entry.rs b/crates/cascade-thug2/src/entry.rs index f2bcfd9..c161b81 100644 --- a/crates/cascade-thug2/src/entry.rs +++ b/crates/cascade-thug2/src/entry.rs @@ -1,138 +1,39 @@ -use std::{ - fs::{self}, - hash::{Hash, Hasher}, - io::{BufReader, BufWriter, Read, Seek, Write}, - path::{Path, PathBuf}, -}; - -use crate::{Error, Result}; - -#[derive(Debug, Clone)] -pub struct Entry { - pub path: PathBuf, - pub dir: PathBuf, - pub filename: String, - pub metadata: Option, -} - -impl cascade_core::Entry for Entry { - type Error = Error; - - fn reader(&self) -> Result { - let file = fs::File::open(&self.path)?; - Ok(BufReader::new(file)) - } - - fn writer(&self) -> Result { - let file = fs::File::create(&self.path)?; - Ok(BufWriter::new(file)) - } - - fn name(&self) -> String { - self.filename.clone() - } - - fn rewrite_metadata(&self) -> Result<()> { - if let Some(metadata) = &self.metadata { - let filepath = &self.path; - - let original_mod_time = filetime::FileTime::from_last_modification_time(metadata); - - log::info!( - "setting file modification time for {:?} to {:?}", - filepath, - original_mod_time - ); - filetime::set_file_mtime(&filepath, original_mod_time)?; - } - - Ok(()) - } -} - -impl Hash for Entry { - fn hash(&self, state: &mut H) { - self.path.hash(state); - } -} - -impl PartialEq for Entry { - fn eq(&self, other: &Self) -> bool { - // TODO: store filepath in entry - self.path == other.path - } -} - -impl Eq for Entry {} - -impl Entry { - pub fn create(path: impl AsRef) -> Result { - let path = path.as_ref(); - - let metadata = fs::metadata(path).ok(); - let filename = path - .file_name() - .map(|s| s.to_string_lossy().into()) - .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(path)))?; - - let dir = path - .parent() - .map(PathBuf::from) - .ok_or_else(|| Error::InvalidSaveFilePath(PathBuf::from(path)))?; - - Ok(Self { - path: PathBuf::from(path), - dir, - filename, - metadata, - }) - } - - pub fn reader(&self) -> Result { - let file = fs::File::open(&self.path)?; - Ok(BufReader::new(file)) - } - - pub fn writer(&self) -> Result { - let file = fs::File::create(&self.path)?; - Ok(BufWriter::new(file)) - } -} - -pub fn find_entries(dir: impl AsRef) -> Result> { - let dir = PathBuf::from(dir.as_ref()); - - dir.is_dir() - .then(|| ()) - .ok_or_else(|| Error::NoSuchDirectory(dir.clone()))?; - - log::info!("finding entries in {:?}", dir); - - Ok(dir - .read_dir()? - .filter_map(|file| file.ok()) - .filter_map(|file| { - let filepath = file.path(); - log::info!("found file at {:?}", filepath); - - // oops i should probably make this cleaner - if let Some(filename) = filepath.file_name() { - if filename.to_string_lossy().ends_with(".SKA") { - match Entry::create(&filepath) { - Ok(save) => { - log::info!("found entry {:?}", filepath); - Some(save) - } - Err(e) => { - log::warn!("error loading entry {:?}: {}", filepath, e); +use std::path::PathBuf; + +pub fn find_entries(dir: &PathBuf) -> Vec { + match dir.read_dir() { + Ok(dir) => { + log::info!("finding entries in {:?}", dir); + dir.filter_map(|file| file.ok()) + .filter_map(|file| { + let filepath = file.path(); + log::info!("found file at {:?}", filepath); + + // oops i should probably make this cleaner + if let Some(filename) = filepath.file_name() { + if filename.to_string_lossy().ends_with(".SKA") { + match cascade_core::Entry::create(&filepath) { + Ok(save) => { + log::info!("found entry {:?}", filepath); + Some(save) + } + Err(e) => { + log::warn!("error loading entry {:?}: {}", filepath, e); + None + } + } + } else { None } + } else { + None } - } else { - None - } - } else { - None - } - })) + }) + .collect() + } + Err(err) => { + log::error!("error reading directory {:?}: {}", dir, err); + Vec::new() + } + } } diff --git a/crates/cascade-thug2/src/error.rs b/crates/cascade-thug2/src/error.rs deleted file mode 100644 index 9295e97..0000000 --- a/crates/cascade-thug2/src/error.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::{io, path::PathBuf, result}; - -use cascade_qb as qb; -use cascade_save as save; - -#[derive(thiserror::Error, Debug, Clone)] -pub enum Error { - #[error("io error: {0}")] - Io(io::ErrorKind), - - #[error("qb error: {0}")] - Qb(#[from] qb::Error), - - #[error("save error: {0}")] - Save(#[from] save::Error), - - #[error("unknown save file extension \"{0}\"")] - UnknownFileExtension(String), - - #[error("symbol not found: {0}")] - SymbolNotFound(qb::Id), - - #[error("directory \"{0}\" was not found")] - NoSuchDirectory(PathBuf), - - #[error("save file path \"{0}\" is not valid")] - InvalidSaveFilePath(PathBuf), -} - -impl From for Error { - fn from(value: io::Error) -> Self { - Self::Io(value.kind()) - } -} - -pub type Result = result::Result; diff --git a/crates/cascade-thug2/src/lib.rs b/crates/cascade-thug2/src/lib.rs index 62fcd43..f404db4 100644 --- a/crates/cascade-thug2/src/lib.rs +++ b/crates/cascade-thug2/src/lib.rs @@ -1,16 +1,11 @@ mod cas; -mod core; mod entry; -mod error; mod id; #[cfg(feature = "lut")] pub mod lut; mod save; // pub mod random; -pub use core::Core; - pub use cas::Cas; -pub use entry::{Entry, find_entries}; -pub use error::{Error, Result}; +pub use entry::find_entries; pub use save::Save; diff --git a/crates/cascade-thug2/src/save.rs b/crates/cascade-thug2/src/save.rs index a16974c..735a858 100644 --- a/crates/cascade-thug2/src/save.rs +++ b/crates/cascade-thug2/src/save.rs @@ -1,12 +1,10 @@ use std::io::{Read, Seek, Write}; -use crate::{Error, Result}; +use cascade_core::Result; pub struct Save(cascade_save::Save); impl cascade_core::Save for Save { - type Error = Error; - fn read(reader: &mut (impl Read + Seek)) -> Result { Ok(Self(cascade_save::Save::read(reader)?)) } From c5c08355ff8fb2603166cac99ffd45ebfb3c38b7 Mon Sep 17 00:00:00 2001 From: ellie <149747415+1borgy@users.noreply.github.com> Date: Tue, 7 Jul 2026 14:19:03 -0400 Subject: [PATCH 12/23] evertything working?! --- .justfile | 3 + Cargo.toml | 2 + assets/saves/thaw/Assi iSL-Progress | Bin 0 -> 98304 bytes assets/saves/thaw/Cooking Edem-Progress | Bin 0 -> 141153 bytes assets/saves/thaw/SSX Edem-Progress | Bin 0 -> 140651 bytes assets/saves/thaw/Skater 3-Progress | Bin 0 -> 180224 bytes assets/saves/thaw/Skater-Progress | Bin 0 -> 180224 bytes assets/saves/thaw/edemnew-Progress | Bin 0 -> 195603 bytes assets/saves/thaw/thps2-Progress | Bin 0 -> 198717 bytes assets/saves/thps4/bluepurp.SKA | Bin 0 -> 2048 bytes assets/saves/thps4/c4mgurl.SKA | Bin 0 -> 2048 bytes assets/saves/thps4/cgeo4.SKA | Bin 0 -> 2048 bytes assets/saves/thps4/purpmf.SKA | Bin 0 -> 2048 bytes assets/saves/thps4/redbuck.SKA | Bin 0 -> 2048 bytes assets/saves/thug/Custom Skajk.SKA | Bin 0 -> 90112 bytes assets/saves/thug/Custom Skak.SKA | Bin 0 -> 90112 bytes assets/saves/thug/Custom Skater.SKA | Bin 0 -> 90112 bytes assets/saves/thug/Custom.SKA | Bin 0 -> 90112 bytes assets/saves/thug/Custom2.SKA | Bin 0 -> 90112 bytes assets/saves/thug/THUGSavegame.SKA | Bin 0 -> 90112 bytes assets/saves/thug/asghan.SKA | Bin 0 -> 90112 bytes assets/saves/thug/blue2vy.SKA | Bin 0 -> 90112 bytes assets/saves/thug/bombsorange.SKA | Bin 0 -> 90112 bytes assets/saves/thug/ertgh.SKA | Bin 0 -> 90112 bytes assets/saves/thug/fly.SKA | Bin 0 -> 90112 bytes assets/saves/thug/genericvy2.SKA | Bin 0 -> 90112 bytes assets/saves/thug/mcyre.SKA | Bin 0 -> 90112 bytes assets/saves/thug/mrhivy.SKA | Bin 0 -> 90112 bytes assets/saves/thug/murs.SKA | Bin 0 -> 90112 bytes assets/saves/thug/skullvy.SKA | Bin 0 -> 90112 bytes assets/saves/thug/yelscyt1.SKA | Bin 0 -> 90112 bytes assets/saves/thug/zed.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/1 2.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/12chopped.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/2414.SKA | Bin assets/saves/{thugpro => thug2}/4fantasy.SKA | Bin assets/saves/thug2/808 2024.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/808.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/80thugg.SKA | Bin assets/saves/thug2/98.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/999.SKA | Bin .../saves/{thugpro => thug2}/AfroSpidey.SKA | Bin assets/saves/thug2/Ardito.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/BG.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/BLU INC.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/CGeorge.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/ClassicGreen.SKA | Bin assets/saves/{thugpro => thug2}/Cus.SKA | Bin assets/saves/thug2/Cusee.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/Cust.SKA | Bin assets/saves/{thugpro => thug2}/Custo111.SKA | Bin assets/saves/thug2/Custoast.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/Custom 123.SKA | Bin 90112 -> 90112 bytes .../saves/{thugpro => thug2}/Custom Ska.SKA | Bin assets/saves/thug2/Custom Skater.SKA | Bin 0 -> 90112 bytes .../{thugpro => thug2}/Custom Skater1.SKA | Bin .../{thugpro => thug2}/Custom Skater11.SKA | Bin .../{thugpro => thug2}/Custom Skater12.SKA | Bin .../{thugpro => thug2}/Custom Skater13.SKA | Bin .../{thugpro => thug2}/Custom Skater15.SKA | Bin assets/saves/{thugpro => thug2}/Custom.SKA | Bin assets/saves/{thugpro => thug2}/Custom1.SKA | Bin assets/saves/{thugpro => thug2}/Custom111.SKA | Bin .../saves/{thugpro => thug2}/Custom11111.SKA | Bin .../{thugpro => thug2}/Custom111111111.SKA | Bin .../saves/{thugpro => thug2}/Custom22222.SKA | Bin assets/saves/thug2/Custom5.SKA | Bin 0 -> 90112 bytes .../{thugpro => thug2}/Custom_Skater13.SKA | Bin assets/saves/{thugpro => thug2}/DraKcula.SKA | Bin assets/saves/{thugpro => thug2}/Draco.SKA | Bin assets/saves/{thugpro => thug2}/Draco05.SKA | Bin assets/saves/{thugpro => thug2}/Draco5.SKA | Bin assets/saves/{thugpro => thug2}/Draco55.SKA | Bin assets/saves/{thugpro => thug2}/Drago.tLT.SKA | Bin .../saves/{thugpro => thug2}/Dragon.eXtLT.SKA | Bin 90112 -> 90112 bytes assets/saves/{thugpro => thug2}/DreamY.SKA | Bin .../{thugpro => thug2}/Drizzteatthis.SKA | Bin assets/saves/{thugpro => thug2}/George.SKA | Bin assets/saves/{thugpro => thug2}/Ghostface.SKA | Bin .../saves/{thugpro => thug2}/GhostsDraco.SKA | Bin assets/saves/{thugpro => thug2}/J1221.SKA | Bin assets/saves/{thugpro => thug2}/J3.SKA | Bin assets/saves/{thugpro => thug2}/JEHCPHUN3.SKA | Bin assets/saves/{thugpro => thug2}/Jaycee 24.SKA | Bin .../{thugpro => thug2}/Jaycee111111111.SKA | Bin .../saves/{thugpro => thug2}/Jayceehoodie.SKA | Bin .../{thugpro => thug2}/Jayceetekcolors.SKA | Bin assets/saves/{thugpro => thug2}/JehCPHUN.SKA | Bin assets/saves/{thugpro => thug2}/JoePro.SKA | Bin .../{thugpro => thug2}/JoeProGreenLon2.SKA | Bin .../{thugpro => thug2}/JoeProPirate2.SKA | Bin assets/saves/thug2/Kmoder.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/KskoutLT.SKA | Bin assets/saves/thug2/LEVYT1.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/LevHSC224.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/LilThotties.SKA | Bin assets/saves/{thugpro => thug2}/MYRAGE.SKA | Bin .../{thugpro => thug2}/MyraGe.hOt._NM1.SKA | Bin assets/saves/{thugpro => thug2}/Nacho6.SKA | Bin assets/saves/thug2/Ned the Cyclops.SKA | Bin 0 -> 90112 bytes .../{thugpro => thug2}/Ned_the_Cyclops.SKA | Bin assets/saves/thug2/Nedcean.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/Neon.SKA | Bin assets/saves/thug2/Newblu.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/Orng.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/ProSkater.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/Proton.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/RegularScuba.SKA | Bin assets/saves/{thugpro => thug2}/SiltLT.SKA | Bin assets/saves/{thugpro => thug2}/TEKREMAKE.SKA | Bin assets/saves/thug2/Thin.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/VARSITYCHOPPED.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/XD.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/afrojaycee.SKA | Bin .../saves/{thugpro => thug2}/afrospideyy.SKA | Bin .../{thugpro => thug2}/alivegudephun.SKA | Bin .../saves/{thugpro => thug2}/alivesunhat.SKA | Bin .../saves/{thugpro => thug2}/alivesunhat1.SKA | Bin .../{thugpro => thug2}/allblackhellmet.SKA | Bin .../{thugpro => thug2}/altblackhellmet.SKA | Bin assets/saves/{thugpro => thug2}/altskel.SKA | Bin .../{thugpro => thug2}/anderson cowboy.SKA | Bin assets/saves/thug2/asghan.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/astrovan.SKA | Bin assets/saves/{thugpro => thug2}/b2.SKA | Bin assets/saves/thug2/babyclothes.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/bace.SKA | Bin assets/saves/{thugpro => thug2}/bacelec.SKA | Bin assets/saves/{thugpro => thug2}/bacetltv2.SKA | Bin assets/saves/{thugpro => thug2}/bacetlv22.SKA | Bin .../saves/{thugpro => thug2}/badacehood.SKA | Bin assets/saves/thug2/baskebtal.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/bemon.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/bigpimpin.SKA | Bin .../saves/{thugpro => thug2}/bigpimpin1.SKA | Bin assets/saves/{thugpro => thug2}/bitch69.SKA | Bin assets/saves/thug2/blaaaaa.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/black gray.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/blacknyello.SKA | Bin assets/saves/thug2/blackrasta.SKA | Bin 0 -> 90112 bytes .../{thugpro => thug2}/blackvestupsend.SKA | Bin assets/saves/thug2/blaz.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blu 123.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blu black vis.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blu cas.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blu gray vis.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blu hood.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blu hoodd.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blu og bluegrip.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blu og.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blu os.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/blu sunhat.SKA | Bin assets/saves/thug2/blu vision.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blu.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blue cas.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blue hood.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/bluepink.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blumainnewbinds.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/blumediumjam.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/blur.SKA | Bin assets/saves/{thugpro => thug2}/blurnewog.SKA | Bin .../saves/{thugpro => thug2}/blursmgvid2.SKA | Bin assets/saves/{thugpro => thug2}/boiiwonda.SKA | Bin assets/saves/thug2/bonkyhood.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/bonkystyle.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/bootmontmurs.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/bootsss.SKA | Bin assets/saves/thug2/bopkonk.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/brbska.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/buck.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/buket.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/bumbean.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/c0lor blu.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/c0lor.SKA | Bin 0 -> 90112 bytes .../{thugpro => thug2}/c4Carl Johnson.SKA | Bin assets/saves/{thugpro => thug2}/c7pink.SKA | Bin .../{thugpro => thug2}/cWalkertStyle.SKA | Bin .../saves/{thugpro => thug2}/camosunhat.SKA | Bin assets/saves/{thugpro => thug2}/cbeanie.SKA | Bin assets/saves/{thugpro => thug2}/ccowboy.SKA | Bin assets/saves/{thugpro => thug2}/cdasendah.SKA | Bin assets/saves/{thugpro => thug2}/cdoc.SKA | Bin .../{thugpro => thug2}/cdot r y afro.SKA | Bin assets/saves/{thugpro => thug2}/cdot.SKA | Bin assets/saves/{thugpro => thug2}/cdot2.SKA | Bin assets/saves/{thugpro => thug2}/cdot3.SKA | Bin assets/saves/{thugpro => thug2}/cdot4.SKA | Bin .../saves/{thugpro => thug2}/cdotccandy.SKA | Bin assets/saves/{thugpro => thug2}/cdotcdot.SKA | Bin .../{thugpro => thug2}/cdotgreenhelmet.SKA | Bin .../{thugpro => thug2}/cdotgrenwhite.SKA | Bin assets/saves/{thugpro => thug2}/cdotpink.SKA | Bin assets/saves/{thugpro => thug2}/cdotslime.SKA | Bin .../{thugpro => thug2}/cdotsmokescales.SKA | Bin .../saves/{thugpro => thug2}/cdotxxxposed.SKA | Bin assets/saves/thug2/chopped rock.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/choppedhomeless.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/colorful.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/conad.SKA | Bin assets/saves/{thugpro => thug2}/conad2.SKA | Bin assets/saves/thug2/corn vendor.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/corn.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/corncas.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/cotton_candy.SKA | Bin .../{thugpro => thug2}/cotton_candy2.SKA | Bin .../{thugpro => thug2}/cottoncandymf.SKA | Bin assets/saves/{thugpro => thug2}/crim.SKA | Bin assets/saves/{thugpro => thug2}/crimm.SKA | Bin .../{thugpro => thug2}/cthotSantaHoe.SKA | Bin .../saves/{thugpro => thug2}/cthotremake.SKA | Bin assets/saves/{thugpro => thug2}/cthottie.SKA | Bin assets/saves/{thugpro => thug2}/cthotv2.SKA | Bin .../saves/{thugpro => thug2}/curtskater2.SKA | Bin assets/saves/thug2/cyan hood.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/daman.SKA | Bin assets/saves/thug2/darby.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/dark afro.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/dark green.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/dblu gray.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/dblue 2024.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/dblue.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/ddd.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/ddo.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/ddoBOMB.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/ddobombyellow.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/ddowhite.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/decembro.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/ded.SKA | Bin assets/saves/{thugpro => thug2}/ded1.SKA | Bin assets/saves/thug2/dede.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/dede3.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/dede4.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/def.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/defa.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/diffscales.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/dns.SKA | Bin assets/saves/{thugpro => thug2}/draco1017.SKA | Bin assets/saves/{thugpro => thug2}/draco11.SKA | Bin assets/saves/{thugpro => thug2}/draghost.SKA | Bin assets/saves/{thugpro => thug2}/dragon.SKA | Bin .../saves/{thugpro => thug2}/dragontlt1.SKA | Bin assets/saves/{thugpro => thug2}/drakcdot.SKA | Bin assets/saves/{thugpro => thug2}/drakcdot1.SKA | Bin assets/saves/{thugpro => thug2}/eG2.SKA | Bin assets/saves/thug2/eatingwendys.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/edcean.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/edem 22.SKA | Bin assets/saves/thug2/edsheeran.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/elecbright.SKA | Bin .../{thugpro => thug2}/evilsanjfixed.SKA | Bin assets/saves/{thugpro => thug2}/fayteish.SKA | Bin .../saves/{thugpro => thug2}/faytejersey.SKA | Bin .../saves/{thugpro => thug2}/fayteptcelec.SKA | Bin assets/saves/{thugpro => thug2}/fazo.SKA | Bin assets/saves/thug2/feeeeeeeeee.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/fireboy69.SKA | Bin assets/saves/thug2/flower.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/flypizza.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/forcdot.SKA | Bin assets/saves/thug2/fr0st.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/freddy.SKA | Bin assets/saves/thug2/fro.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/frontbad.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/frost new.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/frostedclown.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/fuxwitit.SKA | Bin assets/saves/thug2/fync.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/fyncc.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/gard.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/george11111.SKA | Bin assets/saves/{thugpro => thug2}/georgetlt.SKA | Bin assets/saves/thug2/ghopscea.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/ghostRiVblu.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/ghostpurple.SKA | Bin .../saves/{thugpro => thug2}/ghostyellow.SKA | Bin assets/saves/thug2/gnz0.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/golden q.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/gonz0.SKA | Bin 90112 -> 90112 bytes assets/saves/thug2/gonzo colors.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/gonzoceanslight.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/gonzoplasre.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/googst.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/goz.SKA | Bin assets/saves/thug2/gray.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/gre new.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/gre.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/green WIP.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/green buck.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/green in.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/green version.SKA | Bin 0 -> 90112 bytes .../{thugpro => thug2}/greenjerseyafro.SKA | Bin .../{thugpro => thug2}/greenwhitedot.SKA | Bin assets/saves/thug2/grilla.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/grn gray.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/grn.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/grnnn.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/grrrr.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/gurl.SKA | Bin assets/saves/{thugpro => thug2}/gurlive.SKA | Bin assets/saves/thug2/hell.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/hippie.SKA | Bin .../saves/{thugpro => thug2}/hippiecdot.SKA | Bin assets/saves/{thugpro => thug2}/hoe.SKA | Bin assets/saves/thug2/homiecean.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/hoodddd.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/hoodieghostsc.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/icey.SKA | Bin assets/saves/{thugpro => thug2}/idkaman4.SKA | Bin assets/saves/thug2/ish.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/j5 test.SKA | Bin assets/saves/{thugpro => thug2}/j5.SKA | Bin assets/saves/thug2/jade.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/jaycee.SKA | Bin assets/saves/{thugpro => thug2}/jayceetek.SKA | Bin assets/saves/thug2/jeetyA.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/jehcc.SKA | Bin assets/saves/thug2/jenny.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/jennyfer.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/jinzo.SKA | Bin .../saves/{thugpro => thug2}/jokerdotty.SKA | Bin assets/saves/{thugpro => thug2}/jokrdot.SKA | Bin assets/saves/{thugpro => thug2}/jolly22.SKA | Bin assets/saves/{thugpro => thug2}/jona.SKA | Bin assets/saves/{thugpro => thug2}/jonathek.SKA | Bin assets/saves/thug2/kindalevy.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/kindapants.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/kiry bruh.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/knum2.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/konek 2.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/konek3.SKA | Bin assets/saves/{thugpro => thug2}/konekL.SKA | Bin assets/saves/thug2/konekjh00.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/ksk.SKA | Bin assets/saves/thug2/kskcean.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/ksksk.SKA | Bin assets/saves/thug2/largewip.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/lebad.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/lehvsuit.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/levocetricks.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/levycreep.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/luxurybrand.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/lvv.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/main.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/mao.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/maxfli1.SKA | Bin assets/saves/{thugpro => thug2}/maxfli2.SKA | Bin .../saves/{thugpro => thug2}/maxflilike.SKA | Bin assets/saves/thug2/mcyscales.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/mcysuitscales.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/mcyth4.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/mcytraf.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/mf2smg1.SKA | Bin .../saves/{thugpro => thug2}/mikeghost3.SKA | Bin assets/saves/{thugpro => thug2}/mista2.SKA | Bin assets/saves/thug2/mli.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/mmfood.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/momts.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/mont.SKA | Bin assets/saves/thug2/mont2.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/montbombs.SKA | Bin assets/saves/thug2/montredtrik.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/montvex 2.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/montvex.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/montvexsc.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/mpkdd.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/mpkdd2.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/mscales2.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/mursalt.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/myoldcas.SKA | Bin assets/saves/thug2/mystinc.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/ness.SKA | Bin assets/saves/{thugpro => thug2}/newcas.SKA | Bin assets/saves/thug2/newscalesnewme.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/newtek.SKA | Bin assets/saves/thug2/nightmare.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/nu.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/o.SKA | Bin assets/saves/thug2/oceanpag.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/og.SKA | Bin 90112 -> 90112 bytes assets/saves/thug2/okokokok.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/oldfaytecas1.SKA | Bin assets/saves/{thugpro => thug2}/oldmecas.SKA | Bin assets/saves/{thugpro => thug2}/oldogcas.SKA | Bin assets/saves/{thugpro => thug2}/oldogcas1.SKA | Bin assets/saves/thug2/one of them one.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/one of them.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/p1.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/p2.SKA | Bin 0 -> 90112 bytes .../{thugpro => thug2}/paggreensunhat.SKA | Bin assets/saves/{thugpro => thug2}/pagsunhat.SKA | Bin .../saves/{thugpro => thug2}/pagsunhat1.SKA | Bin assets/saves/{thugpro => thug2}/pants.SKA | Bin assets/saves/thug2/paper boi.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/paperboi.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/paperhat.SKA | Bin assets/saves/thug2/pastee.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/pin.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/pink.SKA | Bin assets/saves/{thugpro => thug2}/pinkblack.SKA | Bin assets/saves/{thugpro => thug2}/pinkdread.SKA | Bin .../{thugpro => thug2}/pinklikecamron.SKA | Bin .../saves/{thugpro => thug2}/pinkmohawk.SKA | Bin assets/saves/thug2/plasTHPS.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/plasithunk.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/plasmurs.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/protonbomb.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/pubdisp.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/ravneww.SKA | Bin assets/saves/thug2/rb.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/rb1.SKA | Bin assets/saves/{thugpro => thug2}/realdraco.SKA | Bin assets/saves/thug2/red.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/redb.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/redd.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/redsh.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/redz.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/remake2.SKA | Bin assets/saves/thug2/rethawed blue.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/rethawed.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/rethawed2.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/revmcy.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/rivenocn.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/rlu.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/robot.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/rockstar.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/russian.SKA | Bin 90112 -> 90112 bytes .../{thugpro => thug2}/russianjacket.SKA | Bin assets/saves/thug2/sameletter.SKA | Bin 0 -> 90112 bytes .../{thugpro => thug2}/sandwhich bag.SKA | Bin assets/saves/{thugpro => thug2}/santa.SKA | Bin assets/saves/thug2/scary.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/sdddd.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/seargeant facea.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/seinfeld.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/shed.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/shie.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/shy anne.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/silent.SKA | Bin assets/saves/thug2/sk.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/skgr.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/slimehoodie.SKA | Bin assets/saves/{thugpro => thug2}/smg2pizza.SKA | Bin 90112 -> 90112 bytes assets/saves/{thugpro => thug2}/smoke.SKA | Bin .../{thugpro => thug2}/somewhatfayte.SKA | Bin assets/saves/{thugpro => thug2}/sonics.SKA | Bin assets/saves/{thugpro => thug2}/spbobsmg.SKA | Bin assets/saves/{thugpro => thug2}/spooker.SKA | Bin assets/saves/thug2/stilent.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/stomT1re.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/stomchain.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/stompALT.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/stompzsunnewboa.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/striped chilll.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/stuehat.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/sunhat.SKA | Bin 0 -> 90112 bytes .../saves/{thugpro => thug2}/sunhatscales.SKA | Bin assets/saves/thug2/supreme drip.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/t1type.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/temp..SKA | Bin 0 -> 90112 bytes assets/saves/thug2/test.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/thesedoctors.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/thiccboi.SKA | Bin assets/saves/thug2/thinOrng.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/thugg.SKA | Bin assets/saves/{thugpro => thug2}/thugg_2.SKA | Bin .../saves/{thugpro => thug2}/thuggcrazy.SKA | Bin assets/saves/{thugpro => thug2}/tlt22222.SKA | Bin .../{thugpro => thug2}/tltv5faytelec.SKA | Bin assets/saves/{thugpro => thug2}/uhhh_hmm.SKA | Bin assets/saves/thug2/uktfc.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/uktfcc.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/v1c.SKA | Bin assets/saves/{thugpro => thug2}/vegasmg2.SKA | Bin assets/saves/{thugpro => thug2}/velho.SKA | Bin assets/saves/{thugpro => thug2}/vestupson.SKA | Bin .../{thugpro => thug2}/vestupwbeanie.SKA | Bin assets/saves/{thugpro => thug2}/vicphun.SKA | Bin assets/saves/{thugpro => thug2}/viking.SKA | Bin assets/saves/thug2/wat.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/wdf.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/whitepink.SKA | Bin assets/saves/thug2/whore.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/wormgurl.SKA | Bin .../saves/{thugpro => thug2}/wormgurlbw.SKA | Bin assets/saves/{thugpro => thug2}/wormslime.SKA | Bin .../saves/{thugpro => thug2}/wormsmonkknk.SKA | Bin assets/saves/{thugpro => thug2}/x3og.SKA | Bin assets/saves/thug2/xdd.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/xm.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/yea.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/yell.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/yeller.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/yellow.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/yuzuriah.SKA | Bin 0 -> 90112 bytes assets/saves/{thugpro => thug2}/zoo.SKA | Bin assets/saves/thug2/zzz.SKA | Bin 0 -> 90112 bytes assets/saves/thug2/zzz3.SKA | Bin 0 -> 90112 bytes assets/saves/thugpro/Ned the Cyclops.SKA | Bin 90112 -> 0 bytes crates/cascade-app/Cargo.toml | 1 + crates/cascade-app/src/app.rs | 105 ++++-- crates/cascade-app/src/paths.rs | 7 +- crates/cascade-app/src/state.rs | 10 +- crates/cascade-app/src/theme/text_input.rs | 3 +- crates/cascade-cli/Cargo.toml | 2 +- crates/cascade-cli/src/main.rs | 39 ++- crates/cascade-core/src/entry.rs | 37 ++ crates/cascade-core/src/lib.rs | 7 +- crates/cascade-qb/src/id.rs | 2 + crates/cascade-save/src/lib.rs | 2 +- crates/cascade-save/src/save.rs | 31 +- crates/cascade-test/Cargo.toml | 10 + crates/cascade-test/src/lib.rs | 119 +++++++ crates/cascade-thaw/Cargo.toml | 5 + crates/cascade-thaw/src/entry.rs | 39 --- crates/cascade-thaw/src/lib.rs | 9 +- crates/cascade-thaw/src/save.rs | 10 +- crates/cascade-thaw/tests/round_trip.rs | 5 + crates/cascade-thps4/Cargo.toml | 16 +- crates/cascade-thps4/src/cas.rs | 326 ++++++++++++++++++ crates/cascade-thps4/src/id.rs | 21 ++ crates/cascade-thps4/src/lib.rs | 14 + crates/cascade-thps4/src/save.rs | 35 ++ crates/cascade-thps4/tests/round_trip.rs | 5 + crates/cascade-thug2/Cargo.toml | 6 +- crates/cascade-thug2/src/entry.rs | 39 --- crates/cascade-thug2/src/lib.rs | 10 +- crates/cascade-thug2/src/save.rs | 2 +- crates/cascade-thug2/tests/common/mod.rs | 31 -- crates/cascade-thug2/tests/round_trip.rs | 93 +---- 529 files changed, 778 insertions(+), 268 deletions(-) create mode 100644 assets/saves/thaw/Assi iSL-Progress create mode 100644 assets/saves/thaw/Cooking Edem-Progress create mode 100644 assets/saves/thaw/SSX Edem-Progress create mode 100644 assets/saves/thaw/Skater 3-Progress create mode 100644 assets/saves/thaw/Skater-Progress create mode 100644 assets/saves/thaw/edemnew-Progress create mode 100644 assets/saves/thaw/thps2-Progress create mode 100644 assets/saves/thps4/bluepurp.SKA create mode 100644 assets/saves/thps4/c4mgurl.SKA create mode 100644 assets/saves/thps4/cgeo4.SKA create mode 100644 assets/saves/thps4/purpmf.SKA create mode 100644 assets/saves/thps4/redbuck.SKA create mode 100644 assets/saves/thug/Custom Skajk.SKA create mode 100644 assets/saves/thug/Custom Skak.SKA create mode 100644 assets/saves/thug/Custom Skater.SKA create mode 100644 assets/saves/thug/Custom.SKA create mode 100644 assets/saves/thug/Custom2.SKA create mode 100644 assets/saves/thug/THUGSavegame.SKA create mode 100644 assets/saves/thug/asghan.SKA create mode 100644 assets/saves/thug/blue2vy.SKA create mode 100644 assets/saves/thug/bombsorange.SKA create mode 100644 assets/saves/thug/ertgh.SKA create mode 100644 assets/saves/thug/fly.SKA create mode 100644 assets/saves/thug/genericvy2.SKA create mode 100644 assets/saves/thug/mcyre.SKA create mode 100644 assets/saves/thug/mrhivy.SKA create mode 100644 assets/saves/thug/murs.SKA create mode 100644 assets/saves/thug/skullvy.SKA create mode 100644 assets/saves/thug/yelscyt1.SKA create mode 100644 assets/saves/thug/zed.SKA create mode 100644 assets/saves/thug2/1 2.SKA create mode 100644 assets/saves/thug2/12chopped.SKA rename assets/saves/{thugpro => thug2}/2414.SKA (100%) rename assets/saves/{thugpro => thug2}/4fantasy.SKA (100%) create mode 100644 assets/saves/thug2/808 2024.SKA create mode 100644 assets/saves/thug2/808.SKA rename assets/saves/{thugpro => thug2}/80thugg.SKA (100%) create mode 100644 assets/saves/thug2/98.SKA rename assets/saves/{thugpro => thug2}/999.SKA (100%) rename assets/saves/{thugpro => thug2}/AfroSpidey.SKA (100%) create mode 100644 assets/saves/thug2/Ardito.SKA create mode 100644 assets/saves/thug2/BG.SKA create mode 100644 assets/saves/thug2/BLU INC.SKA create mode 100644 assets/saves/thug2/CGeorge.SKA rename assets/saves/{thugpro => thug2}/ClassicGreen.SKA (100%) rename assets/saves/{thugpro => thug2}/Cus.SKA (100%) create mode 100644 assets/saves/thug2/Cusee.SKA rename assets/saves/{thugpro => thug2}/Cust.SKA (100%) rename assets/saves/{thugpro => thug2}/Custo111.SKA (100%) create mode 100644 assets/saves/thug2/Custoast.SKA rename assets/saves/{thugpro => thug2}/Custom 123.SKA (90%) rename assets/saves/{thugpro => thug2}/Custom Ska.SKA (100%) create mode 100644 assets/saves/thug2/Custom Skater.SKA rename assets/saves/{thugpro => thug2}/Custom Skater1.SKA (100%) rename assets/saves/{thugpro => thug2}/Custom Skater11.SKA (100%) rename assets/saves/{thugpro => thug2}/Custom Skater12.SKA (100%) rename assets/saves/{thugpro => thug2}/Custom Skater13.SKA (100%) rename assets/saves/{thugpro => thug2}/Custom Skater15.SKA (100%) rename assets/saves/{thugpro => thug2}/Custom.SKA (100%) rename assets/saves/{thugpro => thug2}/Custom1.SKA (100%) rename assets/saves/{thugpro => thug2}/Custom111.SKA (100%) rename assets/saves/{thugpro => thug2}/Custom11111.SKA (100%) rename assets/saves/{thugpro => thug2}/Custom111111111.SKA (100%) rename assets/saves/{thugpro => thug2}/Custom22222.SKA (100%) create mode 100644 assets/saves/thug2/Custom5.SKA rename assets/saves/{thugpro => thug2}/Custom_Skater13.SKA (100%) rename assets/saves/{thugpro => thug2}/DraKcula.SKA (100%) rename assets/saves/{thugpro => thug2}/Draco.SKA (100%) rename assets/saves/{thugpro => thug2}/Draco05.SKA (100%) rename assets/saves/{thugpro => thug2}/Draco5.SKA (100%) rename assets/saves/{thugpro => thug2}/Draco55.SKA (100%) rename assets/saves/{thugpro => thug2}/Drago.tLT.SKA (100%) rename assets/saves/{thugpro => thug2}/Dragon.eXtLT.SKA (82%) rename assets/saves/{thugpro => thug2}/DreamY.SKA (100%) rename assets/saves/{thugpro => thug2}/Drizzteatthis.SKA (100%) rename assets/saves/{thugpro => thug2}/George.SKA (100%) rename assets/saves/{thugpro => thug2}/Ghostface.SKA (100%) rename assets/saves/{thugpro => thug2}/GhostsDraco.SKA (100%) rename assets/saves/{thugpro => thug2}/J1221.SKA (100%) rename assets/saves/{thugpro => thug2}/J3.SKA (100%) rename assets/saves/{thugpro => thug2}/JEHCPHUN3.SKA (100%) rename assets/saves/{thugpro => thug2}/Jaycee 24.SKA (100%) rename assets/saves/{thugpro => thug2}/Jaycee111111111.SKA (100%) rename assets/saves/{thugpro => thug2}/Jayceehoodie.SKA (100%) rename assets/saves/{thugpro => thug2}/Jayceetekcolors.SKA (100%) rename assets/saves/{thugpro => thug2}/JehCPHUN.SKA (100%) rename assets/saves/{thugpro => thug2}/JoePro.SKA (100%) rename assets/saves/{thugpro => thug2}/JoeProGreenLon2.SKA (100%) rename assets/saves/{thugpro => thug2}/JoeProPirate2.SKA (100%) create mode 100644 assets/saves/thug2/Kmoder.SKA rename assets/saves/{thugpro => thug2}/KskoutLT.SKA (100%) create mode 100644 assets/saves/thug2/LEVYT1.SKA create mode 100644 assets/saves/thug2/LevHSC224.SKA rename assets/saves/{thugpro => thug2}/LilThotties.SKA (100%) rename assets/saves/{thugpro => thug2}/MYRAGE.SKA (100%) rename assets/saves/{thugpro => thug2}/MyraGe.hOt._NM1.SKA (100%) rename assets/saves/{thugpro => thug2}/Nacho6.SKA (100%) create mode 100644 assets/saves/thug2/Ned the Cyclops.SKA rename assets/saves/{thugpro => thug2}/Ned_the_Cyclops.SKA (100%) create mode 100644 assets/saves/thug2/Nedcean.SKA rename assets/saves/{thugpro => thug2}/Neon.SKA (100%) create mode 100644 assets/saves/thug2/Newblu.SKA create mode 100644 assets/saves/thug2/Orng.SKA create mode 100644 assets/saves/thug2/ProSkater.SKA create mode 100644 assets/saves/thug2/Proton.SKA rename assets/saves/{thugpro => thug2}/RegularScuba.SKA (100%) rename assets/saves/{thugpro => thug2}/SiltLT.SKA (100%) rename assets/saves/{thugpro => thug2}/TEKREMAKE.SKA (100%) create mode 100644 assets/saves/thug2/Thin.SKA create mode 100644 assets/saves/thug2/VARSITYCHOPPED.SKA create mode 100644 assets/saves/thug2/XD.SKA rename assets/saves/{thugpro => thug2}/afrojaycee.SKA (100%) rename assets/saves/{thugpro => thug2}/afrospideyy.SKA (100%) rename assets/saves/{thugpro => thug2}/alivegudephun.SKA (100%) rename assets/saves/{thugpro => thug2}/alivesunhat.SKA (100%) rename assets/saves/{thugpro => thug2}/alivesunhat1.SKA (100%) rename assets/saves/{thugpro => thug2}/allblackhellmet.SKA (100%) rename assets/saves/{thugpro => thug2}/altblackhellmet.SKA (100%) rename assets/saves/{thugpro => thug2}/altskel.SKA (100%) rename assets/saves/{thugpro => thug2}/anderson cowboy.SKA (100%) create mode 100644 assets/saves/thug2/asghan.SKA rename assets/saves/{thugpro => thug2}/astrovan.SKA (100%) rename assets/saves/{thugpro => thug2}/b2.SKA (100%) create mode 100644 assets/saves/thug2/babyclothes.SKA rename assets/saves/{thugpro => thug2}/bace.SKA (100%) rename assets/saves/{thugpro => thug2}/bacelec.SKA (100%) rename assets/saves/{thugpro => thug2}/bacetltv2.SKA (100%) rename assets/saves/{thugpro => thug2}/bacetlv22.SKA (100%) rename assets/saves/{thugpro => thug2}/badacehood.SKA (100%) create mode 100644 assets/saves/thug2/baskebtal.SKA create mode 100644 assets/saves/thug2/bemon.SKA rename assets/saves/{thugpro => thug2}/bigpimpin.SKA (100%) rename assets/saves/{thugpro => thug2}/bigpimpin1.SKA (100%) rename assets/saves/{thugpro => thug2}/bitch69.SKA (100%) create mode 100644 assets/saves/thug2/blaaaaa.SKA create mode 100644 assets/saves/thug2/black gray.SKA rename assets/saves/{thugpro => thug2}/blacknyello.SKA (100%) create mode 100644 assets/saves/thug2/blackrasta.SKA rename assets/saves/{thugpro => thug2}/blackvestupsend.SKA (100%) create mode 100644 assets/saves/thug2/blaz.SKA create mode 100644 assets/saves/thug2/blu 123.SKA create mode 100644 assets/saves/thug2/blu black vis.SKA create mode 100644 assets/saves/thug2/blu cas.SKA create mode 100644 assets/saves/thug2/blu gray vis.SKA create mode 100644 assets/saves/thug2/blu hood.SKA create mode 100644 assets/saves/thug2/blu hoodd.SKA create mode 100644 assets/saves/thug2/blu og bluegrip.SKA create mode 100644 assets/saves/thug2/blu og.SKA create mode 100644 assets/saves/thug2/blu os.SKA rename assets/saves/{thugpro => thug2}/blu sunhat.SKA (100%) create mode 100644 assets/saves/thug2/blu vision.SKA create mode 100644 assets/saves/thug2/blu.SKA create mode 100644 assets/saves/thug2/blue cas.SKA create mode 100644 assets/saves/thug2/blue hood.SKA create mode 100644 assets/saves/thug2/bluepink.SKA create mode 100644 assets/saves/thug2/blumainnewbinds.SKA create mode 100644 assets/saves/thug2/blumediumjam.SKA rename assets/saves/{thugpro => thug2}/blur.SKA (100%) rename assets/saves/{thugpro => thug2}/blurnewog.SKA (100%) rename assets/saves/{thugpro => thug2}/blursmgvid2.SKA (100%) rename assets/saves/{thugpro => thug2}/boiiwonda.SKA (100%) create mode 100644 assets/saves/thug2/bonkyhood.SKA create mode 100644 assets/saves/thug2/bonkystyle.SKA create mode 100644 assets/saves/thug2/bootmontmurs.SKA rename assets/saves/{thugpro => thug2}/bootsss.SKA (100%) create mode 100644 assets/saves/thug2/bopkonk.SKA create mode 100644 assets/saves/thug2/brbska.SKA create mode 100644 assets/saves/thug2/buck.SKA create mode 100644 assets/saves/thug2/buket.SKA create mode 100644 assets/saves/thug2/bumbean.SKA create mode 100644 assets/saves/thug2/c0lor blu.SKA create mode 100644 assets/saves/thug2/c0lor.SKA rename assets/saves/{thugpro => thug2}/c4Carl Johnson.SKA (100%) rename assets/saves/{thugpro => thug2}/c7pink.SKA (100%) rename assets/saves/{thugpro => thug2}/cWalkertStyle.SKA (100%) rename assets/saves/{thugpro => thug2}/camosunhat.SKA (100%) rename assets/saves/{thugpro => thug2}/cbeanie.SKA (100%) rename assets/saves/{thugpro => thug2}/ccowboy.SKA (100%) rename assets/saves/{thugpro => thug2}/cdasendah.SKA (100%) rename assets/saves/{thugpro => thug2}/cdoc.SKA (100%) rename assets/saves/{thugpro => thug2}/cdot r y afro.SKA (100%) rename assets/saves/{thugpro => thug2}/cdot.SKA (100%) rename assets/saves/{thugpro => thug2}/cdot2.SKA (100%) rename assets/saves/{thugpro => thug2}/cdot3.SKA (100%) rename assets/saves/{thugpro => thug2}/cdot4.SKA (100%) rename assets/saves/{thugpro => thug2}/cdotccandy.SKA (100%) rename assets/saves/{thugpro => thug2}/cdotcdot.SKA (100%) rename assets/saves/{thugpro => thug2}/cdotgreenhelmet.SKA (100%) rename assets/saves/{thugpro => thug2}/cdotgrenwhite.SKA (100%) rename assets/saves/{thugpro => thug2}/cdotpink.SKA (100%) rename assets/saves/{thugpro => thug2}/cdotslime.SKA (100%) rename assets/saves/{thugpro => thug2}/cdotsmokescales.SKA (100%) rename assets/saves/{thugpro => thug2}/cdotxxxposed.SKA (100%) create mode 100644 assets/saves/thug2/chopped rock.SKA create mode 100644 assets/saves/thug2/choppedhomeless.SKA create mode 100644 assets/saves/thug2/colorful.SKA rename assets/saves/{thugpro => thug2}/conad.SKA (100%) rename assets/saves/{thugpro => thug2}/conad2.SKA (100%) create mode 100644 assets/saves/thug2/corn vendor.SKA create mode 100644 assets/saves/thug2/corn.SKA create mode 100644 assets/saves/thug2/corncas.SKA rename assets/saves/{thugpro => thug2}/cotton_candy.SKA (100%) rename assets/saves/{thugpro => thug2}/cotton_candy2.SKA (100%) rename assets/saves/{thugpro => thug2}/cottoncandymf.SKA (100%) rename assets/saves/{thugpro => thug2}/crim.SKA (100%) rename assets/saves/{thugpro => thug2}/crimm.SKA (100%) rename assets/saves/{thugpro => thug2}/cthotSantaHoe.SKA (100%) rename assets/saves/{thugpro => thug2}/cthotremake.SKA (100%) rename assets/saves/{thugpro => thug2}/cthottie.SKA (100%) rename assets/saves/{thugpro => thug2}/cthotv2.SKA (100%) rename assets/saves/{thugpro => thug2}/curtskater2.SKA (100%) create mode 100644 assets/saves/thug2/cyan hood.SKA rename assets/saves/{thugpro => thug2}/daman.SKA (100%) create mode 100644 assets/saves/thug2/darby.SKA create mode 100644 assets/saves/thug2/dark afro.SKA create mode 100644 assets/saves/thug2/dark green.SKA create mode 100644 assets/saves/thug2/dblu gray.SKA create mode 100644 assets/saves/thug2/dblue 2024.SKA create mode 100644 assets/saves/thug2/dblue.SKA create mode 100644 assets/saves/thug2/ddd.SKA create mode 100644 assets/saves/thug2/ddo.SKA create mode 100644 assets/saves/thug2/ddoBOMB.SKA create mode 100644 assets/saves/thug2/ddobombyellow.SKA create mode 100644 assets/saves/thug2/ddowhite.SKA create mode 100644 assets/saves/thug2/decembro.SKA rename assets/saves/{thugpro => thug2}/ded.SKA (100%) rename assets/saves/{thugpro => thug2}/ded1.SKA (100%) create mode 100644 assets/saves/thug2/dede.SKA create mode 100644 assets/saves/thug2/dede3.SKA create mode 100644 assets/saves/thug2/dede4.SKA create mode 100644 assets/saves/thug2/def.SKA create mode 100644 assets/saves/thug2/defa.SKA create mode 100644 assets/saves/thug2/diffscales.SKA rename assets/saves/{thugpro => thug2}/dns.SKA (100%) rename assets/saves/{thugpro => thug2}/draco1017.SKA (100%) rename assets/saves/{thugpro => thug2}/draco11.SKA (100%) rename assets/saves/{thugpro => thug2}/draghost.SKA (100%) rename assets/saves/{thugpro => thug2}/dragon.SKA (100%) rename assets/saves/{thugpro => thug2}/dragontlt1.SKA (100%) rename assets/saves/{thugpro => thug2}/drakcdot.SKA (100%) rename assets/saves/{thugpro => thug2}/drakcdot1.SKA (100%) rename assets/saves/{thugpro => thug2}/eG2.SKA (100%) create mode 100644 assets/saves/thug2/eatingwendys.SKA create mode 100644 assets/saves/thug2/edcean.SKA rename assets/saves/{thugpro => thug2}/edem 22.SKA (100%) create mode 100644 assets/saves/thug2/edsheeran.SKA rename assets/saves/{thugpro => thug2}/elecbright.SKA (100%) rename assets/saves/{thugpro => thug2}/evilsanjfixed.SKA (100%) rename assets/saves/{thugpro => thug2}/fayteish.SKA (100%) rename assets/saves/{thugpro => thug2}/faytejersey.SKA (100%) rename assets/saves/{thugpro => thug2}/fayteptcelec.SKA (100%) rename assets/saves/{thugpro => thug2}/fazo.SKA (100%) create mode 100644 assets/saves/thug2/feeeeeeeeee.SKA rename assets/saves/{thugpro => thug2}/fireboy69.SKA (100%) create mode 100644 assets/saves/thug2/flower.SKA create mode 100644 assets/saves/thug2/flypizza.SKA rename assets/saves/{thugpro => thug2}/forcdot.SKA (100%) create mode 100644 assets/saves/thug2/fr0st.SKA rename assets/saves/{thugpro => thug2}/freddy.SKA (100%) create mode 100644 assets/saves/thug2/fro.SKA create mode 100644 assets/saves/thug2/frontbad.SKA create mode 100644 assets/saves/thug2/frost new.SKA create mode 100644 assets/saves/thug2/frostedclown.SKA rename assets/saves/{thugpro => thug2}/fuxwitit.SKA (100%) create mode 100644 assets/saves/thug2/fync.SKA create mode 100644 assets/saves/thug2/fyncc.SKA create mode 100644 assets/saves/thug2/gard.SKA rename assets/saves/{thugpro => thug2}/george11111.SKA (100%) rename assets/saves/{thugpro => thug2}/georgetlt.SKA (100%) create mode 100644 assets/saves/thug2/ghopscea.SKA create mode 100644 assets/saves/thug2/ghostRiVblu.SKA rename assets/saves/{thugpro => thug2}/ghostpurple.SKA (100%) rename assets/saves/{thugpro => thug2}/ghostyellow.SKA (100%) create mode 100644 assets/saves/thug2/gnz0.SKA create mode 100644 assets/saves/thug2/golden q.SKA rename assets/saves/{thugpro => thug2}/gonz0.SKA (97%) create mode 100644 assets/saves/thug2/gonzo colors.SKA create mode 100644 assets/saves/thug2/gonzoceanslight.SKA create mode 100644 assets/saves/thug2/gonzoplasre.SKA create mode 100644 assets/saves/thug2/googst.SKA rename assets/saves/{thugpro => thug2}/goz.SKA (100%) create mode 100644 assets/saves/thug2/gray.SKA create mode 100644 assets/saves/thug2/gre new.SKA create mode 100644 assets/saves/thug2/gre.SKA create mode 100644 assets/saves/thug2/green WIP.SKA create mode 100644 assets/saves/thug2/green buck.SKA create mode 100644 assets/saves/thug2/green in.SKA create mode 100644 assets/saves/thug2/green version.SKA rename assets/saves/{thugpro => thug2}/greenjerseyafro.SKA (100%) rename assets/saves/{thugpro => thug2}/greenwhitedot.SKA (100%) create mode 100644 assets/saves/thug2/grilla.SKA create mode 100644 assets/saves/thug2/grn gray.SKA create mode 100644 assets/saves/thug2/grn.SKA create mode 100644 assets/saves/thug2/grnnn.SKA create mode 100644 assets/saves/thug2/grrrr.SKA rename assets/saves/{thugpro => thug2}/gurl.SKA (100%) rename assets/saves/{thugpro => thug2}/gurlive.SKA (100%) create mode 100644 assets/saves/thug2/hell.SKA rename assets/saves/{thugpro => thug2}/hippie.SKA (100%) rename assets/saves/{thugpro => thug2}/hippiecdot.SKA (100%) rename assets/saves/{thugpro => thug2}/hoe.SKA (100%) create mode 100644 assets/saves/thug2/homiecean.SKA create mode 100644 assets/saves/thug2/hoodddd.SKA create mode 100644 assets/saves/thug2/hoodieghostsc.SKA rename assets/saves/{thugpro => thug2}/icey.SKA (100%) rename assets/saves/{thugpro => thug2}/idkaman4.SKA (100%) create mode 100644 assets/saves/thug2/ish.SKA rename assets/saves/{thugpro => thug2}/j5 test.SKA (100%) rename assets/saves/{thugpro => thug2}/j5.SKA (100%) create mode 100644 assets/saves/thug2/jade.SKA rename assets/saves/{thugpro => thug2}/jaycee.SKA (100%) rename assets/saves/{thugpro => thug2}/jayceetek.SKA (100%) create mode 100644 assets/saves/thug2/jeetyA.SKA rename assets/saves/{thugpro => thug2}/jehcc.SKA (100%) create mode 100644 assets/saves/thug2/jenny.SKA create mode 100644 assets/saves/thug2/jennyfer.SKA rename assets/saves/{thugpro => thug2}/jinzo.SKA (100%) rename assets/saves/{thugpro => thug2}/jokerdotty.SKA (100%) rename assets/saves/{thugpro => thug2}/jokrdot.SKA (100%) rename assets/saves/{thugpro => thug2}/jolly22.SKA (100%) rename assets/saves/{thugpro => thug2}/jona.SKA (100%) rename assets/saves/{thugpro => thug2}/jonathek.SKA (100%) create mode 100644 assets/saves/thug2/kindalevy.SKA create mode 100644 assets/saves/thug2/kindapants.SKA create mode 100644 assets/saves/thug2/kiry bruh.SKA create mode 100644 assets/saves/thug2/knum2.SKA create mode 100644 assets/saves/thug2/konek 2.SKA rename assets/saves/{thugpro => thug2}/konek3.SKA (100%) rename assets/saves/{thugpro => thug2}/konekL.SKA (100%) create mode 100644 assets/saves/thug2/konekjh00.SKA rename assets/saves/{thugpro => thug2}/ksk.SKA (100%) create mode 100644 assets/saves/thug2/kskcean.SKA rename assets/saves/{thugpro => thug2}/ksksk.SKA (100%) create mode 100644 assets/saves/thug2/largewip.SKA create mode 100644 assets/saves/thug2/lebad.SKA create mode 100644 assets/saves/thug2/lehvsuit.SKA create mode 100644 assets/saves/thug2/levocetricks.SKA create mode 100644 assets/saves/thug2/levycreep.SKA create mode 100644 assets/saves/thug2/luxurybrand.SKA create mode 100644 assets/saves/thug2/lvv.SKA create mode 100644 assets/saves/thug2/main.SKA create mode 100644 assets/saves/thug2/mao.SKA rename assets/saves/{thugpro => thug2}/maxfli1.SKA (100%) rename assets/saves/{thugpro => thug2}/maxfli2.SKA (100%) rename assets/saves/{thugpro => thug2}/maxflilike.SKA (100%) create mode 100644 assets/saves/thug2/mcyscales.SKA create mode 100644 assets/saves/thug2/mcysuitscales.SKA create mode 100644 assets/saves/thug2/mcyth4.SKA create mode 100644 assets/saves/thug2/mcytraf.SKA rename assets/saves/{thugpro => thug2}/mf2smg1.SKA (100%) rename assets/saves/{thugpro => thug2}/mikeghost3.SKA (100%) rename assets/saves/{thugpro => thug2}/mista2.SKA (100%) create mode 100644 assets/saves/thug2/mli.SKA create mode 100644 assets/saves/thug2/mmfood.SKA create mode 100644 assets/saves/thug2/momts.SKA rename assets/saves/{thugpro => thug2}/mont.SKA (100%) create mode 100644 assets/saves/thug2/mont2.SKA rename assets/saves/{thugpro => thug2}/montbombs.SKA (100%) create mode 100644 assets/saves/thug2/montredtrik.SKA create mode 100644 assets/saves/thug2/montvex 2.SKA create mode 100644 assets/saves/thug2/montvex.SKA create mode 100644 assets/saves/thug2/montvexsc.SKA create mode 100644 assets/saves/thug2/mpkdd.SKA create mode 100644 assets/saves/thug2/mpkdd2.SKA create mode 100644 assets/saves/thug2/mscales2.SKA create mode 100644 assets/saves/thug2/mursalt.SKA rename assets/saves/{thugpro => thug2}/myoldcas.SKA (100%) create mode 100644 assets/saves/thug2/mystinc.SKA rename assets/saves/{thugpro => thug2}/ness.SKA (100%) rename assets/saves/{thugpro => thug2}/newcas.SKA (100%) create mode 100644 assets/saves/thug2/newscalesnewme.SKA rename assets/saves/{thugpro => thug2}/newtek.SKA (100%) create mode 100644 assets/saves/thug2/nightmare.SKA create mode 100644 assets/saves/thug2/nu.SKA rename assets/saves/{thugpro => thug2}/o.SKA (100%) create mode 100644 assets/saves/thug2/oceanpag.SKA rename assets/saves/{thugpro => thug2}/og.SKA (85%) create mode 100644 assets/saves/thug2/okokokok.SKA rename assets/saves/{thugpro => thug2}/oldfaytecas1.SKA (100%) rename assets/saves/{thugpro => thug2}/oldmecas.SKA (100%) rename assets/saves/{thugpro => thug2}/oldogcas.SKA (100%) rename assets/saves/{thugpro => thug2}/oldogcas1.SKA (100%) create mode 100644 assets/saves/thug2/one of them one.SKA create mode 100644 assets/saves/thug2/one of them.SKA create mode 100644 assets/saves/thug2/p1.SKA create mode 100644 assets/saves/thug2/p2.SKA rename assets/saves/{thugpro => thug2}/paggreensunhat.SKA (100%) rename assets/saves/{thugpro => thug2}/pagsunhat.SKA (100%) rename assets/saves/{thugpro => thug2}/pagsunhat1.SKA (100%) rename assets/saves/{thugpro => thug2}/pants.SKA (100%) create mode 100644 assets/saves/thug2/paper boi.SKA create mode 100644 assets/saves/thug2/paperboi.SKA rename assets/saves/{thugpro => thug2}/paperhat.SKA (100%) create mode 100644 assets/saves/thug2/pastee.SKA create mode 100644 assets/saves/thug2/pin.SKA rename assets/saves/{thugpro => thug2}/pink.SKA (100%) rename assets/saves/{thugpro => thug2}/pinkblack.SKA (100%) rename assets/saves/{thugpro => thug2}/pinkdread.SKA (100%) rename assets/saves/{thugpro => thug2}/pinklikecamron.SKA (100%) rename assets/saves/{thugpro => thug2}/pinkmohawk.SKA (100%) create mode 100644 assets/saves/thug2/plasTHPS.SKA create mode 100644 assets/saves/thug2/plasithunk.SKA create mode 100644 assets/saves/thug2/plasmurs.SKA create mode 100644 assets/saves/thug2/protonbomb.SKA create mode 100644 assets/saves/thug2/pubdisp.SKA rename assets/saves/{thugpro => thug2}/ravneww.SKA (100%) create mode 100644 assets/saves/thug2/rb.SKA rename assets/saves/{thugpro => thug2}/rb1.SKA (100%) rename assets/saves/{thugpro => thug2}/realdraco.SKA (100%) create mode 100644 assets/saves/thug2/red.SKA create mode 100644 assets/saves/thug2/redb.SKA create mode 100644 assets/saves/thug2/redd.SKA create mode 100644 assets/saves/thug2/redsh.SKA create mode 100644 assets/saves/thug2/redz.SKA rename assets/saves/{thugpro => thug2}/remake2.SKA (100%) create mode 100644 assets/saves/thug2/rethawed blue.SKA create mode 100644 assets/saves/thug2/rethawed.SKA create mode 100644 assets/saves/thug2/rethawed2.SKA create mode 100644 assets/saves/thug2/revmcy.SKA create mode 100644 assets/saves/thug2/rivenocn.SKA create mode 100644 assets/saves/thug2/rlu.SKA create mode 100644 assets/saves/thug2/robot.SKA create mode 100644 assets/saves/thug2/rockstar.SKA rename assets/saves/{thugpro => thug2}/russian.SKA (89%) rename assets/saves/{thugpro => thug2}/russianjacket.SKA (100%) create mode 100644 assets/saves/thug2/sameletter.SKA rename assets/saves/{thugpro => thug2}/sandwhich bag.SKA (100%) rename assets/saves/{thugpro => thug2}/santa.SKA (100%) create mode 100644 assets/saves/thug2/scary.SKA create mode 100644 assets/saves/thug2/sdddd.SKA create mode 100644 assets/saves/thug2/seargeant facea.SKA create mode 100644 assets/saves/thug2/seinfeld.SKA create mode 100644 assets/saves/thug2/shed.SKA create mode 100644 assets/saves/thug2/shie.SKA create mode 100644 assets/saves/thug2/shy anne.SKA rename assets/saves/{thugpro => thug2}/silent.SKA (100%) create mode 100644 assets/saves/thug2/sk.SKA create mode 100644 assets/saves/thug2/skgr.SKA rename assets/saves/{thugpro => thug2}/slimehoodie.SKA (100%) rename assets/saves/{thugpro => thug2}/smg2pizza.SKA (85%) rename assets/saves/{thugpro => thug2}/smoke.SKA (100%) rename assets/saves/{thugpro => thug2}/somewhatfayte.SKA (100%) rename assets/saves/{thugpro => thug2}/sonics.SKA (100%) rename assets/saves/{thugpro => thug2}/spbobsmg.SKA (100%) rename assets/saves/{thugpro => thug2}/spooker.SKA (100%) create mode 100644 assets/saves/thug2/stilent.SKA create mode 100644 assets/saves/thug2/stomT1re.SKA create mode 100644 assets/saves/thug2/stomchain.SKA create mode 100644 assets/saves/thug2/stompALT.SKA create mode 100644 assets/saves/thug2/stompzsunnewboa.SKA create mode 100644 assets/saves/thug2/striped chilll.SKA create mode 100644 assets/saves/thug2/stuehat.SKA create mode 100644 assets/saves/thug2/sunhat.SKA rename assets/saves/{thugpro => thug2}/sunhatscales.SKA (100%) create mode 100644 assets/saves/thug2/supreme drip.SKA create mode 100644 assets/saves/thug2/t1type.SKA create mode 100644 assets/saves/thug2/temp..SKA create mode 100644 assets/saves/thug2/test.SKA create mode 100644 assets/saves/thug2/thesedoctors.SKA rename assets/saves/{thugpro => thug2}/thiccboi.SKA (100%) create mode 100644 assets/saves/thug2/thinOrng.SKA rename assets/saves/{thugpro => thug2}/thugg.SKA (100%) rename assets/saves/{thugpro => thug2}/thugg_2.SKA (100%) rename assets/saves/{thugpro => thug2}/thuggcrazy.SKA (100%) rename assets/saves/{thugpro => thug2}/tlt22222.SKA (100%) rename assets/saves/{thugpro => thug2}/tltv5faytelec.SKA (100%) rename assets/saves/{thugpro => thug2}/uhhh_hmm.SKA (100%) create mode 100644 assets/saves/thug2/uktfc.SKA create mode 100644 assets/saves/thug2/uktfcc.SKA rename assets/saves/{thugpro => thug2}/v1c.SKA (100%) rename assets/saves/{thugpro => thug2}/vegasmg2.SKA (100%) rename assets/saves/{thugpro => thug2}/velho.SKA (100%) rename assets/saves/{thugpro => thug2}/vestupson.SKA (100%) rename assets/saves/{thugpro => thug2}/vestupwbeanie.SKA (100%) rename assets/saves/{thugpro => thug2}/vicphun.SKA (100%) rename assets/saves/{thugpro => thug2}/viking.SKA (100%) create mode 100644 assets/saves/thug2/wat.SKA create mode 100644 assets/saves/thug2/wdf.SKA rename assets/saves/{thugpro => thug2}/whitepink.SKA (100%) create mode 100644 assets/saves/thug2/whore.SKA rename assets/saves/{thugpro => thug2}/wormgurl.SKA (100%) rename assets/saves/{thugpro => thug2}/wormgurlbw.SKA (100%) rename assets/saves/{thugpro => thug2}/wormslime.SKA (100%) rename assets/saves/{thugpro => thug2}/wormsmonkknk.SKA (100%) rename assets/saves/{thugpro => thug2}/x3og.SKA (100%) create mode 100644 assets/saves/thug2/xdd.SKA create mode 100644 assets/saves/thug2/xm.SKA create mode 100644 assets/saves/thug2/yea.SKA create mode 100644 assets/saves/thug2/yell.SKA create mode 100644 assets/saves/thug2/yeller.SKA create mode 100644 assets/saves/thug2/yellow.SKA create mode 100644 assets/saves/thug2/yuzuriah.SKA rename assets/saves/{thugpro => thug2}/zoo.SKA (100%) create mode 100644 assets/saves/thug2/zzz.SKA create mode 100644 assets/saves/thug2/zzz3.SKA delete mode 100644 assets/saves/thugpro/Ned the Cyclops.SKA create mode 100644 crates/cascade-test/Cargo.toml create mode 100644 crates/cascade-test/src/lib.rs delete mode 100644 crates/cascade-thaw/src/entry.rs create mode 100644 crates/cascade-thaw/tests/round_trip.rs create mode 100644 crates/cascade-thps4/src/cas.rs create mode 100644 crates/cascade-thps4/src/id.rs create mode 100644 crates/cascade-thps4/src/save.rs create mode 100644 crates/cascade-thps4/tests/round_trip.rs delete mode 100644 crates/cascade-thug2/src/entry.rs delete mode 100644 crates/cascade-thug2/tests/common/mod.rs diff --git a/.justfile b/.justfile index b995f43..b9c53fc 100644 --- a/.justfile +++ b/.justfile @@ -11,3 +11,6 @@ fmt: build-windows: cargo build --target x86_64-pc-windows-gnu --release + +run: + cargo run --package cascade-app diff --git a/Cargo.toml b/Cargo.toml index 8d857a4..d4f1765 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,12 +15,14 @@ cascade-dump = { path = "crates/cascade-dump" } cascade-lut = { path = "crates/cascade-lut" } cascade-qb = { path = "crates/cascade-qb" } cascade-save = { path = "crates/cascade-save" } +cascade-test = { path = "crates/cascade-test" } cascade-thaw = { path = "crates/cascade-thaw" } cascade-thps4 = { path = "crates/cascade-thps4" } cascade-thug = { path = "crates/cascade-thug" } cascade-thug2 = { path = "crates/cascade-thug2" } cascade-wad = { path = "crates/cascade-wad" } +anyhow = "1.0" byteorder = "1.4.3" clap = { version = "4.5.16", features = ["derive"] } color-eyre = "0.6" diff --git a/assets/saves/thaw/Assi iSL-Progress b/assets/saves/thaw/Assi iSL-Progress new file mode 100644 index 0000000000000000000000000000000000000000..83bb90542744183e92cce9dec6adb3466456d22b GIT binary patch literal 98304 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�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 literal 0 HcmV?d00001 diff --git a/assets/saves/thaw/SSX Edem-Progress b/assets/saves/thaw/SSX Edem-Progress new file mode 100644 index 0000000000000000000000000000000000000000..031c0d59b7d7634e560168eeae91747ad6683379 GIT binary patch literal 140651 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 literal 0 HcmV?d00001 diff --git a/assets/saves/thaw/Skater 3-Progress b/assets/saves/thaw/Skater 3-Progress new file mode 100644 index 0000000000000000000000000000000000000000..be03894f911f6b967c7c8cf9f76b91113efb8c90 GIT binary patch literal 180224 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 fpCd1HO~fezIM(&_=WE-F@cvuico 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 literal 0 HcmV?d00001 diff --git a/assets/saves/thaw/Skater-Progress b/assets/saves/thaw/Skater-Progress new file mode 100644 index 0000000000000000000000000000000000000000..18307dcd2cb76a3f5855519dd2eb99daebd3956d GIT binary patch literal 180224 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 literal 0 HcmV?d00001 diff --git a/assets/saves/thaw/thps2-Progress b/assets/saves/thaw/thps2-Progress new file mode 100644 index 0000000000000000000000000000000000000000..457a739c49522d69570dfee7fabe9ef8e06edbd4 GIT binary patch literal 198717 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 B1w#M; literal 0 HcmV?d00001 diff --git a/assets/saves/thps4/bluepurp.SKA b/assets/saves/thps4/bluepurp.SKA new file mode 100644 index 0000000000000000000000000000000000000000..cd8a09a7529d334643f9d2669c1af0b54884d422 GIT binary patch literal 2048 zcmY#cF|SS9QF8`A0|UbkW(EdcAk92W?91V#oYK^S(xL(e2CkHs)m#D}PB2L_apl+g zgmU?Q30L9u}tfh%`4e=3;kBx}XW!1cn0I}Xf^WZcHaz{Sq*rvv61{LgP- z;JTlyY7ge7*SqeRpzv^lqQwLytx3uZT-9<uCxCb89$PX)B}T}((8R2i|a z2P;egD~tmxOo1rmTJq%ZJ+NdvSTY_g84oo@2yDtr|D7ipx&)EftYG$+Wgmgj!L{OC znF;e*JH0UH(&Cc*Tn6UpFBLRG^D=V_a#C|s^GZ@v7!u!A0_C}o6Qs2`XaQ?$~r{16nIc105;I-#vuk?lp3(nl$8)`U7HK;eN zEJ)w3H{9n`n`p21i8CAfdVTMoUS8Gf-xfMIq&KqO`ERYz!!0W_7<%nbzZ4Gda^wLy zoQsEn_hAitbcE>BI^G5)t(8kWW3wPaFO%2K2Mf*Qm4*tH1nt@b7TW7DBLSl7^n)$m z!9xEpoil(4JxYvJ0t*to$DEEKZeAPyp=%x3i;EW{!7s23uX9=R_AEVOa%nm`6HYr+JcZ(yH+7z_*( zOt>bPa!oMfnqbZ~!GddoC6_>r=jmLo307PaY`7*^bM@+~>j?7qYHI)K+bU3Q*l5o< zK~K0@qbjv1g<+D>B*SI{10xe%V-q7w3tbZ{O>)yqi*gtkxKdtLa|wJn!6eDVm0#-< z%C#=~1V67I$0qMki#6R0T-s;On1H#b=gYA(aQS`-R{?YHFSuyHz_sJb%H?3L!vBRb z3|uSyPqTx$SFBlj7`UeOGzEdVANC0FF>sl`vef`{JMY(W0%d=3TtRTVM8NFxuHBLh zT&k8zwqUOOhmQCO3g#0OMJ6bTO;Tp)5(W#W-Do-hwEUfND3}{`@pQ`s1<47DQWKO^ zfU0=kx2QFqnZ5O47b{qPci7~GlN2T>@=s6_0U5##7X5sCUj+k~cU$N^Ft=2sseyrO z)AN5NV6MUcd>}W%*|1xn=B09RqQI-0DlCZt0Uf$?6NO@DOp9XRiuAPI2bL@VOBR47 zQ=pO>E4GM(CG)_Nc_@+zCb7*J#=>+~8L_ViOQwKzMxp3j^5pP6B*_#M$%ln4T42d2 zEIKDl;Dy+UP4anGKtEV#JXmKuvat+YE6$afFrT&43v(_lF3HbjV4nU`K_fITGq)fo zH8(Y{BsGPBmq#;S_THKc#=SbA1l6lGIbmA&B>f&+V1nzib&KG2J_Vv0fFS?h~>uT5e zU7^?Q@m8*Bz3wksw72$p-kNB%yw}U{A45g2&s!nJmR>*M{atDzV}Zruj=)0 z3!NL%8(HuCw^r!kmX#R{z4oVH3Ws+&@_-!9#lyh+u!cQ4LiA}JZ-bK7$|at$SrDO@ z$!q6>g=X?fLxt3)Keho2?RA)u08w@N!Itk}q5qf889;;{B}OWNg*+Mjiy=aD9x6A0 zg#wi8q#!~iLA&;Vg-TpFp{lZjZ@Ytq-Wt?3K~x27+~5Zm3fXTE2N6+?N3s+BkPjAOn~+VFJ%Lu+KmY28IbHToX*WCYW(eFz1?J!8O5>OQ6Q{bS~Ef zE3OGPTobIhCg_Rw>ZD$_@0W4J*CK*jK6e>4tw4Y==!GW8( cLL%ogys!~U=(3o~z>ql#MnhmU1n3X~0QY|ymjD0& literal 0 HcmV?d00001 diff --git a/assets/saves/thps4/cgeo4.SKA b/assets/saves/thps4/cgeo4.SKA new file mode 100644 index 0000000000000000000000000000000000000000..8affe684d378096c897296328f2b4a2fd85d6fd1 GIT binary patch literal 2048 zcmeyqd&;ZFQCE|B7#J9yF*7jm0%_)1VqXp?r>EwdFfeeXysYLD_;7+rl8Gz7)+dz9 z_e;16uOG)IZ+XLC8Vp>ytNByG+==h27#X-;*l@>zxhFc-r!sJ{^ZV(5xd#998yL9m z=c?L+xqsjCcTZ5zn4oAhLCI*6G6Pq&+!Kh*GtCd_lN2T?PEcY4iO<{fn+;(=7dMz~ z+~Ft0&?Srz=i2oAUkMU-$CZ`K!CZy^3uPdtNq|gS>3^CXEMB{N!X5^$X+2FrU~XyD zjzR{m2xr4?ftr`f#R&qhZmO^(2n2NK&P@=CoiQznp^FKuP^(F{Yl4CcZFWJ$6L9k^}4@k(caqYd26E4@?I~)e+(79K5vB>TYCM3_kXSJ zjX15PzNa_f{D)Nqn&P;XdSkiK1SxX-CJ(O&Np zXEyfr`rbdiysFo~Ep%>3Z)Cmm-&&!ETUKT;^xB_(DIDJA2uhI*Ts#cC4{O+?BSfFp z@ir)Ftz6<6n*|YinY?yBSZF4%G*n1!`ePfg&|Zfb2@qAMA8h#!7W#kboB>4WQDUSL zSjdyXzZfDk=b>@~SSUcbP6{Ga60~a%Sg6E>6RIjZ__jM(=&eCr6GT$?u;Q9v!!^O0Yl5C=udcd|Ab+z#YGP3uL$9XxpT4cl8p$TP43mr| s848peHrg{zGM?bT&0Hao^BJ0bg%Y|frZO;Oj)Kt;7!85Z5Woll016@?!2kdN literal 0 HcmV?d00001 diff --git a/assets/saves/thps4/purpmf.SKA b/assets/saves/thps4/purpmf.SKA new file mode 100644 index 0000000000000000000000000000000000000000..6734c5187ec0e093ff069c8c05209e7f922ef834 GIT binary patch literal 2048 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 literal 0 HcmV?d00001 diff --git a/assets/saves/thug/Custom Skater.SKA b/assets/saves/thug/Custom Skater.SKA new file mode 100644 index 0000000000000000000000000000000000000000..1e9f5da59360084d581564ec4eea1845ee92b0de GIT binary patch literal 90112 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

e%X9o1UR^1jMN{4 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 literal 0 HcmV?d00001 diff --git a/assets/saves/thug/THUGSavegame.SKA b/assets/saves/thug/THUGSavegame.SKA new file mode 100644 index 0000000000000000000000000000000000000000..fa48ce2a7c2483b35f7e096f74cf87a5952de14d GIT binary patch literal 90112 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 literal 0 HcmV?d00001 diff --git a/assets/saves/thug/asghan.SKA b/assets/saves/thug/asghan.SKA new file mode 100644 index 0000000000000000000000000000000000000000..2b72843b570a9e1ed46dc5fc0c93724ab240b3c4 GIT binary patch literal 90112 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%0D4iS9*}oBnI{ww^h$_mEelP9~LfxO6N6eo)UL3wd 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�oTYv-uqle*j-oJl?EnhET}67r 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 s=tQw}LioxiLo6)vA{7o+tR~0b>v$ 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 literal 0 HcmV?d00001 diff --git a/assets/saves/thug/fly.SKA b/assets/saves/thug/fly.SKA new file mode 100644 index 0000000000000000000000000000000000000000..e1e2e93cfdd3bd66f8e7d1c0370c8a1e8d71370f GIT binary patch literal 90112 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 literal 0 HcmV?d00001 diff --git a/assets/saves/thug/genericvy2.SKA b/assets/saves/thug/genericvy2.SKA new file mode 100644 index 0000000000000000000000000000000000000000..e15dabff189514a2dcb8e6353f754c974cbd187e GIT binary patch literal 90112 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