From 14dee3b42228568e5c3240a6890124603136db6a Mon Sep 17 00:00:00 2001 From: Maschell Date: Sun, 2 Apr 2023 21:26:13 +0200 Subject: [PATCH] Use a separate Wii U Menu save copy per console --- Dockerfile | 2 +- README.md | 5 ++- src/SaveRedirection.cpp | 89 +++++++++++++++++++++++++++++++++-------- src/SaveRedirection.h | 2 +- src/globals.cpp | 3 ++ src/globals.h | 4 ++ src/main.cpp | 7 ++++ src/utils/utils.cpp | 23 ++++++++++- src/utils/utils.h | 5 +++ 9 files changed, 119 insertions(+), 21 deletions(-) create mode 100644 src/globals.cpp create mode 100644 src/globals.h diff --git a/Dockerfile b/Dockerfile index ecc94c6..8d82d58 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/wiiu-env/devkitppc:20230218 +FROM ghcr.io/wiiu-env/devkitppc:20230402 COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:20230316 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/librpxloader:20230316 /artifacts $DEVKITPRO diff --git a/README.md b/README.md index bf6fb72..83d0476 100644 --- a/README.md +++ b/README.md @@ -47,8 +47,9 @@ CoolGame.wuhb ``` ## Save data redirection -In order to preserve the order of homebrew apps even when you run the Wii U Menu without this plugin, this plugin will redirect the Wii U Menu save data to `sd:/wiiu/homebrew_on_menu_plugin`. -When no save data is found on the sd card, the current save data is copied from the console, but after that it's never updated. +In order to preserve the order of homebrew apps even when you run the Wii U Menu without this plugin, this plugin will redirect the Wii U Menu save data to +`sd:/wiiu/homebrew_on_menu_plugin/[SerialNumberOfTheConsole]/save`. When no save data is found on the sd card, the current save data is copied from the console, +but after that it's never updated. **If the plugin is configured to hide any homebrew except a Homebrew Launcher, the redirection is disabled.** diff --git a/src/SaveRedirection.cpp b/src/SaveRedirection.cpp index a92a23d..d2fe1e6 100644 --- a/src/SaveRedirection.cpp +++ b/src/SaveRedirection.cpp @@ -1,5 +1,7 @@ #include "SaveRedirection.h" +#include "globals.h" #include +#include #include #include #include @@ -13,9 +15,25 @@ bool gInWiiUMenu __attribute__((section(".data"))) = false; CRLayerHandle saveLayer __attribute__((section(".data"))) = 0; +static inline std::string getBaseSavePathLegacy() { + return std::string(HOMEBREW_ON_MENU_PLUGIN_DATA_PATH) + "/save"; +} + +static inline std::string getBaseSavePathLegacyFS() { + return std::string("fs:") + getBaseSavePathLegacy(); +} + +static inline std::string getBaseSavePath() { + return string_format(HOMEBREW_ON_MENU_PLUGIN_DATA_PATH "/%s/save", gSerialId.c_str()); +} + +static inline std::string getBaseSavePathFS() { + return "fs:" + getBaseSavePath(); +} + void SaveRedirectionCleanUp() { if (saveLayer != 0) { - DEBUG_FUNCTION_LINE("Remove save redirection: %s -> %s", "/vol/save", "fs:" SAVE_REPLACEMENT_PATH "/save/"); + DEBUG_FUNCTION_LINE("Remove save redirection: %s -> %s", "/vol/save", getBaseSavePathFS().c_str()); auto res = ContentRedirection_RemoveFSLayer(saveLayer); if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) { DEBUG_FUNCTION_LINE_ERR("Failed to remove save FSLayer"); @@ -29,9 +47,11 @@ void CopyExistingFiles() { nn::act::PersistentId persistentId = nn::act::GetPersistentId(); nn::act::Finalize(); - std::string common = "fs:" SAVE_REPLACEMENT_PATH "/save/common"; + std::string common = getBaseSavePathFS() + "/common"; + std::string commonLegacy = getBaseSavePathLegacyFS() + "/common"; std::string commonOriginal = "fs:/vol/save/common"; - std::string user = string_format("fs:" SAVE_REPLACEMENT_PATH "/save/%08X", 0x80000000 | persistentId); + std::string user = string_format("%s/%08X", getBaseSavePathFS().c_str(), 0x80000000 | persistentId); + std::string userLegacy = string_format("%s/%08X", getBaseSavePathLegacyFS().c_str(), 0x80000000 | persistentId); std::string userOriginal = string_format("fs:/vol/save/%08X", 0x80000000 | persistentId); FSUtils::CreateSubfolder(common.c_str()); @@ -39,28 +59,64 @@ void CopyExistingFiles() { auto BaristaAccountSaveFilePathNew = user + "/BaristaAccountSaveFile.dat"; auto BaristaAccountSaveFilePathOriginal = userOriginal + "/BaristaAccountSaveFile.dat"; + auto BaristaAccountSaveFilePathLegacy = userLegacy + "/BaristaAccountSaveFile.dat"; if (!FSUtils::CheckFile(BaristaAccountSaveFilePathNew.c_str())) { - DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaAccountSaveFilePathOriginal.c_str(), BaristaAccountSaveFilePathNew.c_str()); - if (!FSUtils::copyFile(BaristaAccountSaveFilePathOriginal, BaristaAccountSaveFilePathNew)) { - DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaAccountSaveFilePathOriginal.c_str(), BaristaAccountSaveFilePathNew.c_str()); + if (FSUtils::CheckFile(BaristaAccountSaveFilePathLegacy.c_str())) { + DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaAccountSaveFilePathLegacy.c_str(), BaristaAccountSaveFilePathNew.c_str()); + if (!FSUtils::copyFile(BaristaAccountSaveFilePathLegacy, BaristaAccountSaveFilePathNew)) { + DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaAccountSaveFilePathLegacy.c_str(), BaristaAccountSaveFilePathNew.c_str()); + } else { + if (remove(BaristaAccountSaveFilePathLegacy.c_str()) < 0) { + DEBUG_FUNCTION_LINE_ERR("Failed to delete %s", BaristaAccountSaveFilePathLegacy.c_str()); + } + } + } else { + DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaAccountSaveFilePathOriginal.c_str(), BaristaAccountSaveFilePathNew.c_str()); + if (!FSUtils::copyFile(BaristaAccountSaveFilePathOriginal, BaristaAccountSaveFilePathNew)) { + DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaAccountSaveFilePathOriginal.c_str(), BaristaAccountSaveFilePathNew.c_str()); + } } } auto BaristaCommonSaveFile = common + "/BaristaCommonSaveFile.dat"; auto BaristaCommonSaveFileOriginal = commonOriginal + "/BaristaCommonSaveFile.dat"; + auto BaristaCommonSaveFileLegacy = commonLegacy + "/BaristaCommonSaveFile.dat"; if (!FSUtils::CheckFile(BaristaCommonSaveFile.c_str())) { - DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaCommonSaveFileOriginal.c_str(), BaristaCommonSaveFile.c_str()); - if (!FSUtils::copyFile(BaristaCommonSaveFileOriginal, BaristaCommonSaveFile)) { - DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaCommonSaveFileOriginal.c_str(), BaristaCommonSaveFile.c_str()); + if (FSUtils::CheckFile(BaristaCommonSaveFileLegacy.c_str())) { + DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaCommonSaveFileLegacy.c_str(), BaristaCommonSaveFile.c_str()); + if (!FSUtils::copyFile(BaristaCommonSaveFileLegacy, BaristaCommonSaveFile)) { + DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaCommonSaveFileLegacy.c_str(), BaristaCommonSaveFile.c_str()); + } else { + if (remove(BaristaCommonSaveFileLegacy.c_str()) < 0) { + DEBUG_FUNCTION_LINE_ERR("Failed to delete %s", BaristaCommonSaveFileLegacy.c_str()); + } + } + } else { + DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaCommonSaveFileOriginal.c_str(), BaristaCommonSaveFile.c_str()); + if (!FSUtils::copyFile(BaristaCommonSaveFileOriginal, BaristaCommonSaveFile)) { + DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaCommonSaveFileOriginal.c_str(), BaristaCommonSaveFile.c_str()); + } } } auto BaristaIconDataBase = common + "/BaristaIconDataBase.dat"; auto BaristaIconDataBaseOriginal = commonOriginal + "/BaristaIconDataBase.dat"; + auto BaristaIconDataBaseLegacy = commonLegacy + "/BaristaIconDataBase.dat"; if (!FSUtils::CheckFile(BaristaIconDataBase.c_str())) { - DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaIconDataBaseOriginal.c_str(), BaristaIconDataBase.c_str()); - if (!FSUtils::copyFile(BaristaIconDataBaseOriginal, BaristaIconDataBase)) { - DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaIconDataBaseOriginal.c_str(), BaristaIconDataBase.c_str()); + if (FSUtils::CheckFile(BaristaIconDataBaseLegacy.c_str())) { + DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaIconDataBaseLegacy.c_str(), BaristaIconDataBase.c_str()); + if (!FSUtils::copyFile(BaristaIconDataBaseLegacy, BaristaIconDataBase)) { + DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaIconDataBaseLegacy.c_str(), BaristaIconDataBase.c_str()); + } else { + if (remove(BaristaIconDataBaseLegacy.c_str()) < 0) { + DEBUG_FUNCTION_LINE_ERR("Failed to delete %s", BaristaIconDataBaseLegacy.c_str()); + } + } + } else { + DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaIconDataBaseOriginal.c_str(), BaristaIconDataBase.c_str()); + if (!FSUtils::copyFile(BaristaIconDataBaseOriginal, BaristaIconDataBase)) { + DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaIconDataBaseOriginal.c_str(), BaristaIconDataBase.c_str()); + } } } } @@ -69,8 +125,9 @@ void initSaveData() { SaveRedirectionCleanUp(); CopyExistingFiles(); - DEBUG_FUNCTION_LINE("Setup save redirection: %s -> %s", "/vol/save", "fs:" SAVE_REPLACEMENT_PATH "/save/"); - auto res = ContentRedirection_AddFSLayer(&saveLayer, "homp_save_redirection", "fs:" SAVE_REPLACEMENT_PATH "/save/", FS_LAYER_TYPE_SAVE_REPLACE); + std::string replaceDir = getBaseSavePathFS(); + DEBUG_FUNCTION_LINE("Setup save redirection: %s -> %s", "/vol/save", replaceDir.c_str()); + auto res = ContentRedirection_AddFSLayer(&saveLayer, "homp_save_redirection", replaceDir.c_str(), FS_LAYER_TYPE_SAVE_REPLACE); if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) { DEBUG_FUNCTION_LINE_ERR("Failed to add save FS Layer: %d", res); } @@ -92,13 +149,13 @@ DECL_FUNCTION(SAVEStatus, SAVEGetSharedSaveDataPath, uint64_t titleID, const cha titleID == 0x0005001010040100L || // Wii U Menu USA titleID == 0x0005001010040200L) { // Wii U Menu EUR if (buffer != nullptr) { - std::string commonReplacement = SAVE_REPLACEMENT_PATH "/save/common"; + std::string commonReplacement = getBaseSavePath() + "/common"; auto BaristaCommonSaveFile = "fs:" + commonReplacement + "/BaristaCommonSaveFile.dat"; auto BaristaIconDataBase = "fs:" + commonReplacement + "/BaristaIconDataBase.dat"; if (FSUtils::CheckFile(BaristaCommonSaveFile.c_str()) && FSUtils::CheckFile(BaristaIconDataBase.c_str())) { snprintf(buffer, bufferSize, "%s/%s", commonReplacement.c_str(), path); - DEBUG_FUNCTION_LINE("Redirect Wii U Menu common path with %s", buffer); + DEBUG_FUNCTION_LINE("Redirect Wii U Menu common path to %s", commonReplacement.c_str()); return SAVE_STATUS_OK; } } diff --git a/src/SaveRedirection.h b/src/SaveRedirection.h index 949b8ba..d6dafb0 100644 --- a/src/SaveRedirection.h +++ b/src/SaveRedirection.h @@ -2,6 +2,6 @@ extern bool gInWiiUMenu; -#define SAVE_REPLACEMENT_PATH "/vol/external01/wiiu/homebrew_on_menu_plugin" +#define HOMEBREW_ON_MENU_PLUGIN_DATA_PATH "/vol/external01/wiiu/homebrew_on_menu_plugin" void SaveRedirectionCleanUp(); \ No newline at end of file diff --git a/src/globals.cpp b/src/globals.cpp new file mode 100644 index 0000000..4c44f93 --- /dev/null +++ b/src/globals.cpp @@ -0,0 +1,3 @@ +#include "globals.h" + +std::string gSerialId; \ No newline at end of file diff --git a/src/globals.h b/src/globals.h new file mode 100644 index 0000000..97b22cb --- /dev/null +++ b/src/globals.h @@ -0,0 +1,4 @@ +#pragma once +#include + +extern std::string gSerialId; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index b4a854c..8d0a630 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ #include "fs/FSUtils.h" #include "fs/FileReader.h" #include "fs/FileReaderWUHB.h" +#include "globals.h" #include "utils/StringTools.h" #include "utils/ini.h" #include @@ -94,6 +95,12 @@ INITIALIZE_PLUGIN() { memset((void *) &gLaunchXML, 0, sizeof(gLaunchXML)); gHomebrewLaunched = FALSE; + gSerialId = {}; + if (!Utils::GetSerialId(gSerialId) || gSerialId.empty()) { + DEBUG_FUNCTION_LINE_ERR("Homebrew on Menu Plugin: Failed to get the serial id"); + OSFatal("Homebrew on Menu Plugin: Failed to get the serial id"); + } + // Use libwuhbutils. WUHBUtilsStatus error; if ((error = WUHBUtils_InitLibrary()) != WUHB_UTILS_RESULT_SUCCESS) { diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index a59c05a..63f8812 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -1,4 +1,7 @@ -#include +#include "utils.h" +#include "logger.h" +#include +#include /* hash: compute hash value of string */ unsigned int hash_string(const char *str) { @@ -11,3 +14,21 @@ unsigned int hash_string(const char *str) { } return h; // or, h % ARRAY_SIZE; } + +bool Utils::GetSerialId(std::string &serialID) { + bool result = false; + alignas(0x40) MCPSysProdSettings settings{}; + auto handle = MCP_Open(); + if (handle >= 0) { + if (MCP_GetSysProdSettings(handle, &settings) == 0) { + serialID = std::string(settings.code_id) + settings.serial_id; + result = true; + } else { + DEBUG_FUNCTION_LINE_ERR("Failed to get SerialId"); + } + MCP_Close(handle); + } else { + DEBUG_FUNCTION_LINE_ERR("MCP_Open failed"); + } + return result; +} \ No newline at end of file diff --git a/src/utils/utils.h b/src/utils/utils.h index 8840ce7..094af4b 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -5,6 +5,7 @@ #include #include #include +#include uint32_t hash_string(const char *); @@ -31,3 +32,7 @@ bool remove_locked_first_if(std::mutex &mutex, std::forward_list & } return false; } + +namespace Utils { + bool GetSerialId(std::string &serialID); +} \ No newline at end of file