From d44aebe7f8abe26f9c3bd977688a4354f14aeac7 Mon Sep 17 00:00:00 2001 From: crafterpika Date: Sat, 30 May 2026 09:22:59 +0200 Subject: [PATCH 1/9] add svg --- assets/SplatTool.svg | 25536 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 25536 insertions(+) create mode 100644 assets/SplatTool.svg diff --git a/assets/SplatTool.svg b/assets/SplatTool.svg new file mode 100644 index 0000000..f9624cf --- /dev/null +++ b/assets/SplatTool.svg @@ -0,0 +1,25536 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 0c56eb8b897d7c257e6de85801e40bf037608ff6 Mon Sep 17 00:00:00 2001 From: CrafterPika Date: Sat, 27 Jun 2026 08:36:30 +0200 Subject: [PATCH 2/9] fix wayland and allow save editing of equipped weapon --- Func.cs | 8 ++++ Program.cs | 6 +-- SaveEditor.cs | 5 +++ VERSION.txt | 2 +- assets/Info.plist | 2 +- httpMenu.cs | 12 +++++- modmenu/ids.json | 93 ++++++++++++++++++++++++++++++++++++++++++++++ modmenu/index.html | 12 +++++- modmenu/script.js | 14 +++++++ 9 files changed, 147 insertions(+), 7 deletions(-) diff --git a/Func.cs b/Func.cs index 539b1df..5f5660e 100644 --- a/Func.cs +++ b/Func.cs @@ -200,5 +200,13 @@ namespace Func { return "Game not fully loaded yet..."; } } + public static string EquippedWep() { + try { + var p_SaveDataMgr = Program.readUInt32((uint)(Program.readUInt32(SaveEditor.SAVEDATAMGR_ROOT_PTR) + 0xC)); + return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x18C))}"; + } catch { + return "Game not fully loaded yet..."; + } + } } } diff --git a/Program.cs b/Program.cs index 548af78..12e1fc7 100644 --- a/Program.cs +++ b/Program.cs @@ -72,9 +72,9 @@ namespace ModMenu { public static bool IsWayland() { string runtimeDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR"); - if (string.IsNullOrEmpty(runtimeDir)) return false; + if (string.IsNullOrEmpty(runtimeDir) || !Directory.Exists(runtimeDir)) return false; - return File.Exists(Path.Combine(runtimeDir, "wayland-0")); + return Directory.EnumerateFiles(runtimeDir, "wayland-*").Any(); } [STAThread] @@ -188,7 +188,7 @@ namespace ModMenu { Console.WriteLine($"Found target process: {targetProcess.ProcessName} (PID: {pid})"); if (cbase != 0) { - Console.WriteLine("SplatTool v3.2.0 by CrafterPika"); + Console.WriteLine("SplatTool v3.2.1 by CrafterPika"); Console.WriteLine("Special Thanks: Winterberry, Javi.ig and Tombuntu, KittenTM."); cbaseCorrected = (Program.cbase + 0xE000000) - 0x10000000; diff --git a/SaveEditor.cs b/SaveEditor.cs index d886d3e..2c58014 100644 --- a/SaveEditor.cs +++ b/SaveEditor.cs @@ -153,6 +153,11 @@ namespace ModMenu { Program.writeUInt32((uint)(p_save_start + 0xA5B4), amount); } + public static void ChangeEquippedWeapon(uint WeaponSetID) { + var p_save_start = Program.readUInt32((uint)(Program.readUInt32(SAVEDATAMGR_ROOT_PTR) + 0xC)); + Program.writeUInt32((uint)(p_save_start + 0x18C), WeaponSetID); + } + private static T ByteArrayToStructure(byte[] bytes) where T : struct { GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); try { diff --git a/VERSION.txt b/VERSION.txt index 944880f..e4604e3 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -3.2.0 +3.2.1 diff --git a/assets/Info.plist b/assets/Info.plist index a98b3de..c3cadeb 100644 --- a/assets/Info.plist +++ b/assets/Info.plist @@ -13,7 +13,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 3.2.0 + 3.2.1 CFBundleVersion 1 LSMinimumSystemVersion diff --git a/httpMenu.cs b/httpMenu.cs index 950beaf..e8f91c3 100644 --- a/httpMenu.cs +++ b/httpMenu.cs @@ -22,6 +22,7 @@ namespace ModMenu { public static uint Level; public static uint Cash; public static uint SeaSnails; + public static uint WeaponSetID; public static SessionData session = new SessionData(); static WorkThread sessiondIdThread = new WorkThread(() => { Codes.forceSessiondId(sessionId); @@ -45,12 +46,16 @@ namespace ModMenu { Thread.Sleep(5000); SplatTelemetry.SendTelemetry(); }); + static WorkThread WeaponChangeThread = new WorkThread(() => { + SaveEditor.ChangeEquippedWeapon(WeaponSetID); + }); + public static string RunCode(ModMenuRequest data) { if (data?.action == null) return "0"; switch (data.action) { case "cbase": - return $"Cemu Base: 0x{Program.cbase:X} (0x{Program.cbaseCorrected:X})

Total Wins: {Codes.TotalWins()}
Total Losses: {Codes.TotalLoss()}

Thread Status:
- Write Gear: {WriteGear.Status.ToString()}
- Telemetry: {TelemetryThread.Status.ToString()}
- Change Gender: {ChangeGender.Status.ToString()}
- Change Level: {ChangeLevel.Status.ToString()}
- Change Cash: {ChangeCash.Status.ToString()}
- Change Sea Snails: {ChangeSeaSnails.Status.ToString()}"; + return $"Cemu Base: 0x{Program.cbase:X} (0x{Program.cbaseCorrected:X})

Total Wins: {Codes.TotalWins()}
Total Losses: {Codes.TotalLoss()}
Equipped Weapon: {Codes.EquippedWep()}

Thread Status:
- Write Gear: {WriteGear.Status.ToString()}
- Telemetry: {TelemetryThread.Status.ToString()}
- Change Gender: {ChangeGender.Status.ToString()}
- Change Level: {ChangeLevel.Status.ToString()}
- Change Cash: {ChangeCash.Status.ToString()}
- Change Sea Snails: {ChangeSeaSnails.Status.ToString()}
- Change Weapon: {WeaponChangeThread.Status.ToString()}"; case "sessiondata": return Codes.GetSessionData(); @@ -130,6 +135,11 @@ namespace ModMenu { HandleThread(TelemetryThread); return "1"; + case "WepChange": + WeaponSetID = UInt32.Parse(data.settings[0]); + HandleThread(WeaponChangeThread); + return "1"; + default: return "Not Found"; } diff --git a/modmenu/ids.json b/modmenu/ids.json index 637cbe9..5f00414 100644 --- a/modmenu/ids.json +++ b/modmenu/ids.json @@ -355,5 +355,98 @@ "109": "Ink Resistance Up", "110": "Stealth Jump", "111": "S_Abillity_Locked" + }, + "WeaponSetIds": { + "1000": "Sploosh-o-matic", + "1001": "Neo Sploosh-o-matic", + "1002": "Sploosh-o-matic 7", + "1010": "Splattershot Jr.", + "1011": "Custom Splattershot Jr.", + "1020": "Splash-o-matic", + "1021": "Neo Splash-o-matic", + "1030": "Aerospray MG", + "1031": "Aerospray RG", + "1032": "Aerospray PG", + "1040": "Splattershot", + "1041": "Tentatek Splattershot", + "1042": "Wasabi Splattershot", + "1045": "Hero Shot Replica", + "1046": "Octoshot Replica", + "1050": ".52 Gal", + "1051": ".52 Gal Deco", + "1060": "N-ZAP '85", + "1061": "N-ZAP '89", + "1062": "N-ZAP '83", + "1070": "Splattershot Pro", + "1071": "Forge Splattershot Pro", + "1072": "Berry Splattershot Pro", + "1080": ".96 Gal", + "1081": ".96 Gal Deco", + "1090": "Dual Squelcher", + "1091": "Custom Dual Squelcher", + "1100": "Jet Squelcher", + "1101": "Custom Jet Squelcher", + "1110": "Luna Blaster", + "1111": "Luna Blaster Neo", + "1120": "Blaster", + "1121": "Custom Blaster", + "1130": "Range Blaster", + "1131": "Custom Range Blaster", + "1132": "Grim Range Blaster", + "1140": "Rapid Blaster", + "1141": "Rapid Blaster Deco", + "1150": "Rapid Blaster Pro", + "1151": "Rapid Blaster Pro Deco", + "1160": "L-3 Nozzlenose", + "1161": "L-3 Nozzlenose D", + "1170": "H-3 Nozzlenose", + "1171": "H-3 Nozzlenose D", + "1172": "Cherry H-3 Nozzlenose", + "2000": "Carbon Roller", + "2001": "Carbon Roller Deco", + "2010": "Splat Roller", + "2011": "Krak-On Splat Roller", + "2012": "CoroCoro Splat Roller", + "2015": "Hero Roller Replica", + "2020": "Dynamo Roller", + "2021": "Gold Dynamo Roller", + "2022": "Tempered Dynamo Roller", + "2030": "Inkbrush", + "2031": "Inkbrush Nouveau", + "2032": "Permanent Inkbrush", + "2040": "Octobrush", + "2041": "Octobrush Nouveau", + "3000": "Slosher", + "3001": "Slosher Deco", + "3002": "Soda Slosher", + "3010": "Tri-Slosher", + "3011": "Tri-Slosher Nouveau", + "3020": "Sloshing Machine", + "3021": "Sloshing Machine Neo", + "4000": "Classic Squiffer", + "4001": "New Squiffer", + "4002": "Fresh Squiffer", + "4010": "Splat Charger", + "4011": "Kelp Splat Charger", + "4012": "Bento Splat Charger", + "4015": "Hero Charger Replica", + "4020": "Splatterscope", + "4021": "Kelp Splatterscope", + "4022": "Bento Splatterscope", + "4030": "E-liter 3K", + "4031": "Custom E-liter 3K", + "4040": "E-liter 3K Scope", + "4041": "Custom E-liter 3K Scope", + "4050": "Bamboozler 14 Mk I", + "4051": "Bamboozler 14 Mk II", + "4052": "Bamboozler 14 Mk III", + "5000": "Mini Splatling", + "5001": "Zink Mini Splatling", + "5002": "Refurbished Mini Splatling", + "5010": "Heavy Splatling", + "5011": "Heavy Splatling Deco", + "5012": "Heavy Splatling Remix", + "5020": "Hydra Splatling", + "5021": "Custom Hydra Splatling" } } diff --git a/modmenu/index.html b/modmenu/index.html index 56a433a..72c703e 100644 --- a/modmenu/index.html +++ b/modmenu/index.html @@ -118,6 +118,16 @@ +
+
+ Change Weapon: + Changes Equipped Weapon. +
+
+ + +
+
@@ -177,7 +187,7 @@
-

SplatTool v3.2.0

+

SplatTool v3.2.1

Written by CrafterPika
Special Thanks: Winterberry, Javi.ig, Tombuntu, KittenTM, apoplexy
diff --git a/modmenu/script.js b/modmenu/script.js index f2da8bf..4eb6043 100644 --- a/modmenu/script.js +++ b/modmenu/script.js @@ -73,6 +73,17 @@ function populateAbilities() { }); } +function populateWeaponSets() { + const select = document.getElementById("weapon-sets"); + select.innerHTML = ''; + for (const [val, name] of Object.entries(gearData.WeaponSetIds)) { + const opt = document.createElement('option'); + opt.value = val; + opt.textContent = name; + select.appendChild(opt); + } +} + window.external.receiveMessage(message => { // console.log(message) if (message.startsWith("Cemu Base:")) { @@ -212,12 +223,15 @@ function openTab(evt, tabName) { if (tabName === 'Tab6') { keepStatsUpdated = true; updateStatsPage(); + } else if (tabName == 'Tab8') { + populateWeaponSets() } else { keepStatsUpdated = false; } } function namechange() { sendToCSharp("namechange", [document.getElementById("name-input").value]); } +function changeWeapon() { sendToCSharp("WepChange", [document.getElementById("weapon-sets").value]); } function sessionid() { sendToCSharp("sessionid", [document.getElementById("session-input").value]); } function faceimgtga() { sendToCSharp("faceimgtga", [document.getElementById("format-select").value]); } function GenderChange() { sendToCSharp("ChangeGender", [document.getElementById("gender-select").value]); } From 2d900b0caed594725dbc5683d486504aa1cfd880 Mon Sep 17 00:00:00 2001 From: CrafterPika Date: Sat, 27 Jun 2026 18:38:56 +0200 Subject: [PATCH 3/9] allways set currently selected weapon as default in ui --- httpMenu.cs | 4 ++++ modmenu/script.js | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/httpMenu.cs b/httpMenu.cs index e8f91c3..3378c25 100644 --- a/httpMenu.cs +++ b/httpMenu.cs @@ -140,6 +140,10 @@ namespace ModMenu { HandleThread(WeaponChangeThread); return "1"; + case "EquippedWep": + string weaponId = Codes.EquippedWep(); + return $"{{\"EquippedWepId\": \"{weaponId}\"}}"; + default: return "Not Found"; } diff --git a/modmenu/script.js b/modmenu/script.js index 4eb6043..c6e6b82 100644 --- a/modmenu/script.js +++ b/modmenu/script.js @@ -82,6 +82,8 @@ function populateWeaponSets() { opt.textContent = name; select.appendChild(opt); } + + sendToCSharp("EquippedWep"); } window.external.receiveMessage(message => { @@ -97,6 +99,13 @@ window.external.receiveMessage(message => { try { const data = JSON.parse(message); //console.log("Parsed Data:", data); + + if (data.EquippedWepId !== undefined) { + const select = document.getElementById("weapon-sets"); + select.value = data.EquippedWepId; + return; + } + const container = document.getElementById("pid-display"); if (data.Players) { From 100de2a71b60839b792b768ae432fb43715e7884 Mon Sep 17 00:00:00 2001 From: CrafterPika Date: Sat, 27 Jun 2026 19:46:06 +0200 Subject: [PATCH 4/9] add support for editing headgear, clothes and shoes, seperate into it's own tab --- Func.cs | 26 +++++++++++++++++++ SaveEditor.cs | 12 +++++++++ httpMenu.cs | 52 +++++++++++++++++++++++++++++++++++--- modmenu/index.html | 40 +++++++++++++++++++++++++++++ modmenu/script.js | 63 ++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 179 insertions(+), 14 deletions(-) diff --git a/Func.cs b/Func.cs index 5f5660e..5c76a66 100644 --- a/Func.cs +++ b/Func.cs @@ -200,6 +200,32 @@ namespace Func { return "Game not fully loaded yet..."; } } + + + public static string EquippedHeadgear() { + try { + var p_SaveDataMgr = Program.readUInt32((uint)(Program.readUInt32(SaveEditor.SAVEDATAMGR_ROOT_PTR) + 0xC)); + return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x188))}"; + } catch { + return "Game not fully loaded yet..."; + } + } + public static string EquippedClothes() { + try { + var p_SaveDataMgr = Program.readUInt32((uint)(Program.readUInt32(SaveEditor.SAVEDATAMGR_ROOT_PTR) + 0xC)); + return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x180))}"; + } catch { + return "Game not fully loaded yet..."; + } + } + public static string EquippedShoes() { + try { + var p_SaveDataMgr = Program.readUInt32((uint)(Program.readUInt32(SaveEditor.SAVEDATAMGR_ROOT_PTR) + 0xC)); + return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x184))}"; + } catch { + return "Game not fully loaded yet..."; + } + } public static string EquippedWep() { try { var p_SaveDataMgr = Program.readUInt32((uint)(Program.readUInt32(SaveEditor.SAVEDATAMGR_ROOT_PTR) + 0xC)); diff --git a/SaveEditor.cs b/SaveEditor.cs index 2c58014..ca89462 100644 --- a/SaveEditor.cs +++ b/SaveEditor.cs @@ -153,6 +153,18 @@ namespace ModMenu { Program.writeUInt32((uint)(p_save_start + 0xA5B4), amount); } + public static void ChangeEquippedHeadgear(uint WeaponSetID) { + var p_save_start = Program.readUInt32((uint)(Program.readUInt32(SAVEDATAMGR_ROOT_PTR) + 0xC)); + Program.writeUInt32((uint)(p_save_start + 0x188), WeaponSetID); + } + public static void ChangeEquippedClothes(uint ClothesID) { + var p_save_start = Program.readUInt32((uint)(Program.readUInt32(SAVEDATAMGR_ROOT_PTR) + 0xC)); + Program.writeUInt32((uint)(p_save_start + 0x180), ClothesID); + } + public static void ChangeEquippedShoes(uint ShoesID) { + var p_save_start = Program.readUInt32((uint)(Program.readUInt32(SAVEDATAMGR_ROOT_PTR) + 0xC)); + Program.writeUInt32((uint)(p_save_start + 0x184), ShoesID); + } public static void ChangeEquippedWeapon(uint WeaponSetID) { var p_save_start = Program.readUInt32((uint)(Program.readUInt32(SAVEDATAMGR_ROOT_PTR) + 0xC)); Program.writeUInt32((uint)(p_save_start + 0x18C), WeaponSetID); diff --git a/httpMenu.cs b/httpMenu.cs index 3378c25..adb4944 100644 --- a/httpMenu.cs +++ b/httpMenu.cs @@ -22,6 +22,9 @@ namespace ModMenu { public static uint Level; public static uint Cash; public static uint SeaSnails; + public static uint HeadgearID; + public static uint ClothesID; + public static uint ShoesID; public static uint WeaponSetID; public static SessionData session = new SessionData(); static WorkThread sessiondIdThread = new WorkThread(() => { @@ -46,6 +49,15 @@ namespace ModMenu { Thread.Sleep(5000); SplatTelemetry.SendTelemetry(); }); + static WorkThread HeadgearChangeThread = new WorkThread(() => { + SaveEditor.ChangeEquippedHeadgear(HeadgearID); + }); + static WorkThread ClothesChangeThread = new WorkThread(() => { + SaveEditor.ChangeEquippedClothes(ClothesID); + }); + static WorkThread ShoesChangeThread = new WorkThread(() => { + SaveEditor.ChangeEquippedShoes(ShoesID); + }); static WorkThread WeaponChangeThread = new WorkThread(() => { SaveEditor.ChangeEquippedWeapon(WeaponSetID); }); @@ -55,7 +67,7 @@ namespace ModMenu { switch (data.action) { case "cbase": - return $"Cemu Base: 0x{Program.cbase:X} (0x{Program.cbaseCorrected:X})

Total Wins: {Codes.TotalWins()}
Total Losses: {Codes.TotalLoss()}
Equipped Weapon: {Codes.EquippedWep()}

Thread Status:
- Write Gear: {WriteGear.Status.ToString()}
- Telemetry: {TelemetryThread.Status.ToString()}
- Change Gender: {ChangeGender.Status.ToString()}
- Change Level: {ChangeLevel.Status.ToString()}
- Change Cash: {ChangeCash.Status.ToString()}
- Change Sea Snails: {ChangeSeaSnails.Status.ToString()}
- Change Weapon: {WeaponChangeThread.Status.ToString()}"; + return $"Cemu Base: 0x{Program.cbase:X} (0x{Program.cbaseCorrected:X})

Total Wins: {Codes.TotalWins()}
Total Losses: {Codes.TotalLoss()}
Equipped Headgear: {Codes.EquippedHeadgear()}
Equipped Clothes: {Codes.EquippedClothes()}
Equipped Shoes: {Codes.EquippedShoes()}
Equipped Weapon: {Codes.EquippedWep()}

Thread Status:
- Write Gear: {WriteGear.Status.ToString()}
- Telemetry: {TelemetryThread.Status.ToString()}
- Change Gender: {ChangeGender.Status.ToString()}
- Change Level: {ChangeLevel.Status.ToString()}
- Change Cash: {ChangeCash.Status.ToString()}
- Change Sea Snails: {ChangeSeaSnails.Status.ToString()}
- Change Headgear: {HeadgearChangeThread.Status.ToString()}
- Change Clothes: {ClothesChangeThread.Status.ToString()}
- Change Shoes: {ShoesChangeThread.Status.ToString()}
- Change Weapon: {WeaponChangeThread.Status.ToString()}"; case "sessiondata": return Codes.GetSessionData(); @@ -135,14 +147,48 @@ namespace ModMenu { HandleThread(TelemetryThread); return "1"; + case "HeadgearChange": + HeadgearID = UInt32.Parse(data.settings[0]); + HandleThread(HeadgearChangeThread); + return "1"; + + case "HeadgearChangeApply": + HeadgearID = UInt32.Parse(data.settings[0]); + return "1"; + + case "ClothesChange": + ClothesID = UInt32.Parse(data.settings[0]); + HandleThread(ClothesChangeThread); + return "1"; + + case "ClothesChangeApply": + ClothesID = UInt32.Parse(data.settings[0]); + return "1"; + + case "ShoesChange": + ShoesID = UInt32.Parse(data.settings[0]); + HandleThread(ShoesChangeThread); + return "1"; + + case "ShoesChangeApply": + ShoesID = UInt32.Parse(data.settings[0]); + return "1"; + case "WepChange": WeaponSetID = UInt32.Parse(data.settings[0]); HandleThread(WeaponChangeThread); return "1"; - case "EquippedWep": + case "WepChangeApply": + WeaponSetID = UInt32.Parse(data.settings[0]); + return "1"; + + case "AllEquipment": + string headgearID = Codes.EquippedHeadgear(); + string clothesID = Codes.EquippedClothes(); + string shoesID = Codes.EquippedShoes(); string weaponId = Codes.EquippedWep(); - return $"{{\"EquippedWepId\": \"{weaponId}\"}}"; + return $"{{\"EquippedHeadgearId\": \"{headgearID}\", \"EquippedClothesId\": \"{clothesID}\", \"EquippedShoesId\": \"{shoesID}\", \"EquippedWepId\": \"{weaponId}\"}}"; default: return "Not Found"; diff --git a/modmenu/index.html b/modmenu/index.html index 72c703e..9ddf0f5 100644 --- a/modmenu/index.html +++ b/modmenu/index.html @@ -14,6 +14,7 @@
+ @@ -118,6 +119,44 @@
+ + + +
+
+
+
+ Change Headgear: + Changes Equipped Headgear. +
+
+ + + +
+
+
+
+ Change Clothes: + Changes Clothes Headgear. +
+
+ + + +
+
+
+
+ Change Shoes: + Changes Shoes Headgear. +
+
+ + + +
+
Change Weapon: @@ -126,6 +165,7 @@
+
diff --git a/modmenu/script.js b/modmenu/script.js index c6e6b82..4b848e5 100644 --- a/modmenu/script.js +++ b/modmenu/script.js @@ -73,17 +73,45 @@ function populateAbilities() { }); } -function populateWeaponSets() { - const select = document.getElementById("weapon-sets"); - select.innerHTML = ''; +function populateEquipment() { + const weapons = document.getElementById("weapon-sets"); + const headgear = document.getElementById("headgear-sets"); + const clothes = document.getElementById("clothes-sets"); + const shoes = document.getElementById("shoes-sets"); + + weapons.innerHTML = ''; for (const [val, name] of Object.entries(gearData.WeaponSetIds)) { const opt = document.createElement('option'); opt.value = val; opt.textContent = name; - select.appendChild(opt); + weapons.appendChild(opt); } - sendToCSharp("EquippedWep"); + headgear.innerHTML = ''; + for (const [val, name] of Object.entries(gearData.headgear)) { + const opt = document.createElement('option'); + opt.value = val; + opt.textContent = name; + headgear.appendChild(opt); + } + + clothes.innerHTML = ''; + for (const [val, name] of Object.entries(gearData.clothes)) { + const opt = document.createElement('option'); + opt.value = val; + opt.textContent = name; + clothes.appendChild(opt); + } + + shoes.innerHTML = ''; + for (const [val, name] of Object.entries(gearData.shoes)) { + const opt = document.createElement('option'); + opt.value = val; + opt.textContent = name; + shoes.appendChild(opt); + } + + sendToCSharp("AllEquipment"); } window.external.receiveMessage(message => { @@ -98,11 +126,17 @@ window.external.receiveMessage(message => { try { const data = JSON.parse(message); - //console.log("Parsed Data:", data); + console.log("Parsed Data:", data); if (data.EquippedWepId !== undefined) { - const select = document.getElementById("weapon-sets"); - select.value = data.EquippedWepId; + const weapons = document.getElementById("weapon-sets"); + const headgear = document.getElementById("headgear-sets"); + const clothes = document.getElementById("clothes-sets"); + const shoes = document.getElementById("shoes-sets"); + weapons.value = data.EquippedWepId; + headgear.value = data.EquippedHeadgearId; + clothes.value = data.EquippedClothesId; + shoes.value = data.EquippedShoesId; return; } @@ -232,15 +266,14 @@ function openTab(evt, tabName) { if (tabName === 'Tab6') { keepStatsUpdated = true; updateStatsPage(); - } else if (tabName == 'Tab8') { - populateWeaponSets() + } else if (tabName == 'Tab9') { + populateEquipment() } else { keepStatsUpdated = false; } } function namechange() { sendToCSharp("namechange", [document.getElementById("name-input").value]); } -function changeWeapon() { sendToCSharp("WepChange", [document.getElementById("weapon-sets").value]); } function sessionid() { sendToCSharp("sessionid", [document.getElementById("session-input").value]); } function faceimgtga() { sendToCSharp("faceimgtga", [document.getElementById("format-select").value]); } function GenderChange() { sendToCSharp("ChangeGender", [document.getElementById("gender-select").value]); } @@ -250,3 +283,11 @@ function SeaSnails() { sendToCSharp("ChangeSeaSnails", [document.getElementById( function execute(cheat) { sendToCSharp(cheat); } function fetchCemuBase() { sendToCSharp("cbase"); } function fetchPids() { sendToCSharp("sessiondata"); } +function changeHeadgear() { sendToCSharp("HeadgearChange", [document.getElementById("headgear-sets").value]); } +function changeHeadgearApply() { sendToCSharp("HeadgearChangeApply", [document.getElementById("headgear-sets").value]); } +function changeClothes() { sendToCSharp("ClothesChange", [document.getElementById("clothes-sets").value]); } +function changeClothesApply() { sendToCSharp("ClothesChangeApply", [document.getElementById("clothes-sets").value]); } +function changeShoes() { sendToCSharp("ShoesChange", [document.getElementById("shoes-sets").value]); } +function changeShoesApply() { sendToCSharp("ShoesChangeApply", [document.getElementById("shoes-sets").value]); } +function changeWeapon() { sendToCSharp("WepChange", [document.getElementById("weapon-sets").value]); } +function changeWeaponApply() { sendToCSharp("WepChangeApply", [document.getElementById("weapon-sets").value]); } From 7358c34063b961b5606bbe1c4dc2072cf1feccdd Mon Sep 17 00:00:00 2001 From: CrafterPika Date: Sat, 27 Jun 2026 21:21:29 +0200 Subject: [PATCH 5/9] warn user of potential save file wipe --- modmenu/script.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/modmenu/script.js b/modmenu/script.js index 4b848e5..8214d5b 100644 --- a/modmenu/script.js +++ b/modmenu/script.js @@ -114,6 +114,13 @@ function populateEquipment() { sendToCSharp("AllEquipment"); } +function warnUser() { + if (!sessionStorage.getItem("warnShown")) { + alert("DO NOT USE ANY OF THESE BEFORE THE TITLE SCREEN LOADED OR YOU WILL WIPE YOUR SAVE FILE YOU HAVE BEEN WARNED!!!"); + sessionStorage.setItem('warnShown', 'true'); + } +} + window.external.receiveMessage(message => { // console.log(message) if (message.startsWith("Cemu Base:")) { @@ -266,7 +273,10 @@ function openTab(evt, tabName) { if (tabName === 'Tab6') { keepStatsUpdated = true; updateStatsPage(); + } else if (tabName == 'Tab8') { + warnUser() } else if (tabName == 'Tab9') { + warnUser() populateEquipment() } else { keepStatsUpdated = false; From 867a1df9bf3f5958fa9130e74f3282be3594bc47 Mon Sep 17 00:00:00 2001 From: crafterpika Date: Sun, 28 Jun 2026 00:27:11 +0200 Subject: [PATCH 6/9] fix my stupidity --- modmenu/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modmenu/index.html b/modmenu/index.html index 9ddf0f5..0f927da 100644 --- a/modmenu/index.html +++ b/modmenu/index.html @@ -138,7 +138,7 @@
Change Clothes: - Changes Clothes Headgear. + Changes Clothes.
@@ -149,7 +149,7 @@
Change Shoes: - Changes Shoes Headgear. + Changes Shoes.
From d40ad03badad02208ff9521ba1abc2012c6b243d Mon Sep 17 00:00:00 2001 From: crafterpika Date: Sun, 28 Jun 2026 00:27:55 +0200 Subject: [PATCH 7/9] fix my stupidity part 2 --- modmenu/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modmenu/index.html b/modmenu/index.html index 0f927da..9c98b6a 100644 --- a/modmenu/index.html +++ b/modmenu/index.html @@ -138,7 +138,7 @@
Change Clothes: - Changes Clothes. + Changes Equipped Clothes.
@@ -149,7 +149,7 @@
Change Shoes: - Changes Shoes. + Changes Equipped Shoes.
From f46a4e82832f8a33f3c90df46ab76f75ad139f4b Mon Sep 17 00:00:00 2001 From: CrafterPika Date: Fri, 3 Jul 2026 01:38:36 +0200 Subject: [PATCH 8/9] a little bit of cleanup --- Func.cs | 44 ++++++++++++++++++-------------------------- SaveEditor.cs | 35 +++++++++++++++++++++-------------- httpMenu.cs | 18 +++++++++--------- 3 files changed, 48 insertions(+), 49 deletions(-) diff --git a/Func.cs b/Func.cs index 5c76a66..75765ad 100644 --- a/Func.cs +++ b/Func.cs @@ -202,34 +202,26 @@ namespace Func { } - public static string EquippedHeadgear() { + public static string EquippedGear(string slot) { try { var p_SaveDataMgr = Program.readUInt32((uint)(Program.readUInt32(SaveEditor.SAVEDATAMGR_ROOT_PTR) + 0xC)); - return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x188))}"; - } catch { - return "Game not fully loaded yet..."; - } - } - public static string EquippedClothes() { - try { - var p_SaveDataMgr = Program.readUInt32((uint)(Program.readUInt32(SaveEditor.SAVEDATAMGR_ROOT_PTR) + 0xC)); - return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x180))}"; - } catch { - return "Game not fully loaded yet..."; - } - } - public static string EquippedShoes() { - try { - var p_SaveDataMgr = Program.readUInt32((uint)(Program.readUInt32(SaveEditor.SAVEDATAMGR_ROOT_PTR) + 0xC)); - return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x184))}"; - } catch { - return "Game not fully loaded yet..."; - } - } - public static string EquippedWep() { - try { - var p_SaveDataMgr = Program.readUInt32((uint)(Program.readUInt32(SaveEditor.SAVEDATAMGR_ROOT_PTR) + 0xC)); - return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x18C))}"; + switch (slot.ToLower()) { + case "headgear": + return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x188))}"; + + case "clothes": + return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x180))}"; + + case "shoes": + return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x184))}"; + + case "weapon": + return $"{Program.readUInt32((uint)(p_SaveDataMgr + 0x18C))}"; + + default: + return ""; + } + } catch { return "Game not fully loaded yet..."; } diff --git a/SaveEditor.cs b/SaveEditor.cs index ca89462..831b8f1 100644 --- a/SaveEditor.cs +++ b/SaveEditor.cs @@ -153,21 +153,28 @@ namespace ModMenu { Program.writeUInt32((uint)(p_save_start + 0xA5B4), amount); } - public static void ChangeEquippedHeadgear(uint WeaponSetID) { + public static void ChangeEquippedGear(uint id, string slot) { var p_save_start = Program.readUInt32((uint)(Program.readUInt32(SAVEDATAMGR_ROOT_PTR) + 0xC)); - Program.writeUInt32((uint)(p_save_start + 0x188), WeaponSetID); - } - public static void ChangeEquippedClothes(uint ClothesID) { - var p_save_start = Program.readUInt32((uint)(Program.readUInt32(SAVEDATAMGR_ROOT_PTR) + 0xC)); - Program.writeUInt32((uint)(p_save_start + 0x180), ClothesID); - } - public static void ChangeEquippedShoes(uint ShoesID) { - var p_save_start = Program.readUInt32((uint)(Program.readUInt32(SAVEDATAMGR_ROOT_PTR) + 0xC)); - Program.writeUInt32((uint)(p_save_start + 0x184), ShoesID); - } - public static void ChangeEquippedWeapon(uint WeaponSetID) { - var p_save_start = Program.readUInt32((uint)(Program.readUInt32(SAVEDATAMGR_ROOT_PTR) + 0xC)); - Program.writeUInt32((uint)(p_save_start + 0x18C), WeaponSetID); + switch (slot.ToLower()) { + case "headgear": + Program.writeUInt32((uint)(p_save_start + 0x188), id); + return; + + case "clothes": + Program.writeUInt32((uint)(p_save_start + 0x180), id); + return; + + case "shoes": + Program.writeUInt32((uint)(p_save_start + 0x184), id); + return; + + case "weapon": + Program.writeUInt32((uint)(p_save_start + 0x18C), id); + return; + + default: + return; + } } private static T ByteArrayToStructure(byte[] bytes) where T : struct { diff --git a/httpMenu.cs b/httpMenu.cs index adb4944..e66800b 100644 --- a/httpMenu.cs +++ b/httpMenu.cs @@ -50,16 +50,16 @@ namespace ModMenu { SplatTelemetry.SendTelemetry(); }); static WorkThread HeadgearChangeThread = new WorkThread(() => { - SaveEditor.ChangeEquippedHeadgear(HeadgearID); + SaveEditor.ChangeEquippedGear(HeadgearID, "headgear"); }); static WorkThread ClothesChangeThread = new WorkThread(() => { - SaveEditor.ChangeEquippedClothes(ClothesID); + SaveEditor.ChangeEquippedGear(ClothesID, "clothes"); }); static WorkThread ShoesChangeThread = new WorkThread(() => { - SaveEditor.ChangeEquippedShoes(ShoesID); + SaveEditor.ChangeEquippedGear(ShoesID, "shoes"); }); static WorkThread WeaponChangeThread = new WorkThread(() => { - SaveEditor.ChangeEquippedWeapon(WeaponSetID); + SaveEditor.ChangeEquippedGear(WeaponSetID, "weapon"); }); public static string RunCode(ModMenuRequest data) { @@ -67,7 +67,7 @@ namespace ModMenu { switch (data.action) { case "cbase": - return $"Cemu Base: 0x{Program.cbase:X} (0x{Program.cbaseCorrected:X})

Total Wins: {Codes.TotalWins()}
Total Losses: {Codes.TotalLoss()}
Equipped Headgear: {Codes.EquippedHeadgear()}
Equipped Clothes: {Codes.EquippedClothes()}
Equipped Shoes: {Codes.EquippedShoes()}
Equipped Weapon: {Codes.EquippedWep()}

Thread Status:
- Write Gear: {WriteGear.Status.ToString()}
- Telemetry: {TelemetryThread.Status.ToString()}
- Change Gender: {ChangeGender.Status.ToString()}
- Change Level: {ChangeLevel.Status.ToString()}
- Change Cash: {ChangeCash.Status.ToString()}
- Change Sea Snails: {ChangeSeaSnails.Status.ToString()}
- Change Headgear: {HeadgearChangeThread.Status.ToString()}
- Change Clothes: {ClothesChangeThread.Status.ToString()}
- Change Shoes: {ShoesChangeThread.Status.ToString()}
- Change Weapon: {WeaponChangeThread.Status.ToString()}"; + return $"Cemu Base: 0x{Program.cbase:X} (0x{Program.cbaseCorrected:X})

Total Wins: {Codes.TotalWins()}
Total Losses: {Codes.TotalLoss()}
Equipped Headgear: {Codes.EquippedGear("headgear")}
Equipped Clothes: {Codes.EquippedGear("clothes")}
Equipped Shoes: {Codes.EquippedGear("shoes")}
Equipped Weapon: {Codes.EquippedGear("weapon")}

Thread Status:
- Write Gear: {WriteGear.Status.ToString()}
- Telemetry: {TelemetryThread.Status.ToString()}
- Change Gender: {ChangeGender.Status.ToString()}
- Change Level: {ChangeLevel.Status.ToString()}
- Change Cash: {ChangeCash.Status.ToString()}
- Change Sea Snails: {ChangeSeaSnails.Status.ToString()}
- Change Headgear: {HeadgearChangeThread.Status.ToString()}
- Change Clothes: {ClothesChangeThread.Status.ToString()}
- Change Shoes: {ShoesChangeThread.Status.ToString()}
- Change Weapon: {WeaponChangeThread.Status.ToString()}"; case "sessiondata": return Codes.GetSessionData(); @@ -184,10 +184,10 @@ namespace ModMenu { return "1"; case "AllEquipment": - string headgearID = Codes.EquippedHeadgear(); - string clothesID = Codes.EquippedClothes(); - string shoesID = Codes.EquippedShoes(); - string weaponId = Codes.EquippedWep(); + string headgearID = Codes.EquippedGear("headgear"); + string clothesID = Codes.EquippedGear("clothes"); + string shoesID = Codes.EquippedGear("shoes"); + string weaponId = Codes.EquippedGear("weapon"); return $"{{\"EquippedHeadgearId\": \"{headgearID}\", \"EquippedClothesId\": \"{clothesID}\", \"EquippedShoesId\": \"{shoesID}\", \"EquippedWepId\": \"{weaponId}\"}}"; default: From 6345e3373fec71d0574f24fa879e041d29526d96 Mon Sep 17 00:00:00 2001 From: CrafterPika Date: Sat, 8 Aug 2026 08:37:46 +0200 Subject: [PATCH 9/9] update spfn api to new domain --- Func.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Func.cs b/Func.cs index 75765ad..6011855 100644 --- a/Func.cs +++ b/Func.cs @@ -50,7 +50,7 @@ namespace Func { return "0"; } } else { - HttpResponseMessage response = await client.GetAsync($"https://account.spfn.net/v1/api/admin/mapped_ids?input_type=pid&output_type=user_id&input={pid}"); + HttpResponseMessage response = await client.GetAsync($"https://account.spbr.net/v1/api/admin/mapped_ids?input_type=pid&output_type=user_id&input={pid}"); if (response.IsSuccessStatusCode) { string content = await response.Content.ReadAsStringAsync(); XDocument doc = XDocument.Parse(content);