Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed issue preventing headgear and top bone posing for some races #1440

Merged
merged 2 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 83 additions & 37 deletions Anamnesis/Actor/Posing/Services/PoseService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,22 @@ namespace Anamnesis.Actor;
[AddINotifyPropertyChangedInterface]
public class PoseService : ServiceBase<PoseService>
{
private NopHookViewModel? freezeRot1;
private NopHookViewModel? freezeRot2;
private NopHookViewModel? freezeRot3;
private NopHookViewModel? freezeScale1;
private NopHookViewModel? freezePosition;
private NopHookViewModel? freezePosition2;
private NopHookViewModel? freeseScale2;
private NopHookViewModel? freezePhysics1;
private NopHookViewModel? freezePhysics2;
private NopHookViewModel? freezePhysics3;
private NopHookViewModel? freezeWorldPosition;
private NopHookViewModel? freezeWorldRotation;
private NopHookViewModel? freezeGposeTargetPosition;
private NopHook? freezeRot1; // SyncModelSpace
private NopHook? freezeRot2; // CalculateBoneModelSpace
private NopHook? freezeRot3; // hkaLookAtIkSolve
private NopHook? freezeScale1; // SyncModelSpace
private NopHook? freeseScale2; // CalculateBoneModelSpace
private NopHook? freezePosition; // SyncModelSpace
private NopHook? freezePosition2; // CalculateBoneModelSpace
private NopHook? freezePhysics1; // Rotation
private NopHook? freezePhysics2; // Position
private NopHook? freezePhysics3; // Scale
private NopHook? freezeWorldPosition;
private NopHook? freezeWorldRotation;
private NopHook? freezeGposeTargetPosition;
private NopHook? kineDriverPosition;
private NopHook? kineDriverRotation;
private NopHook? kineDriverScale;

private bool isEnabled;

Expand Down Expand Up @@ -63,8 +66,16 @@ public bool FreezePhysics
}
set
{
this.freezePhysics1?.SetEnabled(value);
this.freezePhysics2?.SetEnabled(value);
if (value)
{
this.freezePhysics2?.SetEnabled(value);
this.freezePhysics1?.SetEnabled(value);
}
else
{
this.freezePhysics1?.SetEnabled(value);
this.freezePhysics2?.SetEnabled(value);
}
}
}

Expand All @@ -76,8 +87,18 @@ public bool FreezePositions
}
set
{
this.freezePosition?.SetEnabled(value);
this.freezePosition2?.SetEnabled(value);
if (value)
{
this.freezePosition?.SetEnabled(value);
this.freezePosition2?.SetEnabled(value);
this.kineDriverPosition?.SetEnabled(value);
}
else
{
this.kineDriverPosition?.SetEnabled(value);
this.freezePosition2?.SetEnabled(value);
this.freezePosition?.SetEnabled(value);
}
}
}

Expand All @@ -89,9 +110,20 @@ public bool FreezeScale
}
set
{
this.freezeScale1?.SetEnabled(value);
this.freezePhysics3?.SetEnabled(value);
this.freeseScale2?.SetEnabled(value);
if (value)
{
this.freezePhysics3?.SetEnabled(value);
this.freeseScale2?.SetEnabled(value);
this.freezeScale1?.SetEnabled(value);
this.kineDriverScale?.SetEnabled(value);
}
else
{
this.kineDriverScale?.SetEnabled(value);
this.freezeScale1?.SetEnabled(value);
this.freeseScale2?.SetEnabled(value);
this.freezePhysics3?.SetEnabled(value);
}
}
}

Expand All @@ -103,9 +135,20 @@ public bool FreezeRotation
}
set
{
this.freezeRot1?.SetEnabled(value);
this.freezeRot2?.SetEnabled(value);
this.freezeRot3?.SetEnabled(value);
if (value)
{
this.freezeRot2?.SetEnabled(value);
this.freezeRot1?.SetEnabled(value);
this.freezeRot3?.SetEnabled(value);
this.kineDriverRotation?.SetEnabled(value);
}
else
{
this.kineDriverRotation?.SetEnabled(value);
this.freezeRot3?.SetEnabled(value);
this.freezeRot1?.SetEnabled(value);
this.freezeRot2?.SetEnabled(value);
}
}
}

Expand Down Expand Up @@ -136,19 +179,22 @@ public override async Task Initialize()
{
await base.Initialize();

this.freezePosition = new NopHookViewModel(AddressService.SkeletonFreezePosition, 5);
this.freezePosition2 = new NopHookViewModel(AddressService.SkeletonFreezePosition2, 5);
this.freezeRot1 = new NopHookViewModel(AddressService.SkeletonFreezeRotation, 6);
this.freezeRot2 = new NopHookViewModel(AddressService.SkeletonFreezeRotation2, 6);
this.freezeRot3 = new NopHookViewModel(AddressService.SkeletonFreezeRotation3, 4);
this.freezeScale1 = new NopHookViewModel(AddressService.SkeletonFreezeScale, 6);
this.freeseScale2 = new NopHookViewModel(AddressService.SkeletonFreezeScale2, 6);
this.freezePhysics1 = new NopHookViewModel(AddressService.SkeletonFreezePhysics, 4);
this.freezePhysics2 = new NopHookViewModel(AddressService.SkeletonFreezePhysics2, 3);
this.freezePhysics3 = new NopHookViewModel(AddressService.SkeletonFreezePhysics3, 4);
this.freezeWorldPosition = new NopHookViewModel(AddressService.WorldPositionFreeze, 16);
this.freezeWorldRotation = new NopHookViewModel(AddressService.WorldRotationFreeze, 4);
this.freezeGposeTargetPosition = new NopHookViewModel(AddressService.GPoseCameraTargetPositionFreeze, 5);
this.freezePosition = new NopHook(AddressService.SkeletonFreezePosition, 5);
this.freezePosition2 = new NopHook(AddressService.SkeletonFreezePosition2, 5);
this.freezeRot1 = new NopHook(AddressService.SkeletonFreezeRotation, 6);
this.freezeRot2 = new NopHook(AddressService.SkeletonFreezeRotation2, 6);
this.freezeRot3 = new NopHook(AddressService.SkeletonFreezeRotation3, 4);
this.freezeScale1 = new NopHook(AddressService.SkeletonFreezeScale, 6);
this.freeseScale2 = new NopHook(AddressService.SkeletonFreezeScale2, 6);
this.freezePhysics1 = new NopHook(AddressService.SkeletonFreezePhysics, 4);
this.freezePhysics2 = new NopHook(AddressService.SkeletonFreezePhysics2, 3);
this.freezePhysics3 = new NopHook(AddressService.SkeletonFreezePhysics3, 4);
this.freezeWorldPosition = new NopHook(AddressService.WorldPositionFreeze, 16);
this.freezeWorldRotation = new NopHook(AddressService.WorldRotationFreeze, 4);
this.freezeGposeTargetPosition = new NopHook(AddressService.GPoseCameraTargetPositionFreeze, 5);
this.kineDriverPosition = new NopHook(AddressService.KineDriverPosition, 5);
this.kineDriverRotation = new NopHook(AddressService.KineDriverRotation, 6);
this.kineDriverScale = new NopHook(AddressService.KineDriverScale, 6);

GposeService.GposeStateChanged += this.OnGposeStateChanged;

Expand All @@ -172,9 +218,9 @@ public void SetEnabled(bool enabled)
return;

this.isEnabled = enabled;
this.FreezePhysics = enabled;
this.FreezeRotation = enabled;
this.FreezePositions = enabled;
this.FreezePhysics = enabled;
this.FreezeScale = false;
this.EnableParenting = true;

Expand Down
116 changes: 60 additions & 56 deletions Anamnesis/Core/Memory/AddressService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@

namespace Anamnesis.Core.Memory;

using Anamnesis.Memory;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Anamnesis.Memory;
using XivToolsWpf;

#pragma warning disable SA1027, SA1025
Expand All @@ -19,28 +18,35 @@ public class AddressService : ServiceBase<AddressService>
// Static offsets
public static IntPtr ActorTable { get; private set; }
public static IntPtr GPoseFilters { get; private set; }
public static IntPtr SkeletonFreezeRotation { get; private set; } // SkeletonOffset
public static IntPtr SkeletonFreezeRotation2 { get; private set; } // SkeletonOffset2
public static IntPtr SkeletonFreezeRotation3 { get; private set; } // SkeletonOffset3
public static IntPtr SkeletonFreezeScale { get; private set; } // SkeletonOffset4
public static IntPtr SkeletonFreezePosition { get; private set; } // SkeletonOffset5
public static IntPtr SkeletonFreezeScale2 { get; private set; } // SkeletonOffset6
public static IntPtr SkeletonFreezePosition2 { get; private set; } // SkeletonOffset7
public static IntPtr SkeletonFreezePhysics { get; private set; } // PhysicsOffset
public static IntPtr SkeletonFreezePhysics2 { get; private set; } // PhysicsOffset2
public static IntPtr SkeletonFreezePhysics3 { get; private set; } // PhysicsOffset3
public static IntPtr SkeletonFreezeRotation { get; private set; } // HkaPose::SyncModelSpace
public static IntPtr SkeletonFreezeRotation2 { get; private set; } // HkaPose::CalculateBoneModelSpace
public static IntPtr SkeletonFreezeRotation3 { get; private set; } // HkaLookAtIkSolver::Solve
public static IntPtr SkeletonFreezeScale { get; private set; } // HkaPose::SyncModelSpace
public static IntPtr SkeletonFreezeScale2 { get; private set; } // HkaPose::CalculateBoneModelSpace
public static IntPtr SkeletonFreezePosition { get; private set; } // HkaPose::SyncModelSpace
public static IntPtr SkeletonFreezePosition2 { get; private set; } // HkaPose::CalculateBoneModelSpace
public static IntPtr SkeletonFreezePhysics { get; private set; } // PhysicsOffset (Rotation)
public static IntPtr SkeletonFreezePhysics2 { get; private set; } // PhysicsOffset2 (Position)
public static IntPtr SkeletonFreezePhysics3 { get; private set; } // PhysicsOffset3 (Scale)
public static IntPtr WorldPositionFreeze { get; set; }
public static IntPtr WorldRotationFreeze { get; set; }
public static IntPtr GPoseCameraTargetPositionFreeze { get; set; }
public static IntPtr GposeCheck { get; private set; } // GPoseCheckOffset
public static IntPtr GposeCheck2 { get; private set; } // GPoseCheck2Offset
public static IntPtr GposeCheck { get; private set; } // GPoseCheckOffset
public static IntPtr GposeCheck2 { get; private set; } // GPoseCheck2Offset
public static IntPtr Territory { get; private set; }
public static IntPtr GPose { get; private set; }
public static IntPtr TimeAsm { get; private set; }
public static IntPtr Framework { get; set; }
public static IntPtr PlayerTargetSystem { get; set; }
public static IntPtr AnimationSpeedPatch { get; set; }

// The kinematic driver is used as an additional measure in freezing the player's position, rotation, and scale.
// It is used in conjunction with the skeleton freeze to ensure the player is completely frozen.
// Otherwise, you won't be able to move the actor's visor and top bones.
public static IntPtr KineDriverPosition { get; private set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think its worthwhile to comment on what exactly the KineDriver things are for, even if we only have a brief description? As I understood right now they are only responsible for one thing and chances are it'll only get harder to understand what exactly they are for in the future.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good point. I ammended the latest commit to include a comment on the kinematic driver's use case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

God damn it, Visual Studio nuked the includes. I just noticed 😆

public static IntPtr KineDriverRotation { get; private set; }
public static IntPtr KineDriverScale { get; private set; }

public static IntPtr Camera
{
get
Expand Down Expand Up @@ -119,49 +125,47 @@ private async Task Scan()

await Dispatch.NonUiThread();

List<Task> tasks = new List<Task>();

// Scan for all static addresses
// Some signatures taken from Dalamud: https://github.com/goatcorp/Dalamud/blob/master/Dalamud/Game/ClientState/ClientStateAddressResolver.cs
tasks.Add(this.GetAddressFromSignature("ActorTable", "48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 44 0F B6 83", 0, (p) => { ActorTable = p; }));
tasks.Add(this.GetAddressFromTextSignature("SkeletonFreezeRotation", "41 0F 29 5C 12 10", (p) => { SkeletonFreezeRotation = p; })); // SkeletonAddress
tasks.Add(this.GetAddressFromTextSignature("SkeletonFreezeRotation2", "43 0F 29 5C 18 10", (p) => { SkeletonFreezeRotation2 = p; })); // SkeletonAddress2
tasks.Add(this.GetAddressFromTextSignature("SkeletonFreezeRotation3", "0F 29 5E 10 49 8B 73 28", (p) => { SkeletonFreezeRotation3 = p; })); // SkeletonAddress3
tasks.Add(this.GetAddressFromTextSignature("SkeletonFreezeScale", "41 0F 29 44 12 20", (p) => { SkeletonFreezeScale = p; })); // SkeletonAddress4
tasks.Add(this.GetAddressFromTextSignature("SkeletonFreezePosition", "41 0F 29 24 12", (p) => { SkeletonFreezePosition = p; })); // SkeletonAddress5
tasks.Add(this.GetAddressFromTextSignature("SkeletonFreezeScale2", "43 0F 29 44 18 20", (p) => { SkeletonFreezeScale2 = p; })); // SkeletonAddress6
tasks.Add(this.GetAddressFromTextSignature("SkeletonFreezePosition2", "43 0f 29 24 18", (p) => { SkeletonFreezePosition2 = p; })); // SkeletonAddress7
tasks.Add(this.GetAddressFromTextSignature("WorldPositionFreeze", "F3 0F 11 ?? ?? F3 0F 11 ?? ?? F3 44 0F 11 ?? ?? 48 8B 8B ?? 01", (p) => { WorldPositionFreeze = p; }));
tasks.Add(this.GetAddressFromTextSignature("WorldRotationFreeze", "0F 11 40 60 48 8B 8B 00 01 00 00 0F B6 81 89 00 00 00 24 0F 3C 03 75 08 48 8B 01 B2 01 FF 50 38 ?? ?? ?? ?? E0", (p) => { WorldRotationFreeze = p; }));
tasks.Add(this.GetAddressFromTextSignature("GPoseCameraTargetPositionFreeze", "F3 0F 10 0E E8 ?? ?? ?? ?? 4C 8B 74 24", (p) => { GPoseCameraTargetPositionFreeze = p + 4; }));
tasks.Add(this.GetAddressFromTextSignature("AnimationSpeedPatch", "F3 0F 11 94 ?? ?? ?? ?? ?? 80 89 ?? ?? ?? ?? 01", (p) => { AnimationSpeedPatch = p; }));
tasks.Add(this.GetAddressFromSignature("Territory", "8B 1D ?? ?? ?? ?? 0F 45 D8 39 1D", 2, (p) => { Territory = p; }));
tasks.Add(this.GetAddressFromSignature("Weather", "48 8B 9F ?? ?? ?? ?? 48 8D 0D", 0, (p) => { Weather = p + 0x8; }));
tasks.Add(this.GetAddressFromSignature("GPoseFilters", "48 85 D2 4C 8B 05 ?? ?? ?? ??", 0, (p) => { GPoseFilters = p; }));
tasks.Add(this.GetAddressFromSignature("GposeCheck", "0F 84 ?? ?? ?? ?? 8B 15 ?? ?? ?? ?? 48 89 6C 24 ??", 0, (p) => { GposeCheck = p; }));
tasks.Add(this.GetAddressFromSignature("GposeCheck2", "8D 48 FF 48 8D 05 ?? ?? ?? ?? 8B 0C 88 48 8B 02 83 F9 04 49 8B CA", 0, (p) => { GposeCheck2 = p; }));
tasks.Add(this.GetAddressFromSignature("GPose", "74 35 48 39 0D ?? ?? ?? ??", 0, (p) => { GPose = p + 0x20; }));
tasks.Add(this.GetAddressFromSignature("Camera", "48 8D 35 ?? ?? ?? ?? 48 8B 09", 0, (p) => { cameraManager = p; })); // CameraAddress
tasks.Add(this.GetAddressFromSignature("PlayerTargetSystem", "48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 3B C3 74 08", 0, (p) => { PlayerTargetSystem = p; }));

tasks.Add(this.GetAddressFromTextSignature("TimeAsm", "48 89 87 ?? ?? ?? ?? 48 69 C0", (p) => TimeAsm = p));

tasks.Add(this.GetAddressFromTextSignature(
"Framework",
"48 C7 05 ?? ?? ?? ?? 00 00 00 00 E8 ?? ?? ?? ?? 48 8D ?? ?? ?? 00 00 E8 ?? ?? ?? ?? 48 8D",
(p) =>
{
int frameworkOffset = MemoryService.Read<int>(p + 3);
IntPtr frameworkPtr = MemoryService.ReadPtr(p + 11 + frameworkOffset);
Framework = frameworkPtr;
}));

tasks.Add(this.GetAddressFromTextSignature("SkeletonFreezePhysics (1/2/3)", "0F 11 48 10 41 0F 10 44 24 ?? 0F 11 40 20 48 8B 46 28", (p) =>
var tasks = new List<Task>
{
SkeletonFreezePhysics = p; // PhysicsAddress
SkeletonFreezePhysics2 = p - 0x9; // SkeletonAddress2
SkeletonFreezePhysics3 = p + 0xA; // SkeletonAddress3
}));
// Scan for all static addresses
// Some signatures taken from Dalamud: https://github.com/goatcorp/Dalamud/blob/master/Dalamud/Game/ClientState/ClientStateAddressResolver.cs
this.GetAddressFromSignature("ActorTable", "48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 44 0F B6 83", 0, (p) => { ActorTable = p; }),
this.GetAddressFromTextSignature("SkeletonFreezeRotation", "41 0F 29 5C 12 10", (p) => { SkeletonFreezeRotation = p; }),
this.GetAddressFromTextSignature("SkeletonFreezeRotation2", "43 0F 29 5C 18 10", (p) => { SkeletonFreezeRotation2 = p; }),
this.GetAddressFromTextSignature("SkeletonFreezeRotation3", "0F 29 5E 10 49 8B 73 28", (p) => { SkeletonFreezeRotation3 = p; }),
this.GetAddressFromTextSignature("SkeletonFreezeScale", "41 0F 29 44 12 20", (p) => { SkeletonFreezeScale = p; }),
this.GetAddressFromTextSignature("SkeletonFreezeScale2", "43 0F 29 44 18 20", (p) => { SkeletonFreezeScale2 = p; }),
this.GetAddressFromTextSignature("SkeletonFreezePosition", "41 0F 29 24 12", (p) => { SkeletonFreezePosition = p; }),
this.GetAddressFromTextSignature("SkeletonFreezePosition2", "43 0f 29 24 18", (p) => { SkeletonFreezePosition2 = p; }),
this.GetAddressFromTextSignature("WorldPositionFreeze", "F3 0F 11 ?? ?? F3 0F 11 ?? ?? F3 44 0F 11 ?? ?? 48 8B 8B ?? 01", (p) => { WorldPositionFreeze = p; }),
this.GetAddressFromTextSignature("WorldRotationFreeze", "0F 11 40 60 48 8B 8B 00 01 00 00 0F B6 81 89 00 00 00 24 0F 3C 03 75 08 48 8B 01 B2 01 FF 50 38 ?? ?? ?? ?? E0", (p) => { WorldRotationFreeze = p; }),
this.GetAddressFromTextSignature("GPoseCameraTargetPositionFreeze", "F3 0F 10 0E E8 ?? ?? ?? ?? 4C 8B 74 24", (p) => { GPoseCameraTargetPositionFreeze = p + 4; }),
this.GetAddressFromTextSignature("AnimationSpeedPatch", "F3 0F 11 94 ?? ?? ?? ?? ?? 80 89 ?? ?? ?? ?? 01", (p) => { AnimationSpeedPatch = p; }),
this.GetAddressFromSignature("Territory", "8B 1D ?? ?? ?? ?? 0F 45 D8 39 1D", 2, (p) => { Territory = p; }),
this.GetAddressFromSignature("Weather", "48 8B 9F ?? ?? ?? ?? 48 8D 0D", 0, (p) => { Weather = p + 0x8; }),
this.GetAddressFromSignature("GPoseFilters", "48 85 D2 4C 8B 05 ?? ?? ?? ??", 0, (p) => { GPoseFilters = p; }),
this.GetAddressFromSignature("GposeCheck", "0F 84 ?? ?? ?? ?? 8B 15 ?? ?? ?? ?? 48 89 6C 24 ??", 0, (p) => { GposeCheck = p; }),
this.GetAddressFromSignature("GposeCheck2", "8D 48 FF 48 8D 05 ?? ?? ?? ?? 8B 0C 88 48 8B 02 83 F9 04 49 8B CA", 0, (p) => { GposeCheck2 = p; }),
this.GetAddressFromSignature("GPose", "74 35 48 39 0D ?? ?? ?? ??", 0, (p) => { GPose = p + 0x20; }),
this.GetAddressFromSignature("Camera", "48 8D 35 ?? ?? ?? ?? 48 8B 09", 0, (p) => { cameraManager = p; }),
this.GetAddressFromSignature("PlayerTargetSystem", "48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 3B C3 74 08", 0, (p) => { PlayerTargetSystem = p; }),
this.GetAddressFromTextSignature("TimeAsm", "48 89 87 ?? ?? ?? ?? 48 69 C0", (p) => TimeAsm = p),
this.GetAddressFromTextSignature("Framework", "48 C7 05 ?? ?? ?? ?? 00 00 00 00 E8 ?? ?? ?? ?? 48 8D ?? ?? ?? 00 00 E8 ?? ?? ?? ?? 48 8D", (p) =>
{
int frameworkOffset = MemoryService.Read<int>(p + 3);
IntPtr frameworkPtr = MemoryService.ReadPtr(p + 11 + frameworkOffset);
Framework = frameworkPtr;
}),
this.GetAddressFromTextSignature("SkeletonFreezePhysics (1/2/3)", "0F 11 00 41 0F 10 4C 24 ?? 0F 11 48 10 41 0F 10 44 24 ?? 0F 11 40 20 48 8B 46 28", (p) =>
{
SkeletonFreezePhysics2 = p;
SkeletonFreezePhysics = p + 0x9;
SkeletonFreezePhysics3 = p + 0x13;
}),
this.GetAddressFromTextSignature("KineDriverPosition", "41 0F 11 04 07", (p) => { KineDriverPosition = p; }),
this.GetAddressFromTextSignature("KineDriverRotation", "41 0F 11 4C 07 ?? 0F 10 41 20", (p) => { KineDriverRotation = p; }),
this.GetAddressFromTextSignature("KineDriverScale", "41 0F 11 44 07 ?? 48 8B 47 28", (p) => { KineDriverScale = p; }),
};

await Task.WhenAll(tasks.ToArray());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Anamnesis.Memory;

using System;

public class NopHookViewModel : IDisposable
public class NopHook : IDisposable
{
private readonly object lockObject = new();
private readonly IntPtr address;
Expand All @@ -14,7 +14,7 @@ public class NopHookViewModel : IDisposable
private bool enabled;
private bool disposed = false;

public NopHookViewModel(IntPtr address, int count)
public NopHook(IntPtr address, int count)
{
this.address = address;

Expand All @@ -28,8 +28,9 @@ public NopHookViewModel(IntPtr address, int count)
this.nopValue[i] = 0x90;
}

// Register for process exit event
// Register events to handle normal process termination and fatal exceptions
AppDomain.CurrentDomain.ProcessExit += this.OnProcessExit;
AppDomain.CurrentDomain.UnhandledException += this.OnUnhandledException;
}

public bool Enabled
Expand Down Expand Up @@ -90,8 +91,9 @@ protected virtual void Dispose(bool disposing)
MemoryService.Write(this.address, this.originalValue, true);
}

// Unregister from process exit event
// Unregister events
AppDomain.CurrentDomain.ProcessExit -= this.OnProcessExit;
AppDomain.CurrentDomain.UnhandledException -= this.OnUnhandledException;
}

this.disposed = true;
Expand All @@ -104,4 +106,10 @@ private void OnProcessExit(object? sender, EventArgs e)
// Call Dispose explicitly in case the GC hasn't called it yet
this.Dispose();
}

private void OnUnhandledException(object? sender, UnhandledExceptionEventArgs e)
{
// Call Dispose explicitly when an unhandled exception occurs to restore the original memory state
this.Dispose();
}
}
Loading