Use a separate Wii U Menu save copy per console

This commit is contained in:
Maschell 2023-04-02 21:26:13 +02:00
parent b1e0696a01
commit 14dee3b422
9 changed files with 119 additions and 21 deletions

View File

@ -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/wiiupluginsystem:20230316 /artifacts $DEVKITPRO
COPY --from=ghcr.io/wiiu-env/librpxloader:20230316 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/librpxloader:20230316 /artifacts $DEVKITPRO

View File

@ -47,8 +47,9 @@ CoolGame.wuhb
``` ```
## Save data redirection ## 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`. 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
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. `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.** **If the plugin is configured to hide any homebrew except a Homebrew Launcher, the redirection is disabled.**

View File

@ -1,5 +1,7 @@
#include "SaveRedirection.h" #include "SaveRedirection.h"
#include "globals.h"
#include <content_redirection/redirection.h> #include <content_redirection/redirection.h>
#include <coreinit/mcp.h>
#include <coreinit/title.h> #include <coreinit/title.h>
#include <fs/FSUtils.h> #include <fs/FSUtils.h>
#include <functional> #include <functional>
@ -13,9 +15,25 @@
bool gInWiiUMenu __attribute__((section(".data"))) = false; bool gInWiiUMenu __attribute__((section(".data"))) = false;
CRLayerHandle saveLayer __attribute__((section(".data"))) = 0; 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() { void SaveRedirectionCleanUp() {
if (saveLayer != 0) { 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); auto res = ContentRedirection_RemoveFSLayer(saveLayer);
if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) { if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to remove save FSLayer"); DEBUG_FUNCTION_LINE_ERR("Failed to remove save FSLayer");
@ -29,9 +47,11 @@ void CopyExistingFiles() {
nn::act::PersistentId persistentId = nn::act::GetPersistentId(); nn::act::PersistentId persistentId = nn::act::GetPersistentId();
nn::act::Finalize(); 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 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); std::string userOriginal = string_format("fs:/vol/save/%08X", 0x80000000 | persistentId);
FSUtils::CreateSubfolder(common.c_str()); FSUtils::CreateSubfolder(common.c_str());
@ -39,28 +59,64 @@ void CopyExistingFiles() {
auto BaristaAccountSaveFilePathNew = user + "/BaristaAccountSaveFile.dat"; auto BaristaAccountSaveFilePathNew = user + "/BaristaAccountSaveFile.dat";
auto BaristaAccountSaveFilePathOriginal = userOriginal + "/BaristaAccountSaveFile.dat"; auto BaristaAccountSaveFilePathOriginal = userOriginal + "/BaristaAccountSaveFile.dat";
auto BaristaAccountSaveFilePathLegacy = userLegacy + "/BaristaAccountSaveFile.dat";
if (!FSUtils::CheckFile(BaristaAccountSaveFilePathNew.c_str())) { if (!FSUtils::CheckFile(BaristaAccountSaveFilePathNew.c_str())) {
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaAccountSaveFilePathOriginal.c_str(), BaristaAccountSaveFilePathNew.c_str()); if (FSUtils::CheckFile(BaristaAccountSaveFilePathLegacy.c_str())) {
if (!FSUtils::copyFile(BaristaAccountSaveFilePathOriginal, BaristaAccountSaveFilePathNew)) { DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaAccountSaveFilePathLegacy.c_str(), BaristaAccountSaveFilePathNew.c_str());
DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaAccountSaveFilePathOriginal.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 BaristaCommonSaveFile = common + "/BaristaCommonSaveFile.dat";
auto BaristaCommonSaveFileOriginal = commonOriginal + "/BaristaCommonSaveFile.dat"; auto BaristaCommonSaveFileOriginal = commonOriginal + "/BaristaCommonSaveFile.dat";
auto BaristaCommonSaveFileLegacy = commonLegacy + "/BaristaCommonSaveFile.dat";
if (!FSUtils::CheckFile(BaristaCommonSaveFile.c_str())) { if (!FSUtils::CheckFile(BaristaCommonSaveFile.c_str())) {
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaCommonSaveFileOriginal.c_str(), BaristaCommonSaveFile.c_str()); if (FSUtils::CheckFile(BaristaCommonSaveFileLegacy.c_str())) {
if (!FSUtils::copyFile(BaristaCommonSaveFileOriginal, BaristaCommonSaveFile)) { DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaCommonSaveFileLegacy.c_str(), BaristaCommonSaveFile.c_str());
DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaCommonSaveFileOriginal.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 BaristaIconDataBase = common + "/BaristaIconDataBase.dat";
auto BaristaIconDataBaseOriginal = commonOriginal + "/BaristaIconDataBase.dat"; auto BaristaIconDataBaseOriginal = commonOriginal + "/BaristaIconDataBase.dat";
auto BaristaIconDataBaseLegacy = commonLegacy + "/BaristaIconDataBase.dat";
if (!FSUtils::CheckFile(BaristaIconDataBase.c_str())) { if (!FSUtils::CheckFile(BaristaIconDataBase.c_str())) {
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaIconDataBaseOriginal.c_str(), BaristaIconDataBase.c_str()); if (FSUtils::CheckFile(BaristaIconDataBaseLegacy.c_str())) {
if (!FSUtils::copyFile(BaristaIconDataBaseOriginal, BaristaIconDataBase)) { DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaIconDataBaseLegacy.c_str(), BaristaIconDataBase.c_str());
DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaIconDataBaseOriginal.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(); SaveRedirectionCleanUp();
CopyExistingFiles(); CopyExistingFiles();
DEBUG_FUNCTION_LINE("Setup save redirection: %s -> %s", "/vol/save", "fs:" SAVE_REPLACEMENT_PATH "/save/"); std::string replaceDir = getBaseSavePathFS();
auto res = ContentRedirection_AddFSLayer(&saveLayer, "homp_save_redirection", "fs:" SAVE_REPLACEMENT_PATH "/save/", FS_LAYER_TYPE_SAVE_REPLACE); 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) { if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) {
DEBUG_FUNCTION_LINE_ERR("Failed to add save FS Layer: %d", res); 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 == 0x0005001010040100L || // Wii U Menu USA
titleID == 0x0005001010040200L) { // Wii U Menu EUR titleID == 0x0005001010040200L) { // Wii U Menu EUR
if (buffer != nullptr) { if (buffer != nullptr) {
std::string commonReplacement = SAVE_REPLACEMENT_PATH "/save/common"; std::string commonReplacement = getBaseSavePath() + "/common";
auto BaristaCommonSaveFile = "fs:" + commonReplacement + "/BaristaCommonSaveFile.dat"; auto BaristaCommonSaveFile = "fs:" + commonReplacement + "/BaristaCommonSaveFile.dat";
auto BaristaIconDataBase = "fs:" + commonReplacement + "/BaristaIconDataBase.dat"; auto BaristaIconDataBase = "fs:" + commonReplacement + "/BaristaIconDataBase.dat";
if (FSUtils::CheckFile(BaristaCommonSaveFile.c_str()) && if (FSUtils::CheckFile(BaristaCommonSaveFile.c_str()) &&
FSUtils::CheckFile(BaristaIconDataBase.c_str())) { FSUtils::CheckFile(BaristaIconDataBase.c_str())) {
snprintf(buffer, bufferSize, "%s/%s", commonReplacement.c_str(), path); 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; return SAVE_STATUS_OK;
} }
} }

View File

@ -2,6 +2,6 @@
extern bool gInWiiUMenu; 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(); void SaveRedirectionCleanUp();

3
src/globals.cpp Normal file
View File

@ -0,0 +1,3 @@
#include "globals.h"
std::string gSerialId;

4
src/globals.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
#include <string>
extern std::string gSerialId;

View File

@ -6,6 +6,7 @@
#include "fs/FSUtils.h" #include "fs/FSUtils.h"
#include "fs/FileReader.h" #include "fs/FileReader.h"
#include "fs/FileReaderWUHB.h" #include "fs/FileReaderWUHB.h"
#include "globals.h"
#include "utils/StringTools.h" #include "utils/StringTools.h"
#include "utils/ini.h" #include "utils/ini.h"
#include <algorithm> #include <algorithm>
@ -94,6 +95,12 @@ INITIALIZE_PLUGIN() {
memset((void *) &gLaunchXML, 0, sizeof(gLaunchXML)); memset((void *) &gLaunchXML, 0, sizeof(gLaunchXML));
gHomebrewLaunched = FALSE; 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. // Use libwuhbutils.
WUHBUtilsStatus error; WUHBUtilsStatus error;
if ((error = WUHBUtils_InitLibrary()) != WUHB_UTILS_RESULT_SUCCESS) { if ((error = WUHBUtils_InitLibrary()) != WUHB_UTILS_RESULT_SUCCESS) {

View File

@ -1,4 +1,7 @@
#include <stdint.h> #include "utils.h"
#include "logger.h"
#include <coreinit/mcp.h>
#include <string>
/* hash: compute hash value of string */ /* hash: compute hash value of string */
unsigned int hash_string(const char *str) { unsigned int hash_string(const char *str) {
@ -11,3 +14,21 @@ unsigned int hash_string(const char *str) {
} }
return h; // or, h % ARRAY_SIZE; 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;
}

View File

@ -5,6 +5,7 @@
#include <malloc.h> #include <malloc.h>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string>
uint32_t hash_string(const char *); uint32_t hash_string(const char *);
@ -31,3 +32,7 @@ bool remove_locked_first_if(std::mutex &mutex, std::forward_list<T, Allocator> &
} }
return false; return false;
} }
namespace Utils {
bool GetSerialId(std::string &serialID);
}