mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
feat: delay main thread continuation until GameFixes are applied
This is a temporary workaround until we have infrastructure to intercept winapi in C++
This commit is contained in:
parent
28102b405b
commit
d2335274ee
8 changed files with 67 additions and 18 deletions
|
|
@ -59,7 +59,7 @@ bool is_full_dumps()
|
||||||
return check_env_var("DALAMUD_IS_VEH_FULL");
|
return check_env_var("DALAMUD_IS_VEH_FULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
DllExport DWORD WINAPI Initialize(LPVOID lpParam)
|
DllExport DWORD WINAPI Initialize(LPVOID lpParam, HANDLE hMainThreadContinue)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
ConsoleSetup(L"Dalamud Boot");
|
ConsoleSetup(L"Dalamud Boot");
|
||||||
|
|
@ -97,7 +97,7 @@ DllExport DWORD WINAPI Initialize(LPVOID lpParam)
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
typedef void (CORECLR_DELEGATE_CALLTYPE* custom_component_entry_point_fn)(LPVOID);
|
typedef void (CORECLR_DELEGATE_CALLTYPE* custom_component_entry_point_fn)(LPVOID, HANDLE);
|
||||||
custom_component_entry_point_fn entrypoint_fn = reinterpret_cast<custom_component_entry_point_fn>(entrypoint_vfn);
|
custom_component_entry_point_fn entrypoint_fn = reinterpret_cast<custom_component_entry_point_fn>(entrypoint_vfn);
|
||||||
|
|
||||||
// ============================== VEH ======================================== //
|
// ============================== VEH ======================================== //
|
||||||
|
|
@ -121,7 +121,7 @@ DllExport DWORD WINAPI Initialize(LPVOID lpParam)
|
||||||
// ============================== Dalamud ==================================== //
|
// ============================== Dalamud ==================================== //
|
||||||
|
|
||||||
printf("Initializing Dalamud... ");
|
printf("Initializing Dalamud... ");
|
||||||
entrypoint_fn(lpParam);
|
entrypoint_fn(lpParam, hMainThreadContinue);
|
||||||
printf("Done!\n");
|
printf("Done!\n");
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
|
||||||
DllExport DWORD WINAPI Initialize(LPVOID lpParam);
|
DllExport DWORD WINAPI Initialize(LPVOID lpParam, HANDLE hMainThreadContinue);
|
||||||
|
|
||||||
struct RewrittenEntryPointParameters {
|
struct RewrittenEntryPointParameters {
|
||||||
void* pAllocation;
|
void* pAllocation;
|
||||||
|
|
@ -379,8 +379,9 @@ DllExport void WINAPI RewrittenEntryPoint(RewrittenEntryPointParameters& params)
|
||||||
params.hMainThread = CreateThread(nullptr, 0, [](void* p) -> DWORD {
|
params.hMainThread = CreateThread(nullptr, 0, [](void* p) -> DWORD {
|
||||||
try {
|
try {
|
||||||
std::string loadInfo;
|
std::string loadInfo;
|
||||||
{
|
|
||||||
auto& params = *reinterpret_cast<RewrittenEntryPointParameters*>(p);
|
auto& params = *reinterpret_cast<RewrittenEntryPointParameters*>(p);
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
// Restore original entry point.
|
// Restore original entry point.
|
||||||
// Use WriteProcessMemory instead of memcpy to avoid having to fiddle with VirtualProtect.
|
// Use WriteProcessMemory instead of memcpy to avoid having to fiddle with VirtualProtect.
|
||||||
|
|
@ -390,12 +391,12 @@ DllExport void WINAPI RewrittenEntryPoint(RewrittenEntryPointParameters& params)
|
||||||
loadInfo = params.pLoadInfo;
|
loadInfo = params.pLoadInfo;
|
||||||
|
|
||||||
// Let the game initialize.
|
// Let the game initialize.
|
||||||
SetEvent(params.hMainThreadContinue);
|
//SetEvent(params.hMainThreadContinue);
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_for_game_window();
|
//wait_for_game_window();
|
||||||
|
|
||||||
Initialize(&loadInfo[0]);
|
Initialize(&loadInfo[0], params.hMainThreadContinue);
|
||||||
return 0;
|
return 0;
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
MessageBoxA(nullptr, std::format("Failed to load Dalamud.\n\nError: {}", e.what()).c_str(), "Dalamud.Boot", MB_OK | MB_ICONERROR);
|
MessageBoxA(nullptr, std::format("Failed to load Dalamud.\n\nError: {}", e.what()).c_str(), "Dalamud.Boot", MB_OK | MB_ICONERROR);
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ namespace Dalamud
|
||||||
|
|
||||||
private readonly ManualResetEvent unloadSignal;
|
private readonly ManualResetEvent unloadSignal;
|
||||||
private readonly ManualResetEvent finishUnloadSignal;
|
private readonly ManualResetEvent finishUnloadSignal;
|
||||||
|
private readonly IntPtr mainThreadContinueEvent;
|
||||||
private MonoMod.RuntimeDetour.Hook processMonoHook;
|
private MonoMod.RuntimeDetour.Hook processMonoHook;
|
||||||
private bool hasDisposedPlugins = false;
|
private bool hasDisposedPlugins = false;
|
||||||
|
|
||||||
|
|
@ -61,7 +62,8 @@ namespace Dalamud
|
||||||
/// <param name="loggingLevelSwitch">LoggingLevelSwitch to control Serilog level.</param>
|
/// <param name="loggingLevelSwitch">LoggingLevelSwitch to control Serilog level.</param>
|
||||||
/// <param name="finishSignal">Signal signalling shutdown.</param>
|
/// <param name="finishSignal">Signal signalling shutdown.</param>
|
||||||
/// <param name="configuration">The Dalamud configuration.</param>
|
/// <param name="configuration">The Dalamud configuration.</param>
|
||||||
public Dalamud(DalamudStartInfo info, LoggingLevelSwitch loggingLevelSwitch, ManualResetEvent finishSignal, DalamudConfiguration configuration)
|
/// <param name="mainThreadContinueEvent">Event used to signal the main thread to continue.</param>
|
||||||
|
public Dalamud(DalamudStartInfo info, LoggingLevelSwitch loggingLevelSwitch, ManualResetEvent finishSignal, DalamudConfiguration configuration, IntPtr mainThreadContinueEvent)
|
||||||
{
|
{
|
||||||
this.ApplyProcessPatch();
|
this.ApplyProcessPatch();
|
||||||
|
|
||||||
|
|
@ -76,6 +78,8 @@ namespace Dalamud
|
||||||
|
|
||||||
this.finishUnloadSignal = finishSignal;
|
this.finishUnloadSignal = finishSignal;
|
||||||
this.finishUnloadSignal.Reset();
|
this.finishUnloadSignal.Reset();
|
||||||
|
|
||||||
|
this.mainThreadContinueEvent = mainThreadContinueEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -107,6 +111,13 @@ namespace Dalamud
|
||||||
var gameFixes = Service<GameFixes>.Set();
|
var gameFixes = Service<GameFixes>.Set();
|
||||||
gameFixes.Apply();
|
gameFixes.Apply();
|
||||||
|
|
||||||
|
Log.Information("[T1] GameFixes OK!");
|
||||||
|
|
||||||
|
// Signal the main game thread to continue
|
||||||
|
NativeFunctions.SetEvent(this.mainThreadContinueEvent);
|
||||||
|
|
||||||
|
Log.Information("[T1] Game thread continued!");
|
||||||
|
|
||||||
// Initialize FFXIVClientStructs function resolver
|
// Initialize FFXIVClientStructs function resolver
|
||||||
FFXIVClientStructs.Resolver.Initialize();
|
FFXIVClientStructs.Resolver.Initialize();
|
||||||
Log.Information("[T1] FFXIVClientStructs initialized!");
|
Log.Information("[T1] FFXIVClientStructs initialized!");
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,8 @@ namespace Dalamud
|
||||||
/// A delegate used during initialization of the CLR from Dalamud.Boot.
|
/// A delegate used during initialization of the CLR from Dalamud.Boot.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="infoPtr">Pointer to a serialized <see cref="DalamudStartInfo"/> data.</param>
|
/// <param name="infoPtr">Pointer to a serialized <see cref="DalamudStartInfo"/> data.</param>
|
||||||
public delegate void InitDelegate(IntPtr infoPtr);
|
/// <param name="mainThreadContinueEvent">Event used to signal the main thread to continue.</param>
|
||||||
|
public delegate void InitDelegate(IntPtr infoPtr, IntPtr mainThreadContinueEvent);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A delegate used from VEH handler on exception which CoreCLR will fast fail by default.
|
/// A delegate used from VEH handler on exception which CoreCLR will fast fail by default.
|
||||||
|
|
@ -43,12 +44,13 @@ namespace Dalamud
|
||||||
/// Initialize Dalamud.
|
/// Initialize Dalamud.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="infoPtr">Pointer to a serialized <see cref="DalamudStartInfo"/> data.</param>
|
/// <param name="infoPtr">Pointer to a serialized <see cref="DalamudStartInfo"/> data.</param>
|
||||||
public static void Initialize(IntPtr infoPtr)
|
/// <param name="mainThreadContinueEvent">Event used to signal the main thread to continue.</param>
|
||||||
|
public static void Initialize(IntPtr infoPtr, IntPtr mainThreadContinueEvent)
|
||||||
{
|
{
|
||||||
var infoStr = Marshal.PtrToStringUTF8(infoPtr);
|
var infoStr = Marshal.PtrToStringUTF8(infoPtr);
|
||||||
var info = JsonConvert.DeserializeObject<DalamudStartInfo>(infoStr);
|
var info = JsonConvert.DeserializeObject<DalamudStartInfo>(infoStr);
|
||||||
|
|
||||||
new Thread(() => RunThread(info)).Start();
|
new Thread(() => RunThread(info, mainThreadContinueEvent)).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -106,7 +108,8 @@ namespace Dalamud
|
||||||
/// Initialize all Dalamud subsystems and start running on the main thread.
|
/// Initialize all Dalamud subsystems and start running on the main thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="info">The <see cref="DalamudStartInfo"/> containing information needed to initialize Dalamud.</param>
|
/// <param name="info">The <see cref="DalamudStartInfo"/> containing information needed to initialize Dalamud.</param>
|
||||||
private static void RunThread(DalamudStartInfo info)
|
/// <param name="mainThreadContinueEvent">Event used to signal the main thread to continue.</param>
|
||||||
|
private static void RunThread(DalamudStartInfo info, IntPtr mainThreadContinueEvent)
|
||||||
{
|
{
|
||||||
// Setup logger
|
// Setup logger
|
||||||
var levelSwitch = InitLogging(info.WorkingDirectory);
|
var levelSwitch = InitLogging(info.WorkingDirectory);
|
||||||
|
|
@ -142,11 +145,12 @@ namespace Dalamud
|
||||||
if (!Util.IsLinux())
|
if (!Util.IsLinux())
|
||||||
InitSymbolHandler(info);
|
InitSymbolHandler(info);
|
||||||
|
|
||||||
var dalamud = new Dalamud(info, levelSwitch, finishSignal, configuration);
|
var dalamud = new Dalamud(info, levelSwitch, finishSignal, configuration, mainThreadContinueEvent);
|
||||||
Log.Information("Starting a session..");
|
Log.Information("Starting a session..");
|
||||||
|
|
||||||
// Run session
|
// Run session
|
||||||
dalamud.LoadTier1();
|
dalamud.LoadTier1();
|
||||||
|
|
||||||
dalamud.WaitForUnload();
|
dalamud.WaitForUnload();
|
||||||
|
|
||||||
dalamud.Dispose();
|
dalamud.Dispose();
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,10 @@ internal class WndProcNullRefFix : IGameFix, IDisposable
|
||||||
|
|
||||||
Log.Information($"Applying WndProcNullRefFix at {patchAddress:X} with o1 {this.object1Address:X}, o2 {this.object2Address:X}");
|
Log.Information($"Applying WndProcNullRefFix at {patchAddress:X} with o1 {this.object1Address:X}, o2 {this.object2Address:X}");
|
||||||
|
|
||||||
this.wndProcHook = new Hook<WndProcDelegate>(patchAddress, this.WndProcDetour);
|
this.wndProcHook = new Hook<WndProcDelegate>(patchAddress, this.WndProcDetour, true);
|
||||||
|
Log.Information("Set up hook");
|
||||||
this.wndProcHook.Enable();
|
this.wndProcHook.Enable();
|
||||||
|
Log.Information("Enabled hook");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,17 @@
|
||||||
|
|
||||||
|
|
||||||
|
#define BOOT_AGING
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CheapLoc;
|
using CheapLoc;
|
||||||
using Dalamud.Configuration.Internal;
|
using Dalamud.Configuration.Internal;
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
|
|
@ -29,7 +34,6 @@ using ImGuiNET;
|
||||||
using ImGuiScene;
|
using ImGuiScene;
|
||||||
using PInvoke;
|
using PInvoke;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
|
||||||
namespace Dalamud.Interface.Internal
|
namespace Dalamud.Interface.Internal
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -350,10 +354,25 @@ namespace Dalamud.Interface.Internal
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private bool signaledBoot = false;
|
||||||
|
|
||||||
private void OnDraw()
|
private void OnDraw()
|
||||||
{
|
{
|
||||||
this.frameCount++;
|
this.frameCount++;
|
||||||
|
|
||||||
|
#if BOOT_AGING
|
||||||
|
if (this.frameCount > 500 && !this.signaledBoot)
|
||||||
|
{
|
||||||
|
this.signaledBoot = true;
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
using var client = new HttpClient();
|
||||||
|
await client.PostAsync("http://localhost:1415/aging/success", new StringContent(string.Empty));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.DrawHiddenDevMenuOpener();
|
this.DrawHiddenDevMenuOpener();
|
||||||
|
|
|
||||||
|
|
@ -1393,6 +1393,18 @@ namespace Dalamud
|
||||||
WriteCombine = 0x400,
|
WriteCombine = 0x400,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// See https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-setevent
|
||||||
|
/// Sets the specified event object to the signaled state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hEvent">A handle to the event object. The CreateEvent or OpenEvent function returns this handle.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// If the function succeeds, the return value is nonzero.
|
||||||
|
/// If the function fails, the return value is zero. To get extended error information, call GetLastError.
|
||||||
|
/// </returns>
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
public static extern bool SetEvent(IntPtr hEvent);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// See https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-freelibrary.
|
/// See https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-freelibrary.
|
||||||
/// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. When the reference
|
/// Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. When the reference
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ int InitializeClrAndGetEntryPoint(
|
||||||
dotnet_path,
|
dotnet_path,
|
||||||
};
|
};
|
||||||
|
|
||||||
printf("Loading coreclr... ");;
|
printf("Loading coreclr... ");
|
||||||
if ((result = g_clr->load_runtime(runtimeconfig_path, &runtime_parameters)) != 0)
|
if ((result = g_clr->load_runtime(runtimeconfig_path, &runtime_parameters)) != 0)
|
||||||
{
|
{
|
||||||
printf("\nError: Failed to load coreclr (err=%d)\n", result);
|
printf("\nError: Failed to load coreclr (err=%d)\n", result);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue