This commit is contained in:
goaaats 2025-06-22 21:39:38 +02:00
commit 95ec633cc5
163 changed files with 7036 additions and 1585 deletions

View file

@ -20,7 +20,7 @@ public sealed class AsmHook : IDisposable, IDalamudHook
private bool isEnabled = false;
private DynamicMethod statsMethod;
private Guid hookId = Guid.NewGuid();
/// <summary>
@ -89,7 +89,7 @@ public sealed class AsmHook : IDisposable, IDalamudHook
}
/// <summary>
/// Gets a value indicating whether or not the hook is enabled.
/// Gets a value indicating whether the hook is enabled.
/// </summary>
public bool IsEnabled
{
@ -101,7 +101,7 @@ public sealed class AsmHook : IDisposable, IDalamudHook
}
/// <summary>
/// Gets a value indicating whether or not the hook has been disposed.
/// Gets a value indicating whether the hook has been disposed.
/// </summary>
public bool IsDisposed { get; private set; }

View file

@ -59,12 +59,12 @@ public abstract class Hook<T> : IDalamudHook where T : Delegate
=> this.IsDisposed ? Marshal.GetDelegateForFunctionPointer<T>(this.address) : this.Original;
/// <summary>
/// Gets a value indicating whether or not the hook is enabled.
/// Gets a value indicating whether the hook is enabled.
/// </summary>
public virtual bool IsEnabled => throw new NotImplementedException();
/// <summary>
/// Gets a value indicating whether or not the hook has been disposed.
/// Gets a value indicating whether the hook has been disposed.
/// </summary>
public bool IsDisposed { get; private set; }
@ -90,6 +90,7 @@ public abstract class Hook<T> : IDalamudHook where T : Delegate
/// <summary>
/// Starts intercepting a call to the function.
/// </summary>
/// <exception cref="ObjectDisposedException">Hook is already disposed.</exception>
public virtual void Enable() => throw new NotImplementedException();
/// <summary>

View file

@ -11,12 +11,12 @@ public interface IDalamudHook : IDisposable
public IntPtr Address { get; }
/// <summary>
/// Gets a value indicating whether or not the hook is enabled.
/// Gets a value indicating whether the hook is enabled.
/// </summary>
public bool IsEnabled { get; }
/// <summary>
/// Gets a value indicating whether or not the hook is disposed.
/// Gets a value indicating whether the hook is disposed.
/// </summary>
public bool IsDisposed { get; }

View file

@ -15,10 +15,10 @@ namespace Dalamud.Hooking.Internal;
/// Only the specific callsite hooked is modified, if the game calls the virtual function from other locations this hook will not be triggered.
/// </summary>
/// <typeparam name="T">Delegate signature for this hook.</typeparam>
internal class CallHook<T> : IDisposable where T : Delegate
internal class CallHook<T> : IDalamudHook where T : Delegate
{
private readonly Reloaded.Hooks.AsmHook asmHook;
private T? detour;
private bool activated;
@ -29,7 +29,10 @@ internal class CallHook<T> : IDisposable where T : Delegate
/// <param name="detour">Delegate to invoke.</param>
internal CallHook(nint address, T detour)
{
ArgumentNullException.ThrowIfNull(detour);
this.detour = detour;
this.Address = address;
var detourPtr = Marshal.GetFunctionPointerForDelegate(this.detour);
var code = new[]
@ -38,22 +41,31 @@ internal class CallHook<T> : IDisposable where T : Delegate
$"mov rax, 0x{detourPtr:X8}",
"call rax",
};
var opt = new AsmHookOptions
{
PreferRelativeJump = true,
Behaviour = Reloaded.Hooks.Definitions.Enums.AsmHookBehaviour.DoNotExecuteOriginal,
MaxOpcodeSize = 5,
};
this.asmHook = new Reloaded.Hooks.AsmHook(code, (nuint)address, opt);
}
/// <summary>
/// Gets a value indicating whether or not the hook is enabled.
/// Gets a value indicating whether the hook is enabled.
/// </summary>
public bool IsEnabled => this.asmHook.IsEnabled;
/// <inheritdoc/>
public IntPtr Address { get; }
/// <inheritdoc/>
public string BackendName => "Reloaded AsmHook";
/// <inheritdoc/>
public bool IsDisposed => this.detour == null;
/// <summary>
/// Starts intercepting a call to the function.
/// </summary>
@ -65,7 +77,7 @@ internal class CallHook<T> : IDisposable where T : Delegate
this.asmHook.Activate();
return;
}
this.asmHook.Enable();
}

View file

@ -116,14 +116,7 @@ internal unsafe class FunctionPointerVariableHook<T> : Hook<T>
}
/// <inheritdoc/>
public override bool IsEnabled
{
get
{
this.CheckDisposed();
return this.enabled;
}
}
public override bool IsEnabled => !this.IsDisposed && this.enabled;
/// <inheritdoc/>
public override string BackendName => "MinHook";
@ -132,9 +125,7 @@ internal unsafe class FunctionPointerVariableHook<T> : Hook<T>
public override void Dispose()
{
if (this.IsDisposed)
{
return;
}
this.Disable();
@ -149,15 +140,13 @@ internal unsafe class FunctionPointerVariableHook<T> : Hook<T>
/// <inheritdoc/>
public override void Enable()
{
this.CheckDisposed();
if (this.enabled)
{
return;
}
lock (HookManager.HookEnableSyncRoot)
{
this.CheckDisposed();
if (this.enabled)
return;
Marshal.WriteIntPtr(this.ppfnThunkJumpTarget, this.pfnDetour);
this.enabled = true;
}
@ -166,15 +155,14 @@ internal unsafe class FunctionPointerVariableHook<T> : Hook<T>
/// <inheritdoc/>
public override void Disable()
{
this.CheckDisposed();
if (!this.enabled)
{
return;
}
lock (HookManager.HookEnableSyncRoot)
{
if (this.IsDisposed)
return;
if (!this.enabled)
return;
Marshal.WriteIntPtr(this.ppfnThunkJumpTarget, this.pfnOriginal);
this.enabled = false;
}

View file

@ -50,14 +50,7 @@ internal class MinHookHook<T> : Hook<T> where T : Delegate
}
/// <inheritdoc/>
public override bool IsEnabled
{
get
{
this.CheckDisposed();
return this.minHookImpl.Enabled;
}
}
public override bool IsEnabled => !this.IsDisposed && this.minHookImpl.Enabled;
/// <inheritdoc/>
public override string BackendName => "MinHook";
@ -84,28 +77,29 @@ internal class MinHookHook<T> : Hook<T> where T : Delegate
/// <inheritdoc/>
public override void Enable()
{
this.CheckDisposed();
if (!this.minHookImpl.Enabled)
lock (HookManager.HookEnableSyncRoot)
{
lock (HookManager.HookEnableSyncRoot)
{
this.minHookImpl.Enable();
}
this.CheckDisposed();
if (!this.minHookImpl.Enabled)
return;
this.minHookImpl.Enable();
}
}
/// <inheritdoc/>
public override void Disable()
{
this.CheckDisposed();
if (this.minHookImpl.Enabled)
lock (HookManager.HookEnableSyncRoot)
{
lock (HookManager.HookEnableSyncRoot)
{
this.minHookImpl.Disable();
}
if (this.IsDisposed)
return;
if (!this.minHookImpl.Enabled)
return;
this.minHookImpl.Disable();
}
}
}

View file

@ -45,14 +45,7 @@ internal class ReloadedHook<T> : Hook<T> where T : Delegate
}
/// <inheritdoc/>
public override bool IsEnabled
{
get
{
this.CheckDisposed();
return this.hookImpl.IsHookEnabled;
}
}
public override bool IsEnabled => !this.IsDisposed && this.hookImpl.IsHookEnabled;
/// <inheritdoc/>
public override string BackendName => "Reloaded";
@ -73,10 +66,10 @@ internal class ReloadedHook<T> : Hook<T> where T : Delegate
/// <inheritdoc/>
public override void Enable()
{
this.CheckDisposed();
lock (HookManager.HookEnableSyncRoot)
{
this.CheckDisposed();
if (!this.hookImpl.IsHookEnabled)
this.hookImpl.Enable();
}
@ -85,10 +78,11 @@ internal class ReloadedHook<T> : Hook<T> where T : Delegate
/// <inheritdoc/>
public override void Disable()
{
this.CheckDisposed();
lock (HookManager.HookEnableSyncRoot)
{
if (this.IsDisposed)
return;
if (!this.hookImpl.IsHookActivated)
return;