mirror of
https://github.com/wiiu-env/homebrew_on_menu_plugin.git
synced 2024-11-22 10:39:16 +01:00
Use a separate Wii U Menu save copy per console
This commit is contained in:
parent
b1e0696a01
commit
14dee3b422
@ -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
|
||||||
|
@ -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.**
|
||||||
|
|
||||||
|
@ -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,38 +59,75 @@ 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())) {
|
||||||
|
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());
|
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaAccountSaveFilePathOriginal.c_str(), BaristaAccountSaveFilePathNew.c_str());
|
||||||
if (!FSUtils::copyFile(BaristaAccountSaveFilePathOriginal, BaristaAccountSaveFilePathNew)) {
|
if (!FSUtils::copyFile(BaristaAccountSaveFilePathOriginal, BaristaAccountSaveFilePathNew)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaAccountSaveFilePathOriginal.c_str(), BaristaAccountSaveFilePathNew.c_str());
|
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())) {
|
||||||
|
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());
|
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaCommonSaveFileOriginal.c_str(), BaristaCommonSaveFile.c_str());
|
||||||
if (!FSUtils::copyFile(BaristaCommonSaveFileOriginal, BaristaCommonSaveFile)) {
|
if (!FSUtils::copyFile(BaristaCommonSaveFileOriginal, BaristaCommonSaveFile)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaCommonSaveFileOriginal.c_str(), BaristaCommonSaveFile.c_str());
|
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())) {
|
||||||
|
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());
|
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaIconDataBaseOriginal.c_str(), BaristaIconDataBase.c_str());
|
||||||
if (!FSUtils::copyFile(BaristaIconDataBaseOriginal, BaristaIconDataBase)) {
|
if (!FSUtils::copyFile(BaristaIconDataBaseOriginal, BaristaIconDataBase)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaIconDataBaseOriginal.c_str(), BaristaIconDataBase.c_str());
|
DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaIconDataBaseOriginal.c_str(), BaristaIconDataBase.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initSaveData() {
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
3
src/globals.cpp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "globals.h"
|
||||||
|
|
||||||
|
std::string gSerialId;
|
4
src/globals.h
Normal file
4
src/globals.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
extern std::string gSerialId;
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user