mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
feat: add wndproc nullref fix
This commit is contained in:
parent
3cf47f7ec4
commit
baad575c53
7 changed files with 112 additions and 3 deletions
|
|
@ -7,6 +7,7 @@ using System.Threading;
|
||||||
|
|
||||||
using Dalamud.Configuration.Internal;
|
using Dalamud.Configuration.Internal;
|
||||||
using Dalamud.Data;
|
using Dalamud.Data;
|
||||||
|
using Dalamud.Fixes;
|
||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
using Dalamud.Game.ClientState;
|
using Dalamud.Game.ClientState;
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
|
|
@ -102,6 +103,10 @@ namespace Dalamud
|
||||||
Service<SigScanner>.Set(new SigScanner(true));
|
Service<SigScanner>.Set(new SigScanner(true));
|
||||||
Service<HookManager>.Set();
|
Service<HookManager>.Set();
|
||||||
|
|
||||||
|
// Initialize game fixes
|
||||||
|
var gameFixes = Service<GameFixes>.Set();
|
||||||
|
gameFixes.Apply();
|
||||||
|
|
||||||
// Initialize FFXIVClientStructs function resolver
|
// Initialize FFXIVClientStructs function resolver
|
||||||
FFXIVClientStructs.Resolver.Initialize();
|
FFXIVClientStructs.Resolver.Initialize();
|
||||||
Log.Information("[T1] FFXIVClientStructs initialized!");
|
Log.Information("[T1] FFXIVClientStructs initialized!");
|
||||||
|
|
@ -347,6 +352,8 @@ namespace Dalamud
|
||||||
Service<Framework>.GetNullable()?.ExplicitDispose();
|
Service<Framework>.GetNullable()?.ExplicitDispose();
|
||||||
Service<ClientState>.GetNullable()?.ExplicitDispose();
|
Service<ClientState>.GetNullable()?.ExplicitDispose();
|
||||||
|
|
||||||
|
Service<GameFixes>.GetNullable()?.ExplicitDispose();
|
||||||
|
|
||||||
this.unloadSignal?.Dispose();
|
this.unloadSignal?.Dispose();
|
||||||
|
|
||||||
Service<WinSockHandlers>.GetNullable()?.Dispose();
|
Service<WinSockHandlers>.GetNullable()?.Dispose();
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ namespace Dalamud
|
||||||
|
|
||||||
var levelSwitch = new LoggingLevelSwitch(LogEventLevel.Verbose);
|
var levelSwitch = new LoggingLevelSwitch(LogEventLevel.Verbose);
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
.WriteTo.Async(a => a.File(logPath))
|
.WriteTo.Async(a => a.File(logPath, fileSizeLimitBytes: null, buffered: false, flushToDiskInterval: TimeSpan.FromSeconds(1)))
|
||||||
.WriteTo.Sink(SerilogEventSink.Instance)
|
.WriteTo.Sink(SerilogEventSink.Instance)
|
||||||
.MinimumLevel.ControlledBy(levelSwitch)
|
.MinimumLevel.ControlledBy(levelSwitch)
|
||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
|
|
|
||||||
43
Dalamud/Fixes/GameFixes.cs
Normal file
43
Dalamud/Fixes/GameFixes.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Dalamud.Fixes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class responsible for executing game fixes.
|
||||||
|
/// </summary>
|
||||||
|
internal class GameFixes : IDisposable
|
||||||
|
{
|
||||||
|
private readonly IGameFix[] fixes =
|
||||||
|
{
|
||||||
|
new WndProcNullRefFix(),
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Apply all game fixes.
|
||||||
|
/// </summary>
|
||||||
|
public void Apply()
|
||||||
|
{
|
||||||
|
foreach (var gameFix in this.fixes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
gameFix.Apply();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Could not apply game fix: {FixName}", gameFix.GetType().FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var disposable in this.fixes.OfType<IDisposable>())
|
||||||
|
{
|
||||||
|
disposable.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
Dalamud/Fixes/IGameFix.cs
Normal file
14
Dalamud/Fixes/IGameFix.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Dalamud.Fixes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base interface to be implemented by game fixes.
|
||||||
|
/// </summary>
|
||||||
|
internal interface IGameFix
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Apply the patch to the game.
|
||||||
|
/// </summary>
|
||||||
|
public void Apply();
|
||||||
|
}
|
||||||
45
Dalamud/Fixes/WndProcNullRefFix.cs
Normal file
45
Dalamud/Fixes/WndProcNullRefFix.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
using System;
|
||||||
|
using Dalamud.Game;
|
||||||
|
using Dalamud.Hooking;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Dalamud.Fixes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This fix is for the following issue:
|
||||||
|
/// Null reference in the game's WndProc function when certain window messages arrive
|
||||||
|
/// before an object on the game's input manager is initialized.
|
||||||
|
/// </summary>
|
||||||
|
internal class WndProcNullRefFix : IGameFix, IDisposable
|
||||||
|
{
|
||||||
|
private AsmHook? wndProcHook;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Apply()
|
||||||
|
{
|
||||||
|
var sigScanner = Service<SigScanner>.Get();
|
||||||
|
|
||||||
|
if (!sigScanner.TryScanText("E8 ?? ?? ?? ?? 48 83 38 00 74 14", out var patchAddress))
|
||||||
|
{
|
||||||
|
Log.Error("Failed to find WndProc patch address");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Information($"Applying WndProcNullRefFix at {patchAddress:X}");
|
||||||
|
|
||||||
|
var patchAsm = new byte[]
|
||||||
|
{
|
||||||
|
0x48, 0x85, 0xc0, // test rax, rax
|
||||||
|
0x74, 0x15, // jz +0x1A
|
||||||
|
};
|
||||||
|
|
||||||
|
this.wndProcHook = new AsmHook(patchAddress, patchAsm, "WndProcNullRefFix");
|
||||||
|
this.wndProcHook.Enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
this.wndProcHook?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
using Dalamud.Game.ClientState.Keys;
|
using Dalamud.Game.ClientState.Keys;
|
||||||
using Dalamud.Game.Gui.Internal;
|
using Dalamud.Game.Gui.Internal;
|
||||||
using Dalamud.Interface.Colors;
|
|
||||||
using Dalamud.Interface.Windowing;
|
using Dalamud.Interface.Windowing;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ namespace Dalamud.Plugin
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether Dalamud is running in Debug mode or the /xldev menu is open. This can occur on release builds.
|
/// Gets a value indicating whether Dalamud is running in Debug mode or the /xldev menu is open. This can occur on release builds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsDevMenuOpen => Service<DalamudInterface>.GetNullable() is {IsDevMenuOpen: true}; // Can be null during boot
|
public bool IsDevMenuOpen => Service<DalamudInterface>.GetNullable() is { IsDevMenuOpen: true }; // Can be null during boot
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether a debugger is attached.
|
/// Gets a value indicating whether a debugger is attached.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue