diff --git a/SharpPluginLoader.Core/InternalCalls.cs b/SharpPluginLoader.Core/InternalCalls.cs index bd81cb2..95831bd 100644 --- a/SharpPluginLoader.Core/InternalCalls.cs +++ b/SharpPluginLoader.Core/InternalCalls.cs @@ -1,6 +1,7 @@  using SharpPluginLoader.Core.Resources; using SharpPluginLoader.Core.Resources.Animation; +using SharpPluginLoader.Core.Rendering; namespace SharpPluginLoader.Core { @@ -41,6 +42,8 @@ internal static unsafe class InternalCalls public static delegate* unmanaged UnloadTexturePtr; public static delegate* unmanaged RegisterTexturePtr; + public static delegate* unmanaged SaveGuiConfigPtr; + public static delegate* unmanaged GetRepositoryAddressPtr; public static delegate* unmanaged GetGameRevisionPtr; #pragma warning restore CS0649 @@ -118,6 +121,8 @@ public static bool TimelineTrack(string label, Span keyFrames, out int se public static nint RegisterTexture(nint texture) => RegisterTexturePtr(texture); + public static void SaveGuiConfig(LoaderGuiConfig* config) => SaveGuiConfigPtr(config); + public static nint GetRepositoryAddress(string name) => GetRepositoryAddressPtr(name); public static string GetGameRevision() diff --git a/SharpPluginLoader.Core/Rendering/Renderer.cs b/SharpPluginLoader.Core/Rendering/Renderer.cs index 39c66fc..345e032 100644 --- a/SharpPluginLoader.Core/Rendering/Renderer.cs +++ b/SharpPluginLoader.Core/Rendering/Renderer.cs @@ -198,22 +198,33 @@ internal static unsafe void ResolveCustomFonts() _fontsSubmitted = true; } + private static unsafe void SaveConfig() + { + LoaderGuiConfig* config = MemoryUtil.Alloc(); + config->MenuKey = Utf8StringMarshaller.ConvertToUnmanaged(_menuKey.ToString()); + var io = ImGui.GetIO(); + config->KeyboardNavigation = (io.ConfigFlags & ImGuiConfigFlags.NavEnableKeyboard) != 0; + config->FontScale = io.FontGlobalScale; + config->WindowTransparency = _baseAlpha; + InternalCalls.SaveGuiConfig(config); + Utf8StringMarshaller.Free(config->MenuKey); + MemoryUtil.Free(config); + } + [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 = Utf8StringMarshaller.ConvertToManaged(config->MenuKey); + if (keyStr != null && 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; + _menuKeyStr = keyStr; + } + else + { + Log.Warn($"Invalid menu key: {keyStr}, falling back to {DefaultMenuKey}"); } _viewportSize = new Vector2(viewportSize.Width, viewportSize.Height); @@ -241,6 +252,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(); @@ -322,6 +340,11 @@ Initializing Renderer with if (Input.IsDown(_menuKey)) { _showMenu = !_showMenu; + if (!_showMenu && _optionsChanged) + { + SaveConfig(); + _optionsChanged = false; + } _waitForRelease = _menuKey; } #if DEBUG @@ -387,7 +410,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 +421,25 @@ internal static unsafe nint ImGuiRender() { if (ImGui.BeginMenu("Options")) { + Key parsedKey; + bool typedKeyValid = Enum.TryParse(_menuKeyStr, true, out parsedKey); + if (!typedKeyValid) + { + ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF); + } + if (ImGui.InputText("Menu Key", ref _menuKeyStr, 12, ImGuiInputTextFlags.EnterReturnsTrue)) + { + if (Enum.TryParse(_menuKeyStr, true, out parsedKey)) + { + _menuKey = parsedKey; + _optionsChanged = true; + } + } + if (!typedKeyValid) + { + ImGui.PopStyleColor(); + } + bool keyboardNav = (io.ConfigFlags & ImGuiConfigFlags.NavEnableKeyboard) != 0; if (ImGui.Checkbox("Keyboard Navigation", ref keyboardNav)) { @@ -409,6 +451,22 @@ internal static unsafe nint ImGuiRender() { io.ConfigFlags &= ~ImGuiConfigFlags.NavEnableKeyboard; } + _optionsChanged = true; + } + + if (ImGui.SliderFloat("Font Scale", + ref io.FontGlobalScale, + 0.5f, 2.0f, null, ImGuiSliderFlags.NoRoundToFormat)) + { + _optionsChanged = true; + } + + if (ImGui.SliderFloat("Window Transparency", + ref _baseAlpha, + 0.25f, 1.0f, null, ImGuiSliderFlags.NoRoundToFormat)) + { + ImGui.GetStyle().DisabledAlpha = _baseAlpha; + _optionsChanged = true; } ImGui.Checkbox("Draw Primitives as Wireframe", @@ -418,16 +476,15 @@ internal static unsafe nint ImGuiRender() ref MemoryUtil.AsRef(_renderingOptionPointers.LineThickness), 1.0f, 10.0f); - ImGui.SliderFloat("Font Scale", ref io.FontGlobalScale, 0.5f, 2.0f); - ImGui.EndMenu(); } - ImGui.EndMenuBar(); - - if (ImGui.IsItemDeactivated()) + else if (_optionsChanged) { - // TODO: Save settings + SaveConfig(); + _optionsChanged = false; } + + ImGui.EndMenuBar(); } foreach (var plugin in PluginManager.Instance.GetPlugins(pluginData => pluginData.OnImGuiRender)) @@ -485,8 +542,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; @@ -598,11 +655,14 @@ private static nint GetCursorPositionHook(nint app, out Point pos) private static Key? _waitForRelease = null; private static bool _showMenu = false; private static Key _menuKey = DefaultMenuKey; + private static string _menuKeyStr = DefaultMenuKey.ToString(); #if DEBUG private static bool _showDemo = false; private static Key _demoKey = DefaultDemoKey; #endif + private static float _baseAlpha = 1.0f; private static RenderingOptionPointers _renderingOptionPointers; + private static bool _optionsChanged = false; private static Vector2 _viewportSize; private static Vector2 _windowSize; private static Vector2 _mousePos; @@ -646,4 +706,13 @@ internal unsafe struct CustomFontNative public ushort* GlyphRanges; public ImFont* Font; } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct LoaderGuiConfig + { + public byte* MenuKey; + public bool KeyboardNavigation; + public float FontScale; + public float WindowTransparency; + } } diff --git a/mhw-cs-plugin-loader/AddressRepository.cpp b/mhw-cs-plugin-loader/AddressRepository.cpp index 41a0dfc..7123480 100644 --- a/mhw-cs-plugin-loader/AddressRepository.cpp +++ b/mhw-cs-plugin-loader/AddressRepository.cpp @@ -10,10 +10,9 @@ #include "Config.h" #include "Log.h" #include "PatternScan.h" +#include "Json.h" -#include #include "picosha2/picosha2.h" -using json = nlohmann::json; std::unordered_map scan_for_address_records(json records_json); std::string get_game_revision(); @@ -25,8 +24,9 @@ void AddressRepository::initialize() { auto& contents_raw = address_records->Contents; std::string contents(contents_raw.begin(), contents_raw.end()); - // Parse the json - json records_json = json::parse(contents); + // Parse the json. + json records_json = json::parse(contents, nullptr, false); + assert(!records_json.is_discarded()); // Get game version/revision and hash of the current address records json file. std::string game_revision = get_game_revision(); 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..d5a643c 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" @@ -71,6 +71,8 @@ void D3DModule::initialize(CoreClr* coreclr) { coreclr->add_internal_call("LoadTexture", (void*)load_texture); coreclr->add_internal_call("UnloadTexture", (void*)unload_texture); coreclr->add_internal_call("RegisterTexture", (void*)register_texture); + + coreclr->add_internal_call("SaveGuiConfig", preloader::LoaderConfig::save_gui_config); } void D3DModule::shutdown() { @@ -493,7 +495,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 +628,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/Json.h b/mhw-cs-plugin-loader/Json.h new file mode 100644 index 0000000..74bfe01 --- /dev/null +++ b/mhw-cs-plugin-loader/Json.h @@ -0,0 +1,6 @@ +#pragma once + +#define JSON_NOEXCEPTION 1 +#include + +using json = nlohmann::ordered_json; diff --git a/mhw-cs-plugin-loader/LoaderConfig.cpp b/mhw-cs-plugin-loader/LoaderConfig.cpp index a1ff4c9..edbdb91 100644 --- a/mhw-cs-plugin-loader/LoaderConfig.cpp +++ b/mhw-cs-plugin-loader/LoaderConfig.cpp @@ -4,12 +4,10 @@ #include #include "Config.h" +#include "Json.h" -namespace preloader -{ - using json = nlohmann::ordered_json; - - void to_json(json& j, const ConfigFile& c) { +namespace preloader { + static void to_json(json& j, const ConfigFile& c) { j = json{ {"logfile", c.LogFile}, {"logcmd", c.LogCmd}, @@ -17,67 +15,74 @@ namespace preloader {"outputEveryPath", c.OutputEveryPath}, {"enablePluginLoader", c.EnablePluginLoader}, {"SPL", { + {"PreloadDLLs", c.PreloadDLLs}, {"ImGuiRenderingEnabled", c.ImGuiRenderingEnabled}, {"PrimitiveRenderingEnabled", c.PrimitiveRenderingEnabled}, {"MenuKey", c.MenuKey}, + {"KeyboardNavigation", c.Gui.KeyboardNavigation}, + {"FontScale", c.Gui.FontScale}, + {"WindowTransparency", c.Gui.WindowTransparency}, }} }; } - void from_json(const json& j, ConfigFile& c) { - j.at("logfile").get_to(c.LogFile); - j.at("logcmd").get_to(c.LogCmd); - j.at("logLevel").get_to(c.LogLevel); - j.at("outputEveryPath").get_to(c.OutputEveryPath); - j.at("enablePluginLoader").get_to(c.EnablePluginLoader); - +#define json_try_get(j, key, out) if ((j).contains(key)) { (j).at(key).get_to(out); } + static void from_json(const json& j, ConfigFile& c) { + json_try_get(j, "logfile", c.LogFile); + json_try_get(j, "logcmd", c.LogCmd); + json_try_get(j, "logLevel", c.LogLevel); + json_try_get(j, "outputEveryPath", c.OutputEveryPath); + json_try_get(j, "enablePluginLoader", 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"); + json_try_get(spl, "PreloadDLLs", c.PreloadDLLs); + json_try_get(spl, "ImGuiRenderingEnabled", c.ImGuiRenderingEnabled); + json_try_get(spl, "PrimitiveRenderingEnabled", c.PrimitiveRenderingEnabled); + json_try_get(spl, "MenuKey", c.MenuKey); + json_try_get(spl, "KeyboardNavigation", c.Gui.KeyboardNavigation); + json_try_get(spl, "FontScale", c.Gui.FontScale); + json_try_get(spl, "WindowTransparency", c.Gui.WindowTransparency); } - else { - c.ImGuiRenderingEnabled = true; - c.PrimitiveRenderingEnabled = true; + } +#undef json_try_get + + static void write_config(ConfigFile& c) { + std::ofstream outfile(config::SPL_LOADER_CONFIG_FILE); + if (outfile.is_open()) { + json data = c; + outfile << std::setw(4) << data << "\n"; + outfile.close(); } } - 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)) - { + void LoaderConfig::save_gui_config(LoaderGuiConfig* config) { + ConfigFile& c = get().config; + c.Gui = *config; + c.MenuKey = std::string(c.Gui.UnmanagedMenuKey); + c.Gui.UnmanagedMenuKey = c.MenuKey.c_str(); + write_config(c); + } + + LoaderConfig::LoaderConfig() { + ConfigFile& c = this->config; + + // 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(); + json data = json::parse(file, nullptr, false); + if (!data.is_discarded()) { + data.get_to(c); + } 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, - }; - } + c.Gui.UnmanagedMenuKey = c.MenuKey.c_str(); - // 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; - outfile << std::setw(4) << data << "\n"; - outfile.close(); - } + // Make sure any new options are added to the config file. + write_config(c); } -} // 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..f5ddf5f 100644 --- a/mhw-cs-plugin-loader/LoaderConfig.h +++ b/mhw-cs-plugin-loader/LoaderConfig.h @@ -1,8 +1,16 @@ #pragma once -#include -namespace preloader -{ +#include +#include + +namespace preloader { + struct LoaderGuiConfig { + const char* UnmanagedMenuKey = nullptr; + bool KeyboardNavigation = false; + float FontScale = 1.0f; + float WindowTransparency = 1.0f; + }; + struct ConfigFile { bool LogFile = true; bool LogCmd = false; @@ -10,13 +18,16 @@ namespace preloader bool OutputEveryPath = false; bool EnablePluginLoader = true; struct { + // dinput8(Stracker's Loader): So any (native) plugins that rely on injecting code via + // relative calls will be able to find available memory for their hooks. + // dxgi(ReShade): Allow ReShade to properly hook the game. + 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); - void from_json(const nlohmann::json& j, ConfigFile& c); class LoaderConfig { @@ -33,11 +44,14 @@ namespace preloader inline bool get_log_file() const { return this->config.LogFile; } inline bool get_log_cmd() const { return this->config.LogCmd; } - inline std::string get_log_level() const { return this->config.LogLevel; } + inline const std::string& get_log_level() const { return this->config.LogLevel; } inline bool get_output_every_path() const { return this->config.OutputEveryPath; } + inline const std::vector& get_preload_dlls() const { 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; } + + static void save_gui_config(LoaderGuiConfig* config); }; -} // namespace preloader \ No newline at end of file +} // namespace preloader diff --git a/mhw-cs-plugin-loader/Log.cpp b/mhw-cs-plugin-loader/Log.cpp index ee86b98..6e2e9ab 100644 --- a/mhw-cs-plugin-loader/Log.cpp +++ b/mhw-cs-plugin-loader/Log.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace debug::log::impl { static HANDLE s_console = nullptr; @@ -30,7 +30,7 @@ static void log_raw(LogLevel level, const void* msg, size_t msg_length, const vo if (!s_console) { auto& loader_config = preloader::LoaderConfig::get(); - const auto log_level = loader_config.get_log_level(); + const auto& log_level = loader_config.get_log_level(); s_log_to_cmd = loader_config.get_log_cmd(); if (log_level == "DEBUG") { @@ -109,7 +109,7 @@ void dlog::impl::log(dlog::impl::LogLevel level, const std::string& msg) { const auto time = std::format("[ {:%H:%M:%S} | SPL ] ", std::chrono::system_clock::now()); log_raw(level, msg.c_str(), msg.size(), time.c_str(), time.size(), WriteConsoleA); - + impl::s_file << time << msg << '\n' << std::flush; } diff --git a/mhw-cs-plugin-loader/NativePluginFramework.cpp b/mhw-cs-plugin-loader/NativePluginFramework.cpp index 066a078..7c9adba 100644 --- a/mhw-cs-plugin-loader/NativePluginFramework.cpp +++ b/mhw-cs-plugin-loader/NativePluginFramework.cpp @@ -8,9 +8,6 @@ #include "ImGuiModule.h" #include "PatternScan.h" -#include - - NativePluginFramework::NativePluginFramework(CoreClr* coreclr, AddressRepository* address_repository) : m_managed_functions(coreclr->get_managed_function_pointers()), m_address_repository(address_repository) { @@ -46,16 +43,6 @@ 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); - } -} - uintptr_t NativePluginFramework::get_repository_address(const char* name) { return s_instance->m_address_repository->get(name); } @@ -64,7 +51,7 @@ const char* NativePluginFramework::get_game_revision() { if (s_instance->m_game_revision != nullptr) { return s_instance->m_game_revision; } - + const auto pattern = Pattern::from_string("48 83 EC 48 48 8B 05 ? ? ? ? 4C 8D 0D ? ? ? ? BA 0A 00 00 00"); const auto func = PatternScanner::find_first(pattern); diff --git a/mhw-cs-plugin-loader/NativePluginFramework.h b/mhw-cs-plugin-loader/NativePluginFramework.h index 4b12762..93c768f 100644 --- a/mhw-cs-plugin-loader/NativePluginFramework.h +++ b/mhw-cs-plugin-loader/NativePluginFramework.h @@ -32,8 +32,7 @@ class NativePluginFramework { void trigger_on_pre_main(); void trigger_on_win_main(); void trigger_on_mh_main_ctor(); - - static void run_compatibility_checks(); + static uintptr_t get_repository_address(const char* name); static const char* get_game_revision(); @@ -45,4 +44,3 @@ class NativePluginFramework { static inline NativePluginFramework* s_instance = nullptr; }; - diff --git a/mhw-cs-plugin-loader/Preloader.cpp b/mhw-cs-plugin-loader/Preloader.cpp index c53e474..bca4d64 100644 --- a/mhw-cs-plugin-loader/Preloader.cpp +++ b/mhw-cs-plugin-loader/Preloader.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -94,7 +95,7 @@ __declspec(noinline) void* hooked_mh_main_ctor(void* this_ptr) { // This is needed this cookie setup will happen within various DLLs that are either // loaded as imports, or injected (overlays, anti-malware, etc). // -// 2. Iterate backwards from the return address and check for the default cookie value +// 2. Iterate backwards from the return address and check for the default cookie value. // The default cookie value will be directly embedded in one of the instructions prior // to the GetSystemTimeAsFileTime call, (e.g. `mov rbx, 2B992DDFA232h`). // @@ -163,7 +164,16 @@ 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(); + // Use our position of loading before the game to preload other user-requested + // DLLs that may run into compatibility issues if left to their delay-load order. + auto& loader_config = preloader::LoaderConfig::get(); + for (const auto& path : loader_config.get_preload_dlls()) { + if (std::filesystem::exists(path)) { + if (!LoadLibraryA(path.c_str())) { + dlog::error("[Preloader] Failed to load {} from PreloadDLLs config", path); + } + } + } // 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(); } }