diff --git a/SharpPluginLoader.Core/IO/Key.cs b/SharpPluginLoader.Core/IO/Key.cs index f491182..a235922 100644 --- a/SharpPluginLoader.Core/IO/Key.cs +++ b/SharpPluginLoader.Core/IO/Key.cs @@ -9,8 +9,10 @@ namespace SharpPluginLoader.Core.IO /// /// The buttons on a keyboard. /// - public enum Key + public enum Key : int { + MaxNameLength = 12, // For parsing purposes. + // ------- Escape = 1, D1 = 2, D2 = 3, diff --git a/SharpPluginLoader.Core/Rendering/Renderer.cs b/SharpPluginLoader.Core/Rendering/Renderer.cs index 39c66fc..f77a915 100644 --- a/SharpPluginLoader.Core/Rendering/Renderer.cs +++ b/SharpPluginLoader.Core/Rendering/Renderer.cs @@ -199,21 +199,18 @@ internal static unsafe void ResolveCustomFonts() } [UnmanagedCallersOnly] - internal static nint Initialize(Size viewportSize, Size windowSize, byte d3d12, nint menuKey) + internal static unsafe nint Initialize(Size viewportSize, Size windowSize, byte d3d12, LoaderGuiConfig* config) { IsDirectX12 = d3d12 != 0; - if (menuKey != 0) + string keyStr = new string(config->MenuKey); + if (Enum.TryParse(keyStr, out var key)) { - var keyStr = MemoryUtil.ReadString(menuKey); - if (Enum.TryParse(keyStr, out var key)) - { - _menuKey = key; - } - else - { - Log.Warn($"Invalid menu key: {keyStr}, falling back to {DefaultMenuKey}"); - } + _menuKey = key; + } + else + { + Log.Warn($"Invalid menu key: {keyStr}, falling back to {DefaultMenuKey}"); } _viewportSize = new Vector2(viewportSize.Width, viewportSize.Height); @@ -241,6 +238,13 @@ Initializing Renderer with // Currently causes a freeze when dragging a window outside of the main window. // Most likely the WndProc doesn't process events anymore which causes windows to think it's frozen. // io.ConfigFlags |= ImGuiConfigFlags.ViewportsEnable; + if (config->KeyboardNavigation) + { + io.ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard; + } + + io.FontGlobalScale = config->FontScale; + _baseAlpha = config->WindowTransparency; SetupImGuiStyle(); @@ -387,7 +391,7 @@ internal static unsafe nint ImGuiRender() io.DisplaySize = _viewportSize; if (_showMenu) - ImGui.GetStyle().Alpha = anyFocused ? 1.0f : 0.5f; + ImGui.GetStyle().Alpha = anyFocused ? _baseAlpha : Math.Max(_baseAlpha - 0.5f, 0.25f); ImGui.NewFrame(); if (_showMenu) @@ -398,6 +402,13 @@ internal static unsafe nint ImGuiRender() { if (ImGui.BeginMenu("Options")) { + ImGui.Checkbox("Draw Primitives as Wireframe", + ref MemoryUtil.AsRef(_renderingOptionPointers.DrawPrimitivesAsWireframe)); + + ImGui.SliderFloat("Line Thickness", + ref MemoryUtil.AsRef(_renderingOptionPointers.LineThickness), + 1.0f, 10.0f); + bool keyboardNav = (io.ConfigFlags & ImGuiConfigFlags.NavEnableKeyboard) != 0; if (ImGui.Checkbox("Keyboard Navigation", ref keyboardNav)) { @@ -411,14 +422,16 @@ internal static unsafe nint ImGuiRender() } } - ImGui.Checkbox("Draw Primitives as Wireframe", - ref MemoryUtil.AsRef(_renderingOptionPointers.DrawPrimitivesAsWireframe)); - - ImGui.SliderFloat("Line Thickness", - ref MemoryUtil.AsRef(_renderingOptionPointers.LineThickness), - 1.0f, 10.0f); + ImGui.SliderFloat("Font Scale", + ref io.FontGlobalScale, + 0.5f, 2.0f, null, ImGuiSliderFlags.NoRoundToFormat); - ImGui.SliderFloat("Font Scale", ref io.FontGlobalScale, 0.5f, 2.0f); + if (ImGui.SliderFloat("Window Transparency", + ref _baseAlpha, + 0.25f, 1.0f, null, ImGuiSliderFlags.NoRoundToFormat)) + { + ImGui.GetStyle().DisabledAlpha = _baseAlpha; + } ImGui.EndMenu(); } @@ -485,8 +498,8 @@ private static void SetupImGuiStyle() { var style = ImGui.GetStyle(); - style.Alpha = 1.0f; - style.DisabledAlpha = 1.0f; + style.Alpha = _baseAlpha; + style.DisabledAlpha = _baseAlpha; style.WindowPadding = new Vector2(12.0f, 12.0f); style.WindowRounding = 2.0f; style.WindowBorderSize = 1.0f; @@ -607,6 +620,7 @@ private static nint GetCursorPositionHook(nint app, out Point pos) private static Vector2 _windowSize; private static Vector2 _mousePos; private static Vector2 _mousePosScalingFactor; + private static float _baseAlpha = 1.0f; private static bool _fontsSubmitted = false; private static NativeArray CustomFonts; @@ -646,4 +660,13 @@ internal unsafe struct CustomFontNative public ushort* GlyphRanges; public ImFont* Font; } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct LoaderGuiConfig + { + public fixed sbyte MenuKey[(int)Key.MaxNameLength + 1]; + public bool KeyboardNavigation; + public float FontScale; + public float WindowTransparency; + } } diff --git a/mhw-cs-plugin-loader/Config.h b/mhw-cs-plugin-loader/Config.h index 897f4fb..d63254b 100644 --- a/mhw-cs-plugin-loader/Config.h +++ b/mhw-cs-plugin-loader/Config.h @@ -95,4 +95,4 @@ static constexpr const char* SPL_DEFAULT_CHUNK_PATH = "nativePC/plugins/CSharp/L // The path of the address repository cache file static constexpr const char* SPL_ADDRESS_REPOSITORY_CACHE_PATH = "nativePC/plugins/CSharp/Loader/NativeAddressCache.json"; -} \ No newline at end of file +} diff --git a/mhw-cs-plugin-loader/D3DModule.cpp b/mhw-cs-plugin-loader/D3DModule.cpp index 4f78de1..8c96465 100644 --- a/mhw-cs-plugin-loader/D3DModule.cpp +++ b/mhw-cs-plugin-loader/D3DModule.cpp @@ -44,7 +44,7 @@ void D3DModule::initialize(CoreClr* coreclr) { L"SharpPluginLoader.Core.Rendering.Renderer", L"ImGuiRender" ); - m_core_initialize_imgui = coreclr->get_method( + m_core_initialize_imgui = coreclr->get_method( config::SPL_CORE_ASSEMBLY_NAME, L"SharpPluginLoader.Core.Rendering.Renderer", L"Initialize" @@ -493,7 +493,7 @@ void D3DModule::d3d12_initialize_imgui(IDXGISwapChain* swap_chain) { }; const auto& config = preloader::LoaderConfig::get(); - const auto context = m_core_initialize_imgui(viewport_size, window_size, true, config.get_menu_key().c_str()); + const auto context = m_core_initialize_imgui(viewport_size, window_size, true, config.get_gui_config()); igSetCurrentContext(context); @@ -626,7 +626,7 @@ void D3DModule::d3d11_initialize_imgui(IDXGISwapChain* swap_chain) { }; const auto& config = preloader::LoaderConfig::get(); - const auto context = m_core_initialize_imgui(viewport_size, window_size, false, config.get_menu_key().c_str()); + const auto context = m_core_initialize_imgui(viewport_size, window_size, false, config.get_gui_config()); igSetCurrentContext(context); imgui_load_fonts(); diff --git a/mhw-cs-plugin-loader/D3DModule.h b/mhw-cs-plugin-loader/D3DModule.h index 5e89755..1fdc41d 100644 --- a/mhw-cs-plugin-loader/D3DModule.h +++ b/mhw-cs-plugin-loader/D3DModule.h @@ -2,6 +2,7 @@ #include "NativeModule.h" #include "TextureManager.h" #include "PrimitiveRenderingModule.h" +#include "LoaderConfig.h" #include #include @@ -121,7 +122,7 @@ class D3DModule final : public NativeModule { HWND m_temp_window = nullptr; WNDCLASSEX* m_temp_window_class = nullptr; - ImGuiContext*(*m_core_initialize_imgui)(MtSize viewport_size, MtSize window_size, bool d3d12, const char* menu_key) = nullptr; + ImGuiContext*(*m_core_initialize_imgui)(MtSize viewport_size, MtSize window_size, bool d3d12, const preloader::LoaderGuiConfig* config) = nullptr; ImDrawData*(*m_core_imgui_render)() = nullptr; void(*m_core_render)() = nullptr; int(*m_core_get_custom_fonts)(CustomFont** out_fonts) = nullptr; diff --git a/mhw-cs-plugin-loader/LoaderConfig.cpp b/mhw-cs-plugin-loader/LoaderConfig.cpp index a1ff4c9..97c4883 100644 --- a/mhw-cs-plugin-loader/LoaderConfig.cpp +++ b/mhw-cs-plugin-loader/LoaderConfig.cpp @@ -10,16 +10,20 @@ namespace preloader using json = nlohmann::ordered_json; void to_json(json& j, const ConfigFile& c) { - j = json{ + j = json { {"logfile", c.LogFile}, {"logcmd", c.LogCmd}, {"logLevel", c.LogLevel}, {"outputEveryPath", c.OutputEveryPath}, {"enablePluginLoader", c.EnablePluginLoader}, {"SPL", { + {"PreloadDlls", c.PreloadDlls}, {"ImGuiRenderingEnabled", c.ImGuiRenderingEnabled}, {"PrimitiveRenderingEnabled", c.PrimitiveRenderingEnabled}, - {"MenuKey", c.MenuKey}, + {"MenuKey", c.Gui.MenuKey}, + {"KeyboardNavigation", c.Gui.KeyboardNavigation}, + {"FontScale", c.Gui.FontScale}, + {"WindowTransparency", c.Gui.WindowTransparency}, }} }; } @@ -30,49 +34,39 @@ namespace preloader j.at("logLevel").get_to(c.LogLevel); j.at("outputEveryPath").get_to(c.OutputEveryPath); j.at("enablePluginLoader").get_to(c.EnablePluginLoader); - if (j.contains("SPL")) { const json& spl = j.at("SPL"); - spl.at("ImGuiRenderingEnabled").get_to(c.ImGuiRenderingEnabled); - spl.at("PrimitiveRenderingEnabled").get_to(c.PrimitiveRenderingEnabled); - c.MenuKey = spl.value("MenuKey", "F9"); - } - else { - c.ImGuiRenderingEnabled = true; - c.PrimitiveRenderingEnabled = true; + if (spl.contains("PreloadDlls")) + { + spl.at("PreloadDlls").get_to(c.PreloadDlls); + } + c.ImGuiRenderingEnabled = spl.value("ImGuiRenderingEnabled", true); + c.PrimitiveRenderingEnabled = spl.value("PrimitiveRenderingEnabled", true); + std::string keyStr = spl.value("MenuKey", "F9"); + if (keyStr.length() <= sizeof(c.Gui.MenuKey) - 1) { + std::memcpy(c.Gui.MenuKey, keyStr.c_str(), keyStr.length() + 1); + } + c.Gui.KeyboardNavigation = spl.value("KeyboardNavigation", false); + c.Gui.FontScale = spl.value("FontScale", 1.0f); + c.Gui.WindowTransparency = spl.value("WindowTransparency", 1.0f); } } - LoaderConfig& LoaderConfig::get() - { + LoaderConfig& LoaderConfig::get() { static LoaderConfig instance; return instance; } - LoaderConfig::LoaderConfig() - { - // Attempt to load file from disk - if (std::filesystem::exists(config::SPL_LOADER_CONFIG_FILE)) - { + LoaderConfig::LoaderConfig() { + // Attempt to load file from disk. + if (std::filesystem::exists(config::SPL_LOADER_CONFIG_FILE)) { std::ifstream file(config::SPL_LOADER_CONFIG_FILE); json data = json::parse(file); this->config = data.get(); file.close(); } - else - { - // No existing config, create a default and save to disk. - this->config = ConfigFile - { - .LogFile = true, - .LogCmd = true, - .LogLevel = "INFO", - .OutputEveryPath = false, - .EnablePluginLoader = true, - }; - } - // Make sure any new options are added to the config file + // Make sure any new options are added to the config file. std::ofstream outfile(config::SPL_LOADER_CONFIG_FILE); if (outfile.is_open()) { json data = this->config; @@ -80,4 +74,4 @@ namespace preloader outfile.close(); } } -} // namespace preloader \ No newline at end of file +} // namespace preloader diff --git a/mhw-cs-plugin-loader/LoaderConfig.h b/mhw-cs-plugin-loader/LoaderConfig.h index b020475..49015fc 100644 --- a/mhw-cs-plugin-loader/LoaderConfig.h +++ b/mhw-cs-plugin-loader/LoaderConfig.h @@ -3,16 +3,24 @@ namespace preloader { + struct LoaderGuiConfig { + char MenuKey[13] = { "F9" }; + bool KeyboardNavigation = false; + float FontScale = 1.0f; + float WindowTransparency = 1.0f; + }; + struct ConfigFile { - bool LogFile = true; - bool LogCmd = false; - std::string LogLevel = "ERROR"; + bool LogFile = false; + bool LogCmd = true; + std::string LogLevel = "INFO"; bool OutputEveryPath = false; bool EnablePluginLoader = true; struct { + std::vector PreloadDlls = { "dinput8.dll", "dxgi.dll" }; bool ImGuiRenderingEnabled = true; bool PrimitiveRenderingEnabled = true; - std::string MenuKey = "F9"; + LoaderGuiConfig Gui; }; }; void to_json(nlohmann::json& j, const ConfigFile& c); @@ -35,9 +43,10 @@ namespace preloader inline bool get_log_cmd() const { return this->config.LogCmd; } inline std::string get_log_level() const { return this->config.LogLevel; } inline bool get_output_every_path() const { return this->config.OutputEveryPath; } + inline std::vector& get_preload_dlls() { return this->config.PreloadDlls; } inline bool get_enable_plugin_loader() const { return this->config.EnablePluginLoader; } inline bool get_imgui_rendering_enabled() const { return this->config.ImGuiRenderingEnabled; } inline bool get_primitive_rendering_enabled() const { return this->config.PrimitiveRenderingEnabled; } - inline std::string get_menu_key() const { return this->config.MenuKey; } + inline const LoaderGuiConfig* get_gui_config() const { return &this->config.Gui; } }; -} // namespace preloader \ No newline at end of file +} // namespace preloader diff --git a/mhw-cs-plugin-loader/NativePluginFramework.cpp b/mhw-cs-plugin-loader/NativePluginFramework.cpp index 066a078..df7e8f6 100644 --- a/mhw-cs-plugin-loader/NativePluginFramework.cpp +++ b/mhw-cs-plugin-loader/NativePluginFramework.cpp @@ -46,13 +46,13 @@ void NativePluginFramework::trigger_on_mh_main_ctor() { m_managed_functions.TriggerOnMhMainCtor(); } -void NativePluginFramework::run_compatibility_checks() { - // We intentionally force Stracker's Loader to be loaded early so any (native) plugins that - // rely on injecting code via relative calls will be able to find available memory for their hooks. - constexpr auto DINPUT8_PATH = "dinput8.dll"; - - if (std::filesystem::exists(DINPUT8_PATH)) { - (void)LoadLibraryA(DINPUT8_PATH); +// We intentionally force Stracker's Loader to be loaded early so any (native) plugins that +// rely on injecting code via relative calls will be able to find available memory for their hooks. +void NativePluginFramework::preload_dlls(std::vector& dlls) { + for (const auto& dll : dlls) { + if (std::filesystem::exists(dll)) { + (void)LoadLibraryA(dll.c_str()); + } } } diff --git a/mhw-cs-plugin-loader/NativePluginFramework.h b/mhw-cs-plugin-loader/NativePluginFramework.h index 4b12762..5152b61 100644 --- a/mhw-cs-plugin-loader/NativePluginFramework.h +++ b/mhw-cs-plugin-loader/NativePluginFramework.h @@ -33,7 +33,7 @@ class NativePluginFramework { void trigger_on_win_main(); void trigger_on_mh_main_ctor(); - static void run_compatibility_checks(); + static void preload_dlls(std::vector& dlls); static uintptr_t get_repository_address(const char* name); static const char* get_game_revision(); diff --git a/mhw-cs-plugin-loader/Preloader.cpp b/mhw-cs-plugin-loader/Preloader.cpp index c53e474..86d68b0 100644 --- a/mhw-cs-plugin-loader/Preloader.cpp +++ b/mhw-cs-plugin-loader/Preloader.cpp @@ -163,7 +163,8 @@ void hooked_get_system_time_as_file_time(LPFILETIME lpSystemTimeAsFileTime) { } dlog::debug("[Preloader] Resolved address for sMhMain::ctor: 0x{:X}", mhmain_ctor_address); - NativePluginFramework::run_compatibility_checks(); + auto& loader_config = preloader::LoaderConfig::get(); + NativePluginFramework::preload_dlls(loader_config.get_preload_dlls()); // Hook the functions. g_scrt_common_main_hook = safetyhook::create_inline( diff --git a/mhw-cs-plugin-loader/dllmain.cpp b/mhw-cs-plugin-loader/dllmain.cpp index 55aabd9..c291863 100644 --- a/mhw-cs-plugin-loader/dllmain.cpp +++ b/mhw-cs-plugin-loader/dllmain.cpp @@ -11,8 +11,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { // Only load the the mod loader DLL if winmm.dll/ucrtbase.dll has been loaded into the correct process. if (wil::GetModuleFileNameW().contains(L"MonsterHunterWorld.exe")) { auto& loader_config = preloader::LoaderConfig::get(); - if (loader_config.get_enable_plugin_loader()) - { + if (loader_config.get_enable_plugin_loader()) { initialize_preloader(); } }