From a57cbf35253dc1e5c1d3c336c90713c3b9860f06 Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Tue, 11 Jun 2024 23:25:00 +0200 Subject: [PATCH 01/13] begin work on FS patching - more complex than onionfs --- include/Megamix/Region.hpp | 19 +++++++++++++ include/Megamix/Types.hpp | 41 +++++++++++++++++++++++++++ src/Megamix/Hooks.cpp | 58 ++++++++++++++++++++++++++++++++++++++ src/Megamix/Region.cpp | 57 +++++++++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+) diff --git a/include/Megamix/Region.hpp b/include/Megamix/Region.hpp index 3cf888e..ea323aa 100644 --- a/include/Megamix/Region.hpp +++ b/include/Megamix/Region.hpp @@ -6,6 +6,8 @@ #include "types.h" +#include "Megamix/Types.hpp" + extern u8 region; namespace Region { @@ -51,6 +53,23 @@ namespace Region { u32 RegionFSHookFunc(); u32 RegionOtherHookFunc(); + + typedef void* (*IsFileCachedSignature) (void* cachedFileManager, s32 fileId, Megamix::FileInfo* fileInfo); + typedef bool (*CacheFileSignature) (void* cachedFileManager, s32 fileId, Megamix::FileInfo* fileInfo); + + typedef Result (*TryOpenFileSignature) (Megamix::FileInputStream::FileBase* fileBase, wchar_t* filePath, u32 mode); + typedef Result (*CloseFileSignature) (void* ptr); + typedef Result (*TryGetSizeSignature) (Megamix::FileInputStream::FileBase* fileBase, s64 position); + + u32 DoOpenFileFunc(); + u32 CacheFileManagerPos(); + u32 FileInputStreamVtable(); + IsFileCachedSignature IsFileCachedFunc(); + CacheFileSignature CacheFileFunc(); + TryOpenFileSignature TryOpenFileFunc(); + CloseFileSignature CloseFileFunc(); + TryGetSizeSignature TryGetSizeFunc(); + } #endif \ No newline at end of file diff --git a/include/Megamix/Types.hpp b/include/Megamix/Types.hpp index 57d1dcd..2416da5 100644 --- a/include/Megamix/Types.hpp +++ b/include/Megamix/Types.hpp @@ -242,6 +242,47 @@ namespace Megamix { this->edgeFade = edgeFade; } }; + + + struct FileInfo { + wchar_t filePath[0x80]; + void* fileBuffer; + u8* compressedFileBuffer; + void* unk108; + u32 fileSize; + u32 compressedFileSize; + u32 unk114; + u8 mode; + s32 fileId; + }; + + struct FileInputStream { + void* vtable; + struct FileBase { + void* ptr; + s64 position; + s64 size; + } base; + }; + + struct CFileManager { + void* vtable; + s32 unk4; + s32 unk8; + void* romWorkingMemory; + u32 romWorkingMemorySize; + u8* gzipWorkingMemory; + FileInfo* fileInfo; + u32 fileIds; + u32 fileIdCount; + u32 unk24; + bool unk28; + u32 unk2C; + wchar_t locale[9]; + wchar_t sublocale[9]; + struct { u32 unk[2]; } thread; //TODO + bool threadCreated; + }; } #endif \ No newline at end of file diff --git a/src/Megamix/Hooks.cpp b/src/Megamix/Hooks.cpp index 7d808be..42baa9a 100644 --- a/src/Megamix/Hooks.cpp +++ b/src/Megamix/Hooks.cpp @@ -6,7 +6,9 @@ #include "Megamix.hpp" #include "Config.hpp" +using CTRPluginFramework::File; using CTRPluginFramework::OSD; +using CTRPluginFramework::Utils; using Megamix::TempoTable; @@ -172,4 +174,60 @@ namespace Megamix::Hooks { // if either StubbedFunction or StubFunction is used with a type, a template // instantiation must be added with that type template void StubFunction(u32); + + void doReadFile(CFileManager* self, FileInfo* fileInfo) { + void* cache; // i don't feel like making another struct for this undocumented thing, so pointer arithmetic go brr + + // cached filesystem hell + if (fileInfo->fileId >= 0 && (cache = Region::IsFileCachedFunc()(*(void**)Region::CacheFileManagerPos(), fileInfo->fileId, fileInfo), cache != 0)) { + fileInfo->fileSize = *(u32*)(cache + 0x84); + fileInfo->fileBuffer = new u8[fileInfo->fileSize]; + memcpy(fileInfo->fileBuffer, *(void**)(cache + 0x80), fileInfo->fileSize); + } + + FileInputStream inputStream = {(void*)Region::FileInputStreamVtable(), {0, 0, 0}}; + wchar_t* buffer = new wchar_t[256]; + File file_ctrpf; + Result result_ctrpf; + Result result_game; + + auto game_result_checker = [] (Result result) { + // taken straight from ghidra + return (((result & 0x3fc00) == 0x4400) && (99 < (result & 0x3ff))) && ((result & 0x3ff) < 0xb4); + }; + + const char* LAYERED_LOCATION = "/spicerack/fs/%ls%ls"; + + // sublocale - SD + file_ctrpf = File(); + result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, self->sublocale, fileInfo->filePath + 5), File::Mode::READ); + + // locale - SD + if (result_ctrpf != 0) { + file_ctrpf.Close(); + result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, self->locale, fileInfo->filePath + 5), File::Mode::READ); + } + + // global - SD + if (result_ctrpf != 0) { + file_ctrpf.Close(); + result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, L"", fileInfo->filePath + 5), File::Mode::READ); + } + + if (result_ctrpf == 0) { + // TODO: read file here + } else { + file_ctrpf.Close(); + + //TODO + + // sublocale - RomFS + swprintf(buffer, 256, L"rom:/%ls%ls", self->sublocale, fileInfo->filePath + 5); + result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); + + // locale - RomFS + swprintf(buffer, 256, L"rom:/%ls%ls", self->locale, fileInfo->filePath + 5); + // global + } + } } \ No newline at end of file diff --git a/src/Megamix/Region.cpp b/src/Megamix/Region.cpp index ce13149..c3bcc9b 100644 --- a/src/Megamix/Region.cpp +++ b/src/Megamix/Region.cpp @@ -333,4 +333,61 @@ namespace Region { } } + + // Filesystem patches + u32 DoOpenFileFunc() { + switch (region) { + case JP: + return -1; //TODO! this will probably need a different hook + case US: + return 0x283f5c; + default: + return 0; + } + } + + u32 CacheFileManagerPos() { + switch (region) { + case US: + return 0x54eeec; + default: + return 0; + } + } + + u32 FileInputStreamVtable() { + switch (region) { + case US: + return 0x4f6454; + } + } + + IsFileCachedSignature IsFileCachedFunc() { + switch (region) { + case US: + return (IsFileCachedSignature)0x129fa0; + default: + return nullptr; + } + } + + CacheFileSignature CacheFileFunc() { + switch (region) { + case US: + return (CacheFileSignature)0x120d28; + default: + return nullptr; + } + } + + //TODO + TryOpenFileSignature TryOpenFileFunc() { + + } + CloseFileSignature CloseFileFunc() { + + } + TryGetSizeSignature TryGetSizeFunc() { + + } } \ No newline at end of file From 24c50e0ea40b8fd768a79b64e134dcfa75a67f07 Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Wed, 12 Jun 2024 00:41:10 +0200 Subject: [PATCH 02/13] continue with fs stuff - finish region stuff + file opening logic --- include/Megamix/Region.hpp | 3 ++- src/Megamix/Hooks.cpp | 38 ++++++++++++++++++++++++++++++++------ src/Megamix/Region.cpp | 33 ++++++++++++++++++++++++++++++--- 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/include/Megamix/Region.hpp b/include/Megamix/Region.hpp index ea323aa..8f4d647 100644 --- a/include/Megamix/Region.hpp +++ b/include/Megamix/Region.hpp @@ -59,7 +59,8 @@ namespace Region { typedef Result (*TryOpenFileSignature) (Megamix::FileInputStream::FileBase* fileBase, wchar_t* filePath, u32 mode); typedef Result (*CloseFileSignature) (void* ptr); - typedef Result (*TryGetSizeSignature) (Megamix::FileInputStream::FileBase* fileBase, s64 position); + typedef Result (*TryGetSizeSignature) (Megamix::FileInputStream::FileBase* fileBase, s64* size); + typedef Result (*TryReadSignature) (Megamix::FileInputStream::FileBase* fileBase, u32* bytesRead, void* fileBuffer, u32 size); u32 DoOpenFileFunc(); u32 CacheFileManagerPos(); diff --git a/src/Megamix/Hooks.cpp b/src/Megamix/Hooks.cpp index 42baa9a..82f5071 100644 --- a/src/Megamix/Hooks.cpp +++ b/src/Megamix/Hooks.cpp @@ -189,7 +189,6 @@ namespace Megamix::Hooks { wchar_t* buffer = new wchar_t[256]; File file_ctrpf; Result result_ctrpf; - Result result_game; auto game_result_checker = [] (Result result) { // taken straight from ghidra @@ -219,15 +218,42 @@ namespace Megamix::Hooks { } else { file_ctrpf.Close(); - //TODO - // sublocale - RomFS swprintf(buffer, 256, L"rom:/%ls%ls", self->sublocale, fileInfo->filePath + 5); - result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); + Result result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); + // locale - RomFS - swprintf(buffer, 256, L"rom:/%ls%ls", self->locale, fileInfo->filePath + 5); - // global + if (game_result_checker(result_game)) { + if ((u32)inputStream.base.ptr >> 1 != 0) { + if ((u32)inputStream.base.ptr & 1 == 1) { + svcBreak(USERBREAK_PANIC); + } + Region::CloseFileFunc()(inputStream.base.ptr); + inputStream.base.ptr = nullptr; + } + + inputStream.base = {0, 0, 0}; + swprintf(buffer, 256, L"rom:/%ls%ls", self->locale, fileInfo->filePath + 5); + result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); + } + + // global - RomFS + if (game_result_checker(result_game)) { + if ((u32)inputStream.base.ptr >> 1 != 0) { + if ((u32)inputStream.base.ptr & 1 == 1) { + svcBreak(USERBREAK_PANIC); + } + Region::CloseFileFunc()(inputStream.base.ptr); + inputStream.base.ptr = nullptr; + } + + inputStream.base = {0, 0, 0}; + swprintf(buffer, 256, L"rom:/%ls%ls", self->locale, fileInfo->filePath + 5); + result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); + } + + // TODO: read and close } } } \ No newline at end of file diff --git a/src/Megamix/Region.cpp b/src/Megamix/Region.cpp index c3bcc9b..ff7b688 100644 --- a/src/Megamix/Region.cpp +++ b/src/Megamix/Region.cpp @@ -359,6 +359,8 @@ namespace Region { switch (region) { case US: return 0x4f6454; + default: + return 0; } } @@ -380,14 +382,39 @@ namespace Region { } } - //TODO TryOpenFileSignature TryOpenFileFunc() { - + switch (region) { + case US: + return (TryOpenFileSignature)0x2859b4; + default: + return nullptr; + } } - CloseFileSignature CloseFileFunc() { + CloseFileSignature CloseFileFunc() { + switch (region) { + case US: + return (CloseFileSignature)0x285944; + default: + return nullptr; + } } + TryGetSizeSignature TryGetSizeFunc() { + switch (region) { + case US: + return (TryGetSizeSignature)0x28595c; + default: + return nullptr; + } + } + TryReadSignature TryReadFunc() { + switch (region) { + case US: + return (TryReadSignature)0x285808; + default: + return nullptr; + } } } \ No newline at end of file From 02b013b3f5b607de4f912f06ba25ab6d9f36b6d2 Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Sun, 23 Jun 2024 17:34:13 +0200 Subject: [PATCH 03/13] finish (?) layeredFS --- Makefile | 2 +- include/Megamix/Region.hpp | 11 ++- include/Megamix/Types.hpp | 2 + src/Megamix/Hooks.cpp | 155 +++++++++++++++++++++++++++---------- src/Megamix/Region.cpp | 11 ++- 5 files changed, 137 insertions(+), 44 deletions(-) diff --git a/Makefile b/Makefile index 4213e6e..bac7437 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ ifneq ($(RELEASE), 0) CFLAGS += -DRELEASE endif -CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++20 +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++20 #-Wno-pointer-arith ASFLAGS := $(ARCH) LDFLAGS := -T $(TOPDIR)/3gx.ld $(ARCH) -Os -Wl,--gc-sections diff --git a/include/Megamix/Region.hpp b/include/Megamix/Region.hpp index 8f4d647..c77fbc6 100644 --- a/include/Megamix/Region.hpp +++ b/include/Megamix/Region.hpp @@ -55,21 +55,28 @@ namespace Region { u32 RegionOtherHookFunc(); typedef void* (*IsFileCachedSignature) (void* cachedFileManager, s32 fileId, Megamix::FileInfo* fileInfo); - typedef bool (*CacheFileSignature) (void* cachedFileManager, s32 fileId, Megamix::FileInfo* fileInfo); + typedef bool (*CacheFileSignature) (void* cachedFileManager, s32 fileId, wchar_t* filePath, void* fileBuffer, size_t fileSize, u8 mode, s32 alignment); typedef Result (*TryOpenFileSignature) (Megamix::FileInputStream::FileBase* fileBase, wchar_t* filePath, u32 mode); typedef Result (*CloseFileSignature) (void* ptr); typedef Result (*TryGetSizeSignature) (Megamix::FileInputStream::FileBase* fileBase, s64* size); typedef Result (*TryReadSignature) (Megamix::FileInputStream::FileBase* fileBase, u32* bytesRead, void* fileBuffer, u32 size); + + typedef void* (*OperatorNewSignature) (size_t size, s32 mode, s32 alignment); - u32 DoOpenFileFunc(); + u32 DoOpenFileHookFunc(); u32 CacheFileManagerPos(); u32 FileInputStreamVtable(); + IsFileCachedSignature IsFileCachedFunc(); CacheFileSignature CacheFileFunc(); TryOpenFileSignature TryOpenFileFunc(); CloseFileSignature CloseFileFunc(); TryGetSizeSignature TryGetSizeFunc(); + TryReadSignature TryReadFunc(); + + // use this to allocate stuff in the game's RAM + OperatorNewSignature OperatorNewFunc(); } diff --git a/include/Megamix/Types.hpp b/include/Megamix/Types.hpp index 2416da5..8c729c4 100644 --- a/include/Megamix/Types.hpp +++ b/include/Megamix/Types.hpp @@ -253,6 +253,8 @@ namespace Megamix { u32 compressedFileSize; u32 unk114; u8 mode; + u32 alignment; + u8 status; s32 fileId; }; diff --git a/src/Megamix/Hooks.cpp b/src/Megamix/Hooks.cpp index 82f5071..ca80dab 100644 --- a/src/Megamix/Hooks.cpp +++ b/src/Megamix/Hooks.cpp @@ -12,6 +12,8 @@ using CTRPluginFramework::Utils; using Megamix::TempoTable; +// TODO: split file further + namespace Megamix::Hooks { RT_HOOK tickflowHook; RT_HOOK gateHook; @@ -24,6 +26,8 @@ namespace Megamix::Hooks { RT_HOOK regionFSHook; RT_HOOK regionOtherHook; + RT_HOOK fsOpenFileHook; + void* getTickflowOffset(int index) { if (config->tickflows.contains(index)) { int result = Megamix::btks.LoadFile(config->tickflows[index]); @@ -115,43 +119,6 @@ namespace Megamix::Hooks { return region; } - void TickflowHooks() { - rtInitHook(&tickflowHook, Region::TickflowHookFunc(), (u32)getTickflowOffset); - rtEnableHook(&tickflowHook); - rtInitHook(&gateHook, Region::GateHookFunc(), (u32)getGateTickflowOffset); - rtEnableHook(&gateHook); - rtInitHook(&gatePracHook, Region::GatePracHookFunc(), (u32)getGatePracticeTickflowOffset); - rtEnableHook(&gatePracHook); - } - - void TempoHooks() { - rtInitHook(&tempoStrmHook, Region::StrmTempoHookFunc(), (u32)getTempoStrm); - rtEnableHook(&tempoStrmHook); - rtInitHook(&tempoSeqHook, Region::SeqTempoHookFunc(), (u32)getTempoSeq); - rtEnableHook(&tempoSeqHook); - rtInitHook(&tempoAllHook, Region::AllTempoHookFunc(), (u32)getTempoAll); - rtEnableHook(&tempoAllHook); - } - - void RegionHooks() { - if (region != Region::JP){ - rtInitHook(®ionFSHook, Region::RegionFSHookFunc(), (u32)getRegionMegamix); - rtEnableHook(®ionFSHook); - } - rtInitHook(®ionOtherHook, Region::RegionOtherHookFunc(), (u32)getRegionCTR); - rtEnableHook(®ionOtherHook); - } - - void DisableAllHooks() { - rtDisableHook(&tickflowHook); - rtDisableHook(&gateHook); - rtDisableHook(&tempoStrmHook); - rtDisableHook(&tempoSeqHook); - rtDisableHook(&tempoAllHook); - rtDisableHook(®ionFSHook); - rtDisableHook(®ionOtherHook); - } - template T StubbedFunction() { return {}; @@ -183,6 +150,7 @@ namespace Megamix::Hooks { fileInfo->fileSize = *(u32*)(cache + 0x84); fileInfo->fileBuffer = new u8[fileInfo->fileSize]; memcpy(fileInfo->fileBuffer, *(void**)(cache + 0x80), fileInfo->fileSize); + return; } FileInputStream inputStream = {(void*)Region::FileInputStreamVtable(), {0, 0, 0}}; @@ -215,6 +183,22 @@ namespace Megamix::Hooks { if (result_ctrpf == 0) { // TODO: read file here + + s64 size = file_ctrpf.GetSize(); + if (size < 0) { + // could not read filesize + svcBreak(USERBREAK_PANIC); + } + fileInfo->fileSize = size; + + void* fileBuffer = Region::OperatorNewFunc()(fileInfo->fileSize, fileInfo->mode, fileInfo->alignment); + result_ctrpf = file_ctrpf.Read(fileBuffer, fileInfo->fileSize); + if (result_ctrpf < 0) { + // could not read file + svcBreak(USERBREAK_PANIC); + } + + file_ctrpf.Close(); } else { file_ctrpf.Close(); @@ -227,6 +211,9 @@ namespace Megamix::Hooks { if (game_result_checker(result_game)) { if ((u32)inputStream.base.ptr >> 1 != 0) { if ((u32)inputStream.base.ptr & 1 == 1) { + // the reason i'm using svcBreak is because any kind of error handling in here is a mess and i don't think we're going to have any errors? + + // pointer is not 2-aligned svcBreak(USERBREAK_PANIC); } Region::CloseFileFunc()(inputStream.base.ptr); @@ -242,6 +229,7 @@ namespace Megamix::Hooks { if (game_result_checker(result_game)) { if ((u32)inputStream.base.ptr >> 1 != 0) { if ((u32)inputStream.base.ptr & 1 == 1) { + // pointer is not 2-aligned svcBreak(USERBREAK_PANIC); } Region::CloseFileFunc()(inputStream.base.ptr); @@ -249,11 +237,98 @@ namespace Megamix::Hooks { } inputStream.base = {0, 0, 0}; - swprintf(buffer, 256, L"rom:/%ls%ls", self->locale, fileInfo->filePath + 5); - result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); + result_game = Region::TryOpenFileFunc()(&inputStream.base, fileInfo->filePath, 1); + } + + // read file (or set status accordingly if file couldn't be opened) + if (game_result_checker(result_game)) { + fileInfo->status = 0xb; + } else { + s64 size; + result_game = Region::TryGetSizeFunc()(&inputStream.base, &size); + if (result_game < 0) { + // couldn't read filesize + svcBreak(USERBREAK_PANIC); + } + + fileInfo->fileSize = size; + fileInfo->fileBuffer = Region::OperatorNewFunc()(size, fileInfo->mode, fileInfo->alignment); + result_game = Region::TryReadFunc()(&inputStream.base, (u32*)&size, fileInfo->fileBuffer, fileInfo->fileSize); + if (result_game < 0) { + // couldn't read file + svcBreak(USERBREAK_PANIC); + } } - // TODO: read and close + // close file if it was opened + if (((s32)inputStream.base.ptr & 0xfffffffe) != 0) { + if (((s32)inputStream.base.ptr & 1) == 1) { + // pointer is not 2-aligned + svcBreak(USERBREAK_PANIC); + } + + Region::CloseFileFunc()(inputStream.base.ptr); // original game has an & 0xfffffffe here which is... superflous considering the million ptr checks + inputStream.base.ptr = nullptr; + + } + + // original game has a second file closing here - not adding unless it seems to give any issues because like wtf + } + + // cache file + // i still refuse to make a struct for cache shit, even if this is documented + u8 is_cache_enabled = *(u8*)(Region::CacheFileManagerPos() + 0xc); + if ((fileInfo->fileId > -1) && is_cache_enabled != 0) { // hey champ shouldnt this also not happen when the file isn't loaded??? + Region::CacheFileFunc()((void*)Region::CacheFileManagerPos(), fileInfo->fileId, fileInfo->filePath, fileInfo->fileBuffer, + fileInfo->fileSize, fileInfo->mode, fileInfo->alignment); + } + + // and done! + } + + + // define hooks + + void TickflowHooks() { + rtInitHook(&tickflowHook, Region::TickflowHookFunc(), (u32)getTickflowOffset); + rtEnableHook(&tickflowHook); + rtInitHook(&gateHook, Region::GateHookFunc(), (u32)getGateTickflowOffset); + rtEnableHook(&gateHook); + rtInitHook(&gatePracHook, Region::GatePracHookFunc(), (u32)getGatePracticeTickflowOffset); + rtEnableHook(&gatePracHook); + } + + void TempoHooks() { + rtInitHook(&tempoStrmHook, Region::StrmTempoHookFunc(), (u32)getTempoStrm); + rtEnableHook(&tempoStrmHook); + rtInitHook(&tempoSeqHook, Region::SeqTempoHookFunc(), (u32)getTempoSeq); + rtEnableHook(&tempoSeqHook); + rtInitHook(&tempoAllHook, Region::AllTempoHookFunc(), (u32)getTempoAll); + rtEnableHook(&tempoAllHook); + } + + void RegionHooks() { + if (region != Region::JP){ + rtInitHook(®ionFSHook, Region::RegionFSHookFunc(), (u32)getRegionMegamix); + rtEnableHook(®ionFSHook); } + rtInitHook(®ionOtherHook, Region::RegionOtherHookFunc(), (u32)getRegionCTR); + rtEnableHook(®ionOtherHook); + } + + void FSHooks() { + rtInitHook(&fsOpenFileHook, Region::DoOpenFileHookFunc(), (u32)doReadFile); + rtEnableHook(&fsOpenFileHook); + } + + void DisableAllHooks() { + rtDisableHook(&tickflowHook); + rtDisableHook(&gateHook); + rtDisableHook(&tempoStrmHook); + rtDisableHook(&tempoSeqHook); + rtDisableHook(&tempoAllHook); + rtDisableHook(®ionFSHook); + rtDisableHook(®ionOtherHook); + rtDisableHook(&fsOpenFileHook); } } \ No newline at end of file diff --git a/src/Megamix/Region.cpp b/src/Megamix/Region.cpp index ff7b688..1e3e36b 100644 --- a/src/Megamix/Region.cpp +++ b/src/Megamix/Region.cpp @@ -335,7 +335,7 @@ namespace Region { } // Filesystem patches - u32 DoOpenFileFunc() { + u32 DoOpenFileHookFunc() { switch (region) { case JP: return -1; //TODO! this will probably need a different hook @@ -417,4 +417,13 @@ namespace Region { return nullptr; } } + + OperatorNewSignature OperatorNewFunc() { + switch (region) { + case US: + return (OperatorNewSignature)0x28b368; + default: + return nullptr; + } + } } \ No newline at end of file From 91e0d0aaf1dcf79f8b5f403b3497e8b0702f92d5 Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Sun, 23 Jun 2024 20:16:11 +0200 Subject: [PATCH 04/13] oops i forgot to toggle it on --- include/Megamix/Hooks.hpp | 1 + src/main.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/Megamix/Hooks.hpp b/include/Megamix/Hooks.hpp index 04b8cd9..a79a9af 100644 --- a/include/Megamix/Hooks.hpp +++ b/include/Megamix/Hooks.hpp @@ -7,6 +7,7 @@ namespace Megamix::Hooks { void TickflowHooks(); void TempoHooks(); void RegionHooks(); + void FSHooks(); void DisableAllHooks(); template T StubbedFunction(); diff --git a/src/main.cpp b/src/main.cpp index ec64541..06a54fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -113,6 +113,10 @@ void ctrpf::PatchProcess(ctrpf::FwkSettings &settings) { Megamix::Hooks::TempoHooks(); } + if (region == Region::US) { + Megamix::Hooks::FSHooks(); + } + if (region != Region::JP && params.extra_rows) { Megamix::Patches::PatchMuseumExtraRows(); } From e90b66f24b7f4da75ccabaef7f12f355dfeb7598 Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Sat, 10 Aug 2024 19:34:56 +0200 Subject: [PATCH 05/13] a bunch of reorganization stuff i forgot to commit --- Makefile | 4 +- include/Helpers.hpp | 13 -- include/Helpers/HoldKey.hpp | 37 ---- include/Helpers/KeySequence.hpp | 36 ---- include/Helpers/MenuEntryHelpers.hpp | 52 ----- include/Helpers/OSDManager.hpp | 55 ----- include/Helpers/QuickMenu.hpp | 82 -------- include/Helpers/Strings.hpp | 16 -- include/Helpers/Wrappers.hpp | 17 -- include/Megamix/Hooks.hpp | 2 +- include/Megamix/Region.hpp | 2 - include/Megamix/Types.hpp | 2 +- include/{ => external}/csvc.h | 0 src/Helpers/HoldKey.cpp | 40 ---- src/Helpers/KeySequence.cpp | 33 --- src/Helpers/OSDManager.cpp | 142 ------------- src/Helpers/QuickMenu.cpp | 174 ---------------- src/Helpers/Strings.cpp | 54 ----- src/Helpers/Wrappers.cpp | 80 -------- src/Megamix/HookFuncs/Charting.cpp | 90 ++++++++ src/Megamix/HookFuncs/FS.cpp | 153 ++++++++++++++ src/Megamix/HookFuncs/HookFuncs.h | 23 +++ src/Megamix/HookFuncs/Misc.cpp | 18 ++ src/Megamix/Hooks.cpp | 294 +++------------------------ src/main.cpp | 2 +- 25 files changed, 315 insertions(+), 1106 deletions(-) delete mode 100644 include/Helpers.hpp delete mode 100644 include/Helpers/HoldKey.hpp delete mode 100644 include/Helpers/KeySequence.hpp delete mode 100644 include/Helpers/MenuEntryHelpers.hpp delete mode 100644 include/Helpers/OSDManager.hpp delete mode 100644 include/Helpers/QuickMenu.hpp delete mode 100644 include/Helpers/Strings.hpp delete mode 100644 include/Helpers/Wrappers.hpp rename include/{ => external}/csvc.h (100%) delete mode 100644 src/Helpers/HoldKey.cpp delete mode 100644 src/Helpers/KeySequence.cpp delete mode 100644 src/Helpers/OSDManager.cpp delete mode 100644 src/Helpers/QuickMenu.cpp delete mode 100644 src/Helpers/Strings.cpp delete mode 100644 src/Helpers/Wrappers.cpp create mode 100644 src/Megamix/HookFuncs/Charting.cpp create mode 100644 src/Megamix/HookFuncs/FS.cpp create mode 100644 src/Megamix/HookFuncs/HookFuncs.h create mode 100644 src/Megamix/HookFuncs/Misc.cpp diff --git a/Makefile b/Makefile index bac7437..ac921df 100644 --- a/Makefile +++ b/Makefile @@ -14,12 +14,12 @@ PLGINFO := saltwater.plgInfo BUILD := build INCLUDES := include -SOURCES := src src/Megamix src/external #src/Helpers +SOURCES := src $(wildcard src/**/.) $(wildcard src/**/**/.) RELEASE ?= 0 FLATPAK := 0 -BARISTA_DIR ?= ../Barista/Barista +BARISTA_DIR ?= ../Barista # Assume flatpak ifeq ($(shell which citra 2> /dev/null || which citra-qt 2> /dev/null || true),) diff --git a/include/Helpers.hpp b/include/Helpers.hpp deleted file mode 100644 index 4c46fe8..0000000 --- a/include/Helpers.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef HELPERS_HPP -#define HELPERS_HPP - -#include "Helpers/AutoRegion.hpp" -#include "Helpers/HoldKey.hpp" -#include "Helpers/KeySequence.hpp" -#include "Helpers/MenuEntryHelpers.hpp" -#include "Helpers/OSDManager.hpp" -#include "Helpers/QuickMenu.hpp" -#include "Helpers/Strings.hpp" -#include "Helpers/Wrappers.hpp" - -#endif diff --git a/include/Helpers/HoldKey.hpp b/include/Helpers/HoldKey.hpp deleted file mode 100644 index d633a85..0000000 --- a/include/Helpers/HoldKey.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef HOLDKEY_HPP -#define HOLDKEY_HPP - -#include "CTRPluginFramework.hpp" - -namespace CTRPluginFramework -{ - class HoldKey - { - public: - /** - * \brief A helping class to check if a key(s) is pressed for a period of time - * \param keys A key or a combo that have to be pressed - * \param holdTime The time the key(s) need to be pressed - */ - HoldKey(u32 keys, Time holdTime); - ~HoldKey(void) {}; - - /** - * \brief Check if the key is pressed - * \return If the key(s) were holded the required amount of time - */ - bool operator()(void); - /** - * \brief Change the keys that needs to be pressed - * \param newKeys The new keys value - */ - void operator = (u32 newKeys); - private: - Clock _timer; - Time _goal; - bool _isHold; - u32 _keys; - }; -}; - -#endif \ No newline at end of file diff --git a/include/Helpers/KeySequence.hpp b/include/Helpers/KeySequence.hpp deleted file mode 100644 index b3b265f..0000000 --- a/include/Helpers/KeySequence.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef HELPERS_KEYSEQUENCE_HPP -#define HELPERS_KEYSEQUENCE_HPP - -#include "types.h" -#include "CTRPluginFramework/System/Controller.hpp" -#include "CTRPluginFramework/System/Clock.hpp" - -#include - -namespace CTRPluginFramework -{ - using KeyVector = std::vector; - - class KeySequence - { - public: - - KeySequence(KeyVector sequence); - ~KeySequence(){} - - /** - * \brief Check the sequence - * \return true if the sequence is completed, false otherwise - */ - bool operator()(void); - - private: - - KeyVector _sequence; - Clock _timer; - unsigned _indexInSequence; - - }; -} - -#endif \ No newline at end of file diff --git a/include/Helpers/MenuEntryHelpers.hpp b/include/Helpers/MenuEntryHelpers.hpp deleted file mode 100644 index 753a7e4..0000000 --- a/include/Helpers/MenuEntryHelpers.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef MENUENTRYHELPERS_HPP -#define MENUENTRYHELPERS_HPP - -#include "CTRPluginFramework/Menu/MenuEntry.hpp" - -namespace CTRPluginFramework -{ - /** - * \brief Return the arg of an entry \n - * If the arg doesn't exist (nullptr) a new one is created calling the default type constructor - * \tparam T The type of the arg - * \param entry The entry to get the arg from - * \return A pointer to the arg (like reinterpret_cast(entry->GetArg())) - */ - template - T *GetArg(MenuEntry *entry) - { - T *arg = reinterpret_cast(entry->GetArg()); - - if (arg == nullptr) - { - arg = new T(); - entry->SetArg(arg); - } - - return (arg); - } - - /** - * \brief Return the arg of an entry \n - * If the arg doesn't exist (nullptr) a new one is created calling the default type constructor - * \tparam T The type of the arg - * \param entry The entry to get the arg from - * \param defaultValue The value to set to a newly created arg - * \return A pointer to the arg (like reinterpret_cast(entry->GetArg())) - */ - template - T *GetArg(MenuEntry *entry, T defaultValue) - { - T *arg = reinterpret_cast(entry->GetArg()); - - if (arg == nullptr) - { - arg = new T(defaultValue); - entry->SetArg(arg); - } - - return (arg); - } -} - -#endif \ No newline at end of file diff --git a/include/Helpers/OSDManager.hpp b/include/Helpers/OSDManager.hpp deleted file mode 100644 index 964fcfb..0000000 --- a/include/Helpers/OSDManager.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef OSD_MANAGER_HPP -#define OSD_MANAGER_HPP - -#include <3ds.h> -#include "CTRPluginFramework.hpp" - -#include -#include -#include - -namespace CTRPluginFramework -{ - #define OSDManager (*_OSDManager::GetInstance()) - - using OSDMITuple = std::tuple; - struct OSDMI - { - OSDMI &operator=(const std::string &str); - OSDMI &operator=(const OSDMITuple &tuple); - OSDMI &SetPos(u32 posX, u32 posY); - OSDMI &SetScreen(bool topScreen); - OSDMI &Enable(void); - OSDMI &Disable(void); - private: - friend class _OSDManager; - explicit OSDMI(OSDMITuple &tuple); - - OSDMITuple &data; - }; - - class _OSDManager - { - public: - ~_OSDManager(void); - - static _OSDManager *GetInstance(void); - - OSDMI operator[](const std::string &key); - void Remove(const std::string &key); - void Lock(void); - void Unlock(void); - private: - - _OSDManager(void); - - static bool OSDCallback(const Screen &screen); - - static _OSDManager *_singleton; - - LightLock _lock; - std::map> _items; - }; -} - -#endif diff --git a/include/Helpers/QuickMenu.hpp b/include/Helpers/QuickMenu.hpp deleted file mode 100644 index 687cf45..0000000 --- a/include/Helpers/QuickMenu.hpp +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef HELPERS_QUICKMENU_HPP -#define HELPERS_QUICKMENU_HPP -#include "types.h" -#include -#include -#include -#include "HoldKey.hpp" - -namespace CTRPluginFramework -{ - using VoidMethod = void(*)(void); - using ArgMethod = void(*)(void *); - using StringVector = std::vector; - struct QuickMenuItem - { - enum class ItemType - { - Entry, SubMenu - }; - - QuickMenuItem(const std::string &name, const ItemType itemType); - - std::string name; - const ItemType itemType; - }; - - struct QuickMenuEntry : QuickMenuItem - { - enum class MethodType - { - VOID, ARG - }; - - QuickMenuEntry(const std::string &name, VoidMethod method); - QuickMenuEntry(const std::string &name, ArgMethod method, void *arg); - ~QuickMenuEntry(); - - MethodType methodType; - union - { - VoidMethod voidMethod; - ArgMethod argMethod; - }; - void *methodArg; - }; - - struct QuickMenuSubMenu : QuickMenuItem - { - QuickMenuSubMenu(const std::string &name); - QuickMenuSubMenu(const std::string &name, const std::vector &items); - ~QuickMenuSubMenu(); - void operator += (QuickMenuItem *item); - void operator -= (QuickMenuItem *item); - - std::vector items; - }; - - class QuickMenu - { - public: - ~QuickMenu(); - static QuickMenu &GetInstance(void); - - void ChangeHotkey(u32 newHotkey); - - void operator += (QuickMenuItem *item); - void operator -= (QuickMenuItem *item); - void operator () (void); - - private: - QuickMenu(u32 hotkey); - - HoldKey _hotkey; - QuickMenuSubMenu *_subMenuOpened; - std::vector _root; - std::stack _submenus; - - static QuickMenu _instance; - }; -} - -#endif \ No newline at end of file diff --git a/include/Helpers/Strings.hpp b/include/Helpers/Strings.hpp deleted file mode 100644 index 1edf548..0000000 --- a/include/Helpers/Strings.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef STRINGS_HPP -#define STRINGS_HPP - -#include - -namespace CTRPluginFramework -{ - std::string Hex(u8 x); - std::string Hex(u16 x); - std::string Hex(u32 x); - std::string Hex(u64 x); - std::string Hex(float x); - std::string Hex(double x); -} - -#endif \ No newline at end of file diff --git a/include/Helpers/Wrappers.hpp b/include/Helpers/Wrappers.hpp deleted file mode 100644 index 2e3804c..0000000 --- a/include/Helpers/Wrappers.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef WRAPPERS_HPP -#define WRAPPERS_HPP - -#include "CTRPluginFramework.hpp" - -namespace CTRPluginFramework -{ - using StringVector = std::vector; - - bool GetInput(u8 &input, const std::string &msg = "", bool useHex = false); - bool GetInput(u16 &input, const std::string &msg = "", bool useHex = false); - bool GetInput(u32 &input, const std::string &msg = "", bool useHex = false); - bool GetInput(float &input, const std::string &msg = ""); - bool GetInput(u16 &input, const StringVector &choices, const std::string &msg = ""); -} - -#endif \ No newline at end of file diff --git a/include/Megamix/Hooks.hpp b/include/Megamix/Hooks.hpp index a79a9af..b9e7fed 100644 --- a/include/Megamix/Hooks.hpp +++ b/include/Megamix/Hooks.hpp @@ -1,7 +1,7 @@ #ifndef MEGAMIX_HOOKS_H #define MEGAMIX_HOOKS_H -#include "types.h" +#include "3ds.h" namespace Megamix::Hooks { void TickflowHooks(); diff --git a/include/Megamix/Region.hpp b/include/Megamix/Region.hpp index c77fbc6..1845b90 100644 --- a/include/Megamix/Region.hpp +++ b/include/Megamix/Region.hpp @@ -4,8 +4,6 @@ #include #include -#include "types.h" - #include "Megamix/Types.hpp" extern u8 region; diff --git a/include/Megamix/Types.hpp b/include/Megamix/Types.hpp index 8c729c4..1422675 100644 --- a/include/Megamix/Types.hpp +++ b/include/Megamix/Types.hpp @@ -3,7 +3,7 @@ #include -#include "types.h" +//#include "types.h" namespace Megamix { struct Tempo { diff --git a/include/csvc.h b/include/external/csvc.h similarity index 100% rename from include/csvc.h rename to include/external/csvc.h diff --git a/src/Helpers/HoldKey.cpp b/src/Helpers/HoldKey.cpp deleted file mode 100644 index 8015052..0000000 --- a/src/Helpers/HoldKey.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "Helpers/HoldKey.hpp" - -namespace CTRPluginFramework -{ - HoldKey::HoldKey(u32 keys, Time holdTime) : - _goal(holdTime), _isHold(false), _keys(keys) - { - } - - bool HoldKey::operator()(void) - { - bool isHold = Controller::IsKeysDown(_keys); - - // If currently hold - if (isHold && _isHold && _timer.HasTimePassed(_goal)) - { - _isHold = false; - return (true); - } - - - - if (isHold && !_isHold) - { - _isHold = true; - _timer.Restart(); - } - else if (_isHold && !isHold) - _isHold = false; - - return (false); - } - - void HoldKey::operator=(u32 newKeys) - { - _keys = newKeys; - _isHold = false; - _timer.Restart(); - } -} diff --git a/src/Helpers/KeySequence.cpp b/src/Helpers/KeySequence.cpp deleted file mode 100644 index 227c52b..0000000 --- a/src/Helpers/KeySequence.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "Helpers/KeySequence.hpp" - -namespace CTRPluginFramework -{ - KeySequence::KeySequence(KeyVector sequence) : - _sequence(sequence), _indexInSequence(0) - { - } - - bool KeySequence::operator()(void) - { - if (Controller::IsKeyDown(_sequence[_indexInSequence])) - { - _indexInSequence++; - - if (_indexInSequence >= _sequence.size()) - { - _indexInSequence = 0; - return (true); - } - - _timer.Restart(); - } - - if (_timer.HasTimePassed(Seconds(1.f))) - { - _indexInSequence = 0; - _timer.Restart(); - } - - return (false); - } -} diff --git a/src/Helpers/OSDManager.cpp b/src/Helpers/OSDManager.cpp deleted file mode 100644 index b9f9337..0000000 --- a/src/Helpers/OSDManager.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include "Helpers/OSDManager.hpp" - -namespace CTRPluginFramework -{ - _OSDManager* _OSDManager::_singleton = nullptr; - - OSDMI& OSDMI::operator=(const std::string &str) - { - OSDManager.Lock(); - std::get<1>(data) = str; - std::get<4>(data) = true; - OSDManager.Unlock(); - return (*this); - } - - OSDMI& OSDMI::operator=(const OSDMITuple &tuple) - { - OSDManager.Lock(); - data = tuple; - OSDManager.Unlock(); - return (*this); - } - - OSDMI& OSDMI::SetPos(u32 posX, u32 posY) - { - OSDManager.Lock(); - std::get<2>(data) = posX; - std::get<3>(data) = posY; - OSDManager.Unlock(); - return (*this); - } - - OSDMI& OSDMI::SetScreen(bool topScreen) - { - OSDManager.Lock(); - std::get<0>(data) = topScreen; - OSDManager.Unlock(); - return (*this); - } - - OSDMI& OSDMI::Enable(void) - { - OSDManager.Lock(); - std::get<4>(data) = true; - OSDManager.Unlock(); - return (*this); - } - - OSDMI& OSDMI::Disable(void) - { - OSDManager.Lock(); - std::get<4>(data) = false; - OSDManager.Unlock(); - return (*this); - } - - OSDMI::OSDMI(OSDMITuple &tuple) : data(tuple) - { - - } - - _OSDManager::~_OSDManager(void) - { - OSD::Stop(OSDCallback); - _items.clear(); - } - - _OSDManager* _OSDManager::GetInstance(void) - { - if (_singleton == nullptr) - _singleton = new _OSDManager; - return (_singleton); - } - - void _OSDManager::Lock(void) - { - LightLock_Lock(&_lock); - } - - void _OSDManager::Unlock(void) - { - LightLock_Unlock(&_lock); - } - - OSDMI _OSDManager::operator[](const std::string &key) - { - Lock(); - OSDMI i(_items[key]); - Unlock(); - return (i); - } - - void _OSDManager::Remove(const std::string& key) - { - Lock(); - _items.erase(key); - Unlock(); - } - - _OSDManager::_OSDManager(void) - { - LightLock_Init(&_lock); - OSD::Run(OSDCallback); - } - - bool _OSDManager::OSDCallback(const Screen &screen) - { - _OSDManager &manager = OSDManager; - - manager.Lock(); - - // If there's no item to draw - if (manager._items.empty()) - { - manager.Unlock(); - return (false); - } - - bool fbEdited = false; - - // Iterate through all our items - for (auto item : manager._items) - { - auto &t = item.second; - std::string &str = std::get<1>(t); - - // If item is disabled or if the item is empty - if (!std::get<4>(t) || str.empty()) - continue; - - // If wanted screen correspond to the screen received, draw the item - if (std::get<0>(t) == screen.IsTop) - { - screen.Draw(str, std::get<2>(t), std::get<3>(t)); - fbEdited = true; - } - } - - manager.Unlock(); - return (fbEdited); - } -} diff --git a/src/Helpers/QuickMenu.cpp b/src/Helpers/QuickMenu.cpp deleted file mode 100644 index f98c4d0..0000000 --- a/src/Helpers/QuickMenu.cpp +++ /dev/null @@ -1,174 +0,0 @@ -#include -#include "Helpers/QuickMenu.hpp" -#include - -namespace CTRPluginFramework -{ - QuickMenuItem::QuickMenuItem(const std::string &name_, const ItemType itemType_) : - name(name_), itemType(itemType_) - { - } - - QuickMenuEntry::QuickMenuEntry(const std::string& name, VoidMethod method) : - QuickMenuItem(name, ItemType::Entry) - { - methodType = MethodType::VOID; - voidMethod = method; - methodArg = nullptr; - } - - QuickMenuEntry::QuickMenuEntry(const std::string& name, ArgMethod method, void* arg) : - QuickMenuItem(name, ItemType::Entry) - { - methodType = MethodType::ARG; - argMethod = method; - methodArg = arg; - } - - QuickMenuEntry::~QuickMenuEntry() - { - } - - QuickMenuSubMenu::QuickMenuSubMenu(const std::string& name) : - QuickMenuItem(name, ItemType::SubMenu) - { - } - - QuickMenuSubMenu::QuickMenuSubMenu(const std::string& name, const std::vector& items_) : - QuickMenuItem(name, ItemType::SubMenu) - { - for (QuickMenuItem *item : items_) - items.push_back(item); - } - - QuickMenuSubMenu::~QuickMenuSubMenu() - { - for (QuickMenuItem *item : items) - delete item; - - items.clear(); - } - - void QuickMenuSubMenu::operator+=(QuickMenuItem* item) - { - items.push_back(item); - } - - void QuickMenuSubMenu::operator-=(QuickMenuItem* item) - { - items.erase(std::remove(items.begin(), items.end(), item), items.end()); - } - - QuickMenu QuickMenu::_instance(Key::Start); - - QuickMenu::QuickMenu(u32 hotkey) : - _hotkey(hotkey, Seconds(0.5f)), - _subMenuOpened(nullptr) - { - } - - QuickMenu::~QuickMenu() - { - for (QuickMenuItem *item : _root) - delete item; - } - - QuickMenu &QuickMenu::GetInstance(void) - { - return (_instance); - } - - void QuickMenu::operator+=(QuickMenuItem* item) - { - _root.push_back(item); - } - - void QuickMenu::operator-=(QuickMenuItem* item) - { - _root.erase(std::remove(_root.begin(), _root.end(), item), _root.end()); - } - - void QuickMenu::operator()(void) - { - if (!_hotkey()) - return; - - Keyboard keyboard; - StringVector options; - - // Create our list of options - for (auto *item : _root) - options.push_back(item->name); - - // Pass it to our keyboard - keyboard.Populate(options); - options.clear(); - while (true) - { - int userChoice = keyboard.Open(); - - // If user selected an item - if (userChoice >= 0) - { - QuickMenuItem *selected = _subMenuOpened ? _subMenuOpened->items[userChoice] : _root[userChoice]; - - // If the selected item is an entry, execute the function - if (selected->itemType == QuickMenuItem::ItemType::Entry) - { - QuickMenuEntry *entry = static_cast(selected); - - if (entry->methodType == QuickMenuEntry::MethodType::VOID) - entry->voidMethod(); - else - entry->argMethod(entry->methodArg); - } - // If it's a submenu, open it - else - { - QuickMenuSubMenu *entry = static_cast(selected); - - if (_subMenuOpened != nullptr) - _submenus.push(_subMenuOpened); - _subMenuOpened = entry; - - // Refresh our list of options - for (QuickMenuItem *item : _subMenuOpened->items) - options.push_back(item->name); - keyboard.Populate(options); - options.clear(); - } - } - // Else if user pressed B - else - { - // If we're inside a submenu, close it - if (_subMenuOpened != nullptr) - { - // If we have a parent, open it - if (_submenus.size()) - { - _subMenuOpened = _submenus.top(); - _submenus.pop(); - } - // Else open root - else - _subMenuOpened = nullptr; - - // Refresh out list of options - for (auto *item : (_subMenuOpened ? _subMenuOpened->items : _root)) - options.push_back(item->name); - keyboard.Populate(options); - options.clear(); - } - // Else if we're on root, close quickmenu - else - break; - } - } - } - - void QuickMenu::ChangeHotkey(u32 newHotkey) - { - _hotkey = newHotkey; - } -} diff --git a/src/Helpers/Strings.cpp b/src/Helpers/Strings.cpp deleted file mode 100644 index 7cf5f64..0000000 --- a/src/Helpers/Strings.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include -#include - -namespace CTRPluginFramework -{ - std::string Hex(u8 x) - { - char buffer[3]; - - sprintf(buffer, "%02X", x); - return (std::string(buffer)); - } - - std::string Hex(u16 x) - { - char buffer[5]; - - sprintf(buffer, "%04X", x); - return (std::string(buffer)); - } - - std::string Hex(u32 x) - { - char buffer[9]; - - sprintf(buffer, "%08X", x); - return (std::string(buffer)); - } - - std::string Hex(u64 x) - { - char buffer[17]; - - sprintf(buffer, "%016llX", x); - return (std::string(buffer)); - } - - std::string Hex(float x) - { - char buffer[9]; - - sprintf(buffer, "%08X", (u32)x); - return (std::string(buffer)); - } - - std::string Hex(double x) - { - char buffer[17]; - - sprintf(buffer, "%016llX", (u64)x); - return (std::string(buffer)); - } -} diff --git a/src/Helpers/Wrappers.cpp b/src/Helpers/Wrappers.cpp deleted file mode 100644 index 9d5467c..0000000 --- a/src/Helpers/Wrappers.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "Helpers/Wrappers.hpp" - -namespace CTRPluginFramework -{ - bool GetInput(u8 &input, const std::string &msg, bool useHex) - { - Keyboard keyboard(msg); - - if (msg.empty()) - keyboard.DisplayTopScreen = false; - keyboard.IsHexadecimal(useHex); - - if (keyboard.Open(input, input) != -1) - return (true); - - return (false); - } - - bool GetInput(u16 &input, const std::string &msg, bool useHex) - { - Keyboard keyboard(msg); - - if (msg.empty()) - keyboard.DisplayTopScreen = false; - keyboard.IsHexadecimal(useHex); - - if (keyboard.Open(input, input) != -1) - return (true); - - return (false); - } - - bool GetInput(u32 &input, const std::string &msg, bool useHex) - { - Keyboard keyboard(msg); - - if (msg.empty()) - keyboard.DisplayTopScreen = false; - keyboard.IsHexadecimal(useHex); - - if (keyboard.Open(input, input) != -1) - return (true); - - return (false); - } - - bool GetInput(float &input, const std::string &msg) - { - Keyboard keyboard(msg); - - if (msg.empty()) - keyboard.DisplayTopScreen = false; - - if (keyboard.Open(input, input) != -1) - return (true); - - return (false); - } - - bool GetInput(u16 &input, const StringVector &choices, const std::string &msg) - { - Keyboard keyboard(msg); - - if (msg.empty()) - keyboard.DisplayTopScreen = false; - - keyboard.Populate(const_cast(choices)); - - int selected = keyboard.Open(); - - if (selected != -1) - { - input = selected; - return (true); - } - - return (false); - } - -} \ No newline at end of file diff --git a/src/Megamix/HookFuncs/Charting.cpp b/src/Megamix/HookFuncs/Charting.cpp new file mode 100644 index 0000000..a09767e --- /dev/null +++ b/src/Megamix/HookFuncs/Charting.cpp @@ -0,0 +1,90 @@ +#include <3ds.h> +#include + +#include "Megamix.hpp" +#include "Config.hpp" + +using CTRPluginFramework::OSD; + +using Megamix::TempoTable; + +namespace Megamix::Hooks { + void* getTickflowOffset(int index) { + if (config->tickflows.contains(index)) { + int result = Megamix::btks.LoadFile(config->tickflows[index]); + if (!result) { + return (void*)(Megamix::btks.start); + } else { + OSD::Notify(CTRPluginFramework::Utils::Format("Error: %s", Megamix::ErrorMessage(result).c_str())); + } + } + return *(void**)(Region::GameTable() + index * 0x34 + 4); // og code + } + + void* getGateTickflowOffset(int index) { + if (config->tickflows.contains(index + 0x100)) { + int result = Megamix::btks.LoadFile(config->tickflows[index + 0x100]); + if (!result) { + return (void*)(Megamix::btks.start); + } else { + OSD::Notify(CTRPluginFramework::Utils::Format("Error: %s", Megamix::ErrorMessage(result).c_str())); + } + } + return *(void**)(Region::GateTable() + index * 0x24 + 4); // og code + } + + void* getGatePracticeTickflowOffset(int index) { + if (config->tickflows.contains((index >> 2) + 0x110)) { + int result = Megamix::btks.LoadFile(config->tickflows[(index >> 2) + 0x110]); + if (!result) { + return (void*)(Megamix::btks.start); + } else { + OSD::Notify(CTRPluginFramework::Utils::Format("Error: %s", Megamix::ErrorMessage(result).c_str())); + } + } + return *(void**)(Region::GateTable() + index * 0x24 + 8); // og code + } + + TempoTable* getTempoStrm(Megamix::CSoundManager* this_, u32 id) { + if (Megamix::btks.tempos.contains(id)) { + return Megamix::btks.tempos[id]; + } else { // Original code + for (s32 low = 0, high = this_->numberTempos; low <= high;) { + s32 current_num = (low + high) / 2; + Megamix::SM_TempoTable* current = &this_->tableStrm[current_num]; + if (current->id > id) high = current_num - 1; + if (current->id < id) low = current_num + 1; + if (current->id == id) return current->tempo; + } + return 0; + } + } + + TempoTable* getTempoSeq(Megamix::CSoundManager* this_, u32 id) { + if (Megamix::btks.tempos.contains(id)) { + return Megamix::btks.tempos[id]; + } else { // Original code + for (s32 low = 0, high = this_->numberTempos; low <= high;) { + s32 current_num = (low + high) / 2; + Megamix::SM_TempoTable* current = &this_->tableSeq[current_num]; + if (current->id > id) high = current_num - 1; + if (current->id < id) low = current_num + 1; + if (current->id == id) return current->tempo; + } + return 0; + } + } + + TempoTable* getTempoAll(Megamix::CSoundManager* this_, u32 id) { + if (Megamix::btks.tempos.contains(id)) { + return Megamix::btks.tempos[id]; + } else { // Original code + for (int i = 0; i < this_->numberTempos; i++) { + Megamix::TempoTable* current = &this_->tempoTable[i]; + if (current->id1 == id || current->id2 == id) + return current; + } + return 0; + } + } +} \ No newline at end of file diff --git a/src/Megamix/HookFuncs/FS.cpp b/src/Megamix/HookFuncs/FS.cpp new file mode 100644 index 0000000..9a4d4c4 --- /dev/null +++ b/src/Megamix/HookFuncs/FS.cpp @@ -0,0 +1,153 @@ +#include <3ds.h> +#include + +#include "Megamix.hpp" + +using CTRPluginFramework::File; +using CTRPluginFramework::Utils; + +namespace Megamix::Hooks { + void doReadFile(CFileManager* self, FileInfo* fileInfo) { + void* cache; // i don't feel like making another struct for this undocumented thing, so pointer arithmetic go brr + + // cached filesystem hell + if (fileInfo->fileId >= 0 && (cache = Region::IsFileCachedFunc()(*(void**)Region::CacheFileManagerPos(), fileInfo->fileId, fileInfo), cache != 0)) { + fileInfo->fileSize = *(u32*)(cache + 0x84); + fileInfo->fileBuffer = new u8[fileInfo->fileSize]; + memcpy(fileInfo->fileBuffer, *(void**)(cache + 0x80), fileInfo->fileSize); + return; + } + + FileInputStream inputStream = {(void*)Region::FileInputStreamVtable(), {0, 0, 0}}; + wchar_t* buffer = new wchar_t[256]; + File file_ctrpf; + Result result_ctrpf; + + auto game_result_checker = [] (Result result) { + // taken straight from ghidra + return (((result & 0x3fc00) == 0x4400) && (99 < (result & 0x3ff))) && ((result & 0x3ff) < 0xb4); + }; + + const char* LAYERED_LOCATION = "/spicerack/fs/%ls%ls"; + + // sublocale - SD + file_ctrpf = File(); + result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, self->sublocale, fileInfo->filePath + 5), File::Mode::READ); + + // locale - SD + if (result_ctrpf != 0) { + file_ctrpf.Close(); + result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, self->locale, fileInfo->filePath + 5), File::Mode::READ); + } + + // global - SD + if (result_ctrpf != 0) { + file_ctrpf.Close(); + result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, L"", fileInfo->filePath + 5), File::Mode::READ); + } + + if (result_ctrpf == 0) { + // TODO: read file here + + s64 size = file_ctrpf.GetSize(); + if (size < 0) { + // could not read filesize + svcBreak(USERBREAK_PANIC); + } + fileInfo->fileSize = size; + + void* fileBuffer = Region::OperatorNewFunc()(fileInfo->fileSize, fileInfo->mode, fileInfo->alignment); + result_ctrpf = file_ctrpf.Read(fileBuffer, fileInfo->fileSize); + if (result_ctrpf < 0) { + // could not read file + svcBreak(USERBREAK_PANIC); + } + + file_ctrpf.Close(); + } else { + file_ctrpf.Close(); + + // sublocale - RomFS + swprintf(buffer, 256, L"rom:/%ls%ls", self->sublocale, fileInfo->filePath + 5); + Result result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); + + + // locale - RomFS + if (game_result_checker(result_game)) { + if ((u32)inputStream.base.ptr >> 1 != 0) { + if ((u32)inputStream.base.ptr & 1 == 1) { + // the reason i'm using svcBreak is because any kind of error handling in here is a mess and i don't think we're going to have any errors? + + // pointer is not 2-aligned + svcBreak(USERBREAK_PANIC); + } + Region::CloseFileFunc()(inputStream.base.ptr); + inputStream.base.ptr = nullptr; + } + + inputStream.base = {0, 0, 0}; + swprintf(buffer, 256, L"rom:/%ls%ls", self->locale, fileInfo->filePath + 5); + result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); + } + + // global - RomFS + if (game_result_checker(result_game)) { + if ((u32)inputStream.base.ptr >> 1 != 0) { + if ((u32)inputStream.base.ptr & 1 == 1) { + // pointer is not 2-aligned + svcBreak(USERBREAK_PANIC); + } + Region::CloseFileFunc()(inputStream.base.ptr); + inputStream.base.ptr = nullptr; + } + + inputStream.base = {0, 0, 0}; + result_game = Region::TryOpenFileFunc()(&inputStream.base, fileInfo->filePath, 1); + } + + // read file (or set status accordingly if file couldn't be opened) + if (game_result_checker(result_game)) { + fileInfo->status = 0xb; + } else { + s64 size; + result_game = Region::TryGetSizeFunc()(&inputStream.base, &size); + if (result_game < 0) { + // couldn't read filesize + svcBreak(USERBREAK_PANIC); + } + + fileInfo->fileSize = size; + fileInfo->fileBuffer = Region::OperatorNewFunc()(size, fileInfo->mode, fileInfo->alignment); + result_game = Region::TryReadFunc()(&inputStream.base, (u32*)&size, fileInfo->fileBuffer, fileInfo->fileSize); + if (result_game < 0) { + // couldn't read file + svcBreak(USERBREAK_PANIC); + } + } + + // close file if it was opened + if (((s32)inputStream.base.ptr & 0xfffffffe) != 0) { + if (((s32)inputStream.base.ptr & 1) == 1) { + // pointer is not 2-aligned + svcBreak(USERBREAK_PANIC); + } + + Region::CloseFileFunc()(inputStream.base.ptr); // original game has an & 0xfffffffe here which is... superflous considering the million ptr checks + inputStream.base.ptr = nullptr; + + } + + // original game has a second file closing here - not adding unless it seems to give any issues because like wtf + } + + // cache file + // i still refuse to make a struct for cache shit, even if this is documented + u8 is_cache_enabled = *(u8*)(Region::CacheFileManagerPos() + 0xc); + if ((fileInfo->fileId > -1) && is_cache_enabled != 0) { // hey champ shouldnt this also not happen when the file isn't loaded??? + Region::CacheFileFunc()((void*)Region::CacheFileManagerPos(), fileInfo->fileId, fileInfo->filePath, fileInfo->fileBuffer, + fileInfo->fileSize, fileInfo->mode, fileInfo->alignment); + } + + // and done! + } +} \ No newline at end of file diff --git a/src/Megamix/HookFuncs/HookFuncs.h b/src/Megamix/HookFuncs/HookFuncs.h new file mode 100644 index 0000000..9ea4147 --- /dev/null +++ b/src/Megamix/HookFuncs/HookFuncs.h @@ -0,0 +1,23 @@ +// for internal usage in Hooks.cpp - please don't call any of these functions directly + +#include <3ds.h> + +#include "Megamix.hpp" + +namespace Megamix::Hooks { + // Charting.cpp + void* getTickflowOffset(int index); + void* getGateTickflowOffset(int index); + void* getGatePracticeTickflowOffset(int index); + + Megamix::TempoTable* getTempoStrm(Megamix::CSoundManager* this_, u32 id); + Megamix::TempoTable* getTempoSeq(Megamix::CSoundManager* this_, u32 id); + Megamix::TempoTable* getTempoAll(Megamix::CSoundManager* this_, u32 id); + + // FS.cpp + void doReadFile(CFileManager* self, FileInfo* fileInfo); + + // Misc.cpp + u32 getRegionCTR(); + u32 getRegionMegamix(); +} \ No newline at end of file diff --git a/src/Megamix/HookFuncs/Misc.cpp b/src/Megamix/HookFuncs/Misc.cpp new file mode 100644 index 0000000..7892557 --- /dev/null +++ b/src/Megamix/HookFuncs/Misc.cpp @@ -0,0 +1,18 @@ +#include <3ds.h> +#include + +#include "Megamix.hpp" + +namespace Megamix::Hooks { + u32 getRegionCTR() { + //TODO: handle JP region / JP langpack + if (region == Region::KR) + return Region::KR_CTR; + return region; + } + + u32 getRegionMegamix() { + //TODO: handle JP region / JP langpack + return region; + } +} \ No newline at end of file diff --git a/src/Megamix/Hooks.cpp b/src/Megamix/Hooks.cpp index ca80dab..f4466bd 100644 --- a/src/Megamix/Hooks.cpp +++ b/src/Megamix/Hooks.cpp @@ -6,15 +6,11 @@ #include "Megamix.hpp" #include "Config.hpp" -using CTRPluginFramework::File; -using CTRPluginFramework::OSD; -using CTRPluginFramework::Utils; - -using Megamix::TempoTable; - -// TODO: split file further +#include "./HookFuncs/HookFuncs.h" namespace Megamix::Hooks { + // Hook functions have been moved to the HookFuncs folder + RT_HOOK tickflowHook; RT_HOOK gateHook; RT_HOOK gatePracHook; @@ -28,267 +24,6 @@ namespace Megamix::Hooks { RT_HOOK fsOpenFileHook; - void* getTickflowOffset(int index) { - if (config->tickflows.contains(index)) { - int result = Megamix::btks.LoadFile(config->tickflows[index]); - if (!result) { - return (void*)(Megamix::btks.start); - } else { - OSD::Notify(CTRPluginFramework::Utils::Format("Error: %s", Megamix::ErrorMessage(result).c_str())); - } - } - return *(void**)(Region::GameTable() + index * 0x34 + 4); // og code - } - - void* getGateTickflowOffset(int index) { - if (config->tickflows.contains(index + 0x100)) { - int result = Megamix::btks.LoadFile(config->tickflows[index + 0x100]); - if (!result) { - return (void*)(Megamix::btks.start); - } else { - OSD::Notify(CTRPluginFramework::Utils::Format("Error: %s", Megamix::ErrorMessage(result).c_str())); - } - } - return *(void**)(Region::GateTable() + index * 0x24 + 4); // og code - } - - void* getGatePracticeTickflowOffset(int index) { - if (config->tickflows.contains((index >> 2) + 0x110)) { - int result = Megamix::btks.LoadFile(config->tickflows[(index >> 2) + 0x110]); - if (!result) { - return (void*)(Megamix::btks.start); - } else { - OSD::Notify(CTRPluginFramework::Utils::Format("Error: %s", Megamix::ErrorMessage(result).c_str())); - } - } - return *(void**)(Region::GateTable() + index * 0x24 + 8); // og code - } - - TempoTable* getTempoStrm(Megamix::CSoundManager* this_, u32 id) { - if (Megamix::btks.tempos.contains(id)) { - return Megamix::btks.tempos[id]; - } else { // Original code - for (s32 low = 0, high = this_->numberTempos; low <= high;) { - s32 current_num = (low + high) / 2; - Megamix::SM_TempoTable* current = &this_->tableStrm[current_num]; - if (current->id > id) high = current_num - 1; - if (current->id < id) low = current_num + 1; - if (current->id == id) return current->tempo; - } - return 0; - } - } - - TempoTable* getTempoSeq(Megamix::CSoundManager* this_, u32 id) { - if (Megamix::btks.tempos.contains(id)) { - return Megamix::btks.tempos[id]; - } else { // Original code - for (s32 low = 0, high = this_->numberTempos; low <= high;) { - s32 current_num = (low + high) / 2; - Megamix::SM_TempoTable* current = &this_->tableSeq[current_num]; - if (current->id > id) high = current_num - 1; - if (current->id < id) low = current_num + 1; - if (current->id == id) return current->tempo; - } - return 0; - } - } - - TempoTable* getTempoAll(Megamix::CSoundManager* this_, u32 id) { - if (Megamix::btks.tempos.contains(id)) { - return Megamix::btks.tempos[id]; - } else { // Original code - for (int i = 0; i < this_->numberTempos; i++) { - Megamix::TempoTable* current = &this_->tempoTable[i]; - if (current->id1 == id || current->id2 == id) - return current; - } - return 0; - } - } - - u32 getRegionCTR() { - //TODO: handle JP region / JP langpack - if (region == Region::KR) - return Region::KR_CTR; - return region; - } - - u32 getRegionMegamix() { - //TODO: handle JP region / JP langpack - return region; - } - - template - T StubbedFunction() { - return {}; - } - - template<> - void StubbedFunction() { - } - - // redirects function at address to a stubbed function - template - void StubFunction(u32 address) { - rtGenerateJumpCode( - (u32) StubbedFunction, - (u32 *) address - ); - } - - // template instantiations - // if either StubbedFunction or StubFunction is used with a type, a template - // instantiation must be added with that type - template void StubFunction(u32); - - void doReadFile(CFileManager* self, FileInfo* fileInfo) { - void* cache; // i don't feel like making another struct for this undocumented thing, so pointer arithmetic go brr - - // cached filesystem hell - if (fileInfo->fileId >= 0 && (cache = Region::IsFileCachedFunc()(*(void**)Region::CacheFileManagerPos(), fileInfo->fileId, fileInfo), cache != 0)) { - fileInfo->fileSize = *(u32*)(cache + 0x84); - fileInfo->fileBuffer = new u8[fileInfo->fileSize]; - memcpy(fileInfo->fileBuffer, *(void**)(cache + 0x80), fileInfo->fileSize); - return; - } - - FileInputStream inputStream = {(void*)Region::FileInputStreamVtable(), {0, 0, 0}}; - wchar_t* buffer = new wchar_t[256]; - File file_ctrpf; - Result result_ctrpf; - - auto game_result_checker = [] (Result result) { - // taken straight from ghidra - return (((result & 0x3fc00) == 0x4400) && (99 < (result & 0x3ff))) && ((result & 0x3ff) < 0xb4); - }; - - const char* LAYERED_LOCATION = "/spicerack/fs/%ls%ls"; - - // sublocale - SD - file_ctrpf = File(); - result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, self->sublocale, fileInfo->filePath + 5), File::Mode::READ); - - // locale - SD - if (result_ctrpf != 0) { - file_ctrpf.Close(); - result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, self->locale, fileInfo->filePath + 5), File::Mode::READ); - } - - // global - SD - if (result_ctrpf != 0) { - file_ctrpf.Close(); - result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, L"", fileInfo->filePath + 5), File::Mode::READ); - } - - if (result_ctrpf == 0) { - // TODO: read file here - - s64 size = file_ctrpf.GetSize(); - if (size < 0) { - // could not read filesize - svcBreak(USERBREAK_PANIC); - } - fileInfo->fileSize = size; - - void* fileBuffer = Region::OperatorNewFunc()(fileInfo->fileSize, fileInfo->mode, fileInfo->alignment); - result_ctrpf = file_ctrpf.Read(fileBuffer, fileInfo->fileSize); - if (result_ctrpf < 0) { - // could not read file - svcBreak(USERBREAK_PANIC); - } - - file_ctrpf.Close(); - } else { - file_ctrpf.Close(); - - // sublocale - RomFS - swprintf(buffer, 256, L"rom:/%ls%ls", self->sublocale, fileInfo->filePath + 5); - Result result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); - - - // locale - RomFS - if (game_result_checker(result_game)) { - if ((u32)inputStream.base.ptr >> 1 != 0) { - if ((u32)inputStream.base.ptr & 1 == 1) { - // the reason i'm using svcBreak is because any kind of error handling in here is a mess and i don't think we're going to have any errors? - - // pointer is not 2-aligned - svcBreak(USERBREAK_PANIC); - } - Region::CloseFileFunc()(inputStream.base.ptr); - inputStream.base.ptr = nullptr; - } - - inputStream.base = {0, 0, 0}; - swprintf(buffer, 256, L"rom:/%ls%ls", self->locale, fileInfo->filePath + 5); - result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); - } - - // global - RomFS - if (game_result_checker(result_game)) { - if ((u32)inputStream.base.ptr >> 1 != 0) { - if ((u32)inputStream.base.ptr & 1 == 1) { - // pointer is not 2-aligned - svcBreak(USERBREAK_PANIC); - } - Region::CloseFileFunc()(inputStream.base.ptr); - inputStream.base.ptr = nullptr; - } - - inputStream.base = {0, 0, 0}; - result_game = Region::TryOpenFileFunc()(&inputStream.base, fileInfo->filePath, 1); - } - - // read file (or set status accordingly if file couldn't be opened) - if (game_result_checker(result_game)) { - fileInfo->status = 0xb; - } else { - s64 size; - result_game = Region::TryGetSizeFunc()(&inputStream.base, &size); - if (result_game < 0) { - // couldn't read filesize - svcBreak(USERBREAK_PANIC); - } - - fileInfo->fileSize = size; - fileInfo->fileBuffer = Region::OperatorNewFunc()(size, fileInfo->mode, fileInfo->alignment); - result_game = Region::TryReadFunc()(&inputStream.base, (u32*)&size, fileInfo->fileBuffer, fileInfo->fileSize); - if (result_game < 0) { - // couldn't read file - svcBreak(USERBREAK_PANIC); - } - } - - // close file if it was opened - if (((s32)inputStream.base.ptr & 0xfffffffe) != 0) { - if (((s32)inputStream.base.ptr & 1) == 1) { - // pointer is not 2-aligned - svcBreak(USERBREAK_PANIC); - } - - Region::CloseFileFunc()(inputStream.base.ptr); // original game has an & 0xfffffffe here which is... superflous considering the million ptr checks - inputStream.base.ptr = nullptr; - - } - - // original game has a second file closing here - not adding unless it seems to give any issues because like wtf - } - - // cache file - // i still refuse to make a struct for cache shit, even if this is documented - u8 is_cache_enabled = *(u8*)(Region::CacheFileManagerPos() + 0xc); - if ((fileInfo->fileId > -1) && is_cache_enabled != 0) { // hey champ shouldnt this also not happen when the file isn't loaded??? - Region::CacheFileFunc()((void*)Region::CacheFileManagerPos(), fileInfo->fileId, fileInfo->filePath, fileInfo->fileBuffer, - fileInfo->fileSize, fileInfo->mode, fileInfo->alignment); - } - - // and done! - } - - - // define hooks - void TickflowHooks() { rtInitHook(&tickflowHook, Region::TickflowHookFunc(), (u32)getTickflowOffset); rtEnableHook(&tickflowHook); @@ -331,4 +66,27 @@ namespace Megamix::Hooks { rtDisableHook(®ionOtherHook); rtDisableHook(&fsOpenFileHook); } + + template + T StubbedFunction() { + return {}; + } + + // redirects function at address to a stubbed function + template + void StubFunction(u32 address) { + rtGenerateJumpCode( + (u32) StubbedFunction, + (u32 *) address + ); + } + + // template instantiations + // if either StubbedFunction or StubFunction is used with a type, a template + // instantiation must be added with that type + template<> + void StubbedFunction() { + } + + template void StubFunction(u32); } \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 06a54fa..0c8f9ad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ #include <3ds.h> #include -#include "csvc.h" +#include "external/csvc.h" #include "external/plgldr.h" #include "Megamix.hpp" From e6374808cb71cb29b1ebc36b9421f80d5d7c8173 Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Wed, 21 Aug 2024 20:11:55 +0200 Subject: [PATCH 06/13] fs: actual error handling --- src/Megamix/HookFuncs/FS.cpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/Megamix/HookFuncs/FS.cpp b/src/Megamix/HookFuncs/FS.cpp index 9a4d4c4..c35300a 100644 --- a/src/Megamix/HookFuncs/FS.cpp +++ b/src/Megamix/HookFuncs/FS.cpp @@ -51,16 +51,14 @@ namespace Megamix::Hooks { s64 size = file_ctrpf.GetSize(); if (size < 0) { - // could not read filesize - svcBreak(USERBREAK_PANIC); + ERRF_ThrowResultWithMessage(size, "(m) Could not read file"); } fileInfo->fileSize = size; void* fileBuffer = Region::OperatorNewFunc()(fileInfo->fileSize, fileInfo->mode, fileInfo->alignment); result_ctrpf = file_ctrpf.Read(fileBuffer, fileInfo->fileSize); if (result_ctrpf < 0) { - // could not read file - svcBreak(USERBREAK_PANIC); + ERRF_ThrowResultWithMessage(result_ctrpf, "(m) Could not read file"); } file_ctrpf.Close(); @@ -72,14 +70,11 @@ namespace Megamix::Hooks { Result result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); - // locale - RomFS + // locale - RomFS if (game_result_checker(result_game)) { if ((u32)inputStream.base.ptr >> 1 != 0) { if ((u32)inputStream.base.ptr & 1 == 1) { - // the reason i'm using svcBreak is because any kind of error handling in here is a mess and i don't think we're going to have any errors? - - // pointer is not 2-aligned - svcBreak(USERBREAK_PANIC); + ERRF_ThrowResultWithMessage(-1, "(sl) File pointer is not 2-aligned"); } Region::CloseFileFunc()(inputStream.base.ptr); inputStream.base.ptr = nullptr; @@ -94,8 +89,7 @@ namespace Megamix::Hooks { if (game_result_checker(result_game)) { if ((u32)inputStream.base.ptr >> 1 != 0) { if ((u32)inputStream.base.ptr & 1 == 1) { - // pointer is not 2-aligned - svcBreak(USERBREAK_PANIC); + ERRF_ThrowResultWithMessage(-1, "(l) File pointer is not 2-aligned"); } Region::CloseFileFunc()(inputStream.base.ptr); inputStream.base.ptr = nullptr; @@ -112,24 +106,21 @@ namespace Megamix::Hooks { s64 size; result_game = Region::TryGetSizeFunc()(&inputStream.base, &size); if (result_game < 0) { - // couldn't read filesize - svcBreak(USERBREAK_PANIC); + ERRF_ThrowResultWithMessage(result_game, "Could not read filesize"); } fileInfo->fileSize = size; fileInfo->fileBuffer = Region::OperatorNewFunc()(size, fileInfo->mode, fileInfo->alignment); result_game = Region::TryReadFunc()(&inputStream.base, (u32*)&size, fileInfo->fileBuffer, fileInfo->fileSize); if (result_game < 0) { - // couldn't read file - svcBreak(USERBREAK_PANIC); + ERRF_ThrowResultWithMessage(result_game, "Could not read file"); } } // close file if it was opened if (((s32)inputStream.base.ptr & 0xfffffffe) != 0) { if (((s32)inputStream.base.ptr & 1) == 1) { - // pointer is not 2-aligned - svcBreak(USERBREAK_PANIC); + ERRF_ThrowResultWithMessage(-1, "(g) File pointer is not 2-aligned"); } Region::CloseFileFunc()(inputStream.base.ptr); // original game has an & 0xfffffffe here which is... superflous considering the million ptr checks From 13aa4440bddc84a3726bb6886617e3209906818e Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Thu, 22 Aug 2024 00:49:18 +0200 Subject: [PATCH 07/13] IT BOOTS FOLKS --- include/Megamix/Region.hpp | 8 ++++++-- include/Megamix/Types.hpp | 6 +++--- src/Megamix/HookFuncs/FS.cpp | 27 +++++++++++++++++++-------- src/Megamix/Region.cpp | 10 ++++++++++ src/main.cpp | 2 +- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/include/Megamix/Region.hpp b/include/Megamix/Region.hpp index 1845b90..4a374a9 100644 --- a/include/Megamix/Region.hpp +++ b/include/Megamix/Region.hpp @@ -53,13 +53,15 @@ namespace Region { u32 RegionOtherHookFunc(); typedef void* (*IsFileCachedSignature) (void* cachedFileManager, s32 fileId, Megamix::FileInfo* fileInfo); - typedef bool (*CacheFileSignature) (void* cachedFileManager, s32 fileId, wchar_t* filePath, void* fileBuffer, size_t fileSize, u8 mode, s32 alignment); + typedef bool (*CacheFileSignature) (void* cachedFileManager, s32 fileId, char16_t* filePath, void* fileBuffer, size_t fileSize, u8 mode, s32 alignment); - typedef Result (*TryOpenFileSignature) (Megamix::FileInputStream::FileBase* fileBase, wchar_t* filePath, u32 mode); + typedef Result (*TryOpenFileSignature) (Megamix::FileInputStream::FileBase* fileBase, char16_t* filePath, u32 mode); typedef Result (*CloseFileSignature) (void* ptr); typedef Result (*TryGetSizeSignature) (Megamix::FileInputStream::FileBase* fileBase, s64* size); typedef Result (*TryReadSignature) (Megamix::FileInputStream::FileBase* fileBase, u32* bytesRead, void* fileBuffer, u32 size); + typedef int (*SWPrintfSignature) (char16_t* buffer, size_t size, const char16_t* format, ...); + typedef void* (*OperatorNewSignature) (size_t size, s32 mode, s32 alignment); u32 DoOpenFileHookFunc(); @@ -73,6 +75,8 @@ namespace Region { TryGetSizeSignature TryGetSizeFunc(); TryReadSignature TryReadFunc(); + SWPrintfSignature SWPrintfFunc(); + // use this to allocate stuff in the game's RAM OperatorNewSignature OperatorNewFunc(); diff --git a/include/Megamix/Types.hpp b/include/Megamix/Types.hpp index 1422675..ec3f7d4 100644 --- a/include/Megamix/Types.hpp +++ b/include/Megamix/Types.hpp @@ -245,7 +245,7 @@ namespace Megamix { struct FileInfo { - wchar_t filePath[0x80]; + char16_t filePath[0x80]; void* fileBuffer; u8* compressedFileBuffer; void* unk108; @@ -280,8 +280,8 @@ namespace Megamix { u32 unk24; bool unk28; u32 unk2C; - wchar_t locale[9]; - wchar_t sublocale[9]; + char16_t locale[9]; + char16_t sublocale[9]; struct { u32 unk[2]; } thread; //TODO bool threadCreated; }; diff --git a/src/Megamix/HookFuncs/FS.cpp b/src/Megamix/HookFuncs/FS.cpp index c35300a..3cbb1f5 100644 --- a/src/Megamix/HookFuncs/FS.cpp +++ b/src/Megamix/HookFuncs/FS.cpp @@ -8,6 +8,8 @@ using CTRPluginFramework::Utils; namespace Megamix::Hooks { void doReadFile(CFileManager* self, FileInfo* fileInfo) { + // TODO: triple check everything here works properly - ESPECIALLY the filenames, both for internal game functions and ctrpf functions + void* cache; // i don't feel like making another struct for this undocumented thing, so pointer arithmetic go brr // cached filesystem hell @@ -19,7 +21,7 @@ namespace Megamix::Hooks { } FileInputStream inputStream = {(void*)Region::FileInputStreamVtable(), {0, 0, 0}}; - wchar_t* buffer = new wchar_t[256]; + char16_t* buffer = new char16_t[256]; File file_ctrpf; Result result_ctrpf; @@ -30,20 +32,29 @@ namespace Megamix::Hooks { const char* LAYERED_LOCATION = "/spicerack/fs/%ls%ls"; + wchar_t* strings_utf32[3] = { + new wchar_t[9], + new wchar_t[9], + new wchar_t[0x80] + }; + utf16_to_utf32((u32*)strings_utf32[0], (u16*)&self->sublocale, 9); + utf16_to_utf32((u32*)strings_utf32[1], (u16*)&self->locale, 9); + utf16_to_utf32((u32*)strings_utf32[2], (u16*)&fileInfo->filePath, 0x80); + // sublocale - SD file_ctrpf = File(); - result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, self->sublocale, fileInfo->filePath + 5), File::Mode::READ); + result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, strings_utf32[0], strings_utf32[2] + 5), File::Mode::READ); // locale - SD if (result_ctrpf != 0) { file_ctrpf.Close(); - result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, self->locale, fileInfo->filePath + 5), File::Mode::READ); + result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, strings_utf32[1], strings_utf32[2] + 5), File::Mode::READ); } // global - SD if (result_ctrpf != 0) { file_ctrpf.Close(); - result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, L"", fileInfo->filePath + 5), File::Mode::READ); + result_ctrpf = File::Open(file_ctrpf, Utils::Format(LAYERED_LOCATION, L"", strings_utf32[2] + 5), File::Mode::READ); } if (result_ctrpf == 0) { @@ -66,7 +77,7 @@ namespace Megamix::Hooks { file_ctrpf.Close(); // sublocale - RomFS - swprintf(buffer, 256, L"rom:/%ls%ls", self->sublocale, fileInfo->filePath + 5); + Region::SWPrintfFunc()(buffer, 256, u"rom:/%ls%ls", self->sublocale, fileInfo->filePath + 5); Result result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); @@ -79,9 +90,9 @@ namespace Megamix::Hooks { Region::CloseFileFunc()(inputStream.base.ptr); inputStream.base.ptr = nullptr; } - + inputStream.base = {0, 0, 0}; - swprintf(buffer, 256, L"rom:/%ls%ls", self->locale, fileInfo->filePath + 5); + Region::SWPrintfFunc()(buffer, 256, u"rom:/%ls%ls", self->locale, fileInfo->filePath + 5); result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); } @@ -94,7 +105,7 @@ namespace Megamix::Hooks { Region::CloseFileFunc()(inputStream.base.ptr); inputStream.base.ptr = nullptr; } - + inputStream.base = {0, 0, 0}; result_game = Region::TryOpenFileFunc()(&inputStream.base, fileInfo->filePath, 1); } diff --git a/src/Megamix/Region.cpp b/src/Megamix/Region.cpp index 1e3e36b..8398323 100644 --- a/src/Megamix/Region.cpp +++ b/src/Megamix/Region.cpp @@ -418,6 +418,16 @@ namespace Region { } } + + SWPrintfSignature SWPrintfFunc() { + switch (region) { + case US: + return (SWPrintfSignature)(0x28a2d0 + 1); + default: + return nullptr; + } + } + OperatorNewSignature OperatorNewFunc() { switch (region) { case US: diff --git a/src/main.cpp b/src/main.cpp index 0c8f9ad..5cab4a0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,7 +77,7 @@ void ctrpf::PatchProcess(ctrpf::FwkSettings &settings) { ToggleTouchscreenForceOn(); // Crash handler - Process::exceptionCallback = Megamix::CrashHandler; + //Process::exceptionCallback = Megamix::CrashHandler; // le params :D params = *(SaltwaterParams*)ctrpf::FwkSettings::Header->config; From c904856c45e87feb71f84911a0d8ba02b7bf23d3 Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Mon, 2 Sep 2024 17:33:00 +0200 Subject: [PATCH 08/13] Fix cache system - game shouldn't crash on save load now --- include/Megamix/Region.hpp | 10 +++++----- include/Megamix/Types.hpp | 26 +++++++++++++++++++++++++- src/Megamix/HookFuncs/FS.cpp | 27 +++++++++++++++------------ src/main.cpp | 6 +++--- 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/include/Megamix/Region.hpp b/include/Megamix/Region.hpp index 4a374a9..a09fcbc 100644 --- a/include/Megamix/Region.hpp +++ b/include/Megamix/Region.hpp @@ -52,13 +52,13 @@ namespace Region { u32 RegionFSHookFunc(); u32 RegionOtherHookFunc(); - typedef void* (*IsFileCachedSignature) (void* cachedFileManager, s32 fileId, Megamix::FileInfo* fileInfo); - typedef bool (*CacheFileSignature) (void* cachedFileManager, s32 fileId, char16_t* filePath, void* fileBuffer, size_t fileSize, u8 mode, s32 alignment); + typedef Megamix::CachedFileInfo* (*IsFileCachedSignature) (Megamix::CCachedFileManager* self, s32 fileId, Megamix::FileInfo* fileInfo); + typedef bool (*CacheFileSignature) (Megamix::CCachedFileManager* self, s32 fileId, char16_t* filePath, void* fileBuffer, size_t fileSize, u8 mode, s32 alignment); - typedef Result (*TryOpenFileSignature) (Megamix::FileInputStream::FileBase* fileBase, char16_t* filePath, u32 mode); + typedef Result (*TryOpenFileSignature) (Megamix::FileInputStream::FileBase* self, char16_t* filePath, u32 mode); typedef Result (*CloseFileSignature) (void* ptr); - typedef Result (*TryGetSizeSignature) (Megamix::FileInputStream::FileBase* fileBase, s64* size); - typedef Result (*TryReadSignature) (Megamix::FileInputStream::FileBase* fileBase, u32* bytesRead, void* fileBuffer, u32 size); + typedef Result (*TryGetSizeSignature) (Megamix::FileInputStream::FileBase* self, s64* size); + typedef Result (*TryReadSignature) (Megamix::FileInputStream::FileBase* self, u32* bytesRead, void* fileBuffer, u32 size); typedef int (*SWPrintfSignature) (char16_t* buffer, size_t size, const char16_t* format, ...); diff --git a/include/Megamix/Types.hpp b/include/Megamix/Types.hpp index ec3f7d4..d018777 100644 --- a/include/Megamix/Types.hpp +++ b/include/Megamix/Types.hpp @@ -282,9 +282,33 @@ namespace Megamix { u32 unk2C; char16_t locale[9]; char16_t sublocale[9]; - struct { u32 unk[2]; } thread; //TODO + struct { u32 unk[2]; } thread; //TODO: s64? bool threadCreated; }; + + struct CachedFileInfo { + char16_t filePath[64]; + void* memory; + u32 size; + u8 mode; + s32 alignment; + }; + + struct CCachedFile { + void* vtable; + void* heapStart; + u8 expHeap[0x58]; // TODO + u8 expHeapMutex[0xc]; //TODO + u32 unk; + CachedFileInfo* info; + }; + + struct CCachedFileManager { + void* vtable; + CCachedFile* files; + s32 fileCount; + bool enabled; + }; } #endif \ No newline at end of file diff --git a/src/Megamix/HookFuncs/FS.cpp b/src/Megamix/HookFuncs/FS.cpp index 3cbb1f5..ccb3de6 100644 --- a/src/Megamix/HookFuncs/FS.cpp +++ b/src/Megamix/HookFuncs/FS.cpp @@ -10,14 +10,15 @@ namespace Megamix::Hooks { void doReadFile(CFileManager* self, FileInfo* fileInfo) { // TODO: triple check everything here works properly - ESPECIALLY the filenames, both for internal game functions and ctrpf functions - void* cache; // i don't feel like making another struct for this undocumented thing, so pointer arithmetic go brr - // cached filesystem hell - if (fileInfo->fileId >= 0 && (cache = Region::IsFileCachedFunc()(*(void**)Region::CacheFileManagerPos(), fileInfo->fileId, fileInfo), cache != 0)) { - fileInfo->fileSize = *(u32*)(cache + 0x84); - fileInfo->fileBuffer = new u8[fileInfo->fileSize]; - memcpy(fileInfo->fileBuffer, *(void**)(cache + 0x80), fileInfo->fileSize); - return; + if (fileInfo->fileId >= 0) { + CachedFileInfo* cache = Region::IsFileCachedFunc()(*(CCachedFileManager**)Region::CacheFileManagerPos(), fileInfo->fileId, fileInfo); + if (cache != nullptr) { + fileInfo->fileSize = cache->size; + fileInfo->fileBuffer = Region::OperatorNewFunc()(fileInfo->fileSize, cache->mode, cache->alignment); + memcpy(fileInfo->fileBuffer, fileInfo->fileBuffer, fileInfo->fileSize); + return; + } } FileInputStream inputStream = {(void*)Region::FileInputStreamVtable(), {0, 0, 0}}; @@ -59,6 +60,7 @@ namespace Megamix::Hooks { if (result_ctrpf == 0) { // TODO: read file here + ERRF_ThrowResultWithMessage(0xdeadc0de, "WIP"); s64 size = file_ctrpf.GetSize(); if (size < 0) { @@ -143,11 +145,12 @@ namespace Megamix::Hooks { } // cache file - // i still refuse to make a struct for cache shit, even if this is documented - u8 is_cache_enabled = *(u8*)(Region::CacheFileManagerPos() + 0xc); - if ((fileInfo->fileId > -1) && is_cache_enabled != 0) { // hey champ shouldnt this also not happen when the file isn't loaded??? - Region::CacheFileFunc()((void*)Region::CacheFileManagerPos(), fileInfo->fileId, fileInfo->filePath, fileInfo->fileBuffer, - fileInfo->fileSize, fileInfo->mode, fileInfo->alignment); + if (fileInfo->fileId > -1) { + auto cache_manager = *(CCachedFileManager**)Region::CacheFileManagerPos(); + if (cache_manager->enabled) { + Region::CacheFileFunc()(cache_manager, fileInfo->fileId, fileInfo->filePath, fileInfo->fileBuffer, + fileInfo->fileSize, fileInfo->mode, fileInfo->alignment); + } } // and done! diff --git a/src/main.cpp b/src/main.cpp index 5cab4a0..811f7c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -76,9 +76,6 @@ static void ToggleTouchscreenForceOn(void) { void ctrpf::PatchProcess(ctrpf::FwkSettings &settings) { ToggleTouchscreenForceOn(); - // Crash handler - //Process::exceptionCallback = Megamix::CrashHandler; - // le params :D params = *(SaltwaterParams*)ctrpf::FwkSettings::Header->config; @@ -158,6 +155,9 @@ void InitMenu(ctrpf::PluginMenu &menu) { #endif int ctrpf::main(void) { + // Crash handler + //Process::exceptionCallback = Megamix::CrashHandler; + if (params.barista != 0xD06) { ctrpf::MessageBox("Barista not used!", "You must run Saltwater from the Barista launcher!")(); Process::ReturnToHomeMenu(); From 593bb733730d6b7e9a33266d24cf5d70d34ba0e5 Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Mon, 2 Sep 2024 18:03:16 +0200 Subject: [PATCH 09/13] some manual changes to make stuff work with the rework --- include/Megamix.hpp | 11 ++-- include/Megamix/Commands.hpp | 25 ---------- include/Megamix/Types.hpp | 50 ++----------------- src/Megamix/{ => HookFuncs}/Commands.cpp | 29 ++++++++--- .../HookFuncs/{HookFuncs.h => HookFuncs.hpp} | 10 +++- src/Megamix/Hooks.cpp | 2 +- 6 files changed, 41 insertions(+), 86 deletions(-) delete mode 100644 include/Megamix/Commands.hpp rename src/Megamix/{ => HookFuncs}/Commands.cpp (82%) rename src/Megamix/HookFuncs/{HookFuncs.h => HookFuncs.hpp} (85%) diff --git a/include/Megamix.hpp b/include/Megamix.hpp index 482bfd8..bbc40ed 100644 --- a/include/Megamix.hpp +++ b/include/Megamix.hpp @@ -7,13 +7,12 @@ #define MEGAMIX_MODS_PATH "/spicerack/mods/" #define MEGAMIX_CONFIG_PATH MEGAMIX_BIN_PATH "saltwater.cfg" -#endif - #include "Saltwater.hpp" -#include "Megamix/Region.hpp" -#include "Megamix/Hooks.hpp" -#include "Megamix/Patches.hpp" #include "Megamix/BTKS.hpp" #include "Megamix/Error.hpp" -#include "Megamix/Commands.hpp" +#include "Megamix/Hooks.hpp" +#include "Megamix/Patches.hpp" +#include "Megamix/Region.hpp" #include "Megamix/Types.hpp" + +#endif \ No newline at end of file diff --git a/include/Megamix/Commands.hpp b/include/Megamix/Commands.hpp deleted file mode 100644 index 9e0e212..0000000 --- a/include/Megamix/Commands.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef MEGAMIX_COMMANDS_HPP -#define MEGAMIX_COMMANDS_HPP - -#include "Megamix/Types.hpp" - -namespace Megamix{ - enum CustomCommands: u16{ - InputCheck = 0x200, - VersionNumber = 0x201, - LanguageCheck = 0x202, - - DisplayCondvar = 0x300 - }; - - void tickflowCommandsHookWrapper(); - - extern "C" int tickflowCommandsHook(CTickflow* self, u32 cmd_num, u32 arg0, u32* args); - - void input_cmd(CTickflow* self, u32 arg0, u32* args); - void versionCheck(CTickflow* self, u32 arg0, u32* args); - void languageCheck(CTickflow* self, u32 arg0, u32* args); - void displayCondvar(CTickflow* self, u32 arg0, u32* args); -} - -#endif diff --git a/include/Megamix/Types.hpp b/include/Megamix/Types.hpp index 62f5a3e..6a9dc8a 100644 --- a/include/Megamix/Types.hpp +++ b/include/Megamix/Types.hpp @@ -472,53 +472,9 @@ namespace Megamix { struct CInputTouchPanelHandler* touchPanelHandler; }; - - //----------------- - //File Manager - //----------------- - - struct CFileManager { - int* _vtable; - s32 field1_0x4; - s32 field2_0x8; - void* romWorkingMemory; - u32 romWorkingMemorySize; - u8* gzipWorkMemory; - struct FileInfo* fileInfo; - u32* fileIds; - u32 fileIdCount; - u32 field9_0x24; - bool field10_0x28; - u8 field11_0x29; - u8 field12_0x2a; - u8 field13_0x2b; - u32 field14_0x2c; - u16 locale[9]; - u16 sublocale[9]; - }; - - struct FileInfo { - u16 filePath[128]; - void* fileBuffer; - u8* compFileBuffer; - void* field3_0x108; - size_t fileSize; - size_t compFileSize; - size_t field6_0x114; - u8 mode; - u8 field8_0x119; - u8 field9_0x11a; - u8 field10_0x11b; - u32 alignment; - u8 status; - u8 field13_0x121; - u8 field14_0x122; - u8 field15_0x123; - s32 id; - }; - -} // namespace Megamix - + // ---------- + // Filesystem + // ---------- struct FileInfo { char16_t filePath[0x80]; diff --git a/src/Megamix/Commands.cpp b/src/Megamix/HookFuncs/Commands.cpp similarity index 82% rename from src/Megamix/Commands.cpp rename to src/Megamix/HookFuncs/Commands.cpp index 3825416..fc94a66 100644 --- a/src/Megamix/Commands.cpp +++ b/src/Megamix/HookFuncs/Commands.cpp @@ -6,7 +6,24 @@ using CTRPluginFramework::OSD; using CTRPluginFramework::Utils; -namespace Megamix{ +namespace Megamix::Hooks { + extern "C" int tickflowCommandsHook(CTickflow* self, u32 cmd_num, u32 arg0, u32* args); + + // define commands up here + enum CustomCommands: u16 { + InputCheck = 0x200, + VersionNumber = 0x201, + LanguageCheck = 0x202, + + DisplayCondvar = 0x300 + }; + + void input_cmd(CTickflow* self, u32 arg0, u32* args); + void versionCheck(CTickflow* self, u32 arg0, u32* args); + void languageCheck(CTickflow* self, u32 arg0, u32* args); + void displayCondvar(CTickflow* self, u32 arg0, u32* args); + + // ------- void tickflowCommandsHookWrapper() { asm( @@ -48,7 +65,7 @@ namespace Megamix{ return; } else if (arg0 == 2) { CSaveData** gSaveData = (CSaveData**)Region::GlobalSaveDataPointer(); - // Here, arg0 gets replaced by the playstyle - 0 for buttons, 1 for tap - Results in playstyle-dependant reading + // Here, arg0 gets replaced by the playstyle - 0 for buttons, 1 for tap. Results in playstyle-dependant reading arg0 = (u32)(*gSaveData)->fileData[(*gSaveData)->currentFile].playStyle; } @@ -66,10 +83,10 @@ namespace Megamix{ } void versionCheck(CTickflow* self, u32 arg0, u32* args) { - if (arg0 == 0){ //RHMPatch version + if (arg0 == 0){ // RHMPatch version self->condvar = SUPPORTED_RHMPATCH; } else if (arg0 == 1){ //Saltwater version - self->condvar = VERSION_MAJOR*0x10+VERSION_MINOR; + self->condvar = VERSION_MAJOR * 0x10 + VERSION_MINOR; } } @@ -81,7 +98,7 @@ namespace Megamix{ self->condvar = 0; } else { wchar_t sublocale[5]; - utf16_to_utf32((u32*)sublocale, (*gFileManager)->sublocale, 4); + utf16_to_utf32((u32*)sublocale, (u16*)(*gFileManager)->sublocale, 4); sublocale[4] = '\0'; std::wstring localews(sublocale); if(localews.find(L"JP") != (unsigned int)-1){ @@ -108,7 +125,7 @@ namespace Megamix{ // Keeping that just in case // Screen bottomScreen = OSD::GetBottomScreen(); // bottomScreen.Draw("Condvar:"+Utils::Format("0x%08x",self->condvar), 0, 0, Color::White, Color::Black); - if(arg0 == 0) { + if (arg0 == 0) { OSD::Notify("Condvar:"+Utils::Format("0x%08x",self->condvar)); } else if (arg0 == 1){ OSD::Notify("Condvar:"+Utils::Format("%08d",self->condvar)); diff --git a/src/Megamix/HookFuncs/HookFuncs.h b/src/Megamix/HookFuncs/HookFuncs.hpp similarity index 85% rename from src/Megamix/HookFuncs/HookFuncs.h rename to src/Megamix/HookFuncs/HookFuncs.hpp index 9ea4147..1abf4b9 100644 --- a/src/Megamix/HookFuncs/HookFuncs.h +++ b/src/Megamix/HookFuncs/HookFuncs.hpp @@ -1,3 +1,6 @@ +#ifndef HOOKFUNCS_HPP +#define HOOKFUNCS_HPP + // for internal usage in Hooks.cpp - please don't call any of these functions directly #include <3ds.h> @@ -14,10 +17,15 @@ namespace Megamix::Hooks { Megamix::TempoTable* getTempoSeq(Megamix::CSoundManager* this_, u32 id); Megamix::TempoTable* getTempoAll(Megamix::CSoundManager* this_, u32 id); + // Commands.cpp + void tickflowCommandsHookWrapper(); + // FS.cpp void doReadFile(CFileManager* self, FileInfo* fileInfo); // Misc.cpp u32 getRegionCTR(); u32 getRegionMegamix(); -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/Megamix/Hooks.cpp b/src/Megamix/Hooks.cpp index ff9bc13..3984b24 100644 --- a/src/Megamix/Hooks.cpp +++ b/src/Megamix/Hooks.cpp @@ -6,7 +6,7 @@ #include "Megamix.hpp" #include "Config.hpp" -#include "./HookFuncs/HookFuncs.h" +#include "./HookFuncs/HookFuncs.hpp" namespace Megamix::Hooks { // Hook functions have been moved to the HookFuncs folder From b3a1ecdbbd4f913947cd92bb06e3825477d23e3e Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Mon, 2 Sep 2024 19:01:15 +0200 Subject: [PATCH 10/13] fix crashes on loading cached files (cache will be my downfall) --- include/Megamix/Types.hpp | 2 +- src/Megamix/HookFuncs/FS.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/Megamix/Types.hpp b/include/Megamix/Types.hpp index 6a9dc8a..32834db 100644 --- a/include/Megamix/Types.hpp +++ b/include/Megamix/Types.hpp @@ -520,7 +520,7 @@ namespace Megamix { struct CachedFileInfo { char16_t filePath[64]; - void* memory; + void* buffer; u32 size; u8 mode; s32 alignment; diff --git a/src/Megamix/HookFuncs/FS.cpp b/src/Megamix/HookFuncs/FS.cpp index ccb3de6..070c53a 100644 --- a/src/Megamix/HookFuncs/FS.cpp +++ b/src/Megamix/HookFuncs/FS.cpp @@ -16,7 +16,7 @@ namespace Megamix::Hooks { if (cache != nullptr) { fileInfo->fileSize = cache->size; fileInfo->fileBuffer = Region::OperatorNewFunc()(fileInfo->fileSize, cache->mode, cache->alignment); - memcpy(fileInfo->fileBuffer, fileInfo->fileBuffer, fileInfo->fileSize); + memcpy(fileInfo->fileBuffer, cache->buffer, fileInfo->fileSize); return; } } From b4292c777aec03d56f8816abfc7b7d28640d392d Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Mon, 2 Sep 2024 20:20:42 +0200 Subject: [PATCH 11/13] some fixes to modded file loading --- include/Megamix.hpp | 10 +++++----- src/Megamix/HookFuncs/FS.cpp | 16 ++++++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/include/Megamix.hpp b/include/Megamix.hpp index bbc40ed..ed9a35a 100644 --- a/include/Megamix.hpp +++ b/include/Megamix.hpp @@ -1,11 +1,11 @@ #ifndef MEGAMIX_H #define MEGAMIX_H -#define MEGAMIX_BASE_PATH "/spicerack/" -#define MEGAMIX_BIN_PATH "/spicerack/bin/" -#define MEGAMIX_CRASH_PATH "/spicerack/crash/" -#define MEGAMIX_MODS_PATH "/spicerack/mods/" -#define MEGAMIX_CONFIG_PATH MEGAMIX_BIN_PATH "saltwater.cfg" +#define MEGAMIX_BASE_PATH "/spicerack/" +#define MEGAMIX_BIN_PATH MEGAMIX_BASE_PATH "bin/" +#define MEGAMIX_CRASH_PATH MEGAMIX_BASE_PATH "crash/" +#define MEGAMIX_MODS_PATH MEGAMIX_BASE_PATH "mods/" +#define MEGAMIX_CONFIG_PATH MEGAMIX_BIN_PATH "saltwater.cfg" #include "Saltwater.hpp" #include "Megamix/BTKS.hpp" diff --git a/src/Megamix/HookFuncs/FS.cpp b/src/Megamix/HookFuncs/FS.cpp index 070c53a..9d7d9b2 100644 --- a/src/Megamix/HookFuncs/FS.cpp +++ b/src/Megamix/HookFuncs/FS.cpp @@ -31,7 +31,7 @@ namespace Megamix::Hooks { return (((result & 0x3fc00) == 0x4400) && (99 < (result & 0x3ff))) && ((result & 0x3ff) < 0xb4); }; - const char* LAYERED_LOCATION = "/spicerack/fs/%ls%ls"; + const char* LAYERED_LOCATION = MEGAMIX_BIN_PATH "fs/%ls%ls"; wchar_t* strings_utf32[3] = { new wchar_t[9], @@ -59,20 +59,24 @@ namespace Megamix::Hooks { } if (result_ctrpf == 0) { - // TODO: read file here - ERRF_ThrowResultWithMessage(0xdeadc0de, "WIP"); + // read the file here s64 size = file_ctrpf.GetSize(); if (size < 0) { - ERRF_ThrowResultWithMessage(size, "(m) Could not read file"); + ERRF_ThrowResultWithMessage(size, "(m) Could not read filesize"); } fileInfo->fileSize = size; - void* fileBuffer = Region::OperatorNewFunc()(fileInfo->fileSize, fileInfo->mode, fileInfo->alignment); - result_ctrpf = file_ctrpf.Read(fileBuffer, fileInfo->fileSize); + fileInfo->fileBuffer = Region::OperatorNewFunc()(fileInfo->fileSize, fileInfo->mode, fileInfo->alignment); + + // CTRPF can't write to RAM for whatever reason, so we're adding an extra buffer + u8* tempBuffer = new u8[size]; + result_ctrpf = file_ctrpf.Read(tempBuffer, fileInfo->fileSize); if (result_ctrpf < 0) { ERRF_ThrowResultWithMessage(result_ctrpf, "(m) Could not read file"); } + memcpy(fileInfo->fileBuffer, tempBuffer, fileInfo->fileSize); + delete tempBuffer; file_ctrpf.Close(); } else { From e5561367f793d70fefcc2f506f4cf3088eb41bbc Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Wed, 18 Sep 2024 18:47:45 +0200 Subject: [PATCH 12/13] FINALLY fix error screen --- src/Megamix/Error.cpp | 19 ++++++++++--------- src/Megamix/HookFuncs/FS.cpp | 4 ++-- src/main.cpp | 5 +++++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/Megamix/Error.cpp b/src/Megamix/Error.cpp index 3dce500..704452e 100644 --- a/src/Megamix/Error.cpp +++ b/src/Megamix/Error.cpp @@ -153,19 +153,20 @@ namespace Megamix { crash.registers[i] = regs->r[i]; crash.registers[13] = regs->sp; - u8* stack = (u8*)regs->sp; - u32 stack_len = (u32)stack >= 0x06000000 - ? 0x100 // (u32)pluginStackEnd - (u32)stack --- no autodetect for now - : 0x01000000 - (u32)stack; - crash.stackLength = stack_len < 0x100 ? stack_len : 0x100; + u32 stack = regs->sp; - memcpy(crash.stackDump, stack, stack_len); + u32 stack_len = stack >= 0x06000000 + ? 0x100 // pluginStackEnd - stack --- no autodetect for now + : 0x01000000 - stack; + crash.stackLength = stack_len = stack_len <= 0x100 ? stack_len : 0x100; - // TODO: get call stack + memcpy(crash.stackDump, (u8*)stack, stack_len); + + // get call stack u32 stack_offset = 0; for (int i = 0; i < CALL_STACK_SIZE; i++) { - while ((u32)stack >= 0x06000000 || (u32)(stack + stack_offset) < 0x01000000) { - u32 val = *(u32*)(regs->sp + stack_offset); + while (stack_offset < stack_len) { + u32 val = *(u32*)(stack + stack_offset); if ((val >= 0x0010000 && val < Region::TextEnd() || (val >= (u32)_start && val < _TEXT_END))) { crash.info.callStack[i] = val; stack_offset += 4; diff --git a/src/Megamix/HookFuncs/FS.cpp b/src/Megamix/HookFuncs/FS.cpp index 9d7d9b2..646c61c 100644 --- a/src/Megamix/HookFuncs/FS.cpp +++ b/src/Megamix/HookFuncs/FS.cpp @@ -87,7 +87,7 @@ namespace Megamix::Hooks { Result result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); - // locale - RomFS + // locale - RomFS if (game_result_checker(result_game)) { if ((u32)inputStream.base.ptr >> 1 != 0) { if ((u32)inputStream.base.ptr & 1 == 1) { @@ -102,7 +102,7 @@ namespace Megamix::Hooks { result_game = Region::TryOpenFileFunc()(&inputStream.base, buffer, 1); } - // global - RomFS + // global - RomFS if (game_result_checker(result_game)) { if ((u32)inputStream.base.ptr >> 1 != 0) { if ((u32)inputStream.base.ptr & 1 == 1) { diff --git a/src/main.cpp b/src/main.cpp index 3ccc5dc..ce934d4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -160,6 +160,11 @@ int ctrpf::main(void) { // Crash handler Process::exceptionCallback = Megamix::CrashHandler; +#ifdef RELEASE + // it's more important to be able to fix an error with the game than an error with the crash handler + Process::ThrowOldExceptionOnCallbackException = true; +#endif + if (params.barista != 0xD06) { ctrpf::MessageBox("Barista not used!", "You must run Saltwater from the Barista launcher!")(); Process::ReturnToHomeMenu(); From 28abf1c927ba86903d65451887a6b18fc3d1cc3d Mon Sep 17 00:00:00 2001 From: patataofcourse Date: Wed, 18 Sep 2024 19:40:03 +0200 Subject: [PATCH 13/13] small fix to modded FS --- src/Megamix/HookFuncs/FS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Megamix/HookFuncs/FS.cpp b/src/Megamix/HookFuncs/FS.cpp index 646c61c..d766d58 100644 --- a/src/Megamix/HookFuncs/FS.cpp +++ b/src/Megamix/HookFuncs/FS.cpp @@ -76,7 +76,7 @@ namespace Megamix::Hooks { ERRF_ThrowResultWithMessage(result_ctrpf, "(m) Could not read file"); } memcpy(fileInfo->fileBuffer, tempBuffer, fileInfo->fileSize); - delete tempBuffer; + delete[] tempBuffer; file_ctrpf.Close(); } else {