From eb12f209ceb438b7a704c22f331b23c0743cd6bd Mon Sep 17 00:00:00 2001 From: Maschell Date: Wed, 18 Dec 2024 16:11:14 +0100 Subject: [PATCH] Add ButtonComboAPI support --- Dockerfile | 3 +- Makefile | 5 +- source/PluginManagement.cpp | 1 + source/hooks.cpp | 32 + source/main.cpp | 16 +- source/plugin/ButtonComboManager.cpp | 575 ++++++++++++++++++ source/plugin/ButtonComboManager.h | 73 +++ source/plugin/PluginContainer.cpp | 61 +- source/plugin/PluginContainer.h | 12 +- source/plugin/PluginData.cpp | 11 +- source/plugin/PluginData.h | 1 + .../plugin/PluginMetaInformationFactory.cpp | 2 + source/utils/HeapMemoryFixedSize.cpp | 2 +- source/utils/buttoncombo/ButtonComboUtils.cpp | 200 ++++++ source/utils/buttoncombo/ButtonComboUtils.h | 65 ++ source/utils/config/ConfigUtils.cpp | 7 - source/utils/storage/StorageItem.cpp | 4 +- source/utils/storage/StorageItem.h | 3 + 18 files changed, 1028 insertions(+), 45 deletions(-) create mode 100644 source/plugin/ButtonComboManager.cpp create mode 100644 source/plugin/ButtonComboManager.h create mode 100644 source/utils/buttoncombo/ButtonComboUtils.cpp create mode 100644 source/utils/buttoncombo/ButtonComboUtils.h diff --git a/Dockerfile b/Dockerfile index c9d9c87..daa40b6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,11 @@ FROM ghcr.io/wiiu-env/devkitppc:20241128 COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20240424 /artifacts $DEVKITPRO -COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:0.8.2-dev-20241128-1ac579a /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:0.8.2-dev-20241226-f71cb8c /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/libwupsbackend:20240425 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libnotifications:20240426 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/libbuttoncombo:20241226-12d1594 /artifacts $DEVKITPRO WORKDIR project diff --git a/Makefile b/Makefile index 042b6fd..316f367 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,8 @@ SOURCES := source \ source/utils \ source/utils/config \ source/utils/storage \ - source/uitls/input + source/utils/buttoncombo \ + source/utils/input DATA := data INCLUDES := source @@ -58,7 +59,7 @@ CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g endif -LIBS := -lwums -lwups -lwut -lfunctionpatcher -lmappedmemory -lz -lnotifications +LIBS := -lwums -lwups -lwut -lfunctionpatcher -lmappedmemory -lz -lnotifications -lbuttoncombo #------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level diff --git a/source/PluginManagement.cpp b/source/PluginManagement.cpp index 2d22f67..dc8270b 100644 --- a/source/PluginManagement.cpp +++ b/source/PluginManagement.cpp @@ -186,6 +186,7 @@ bool PluginManagement::DoFunctionPatches(std::vector &plugins) } void PluginManagement::callInitHooks(const std::vector &plugins, const std::function &pred) { + CallHook(plugins, WUPS_LOADER_HOOK_INIT_BUTTON_COMBO, pred); CallHook(plugins, WUPS_LOADER_HOOK_INIT_CONFIG, pred); CallHook(plugins, WUPS_LOADER_HOOK_INIT_STORAGE_DEPRECATED, pred); CallHook(plugins, WUPS_LOADER_HOOK_INIT_STORAGE, pred); diff --git a/source/hooks.cpp b/source/hooks.cpp index 0925bf9..477d9af 100644 --- a/source/hooks.cpp +++ b/source/hooks.cpp @@ -1,10 +1,13 @@ #include "hooks.h" #include "plugin/PluginContainer.h" #include "utils/StorageUtilsDeprecated.h" +#include "utils/buttoncombo/ButtonComboUtils.h" #include "utils/logger.h" #include "utils/storage/StorageUtils.h" #include +#include +#include #include static const char **hook_names = (const char *[]){ @@ -126,6 +129,35 @@ void CallHook(const PluginContainer &plugin, wups_loader_hook_type_t hook_type) } break; } + case WUPS_LOADER_HOOK_INIT_BUTTON_COMBO: { + if (plugin.getMetaInformation().getWUPSVersion() <= WUPSVersion(0, 8, 1)) { + break; + } + wups_loader_init_button_combo_args_t args; + args.version = WUPS_BUTTON_COMBO_CUR_API_VERSION; + args.identifier = reinterpret_cast(plugin.getButtonComboManagerHandle()); + args.add_button_combo_function_ptr = &ButtonComboUtils::API::AddButtonCombo; + args.remove_button_combo_function_ptr = &ButtonComboUtils::API::RemoveButtonCombo; + args.get_button_combo_status_function_ptr = &ButtonComboUtils::API::GetButtonComboStatus; + args.update_button_combo_meta_function_ptr = &ButtonComboUtils::API::UpdateButtonComboMeta; + args.update_button_combo_callback_function_ptr = &ButtonComboUtils::API::UpdateButtonComboCallback; + args.update_controller_mask_function_ptr = &ButtonComboUtils::API::UpdateControllerMask; + args.update_button_combo_function_ptr = &ButtonComboUtils::API::UpdateButtonCombo; + args.update_hold_duration_function_ptr = &ButtonComboUtils::API::UpdateHoldDuration; + args.get_button_combo_meta_function_ptr = &ButtonComboUtils::API::GetButtonComboMeta; + args.get_button_combo_callback_function_ptr = &ButtonComboUtils::API::GetButtonComboCallback; + args.get_button_combo_info_ex_function_ptr = &ButtonComboUtils::API::GetButtonComboInfoEx; + args.check_button_combo_available_function_ptr = &ButtonComboUtils::API::CheckComboAvailable; + args.detect_button_combo_blocking_function_ptr = &ButtonComboUtils::API::DetectButtonCombo_Blocking; + + auto res = ((WUPSButtonCombo_Error(*)(wups_loader_init_button_combo_args_t))((uint32_t *) func_ptr))(args); + // clang-format on + if (res != WUPS_BUTTON_COMBO_ERROR_SUCCESS) { + // TODO: More error handling? Notification? + DEBUG_FUNCTION_LINE_ERR("WUPS_LOADER_HOOK_INIT_BUTTON_COMBO failed for plugin %s: %s", plugin.getMetaInformation().getName().c_str(), WUPSButtonComboAPI_GetStatusStr(res)); + } + break; + } default: { DEBUG_FUNCTION_LINE_ERR("######################################"); DEBUG_FUNCTION_LINE_ERR("Hook is not implemented %s [%d]", hook_names[hook_type], hook_type); diff --git a/source/main.cpp b/source/main.cpp index addae80..bdda1b0 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -12,6 +12,7 @@ #include "utils/utils.h" #include "version.h" +#include #include #include #include @@ -32,6 +33,10 @@ WUMS_INITIALIZE() { OSFatal("homebrew_wupsbackend: FunctionPatcher_InitLibrary failed"); } + if (ButtonComboModule_InitLibrary() != BUTTON_COMBO_MODULE_ERROR_SUCCESS) { + OSFatal("homebrew_wupsbackend: ButtonComboModule_InitLibrary failed"); + } + if (const NotificationModuleStatus res = NotificationModule_InitLibrary(); res != NOTIFICATION_MODULE_RESULT_SUCCESS) { DEBUG_FUNCTION_LINE_ERR("Failed to init NotificationModule: %s (%d)", NotificationModule_GetStatusStr(res), res); gNotificationModuleLoaded = false; @@ -207,14 +212,6 @@ WUMS_APPLICATION_STARTS() { std::vector pluginsToDeinit = std::move(gLoadedPlugins); gLoadedPlugins = std::move(pluginsToKeep); - for (const auto &p : pluginsToKeep) { - DEBUG_FUNCTION_LINE_INFO("KEEP: %s", p.getMetaInformation().getName().c_str()); - } - - for (const auto &p : pluginsToDeinit) { - DEBUG_FUNCTION_LINE_ERR("DEINIT: %s", p.getMetaInformation().getName().c_str()); - } - DEBUG_FUNCTION_LINE("Deinit unused plugins"); CleanupPlugins(std::move(pluginsToDeinit)); @@ -255,6 +252,7 @@ WUMS_APPLICATION_STARTS() { if (const WUPSStorageError err = plugin.OpenStorage(); err != WUPS_STORAGE_ERROR_SUCCESS) { DEBUG_FUNCTION_LINE_ERR("Failed to open storage for plugin: %s. (%s)", plugin.getMetaInformation().getName().c_str(), WUPSStorageAPI_GetStatusStr(err)); } + plugin.InitButtonComboData(); } PluginManagement::callInitHooks(gLoadedPlugins, needsInitsCheck); @@ -287,9 +285,11 @@ void CleanupPlugins(std::vector &&pluginsToDeinit) { PluginManagement::RestoreFunctionPatches(pluginsToDeinit); for (auto &plugin : pluginsToDeinit) { + if (!plugin.isInitDone()) { continue; } if (const WUPSStorageError err = plugin.CloseStorage(); err != WUPS_STORAGE_ERROR_SUCCESS) { DEBUG_FUNCTION_LINE_ERR("Failed to close storage for plugin: %s", plugin.getMetaInformation().getName().c_str()); } + plugin.DeinitButtonComboData(); } for (const auto &pluginContainer : pluginsToDeinit) { diff --git a/source/plugin/ButtonComboManager.cpp b/source/plugin/ButtonComboManager.cpp new file mode 100644 index 0000000..6fd4f14 --- /dev/null +++ b/source/plugin/ButtonComboManager.cpp @@ -0,0 +1,575 @@ +#include "ButtonComboManager.h" +#include +#include +#include +#include + +namespace { + WUPSButtonCombo_Error convertError(const ButtonComboModule_Error other) { + switch (other) { + case BUTTON_COMBO_MODULE_ERROR_SUCCESS: + return WUPS_BUTTON_COMBO_ERROR_SUCCESS; + case BUTTON_COMBO_MODULE_ERROR_INVALID_ARGUMENT: + case BUTTON_COMBO_MODULE_ERROR_INVALID_COMBO: + case BUTTON_COMBO_MODULE_ERROR_INVALID_COMBO_TYPE: + case BUTTON_COMBO_MODULE_ERROR_DURATION_MISSING: + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + case BUTTON_COMBO_MODULE_ERROR_INCOMPATIBLE_OPTIONS_VERSION: + case BUTTON_COMBO_MODULE_ERROR_MODULE_NOT_FOUND: + case BUTTON_COMBO_MODULE_ERROR_MODULE_MISSING_EXPORT: + case BUTTON_COMBO_MODULE_ERROR_UNSUPPORTED_API_VERSION: + case BUTTON_COMBO_MODULE_ERROR_UNSUPPORTED_COMMAND: + case BUTTON_COMBO_MODULE_ERROR_LIB_UNINITIALIZED: + return WUPS_BUTTON_COMBO_ERROR_INTERNAL_INVALID_VERSION; + case BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR: + break; + case BUTTON_COMBO_MODULE_ERROR_HANDLE_NOT_FOUND: + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + case BUTTON_COMBO_MODULE_ERROR_ABORTED: + return WUPS_BUTTON_COMBO_ERROR_ABORTED; + } + return WUPS_BUTTON_COMBO_ERROR_UNKNOWN_ERROR; + } + + ButtonComboModule_ControllerTypes convert(const WUPSButtonCombo_ControllerTypes other) { + ButtonComboModule_ControllerTypes res = BUTTON_COMBO_MODULE_CONTROLLER_NONE; + if (other & WUPS_BUTTON_COMBO_CONTROLLER_VPAD_0) { + res |= BUTTON_COMBO_MODULE_CONTROLLER_VPAD_0; + } + if (other & WUPS_BUTTON_COMBO_CONTROLLER_VPAD_1) { + res |= BUTTON_COMBO_MODULE_CONTROLLER_VPAD_1; + } + if (other & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_0) { + res |= BUTTON_COMBO_MODULE_CONTROLLER_WPAD_0; + } + if (other & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_1) { + res |= BUTTON_COMBO_MODULE_CONTROLLER_WPAD_1; + } + if (other & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_2) { + res |= BUTTON_COMBO_MODULE_CONTROLLER_WPAD_2; + } + if (other & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_3) { + res |= BUTTON_COMBO_MODULE_CONTROLLER_WPAD_3; + } + if (other & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_4) { + res |= BUTTON_COMBO_MODULE_CONTROLLER_WPAD_4; + } + if (other & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_5) { + res |= BUTTON_COMBO_MODULE_CONTROLLER_WPAD_5; + } + if (other & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_6) { + res |= BUTTON_COMBO_MODULE_CONTROLLER_WPAD_6; + } + return res; + } + + WUPSButtonCombo_ControllerTypes convert(const ButtonComboModule_ControllerTypes other) { + WUPSButtonCombo_ControllerTypes res = WUPS_BUTTON_COMBO_CONTROLLER_NONE; + if (other & BUTTON_COMBO_MODULE_CONTROLLER_VPAD_0) { + res |= WUPS_BUTTON_COMBO_CONTROLLER_VPAD_0; + } + if (other & BUTTON_COMBO_MODULE_CONTROLLER_VPAD_1) { + res |= WUPS_BUTTON_COMBO_CONTROLLER_VPAD_1; + } + if (other & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_0) { + res |= WUPS_BUTTON_COMBO_CONTROLLER_WPAD_0; + } + if (other & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_1) { + res |= WUPS_BUTTON_COMBO_CONTROLLER_WPAD_1; + } + if (other & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_2) { + res |= WUPS_BUTTON_COMBO_CONTROLLER_WPAD_2; + } + if (other & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_3) { + res |= WUPS_BUTTON_COMBO_CONTROLLER_WPAD_3; + } + if (other & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_4) { + res |= WUPS_BUTTON_COMBO_CONTROLLER_WPAD_4; + } + if (other & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_5) { + res |= WUPS_BUTTON_COMBO_CONTROLLER_WPAD_5; + } + if (other & BUTTON_COMBO_MODULE_CONTROLLER_WPAD_6) { + res |= WUPS_BUTTON_COMBO_CONTROLLER_WPAD_6; + } + return res; + } + + ButtonComboModule_Buttons convert(const WUPSButtonCombo_Buttons other) { + uint32_t res = 0; + if (other & WUPS_BUTTON_COMBO_BUTTON_A) { + res |= BCMPAD_BUTTON_A; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_B) { + res |= BCMPAD_BUTTON_B; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_X) { + res |= BCMPAD_BUTTON_X; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_Y) { + res |= BCMPAD_BUTTON_Y; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_LEFT) { + res |= BCMPAD_BUTTON_LEFT; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_RIGHT) { + res |= BCMPAD_BUTTON_RIGHT; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_UP) { + res |= BCMPAD_BUTTON_UP; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_DOWN) { + res |= BCMPAD_BUTTON_DOWN; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_ZL) { + res |= BCMPAD_BUTTON_ZL; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_ZR) { + res |= BCMPAD_BUTTON_ZR; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_L) { + res |= BCMPAD_BUTTON_L; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_R) { + res |= BCMPAD_BUTTON_R; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_PLUS) { + res |= BCMPAD_BUTTON_PLUS; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_MINUS) { + res |= BCMPAD_BUTTON_MINUS; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_STICK_R) { + res |= BCMPAD_BUTTON_STICK_R; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_STICK_L) { + res |= BCMPAD_BUTTON_STICK_L; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_TV) { + res |= BCMPAD_BUTTON_TV; + } + if (other & WUPS_BUTTON_COMBO_BUTTON_RESERVED_BIT) { + res |= BCMPAD_BUTTON_RESERVED_BIT; + } + return static_cast(res); + } + + WUPSButtonCombo_Buttons convert(const ButtonComboModule_Buttons other) { + uint32_t res = 0; + if (other & BCMPAD_BUTTON_A) { + res |= WUPS_BUTTON_COMBO_BUTTON_A; + } + if (other & BCMPAD_BUTTON_B) { + res |= WUPS_BUTTON_COMBO_BUTTON_B; + } + if (other & BCMPAD_BUTTON_X) { + res |= WUPS_BUTTON_COMBO_BUTTON_B; + } + if (other & BCMPAD_BUTTON_Y) { + res |= WUPS_BUTTON_COMBO_BUTTON_B; + } + if (other & BCMPAD_BUTTON_LEFT) { + res |= WUPS_BUTTON_COMBO_BUTTON_LEFT; + } + if (other & BCMPAD_BUTTON_RIGHT) { + res |= WUPS_BUTTON_COMBO_BUTTON_RIGHT; + } + if (other & BCMPAD_BUTTON_UP) { + res |= WUPS_BUTTON_COMBO_BUTTON_UP; + } + if (other & BCMPAD_BUTTON_DOWN) { + res |= WUPS_BUTTON_COMBO_BUTTON_DOWN; + } + if (other & BCMPAD_BUTTON_ZL) { + res |= WUPS_BUTTON_COMBO_BUTTON_ZL; + } + if (other & BCMPAD_BUTTON_ZR) { + res |= WUPS_BUTTON_COMBO_BUTTON_ZR; + } + if (other & BCMPAD_BUTTON_L) { + res |= WUPS_BUTTON_COMBO_BUTTON_L; + } + if (other & BCMPAD_BUTTON_R) { + res |= WUPS_BUTTON_COMBO_BUTTON_R; + } + if (other & BCMPAD_BUTTON_PLUS) { + res |= WUPS_BUTTON_COMBO_BUTTON_PLUS; + } + if (other & BCMPAD_BUTTON_MINUS) { + res |= WUPS_BUTTON_COMBO_BUTTON_MINUS; + } + if (other & BCMPAD_BUTTON_STICK_R) { + res |= WUPS_BUTTON_COMBO_BUTTON_STICK_R; + } + if (other & BCMPAD_BUTTON_STICK_L) { + res |= WUPS_BUTTON_COMBO_BUTTON_STICK_L; + } + if (other & BCMPAD_BUTTON_TV) { + res |= WUPS_BUTTON_COMBO_BUTTON_TV; + } + if (other & BCMPAD_BUTTON_RESERVED_BIT) { + res |= WUPS_BUTTON_COMBO_BUTTON_RESERVED_BIT; + } + return static_cast(res); + } + + ButtonComboModule_ComboType convertType(const WUPSButtonCombo_ComboType other) { + switch (other) { + case WUPS_BUTTON_COMBO_COMBO_TYPE_INVALID: + return BUTTON_COMBO_MODULE_TYPE_INVALID; + case WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD: + return BUTTON_COMBO_MODULE_TYPE_HOLD; + case WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN: + return BUTTON_COMBO_MODULE_TYPE_PRESS_DOWN; + case WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD_OBSERVER: + return BUTTON_COMBO_MODULE_TYPE_HOLD_OBSERVER; + case WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN_OBSERVER: + return BUTTON_COMBO_MODULE_TYPE_PRESS_DOWN_OBSERVER; + } + return BUTTON_COMBO_MODULE_TYPE_INVALID; + } + + WUPSButtonCombo_ComboType convertType(const ButtonComboModule_ComboType other) { + switch (other) { + case BUTTON_COMBO_MODULE_TYPE_INVALID: + return WUPS_BUTTON_COMBO_COMBO_TYPE_INVALID; + case BUTTON_COMBO_MODULE_TYPE_HOLD: + return WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD; + case BUTTON_COMBO_MODULE_TYPE_PRESS_DOWN: + return WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN; + case BUTTON_COMBO_MODULE_TYPE_HOLD_OBSERVER: + return WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD_OBSERVER; + case BUTTON_COMBO_MODULE_TYPE_PRESS_DOWN_OBSERVER: + return WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN_OBSERVER; + } + return WUPS_BUTTON_COMBO_COMBO_TYPE_INVALID; + } + + WUPSButtonCombo_ComboStatus convertStatus(const ButtonComboModule_ComboStatus other) { + switch (other) { + case BUTTON_COMBO_MODULE_COMBO_STATUS_INVALID_STATUS: + return WUPS_BUTTON_COMBO_COMBO_STATUS_INVALID_STATUS; + case BUTTON_COMBO_MODULE_COMBO_STATUS_VALID: + return WUPS_BUTTON_COMBO_COMBO_STATUS_VALID; + case BUTTON_COMBO_MODULE_COMBO_STATUS_CONFLICT: + return WUPS_BUTTON_COMBO_COMBO_STATUS_CONFLICT; + } + return WUPS_BUTTON_COMBO_COMBO_STATUS_INVALID_STATUS; + } + + ButtonComboModule_MetaOptions convert(const WUPSButtonCombo_MetaOptions &other) { + ButtonComboModule_MetaOptions options; + options.label = other.label; + return options; + } + + ButtonComboModule_ButtonComboInfoEx convert(const WUPSButtonCombo_ButtonComboInfoEx &other) { + ButtonComboModule_ButtonComboInfoEx options; + options.basicCombo.combo = convert(other.basicCombo.combo); + options.basicCombo.controllerMask = convert(other.basicCombo.controllerMask); + options.type = convertType(other.type); + options.optionalHoldForXFrames = other.optionalHoldForXFrames; + return options; + } + + WUPSButtonCombo_ButtonComboInfoEx convert(const ButtonComboModule_ButtonComboInfoEx &other) { + WUPSButtonCombo_ButtonComboInfoEx options; + options.type = convertType(other.type); + options.basicCombo.combo = convert(other.basicCombo.combo); + options.basicCombo.controllerMask = convert(other.basicCombo.controllerMask); + options.optionalHoldForXFrames = other.optionalHoldForXFrames; + return options; + } + + ButtonComboModule_ButtonComboOptions convert(const WUPSButtonCombo_ButtonComboOptions &other) { + ButtonComboModule_ButtonComboOptions options; + options.combo = convert(other.combo); + options.controllerMask = convert(other.controllerMask); + return options; + } + + ButtonComboModule_DetectButtonComboOptions convert(const WUPSButtonCombo_DetectButtonComboOptions &other) { + ButtonComboModule_DetectButtonComboOptions options; + options.controllerMask = convert(other.controllerMask); + options.abortButtonCombo = convert(other.abortButtonCombo); + options.holdAbortForInMs = other.holdAbortForInMs; + options.holdComboForInMs = other.holdComboForInMs; + return options; + } + + struct ComboCallbackWrapperData { + WUPSButtonCombo_ComboCallback callback = nullptr; + void *context = nullptr; + }; + + void ButtonComboCallbackWrapper(const ButtonComboModule_ComboHandle handle, void *context) { + const auto *data = static_cast(context); + data->callback(WUPSButtonCombo_ComboHandle(handle.handle), data->context); + } +} // namespace + +class ButtonComboWrapper { +public: + ButtonComboWrapper(const WUPSButtonCombo_ComboOptions &otherOptions, WUPSButtonCombo_ComboStatus &outStatus) { + // Abuse this as a stable handle that references itself and survives std::move + *mHandle = reinterpret_cast(mHandle.get()); + + ButtonComboModule_ComboStatus status = BUTTON_COMBO_MODULE_COMBO_STATUS_INVALID_STATUS; + mContextData = std::make_unique(otherOptions.callbackOptions.callback, otherOptions.callbackOptions.context); + ButtonComboModule_ComboOptions convertedOptions; + convertedOptions.version = BUTTON_COMBO_MODULE_COMBO_OPTIONS_VERSION; + convertedOptions.metaOptions = convert(otherOptions.metaOptions); + convertedOptions.callbackOptions = {.callback = ButtonComboCallbackWrapper, .context = mContextData.get()}; + convertedOptions.buttonComboOptions = convert(otherOptions.buttonComboOptions); + mCreationError = ButtonComboModule_AddButtonCombo(&convertedOptions, &mButtonComboHandle, &status); + outStatus = convertStatus(status); + } + + ~ButtonComboWrapper() { + if (mButtonComboHandle != nullptr) { + if (const auto res = ButtonComboModule_RemoveButtonCombo(mButtonComboHandle); res != BUTTON_COMBO_MODULE_ERROR_SUCCESS) { + DEBUG_FUNCTION_LINE_WARN("ButtonComboModule_RemoveButtonCombo for %08X returned: %s", mButtonComboHandle, ButtonComboModule_GetStatusStr(res)); + } + } + } + + ButtonComboWrapper(const ButtonComboWrapper &) = delete; + + ButtonComboWrapper(ButtonComboWrapper &&src) noexcept : mCreationError(src.mCreationError), + mButtonComboHandle(src.mButtonComboHandle), + mContextData(std::move(src.mContextData)), + mHandle(std::move(src.mHandle)) { + this->mCreationError = BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; + this->mButtonComboHandle = ButtonComboModule_ComboHandle(nullptr); + } + + ButtonComboWrapper &operator=(ButtonComboWrapper &&src) noexcept { + if (this != &src) { + this->mCreationError = src.mCreationError; + this->mButtonComboHandle = src.mButtonComboHandle; + this->mContextData = std::move(src.mContextData); + this->mHandle = std::move(src.mHandle); + + this->mCreationError = BUTTON_COMBO_MODULE_ERROR_UNKNOWN_ERROR; + this->mButtonComboHandle = ButtonComboModule_ComboHandle(nullptr); + } + return *this; + } + + [[nodiscard]] WUPSButtonCombo_ComboHandle getHandle() const { + return WUPSButtonCombo_ComboHandle(reinterpret_cast(*mHandle)); + } + + WUPSButtonCombo_Error GetButtonComboStatus(WUPSButtonCombo_ComboStatus &outStatus) const { + ButtonComboModule_ComboStatus status = BUTTON_COMBO_MODULE_COMBO_STATUS_INVALID_STATUS; + const auto res = ButtonComboModule_GetButtonComboStatus(mButtonComboHandle, &status); + if (res == BUTTON_COMBO_MODULE_ERROR_SUCCESS) { + outStatus = convertStatus(status); + } + return convertError(res); + } + + [[nodiscard]] WUPSButtonCombo_Error UpdateButtonComboMeta(const WUPSButtonCombo_MetaOptions &metaOptions) const { + const auto convertedOptions = convert(metaOptions); + return convertError(ButtonComboModule_UpdateButtonComboMeta(mButtonComboHandle, &convertedOptions)); + } + + [[nodiscard]] WUPSButtonCombo_Error UpdateButtonComboCallback(const WUPSButtonCombo_CallbackOptions &callbackOptions) const { + mContextData->callback = callbackOptions.callback; + mContextData->context = callbackOptions.context; + return WUPS_BUTTON_COMBO_ERROR_SUCCESS; + } + + [[nodiscard]] WUPSButtonCombo_Error UpdateControllerMask(const WUPSButtonCombo_ControllerTypes controllerMask, + WUPSButtonCombo_ComboStatus &outStatus) const { + ButtonComboModule_ComboStatus comboStatus = BUTTON_COMBO_MODULE_COMBO_STATUS_INVALID_STATUS; + const auto res = convertError(ButtonComboModule_UpdateControllerMask(mButtonComboHandle, convert(controllerMask), &comboStatus)); + outStatus = convertStatus(comboStatus); + return res; + } + + [[nodiscard]] WUPSButtonCombo_Error UpdateButtonCombo(const WUPSButtonCombo_Buttons combo, + WUPSButtonCombo_ComboStatus &outStatus) const { + ButtonComboModule_ComboStatus comboStatus = BUTTON_COMBO_MODULE_COMBO_STATUS_INVALID_STATUS; + const auto res = convertError(ButtonComboModule_UpdateButtonCombo(mButtonComboHandle, convert(combo), &comboStatus)); + outStatus = convertStatus(comboStatus); + return res; + } + + [[nodiscard]] WUPSButtonCombo_Error UpdateHoldDuration(const uint32_t holdDurationInFrames) const { + return convertError(ButtonComboModule_UpdateHoldDuration(mButtonComboHandle, holdDurationInFrames)); + } + + [[nodiscard]] WUPSButtonCombo_Error GetButtonComboMeta(WUPSButtonCombo_MetaOptionsOut &outOptions) const { + ButtonComboModule_MetaOptionsOut options = {.labelBuffer = outOptions.labelBuffer, .labelBufferLength = outOptions.labelBufferLength}; + return convertError(ButtonComboModule_GetButtonComboMeta(mButtonComboHandle, &options)); + } + + WUPSButtonCombo_Error GetButtonComboCallback(WUPSButtonCombo_CallbackOptions &outOptions) const { + outOptions.callback = mContextData->callback; + outOptions.context = mContextData->context; + + return WUPS_BUTTON_COMBO_ERROR_SUCCESS; + } + + WUPSButtonCombo_Error GetButtonComboInfoEx(WUPSButtonCombo_ButtonComboInfoEx &outOptions) const { + ButtonComboModule_ButtonComboInfoEx tmpOptions; + const auto res = convertError(ButtonComboModule_GetButtonComboInfoEx(mButtonComboHandle, &tmpOptions)); + outOptions = convert(tmpOptions); + return res; + } + + WUPSButtonCombo_Error GetCreationError() const { + return convertError(mCreationError); + } + +private: + ButtonComboModule_Error mCreationError; + ButtonComboModule_ComboHandle mButtonComboHandle; + std::unique_ptr mContextData; + std::unique_ptr mHandle = std::make_unique(); +}; + +ButtonComboManager::ButtonComboManager() { + // Abuse this as a stable handle that references itself and survives std::move + *mHandle = reinterpret_cast(mHandle.get()); +} + +ButtonComboManager::~ButtonComboManager() = default; + +ButtonComboManager::ButtonComboManager(ButtonComboManager &&src) : mComboWrappers(std::move(src.mComboWrappers)), mHandle(std::move(src.mHandle)) { +} + +ButtonComboManager &ButtonComboManager::operator=(ButtonComboManager &&src) { + if (this != &src) { + this->mHandle = std::move(src.mHandle); + this->mComboWrappers = std::move(src.mComboWrappers); + } + return *this; +} + +WUPSButtonCombo_Error ButtonComboManager::AddButtonComboHandle(const WUPSButtonCombo_ComboOptions &options, + WUPSButtonCombo_ComboHandle &outHandle, + WUPSButtonCombo_ComboStatus &outStatus) { + mComboWrappers.emplace_back(options, outStatus); + const auto &addedItem = mComboWrappers.back(); + const auto handle = addedItem.getHandle(); + if (const auto res = addedItem.GetCreationError(); res != WUPS_BUTTON_COMBO_ERROR_SUCCESS) { + if (!remove_first_if(mComboWrappers, [&handle](const auto &comboWrapper) { return comboWrapper.getHandle() == handle; })) { + DEBUG_FUNCTION_LINE_INFO("Failed to re removed from mComboWrappers"); + } + return res; + } + + outHandle = handle; + + return WUPS_BUTTON_COMBO_ERROR_SUCCESS; +} + +WUPSButtonCombo_Error ButtonComboManager::RemoveButtonCombo(const WUPSButtonCombo_ComboHandle handle) { + if (remove_first_if(mComboWrappers, [&handle](const auto &comboWrapper) { return comboWrapper.getHandle() == handle; })) { + // Destructor removes it from the button combo module + return WUPS_BUTTON_COMBO_ERROR_SUCCESS; + } + DEBUG_FUNCTION_LINE_WARN("Could not remove button combo: not found! %08X", handle); + + return WUPS_BUTTON_COMBO_ERROR_NOT_FOUND; +} + +WUPSButtonCombo_Error ButtonComboManager::GetButtonComboStatus(const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ComboStatus &outStatus) { + return ExecuteForWrapper(handle, [&](const ButtonComboWrapper &wrapper) { + return wrapper.GetButtonComboStatus(outStatus); + }); +} + +WUPSButtonCombo_Error ButtonComboManager::UpdateButtonComboMeta(const WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_MetaOptions &metaOptions) { + return ExecuteForWrapper(handle, [&](const ButtonComboWrapper &wrapper) { + return wrapper.UpdateButtonComboMeta(metaOptions); + }); +} + +WUPSButtonCombo_Error ButtonComboManager::UpdateButtonComboCallback(const WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_CallbackOptions &callbackOptions) { + return ExecuteForWrapper(handle, [&](const ButtonComboWrapper &wrapper) { + return wrapper.UpdateButtonComboCallback(callbackOptions); + }); +} + +WUPSButtonCombo_Error ButtonComboManager::UpdateControllerMask(const WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_ControllerTypes controllerMask, + WUPSButtonCombo_ComboStatus &outStatus) { + return ExecuteForWrapper(handle, [&](const ButtonComboWrapper &wrapper) { + return wrapper.UpdateControllerMask(controllerMask, outStatus); + }); +} + +WUPSButtonCombo_Error ButtonComboManager::UpdateButtonCombo(const WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_Buttons combo, + WUPSButtonCombo_ComboStatus &outStatus) { + return ExecuteForWrapper(handle, [&](const ButtonComboWrapper &wrapper) { + return wrapper.UpdateButtonCombo(combo, outStatus); + }); +} + +WUPSButtonCombo_Error ButtonComboManager::UpdateHoldDuration(const WUPSButtonCombo_ComboHandle handle, + const uint32_t holdDurationInFrames) { + return ExecuteForWrapper(handle, [&](const ButtonComboWrapper &wrapper) { + return wrapper.UpdateHoldDuration(holdDurationInFrames); + }); +} + +WUPSButtonCombo_Error ButtonComboManager::GetButtonComboMeta(const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_MetaOptionsOut &outOptions) { + return ExecuteForWrapper(handle, [&](const ButtonComboWrapper &wrapper) { + return wrapper.GetButtonComboMeta(outOptions); + }); +} + +WUPSButtonCombo_Error ButtonComboManager::GetButtonComboCallback(const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_CallbackOptions &outOptions) { + return ExecuteForWrapper(handle, [&](const ButtonComboWrapper &wrapper) { + return wrapper.GetButtonComboCallback(outOptions); + }); +} + +WUPSButtonCombo_Error ButtonComboManager::GetButtonComboInfoEx(const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ButtonComboInfoEx &outOptions) { + return ExecuteForWrapper(handle, [&](const ButtonComboWrapper &wrapper) { + return wrapper.GetButtonComboInfoEx(outOptions); + }); +} + +WUPSButtonCombo_Error ButtonComboManager::CheckComboAvailable(const WUPSButtonCombo_ButtonComboOptions &options, + WUPSButtonCombo_ComboStatus &outStatus) { + const auto convertedOptions = convert(options); + ButtonComboModule_ComboStatus status = BUTTON_COMBO_MODULE_COMBO_STATUS_INVALID_STATUS; + const auto res = convertError(ButtonComboModule_CheckComboAvailable(&convertedOptions, &status)); + outStatus = convertStatus(status); + return res; +} + +WUPSButtonCombo_Error ButtonComboManager::DetectButtonCombo_Blocking(const WUPSButtonCombo_DetectButtonComboOptions &options, WUPSButtonCombo_Buttons &outButtonCombo) { + const auto convertedOptions = convert(options); + auto combo = static_cast(0); + const auto res = convertError(ButtonComboModule_DetectButtonCombo_Blocking(&convertedOptions, &combo)); + outButtonCombo = convert(combo); + return res; +} + +WUPSButtonCombo_Error ButtonComboManager::ExecuteForWrapper(const WUPSButtonCombo_ComboHandle &handle, const std::function &callback) { + if (handle == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + for (auto &wrapper : mComboWrappers) { + if (wrapper.getHandle() == handle) { + return callback(wrapper); + } + } + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; +} + +uint32_t ButtonComboManager::getHandle() const { + return *mHandle; +} \ No newline at end of file diff --git a/source/plugin/ButtonComboManager.h b/source/plugin/ButtonComboManager.h new file mode 100644 index 0000000..f700017 --- /dev/null +++ b/source/plugin/ButtonComboManager.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + + +class ButtonComboWrapper; + +class ButtonComboManager { +public: + explicit ButtonComboManager(); + ~ButtonComboManager(); + + + ButtonComboManager(const ButtonComboManager &) = delete; + + ButtonComboManager(ButtonComboManager &&src) noexcept; + + ButtonComboManager &operator=(ButtonComboManager &&src) noexcept; + + WUPSButtonCombo_Error AddButtonComboHandle(const WUPSButtonCombo_ComboOptions &options, + WUPSButtonCombo_ComboHandle &outHandle, + WUPSButtonCombo_ComboStatus &outStatus); + + WUPSButtonCombo_Error RemoveButtonCombo(WUPSButtonCombo_ComboHandle handle); + + WUPSButtonCombo_Error GetButtonComboStatus(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ComboStatus &outStatus); + + WUPSButtonCombo_Error UpdateButtonComboMeta(WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_MetaOptions &metaOptions); + + WUPSButtonCombo_Error UpdateButtonComboCallback(WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_CallbackOptions &callbackOptions); + + WUPSButtonCombo_Error UpdateControllerMask(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ControllerTypes controllerMask, + WUPSButtonCombo_ComboStatus &outStatus); + + WUPSButtonCombo_Error UpdateButtonCombo(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_Buttons combo, + WUPSButtonCombo_ComboStatus &outStatus); + + WUPSButtonCombo_Error UpdateHoldDuration(WUPSButtonCombo_ComboHandle handle, + uint32_t holdDurationInFrames); + + WUPSButtonCombo_Error GetButtonComboMeta(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_MetaOptionsOut &outOptions); + + WUPSButtonCombo_Error GetButtonComboCallback(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_CallbackOptions &outOptions); + + WUPSButtonCombo_Error GetButtonComboInfoEx(WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ButtonComboInfoEx &outOptions); + + WUPSButtonCombo_Error CheckComboAvailable(const WUPSButtonCombo_ButtonComboOptions &options, + WUPSButtonCombo_ComboStatus &outStatus); + + WUPSButtonCombo_Error DetectButtonCombo_Blocking(const WUPSButtonCombo_DetectButtonComboOptions &options, + WUPSButtonCombo_Buttons &outButtonCombo); + + WUPSButtonCombo_Error ExecuteForWrapper(const WUPSButtonCombo_ComboHandle &handle, const std::function &callback); + + [[nodiscard]] uint32_t getHandle() const; + +private: + std::vector mComboWrappers; + std::unique_ptr mHandle = std::make_unique(); +}; diff --git a/source/plugin/PluginContainer.cpp b/source/plugin/PluginContainer.cpp index f88e154..0f926b3 100644 --- a/source/plugin/PluginContainer.cpp +++ b/source/plugin/PluginContainer.cpp @@ -1,36 +1,43 @@ #include "PluginContainer.h" #include "utils/storage/StorageUtils.h" +#include + PluginContainer::PluginContainer(PluginMetaInformation metaInformation, PluginLinkInformation pluginLinkInformation, std::shared_ptr pluginData) : mMetaInformation(std::move(metaInformation)), mPluginLinkInformation(std::move(pluginLinkInformation)), mPluginData(std::move(pluginData)) { + // Abuse this as a stable handle that references itself and survives std::move + *mHandle = reinterpret_cast(mHandle.get()); } - -PluginContainer::PluginContainer(PluginContainer &&src) : mMetaInformation(std::move(src.mMetaInformation)), - mPluginLinkInformation(std::move(src.mPluginLinkInformation)), - mPluginData(std::move(src.mPluginData)), - mPluginConfigData(std::move(src.mPluginConfigData)), - mStorageRootItem(src.mStorageRootItem), - mInitDone(src.mInitDone) - -{ +PluginContainer::PluginContainer(PluginContainer &&src) noexcept : mMetaInformation(std::move(src.mMetaInformation)), + mPluginLinkInformation(std::move(src.mPluginLinkInformation)), + mPluginData(std::move(src.mPluginData)), + mHandle(std::move(src.mHandle)), + mPluginConfigData(std::move(src.mPluginConfigData)), + mStorageRootItem(src.mStorageRootItem), + mInitDone(src.mInitDone), + mButtonComboManagerHandle(src.mButtonComboManagerHandle) { + src.mHandle = {}; src.mStorageRootItem = {}; src.mInitDone = {}; } PluginContainer &PluginContainer::operator=(PluginContainer &&src) noexcept { if (this != &src) { - this->mMetaInformation = std::move(src.mMetaInformation); - this->mPluginLinkInformation = std::move(src.mPluginLinkInformation); - this->mPluginData = std::move(src.mPluginData); - this->mPluginConfigData = std::move(src.mPluginConfigData); - this->mStorageRootItem = src.mStorageRootItem; - this->mInitDone = src.mInitDone; + this->mMetaInformation = std::move(src.mMetaInformation); + this->mPluginLinkInformation = std::move(src.mPluginLinkInformation); + this->mPluginData = std::move(src.mPluginData); + this->mPluginConfigData = std::move(src.mPluginConfigData); + this->mHandle = std::move(src.mHandle); + this->mStorageRootItem = src.mStorageRootItem; + this->mInitDone = src.mInitDone; + this->mButtonComboManagerHandle = src.mButtonComboManagerHandle; - src.mStorageRootItem = nullptr; - src.mInitDone = false; + src.mStorageRootItem = nullptr; + src.mInitDone = false; + src.mButtonComboManagerHandle = false; } return *this; } @@ -39,7 +46,6 @@ const PluginMetaInformation &PluginContainer::getMetaInformation() const { return this->mMetaInformation; } - const PluginLinkInformation &PluginContainer::getPluginLinkInformation() const { return this->mPluginLinkInformation; } @@ -53,7 +59,7 @@ std::shared_ptr PluginContainer::getPluginDataCopy() const { } uint32_t PluginContainer::getHandle() const { - return reinterpret_cast(this); + return *mHandle; } const std::optional &PluginContainer::getConfigData() const { @@ -104,4 +110,21 @@ void PluginContainer::setInitDone(const bool val) { bool PluginContainer::isInitDone() const { return mInitDone; +} + +void PluginContainer::InitButtonComboData() { + if (getMetaInformation().getWUPSVersion() < WUPSVersion(0, 8, 2)) { + return; + } + mButtonComboManagerHandle = ButtonComboUtils::API::Internal::CreateButtonComboData(); +} +void PluginContainer::DeinitButtonComboData() { + if (getMetaInformation().getWUPSVersion() < WUPSVersion(0, 8, 2)) { + return; + } + ButtonComboUtils::API::Internal::RemoveButtonComboData(mButtonComboManagerHandle); +} + +uint32_t PluginContainer::getButtonComboManagerHandle() const { + return mButtonComboManagerHandle; } \ No newline at end of file diff --git a/source/plugin/PluginContainer.h b/source/plugin/PluginContainer.h index 7de0107..df25217 100644 --- a/source/plugin/PluginContainer.h +++ b/source/plugin/PluginContainer.h @@ -32,9 +32,9 @@ public: PluginContainer(const PluginContainer &) = delete; - PluginContainer(PluginContainer &&src); + PluginContainer(PluginContainer &&src) noexcept; - PluginContainer &operator=(PluginContainer &&src); + PluginContainer &operator=(PluginContainer &&src) noexcept; [[nodiscard]] const PluginMetaInformation &getMetaInformation() const; @@ -62,12 +62,20 @@ public: [[nodiscard]] bool isInitDone() const; + void InitButtonComboData(); + void DeinitButtonComboData(); + + [[nodiscard]] uint32_t getButtonComboManagerHandle() const; + private: PluginMetaInformation mMetaInformation; PluginLinkInformation mPluginLinkInformation; std::shared_ptr mPluginData; + std::unique_ptr mHandle = std::make_unique(); + std::optional mPluginConfigData = std::nullopt; wups_storage_root_item mStorageRootItem = nullptr; bool mInitDone = false; + uint32_t mButtonComboManagerHandle = 0; }; diff --git a/source/plugin/PluginData.cpp b/source/plugin/PluginData.cpp index bb73375..0d4b823 100644 --- a/source/plugin/PluginData.cpp +++ b/source/plugin/PluginData.cpp @@ -1,26 +1,29 @@ #include "PluginData.h" PluginData::PluginData(std::vector &&buffer, const std::string_view source) : mBuffer(std::move(buffer)), mSource(source) { + // Abuse this as a stable handle that references itself and survives std::move + *mHandle = reinterpret_cast(mHandle.get()); } -PluginData::PluginData(std::span buffer, const std::string_view source) : mBuffer(buffer.begin(), buffer.end()), mSource(source) { +PluginData::PluginData(std::span buffer, const std::string_view source) : PluginData(std::vector(buffer.begin(), buffer.end()), source) { } - PluginData::PluginData(PluginData &&src) : mBuffer(std::move(src.mBuffer)), - mSource(std::move(src.mSource)) { + mSource(std::move(src.mSource)), + mHandle(std::move(src.mHandle)) { } PluginData &PluginData::operator=(PluginData &&src) noexcept { if (this != &src) { this->mBuffer = std::move(src.mBuffer); this->mSource = std::move(src.mSource); + this->mHandle = std::move(src.mHandle); } return *this; } uint32_t PluginData::getHandle() const { - return reinterpret_cast(this); + return *mHandle; } std::span PluginData::getBuffer() const { diff --git a/source/plugin/PluginData.h b/source/plugin/PluginData.h index 761c7ce..6dcb65b 100644 --- a/source/plugin/PluginData.h +++ b/source/plugin/PluginData.h @@ -44,6 +44,7 @@ public: private: std::vector mBuffer; std::string mSource; + std::unique_ptr mHandle = std::make_unique(); }; struct PluginDataSharedPtrComparator { diff --git a/source/plugin/PluginMetaInformationFactory.cpp b/source/plugin/PluginMetaInformationFactory.cpp index 4324e9e..b3b67a3 100644 --- a/source/plugin/PluginMetaInformationFactory.cpp +++ b/source/plugin/PluginMetaInformationFactory.cpp @@ -113,6 +113,8 @@ std::optional PluginMetaInformationFactory::loadPlugin(st pluginInfo.setWUPSVersion(0, 7, 1); } else if (value == "0.8.1") { pluginInfo.setWUPSVersion(0, 8, 1); + } else if (value == "0.8.2") { + pluginInfo.setWUPSVersion(0, 8, 2); } else { error = PLUGIN_PARSE_ERROR_INCOMPATIBLE_VERSION; DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str()); diff --git a/source/utils/HeapMemoryFixedSize.cpp b/source/utils/HeapMemoryFixedSize.cpp index ee6ba4c..b9de681 100644 --- a/source/utils/HeapMemoryFixedSize.cpp +++ b/source/utils/HeapMemoryFixedSize.cpp @@ -3,7 +3,7 @@ HeapMemoryFixedSize::HeapMemoryFixedSize() = default; -HeapMemoryFixedSize::HeapMemoryFixedSize(std::size_t size) : mData(make_unique_nothrow(size)), mSize(mData ? size : 0) {} +HeapMemoryFixedSize::HeapMemoryFixedSize(const std::size_t size) : mData(make_unique_nothrow(size)), mSize(mData ? size : 0) {} HeapMemoryFixedSize::HeapMemoryFixedSize(HeapMemoryFixedSize &&other) noexcept : mData(std::move(other.mData)), mSize(other.mSize) { diff --git a/source/utils/buttoncombo/ButtonComboUtils.cpp b/source/utils/buttoncombo/ButtonComboUtils.cpp new file mode 100644 index 0000000..a0a43e0 --- /dev/null +++ b/source/utils/buttoncombo/ButtonComboUtils.cpp @@ -0,0 +1,200 @@ +#include "ButtonComboUtils.h" + +#include +#include +#include +#include +#include +#include + +namespace ButtonComboUtils::API { + static std::forward_list sButtonComboManager; + static std::mutex sButtonComboMutex; + + namespace Internal { + uint32_t CreateButtonComboData() { + std::lock_guard lock(sButtonComboMutex); + sButtonComboManager.emplace_front(); + return sButtonComboManager.front().getHandle(); + } + + void RemoveButtonComboData(uint32_t buttonComboManagerHandle) { + if (!remove_locked_first_if(sButtonComboMutex, sButtonComboManager, [buttonComboManagerHandle](const ButtonComboManager &buttonComboData) { return buttonComboData.getHandle() == buttonComboManagerHandle; })) { + DEBUG_FUNCTION_LINE_WARN("Tried to remove ButtonComboManager by invalid handle: %08X", buttonComboManagerHandle); + } + } + } // namespace Internal + + namespace { + WUPSButtonCombo_Error ExecuteForIdentifierLocked(void *identifier, const std::function &callback) { + if (identifier == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + std::lock_guard lock(sButtonComboMutex); + for (auto &manager : sButtonComboManager) { + if (manager.getHandle() == reinterpret_cast(identifier)) { + return callback(manager); + } + } + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + } // namespace + + WUPSButtonCombo_Error AddButtonCombo(void *identifier, + const WUPSButtonCombo_ComboOptions *options, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus) { + if (options == nullptr || outHandle == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + WUPSButtonCombo_ComboStatus tmpStatus; + const auto res = ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.AddButtonComboHandle(*options, *outHandle, tmpStatus); + }); + if (outStatus) { *outStatus = tmpStatus; } + return res; + } + + WUPSButtonCombo_Error RemoveButtonCombo(void *identifier, + const WUPSButtonCombo_ComboHandle handle) { + if (identifier == nullptr || handle == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.RemoveButtonCombo(handle); + }); + } + + WUPSButtonCombo_Error GetButtonComboStatus(void *identifier, + const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ComboStatus *outStatus) { + if (identifier == nullptr || handle == nullptr || outStatus == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.GetButtonComboStatus(handle, *outStatus); + }); + } + + WUPSButtonCombo_Error UpdateButtonComboMeta(void *identifier, + const WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_MetaOptions *metaOptions) { + if (metaOptions == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.UpdateButtonComboMeta(handle, *metaOptions); + }); + } + + WUPSButtonCombo_Error UpdateButtonComboCallback(void *identifier, + const WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_CallbackOptions *callbackOptions) { + if (callbackOptions == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.UpdateButtonComboCallback(handle, *callbackOptions); + }); + } + + WUPSButtonCombo_Error UpdateControllerMask(void *identifier, + const WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_ControllerTypes controllerMask, + WUPSButtonCombo_ComboStatus *outStatus) { + WUPSButtonCombo_ComboStatus tmpStatus; + const auto res = ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.UpdateControllerMask(handle, controllerMask, tmpStatus); + }); + if (outStatus) { *outStatus = tmpStatus; } + return res; + } + + WUPSButtonCombo_Error UpdateButtonCombo(void *identifier, + const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_Buttons combo, + WUPSButtonCombo_ComboStatus *outStatus) { + WUPSButtonCombo_ComboStatus tmpStatus; + const auto res = ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.UpdateButtonCombo(handle, combo, tmpStatus); + }); + if (outStatus) { *outStatus = tmpStatus; } + return res; + } + + WUPSButtonCombo_Error UpdateHoldDuration(void *identifier, + const WUPSButtonCombo_ComboHandle handle, + const uint32_t holdDurationInFrames) { + const auto res = ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.UpdateHoldDuration(handle, holdDurationInFrames); + }); + return res; + } + + WUPSButtonCombo_Error GetButtonComboMeta(void *identifier, + const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_MetaOptionsOut *outOptions) { + if (outOptions == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.GetButtonComboMeta(handle, *outOptions); + }); + } + WUPSButtonCombo_Error GetButtonComboCallback(void *identifier, + const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_CallbackOptions *outOptions) { + + if (outOptions == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.GetButtonComboCallback(handle, *outOptions); + }); + } + + WUPSButtonCombo_Error GetButtonComboInfoEx(void *identifier, + const WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ButtonComboInfoEx *outOptions) { + if (outOptions == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.GetButtonComboInfoEx(handle, *outOptions); + }); + } + + WUPSButtonCombo_Error CheckComboAvailable(void *identifier, + const WUPSButtonCombo_ButtonComboOptions *options, + WUPSButtonCombo_ComboStatus *outStatus) { + if (outStatus == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.CheckComboAvailable(*options, *outStatus); + }); + } + WUPSButtonCombo_Error DetectButtonCombo_Blocking(void *identifier, + const WUPSButtonCombo_DetectButtonComboOptions *options, + WUPSButtonCombo_Buttons *outButtonCombo) { + if (options == nullptr || outButtonCombo == nullptr) { + return WUPS_BUTTON_COMBO_ERROR_INVALID_ARGS; + } + return ExecuteForIdentifierLocked(identifier, + [&](ButtonComboManager &manager) { + return manager.DetectButtonCombo_Blocking(*options, *outButtonCombo); + }); + } +} // namespace ButtonComboUtils::API \ No newline at end of file diff --git a/source/utils/buttoncombo/ButtonComboUtils.h b/source/utils/buttoncombo/ButtonComboUtils.h new file mode 100644 index 0000000..0b3467a --- /dev/null +++ b/source/utils/buttoncombo/ButtonComboUtils.h @@ -0,0 +1,65 @@ +#pragma once + +#include + +namespace ButtonComboUtils::API { + namespace Internal { + uint32_t CreateButtonComboData(); + void RemoveButtonComboData(uint32_t buttonComboManagerHandle); + } // namespace Internal + + WUPSButtonCombo_Error AddButtonCombo(void *identifier, + const WUPSButtonCombo_ComboOptions *options, + WUPSButtonCombo_ComboHandle *outHandle, + WUPSButtonCombo_ComboStatus *outStatus); + + WUPSButtonCombo_Error RemoveButtonCombo(void *identifier, + WUPSButtonCombo_ComboHandle handle); + + WUPSButtonCombo_Error GetButtonComboStatus(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ComboStatus *outStatus); + + WUPSButtonCombo_Error UpdateButtonComboMeta(void *identifier, + WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_MetaOptions *metaOptions); + + WUPSButtonCombo_Error UpdateButtonComboCallback(void *identifier, + WUPSButtonCombo_ComboHandle handle, + const WUPSButtonCombo_CallbackOptions *callbackOptions); + + WUPSButtonCombo_Error UpdateControllerMask(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ControllerTypes controllerMask, + WUPSButtonCombo_ComboStatus *outStatus); + + WUPSButtonCombo_Error UpdateButtonCombo(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_Buttons combo, + WUPSButtonCombo_ComboStatus *outStatus); + + WUPSButtonCombo_Error UpdateHoldDuration(void *identifier, + WUPSButtonCombo_ComboHandle handle, + uint32_t holdDurationInFrames); + + WUPSButtonCombo_Error GetButtonComboMeta(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_MetaOptionsOut *outOptions); + + WUPSButtonCombo_Error GetButtonComboCallback(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_CallbackOptions *outOptions); + + WUPSButtonCombo_Error GetButtonComboInfoEx(void *identifier, + WUPSButtonCombo_ComboHandle handle, + WUPSButtonCombo_ButtonComboInfoEx *outOptions); + + WUPSButtonCombo_Error CheckComboAvailable(void *identifier, + const WUPSButtonCombo_ButtonComboOptions *options, + WUPSButtonCombo_ComboStatus *outStatus); + + WUPSButtonCombo_Error DetectButtonCombo_Blocking(void *identifier, + const WUPSButtonCombo_DetectButtonComboOptions *options, + WUPSButtonCombo_Buttons *outButtonCombo); + +} // namespace ButtonComboUtils::API diff --git a/source/utils/config/ConfigUtils.cpp b/source/utils/config/ConfigUtils.cpp index 8b36b19..d9af0f7 100644 --- a/source/utils/config/ConfigUtils.cpp +++ b/source/utils/config/ConfigUtils.cpp @@ -108,12 +108,10 @@ void ConfigUtils::displayMenu() { for (const auto &hook : plugin.getPluginLinkInformation().getHookDataList()) { if (hook.getType() == WUPS_LOADER_HOOK_GET_CONFIG_DEPRECATED) { if (hook.getFunctionPointer() == nullptr) { - DEBUG_FUNCTION_LINE_ERR("Hook had invalid ptr"); break; } auto cur_config_handle = ((void *(*) ())((uint32_t *) hook.getFunctionPointer()))(); if (cur_config_handle == nullptr) { - DEBUG_FUNCTION_LINE_WARN("Hook returned empty handle"); break; } config = WUPSConfigAPIBackend::Intern::PopConfigByHandle(WUPSConfigHandle(cur_config_handle)); @@ -238,11 +236,6 @@ void ConfigUtils::displayMenu() { } } } - DEBUG_FUNCTION_LINE_INFO("Save new plugin list"); - for (const auto &cur : newActivePluginsList) { - DEBUG_FUNCTION_LINE_ERR("%08X %s", cur.getPluginData()->getHandle(), cur.isLoadAndLink() ? "active" : "inactive"); - } - DEBUG_FUNCTION_LINE_INFO("==="); gLoadOnNextLaunch = newActivePluginsList; WUPSBackendSettings::SetInactivePluginFilenames(newInactivePluginsList); if (!WUPSBackendSettings::SaveSettings()) { diff --git a/source/utils/storage/StorageItem.cpp b/source/utils/storage/StorageItem.cpp index b7d2027..c33b210 100644 --- a/source/utils/storage/StorageItem.cpp +++ b/source/utils/storage/StorageItem.cpp @@ -4,10 +4,12 @@ #include "utils/logger.h" StorageItem::StorageItem(const std::string_view key) : mKey(key) { + // Abuse this as a stable handle that references itself and survives std::move + *mHandle = reinterpret_cast(mHandle.get()); } uint32_t StorageItem::getHandle() const { - return reinterpret_cast(this); + return *mHandle; } void StorageItem::setValue(const std::string &value) { diff --git a/source/utils/storage/StorageItem.h b/source/utils/storage/StorageItem.h index 83c224c..e681d63 100644 --- a/source/utils/storage/StorageItem.h +++ b/source/utils/storage/StorageItem.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include #include @@ -78,4 +79,6 @@ private: std::string mKey = {}; bool mBinaryConversionDone = true; + + std::unique_ptr mHandle = std::make_unique(); };