Initial support for disabling/enabling plugins in config menu

This commit is contained in:
Maschell 2024-08-04 16:42:24 +02:00
parent 39256e45f0
commit 16c40684a1
14 changed files with 134 additions and 56 deletions

View File

@ -3,6 +3,7 @@
#include "hooks.h" #include "hooks.h"
#include "plugin/PluginContainer.h" #include "plugin/PluginContainer.h"
#include "plugin/PluginLinkInformationFactory.h" #include "plugin/PluginLinkInformationFactory.h"
#include "plugin/PluginLoadWrapper.h"
#include "plugin/PluginMetaInformationFactory.h" #include "plugin/PluginMetaInformationFactory.h"
#include "utils/ElfUtils.h" #include "utils/ElfUtils.h"
#include "utils/StringTools.h" #include "utils/StringTools.h"
@ -10,47 +11,32 @@
#include <coreinit/cache.h> #include <coreinit/cache.h>
#include <coreinit/dynload.h> #include <coreinit/dynload.h>
#include <memory.h> #include <memory.h>
#include <memory>
bool CheckIfAllowed(const PluginMetaInformation &metaInfo) {
std::vector<std::pair<std::string, std::string>> allowList = {
{"Maschell", "Aroma Base Plugin"},
{"Maschell", "DRC Region Free Plugin"},
{"Maschell", "Homebrew on Wii U menu"},
{"Maschell", "Region Free Plugin"},
{"Maschell", "Wiiload"},
{"mtheall, Maschell", "ftpiiu"},
};
return std::any_of(allowList.begin(), allowList.end(), [&metaInfo](const auto &cur) {
return metaInfo.getAuthor() == cur.first && metaInfo.getName() == cur.second;
});
}
std::vector<PluginContainer> std::vector<PluginContainer>
PluginManagement::loadPlugins(const std::set<std::shared_ptr<PluginData>> &pluginDataList, std::vector<relocation_trampoline_entry_t> &trampolineData) { PluginManagement::loadPlugins(const std::vector<PluginLoadWrapper> &pluginDataList, std::vector<relocation_trampoline_entry_t> &trampolineData) {
std::vector<PluginContainer> plugins; std::vector<PluginContainer> plugins;
uint32_t trampolineID = 0; uint32_t trampolineID = 0;
for (const auto &pluginData : pluginDataList) { for (const auto &pluginDataWrapper : pluginDataList) {
PluginParseErrors error = PLUGIN_PARSE_ERROR_UNKNOWN; PluginParseErrors error = PLUGIN_PARSE_ERROR_UNKNOWN;
auto metaInfo = PluginMetaInformationFactory::loadPlugin(*pluginData, error); auto metaInfo = PluginMetaInformationFactory::loadPlugin(*pluginDataWrapper.getPluginData(), error);
if (metaInfo && error == PLUGIN_PARSE_ERROR_NONE) { if (metaInfo && error == PLUGIN_PARSE_ERROR_NONE) {
if (!pluginData->getSource().ends_with(".wps") || CheckIfAllowed(*metaInfo)) { if (pluginDataWrapper.isLoadAndLink()) {
DEBUG_FUNCTION_LINE_INFO("We want to link %s by %s", metaInfo->getName().c_str(), metaInfo->getAuthor().c_str()); DEBUG_FUNCTION_LINE_INFO("We want to link %s by %s", metaInfo->getName().c_str(), metaInfo->getAuthor().c_str());
auto linkInfo = PluginLinkInformationFactory::load(*pluginData, trampolineData, trampolineID++); auto linkInfo = PluginLinkInformationFactory::load(*pluginDataWrapper.getPluginData(), trampolineData, trampolineID++);
if (!linkInfo) { if (!linkInfo) {
auto errMsg = string_format("Failed to load plugin: %s", pluginData->getSource().c_str()); auto errMsg = string_format("Failed to load plugin: %s", pluginDataWrapper.getPluginData()->getSource().c_str());
DEBUG_FUNCTION_LINE_ERR("%s", errMsg.c_str()); DEBUG_FUNCTION_LINE_ERR("%s", errMsg.c_str());
DisplayErrorNotificationMessage(errMsg, 15.0f); DisplayErrorNotificationMessage(errMsg, 15.0f);
continue; continue;
} }
plugins.emplace_back(std::move(*metaInfo), std::move(*linkInfo), pluginData); plugins.emplace_back(std::move(*metaInfo), std::move(*linkInfo), pluginDataWrapper.getPluginData());
} else { } else {
DEBUG_FUNCTION_LINE_INFO("We want to skip %s by %s", metaInfo->getName().c_str(), metaInfo->getAuthor().c_str()); DEBUG_FUNCTION_LINE_INFO("We want to skip %s by %s", metaInfo->getName().c_str(), metaInfo->getAuthor().c_str());
plugins.emplace_back(std::move(*metaInfo), PluginLinkInformation::CreateStub(), pluginData); plugins.emplace_back(std::move(*metaInfo), PluginLinkInformation::CreateStub(), pluginDataWrapper.getPluginData());
} }
} else { } else {
auto errMsg = string_format("Failed to load plugin: %s", pluginData->getSource().c_str()); auto errMsg = string_format("Failed to load plugin: %s", *pluginDataWrapper.getPluginData()->getSource().c_str());
if (error == PLUGIN_PARSE_ERROR_INCOMPATIBLE_VERSION) { if (error == PLUGIN_PARSE_ERROR_INCOMPATIBLE_VERSION) {
errMsg += ". Incompatible version."; errMsg += ". Incompatible version.";
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "plugin/PluginContainer.h" #include "plugin/PluginContainer.h"
#include "plugin/PluginLoadWrapper.h"
#include <coreinit/dynload.h> #include <coreinit/dynload.h>
#include <map> #include <map>
#include <memory> #include <memory>
@ -10,7 +11,7 @@
class PluginManagement { class PluginManagement {
public: public:
static std::vector<PluginContainer> loadPlugins( static std::vector<PluginContainer> loadPlugins(
const std::set<std::shared_ptr<PluginData>> &pluginDataList, const std::vector<PluginLoadWrapper> &pluginDataList,
std::vector<relocation_trampoline_entry_t> &trampolineData); std::vector<relocation_trampoline_entry_t> &trampolineData);
static void callInitHooks(const std::vector<PluginContainer> &plugins); static void callInitHooks(const std::vector<PluginContainer> &plugins);

View File

@ -7,7 +7,7 @@ std::vector<PluginContainer> gLoadedPlugins;
std::vector<relocation_trampoline_entry_t> gTrampData; std::vector<relocation_trampoline_entry_t> gTrampData;
std::set<std::shared_ptr<PluginData>> gLoadedData; std::set<std::shared_ptr<PluginData>> gLoadedData;
std::set<std::shared_ptr<PluginData>> gLoadOnNextLaunch; std::vector<PluginLoadWrapper> gLoadOnNextLaunch;
std::mutex gLoadedDataMutex; std::mutex gLoadedDataMutex;
std::map<std::string, OSDynLoad_Module> gUsedRPLs; std::map<std::string, OSDynLoad_Module> gUsedRPLs;
std::vector<void *> gAllocatedAddresses; std::vector<void *> gAllocatedAddresses;

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "plugin/PluginContainer.h" #include "plugin/PluginContainer.h"
#include "plugin/PluginLoadWrapper.h"
#include "utils/config/ConfigUtils.h" #include "utils/config/ConfigUtils.h"
#include "version.h" #include "version.h"
#include <coreinit/dynload.h> #include <coreinit/dynload.h>
@ -20,7 +21,7 @@ extern std::vector<relocation_trampoline_entry_t> gTrampData;
extern std::vector<PluginContainer> gLoadedPlugins; extern std::vector<PluginContainer> gLoadedPlugins;
extern std::set<std::shared_ptr<PluginData>> gLoadedData; extern std::set<std::shared_ptr<PluginData>> gLoadedData;
extern std::set<std::shared_ptr<PluginData>> gLoadOnNextLaunch; extern std::vector<PluginLoadWrapper> 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;

View File

@ -78,6 +78,7 @@ WUMS_APPLICATION_STARTS() {
OSReport("Running WiiUPluginLoaderBackend " VERSION_FULL "\n"); OSReport("Running WiiUPluginLoaderBackend " VERSION_FULL "\n");
gStoredTVBuffer = {}; gStoredTVBuffer = {};
gConfigMenuShouldClose = false;
gUsedRPLs.clear(); gUsedRPLs.clear();

View File

@ -48,7 +48,7 @@ static uint32_t lastData0 = 0;
DECL_FUNCTION(BOOL, OSSendMessage, OSMessageQueue *queue, OSMessage *message, OSMessageFlags flags) { DECL_FUNCTION(BOOL, OSSendMessage, OSMessageQueue *queue, OSMessage *message, OSMessageFlags flags) {
if (sConfigMenuOpened && queue == OSGetSystemMessageQueue()) { if (sConfigMenuOpened && queue == OSGetSystemMessageQueue()) {
if (message != nullptr) { if (message != nullptr) {
if (message->args[0] == 0xfacebacc) { // Release foreground if (message->args[0] == 0xfacebacc && sConfigMenuOpened) { // Release foreground
gConfigMenuShouldClose = true; gConfigMenuShouldClose = true;
} }
} }

View File

@ -16,6 +16,7 @@
****************************************************************************/ ****************************************************************************/
#include "PluginDataFactory.h" #include "PluginDataFactory.h"
#include "NotificationsUtils.h" #include "NotificationsUtils.h"
#include "PluginLoadWrapper.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"
@ -24,8 +25,8 @@
#include <forward_list> #include <forward_list>
#include <memory> #include <memory>
std::set<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(std::string_view path) { std::vector<PluginLoadWrapper> PluginDataFactory::loadDir(std::string_view path) {
std::set<std::shared_ptr<PluginData>> result; std::vector<PluginLoadWrapper> result;
struct dirent *dp; struct dirent *dp;
DIR *dfd; DIR *dfd;
@ -52,7 +53,16 @@ std::set<std::shared_ptr<PluginData>> PluginDataFactory::loadDir(std::string_vie
DEBUG_FUNCTION_LINE("Loading plugin: %s", full_file_path.c_str()); DEBUG_FUNCTION_LINE("Loading plugin: %s", full_file_path.c_str());
auto pluginData = load(full_file_path); auto pluginData = load(full_file_path);
if (pluginData) { if (pluginData) {
result.insert(std::move(pluginData)); // TODO: This is only for testing. Remove me!c
bool shouldBeLoadedAndLinked = false;
if (full_file_path.ends_with("AromaBasePlugin.wps") ||
full_file_path.ends_with("drc_region_free.wps") ||
full_file_path.ends_with("regionfree.wps") ||
full_file_path.ends_with("ftpiiu.wps") ||
full_file_path.ends_with("wiiload.wps")) {
shouldBeLoadedAndLinked = true;
}
result.emplace_back(std::move(pluginData), shouldBeLoadedAndLinked);
} else { } else {
auto errMsg = string_format("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()); DEBUG_FUNCTION_LINE_ERR("%s", errMsg.c_str());

View File

@ -18,6 +18,7 @@
#pragma once #pragma once
#include "PluginData.h" #include "PluginData.h"
#include "PluginLoadWrapper.h"
#include <coreinit/memexpheap.h> #include <coreinit/memexpheap.h>
#include <forward_list> #include <forward_list>
#include <memory> #include <memory>
@ -28,7 +29,7 @@
class PluginDataFactory { class PluginDataFactory {
public: public:
static std::set<std::shared_ptr<PluginData>> loadDir(std::string_view path); static std::vector<PluginLoadWrapper> loadDir(std::string_view path);
static std::unique_ptr<PluginData> load(std::string_view path); static std::unique_ptr<PluginData> load(std::string_view path);

View File

@ -0,0 +1,21 @@
#pragma once
#include "PluginData.h"
#include <memory>
class PluginLoadWrapper {
public:
PluginLoadWrapper(std::shared_ptr<PluginData> pluginData, bool linkAndLoad) : mPluginData(std::move(pluginData)), mIsLoadAndLink(linkAndLoad) {
}
[[nodiscard]] const std::shared_ptr<PluginData> &getPluginData() const {
return mPluginData;
}
[[nodiscard]] bool isLoadAndLink() const {
return mIsLoadAndLink;
}
private:
std::shared_ptr<PluginData> mPluginData;
bool mIsLoadAndLink = false;
};

View File

@ -22,10 +22,14 @@ public:
return *mConfig; return *mConfig;
} }
[[nodiscard]] bool isActivePlugin () const { [[nodiscard]] bool isActivePlugin() const {
return mIsActivePlugin; return mIsActivePlugin;
} }
void toggleIsActivePlugin() {
mIsActivePlugin = !mIsActivePlugin;
}
private: private:
std::unique_ptr<WUPSConfigAPIBackend::WUPSConfig> mConfig; std::unique_ptr<WUPSConfigAPIBackend::WUPSConfig> mConfig;
GeneralConfigInformation mInfo; GeneralConfigInformation mInfo;

View File

@ -1,7 +1,10 @@
#include "ConfigRenderer.h" #include "ConfigRenderer.h"
#include <coreinit/title.h>
#include <sysapp/launch.h>
void ConfigRenderer::RenderStateMain() const { void ConfigRenderer::RenderStateMain() const {
auto totalElementSize = (int32_t) mActiveConfigs.size(); auto &configs = GetConfigList();
auto totalElementSize = (int32_t) configs.size();
// Calculate the range of items to display // Calculate the range of items to display
int start = std::max(0, mRenderOffset); int start = std::max(0, mRenderOffset);
int end = std::min(start + MAX_BUTTONS_ON_SCREEN, totalElementSize); int end = std::min(start + MAX_BUTTONS_ON_SCREEN, totalElementSize);
@ -11,7 +14,7 @@ void ConfigRenderer::RenderStateMain() const {
uint32_t yOffset = 8 + 24 + 8 + 4; uint32_t yOffset = 8 + 24 + 8 + 4;
for (int32_t i = start; i < end; i++) { for (int32_t i = start; i < end; i++) {
drawConfigEntry(yOffset, mActiveConfigs[i].get().getConfigInformation(), i == mCursorPos); drawConfigEntry(yOffset, configs[i].get().getConfigInformation(), i == mCursorPos, configs[i].get().isActivePlugin());
yOffset += 42 + 8; yOffset += 42 + 8;
} }
@ -19,7 +22,11 @@ void ConfigRenderer::RenderStateMain() const {
// draw top bar // draw top bar
DrawUtils::setFontSize(24); DrawUtils::setFontSize(24);
if (mSetActivePluginsMode) {
DrawUtils::print(16, 6 + 24, "Please select the plugin that should be active");
} else {
DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu"); DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu");
}
DrawUtils::setFontSize(18); DrawUtils::setFontSize(18);
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, VERSION_FULL, true); DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, VERSION_FULL, true);
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK); DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
@ -28,7 +35,11 @@ void ConfigRenderer::RenderStateMain() const {
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK); DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
DrawUtils::setFontSize(18); DrawUtils::setFontSize(18);
DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate "); DrawUtils::print(16, SCREEN_HEIGHT - 10, "\ue07d Navigate ");
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select", true); if (mSetActivePluginsMode) {
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Select | \uE045 Apply", true);
} else {
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, "\ue000 Activate", true);
}
// draw scroll indicator // draw scroll indicator
DrawUtils::setFontSize(24); DrawUtils::setFontSize(24);
@ -47,7 +58,7 @@ void ConfigRenderer::RenderStateMain() const {
DrawUtils::endDraw(); DrawUtils::endDraw();
} }
void ConfigRenderer::drawConfigEntry(uint32_t yOffset, const GeneralConfigInformation &configInformation, bool isHighlighted) const { void ConfigRenderer::drawConfigEntry(uint32_t yOffset, const GeneralConfigInformation &configInformation, bool isHighlighted, bool isActive) const {
DrawUtils::setFontColor(COLOR_TEXT); DrawUtils::setFontColor(COLOR_TEXT);
if (isHighlighted) { if (isHighlighted) {
@ -56,41 +67,70 @@ void ConfigRenderer::drawConfigEntry(uint32_t yOffset, const GeneralConfigInform
DrawUtils::drawRect(16, yOffset, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER); DrawUtils::drawRect(16, yOffset, SCREEN_WIDTH - 16 * 2, 44, 2, COLOR_BORDER);
} }
int textXOffset = 16 * 2;
if (mSetActivePluginsMode) {
DrawUtils::setFontSize(24); DrawUtils::setFontSize(24);
DrawUtils::print(16 * 2, yOffset + 8 + 24, configInformation.name.c_str()); if (isActive) {
DrawUtils::print(textXOffset, yOffset + 8 + 24, "x");
}
textXOffset += 32;
}
DrawUtils::setFontSize(24);
DrawUtils::print(textXOffset, yOffset + 8 + 24, configInformation.name.c_str());
uint32_t sz = DrawUtils::getTextWidth(configInformation.name.c_str()); uint32_t sz = DrawUtils::getTextWidth(configInformation.name.c_str());
DrawUtils::setFontSize(12); DrawUtils::setFontSize(12);
DrawUtils::print(16 * 2 + sz + 4, yOffset + 8 + 24, configInformation.author.c_str()); DrawUtils::print(textXOffset + sz + 4, yOffset + 8 + 24, configInformation.author.c_str());
DrawUtils::print(SCREEN_WIDTH - 16 * 2, yOffset + 8 + 24, configInformation.version.c_str(), true); DrawUtils::print(SCREEN_WIDTH - 16 * 2, yOffset + 8 + 24, configInformation.version.c_str(), true);
} }
ConfigSubState ConfigRenderer::UpdateStateMain(const Input &input) { ConfigSubState ConfigRenderer::UpdateStateMain(const Input &input) {
if (mActiveConfigs.empty()) { auto &configs = GetConfigList();
if (configs.empty()) {
mNeedRedraw = true; mNeedRedraw = true;
return SUB_STATE_ERROR; return SUB_STATE_ERROR;
} }
auto prevSelectedItem = mCursorPos; auto prevSelectedItem = mCursorPos;
auto totalElementSize = mActiveConfigs.size(); auto totalElementSize = configs.size();
if (input.data.buttons_d & Input::eButtons::BUTTON_DOWN) { if (input.data.buttons_d & Input::eButtons::BUTTON_DOWN) {
mCursorPos++; mCursorPos++;
} else if (input.data.buttons_d & Input::eButtons::BUTTON_UP) { } else if (input.data.buttons_d & Input::eButtons::BUTTON_UP) {
mCursorPos--; mCursorPos--;
} else if (input.data.buttons_d & Input::eButtons::BUTTON_PLUS) {
if (mSetActivePluginsMode) {
if (mActivePluginsDirty) {
for (const auto &cur : mConfigs) {
gLoadOnNextLaunch.emplace_back(cur.getConfigInformation().pluginData, cur.isActivePlugin());
}
_SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr);
}
mNeedRedraw = true;
mCategoryRenderer.reset();
return SUB_STATE_RETURN;
}
} else if (input.data.buttons_d & Input::eButtons::BUTTON_X) { } else if (input.data.buttons_d & Input::eButtons::BUTTON_X) {
mSetActivePluginsMode = !mSetActivePluginsMode; mSetActivePluginsMode = !mSetActivePluginsMode;
} else if (input.data.buttons_d & Input::eButtons::BUTTON_A) { } else if (input.data.buttons_d & Input::eButtons::BUTTON_A) {
if (mSetActivePluginsMode) {
mActivePluginsDirty = true;
mNeedRedraw = true;
configs[mCursorPos].get().toggleIsActivePlugin();
return SUB_STATE_RUNNING;
} else {
if (mCursorPos != mCurrentOpen) { if (mCursorPos != mCurrentOpen) {
mCategoryRenderer.reset(); mCategoryRenderer.reset();
mCategoryRenderer = make_unique_nothrow<CategoryRenderer>(&(mActiveConfigs[mCursorPos].get().getConfigInformation()), &(mActiveConfigs[mCursorPos].get().getConfig()), true); mCategoryRenderer = make_unique_nothrow<CategoryRenderer>(&(configs[mCursorPos].get().getConfigInformation()), &(configs[mCursorPos].get().getConfig()), true);
} }
mNeedRedraw = true; mNeedRedraw = true;
mCurrentOpen = mCursorPos; mCurrentOpen = mCursorPos;
mState = STATE_SUB; mState = STATE_SUB;
return SUB_STATE_RUNNING; return SUB_STATE_RUNNING;
}
} else if (input.data.buttons_d & (Input::eButtons::BUTTON_B | Input::eButtons::BUTTON_HOME)) { } else if (input.data.buttons_d & (Input::eButtons::BUTTON_B | Input::eButtons::BUTTON_HOME)) {
mNeedRedraw = true; mNeedRedraw = true;
mCategoryRenderer.reset(); mCategoryRenderer.reset();
for (const auto &element : mActiveConfigs) { for (const auto &element : configs) {
CallOnCloseCallback(element.get().getConfigInformation(), element.get().getConfig()); CallOnCloseCallback(element.get().getConfigInformation(), element.get().getConfig());
} }
return SUB_STATE_RETURN; return SUB_STATE_RETURN;

View File

@ -11,9 +11,11 @@ class ConfigRenderer {
public: public:
explicit ConfigRenderer(std::vector<ConfigDisplayItem> &&vec) : mConfigs(std::move(vec)) { explicit ConfigRenderer(std::vector<ConfigDisplayItem> &&vec) : mConfigs(std::move(vec)) {
std::copy(mConfigs.begin(), mConfigs.end(),
std::back_inserter(mAllConfigs));
std::copy_if(mConfigs.begin(), mConfigs.end(), std::copy_if(mConfigs.begin(), mConfigs.end(),
std::back_inserter(mActiveConfigs), std::back_inserter(mActiveConfigs),
[&](const auto & value) { [&](const auto &value) {
return value.isActivePlugin(); return value.isActivePlugin();
}); });
} }
@ -33,7 +35,14 @@ private:
void RenderStateMain() const; void RenderStateMain() const;
void drawConfigEntry(uint32_t yOffset, const GeneralConfigInformation &configInformation, bool isHighlighted) const; [[nodiscard]] const std::vector<std::reference_wrapper<ConfigDisplayItem>> &GetConfigList() const {
if (mSetActivePluginsMode) {
return mAllConfigs;
}
return mActiveConfigs;
}
void drawConfigEntry(uint32_t yOffset, const GeneralConfigInformation &configInformation, bool isHighlighted, bool isActive) const;
enum State { enum State {
STATE_MAIN = 0, STATE_MAIN = 0,
@ -41,6 +50,7 @@ private:
}; };
std::vector<ConfigDisplayItem> mConfigs; std::vector<ConfigDisplayItem> mConfigs;
std::vector<std::reference_wrapper<ConfigDisplayItem>> mAllConfigs;
std::vector<std::reference_wrapper<ConfigDisplayItem>> mActiveConfigs; std::vector<std::reference_wrapper<ConfigDisplayItem>> mActiveConfigs;
std::unique_ptr<CategoryRenderer> mCategoryRenderer = {}; std::unique_ptr<CategoryRenderer> mCategoryRenderer = {};
@ -53,4 +63,6 @@ private:
void CallOnCloseCallback(const GeneralConfigInformation &info, const WUPSConfigAPIBackend::WUPSConfig &config); void CallOnCloseCallback(const GeneralConfigInformation &info, const WUPSConfigAPIBackend::WUPSConfig &config);
bool mNeedRedraw = true; bool mNeedRedraw = true;
bool mSetActivePluginsMode = false;
bool mActivePluginsDirty = false;
}; };

View File

@ -125,6 +125,7 @@ void ConfigUtils::displayMenu() {
if (!config) { if (!config) {
config = make_unique_nothrow<WUPSConfigAPIBackend::WUPSConfig>(info.name); config = make_unique_nothrow<WUPSConfigAPIBackend::WUPSConfig>(info.name);
} }
configs.emplace_back(info, std::move(config), plugin.isLinkedAndLoaded()); configs.emplace_back(info, std::move(config), plugin.isLinkedAndLoaded());
} }

View File

@ -30,7 +30,7 @@ extern "C" PluginBackendApiErrorType WUPSLoadAndLinkByDataHandle(const wups_back
for (const auto &pluginData : gLoadedData) { for (const auto &pluginData : gLoadedData) {
if (pluginData->getHandle() == handle) { if (pluginData->getHandle() == handle) {
gLoadOnNextLaunch.insert(pluginData); gLoadOnNextLaunch.emplace_back(pluginData, true);
found = true; found = true;
break; break;
} }