From e569d577885333faa42abee733720197e351d93f Mon Sep 17 00:00:00 2001 From: akanyan Date: Mon, 21 Apr 2025 22:05:37 +0000 Subject: [PATCH] feat: hex patches --- CHANGELOG.md | 4 ++++ README.md | 5 ++++- TODO.md | 1 + rust/src/cmd.rs | 2 +- rust/src/model/patch.rs | 29 +++++++++++++++++++++++++++++ rust/src/modules/mempatcher.rs | 15 +++++++++++++++ rust/static/standard-chunithm.json5 | 20 ++++++++++++++++++++ src/components/PatchEntry.vue | 22 +++++++++++++++++++++- src/types.ts | 2 +- 9 files changed, 96 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6815f2..92fa442 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.14.0 + +- Added the custom FREE PLAY patch for Verse + ## 0.13.0 - Added profile imports/exports diff --git a/README.md b/README.md index 5ade5e3..dcc0177 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -Looking for maimai DX players willing to help develop/test maimai DX support +Looking for + +- maimai DX players willing to help develop/test maimai DX support +- translators (any language other than English) # STARTLINER diff --git a/TODO.md b/TODO.md index c7cd2dc..6fb4895 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,6 @@ ### Short-term +- i18n - https://gitea.tendokyu.moe/TeamTofuShop/segatools/issues/63 ### Long-term diff --git a/rust/src/cmd.rs b/rust/src/cmd.rs index 79b4cfc..0ca1be9 100644 --- a/rust/src/cmd.rs +++ b/rust/src/cmd.rs @@ -431,7 +431,7 @@ pub async fn export_profile(state: State<'_, Mutex>, export_keychip: bo } #[tauri::command] -pub async fn import_profile(state: State<'_, Mutex>, path: PathBuf) -> Result<(), String> { +pub async fn import_profile(path: PathBuf) -> Result<(), String> { log::debug!("invoke: import_profile({:?})", path); Profile::import(path).map_err(|e| e.to_string()) diff --git a/rust/src/model/patch.rs b/rust/src/model/patch.rs index b15d553..4fdd639 100644 --- a/rust/src/model/patch.rs +++ b/rust/src/model/patch.rs @@ -42,6 +42,7 @@ pub struct Patch { pub enum PatchData { Normal(NormalPatch), Number(NumberPatch), + Hex(HexPatch), } #[derive(Deserialize, Serialize, Clone, Debug)] @@ -65,6 +66,12 @@ pub struct NumberPatch { pub max: i32 } +#[derive(Deserialize, Serialize, Clone, Debug)] +pub struct HexPatch { + pub offset: u64, + pub off: Vec, +} + impl Serialize for Patch { fn serialize(&self, serializer: S) -> Result where S: Serializer { @@ -83,6 +90,11 @@ impl Serialize for Patch { state.serialize_field("size", &patch.size)?; state.serialize_field("min", &patch.min)?; state.serialize_field("max", &patch.max)?; + }, + PatchData::Hex(patch) => { + state.serialize_field("type", "hex")?; + state.serialize_field("offset", &patch.offset)?; + state.serialize_field("off", &patch.off)?; } } state.end() @@ -114,6 +126,23 @@ impl<'de> serde::Deserialize<'de> for Patch { .ok_or_else(|| de::Error::missing_field("max"))? ).map_err(|_| de::Error::missing_field("max"))? }), + Some("hex") => { + let mut off_list = Vec::new(); + for off in value.get("off").and_then(Value::as_array).unwrap() { + off_list.push(u8::try_from( + off.as_u64().ok_or_else(|| de::Error::missing_field("off"))? + ).map_err(|_| de::Error::missing_field("off"))?); + } + // for off in value.get("off").and_then(Value::as_str).unwrap().bytes() { + // off_list.push(off); + // } + PatchData::Hex(HexPatch { + offset: value.get("offset") + .and_then(Value::as_u64) + .ok_or_else(|| de::Error::missing_field("offset"))?, + off: off_list + }) + }, None => { let mut patches = vec![]; for patch in value.get("patches").and_then(Value::as_array).unwrap() { diff --git a/rust/src/modules/mempatcher.rs b/rust/src/modules/mempatcher.rs index 0183362..a9be600 100644 --- a/rust/src/modules/mempatcher.rs +++ b/rust/src/modules/mempatcher.rs @@ -50,6 +50,21 @@ impl PatchSelection { } else { log::error!("invalid number patch {:?}", patch); } + }, + PatchData::Hex(data) => { + if let PatchSelectionData::Hex(val) = sel { + res += &format!("{} F+{:X} ", filename, data.offset); + for byte in val { + res += &format!("{:02X}", byte); + } + res += " "; + for byte in &data.off { + res += &format!("{:02X}", byte); + } + } else { + log::error!("invalid number patch {:?}", patch); + } + } } format!("{}\n", res) diff --git a/rust/static/standard-chunithm.json5 b/rust/static/standard-chunithm.json5 index 173ae1a..bc84ea3 100644 --- a/rust/static/standard-chunithm.json5 +++ b/rust/static/standard-chunithm.json5 @@ -326,6 +326,26 @@ }, ], }, + { + id: 'standard-custom-free-play-length', + type: 'number', + name: 'Custom FREE PLAY text length', + tooltip: 'Changes the length of the text displayed when Force FREE PLAY credit text is enabled', + danger: 'If this is longer than 11 characters, \"Force FREE PLAY credit text\" MUST be enabled.', + offset: 0x3875A9, + size: 1, + default: 9, + min: 0, + max: 27, + }, + { + id: 'standard-custom-free-play-text', + type: 'hex', + name: 'Custom FREE PLAY text', + tooltip: 'Replace the FREE PLAY text when using Infinite credits', + offset: 0x1A5DFB4, + off: [0x46, 0x52, 0x45, 0x45, 0x20, 0x50, 0x4c, 0x41, 0x59], + }, ], }, { diff --git a/src/components/PatchEntry.vue b/src/components/PatchEntry.vue index 90a173d..a7ae304 100644 --- a/src/components/PatchEntry.vue +++ b/src/components/PatchEntry.vue @@ -1,5 +1,7 @@ diff --git a/src/types.ts b/src/types.ts index a7b6fc8..cfe50ed 100644 --- a/src/types.ts +++ b/src/types.ts @@ -167,7 +167,7 @@ export interface Patch { id: string; name: string; tooltip: string; - type: undefined | 'number'; + type: undefined | 'number' | 'hex'; default: number; min: number; max: number;