mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2024-11-24 21:56:53 +01:00
Add support for notifications on error
This commit is contained in:
parent
efcde57f74
commit
07de996bf9
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,3 +8,4 @@ build/
|
|||||||
cmake-build-debug/
|
cmake-build-debug/
|
||||||
CMakeLists.txt
|
CMakeLists.txt
|
||||||
*.wms
|
*.wms
|
||||||
|
*.zip
|
||||||
|
@ -5,5 +5,6 @@ COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:20230719 /artifacts $DEVKITPRO
|
|||||||
COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO
|
COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO
|
||||||
COPY --from=ghcr.io/wiiu-env/libmappedmemory:20230621 /artifacts $DEVKITPRO
|
COPY --from=ghcr.io/wiiu-env/libmappedmemory:20230621 /artifacts $DEVKITPRO
|
||||||
COPY --from=ghcr.io/wiiu-env/libwupsbackend:20230621 /artifacts $DEVKITPRO
|
COPY --from=ghcr.io/wiiu-env/libwupsbackend:20230621 /artifacts $DEVKITPRO
|
||||||
|
COPY --from=ghcr.io/wiiu-env/libnotifications:20230621 /artifacts $DEVKITPRO
|
||||||
|
|
||||||
WORKDIR project
|
WORKDIR project
|
||||||
|
2
Makefile
2
Makefile
@ -55,7 +55,7 @@ CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
|||||||
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LIBS := -lwums -lwut -lwups -lfunctionpatcher -lmappedmemory -lz
|
LIBS := -lwums -lwut -lwups -lfunctionpatcher -lmappedmemory -lz -lnotifications
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
# list of directories containing libraries, this must be the top level
|
# list of directories containing libraries, this must be the top level
|
||||||
|
@ -10,6 +10,7 @@ This is the backend for the [WiiUPluginSystem](https://github.com/wiiu-env/WiiUP
|
|||||||
2. Requires the [WUMSLoader](https://github.com/wiiu-env/WUMSLoader) in `sd:/wiiu/environments/[ENVIRONMENT]/modules/setup`.
|
2. Requires the [WUMSLoader](https://github.com/wiiu-env/WUMSLoader) in `sd:/wiiu/environments/[ENVIRONMENT]/modules/setup`.
|
||||||
3. Requires the [FunctionPatcherModule](https://github.com/wiiu-env/FunctionPatcherModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
3. Requires the [FunctionPatcherModule](https://github.com/wiiu-env/FunctionPatcherModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
||||||
4. Requires the [MemoryMappingModule](https://github.com/wiiu-env/MemoryMappingModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
4. Requires the [MemoryMappingModule](https://github.com/wiiu-env/MemoryMappingModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
||||||
|
5. Requires the [NotificationModule](https://github.com/wiiu-env/NotificationModule) in `sd:/wiiu/environments/[ENVIRONMENT]/modules`.
|
||||||
|
|
||||||
Plugins needs to be placed into the following directory:
|
Plugins needs to be placed into the following directory:
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ DEVKITPRO=/opt/devkitpro
|
|||||||
DEVKITPPC=/opt/devkitpro/devkitPPC
|
DEVKITPPC=/opt/devkitpro/devkitPPC
|
||||||
```
|
```
|
||||||
|
|
||||||
Also make sure to install [wut](https://github.com/decaf-emu/wut), [WiiUPluginSystem](https://github.com/wiiu-env/WiiUPluginSystem), [WiiUModuleSystem](https://github.com/wiiu-env/WiiUModuleSystem), [libfunctionpatcher](https://github.com/wiiu-env/libfunctionpatcher) and [libmappedmemory](https://github.com/wiiu-env/libmappedmemory).
|
Also make sure to install [wut](https://github.com/decaf-emu/wut), [WiiUPluginSystem](https://github.com/wiiu-env/WiiUPluginSystem), [WiiUModuleSystem](https://github.com/wiiu-env/WiiUModuleSystem), [libfunctionpatcher](https://github.com/wiiu-env/libfunctionpatcher), [libnotifications](https://github.com/wiiu-env/libnotifications) and [libmappedmemory](https://github.com/wiiu-env/libmappedmemory).
|
||||||
|
|
||||||
## Buildflags
|
## Buildflags
|
||||||
|
|
||||||
|
117
source/NotificationsUtils.cpp
Normal file
117
source/NotificationsUtils.cpp
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
#include "NotificationsUtils.h"
|
||||||
|
#include "globals.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include <coreinit/cache.h>
|
||||||
|
#include <coreinit/messagequeue.h>
|
||||||
|
#include <coreinit/thread.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <notifications/notifications.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
std::unique_ptr<std::thread> sNotificationsThread;
|
||||||
|
static bool sShutdownNotificationsThread = false;
|
||||||
|
|
||||||
|
OSMessageQueue sNotificationQueue;
|
||||||
|
OSMessage sNotificationMessages[0x10];
|
||||||
|
|
||||||
|
#define NOTIFICATION_QUEUE_COMMAND_STOP 0
|
||||||
|
#define NOTIFICATION_QUEUE_COMMAND_ERROR 1
|
||||||
|
|
||||||
|
struct NotificationMessageWrapper {
|
||||||
|
NotificationModuleNotificationType type = NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO;
|
||||||
|
char text[512] = {};
|
||||||
|
float duration = 10.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
void NotificationMainLoop() {
|
||||||
|
bool isOverlayReady = false;
|
||||||
|
while (!sShutdownNotificationsThread &&
|
||||||
|
NotificationModule_IsOverlayReady(&isOverlayReady) == NOTIFICATION_MODULE_RESULT_SUCCESS && !isOverlayReady) {
|
||||||
|
OSSleepTicks(OSMillisecondsToTicks(16));
|
||||||
|
}
|
||||||
|
if (sShutdownNotificationsThread || !isOverlayReady) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSMessage recv;
|
||||||
|
while (OSReceiveMessage(&sNotificationQueue, &recv, OS_MESSAGE_FLAGS_BLOCKING)) {
|
||||||
|
if (recv.args[0] == NOTIFICATION_QUEUE_COMMAND_STOP) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recv.args[0] == NOTIFICATION_QUEUE_COMMAND_ERROR) {
|
||||||
|
auto *param = (NotificationMessageWrapper *) recv.message;
|
||||||
|
if (param->type == NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO) {
|
||||||
|
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, param->duration);
|
||||||
|
NotificationModule_AddInfoNotification(param->text);
|
||||||
|
} else if (param->type == NOTIFICATION_MODULE_NOTIFICATION_TYPE_ERROR) {
|
||||||
|
NotificationModule_SetDefaultValue(NOTIFICATION_MODULE_NOTIFICATION_TYPE_ERROR, NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, param->duration);
|
||||||
|
NotificationModule_AddErrorNotification(param->text);
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Unsupported notification type: %d", param->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(param);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DisplayNotificationMessage(std::string &text, NotificationModuleNotificationType type, float duration) {
|
||||||
|
if (!gNotificationModuleLoaded) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (type == NOTIFICATION_MODULE_NOTIFICATION_TYPE_DYNAMIC) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto *param = (NotificationMessageWrapper *) malloc(sizeof(NotificationMessageWrapper));
|
||||||
|
if (!param) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
strncpy(param->text, text.c_str(), sizeof(param->text) - 1);
|
||||||
|
param->type = type;
|
||||||
|
param->duration = duration;
|
||||||
|
|
||||||
|
OSMessage send;
|
||||||
|
send.message = param;
|
||||||
|
send.args[0] = NOTIFICATION_QUEUE_COMMAND_ERROR;
|
||||||
|
auto res = OSSendMessage(&sNotificationQueue, &send, OS_MESSAGE_FLAGS_NONE);
|
||||||
|
if (!res) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to add Error Notification: Queue full");
|
||||||
|
free(param);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DisplayInfoNotificationMessage(std::string &text, float duration) {
|
||||||
|
return DisplayNotificationMessage(text, NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DisplayErrorNotificationMessage(std::string &text, float duration) {
|
||||||
|
return DisplayNotificationMessage(text, NOTIFICATION_MODULE_NOTIFICATION_TYPE_ERROR, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartNotificationThread() {
|
||||||
|
sNotificationsThread.reset();
|
||||||
|
sShutdownNotificationsThread = false;
|
||||||
|
if (!gNotificationModuleLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int32_t messageSize = sizeof(sNotificationMessages) / sizeof(sNotificationMessages[0]);
|
||||||
|
OSInitMessageQueue(&sNotificationQueue, sNotificationMessages, messageSize);
|
||||||
|
sNotificationsThread = std::make_unique<std::thread>(NotificationMainLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopNotificationThread() {
|
||||||
|
if (sNotificationsThread != nullptr) {
|
||||||
|
OSMessage message;
|
||||||
|
message.args[0] = NOTIFICATION_QUEUE_COMMAND_STOP;
|
||||||
|
OSSendMessage(&sNotificationQueue, &message, OS_MESSAGE_FLAGS_NONE);
|
||||||
|
sShutdownNotificationsThread = true;
|
||||||
|
OSMemoryBarrier();
|
||||||
|
sNotificationsThread->join();
|
||||||
|
sNotificationsThread.reset();
|
||||||
|
}
|
||||||
|
}
|
11
source/NotificationsUtils.h
Normal file
11
source/NotificationsUtils.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void StartNotificationThread();
|
||||||
|
|
||||||
|
void StopNotificationThread();
|
||||||
|
|
||||||
|
bool DisplayInfoNotificationMessage(std::string &text, float duration);
|
||||||
|
|
||||||
|
bool DisplayErrorNotificationMessage(std::string &text, float duration);
|
@ -156,7 +156,9 @@ PluginManagement::loadPlugins(const std::forward_list<std::shared_ptr<PluginData
|
|||||||
if (metaInfo) {
|
if (metaInfo) {
|
||||||
auto info = PluginInformationFactory::load(pluginData, trampoline_data, trampoline_data_length, trampolineID++);
|
auto info = PluginInformationFactory::load(pluginData, trampoline_data, trampoline_data_length, trampolineID++);
|
||||||
if (!info) {
|
if (!info) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to load Plugin %s", metaInfo.value()->getName().c_str());
|
auto errMsg = string_format("Failed to load plugin: %s", metaInfo.value()->getName().c_str());
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("%s", errMsg.c_str());
|
||||||
|
DisplayErrorNotificationMessage(errMsg, 15.0f);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto container = make_unique_nothrow<PluginContainer>(std::move(metaInfo.value()), std::move(info.value()), pluginData);
|
auto container = make_unique_nothrow<PluginContainer>(std::move(metaInfo.value()), std::move(info.value()), pluginData);
|
||||||
|
@ -11,3 +11,5 @@ std::forward_list<std::shared_ptr<PluginData>> gLoadOnNextLaunch __attribute__((
|
|||||||
std::mutex gLoadedDataMutex __attribute__((section(".data")));
|
std::mutex gLoadedDataMutex __attribute__((section(".data")));
|
||||||
std::map<std::string, OSDynLoad_Module> gUsedRPLs __attribute__((section(".data")));
|
std::map<std::string, OSDynLoad_Module> gUsedRPLs __attribute__((section(".data")));
|
||||||
std::vector<void *> gAllocatedAddresses __attribute__((section(".data")));
|
std::vector<void *> gAllocatedAddresses __attribute__((section(".data")));
|
||||||
|
|
||||||
|
bool gNotificationModuleLoaded __attribute__((section(".data"))) = false;
|
@ -24,3 +24,5 @@ extern std::forward_list<std::shared_ptr<PluginData>> gLoadOnNextLaunch;
|
|||||||
extern std::mutex gLoadedDataMutex;
|
extern std::mutex gLoadedDataMutex;
|
||||||
extern std::map<std::string, OSDynLoad_Module> gUsedRPLs;
|
extern std::map<std::string, OSDynLoad_Module> gUsedRPLs;
|
||||||
extern std::vector<void *> gAllocatedAddresses;
|
extern std::vector<void *> gAllocatedAddresses;
|
||||||
|
|
||||||
|
extern bool gNotificationModuleLoaded;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "NotificationsUtils.h"
|
||||||
#include "PluginManagement.h"
|
#include "PluginManagement.h"
|
||||||
#include "coreinit/interrupts.h"
|
#include "coreinit/interrupts.h"
|
||||||
#include "coreinit/scheduler.h"
|
#include "coreinit/scheduler.h"
|
||||||
@ -7,12 +8,14 @@
|
|||||||
#include "plugin/PluginDataFactory.h"
|
#include "plugin/PluginDataFactory.h"
|
||||||
#include "utils/utils.h"
|
#include "utils/utils.h"
|
||||||
#include <coreinit/debug.h>
|
#include <coreinit/debug.h>
|
||||||
|
#include <notifications/notifications.h>
|
||||||
#include <wums.h>
|
#include <wums.h>
|
||||||
|
|
||||||
WUMS_MODULE_EXPORT_NAME("homebrew_wupsbackend");
|
WUMS_MODULE_EXPORT_NAME("homebrew_wupsbackend");
|
||||||
WUMS_USE_WUT_DEVOPTAB();
|
WUMS_USE_WUT_DEVOPTAB();
|
||||||
WUMS_DEPENDS_ON(homebrew_functionpatcher);
|
WUMS_DEPENDS_ON(homebrew_functionpatcher);
|
||||||
WUMS_DEPENDS_ON(homebrew_memorymapping);
|
WUMS_DEPENDS_ON(homebrew_memorymapping);
|
||||||
|
WUMS_DEPENDS_ON(homebrew_notifications);
|
||||||
|
|
||||||
WUMS_INITIALIZE() {
|
WUMS_INITIALIZE() {
|
||||||
initLogging();
|
initLogging();
|
||||||
@ -21,6 +24,14 @@ WUMS_INITIALIZE() {
|
|||||||
OSFatal("homebrew_wupsbackend: FunctionPatcher_InitLibrary failed");
|
OSFatal("homebrew_wupsbackend: FunctionPatcher_InitLibrary failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NotificationModuleStatus res;
|
||||||
|
if ((res = NotificationModule_InitLibrary()) != NOTIFICATION_MODULE_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to init NotificationModule");
|
||||||
|
gNotificationModuleLoaded = false;
|
||||||
|
} else {
|
||||||
|
gNotificationModuleLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Patching functions");
|
DEBUG_FUNCTION_LINE("Patching functions");
|
||||||
for (uint32_t i = 0; i < method_hooks_static_size; i++) {
|
for (uint32_t i = 0; i < method_hooks_static_size; i++) {
|
||||||
if (FunctionPatcher_AddFunctionPatch(&method_hooks_static[i], nullptr, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
if (FunctionPatcher_AddFunctionPatch(&method_hooks_static[i], nullptr, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||||
@ -43,6 +54,7 @@ WUMS_APPLICATION_ENDS() {
|
|||||||
if (upid != 2 && upid != 15) {
|
if (upid != 2 && upid != 15) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_APPLICATION_ENDS);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_APPLICATION_ENDS);
|
||||||
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_SOCKETS);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_SOCKETS);
|
||||||
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB);
|
CallHook(gLoadedPlugins, WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB);
|
||||||
@ -52,6 +64,8 @@ WUMS_APPLICATION_ENDS() {
|
|||||||
}
|
}
|
||||||
gUsedRPLs.clear();
|
gUsedRPLs.clear();
|
||||||
|
|
||||||
|
StopNotificationThread();
|
||||||
|
|
||||||
deinitLogging();
|
deinitLogging();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +79,8 @@ WUMS_APPLICATION_STARTS() {
|
|||||||
|
|
||||||
OSReport("Running WiiUPluginLoaderBackend " VERSION_FULL "\n");
|
OSReport("Running WiiUPluginLoaderBackend " VERSION_FULL "\n");
|
||||||
|
|
||||||
|
StartNotificationThread();
|
||||||
|
|
||||||
gUsedRPLs.clear();
|
gUsedRPLs.clear();
|
||||||
|
|
||||||
// If an allocated rpl was not released properly (e.g. if something else calls OSDynload_Acquire without releasing it) memory get leaked.
|
// If an allocated rpl was not released properly (e.g. if something else calls OSDynload_Acquire without releasing it) memory get leaked.
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#include "PluginDataFactory.h"
|
#include "PluginDataFactory.h"
|
||||||
|
#include "NotificationsUtils.h"
|
||||||
#include "fs/FSUtils.h"
|
#include "fs/FSUtils.h"
|
||||||
#include "utils/StringTools.h"
|
#include "utils/StringTools.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
@ -54,7 +55,9 @@ std::forward_list<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(const
|
|||||||
if (pluginData) {
|
if (pluginData) {
|
||||||
result.push_front(std::move(pluginData.value()));
|
result.push_front(std::move(pluginData.value()));
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to load plugin: %s", full_file_path.c_str());
|
auto errMsg = string_format("Failed to load plugin: %s", full_file_path.c_str());
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("%s", errMsg.c_str());
|
||||||
|
DisplayErrorNotificationMessage(errMsg, 15.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#include "StorageUtils.h"
|
#include "StorageUtils.h"
|
||||||
|
#include "NotificationsUtils.h"
|
||||||
#include "StringTools.h"
|
#include "StringTools.h"
|
||||||
#include "fs/CFile.hpp"
|
#include "fs/CFile.hpp"
|
||||||
#include "fs/FSUtils.h"
|
#include "fs/FSUtils.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "utils/json.hpp"
|
#include "utils/json.hpp"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
|
#include <notifications/notifications.h>
|
||||||
|
|
||||||
static void processJson(wups_storage_item_t *items, nlohmann::json json) {
|
static void processJson(wups_storage_item_t *items, nlohmann::json json) {
|
||||||
if (items == nullptr) {
|
if (items == nullptr) {
|
||||||
@ -72,6 +74,8 @@ WUPSStorageError StorageUtils::OpenStorage(const char *plugin_id, wups_storage_i
|
|||||||
DEBUG_FUNCTION_LINE_ERR("%s", errorMessage.c_str());
|
DEBUG_FUNCTION_LINE_ERR("%s", errorMessage.c_str());
|
||||||
remove(filePath.c_str());
|
remove(filePath.c_str());
|
||||||
|
|
||||||
|
DisplayErrorNotificationMessage(errorMessage, 10.0f);
|
||||||
|
|
||||||
return WUPS_STORAGE_ERROR_SUCCESS;
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
} else { // empty or no config exists yet
|
} else { // empty or no config exists yet
|
||||||
|
Loading…
Reference in New Issue
Block a user