diff --git a/lib/external/libwolv b/lib/external/libwolv index 7b441291c..6b02f5207 160000 --- a/lib/external/libwolv +++ b/lib/external/libwolv @@ -1 +1 @@ -Subproject commit 7b441291cd8f13c5d15e104d46b82a3fc493adcf +Subproject commit 6b02f52077093975cae49d7fa337b1e490b51841 diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index a54606312..32a3fe8aa 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -813,6 +814,35 @@ namespace hex { } } + + namespace BackgroundServices { + + namespace impl { + using Callback = std::function; + + struct Service { + std::string name; + std::jthread thread; + }; + + std::vector &getServices(); + void stopServices(); + } + + void registerService(const std::string &unlocalizedName, const impl::Callback &callback); + } + + namespace CommunicationInterface { + + namespace impl { + using NetworkCallback = std::function; + + std::map &getNetworkEndpoints(); + } + + void registerNetworkEndpoint(const std::string &endpoint, const impl::NetworkCallback &callback); + + } } } diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index 8da050bf5..c3bee51e7 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -7,6 +7,7 @@ #include #include +#include #include @@ -787,4 +788,62 @@ namespace hex { } + namespace ContentRegistry::BackgroundServices { + + namespace impl { + + std::vector &getServices() { + static std::vector services; + + return services; + } + + void stopServices() { + for (auto &service : getServices()) { + service.thread.request_stop(); + } + + for (auto &service : getServices()) { + service.thread.join(); + } + } + + } + + void registerService(const std::string &unlocalizedName, const impl::Callback &callback) { + log::debug("Registered new background service: {}", unlocalizedName); + + impl::getServices().push_back(impl::Service { + unlocalizedName, + std::jthread([callback](const std::stop_token &stopToken){ + while (!stopToken.stop_requested()) { + callback(); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + }) + }); + } + + } + + namespace ContentRegistry::CommunicationInterface { + + namespace impl { + + std::map &getNetworkEndpoints() { + static std::map endpoints; + + return endpoints; + } + + } + + void registerNetworkEndpoint(const std::string &endpoint, const impl::NetworkCallback &callback) { + log::debug("Registered new network endpoint: {}", endpoint); + + impl::getNetworkEndpoints().insert({ endpoint, callback }); + } + + } + } diff --git a/main/source/init/tasks.cpp b/main/source/init/tasks.cpp index 513dd1cdb..f3f413e21 100644 --- a/main/source/init/tasks.cpp +++ b/main/source/init/tasks.cpp @@ -325,6 +325,11 @@ namespace hex::init { ContentRegistry::FileHandler::impl::getEntries().clear(); ContentRegistry::Hashes::impl::getHashes().clear(); + ContentRegistry::BackgroundServices::impl::stopServices(); + ContentRegistry::BackgroundServices::impl::getServices().clear(); + + ContentRegistry::CommunicationInterface::impl::getNetworkEndpoints().clear(); + LayoutManager::reset(); ThemeManager::reset(); diff --git a/main/source/window/window.cpp b/main/source/window/window.cpp index 05897ac08..f62218cc9 100644 --- a/main/source/window/window.cpp +++ b/main/source/window/window.cpp @@ -164,7 +164,9 @@ namespace hex { } this->m_windowTitle = title; - glfwSetWindowTitle(this->m_window, title.c_str()); + + if (this->m_window != nullptr) + glfwSetWindowTitle(this->m_window, title.c_str()); }); constexpr static auto CrashBackupFileName = "crash_backup.hexproj"; @@ -1012,6 +1014,8 @@ namespace hex { void Window::exitGLFW() { glfwDestroyWindow(this->m_window); glfwTerminate(); + + this->m_window = nullptr; } void Window::exitImGui() { diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 0f739888f..be04b2041 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -6,7 +6,9 @@ project(builtin) add_library(${PROJECT_NAME} SHARED source/plugin_builtin.cpp + source/content/background_services.cpp source/content/command_palette_commands.cpp + source/content/communication_interface.cpp source/content/data_inspector.cpp source/content/pl_builtin_functions.cpp source/content/pl_pragmas.cpp diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index 442ad0972..acb970191 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -421,6 +421,7 @@ "hex.builtin.setting.general.auto_load_patterns": "Auto-load supported pattern", "hex.builtin.setting.general.check_for_updates": "Check for updates on startup", "hex.builtin.setting.general.enable_unicode": "Load all unicode characters", + "hex.builtin.setting.general.network_interface": "Enable network interface", "hex.builtin.setting.general.save_recent_providers": "Save recently used providers", "hex.builtin.setting.general.show_tips": "Show tips on startup", "hex.builtin.setting.general.sync_pattern_source": "Sync pattern source code between providers", diff --git a/plugins/builtin/source/content/background_services.cpp b/plugins/builtin/source/content/background_services.cpp new file mode 100644 index 000000000..f23b0d551 --- /dev/null +++ b/plugins/builtin/source/content/background_services.cpp @@ -0,0 +1,58 @@ +#include +#include +#include + +#include + +#include + +#include + +namespace hex::plugin::builtin { + + static bool networkInterfaceServiceEnabled = false; + + namespace { + + void handleNetworkInterfaceService() { + if (!networkInterfaceServiceEnabled) { + std::this_thread::yield(); + return; + } + static wolv::net::SocketServer networkInterfaceServer(51337); + networkInterfaceServer.accept([](auto, const std::vector &data) -> std::vector { + nlohmann::json result; + + try { + auto json = nlohmann::json::parse(data.begin(), data.end()); + + const auto &endpoints = ContentRegistry::CommunicationInterface::impl::getNetworkEndpoints(); + if (auto callback = endpoints.find(json["endpoint"].get()); callback != endpoints.end()) { + auto responseData = callback->second(json["data"]); + + result["status"] = "success"; + result["data"] = responseData; + } + } catch (const std::exception &e) { + log::error("Network interface service error: {}", e.what()); + + result["status"] = "error"; + result["data"]["error"] = e.what(); + } + + auto resultString = result.dump(); + return { resultString.begin(), resultString.end() }; + }); + } + + } + + void registerBackgroundServices() { + EventManager::subscribe([]{ + networkInterfaceServiceEnabled = bool(ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.network_interface", 0)); + }); + + ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.network_interface"_lang, handleNetworkInterfaceService); + } + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/communication_interface.cpp b/plugins/builtin/source/content/communication_interface.cpp new file mode 100644 index 000000000..ae80e4e26 --- /dev/null +++ b/plugins/builtin/source/content/communication_interface.cpp @@ -0,0 +1,17 @@ +#include + +#include + +namespace hex::plugin::builtin { + + void registerNetworkEndpoints() { + ContentRegistry::CommunicationInterface::registerNetworkEndpoint("pattern_editor/set_code", [](const nlohmann::json &data) -> nlohmann::json { + auto code = data["code"].get(); + + EventManager::post(code); + + return { }; + }); + } + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/settings_entries.cpp b/plugins/builtin/source/content/settings_entries.cpp index 5ad5bcedc..53cf40c25 100644 --- a/plugins/builtin/source/content/settings_entries.cpp +++ b/plugins/builtin/source/content/settings_entries.cpp @@ -113,6 +113,17 @@ namespace hex::plugin::builtin { return false; }); + ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.network_interface", 0, [](auto name, nlohmann::json &setting) { + static bool enabled = static_cast(setting); + + if (ImGui::Checkbox(name.data(), &enabled)) { + setting = static_cast(enabled); + return true; + } + + return false; + }); + /* Interface */ ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", "Dark", [](auto name, nlohmann::json &setting) { diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index a95102e25..0c93ced75 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -724,6 +724,7 @@ namespace hex::plugin::builtin { EventManager::subscribe(this, [this](const std::string &code) { this->m_textEditor.SetText(code); + this->m_hasUnevaluatedChanges = true; }); EventManager::subscribe(this, [this] { diff --git a/plugins/builtin/source/plugin_builtin.cpp b/plugins/builtin/source/plugin_builtin.cpp index 7e7217b33..a8c6acec1 100644 --- a/plugins/builtin/source/plugin_builtin.cpp +++ b/plugins/builtin/source/plugin_builtin.cpp @@ -28,6 +28,8 @@ namespace hex::plugin::builtin { void registerThemeHandlers(); void registerStyleHandlers(); void registerThemes(); + void registerBackgroundServices(); + void registerNetworkEndpoints(); void addFooterItems(); void addToolbarItems(); @@ -64,6 +66,8 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") { registerThemeHandlers(); registerStyleHandlers(); registerThemes(); + registerBackgroundServices(); + registerNetworkEndpoints(); addFooterItems(); addToolbarItems();