mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 07:47:03 -05:00
feat: Allow plugins to be dynamically turned on and off
This commit is contained in:
@@ -46,6 +46,7 @@ EXPORT_MODULE namespace hex {
|
||||
using SetImGuiContextFunc = void (*)(ImGuiContext *);
|
||||
using GetSubCommandsFunc = void* (*)();
|
||||
using GetFeaturesFunc = void* (*)();
|
||||
using IsBuiltinPluginFunc = bool (*)();
|
||||
|
||||
InitializePluginFunc initializePluginFunction = nullptr;
|
||||
InitializeLibraryFunc initializeLibraryFunction = nullptr;
|
||||
@@ -58,6 +59,7 @@ EXPORT_MODULE namespace hex {
|
||||
SetImGuiContextFunc setImGuiContextLibraryFunction = nullptr;
|
||||
GetSubCommandsFunc getSubCommandsFunction = nullptr;
|
||||
GetFeaturesFunc getFeaturesFunction = nullptr;
|
||||
IsBuiltinPluginFunc isBuiltinPluginFunction = nullptr;
|
||||
};
|
||||
|
||||
class Plugin {
|
||||
@@ -84,6 +86,7 @@ EXPORT_MODULE namespace hex {
|
||||
[[nodiscard]] bool isLoaded() const;
|
||||
[[nodiscard]] bool isValid() const;
|
||||
[[nodiscard]] bool isInitialized() const;
|
||||
[[nodiscard]] bool isBuiltinPlugin() const;
|
||||
|
||||
[[nodiscard]] std::span<SubCommand> getSubCommands() const;
|
||||
[[nodiscard]] std::span<Feature> getFeatures() const;
|
||||
@@ -92,12 +95,15 @@ EXPORT_MODULE namespace hex {
|
||||
|
||||
[[nodiscard]] bool wasAddedManually() const;
|
||||
|
||||
void setEnabled(bool enabled);
|
||||
|
||||
private:
|
||||
uintptr_t m_handle = 0;
|
||||
std::fs::path m_path;
|
||||
|
||||
mutable bool m_initialized = false;
|
||||
bool m_addedManually = false;
|
||||
bool m_enabled = true;
|
||||
|
||||
PluginFunctions m_functions = {};
|
||||
|
||||
@@ -133,6 +139,8 @@ EXPORT_MODULE namespace hex {
|
||||
|
||||
static bool isPluginLoaded(const std::fs::path &path);
|
||||
|
||||
static void setPluginEnabled(const Plugin &plugin, bool enabled);
|
||||
|
||||
private:
|
||||
static std::list<Plugin>& getPluginsMutable();
|
||||
|
||||
|
||||
@@ -80,6 +80,10 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
|
||||
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
|
||||
#define IMHEX_LIBRARY_SETUP(name) IMHEX_LIBRARY_SETUP_IMPL(name)
|
||||
|
||||
#define IMHEX_PLUGIN_SETUP_BUILTIN(name, author, description) \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX bool isBuiltinPlugin() { return true; } \
|
||||
IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
|
||||
|
||||
#define IMHEX_LIBRARY_SETUP_IMPL(name) \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(initializeLibrary_, IMHEX_PLUGIN_NAME)(); \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *WOLV_TOKEN_CONCAT(getLibraryName_, IMHEX_PLUGIN_NAME)() { return name; } \
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace hex {
|
||||
m_functions.setImGuiContextLibraryFunction = getPluginFunction<PluginFunctions::SetImGuiContextFunc>(hex::format("setImGuiContext_{}", fileName));
|
||||
m_functions.getSubCommandsFunction = getPluginFunction<PluginFunctions::GetSubCommandsFunc>("getSubCommands");
|
||||
m_functions.getFeaturesFunction = getPluginFunction<PluginFunctions::GetSubCommandsFunc>("getFeatures");
|
||||
m_functions.isBuiltinPluginFunction = getPluginFunction<PluginFunctions::IsBuiltinPluginFunc>("isBuiltinPlugin");
|
||||
}
|
||||
|
||||
Plugin::Plugin(const std::string &name, const hex::PluginFunctions &functions) :
|
||||
@@ -96,6 +97,9 @@ namespace hex {
|
||||
|
||||
m_functions = other.m_functions;
|
||||
other.m_functions = {};
|
||||
|
||||
m_enabled = other.m_enabled;
|
||||
m_initialized = other.m_initialized;
|
||||
}
|
||||
|
||||
Plugin& Plugin::operator=(Plugin &&other) noexcept {
|
||||
@@ -108,6 +112,9 @@ namespace hex {
|
||||
m_functions = other.m_functions;
|
||||
other.m_functions = {};
|
||||
|
||||
m_enabled = other.m_enabled;
|
||||
m_initialized = other.m_initialized;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -127,6 +134,8 @@ namespace hex {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!m_enabled)
|
||||
return true;
|
||||
|
||||
const auto requestedVersion = getCompatibleVersion();
|
||||
const auto imhexVersion = ImHexApi::System::getImHexVersion().get();
|
||||
@@ -215,6 +224,11 @@ namespace hex {
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
bool Plugin::isBuiltinPlugin() const {
|
||||
return m_functions.isBuiltinPluginFunction != nullptr && m_functions.isBuiltinPluginFunction();
|
||||
}
|
||||
|
||||
|
||||
std::span<SubCommand> Plugin::getSubCommands() const {
|
||||
if (m_functions.getSubCommandsFunction != nullptr) {
|
||||
const auto result = m_functions.getSubCommandsFunction();
|
||||
@@ -248,7 +262,7 @@ namespace hex {
|
||||
return m_addedManually;
|
||||
}
|
||||
|
||||
void *Plugin::getPluginFunction(const std::string &symbol) const {
|
||||
void* Plugin::getPluginFunction(const std::string &symbol) const {
|
||||
#if defined(OS_WINDOWS)
|
||||
return reinterpret_cast<void *>(GetProcAddress(HMODULE(m_handle), symbol.c_str()));
|
||||
#else
|
||||
@@ -256,6 +270,11 @@ namespace hex {
|
||||
#endif
|
||||
}
|
||||
|
||||
void Plugin::setEnabled(bool enabled) {
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AutoReset<std::vector<std::fs::path>> PluginManager::s_pluginPaths, PluginManager::s_pluginLoadPaths;
|
||||
|
||||
@@ -288,7 +307,7 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
// Load regular plugins afterwards
|
||||
// Load regular plugins afterward
|
||||
for (auto &pluginPath : std::fs::directory_iterator(pluginFolder)) {
|
||||
if (pluginPath.is_regular_file() && pluginPath.path().extension() == ".hexplug") {
|
||||
if (!isPluginLoaded(pluginPath.path())) {
|
||||
@@ -301,6 +320,17 @@ namespace hex {
|
||||
return !plugin.isValid();
|
||||
});
|
||||
|
||||
// Move the built-in plugins to the front of the list so they get initialized first
|
||||
getPluginsMutable().sort([](const Plugin &a, const Plugin &b) {
|
||||
if (a.isBuiltinPlugin() && !b.isBuiltinPlugin()) {
|
||||
return true;
|
||||
} else if (!a.isBuiltinPlugin() && b.isBuiltinPlugin()) {
|
||||
return false;
|
||||
} else {
|
||||
return a.getPluginName() < b.getPluginName();
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -398,4 +428,16 @@ namespace hex {
|
||||
});
|
||||
}
|
||||
|
||||
void PluginManager::setPluginEnabled(const Plugin &plugin, bool enabled) {
|
||||
auto &plugins = getPluginsMutable();
|
||||
auto it = std::ranges::find_if(plugins, [&plugin](const Plugin &p) {
|
||||
return &plugin == &p;
|
||||
});
|
||||
|
||||
if (it != plugins.end()) {
|
||||
it->setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -532,6 +532,8 @@
|
||||
"hex.builtin.setting.interface.pattern_data_row_bg": "Enable colored pattern background",
|
||||
"hex.builtin.setting.interface.wiki_explain_language": "Wikipedia Language",
|
||||
"hex.builtin.setting.interface.restore_window_pos": "Restore window position",
|
||||
"hex.builtin.setting.plugins": "Plugins",
|
||||
"hex.builtin.setting.loaded_plugins": "Plugins to be loaded",
|
||||
"hex.builtin.setting.proxy": "Proxy",
|
||||
"hex.builtin.setting.proxy.description": "Proxy will take effect on store, wikipedia or any other plugin immediately.",
|
||||
"hex.builtin.setting.proxy.enable": "Enable Proxy",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <hex/api/plugin_manager.hpp>
|
||||
#include <romfs/romfs.hpp>
|
||||
|
||||
#if defined(OS_WEB)
|
||||
@@ -972,6 +973,27 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ContentRegistry::Settings::impl::store();
|
||||
});
|
||||
|
||||
|
||||
/* Plugins */
|
||||
{
|
||||
for (const auto &plugin : PluginManager::getPlugins()) {
|
||||
if (plugin.isLibraryPlugin())
|
||||
continue;
|
||||
if (plugin.isBuiltinPlugin())
|
||||
continue;
|
||||
|
||||
auto interface = ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.plugins", "hex.builtin.setting.loaded_plugins", plugin.getPluginName(), true)
|
||||
.setTooltip(plugin.getPluginDescription())
|
||||
.setChangedCallback([&plugin](Widgets::Widget &widget) {
|
||||
auto checkBox = static_cast<Widgets::Checkbox *>(&widget);
|
||||
PluginManager::setPluginEnabled(plugin, checkBox->isChecked());
|
||||
})
|
||||
.requiresRestart();
|
||||
|
||||
PluginManager::setPluginEnabled(plugin, static_cast<Widgets::Checkbox *>(&interface.getWidget())->isChecked());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void loadLayoutSettings() {
|
||||
|
||||
@@ -88,7 +88,7 @@ IMHEX_PLUGIN_SUBCOMMANDS() {
|
||||
{ "save-editor", "", "Opens a pattern file for save file editing", hex::plugin::builtin::handleSaveEditorCommand },
|
||||
};
|
||||
|
||||
IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
IMHEX_PLUGIN_SETUP_BUILTIN("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
using namespace hex::plugin::builtin;
|
||||
|
||||
// Show a warning banner on debug builds
|
||||
|
||||
Reference in New Issue
Block a user