chore: convert Dalamud to file-scoped namespaces

This commit is contained in:
goat 2022-10-29 15:23:22 +02:00
parent b093323acc
commit 987ff8dc8f
No known key found for this signature in database
GPG key ID: 49E2AA8C6A76498B
368 changed files with 55081 additions and 55450 deletions

View file

@ -6,126 +6,125 @@ using Dalamud.Configuration.Internal;
#endif
using Serilog;
namespace Dalamud.Game.Internal
namespace Dalamud.Game.Internal;
/// <summary>
/// This class disables anti-debug functionality in the game client.
/// </summary>
[ServiceManager.EarlyLoadedService]
internal sealed partial class AntiDebug : IServiceType
{
/// <summary>
/// This class disables anti-debug functionality in the game client.
/// </summary>
[ServiceManager.EarlyLoadedService]
internal sealed partial class AntiDebug : IServiceType
private readonly byte[] nop = new byte[] { 0x31, 0xC0, 0x90, 0x90, 0x90, 0x90 };
private byte[] original;
private IntPtr debugCheckAddress;
[ServiceManager.ServiceConstructor]
private AntiDebug(SigScanner sigScanner)
{
private readonly byte[] nop = new byte[] { 0x31, 0xC0, 0x90, 0x90, 0x90, 0x90 };
private byte[] original;
private IntPtr debugCheckAddress;
[ServiceManager.ServiceConstructor]
private AntiDebug(SigScanner sigScanner)
try
{
try
{
this.debugCheckAddress = sigScanner.ScanText("FF 15 ?? ?? ?? ?? 85 C0 74 11 41");
}
catch (KeyNotFoundException)
{
this.debugCheckAddress = IntPtr.Zero;
}
this.debugCheckAddress = sigScanner.ScanText("FF 15 ?? ?? ?? ?? 85 C0 74 11 41");
}
catch (KeyNotFoundException)
{
this.debugCheckAddress = IntPtr.Zero;
}
Log.Verbose($"Debug check address 0x{this.debugCheckAddress.ToInt64():X}");
Log.Verbose($"Debug check address 0x{this.debugCheckAddress.ToInt64():X}");
if (!this.IsEnabled)
{
if (!this.IsEnabled)
{
#if DEBUG
this.Enable();
#else
if (Service<DalamudConfiguration>.Get().IsAntiAntiDebugEnabled)
this.Enable();
if (Service<DalamudConfiguration>.Get().IsAntiAntiDebugEnabled)
this.Enable();
#endif
}
}
/// <summary>
/// Gets a value indicating whether the anti-debugging is enabled.
/// </summary>
public bool IsEnabled { get; private set; } = false;
/// <summary>
/// Enables the anti-debugging by overwriting code in memory.
/// </summary>
public void Enable()
{
this.original = new byte[this.nop.Length];
if (this.debugCheckAddress != IntPtr.Zero && !this.IsEnabled)
{
Log.Information($"Overwriting debug check at 0x{this.debugCheckAddress.ToInt64():X}");
SafeMemory.ReadBytes(this.debugCheckAddress, this.nop.Length, out this.original);
SafeMemory.WriteBytes(this.debugCheckAddress, this.nop);
}
else
{
Log.Information("Debug check already overwritten?");
}
this.IsEnabled = true;
}
/// <summary>
/// Disable the anti-debugging by reverting the overwritten code in memory.
/// </summary>
public void Disable()
{
if (this.debugCheckAddress != IntPtr.Zero && this.original != null)
{
Log.Information($"Reverting debug check at 0x{this.debugCheckAddress.ToInt64():X}");
SafeMemory.WriteBytes(this.debugCheckAddress, this.original);
}
else
{
Log.Information("Debug check was not overwritten?");
}
this.IsEnabled = false;
}
}
/// <summary>
/// Implementing IDisposable.
/// Gets a value indicating whether the anti-debugging is enabled.
/// </summary>
internal sealed partial class AntiDebug : IDisposable
public bool IsEnabled { get; private set; } = false;
/// <summary>
/// Enables the anti-debugging by overwriting code in memory.
/// </summary>
public void Enable()
{
private bool disposed = false;
/// <summary>
/// Finalizes an instance of the <see cref="AntiDebug"/> class.
/// </summary>
~AntiDebug() => this.Dispose(false);
/// <summary>
/// Disposes of managed and unmanaged resources.
/// </summary>
public void Dispose()
this.original = new byte[this.nop.Length];
if (this.debugCheckAddress != IntPtr.Zero && !this.IsEnabled)
{
this.Dispose(true);
GC.SuppressFinalize(this);
Log.Information($"Overwriting debug check at 0x{this.debugCheckAddress.ToInt64():X}");
SafeMemory.ReadBytes(this.debugCheckAddress, this.nop.Length, out this.original);
SafeMemory.WriteBytes(this.debugCheckAddress, this.nop);
}
else
{
Log.Information("Debug check already overwritten?");
}
/// <summary>
/// Disposes of managed and unmanaged resources.
/// </summary>
/// <param name="disposing">If this was disposed through calling Dispose() or from being finalized.</param>
private void Dispose(bool disposing)
this.IsEnabled = true;
}
/// <summary>
/// Disable the anti-debugging by reverting the overwritten code in memory.
/// </summary>
public void Disable()
{
if (this.debugCheckAddress != IntPtr.Zero && this.original != null)
{
if (this.disposed)
return;
if (disposing)
{
// If anti-debug is enabled and is being disposed, odds are either the game is exiting, or Dalamud is being reloaded.
// If it is the latter, there's half a chance a debugger is currently attached. There's no real need to disable the
// check in either situation anyways. However if Dalamud is being reloaded, the sig may fail so may as well undo it.
this.Disable();
}
this.disposed = true;
Log.Information($"Reverting debug check at 0x{this.debugCheckAddress.ToInt64():X}");
SafeMemory.WriteBytes(this.debugCheckAddress, this.original);
}
else
{
Log.Information("Debug check was not overwritten?");
}
this.IsEnabled = false;
}
}
/// <summary>
/// Implementing IDisposable.
/// </summary>
internal sealed partial class AntiDebug : IDisposable
{
private bool disposed = false;
/// <summary>
/// Finalizes an instance of the <see cref="AntiDebug"/> class.
/// </summary>
~AntiDebug() => this.Dispose(false);
/// <summary>
/// Disposes of managed and unmanaged resources.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Disposes of managed and unmanaged resources.
/// </summary>
/// <param name="disposing">If this was disposed through calling Dispose() or from being finalized.</param>
private void Dispose(bool disposing)
{
if (this.disposed)
return;
if (disposing)
{
// If anti-debug is enabled and is being disposed, odds are either the game is exiting, or Dalamud is being reloaded.
// If it is the latter, there's half a chance a debugger is currently attached. There's no real need to disable the
// check in either situation anyways. However if Dalamud is being reloaded, the sig may fail so may as well undo it.
this.Disable();
}
this.disposed = true;
}
}

View file

@ -1,227 +1,226 @@
namespace Dalamud.Game.Internal.DXGI.Definitions
namespace Dalamud.Game.Internal.DXGI.Definitions;
/// <summary>
/// Contains a full list of ID3D11Device functions to be used as an indexer into the DirectX Virtual Function Table entries.
/// </summary>
internal enum ID3D11DeviceVtbl
{
// IUnknown
/// <summary>
/// Contains a full list of ID3D11Device functions to be used as an indexer into the DirectX Virtual Function Table entries.
/// IUnknown::QueryInterface method (unknwn.h).
/// </summary>
internal enum ID3D11DeviceVtbl
{
// IUnknown
QueryInterface = 0,
/// <summary>
/// IUnknown::QueryInterface method (unknwn.h).
/// </summary>
QueryInterface = 0,
/// <summary>
/// IUnknown::AddRef method (unknwn.h).
/// </summary>
AddRef = 1,
/// <summary>
/// IUnknown::AddRef method (unknwn.h).
/// </summary>
AddRef = 1,
/// <summary>
/// IUnknown::Release method (unknwn.h).
/// </summary>
Release = 2,
/// <summary>
/// IUnknown::Release method (unknwn.h).
/// </summary>
Release = 2,
// ID3D11Device
// ID3D11Device
/// <summary>
/// ID3D11Device::CreateBuffer method (d3d11.h).
/// </summary>
CreateBuffer = 3,
/// <summary>
/// ID3D11Device::CreateBuffer method (d3d11.h).
/// </summary>
CreateBuffer = 3,
/// <summary>
/// ID3D11Device::CreateTexture1D method (d3d11.h).
/// </summary>
CreateTexture1D = 4,
/// <summary>
/// ID3D11Device::CreateTexture1D method (d3d11.h).
/// </summary>
CreateTexture1D = 4,
/// <summary>
/// ID3D11Device::CreateTexture2D method (d3d11.h).
/// </summary>
CreateTexture2D = 5,
/// <summary>
/// ID3D11Device::CreateTexture2D method (d3d11.h).
/// </summary>
CreateTexture2D = 5,
/// <summary>
/// ID3D11Device::CreateTexture3D method (d3d11.h).
/// </summary>
CreateTexture3D = 6,
/// <summary>
/// ID3D11Device::CreateTexture3D method (d3d11.h).
/// </summary>
CreateTexture3D = 6,
/// <summary>
/// ID3D11Device::CreateShaderResourceView method (d3d11.h).
/// </summary>
CreateShaderResourceView = 7,
/// <summary>
/// ID3D11Device::CreateShaderResourceView method (d3d11.h).
/// </summary>
CreateShaderResourceView = 7,
/// <summary>
/// ID3D11Device::CreateUnorderedAccessView method (d3d11.h).
/// </summary>
CreateUnorderedAccessView = 8,
/// <summary>
/// ID3D11Device::CreateUnorderedAccessView method (d3d11.h).
/// </summary>
CreateUnorderedAccessView = 8,
/// <summary>
/// ID3D11Device::CreateRenderTargetView method (d3d11.h).
/// </summary>
CreateRenderTargetView = 9,
/// <summary>
/// ID3D11Device::CreateRenderTargetView method (d3d11.h).
/// </summary>
CreateRenderTargetView = 9,
/// <summary>
/// ID3D11Device::CreateDepthStencilView method (d3d11.h).
/// </summary>
CreateDepthStencilView = 10,
/// <summary>
/// ID3D11Device::CreateDepthStencilView method (d3d11.h).
/// </summary>
CreateDepthStencilView = 10,
/// <summary>
/// ID3D11Device::CreateInputLayout method (d3d11.h).
/// </summary>
CreateInputLayout = 11,
/// <summary>
/// ID3D11Device::CreateInputLayout method (d3d11.h).
/// </summary>
CreateInputLayout = 11,
/// <summary>
/// ID3D11Device::CreateVertexShader method (d3d11.h).
/// </summary>
CreateVertexShader = 12,
/// <summary>
/// ID3D11Device::CreateVertexShader method (d3d11.h).
/// </summary>
CreateVertexShader = 12,
/// <summary>
/// ID3D11Device::CreateGeometryShader method (d3d11.h).
/// </summary>
CreateGeometryShader = 13,
/// <summary>
/// ID3D11Device::CreateGeometryShader method (d3d11.h).
/// </summary>
CreateGeometryShader = 13,
/// <summary>
/// ID3D11Device::CreateGeometryShaderWithStreamOutput method (d3d11.h).
/// </summary>
CreateGeometryShaderWithStreamOutput = 14,
/// <summary>
/// ID3D11Device::CreateGeometryShaderWithStreamOutput method (d3d11.h).
/// </summary>
CreateGeometryShaderWithStreamOutput = 14,
/// <summary>
/// ID3D11Device::CreatePixelShader method (d3d11.h).
/// </summary>
CreatePixelShader = 15,
/// <summary>
/// ID3D11Device::CreatePixelShader method (d3d11.h).
/// </summary>
CreatePixelShader = 15,
/// <summary>
/// ID3D11Device::CreateHullShader method (d3d11.h).
/// </summary>
CreateHullShader = 16,
/// <summary>
/// ID3D11Device::CreateHullShader method (d3d11.h).
/// </summary>
CreateHullShader = 16,
/// <summary>
/// ID3D11Device::CreateDomainShader method (d3d11.h).
/// </summary>
CreateDomainShader = 17,
/// <summary>
/// ID3D11Device::CreateDomainShader method (d3d11.h).
/// </summary>
CreateDomainShader = 17,
/// <summary>
/// ID3D11Device::CreateComputeShader method (d3d11.h).
/// </summary>
CreateComputeShader = 18,
/// <summary>
/// ID3D11Device::CreateComputeShader method (d3d11.h).
/// </summary>
CreateComputeShader = 18,
/// <summary>
/// ID3D11Device::CreateClassLinkage method (d3d11.h).
/// </summary>
CreateClassLinkage = 19,
/// <summary>
/// ID3D11Device::CreateClassLinkage method (d3d11.h).
/// </summary>
CreateClassLinkage = 19,
/// <summary>
/// ID3D11Device::CreateBlendState method (d3d11.h).
/// </summary>
CreateBlendState = 20,
/// <summary>
/// ID3D11Device::CreateBlendState method (d3d11.h).
/// </summary>
CreateBlendState = 20,
/// <summary>
/// ID3D11Device::CreateDepthStencilState method (d3d11.h).
/// </summary>
CreateDepthStencilState = 21,
/// <summary>
/// ID3D11Device::CreateDepthStencilState method (d3d11.h).
/// </summary>
CreateDepthStencilState = 21,
/// <summary>
/// ID3D11Device::CreateRasterizerState method (d3d11.h).
/// </summary>
CreateRasterizerState = 22,
/// <summary>
/// ID3D11Device::CreateRasterizerState method (d3d11.h).
/// </summary>
CreateRasterizerState = 22,
/// <summary>
/// ID3D11Device::CreateSamplerState method (d3d11.h).
/// </summary>
CreateSamplerState = 23,
/// <summary>
/// ID3D11Device::CreateSamplerState method (d3d11.h).
/// </summary>
CreateSamplerState = 23,
/// <summary>
/// ID3D11Device::CreateQuery method (d3d11.h).
/// </summary>
CreateQuery = 24,
/// <summary>
/// ID3D11Device::CreateQuery method (d3d11.h).
/// </summary>
CreateQuery = 24,
/// <summary>
/// ID3D11Device::CreatePredicate method (d3d11.h).
/// </summary>
CreatePredicate = 25,
/// <summary>
/// ID3D11Device::CreatePredicate method (d3d11.h).
/// </summary>
CreatePredicate = 25,
/// <summary>
/// ID3D11Device::CreateCounter method (d3d11.h).
/// </summary>
CreateCounter = 26,
/// <summary>
/// ID3D11Device::CreateCounter method (d3d11.h).
/// </summary>
CreateCounter = 26,
/// <summary>
/// ID3D11Device::CreateDeferredContext method (d3d11.h).
/// </summary>
CreateDeferredContext = 27,
/// <summary>
/// ID3D11Device::CreateDeferredContext method (d3d11.h).
/// </summary>
CreateDeferredContext = 27,
/// <summary>
/// ID3D11Device::OpenSharedResource method (d3d11.h).
/// </summary>
OpenSharedResource = 28,
/// <summary>
/// ID3D11Device::OpenSharedResource method (d3d11.h).
/// </summary>
OpenSharedResource = 28,
/// <summary>
/// ID3D11Device::CheckFormatSupport method (d3d11.h).
/// </summary>
CheckFormatSupport = 29,
/// <summary>
/// ID3D11Device::CheckFormatSupport method (d3d11.h).
/// </summary>
CheckFormatSupport = 29,
/// <summary>
/// ID3D11Device::CheckMultisampleQualityLevels method (d3d11.h).
/// </summary>
CheckMultisampleQualityLevels = 30,
/// <summary>
/// ID3D11Device::CheckMultisampleQualityLevels method (d3d11.h).
/// </summary>
CheckMultisampleQualityLevels = 30,
/// <summary>
/// ID3D11Device::CheckCounterInfo method (d3d11.h).
/// </summary>
CheckCounterInfo = 31,
/// <summary>
/// ID3D11Device::CheckCounterInfo method (d3d11.h).
/// </summary>
CheckCounterInfo = 31,
/// <summary>
/// ID3D11Device::CheckCounter method (d3d11.h).
/// </summary>
CheckCounter = 32,
/// <summary>
/// ID3D11Device::CheckCounter method (d3d11.h).
/// </summary>
CheckCounter = 32,
/// <summary>
/// ID3D11Device::CheckFeatureSupport method (d3d11.h).
/// </summary>
CheckFeatureSupport = 33,
/// <summary>
/// ID3D11Device::CheckFeatureSupport method (d3d11.h).
/// </summary>
CheckFeatureSupport = 33,
/// <summary>
/// ID3D11Device::GetPrivateData method (d3d11.h).
/// </summary>
GetPrivateData = 34,
/// <summary>
/// ID3D11Device::GetPrivateData method (d3d11.h).
/// </summary>
GetPrivateData = 34,
/// <summary>
/// ID3D11Device::SetPrivateData method (d3d11.h).
/// </summary>
SetPrivateData = 35,
/// <summary>
/// ID3D11Device::SetPrivateData method (d3d11.h).
/// </summary>
SetPrivateData = 35,
/// <summary>
/// ID3D11Device::SetPrivateDataInterface method (d3d11.h).
/// </summary>
SetPrivateDataInterface = 36,
/// <summary>
/// ID3D11Device::SetPrivateDataInterface method (d3d11.h).
/// </summary>
SetPrivateDataInterface = 36,
/// <summary>
/// ID3D11Device::GetFeatureLevel method (d3d11.h).
/// </summary>
GetFeatureLevel = 37,
/// <summary>
/// ID3D11Device::GetFeatureLevel method (d3d11.h).
/// </summary>
GetFeatureLevel = 37,
/// <summary>
/// ID3D11Device::GetCreationFlags method (d3d11.h).
/// </summary>
GetCreationFlags = 38,
/// <summary>
/// ID3D11Device::GetCreationFlags method (d3d11.h).
/// </summary>
GetCreationFlags = 38,
/// <summary>
/// ID3D11Device::GetDeviceRemovedReason method (d3d11.h).
/// </summary>
GetDeviceRemovedReason = 39,
/// <summary>
/// ID3D11Device::GetDeviceRemovedReason method (d3d11.h).
/// </summary>
GetDeviceRemovedReason = 39,
/// <summary>
/// ID3D11Device::GetImmediateContext method (d3d11.h).
/// </summary>
GetImmediateContext = 40,
/// <summary>
/// ID3D11Device::GetImmediateContext method (d3d11.h).
/// </summary>
GetImmediateContext = 40,
/// <summary>
/// ID3D11Device::SetExceptionMode method (d3d11.h).
/// </summary>
SetExceptionMode = 41,
/// <summary>
/// ID3D11Device::SetExceptionMode method (d3d11.h).
/// </summary>
SetExceptionMode = 41,
/// <summary>
/// ID3D11Device::GetExceptionMode method (d3d11.h).
/// </summary>
GetExceptionMode = 42,
}
/// <summary>
/// ID3D11Device::GetExceptionMode method (d3d11.h).
/// </summary>
GetExceptionMode = 42,
}

View file

@ -1,107 +1,106 @@
namespace Dalamud.Game.Internal.DXGI.Definitions
namespace Dalamud.Game.Internal.DXGI.Definitions;
/// <summary>
/// Contains a full list of IDXGISwapChain functions to be used as an indexer into the SwapChain Virtual Function Table
/// entries.
/// </summary>
internal enum IDXGISwapChainVtbl
{
// IUnknown
/// <summary>
/// Contains a full list of IDXGISwapChain functions to be used as an indexer into the SwapChain Virtual Function Table
/// entries.
/// IUnknown::QueryInterface method (unknwn.h).
/// </summary>
internal enum IDXGISwapChainVtbl
{
// IUnknown
QueryInterface = 0,
/// <summary>
/// IUnknown::QueryInterface method (unknwn.h).
/// </summary>
QueryInterface = 0,
/// <summary>
/// IUnknown::AddRef method (unknwn.h).
/// </summary>
AddRef = 1,
/// <summary>
/// IUnknown::AddRef method (unknwn.h).
/// </summary>
AddRef = 1,
/// <summary>
/// IUnknown::Release method (unknwn.h).
/// </summary>
Release = 2,
/// <summary>
/// IUnknown::Release method (unknwn.h).
/// </summary>
Release = 2,
// IDXGIObject
// IDXGIObject
/// <summary>
/// IDXGIObject::SetPrivateData method (dxgi.h).
/// </summary>
SetPrivateData = 3,
/// <summary>
/// IDXGIObject::SetPrivateData method (dxgi.h).
/// </summary>
SetPrivateData = 3,
/// <summary>
/// IDXGIObject::SetPrivateDataInterface method (dxgi.h).
/// </summary>
SetPrivateDataInterface = 4,
/// <summary>
/// IDXGIObject::SetPrivateDataInterface method (dxgi.h).
/// </summary>
SetPrivateDataInterface = 4,
/// <summary>
/// IDXGIObject::GetPrivateData method (dxgi.h).
/// </summary>
GetPrivateData = 5,
/// <summary>
/// IDXGIObject::GetPrivateData method (dxgi.h).
/// </summary>
GetPrivateData = 5,
/// <summary>
/// IDXGIObject::GetParent method (dxgi.h).
/// </summary>
GetParent = 6,
/// <summary>
/// IDXGIObject::GetParent method (dxgi.h).
/// </summary>
GetParent = 6,
// IDXGIDeviceSubObject
// IDXGIDeviceSubObject
/// <summary>
/// IDXGIDeviceSubObject::GetDevice method (dxgi.h).
/// </summary>
GetDevice = 7,
/// <summary>
/// IDXGIDeviceSubObject::GetDevice method (dxgi.h).
/// </summary>
GetDevice = 7,
// IDXGISwapChain
// IDXGISwapChain
/// <summary>
/// IDXGISwapChain::Present method (dxgi.h).
/// </summary>
Present = 8,
/// <summary>
/// IDXGISwapChain::Present method (dxgi.h).
/// </summary>
Present = 8,
/// <summary>
/// IUnknIDXGISwapChainown::GetBuffer method (dxgi.h).
/// </summary>
GetBuffer = 9,
/// <summary>
/// IUnknIDXGISwapChainown::GetBuffer method (dxgi.h).
/// </summary>
GetBuffer = 9,
/// <summary>
/// IDXGISwapChain::SetFullscreenState method (dxgi.h).
/// </summary>
SetFullscreenState = 10,
/// <summary>
/// IDXGISwapChain::SetFullscreenState method (dxgi.h).
/// </summary>
SetFullscreenState = 10,
/// <summary>
/// IDXGISwapChain::GetFullscreenState method (dxgi.h).
/// </summary>
GetFullscreenState = 11,
/// <summary>
/// IDXGISwapChain::GetFullscreenState method (dxgi.h).
/// </summary>
GetFullscreenState = 11,
/// <summary>
/// IDXGISwapChain::GetDesc method (dxgi.h).
/// </summary>
GetDesc = 12,
/// <summary>
/// IDXGISwapChain::GetDesc method (dxgi.h).
/// </summary>
GetDesc = 12,
/// <summary>
/// IDXGISwapChain::ResizeBuffers method (dxgi.h).
/// </summary>
ResizeBuffers = 13,
/// <summary>
/// IDXGISwapChain::ResizeBuffers method (dxgi.h).
/// </summary>
ResizeBuffers = 13,
/// <summary>
/// IDXGISwapChain::ResizeTarget method (dxgi.h).
/// </summary>
ResizeTarget = 14,
/// <summary>
/// IDXGISwapChain::ResizeTarget method (dxgi.h).
/// </summary>
ResizeTarget = 14,
/// <summary>
/// IDXGISwapChain::GetContainingOutput method (dxgi.h).
/// </summary>
GetContainingOutput = 15,
/// <summary>
/// IDXGISwapChain::GetContainingOutput method (dxgi.h).
/// </summary>
GetContainingOutput = 15,
/// <summary>
/// IDXGISwapChain::GetFrameStatistics method (dxgi.h).
/// </summary>
GetFrameStatistics = 16,
/// <summary>
/// IDXGISwapChain::GetFrameStatistics method (dxgi.h).
/// </summary>
GetFrameStatistics = 16,
/// <summary>
/// IDXGISwapChain::GetLastPresentCount method (dxgi.h).
/// </summary>
GetLastPresentCount = 17,
}
/// <summary>
/// IDXGISwapChain::GetLastPresentCount method (dxgi.h).
/// </summary>
GetLastPresentCount = 17,
}

View file

@ -1,20 +1,19 @@
using System;
namespace Dalamud.Game.Internal.DXGI
namespace Dalamud.Game.Internal.DXGI;
/// <summary>
/// An interface binding for the address resolvers that attempt to find native D3D11 methods.
/// </summary>
public interface ISwapChainAddressResolver
{
/// <summary>
/// An interface binding for the address resolvers that attempt to find native D3D11 methods.
/// Gets or sets the address of the native D3D11.Present method.
/// </summary>
public interface ISwapChainAddressResolver
{
/// <summary>
/// Gets or sets the address of the native D3D11.Present method.
/// </summary>
IntPtr Present { get; set; }
IntPtr Present { get; set; }
/// <summary>
/// Gets or sets the address of the native D3D11.ResizeBuffers method.
/// </summary>
IntPtr ResizeBuffers { get; set; }
}
/// <summary>
/// Gets or sets the address of the native D3D11.ResizeBuffers method.
/// </summary>
IntPtr ResizeBuffers { get; set; }
}

View file

@ -4,33 +4,32 @@ using System.Linq;
using Serilog;
namespace Dalamud.Game.Internal.DXGI
namespace Dalamud.Game.Internal.DXGI;
/// <summary>
/// The address resolver for native D3D11 methods to facilitate displaying the Dalamud UI.
/// </summary>
[Obsolete("This has been deprecated in favor of the VTable resolver.")]
public sealed class SwapChainSigResolver : BaseAddressResolver, ISwapChainAddressResolver
{
/// <summary>
/// The address resolver for native D3D11 methods to facilitate displaying the Dalamud UI.
/// </summary>
[Obsolete("This has been deprecated in favor of the VTable resolver.")]
public sealed class SwapChainSigResolver : BaseAddressResolver, ISwapChainAddressResolver
/// <inheritdoc/>
public IntPtr Present { get; set; }
/// <inheritdoc/>
public IntPtr ResizeBuffers { get; set; }
/// <inheritdoc/>
protected override void Setup64Bit(SigScanner sig)
{
/// <inheritdoc/>
public IntPtr Present { get; set; }
var module = Process.GetCurrentProcess().Modules.Cast<ProcessModule>().First(m => m.ModuleName == "dxgi.dll");
/// <inheritdoc/>
public IntPtr ResizeBuffers { get; set; }
Log.Debug($"Found DXGI: 0x{module.BaseAddress.ToInt64():X}");
/// <inheritdoc/>
protected override void Setup64Bit(SigScanner sig)
{
var module = Process.GetCurrentProcess().Modules.Cast<ProcessModule>().First(m => m.ModuleName == "dxgi.dll");
var scanner = new SigScanner(module);
Log.Debug($"Found DXGI: 0x{module.BaseAddress.ToInt64():X}");
// This(code after the function head - offset of it) was picked to avoid running into issues with other hooks being installed into this function.
this.Present = scanner.ScanModule("41 8B F0 8B FA 89 54 24 ?? 48 8B D9 48 89 4D ?? C6 44 24 ?? 00") - 0x37;
var scanner = new SigScanner(module);
// This(code after the function head - offset of it) was picked to avoid running into issues with other hooks being installed into this function.
this.Present = scanner.ScanModule("41 8B F0 8B FA 89 54 24 ?? 48 8B D9 48 89 4D ?? C6 44 24 ?? 00") - 0x37;
this.ResizeBuffers = scanner.ScanModule("48 8B C4 55 41 54 41 55 41 56 41 57 48 8D 68 B1 48 81 EC ?? ?? ?? ?? 48 C7 45 ?? ?? ?? ?? ?? 48 89 58 10 48 89 70 18 48 89 78 20 45 8B F9 45 8B E0 44 8B EA 48 8B F9 8B 45 7F 89 44 24 30 8B 75 77 89 74 24 28 44 89 4C 24");
}
this.ResizeBuffers = scanner.ScanModule("48 8B C4 55 41 54 41 55 41 56 41 57 48 8D 68 B1 48 81 EC ?? ?? ?? ?? 48 C7 45 ?? ?? ?? ?? ?? 48 89 58 10 48 89 70 18 48 89 78 20 45 8B F9 45 8B E0 44 8B EA 48 8B F9 8B 45 7F 89 44 24 30 8B 75 77 89 74 24 28 44 89 4C 24");
}
}

View file

@ -7,97 +7,96 @@ using Dalamud.Game.Internal.DXGI.Definitions;
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
using Serilog;
namespace Dalamud.Game.Internal.DXGI
namespace Dalamud.Game.Internal.DXGI;
/// <summary>
/// This class attempts to determine the D3D11 SwapChain vtable addresses via instantiating a new form and inspecting it.
/// </summary>
/// <remarks>
/// If the normal signature based method of resolution fails, this is the backup.
/// </remarks>
public class SwapChainVtableResolver : BaseAddressResolver, ISwapChainAddressResolver
{
/// <inheritdoc/>
public IntPtr Present { get; set; }
/// <inheritdoc/>
public IntPtr ResizeBuffers { get; set; }
/// <summary>
/// This class attempts to determine the D3D11 SwapChain vtable addresses via instantiating a new form and inspecting it.
/// Gets a value indicating whether or not ReShade is loaded/used.
/// </summary>
/// <remarks>
/// If the normal signature based method of resolution fails, this is the backup.
/// </remarks>
public class SwapChainVtableResolver : BaseAddressResolver, ISwapChainAddressResolver
public bool IsReshade { get; private set; }
/// <inheritdoc/>
protected override unsafe void Setup64Bit(SigScanner sig)
{
/// <inheritdoc/>
public IntPtr Present { get; set; }
Device* kernelDev;
SwapChain* swapChain;
void* dxgiSwapChain;
/// <inheritdoc/>
public IntPtr ResizeBuffers { get; set; }
/// <summary>
/// Gets a value indicating whether or not ReShade is loaded/used.
/// </summary>
public bool IsReshade { get; private set; }
/// <inheritdoc/>
protected override unsafe void Setup64Bit(SigScanner sig)
while (true)
{
Device* kernelDev;
SwapChain* swapChain;
void* dxgiSwapChain;
kernelDev = Device.Instance();
if (kernelDev == null)
continue;
while (true)
swapChain = kernelDev->SwapChain;
if (swapChain == null)
continue;
dxgiSwapChain = swapChain->DXGISwapChain;
if (dxgiSwapChain == null)
continue;
break;
}
var scVtbl = GetVTblAddresses(new IntPtr(dxgiSwapChain), Enum.GetValues(typeof(IDXGISwapChainVtbl)).Length);
this.Present = scVtbl[(int)IDXGISwapChainVtbl.Present];
var modules = Process.GetCurrentProcess().Modules;
foreach (ProcessModule processModule in modules)
{
if (processModule.FileName != null && processModule.FileName.EndsWith("game\\dxgi.dll"))
{
kernelDev = Device.Instance();
if (kernelDev == null)
continue;
// reshade master@4232872 RVA
// var p = processModule.BaseAddress + 0x82C7E0; // DXGISwapChain::Present
// var p = processModule.BaseAddress + 0x82FAC0; // DXGISwapChain::runtime_present
swapChain = kernelDev->SwapChain;
if (swapChain == null)
continue;
dxgiSwapChain = swapChain->DXGISwapChain;
if (dxgiSwapChain == null)
continue;
break;
}
var scVtbl = GetVTblAddresses(new IntPtr(dxgiSwapChain), Enum.GetValues(typeof(IDXGISwapChainVtbl)).Length);
this.Present = scVtbl[(int)IDXGISwapChainVtbl.Present];
var modules = Process.GetCurrentProcess().Modules;
foreach (ProcessModule processModule in modules)
{
if (processModule.FileName != null && processModule.FileName.EndsWith("game\\dxgi.dll"))
var scanner = new SigScanner(processModule);
try
{
// reshade master@4232872 RVA
// var p = processModule.BaseAddress + 0x82C7E0; // DXGISwapChain::Present
// var p = processModule.BaseAddress + 0x82FAC0; // DXGISwapChain::runtime_present
var p = scanner.ScanText("F6 C2 01 0F 85 ?? ?? ?? ??");
Log.Information($"ReShade DLL: {processModule.FileName} with DXGISwapChain::runtime_present at {p:X}");
var scanner = new SigScanner(processModule);
try
{
var p = scanner.ScanText("F6 C2 01 0F 85 ?? ?? ?? ??");
Log.Information($"ReShade DLL: {processModule.FileName} with DXGISwapChain::runtime_present at {p:X}");
this.Present = p;
this.IsReshade = true;
break;
}
catch (Exception ex)
{
Log.Error(ex, "Could not find reshade DXGISwapChain::runtime_present offset!");
}
this.Present = p;
this.IsReshade = true;
break;
}
catch (Exception ex)
{
Log.Error(ex, "Could not find reshade DXGISwapChain::runtime_present offset!");
}
}
this.ResizeBuffers = scVtbl[(int)IDXGISwapChainVtbl.ResizeBuffers];
}
private static List<IntPtr> GetVTblAddresses(IntPtr pointer, int numberOfMethods)
{
return GetVTblAddresses(pointer, 0, numberOfMethods);
}
this.ResizeBuffers = scVtbl[(int)IDXGISwapChainVtbl.ResizeBuffers];
}
private static List<IntPtr> GetVTblAddresses(IntPtr pointer, int startIndex, int numberOfMethods)
{
var vtblAddresses = new List<IntPtr>();
var vTable = Marshal.ReadIntPtr(pointer);
for (var i = startIndex; i < startIndex + numberOfMethods; i++)
vtblAddresses.Add(Marshal.ReadIntPtr(vTable, i * IntPtr.Size)); // using IntPtr.Size allows us to support both 32 and 64-bit processes
private static List<IntPtr> GetVTblAddresses(IntPtr pointer, int numberOfMethods)
{
return GetVTblAddresses(pointer, 0, numberOfMethods);
}
return vtblAddresses;
}
private static List<IntPtr> GetVTblAddresses(IntPtr pointer, int startIndex, int numberOfMethods)
{
var vtblAddresses = new List<IntPtr>();
var vTable = Marshal.ReadIntPtr(pointer);
for (var i = startIndex; i < startIndex + numberOfMethods; i++)
vtblAddresses.Add(Marshal.ReadIntPtr(vTable, i * IntPtr.Size)); // using IntPtr.Size allows us to support both 32 and 64-bit processes
return vtblAddresses;
}
}

View file

@ -14,265 +14,264 @@ using Serilog;
using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
namespace Dalamud.Game.Internal
namespace Dalamud.Game.Internal;
/// <summary>
/// This class implements in-game Dalamud options in the in-game System menu.
/// </summary>
[ServiceManager.EarlyLoadedService]
internal sealed unsafe partial class DalamudAtkTweaks : IServiceType
{
/// <summary>
/// This class implements in-game Dalamud options in the in-game System menu.
/// </summary>
[ServiceManager.EarlyLoadedService]
internal sealed unsafe partial class DalamudAtkTweaks : IServiceType
private readonly AtkValueChangeType atkValueChangeType;
private readonly AtkValueSetString atkValueSetString;
private readonly Hook<AgentHudOpenSystemMenuPrototype> hookAgentHudOpenSystemMenu;
// TODO: Make this into events in Framework.Gui
private readonly Hook<UiModuleRequestMainCommand> hookUiModuleRequestMainCommand;
private readonly Hook<AtkUnitBaseReceiveGlobalEvent> hookAtkUnitBaseReceiveGlobalEvent;
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
// [ServiceManager.ServiceDependency]
// private readonly ContextMenu contextMenu = Service<ContextMenu>.Get();
private readonly string locDalamudPlugins;
private readonly string locDalamudSettings;
[ServiceManager.ServiceConstructor]
private DalamudAtkTweaks(SigScanner sigScanner)
{
private readonly AtkValueChangeType atkValueChangeType;
private readonly AtkValueSetString atkValueSetString;
private readonly Hook<AgentHudOpenSystemMenuPrototype> hookAgentHudOpenSystemMenu;
var openSystemMenuAddress = sigScanner.ScanText("E8 ?? ?? ?? ?? 32 C0 4C 8B AC 24 ?? ?? ?? ?? 48 8B 8D ?? ?? ?? ??");
// TODO: Make this into events in Framework.Gui
private readonly Hook<UiModuleRequestMainCommand> hookUiModuleRequestMainCommand;
this.hookAgentHudOpenSystemMenu = Hook<AgentHudOpenSystemMenuPrototype>.FromAddress(openSystemMenuAddress, this.AgentHudOpenSystemMenuDetour);
private readonly Hook<AtkUnitBaseReceiveGlobalEvent> hookAtkUnitBaseReceiveGlobalEvent;
var atkValueChangeTypeAddress = sigScanner.ScanText("E8 ?? ?? ?? ?? 45 84 F6 48 8D 4C 24 ??");
this.atkValueChangeType = Marshal.GetDelegateForFunctionPointer<AtkValueChangeType>(atkValueChangeTypeAddress);
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service<DalamudConfiguration>.Get();
var atkValueSetStringAddress = sigScanner.ScanText("E8 ?? ?? ?? ?? 41 03 ED");
this.atkValueSetString = Marshal.GetDelegateForFunctionPointer<AtkValueSetString>(atkValueSetStringAddress);
// [ServiceManager.ServiceDependency]
// private readonly ContextMenu contextMenu = Service<ContextMenu>.Get();
var uiModuleRequestMainCommandAddress = sigScanner.ScanText("40 53 56 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B 01 8B DA 48 8B F1 FF 90 ?? ?? ?? ??");
this.hookUiModuleRequestMainCommand = Hook<UiModuleRequestMainCommand>.FromAddress(uiModuleRequestMainCommandAddress, this.UiModuleRequestMainCommandDetour);
private readonly string locDalamudPlugins;
private readonly string locDalamudSettings;
var atkUnitBaseReceiveGlobalEventAddress = sigScanner.ScanText("48 89 5C 24 ?? 48 89 7C 24 ?? 55 41 56 41 57 48 8B EC 48 83 EC 50 44 0F B7 F2 ");
this.hookAtkUnitBaseReceiveGlobalEvent = Hook<AtkUnitBaseReceiveGlobalEvent>.FromAddress(atkUnitBaseReceiveGlobalEventAddress, this.AtkUnitBaseReceiveGlobalEventDetour);
[ServiceManager.ServiceConstructor]
private DalamudAtkTweaks(SigScanner sigScanner)
{
var openSystemMenuAddress = sigScanner.ScanText("E8 ?? ?? ?? ?? 32 C0 4C 8B AC 24 ?? ?? ?? ?? 48 8B 8D ?? ?? ?? ??");
this.locDalamudPlugins = Loc.Localize("SystemMenuPlugins", "Dalamud Plugins");
this.locDalamudSettings = Loc.Localize("SystemMenuSettings", "Dalamud Settings");
this.hookAgentHudOpenSystemMenu = Hook<AgentHudOpenSystemMenuPrototype>.FromAddress(openSystemMenuAddress, this.AgentHudOpenSystemMenuDetour);
var atkValueChangeTypeAddress = sigScanner.ScanText("E8 ?? ?? ?? ?? 45 84 F6 48 8D 4C 24 ??");
this.atkValueChangeType = Marshal.GetDelegateForFunctionPointer<AtkValueChangeType>(atkValueChangeTypeAddress);
var atkValueSetStringAddress = sigScanner.ScanText("E8 ?? ?? ?? ?? 41 03 ED");
this.atkValueSetString = Marshal.GetDelegateForFunctionPointer<AtkValueSetString>(atkValueSetStringAddress);
var uiModuleRequestMainCommandAddress = sigScanner.ScanText("40 53 56 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B 01 8B DA 48 8B F1 FF 90 ?? ?? ?? ??");
this.hookUiModuleRequestMainCommand = Hook<UiModuleRequestMainCommand>.FromAddress(uiModuleRequestMainCommandAddress, this.UiModuleRequestMainCommandDetour);
var atkUnitBaseReceiveGlobalEventAddress = sigScanner.ScanText("48 89 5C 24 ?? 48 89 7C 24 ?? 55 41 56 41 57 48 8B EC 48 83 EC 50 44 0F B7 F2 ");
this.hookAtkUnitBaseReceiveGlobalEvent = Hook<AtkUnitBaseReceiveGlobalEvent>.FromAddress(atkUnitBaseReceiveGlobalEventAddress, this.AtkUnitBaseReceiveGlobalEventDetour);
this.locDalamudPlugins = Loc.Localize("SystemMenuPlugins", "Dalamud Plugins");
this.locDalamudSettings = Loc.Localize("SystemMenuSettings", "Dalamud Settings");
// this.contextMenu.ContextMenuOpened += this.ContextMenuOnContextMenuOpened;
}
private delegate void AgentHudOpenSystemMenuPrototype(void* thisPtr, AtkValue* atkValueArgs, uint menuSize);
private delegate void AtkValueChangeType(AtkValue* thisPtr, ValueType type);
private delegate void AtkValueSetString(AtkValue* thisPtr, byte* bytes);
private delegate void UiModuleRequestMainCommand(void* thisPtr, int commandId);
private delegate IntPtr AtkUnitBaseReceiveGlobalEvent(AtkUnitBase* thisPtr, ushort cmd, uint a3, IntPtr a4, uint* a5);
[ServiceManager.CallWhenServicesReady]
private void ContinueConstruction(DalamudInterface dalamudInterface)
{
this.hookAgentHudOpenSystemMenu.Enable();
this.hookUiModuleRequestMainCommand.Enable();
this.hookAtkUnitBaseReceiveGlobalEvent.Enable();
}
/*
private void ContextMenuOnContextMenuOpened(ContextMenuOpenedArgs args)
{
var systemText = Service<DataManager>.GetNullable()?.GetExcelSheet<Addon>()?.GetRow(1059)?.Text?.RawString; // "System"
var interfaceManager = Service<InterfaceManager>.GetNullable();
if (systemText == null || interfaceManager == null)
return;
if (args.Title == systemText && this.configuration.DoButtonsSystemMenu && interfaceManager.IsDispatchingEvents)
{
var dalamudInterface = Service<DalamudInterface>.Get();
args.Items.Insert(0, new CustomContextMenuItem(this.locDalamudSettings, selectedArgs =>
{
dalamudInterface.ToggleSettingsWindow();
}));
args.Items.Insert(0, new CustomContextMenuItem(this.locDalamudPlugins, selectedArgs =>
{
dalamudInterface.TogglePluginInstallerWindow();
}));
}
}
*/
private IntPtr AtkUnitBaseReceiveGlobalEventDetour(AtkUnitBase* thisPtr, ushort cmd, uint a3, IntPtr a4, uint* arg)
{
// Log.Information("{0}: cmd#{1} a3#{2} - HasAnyFocus:{3}", Marshal.PtrToStringAnsi(new IntPtr(thisPtr->Name)), cmd, a3, WindowSystem.HasAnyWindowSystemFocus);
// "SendHotkey"
// 3 == Close
if (cmd == 12 && WindowSystem.HasAnyWindowSystemFocus && *arg == 3 && this.configuration.IsFocusManagementEnabled)
{
Log.Verbose($"Cancelling global event SendHotkey command due to WindowSystem {WindowSystem.FocusedWindowSystemNamespace}");
return IntPtr.Zero;
}
return this.hookAtkUnitBaseReceiveGlobalEvent.Original(thisPtr, cmd, a3, a4, arg);
}
private void AgentHudOpenSystemMenuDetour(void* thisPtr, AtkValue* atkValueArgs, uint menuSize)
{
if (WindowSystem.HasAnyWindowSystemFocus && this.configuration.IsFocusManagementEnabled)
{
Log.Verbose($"Cancelling OpenSystemMenu due to WindowSystem {WindowSystem.FocusedWindowSystemNamespace}");
return;
}
var interfaceManager = Service<InterfaceManager>.GetNullable();
if (interfaceManager == null)
{
this.hookAgentHudOpenSystemMenu.Original(thisPtr, atkValueArgs, menuSize);
return;
}
if (!this.configuration.DoButtonsSystemMenu || !interfaceManager.IsDispatchingEvents)
{
this.hookAgentHudOpenSystemMenu.Original(thisPtr, atkValueArgs, menuSize);
return;
}
// the max size (hardcoded) is 0x11/17, but the system menu currently uses 0xC/12
// this is a just in case that doesnt really matter
// see if we can add 2 entries
if (menuSize >= 0x11)
{
this.hookAgentHudOpenSystemMenu.Original(thisPtr, atkValueArgs, menuSize);
return;
}
// atkValueArgs is actually an array of AtkValues used as args. all their UI code works like this.
// in this case, menu size is stored in atkValueArgs[4], and the next 17 slots are the MainCommand
// the 17 slots after that, if they exist, are the entry names, but they are otherwise pulled from MainCommand EXD
// reference the original function for more details :)
// step 1) move all the current menu items down so we can put Dalamud at the top like it deserves
this.atkValueChangeType(&atkValueArgs[menuSize + 5], ValueType.Int); // currently this value has no type, set it to int
this.atkValueChangeType(&atkValueArgs[menuSize + 5 + 1], ValueType.Int);
for (var i = menuSize + 2; i > 1; i--)
{
var curEntry = &atkValueArgs[i + 5 - 2];
var nextEntry = &atkValueArgs[i + 5];
nextEntry->Int = curEntry->Int;
}
// step 2) set our new entries to dummy commands
var firstEntry = &atkValueArgs[5];
firstEntry->Int = 69420;
var secondEntry = &atkValueArgs[6];
secondEntry->Int = 69421;
// step 3) create strings for them
// since the game first checks for strings in the AtkValue argument before pulling them from the exd, if we create strings we dont have to worry
// about hooking the exd reader, thank god
var firstStringEntry = &atkValueArgs[5 + 17];
this.atkValueChangeType(firstStringEntry, ValueType.String);
var secondStringEntry = &atkValueArgs[6 + 17];
this.atkValueChangeType(secondStringEntry, ValueType.String);
const int color = 539;
var strPlugins = new SeString().Append(new UIForegroundPayload(color))
.Append($"{SeIconChar.BoxedLetterD.ToIconString()} ")
.Append(new UIForegroundPayload(0))
.Append(this.locDalamudPlugins).Encode();
var strSettings = new SeString().Append(new UIForegroundPayload(color))
.Append($"{SeIconChar.BoxedLetterD.ToIconString()} ")
.Append(new UIForegroundPayload(0))
.Append(this.locDalamudSettings).Encode();
// do this the most terrible way possible since im lazy
var bytes = stackalloc byte[strPlugins.Length + 1];
Marshal.Copy(strPlugins, 0, new IntPtr(bytes), strPlugins.Length);
bytes[strPlugins.Length] = 0x0;
this.atkValueSetString(firstStringEntry, bytes); // this allocs the string properly using the game's allocators and copies it, so we dont have to worry about memory fuckups
var bytes2 = stackalloc byte[strSettings.Length + 1];
Marshal.Copy(strSettings, 0, new IntPtr(bytes2), strSettings.Length);
bytes2[strSettings.Length] = 0x0;
this.atkValueSetString(secondStringEntry, bytes2);
// open menu with new size
var sizeEntry = &atkValueArgs[4];
sizeEntry->UInt = menuSize + 2;
this.hookAgentHudOpenSystemMenu.Original(thisPtr, atkValueArgs, menuSize + 2);
}
private void UiModuleRequestMainCommandDetour(void* thisPtr, int commandId)
{
var dalamudInterface = Service<DalamudInterface>.GetNullable();
switch (commandId)
{
case 69420:
dalamudInterface?.TogglePluginInstallerWindow();
break;
case 69421:
dalamudInterface?.ToggleSettingsWindow();
break;
default:
this.hookUiModuleRequestMainCommand.Original(thisPtr, commandId);
break;
}
}
// this.contextMenu.ContextMenuOpened += this.ContextMenuOnContextMenuOpened;
}
/// <summary>
/// Implements IDisposable.
/// </summary>
internal sealed partial class DalamudAtkTweaks : IDisposable
private delegate void AgentHudOpenSystemMenuPrototype(void* thisPtr, AtkValue* atkValueArgs, uint menuSize);
private delegate void AtkValueChangeType(AtkValue* thisPtr, ValueType type);
private delegate void AtkValueSetString(AtkValue* thisPtr, byte* bytes);
private delegate void UiModuleRequestMainCommand(void* thisPtr, int commandId);
private delegate IntPtr AtkUnitBaseReceiveGlobalEvent(AtkUnitBase* thisPtr, ushort cmd, uint a3, IntPtr a4, uint* a5);
[ServiceManager.CallWhenServicesReady]
private void ContinueConstruction(DalamudInterface dalamudInterface)
{
private bool disposed = false;
this.hookAgentHudOpenSystemMenu.Enable();
this.hookUiModuleRequestMainCommand.Enable();
this.hookAtkUnitBaseReceiveGlobalEvent.Enable();
}
/// <summary>
/// Finalizes an instance of the <see cref="DalamudAtkTweaks"/> class.
/// </summary>
~DalamudAtkTweaks() => this.Dispose(false);
/*
private void ContextMenuOnContextMenuOpened(ContextMenuOpenedArgs args)
{
var systemText = Service<DataManager>.GetNullable()?.GetExcelSheet<Addon>()?.GetRow(1059)?.Text?.RawString; // "System"
var interfaceManager = Service<InterfaceManager>.GetNullable();
/// <summary>
/// Dispose of managed and unmanaged resources.
/// </summary>
public void Dispose()
if (systemText == null || interfaceManager == null)
return;
if (args.Title == systemText && this.configuration.DoButtonsSystemMenu && interfaceManager.IsDispatchingEvents)
{
this.Dispose(true);
GC.SuppressFinalize(this);
var dalamudInterface = Service<DalamudInterface>.Get();
args.Items.Insert(0, new CustomContextMenuItem(this.locDalamudSettings, selectedArgs =>
{
dalamudInterface.ToggleSettingsWindow();
}));
args.Items.Insert(0, new CustomContextMenuItem(this.locDalamudPlugins, selectedArgs =>
{
dalamudInterface.TogglePluginInstallerWindow();
}));
}
}
*/
private IntPtr AtkUnitBaseReceiveGlobalEventDetour(AtkUnitBase* thisPtr, ushort cmd, uint a3, IntPtr a4, uint* arg)
{
// Log.Information("{0}: cmd#{1} a3#{2} - HasAnyFocus:{3}", Marshal.PtrToStringAnsi(new IntPtr(thisPtr->Name)), cmd, a3, WindowSystem.HasAnyWindowSystemFocus);
// "SendHotkey"
// 3 == Close
if (cmd == 12 && WindowSystem.HasAnyWindowSystemFocus && *arg == 3 && this.configuration.IsFocusManagementEnabled)
{
Log.Verbose($"Cancelling global event SendHotkey command due to WindowSystem {WindowSystem.FocusedWindowSystemNamespace}");
return IntPtr.Zero;
}
/// <summary>
/// Dispose of managed and unmanaged resources.
/// </summary>
private void Dispose(bool disposing)
return this.hookAtkUnitBaseReceiveGlobalEvent.Original(thisPtr, cmd, a3, a4, arg);
}
private void AgentHudOpenSystemMenuDetour(void* thisPtr, AtkValue* atkValueArgs, uint menuSize)
{
if (WindowSystem.HasAnyWindowSystemFocus && this.configuration.IsFocusManagementEnabled)
{
if (this.disposed)
return;
Log.Verbose($"Cancelling OpenSystemMenu due to WindowSystem {WindowSystem.FocusedWindowSystemNamespace}");
return;
}
if (disposing)
{
this.hookAgentHudOpenSystemMenu.Dispose();
this.hookUiModuleRequestMainCommand.Dispose();
this.hookAtkUnitBaseReceiveGlobalEvent.Dispose();
var interfaceManager = Service<InterfaceManager>.GetNullable();
if (interfaceManager == null)
{
this.hookAgentHudOpenSystemMenu.Original(thisPtr, atkValueArgs, menuSize);
return;
}
// this.contextMenu.ContextMenuOpened -= this.ContextMenuOnContextMenuOpened;
}
if (!this.configuration.DoButtonsSystemMenu || !interfaceManager.IsDispatchingEvents)
{
this.hookAgentHudOpenSystemMenu.Original(thisPtr, atkValueArgs, menuSize);
return;
}
this.disposed = true;
// the max size (hardcoded) is 0x11/17, but the system menu currently uses 0xC/12
// this is a just in case that doesnt really matter
// see if we can add 2 entries
if (menuSize >= 0x11)
{
this.hookAgentHudOpenSystemMenu.Original(thisPtr, atkValueArgs, menuSize);
return;
}
// atkValueArgs is actually an array of AtkValues used as args. all their UI code works like this.
// in this case, menu size is stored in atkValueArgs[4], and the next 17 slots are the MainCommand
// the 17 slots after that, if they exist, are the entry names, but they are otherwise pulled from MainCommand EXD
// reference the original function for more details :)
// step 1) move all the current menu items down so we can put Dalamud at the top like it deserves
this.atkValueChangeType(&atkValueArgs[menuSize + 5], ValueType.Int); // currently this value has no type, set it to int
this.atkValueChangeType(&atkValueArgs[menuSize + 5 + 1], ValueType.Int);
for (var i = menuSize + 2; i > 1; i--)
{
var curEntry = &atkValueArgs[i + 5 - 2];
var nextEntry = &atkValueArgs[i + 5];
nextEntry->Int = curEntry->Int;
}
// step 2) set our new entries to dummy commands
var firstEntry = &atkValueArgs[5];
firstEntry->Int = 69420;
var secondEntry = &atkValueArgs[6];
secondEntry->Int = 69421;
// step 3) create strings for them
// since the game first checks for strings in the AtkValue argument before pulling them from the exd, if we create strings we dont have to worry
// about hooking the exd reader, thank god
var firstStringEntry = &atkValueArgs[5 + 17];
this.atkValueChangeType(firstStringEntry, ValueType.String);
var secondStringEntry = &atkValueArgs[6 + 17];
this.atkValueChangeType(secondStringEntry, ValueType.String);
const int color = 539;
var strPlugins = new SeString().Append(new UIForegroundPayload(color))
.Append($"{SeIconChar.BoxedLetterD.ToIconString()} ")
.Append(new UIForegroundPayload(0))
.Append(this.locDalamudPlugins).Encode();
var strSettings = new SeString().Append(new UIForegroundPayload(color))
.Append($"{SeIconChar.BoxedLetterD.ToIconString()} ")
.Append(new UIForegroundPayload(0))
.Append(this.locDalamudSettings).Encode();
// do this the most terrible way possible since im lazy
var bytes = stackalloc byte[strPlugins.Length + 1];
Marshal.Copy(strPlugins, 0, new IntPtr(bytes), strPlugins.Length);
bytes[strPlugins.Length] = 0x0;
this.atkValueSetString(firstStringEntry, bytes); // this allocs the string properly using the game's allocators and copies it, so we dont have to worry about memory fuckups
var bytes2 = stackalloc byte[strSettings.Length + 1];
Marshal.Copy(strSettings, 0, new IntPtr(bytes2), strSettings.Length);
bytes2[strSettings.Length] = 0x0;
this.atkValueSetString(secondStringEntry, bytes2);
// open menu with new size
var sizeEntry = &atkValueArgs[4];
sizeEntry->UInt = menuSize + 2;
this.hookAgentHudOpenSystemMenu.Original(thisPtr, atkValueArgs, menuSize + 2);
}
private void UiModuleRequestMainCommandDetour(void* thisPtr, int commandId)
{
var dalamudInterface = Service<DalamudInterface>.GetNullable();
switch (commandId)
{
case 69420:
dalamudInterface?.TogglePluginInstallerWindow();
break;
case 69421:
dalamudInterface?.ToggleSettingsWindow();
break;
default:
this.hookUiModuleRequestMainCommand.Original(thisPtr, commandId);
break;
}
}
}
/// <summary>
/// Implements IDisposable.
/// </summary>
internal sealed partial class DalamudAtkTweaks : IDisposable
{
private bool disposed = false;
/// <summary>
/// Finalizes an instance of the <see cref="DalamudAtkTweaks"/> class.
/// </summary>
~DalamudAtkTweaks() => this.Dispose(false);
/// <summary>
/// Dispose of managed and unmanaged resources.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose of managed and unmanaged resources.
/// </summary>
private void Dispose(bool disposing)
{
if (this.disposed)
return;
if (disposing)
{
this.hookAgentHudOpenSystemMenu.Dispose();
this.hookUiModuleRequestMainCommand.Dispose();
this.hookAtkUnitBaseReceiveGlobalEvent.Dispose();
// this.contextMenu.ContextMenuOpened -= this.ContextMenuOnContextMenuOpened;
}
this.disposed = true;
}
}