From 3e2a01a8a7ae50751e1599927b424c855836458f Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Sun, 18 Dec 2022 11:37:35 +0100 Subject: [PATCH 1/9] Rename { => Global}Init, { => Global}Dispose --- Ktisis/History/HistoryManager.cs | 4 +- Ktisis/Interface/Input.cs | 4 +- Ktisis/Interop/Alloc.cs | 4 +- Ktisis/Interop/Hooks/ActorHooks.cs | 4 +- Ktisis/Interop/Hooks/ControlHooks.cs | 4 +- Ktisis/Interop/Hooks/EventsHooks.cs | 4 +- Ktisis/Interop/Hooks/GuiHooks.cs | 4 +- Ktisis/Interop/Hooks/PoseHooks.cs | 4 +- Ktisis/Interop/Methods.cs | 2 +- Ktisis/Interop/StaticOffsets.cs | 2 +- Ktisis/Ktisis.cs | 40 +++++++++---------- .../Structs/Actor/State/ActorStateWatcher.cs | 2 +- 12 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Ktisis/History/HistoryManager.cs b/Ktisis/History/HistoryManager.cs index 500d45115..0e9d1aa0f 100644 --- a/Ktisis/History/HistoryManager.cs +++ b/Ktisis/History/HistoryManager.cs @@ -21,14 +21,14 @@ public static class HistoryManager { // Init & Dispose - public static void Init() { + public static void GlobalInit() { EventManager.OnKeyPressed += OnInput; EventManager.OnGPoseChange += OnGPoseChange; EventManager.OnGizmoChange += OnGizmoChange; EventManager.OnTransformationMatrixChange += OnGizmoChange; } - public static void Dispose() { + public static void GlobalDispose() { EventManager.OnKeyPressed -= OnInput; EventManager.OnGPoseChange -= OnGPoseChange; EventManager.OnGizmoChange -= OnGizmoChange; diff --git a/Ktisis/Interface/Input.cs b/Ktisis/Interface/Input.cs index 6fce59495..2b696bed9 100644 --- a/Ktisis/Interface/Input.cs +++ b/Ktisis/Interface/Input.cs @@ -176,11 +176,11 @@ public enum Purpose { // Init & dispose - public static void Init() { + public static void GlobalInit() { EventManager.OnKeyPressed += OnKeyPressed; EventManager.OnKeyReleased += OnKeyReleased; } - public static void Dispose() { + public static void GlobalDispose() { EventManager.OnKeyPressed -= OnKeyPressed; EventManager.OnKeyReleased -= OnKeyReleased; } diff --git a/Ktisis/Interop/Alloc.cs b/Ktisis/Interop/Alloc.cs index bb310e041..9db0cca87 100644 --- a/Ktisis/Interop/Alloc.cs +++ b/Ktisis/Interop/Alloc.cs @@ -21,14 +21,14 @@ internal unsafe static void SetMatrix(hkQsTransformf* transform, Matrix4x4 matri } // Init & disspose - public unsafe static void Init() { + public unsafe static void GlobalInit() { // Allocate space for our matrix to be aligned on a 16-byte boundary. // This is required due to ffxiv's use of the MOVAPS instruction. // Thanks to Fayti1703 for helping with debugging and coming up with this fix. MatrixAlloc = Marshal.AllocHGlobal(sizeof(float) * 16 + 16); Matrix = (Matrix4x4*)(16 * ((long)(MatrixAlloc + 15) / 16)); } - public static void Dispose() { + public static void GlobalDispose() { Marshal.FreeHGlobal(MatrixAlloc); } } diff --git a/Ktisis/Interop/Hooks/ActorHooks.cs b/Ktisis/Interop/Hooks/ActorHooks.cs index c10f80eff..6ed3a9806 100644 --- a/Ktisis/Interop/Hooks/ActorHooks.cs +++ b/Ktisis/Interop/Hooks/ActorHooks.cs @@ -21,13 +21,13 @@ internal unsafe static IntPtr ControlGaze(IntPtr a1) { // Init & Dispose - internal static void Init() { + internal static void GlobalInit() { var controlGaze = Services.SigScanner.ScanText("40 53 41 54 41 55 48 81 EC ?? ?? ?? ?? 48 8B D9"); ControlGazeHook = Hook.FromAddress(controlGaze, ControlGaze); ControlGazeHook.Enable(); } - internal static void Dispose() { + internal static void GlobalDispose() { ControlGazeHook.Disable(); ControlGazeHook.Dispose(); } diff --git a/Ktisis/Interop/Hooks/ControlHooks.cs b/Ktisis/Interop/Hooks/ControlHooks.cs index 6e72f01e3..07518645e 100644 --- a/Ktisis/Interop/Hooks/ControlHooks.cs +++ b/Ktisis/Interop/Hooks/ControlHooks.cs @@ -76,7 +76,7 @@ internal static IntPtr InputDetour2(ulong a1, uint a2, ulong a3, uint a4) { // Init & dispose - internal static void Init() { + internal static void GlobalInit() { unsafe { var addr = Services.SigScanner.ScanText("E8 ?? ?? ?? ?? 83 7B 58 00"); InputHook = Hook.FromAddress(addr, InputDetour); @@ -88,7 +88,7 @@ internal static void Init() { } } - internal static void Dispose() { + internal static void GlobalDispose() { InputHook.Disable(); InputHook.Dispose(); diff --git a/Ktisis/Interop/Hooks/EventsHooks.cs b/Ktisis/Interop/Hooks/EventsHooks.cs index d1996d86f..1f2f35617 100644 --- a/Ktisis/Interop/Hooks/EventsHooks.cs +++ b/Ktisis/Interop/Hooks/EventsHooks.cs @@ -13,7 +13,7 @@ namespace Ktisis.Interop.Hooks { public class EventsHooks { - public static void Init() { + public static void GlobalInit() { Services.AddonManager = new AddonManager(); Services.ClientState.Login += OnLogin; Services.ClientState.Logout += OnLogout; @@ -25,7 +25,7 @@ public static void Init() { OnLogin(null!, null!); } - public static void Dispose() { + public static void GlobalDispose() { Services.AddonManager.Dispose(); Services.ClientState.Logout -= OnLogout; Services.ClientState.Login -= OnLogin; diff --git a/Ktisis/Interop/Hooks/GuiHooks.cs b/Ktisis/Interop/Hooks/GuiHooks.cs index 5c34fb838..228782998 100644 --- a/Ktisis/Interop/Hooks/GuiHooks.cs +++ b/Ktisis/Interop/Hooks/GuiHooks.cs @@ -37,13 +37,13 @@ internal unsafe static void UpdateTarName(IntPtr a1) { // Init & dispose - internal static void Init() { + internal static void GlobalInit() { var tarName = Services.SigScanner.ScanText("40 56 48 83 EC 50 48 8B 05 ?? ?? ?? ?? 48 8B F1 48 85 C0"); TarNameHook = Hook.FromAddress(tarName, UpdateTarName); TarNameHook.Enable(); } - internal static void Dispose() { + internal static void GlobalDispose() { TarNameHook.Disable(); TarNameHook.Dispose(); } diff --git a/Ktisis/Interop/Hooks/PoseHooks.cs b/Ktisis/Interop/Hooks/PoseHooks.cs index 6f6b0f1ec..8f0e71931 100644 --- a/Ktisis/Interop/Hooks/PoseHooks.cs +++ b/Ktisis/Interop/Hooks/PoseHooks.cs @@ -43,7 +43,7 @@ public static class PoseHooks { internal static Dictionary PreservedPoses = new(); - internal static unsafe void Init() { + internal static unsafe void GlobalInit() { var setBoneModelSpaceFfxiv = Services.SigScanner.ScanText("48 8B C4 48 89 58 18 55 56 57 41 54 41 55 41 56 41 57 48 81 EC ?? ?? ?? ?? 0F 29 70 B8 0F 29 78 A8 44 0F 29 40 ?? 44 0F 29 48 ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B B1"); SetBoneModelSpaceFfxivHook = Hook.FromAddress(setBoneModelSpaceFfxiv, SetBoneModelSpaceFfxivDetour); @@ -233,7 +233,7 @@ public static unsafe bool IsGamePlaybackRunning(GameObject? gPoseTarget) { return csObject->DrawObject->Skeleton->PartialSkeletons->GetHavokAnimatedSkeleton(0)->AnimationControls[0]; } - internal static void Dispose() { + internal static void GlobalDispose() { SetBoneModelSpaceFfxivHook.Disable(); SetBoneModelSpaceFfxivHook.Dispose(); CalculateBoneModelSpaceHook.Disable(); diff --git a/Ktisis/Interop/Methods.cs b/Ktisis/Interop/Methods.cs index 16c741fc7..51f82ff48 100644 --- a/Ktisis/Interop/Methods.cs +++ b/Ktisis/Interop/Methods.cs @@ -32,7 +32,7 @@ internal class Methods { private static TDelegate Retrieve(string sig) => Marshal.GetDelegateForFunctionPointer(Services.SigScanner.ScanText(sig)); - internal static void Init() { + internal static void GlobalInit() { ActorLookAt = Retrieve("40 53 55 57 41 56 41 57 48 83 EC 70"); ActorChangeEquip = Retrieve("E8 ?? ?? ?? ?? 41 B5 01 FF C6"); ActorChangeWeapon = Retrieve("E8 ?? ?? ?? ?? 80 7F 25 00"); diff --git a/Ktisis/Interop/StaticOffsets.cs b/Ktisis/Interop/StaticOffsets.cs index 5d86aca38..fc7357927 100644 --- a/Ktisis/Interop/StaticOffsets.cs +++ b/Ktisis/Interop/StaticOffsets.cs @@ -17,7 +17,7 @@ internal static class StaticOffsets { internal static bool IsAnamPosing => IsPositionFrozen || IsRotationFrozen || IsScalingFrozen; // Init - internal unsafe static void Init() { + internal unsafe static void GlobalInit() { var qword_14200E548 = *(IntPtr*)Services.SigScanner.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 C7 44 24 24 05 00 00 00 C6 84 24"); CharaDatData = *(IntPtr*)(qword_14200E548 + 1392); diff --git a/Ktisis/Ktisis.cs b/Ktisis/Ktisis.cs index a68fed749..816b87ec8 100644 --- a/Ktisis/Ktisis.cs +++ b/Ktisis/Ktisis.cs @@ -54,20 +54,20 @@ public Ktisis(DalamudPluginInterface pluginInterface) { // Init interop stuff - Interop.Alloc.Init(); - Interop.Methods.Init(); - Interop.StaticOffsets.Init(); + Interop.Alloc.GlobalInit(); + Interop.Methods.GlobalInit(); + Interop.StaticOffsets.GlobalInit(); - Interop.Hooks.ActorHooks.Init(); - Interop.Hooks.ControlHooks.Init(); - Interop.Hooks.EventsHooks.Init(); - Interop.Hooks.GuiHooks.Init(); - Interop.Hooks.PoseHooks.Init(); + Interop.Hooks.ActorHooks.GlobalInit(); + Interop.Hooks.ControlHooks.GlobalInit(); + Interop.Hooks.EventsHooks.GlobalInit(); + Interop.Hooks.GuiHooks.GlobalInit(); + Interop.Hooks.PoseHooks.GlobalInit(); - EventManager.OnGPoseChange += Workspace.OnEnterGposeToggle; // must be placed before ActorStateWatcher.Init() + EventManager.OnGPoseChange += Workspace.OnEnterGposeToggle; // must be placed before ActorStateWatcher.GlobalInit() - Input.Init(); - ActorStateWatcher.Init(); + Input.GlobalInit(); + ActorStateWatcher.GlobalInit(); // Register command @@ -84,7 +84,7 @@ public Ktisis(DalamudPluginInterface pluginInterface) { pluginInterface.UiBuilder.DisableGposeUiHide = true; pluginInterface.UiBuilder.Draw += KtisisGui.Draw; - HistoryManager.Init(); + HistoryManager.GlobalInit(); References.LoadReferences(Configuration); } @@ -95,13 +95,13 @@ public void Dispose() { OverlayWindow.DeselectGizmo(); - Interop.Hooks.ActorHooks.Dispose(); - Interop.Hooks.ControlHooks.Dispose(); - Interop.Hooks.EventsHooks.Dispose(); - Interop.Hooks.GuiHooks.Dispose(); - Interop.Hooks.PoseHooks.Dispose(); + Interop.Hooks.ActorHooks.GlobalDispose(); + Interop.Hooks.ControlHooks.GlobalDispose(); + Interop.Hooks.EventsHooks.GlobalDispose(); + Interop.Hooks.GuiHooks.GlobalDispose(); + Interop.Hooks.PoseHooks.GlobalDispose(); - Interop.Alloc.Dispose(); + Interop.Alloc.GlobalDispose(); ActorStateWatcher.Instance.Dispose(); EventManager.OnGPoseChange -= Workspace.OnEnterGposeToggle; @@ -110,8 +110,8 @@ public void Dispose() { if (EditEquip.Items != null) EditEquip.Items = null; - Input.Dispose(); - HistoryManager.Dispose(); + Input.GlobalDispose(); + HistoryManager.GlobalDispose(); foreach (var (_, texture) in References.Textures) { texture.Dispose(); diff --git a/Ktisis/Structs/Actor/State/ActorStateWatcher.cs b/Ktisis/Structs/Actor/State/ActorStateWatcher.cs index 7aae3b17a..14d77ffb7 100644 --- a/Ktisis/Structs/Actor/State/ActorStateWatcher.cs +++ b/Ktisis/Structs/Actor/State/ActorStateWatcher.cs @@ -28,7 +28,7 @@ public void Dispose() { EventManager.FireOnGposeChangeEvent(ActorGposeState.OFF); } - public static void Init() { + public static void GlobalInit() { _ = Instance; } From 922acfa943b47362ac6ebe9ab1664fdc05bee16f Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Sun, 18 Dec 2022 12:00:17 +0100 Subject: [PATCH 2/9] Add Global State Attributes --- Ktisis/GlobalDisposeAttribute.cs | 12 ++++++++++++ Ktisis/GlobalInitAttribute.cs | 12 ++++++++++++ Ktisis/GlobalStateAttribute.cs | 9 +++++++++ 3 files changed, 33 insertions(+) create mode 100644 Ktisis/GlobalDisposeAttribute.cs create mode 100644 Ktisis/GlobalInitAttribute.cs create mode 100644 Ktisis/GlobalStateAttribute.cs diff --git a/Ktisis/GlobalDisposeAttribute.cs b/Ktisis/GlobalDisposeAttribute.cs new file mode 100644 index 000000000..b83557191 --- /dev/null +++ b/Ktisis/GlobalDisposeAttribute.cs @@ -0,0 +1,12 @@ +using System; + +using JetBrains.Annotations; + +namespace Ktisis { + /** + * Marks a static method as a global destructor. It will be called during plugin disposing. + */ + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + [MeansImplicitUse(ImplicitUseKindFlags.Access)] + public class GlobalDisposeAttribute : Attribute {} +} diff --git a/Ktisis/GlobalInitAttribute.cs b/Ktisis/GlobalInitAttribute.cs new file mode 100644 index 000000000..e746ac079 --- /dev/null +++ b/Ktisis/GlobalInitAttribute.cs @@ -0,0 +1,12 @@ +using System; + +using JetBrains.Annotations; + +namespace Ktisis { + /** + * Marks a static method as a global initializer. It will be called during plugin construction. + */ + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + [MeansImplicitUse(ImplicitUseKindFlags.Access)] + public class GlobalInitAttribute : Attribute {} +} diff --git a/Ktisis/GlobalStateAttribute.cs b/Ktisis/GlobalStateAttribute.cs new file mode 100644 index 000000000..cc661a3a3 --- /dev/null +++ b/Ktisis/GlobalStateAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace Ktisis { + /** + * Indicates that this class has global state and may contain static methods annotated with and/or . + */ + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + public class GlobalStateAttribute : Attribute {} +} From 5354ddd4bad922cc55fd95c23d41fc392670d59b Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Sun, 18 Dec 2022 12:03:32 +0100 Subject: [PATCH 3/9] Sprinkle Global State Attributes as appropriate --- Ktisis/History/HistoryManager.cs | 3 +++ Ktisis/Interface/Input.cs | 3 +++ Ktisis/Interop/Alloc.cs | 3 +++ Ktisis/Interop/Hooks/ActorHooks.cs | 3 +++ Ktisis/Interop/Hooks/ControlHooks.cs | 3 +++ Ktisis/Interop/Hooks/EventsHooks.cs | 3 +++ Ktisis/Interop/Hooks/GuiHooks.cs | 3 +++ Ktisis/Interop/Hooks/PoseHooks.cs | 3 +++ Ktisis/Interop/Methods.cs | 2 ++ Ktisis/Interop/StaticOffsets.cs | 2 ++ Ktisis/Structs/Actor/State/ActorStateWatcher.cs | 2 ++ 11 files changed, 30 insertions(+) diff --git a/Ktisis/History/HistoryManager.cs b/Ktisis/History/HistoryManager.cs index 0e9d1aa0f..2d9b97a5f 100644 --- a/Ktisis/History/HistoryManager.cs +++ b/Ktisis/History/HistoryManager.cs @@ -9,6 +9,7 @@ using Ktisis.Structs.Actor.State; namespace Ktisis.History { + [GlobalState] public static class HistoryManager { public static List? History { get; set; } private static int _currentIdx = -1; @@ -21,6 +22,7 @@ public static class HistoryManager { // Init & Dispose + [GlobalInit] public static void GlobalInit() { EventManager.OnKeyPressed += OnInput; EventManager.OnGPoseChange += OnGPoseChange; @@ -28,6 +30,7 @@ public static void GlobalInit() { EventManager.OnTransformationMatrixChange += OnGizmoChange; } + [GlobalDispose] public static void GlobalDispose() { EventManager.OnKeyPressed -= OnInput; EventManager.OnGPoseChange -= OnGPoseChange; diff --git a/Ktisis/Interface/Input.cs b/Ktisis/Interface/Input.cs index 2b696bed9..8265d993e 100644 --- a/Ktisis/Interface/Input.cs +++ b/Ktisis/Interface/Input.cs @@ -17,6 +17,7 @@ using Ktisis.Interface.Components; namespace Ktisis.Interface { + [GlobalState] public static class Input { // When adding a new keybind: // - add the logic in Monitor @@ -176,10 +177,12 @@ public enum Purpose { // Init & dispose + [GlobalInit] public static void GlobalInit() { EventManager.OnKeyPressed += OnKeyPressed; EventManager.OnKeyReleased += OnKeyReleased; } + [GlobalDispose] public static void GlobalDispose() { EventManager.OnKeyPressed -= OnKeyPressed; EventManager.OnKeyReleased -= OnKeyReleased; diff --git a/Ktisis/Interop/Alloc.cs b/Ktisis/Interop/Alloc.cs index 9db0cca87..f19f07dc1 100644 --- a/Ktisis/Interop/Alloc.cs +++ b/Ktisis/Interop/Alloc.cs @@ -5,6 +5,7 @@ using FFXIVClientStructs.Havok; namespace Ktisis.Interop { + [GlobalState] internal static class Alloc { // Allocations private static IntPtr MatrixAlloc; @@ -21,6 +22,7 @@ internal unsafe static void SetMatrix(hkQsTransformf* transform, Matrix4x4 matri } // Init & disspose + [GlobalInit] public unsafe static void GlobalInit() { // Allocate space for our matrix to be aligned on a 16-byte boundary. // This is required due to ffxiv's use of the MOVAPS instruction. @@ -28,6 +30,7 @@ public unsafe static void GlobalInit() { MatrixAlloc = Marshal.AllocHGlobal(sizeof(float) * 16 + 16); Matrix = (Matrix4x4*)(16 * ((long)(MatrixAlloc + 15) / 16)); } + [GlobalDispose] public static void GlobalDispose() { Marshal.FreeHGlobal(MatrixAlloc); } diff --git a/Ktisis/Interop/Hooks/ActorHooks.cs b/Ktisis/Interop/Hooks/ActorHooks.cs index 6ed3a9806..dbd08ef69 100644 --- a/Ktisis/Interop/Hooks/ActorHooks.cs +++ b/Ktisis/Interop/Hooks/ActorHooks.cs @@ -6,6 +6,7 @@ using Ktisis.Interface.Windows.Workspace; namespace Ktisis.Interop.Hooks { + [GlobalState] internal static class ActorHooks { // Control actor gaze // a1 = Actor + 0xC20 @@ -21,12 +22,14 @@ internal unsafe static IntPtr ControlGaze(IntPtr a1) { // Init & Dispose + [GlobalInit] internal static void GlobalInit() { var controlGaze = Services.SigScanner.ScanText("40 53 41 54 41 55 48 81 EC ?? ?? ?? ?? 48 8B D9"); ControlGazeHook = Hook.FromAddress(controlGaze, ControlGaze); ControlGazeHook.Enable(); } + [GlobalDispose] internal static void GlobalDispose() { ControlGazeHook.Disable(); ControlGazeHook.Dispose(); diff --git a/Ktisis/Interop/Hooks/ControlHooks.cs b/Ktisis/Interop/Hooks/ControlHooks.cs index 07518645e..754d5b9a9 100644 --- a/Ktisis/Interop/Hooks/ControlHooks.cs +++ b/Ktisis/Interop/Hooks/ControlHooks.cs @@ -7,6 +7,7 @@ using Ktisis.Structs.Input; namespace Ktisis.Interop.Hooks { + [GlobalState] internal static class ControlHooks { public static KeyboardState KeyboardState = new(); @@ -76,6 +77,7 @@ internal static IntPtr InputDetour2(ulong a1, uint a2, ulong a3, uint a4) { // Init & dispose + [GlobalInit] internal static void GlobalInit() { unsafe { var addr = Services.SigScanner.ScanText("E8 ?? ?? ?? ?? 83 7B 58 00"); @@ -88,6 +90,7 @@ internal static void GlobalInit() { } } + [GlobalDispose] internal static void GlobalDispose() { InputHook.Disable(); InputHook.Dispose(); diff --git a/Ktisis/Interop/Hooks/EventsHooks.cs b/Ktisis/Interop/Hooks/EventsHooks.cs index 1f2f35617..02e956889 100644 --- a/Ktisis/Interop/Hooks/EventsHooks.cs +++ b/Ktisis/Interop/Hooks/EventsHooks.cs @@ -12,7 +12,9 @@ using Ktisis.Structs.Actor.Equip.SetSources; namespace Ktisis.Interop.Hooks { + [GlobalState] public class EventsHooks { + [GlobalInit] public static void GlobalInit() { Services.AddonManager = new AddonManager(); Services.ClientState.Login += OnLogin; @@ -25,6 +27,7 @@ public static void GlobalInit() { OnLogin(null!, null!); } + [GlobalDispose] public static void GlobalDispose() { Services.AddonManager.Dispose(); Services.ClientState.Logout -= OnLogout; diff --git a/Ktisis/Interop/Hooks/GuiHooks.cs b/Ktisis/Interop/Hooks/GuiHooks.cs index 228782998..a948044e6 100644 --- a/Ktisis/Interop/Hooks/GuiHooks.cs +++ b/Ktisis/Interop/Hooks/GuiHooks.cs @@ -5,6 +5,7 @@ using Ktisis.Structs.Actor; namespace Ktisis.Interop.Hooks { + [GlobalState] internal class GuiHooks { // Target name in the GPose window @@ -37,12 +38,14 @@ internal unsafe static void UpdateTarName(IntPtr a1) { // Init & dispose + [GlobalInit] internal static void GlobalInit() { var tarName = Services.SigScanner.ScanText("40 56 48 83 EC 50 48 8B 05 ?? ?? ?? ?? 48 8B F1 48 85 C0"); TarNameHook = Hook.FromAddress(tarName, UpdateTarName); TarNameHook.Enable(); } + [GlobalDispose] internal static void GlobalDispose() { TarNameHook.Disable(); TarNameHook.Dispose(); diff --git a/Ktisis/Interop/Hooks/PoseHooks.cs b/Ktisis/Interop/Hooks/PoseHooks.cs index 8f0e71931..4c919d0bc 100644 --- a/Ktisis/Interop/Hooks/PoseHooks.cs +++ b/Ktisis/Interop/Hooks/PoseHooks.cs @@ -13,6 +13,7 @@ using Dalamud.Logging; namespace Ktisis.Interop.Hooks { + [GlobalState] public static class PoseHooks { internal delegate ulong SetBoneModelSpaceFfxivDelegate(IntPtr partialSkeleton, ushort boneId, IntPtr transform, bool enableSecondary, bool enablePropagate); internal static Hook SetBoneModelSpaceFfxivHook = null!; @@ -43,6 +44,7 @@ public static class PoseHooks { internal static Dictionary PreservedPoses = new(); + [GlobalInit] internal static unsafe void GlobalInit() { var setBoneModelSpaceFfxiv = Services.SigScanner.ScanText("48 8B C4 48 89 58 18 55 56 57 41 54 41 55 41 56 41 57 48 81 EC ?? ?? ?? ?? 0F 29 70 B8 0F 29 78 A8 44 0F 29 40 ?? 44 0F 29 48 ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B B1"); SetBoneModelSpaceFfxivHook = Hook.FromAddress(setBoneModelSpaceFfxiv, SetBoneModelSpaceFfxivDetour); @@ -233,6 +235,7 @@ public static unsafe bool IsGamePlaybackRunning(GameObject? gPoseTarget) { return csObject->DrawObject->Skeleton->PartialSkeletons->GetHavokAnimatedSkeleton(0)->AnimationControls[0]; } + [GlobalDispose] internal static void GlobalDispose() { SetBoneModelSpaceFfxivHook.Disable(); SetBoneModelSpaceFfxivHook.Dispose(); diff --git a/Ktisis/Interop/Methods.cs b/Ktisis/Interop/Methods.cs index 51f82ff48..43038243f 100644 --- a/Ktisis/Interop/Methods.cs +++ b/Ktisis/Interop/Methods.cs @@ -5,6 +5,7 @@ using Ktisis.Structs.FFXIV; namespace Ktisis.Interop { + [GlobalState] internal class Methods { // Make actor look at co-ordinate point // a1 = Actor + 0xC20, a2 = TrackPos*, a3 = bodypart, a4 = ? @@ -32,6 +33,7 @@ internal class Methods { private static TDelegate Retrieve(string sig) => Marshal.GetDelegateForFunctionPointer(Services.SigScanner.ScanText(sig)); + [GlobalInit] internal static void GlobalInit() { ActorLookAt = Retrieve("40 53 55 57 41 56 41 57 48 83 EC 70"); ActorChangeEquip = Retrieve("E8 ?? ?? ?? ?? 41 B5 01 FF C6"); diff --git a/Ktisis/Interop/StaticOffsets.cs b/Ktisis/Interop/StaticOffsets.cs index fc7357927..3fd5297af 100644 --- a/Ktisis/Interop/StaticOffsets.cs +++ b/Ktisis/Interop/StaticOffsets.cs @@ -1,6 +1,7 @@ using System; namespace Ktisis.Interop { + [GlobalState] internal static class StaticOffsets { // Address of loaded FFXIV_CHARA files in memory. internal static IntPtr CharaDatData; @@ -17,6 +18,7 @@ internal static class StaticOffsets { internal static bool IsAnamPosing => IsPositionFrozen || IsRotationFrozen || IsScalingFrozen; // Init + [GlobalInit] internal unsafe static void GlobalInit() { var qword_14200E548 = *(IntPtr*)Services.SigScanner.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 C7 44 24 24 05 00 00 00 C6 84 24"); CharaDatData = *(IntPtr*)(qword_14200E548 + 1392); diff --git a/Ktisis/Structs/Actor/State/ActorStateWatcher.cs b/Ktisis/Structs/Actor/State/ActorStateWatcher.cs index 14d77ffb7..78b4b70bd 100644 --- a/Ktisis/Structs/Actor/State/ActorStateWatcher.cs +++ b/Ktisis/Structs/Actor/State/ActorStateWatcher.cs @@ -3,6 +3,7 @@ using System; namespace Ktisis.Structs.Actor.State { + [GlobalState] public sealed class ActorStateWatcher : IDisposable { private static ActorStateWatcher? _instance; @@ -28,6 +29,7 @@ public void Dispose() { EventManager.FireOnGposeChangeEvent(ActorGposeState.OFF); } + [GlobalInit] public static void GlobalInit() { _ = Instance; } From 4c31c6252bc42046fc41e79aadefaed64fad4026 Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Sun, 18 Dec 2022 12:06:55 +0100 Subject: [PATCH 4/9] Extract GlobalInits and GlobalDisposes --- Ktisis/Ktisis.cs | 54 +++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/Ktisis/Ktisis.cs b/Ktisis/Ktisis.cs index 816b87ec8..b3b5fd165 100644 --- a/Ktisis/Ktisis.cs +++ b/Ktisis/Ktisis.cs @@ -54,20 +54,9 @@ public Ktisis(DalamudPluginInterface pluginInterface) { // Init interop stuff - Interop.Alloc.GlobalInit(); - Interop.Methods.GlobalInit(); - Interop.StaticOffsets.GlobalInit(); - - Interop.Hooks.ActorHooks.GlobalInit(); - Interop.Hooks.ControlHooks.GlobalInit(); - Interop.Hooks.EventsHooks.GlobalInit(); - Interop.Hooks.GuiHooks.GlobalInit(); - Interop.Hooks.PoseHooks.GlobalInit(); - EventManager.OnGPoseChange += Workspace.OnEnterGposeToggle; // must be placed before ActorStateWatcher.GlobalInit() - Input.GlobalInit(); - ActorStateWatcher.GlobalInit(); + GlobalInit(); // Register command @@ -84,7 +73,6 @@ public Ktisis(DalamudPluginInterface pluginInterface) { pluginInterface.UiBuilder.DisableGposeUiHide = true; pluginInterface.UiBuilder.Draw += KtisisGui.Draw; - HistoryManager.GlobalInit(); References.LoadReferences(Configuration); } @@ -95,13 +83,7 @@ public void Dispose() { OverlayWindow.DeselectGizmo(); - Interop.Hooks.ActorHooks.GlobalDispose(); - Interop.Hooks.ControlHooks.GlobalDispose(); - Interop.Hooks.EventsHooks.GlobalDispose(); - Interop.Hooks.GuiHooks.GlobalDispose(); - Interop.Hooks.PoseHooks.GlobalDispose(); - - Interop.Alloc.GlobalDispose(); + GlobalDispose(); ActorStateWatcher.Instance.Dispose(); EventManager.OnGPoseChange -= Workspace.OnEnterGposeToggle; @@ -110,9 +92,6 @@ public void Dispose() { if (EditEquip.Items != null) EditEquip.Items = null; - Input.GlobalDispose(); - HistoryManager.GlobalDispose(); - foreach (var (_, texture) in References.Textures) { texture.Dispose(); } @@ -136,5 +115,34 @@ private void OnCommand(string command, string arguments) { break; } } + + private static void GlobalInit() { + Interop.Alloc.GlobalInit(); + Interop.Methods.GlobalInit(); + Interop.StaticOffsets.GlobalInit(); + + Interop.Hooks.ActorHooks.GlobalInit(); + Interop.Hooks.ControlHooks.GlobalInit(); + Interop.Hooks.EventsHooks.GlobalInit(); + Interop.Hooks.GuiHooks.GlobalInit(); + Interop.Hooks.PoseHooks.GlobalInit(); + + Input.GlobalInit(); + ActorStateWatcher.GlobalInit(); + + HistoryManager.GlobalInit(); + } + + private static void GlobalDispose() { + Interop.Hooks.ActorHooks.GlobalDispose(); + Interop.Hooks.ControlHooks.GlobalDispose(); + Interop.Hooks.EventsHooks.GlobalDispose(); + Interop.Hooks.GuiHooks.GlobalDispose(); + Interop.Hooks.PoseHooks.GlobalDispose(); + + Interop.Alloc.GlobalDispose(); + Input.GlobalDispose(); + HistoryManager.GlobalDispose(); + } } } From 1479845476e14c4c56b7a1015ca42ab4f64d03ce Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Sun, 18 Dec 2022 12:10:34 +0100 Subject: [PATCH 5/9] Invert the order of GlobalDisposes First to init, last to dispose; for dependency reasons. New system is going to follow this order as well. This commit exists primarily for bisection reasons. If a bisect lead you here, you just discovered an ordering problem. --- Ktisis/Ktisis.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Ktisis/Ktisis.cs b/Ktisis/Ktisis.cs index b3b5fd165..e9fc6479e 100644 --- a/Ktisis/Ktisis.cs +++ b/Ktisis/Ktisis.cs @@ -134,15 +134,15 @@ private static void GlobalInit() { } private static void GlobalDispose() { - Interop.Hooks.ActorHooks.GlobalDispose(); - Interop.Hooks.ControlHooks.GlobalDispose(); - Interop.Hooks.EventsHooks.GlobalDispose(); - Interop.Hooks.GuiHooks.GlobalDispose(); - Interop.Hooks.PoseHooks.GlobalDispose(); - - Interop.Alloc.GlobalDispose(); - Input.GlobalDispose(); HistoryManager.GlobalDispose(); + Input.GlobalDispose(); + Interop.Alloc.GlobalDispose(); + + Interop.Hooks.PoseHooks.GlobalDispose(); + Interop.Hooks.GuiHooks.GlobalDispose(); + Interop.Hooks.EventsHooks.GlobalDispose(); + Interop.Hooks.ControlHooks.GlobalDispose(); + Interop.Hooks.ActorHooks.GlobalDispose(); } } } From ba3dfed50c8e7505a6a636021e5f4cac1f38113a Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Sun, 18 Dec 2022 12:23:13 +0100 Subject: [PATCH 6/9] Make GlobalInit handling attribute-based Note that the individual initializations are currently **entirely unordered**! This may or may not present a problem later down the line. If a bisect lead you here, it does/did present a problem. --- Ktisis/Ktisis.cs | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/Ktisis/Ktisis.cs b/Ktisis/Ktisis.cs index e9fc6479e..827eed076 100644 --- a/Ktisis/Ktisis.cs +++ b/Ktisis/Ktisis.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; using Dalamud.Plugin; using Dalamud.Game.Command; @@ -116,33 +119,31 @@ private void OnCommand(string command, string arguments) { } } - private static void GlobalInit() { - Interop.Alloc.GlobalInit(); - Interop.Methods.GlobalInit(); - Interop.StaticOffsets.GlobalInit(); - - Interop.Hooks.ActorHooks.GlobalInit(); - Interop.Hooks.ControlHooks.GlobalInit(); - Interop.Hooks.EventsHooks.GlobalInit(); - Interop.Hooks.GuiHooks.GlobalInit(); - Interop.Hooks.PoseHooks.GlobalInit(); - - Input.GlobalInit(); - ActorStateWatcher.GlobalInit(); + private static Stack ToGloballyDispose = new(); - HistoryManager.GlobalInit(); + private static void GlobalInit() { + foreach (Type globalStateContainer in + typeof(Ktisis).Assembly.GetTypes() + .Where(type => type.CustomAttributes + .Any(attr => attr.AttributeType == typeof(GlobalStateAttribute)) + ) + ) { + foreach (var method in globalStateContainer.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)) { + foreach (var attr in method.CustomAttributes) { + if (attr.AttributeType == typeof(GlobalInitAttribute)) + method.Invoke(null, Array.Empty()); + else if (attr.AttributeType == typeof(GlobalDisposeAttribute)) + ToGloballyDispose.Push(method); + } + } + } + ToGloballyDispose.TrimExcess(); } private static void GlobalDispose() { - HistoryManager.GlobalDispose(); - Input.GlobalDispose(); - Interop.Alloc.GlobalDispose(); - - Interop.Hooks.PoseHooks.GlobalDispose(); - Interop.Hooks.GuiHooks.GlobalDispose(); - Interop.Hooks.EventsHooks.GlobalDispose(); - Interop.Hooks.ControlHooks.GlobalDispose(); - Interop.Hooks.ActorHooks.GlobalDispose(); + while (ToGloballyDispose.TryPop(out MethodInfo? toDispose)) { + toDispose.Invoke(null, Array.Empty()); + } } } } From c0c94478de321f3725f073dd24b6c64a10afd5bd Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Tue, 27 Dec 2022 18:20:40 +0100 Subject: [PATCH 7/9] Mark Global Disposition list as 'readonly' --- Ktisis/Ktisis.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ktisis/Ktisis.cs b/Ktisis/Ktisis.cs index 827eed076..10cf738b1 100644 --- a/Ktisis/Ktisis.cs +++ b/Ktisis/Ktisis.cs @@ -119,7 +119,7 @@ private void OnCommand(string command, string arguments) { } } - private static Stack ToGloballyDispose = new(); + private static readonly Stack ToGloballyDispose = new(); private static void GlobalInit() { foreach (Type globalStateContainer in From b08820e94a7b4dfc42d3fb61b2902eeeed72967a Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Tue, 27 Dec 2022 18:25:59 +0100 Subject: [PATCH 8/9] Extract GlobalState type searching to own method --- Ktisis/Ktisis.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Ktisis/Ktisis.cs b/Ktisis/Ktisis.cs index 10cf738b1..979aa600d 100644 --- a/Ktisis/Ktisis.cs +++ b/Ktisis/Ktisis.cs @@ -122,12 +122,7 @@ private void OnCommand(string command, string arguments) { private static readonly Stack ToGloballyDispose = new(); private static void GlobalInit() { - foreach (Type globalStateContainer in - typeof(Ktisis).Assembly.GetTypes() - .Where(type => type.CustomAttributes - .Any(attr => attr.AttributeType == typeof(GlobalStateAttribute)) - ) - ) { + foreach (Type globalStateContainer in GetGlobalInitTypes()) { foreach (var method in globalStateContainer.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)) { foreach (var attr in method.CustomAttributes) { if (attr.AttributeType == typeof(GlobalInitAttribute)) @@ -140,6 +135,10 @@ private static void GlobalInit() { ToGloballyDispose.TrimExcess(); } + private static IEnumerable GetGlobalInitTypes() => + typeof(Ktisis).Assembly.GetTypes() + .Where(x => x.CustomAttributes.Any(x => x.AttributeType == typeof(GlobalStateAttribute))); + private static void GlobalDispose() { while (ToGloballyDispose.TryPop(out MethodInfo? toDispose)) { toDispose.Invoke(null, Array.Empty()); From 3537188e018fdcc769c1deddea28f3c84e7150ed Mon Sep 17 00:00:00 2001 From: Fayti1703 Date: Tue, 27 Dec 2022 18:29:05 +0100 Subject: [PATCH 9/9] Implement InitAfter on GlobalStateAttribute --- Ktisis/GlobalStateAttribute.cs | 4 +++- Ktisis/Ktisis.cs | 26 ++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Ktisis/GlobalStateAttribute.cs b/Ktisis/GlobalStateAttribute.cs index cc661a3a3..0e83b04db 100644 --- a/Ktisis/GlobalStateAttribute.cs +++ b/Ktisis/GlobalStateAttribute.cs @@ -5,5 +5,7 @@ namespace Ktisis { * Indicates that this class has global state and may contain static methods annotated with and/or . */ [AttributeUsage(AttributeTargets.Class, Inherited = false)] - public class GlobalStateAttribute : Attribute {} + public class GlobalStateAttribute : Attribute { + public Type[] InitAfter { get; set; } = Array.Empty(); + } } diff --git a/Ktisis/Ktisis.cs b/Ktisis/Ktisis.cs index 979aa600d..ef49ba274 100644 --- a/Ktisis/Ktisis.cs +++ b/Ktisis/Ktisis.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using Dalamud.Plugin; using Dalamud.Game.Command; @@ -136,8 +137,15 @@ private static void GlobalInit() { } private static IEnumerable GetGlobalInitTypes() => - typeof(Ktisis).Assembly.GetTypes() - .Where(x => x.CustomAttributes.Any(x => x.AttributeType == typeof(GlobalStateAttribute))); + typeof(Ktisis).Assembly.GetTypes().Select(type => (type, globalStateAttr: type.GetCustomAttribute())) + .Where(x => x.globalStateAttr != null) + .OrderBy(x => (x.type, initAfter: new HashSet(x.globalStateAttr!.InitAfter)), new DelegateComparer<(Type type, HashSet initAfter)>((a, b) => { + if(a.initAfter.Contains(b.type)) + return 1; + if(b.initAfter.Contains(a.type)) + return -1; + return 0; + })).Select(x => x.type); private static void GlobalDispose() { while (ToGloballyDispose.TryPop(out MethodInfo? toDispose)) { @@ -145,4 +153,18 @@ private static void GlobalDispose() { } } } + + public struct DelegateComparer : IComparer { + + public delegate int Comparer(T? x, T? y); + + public Comparer comparer; + + public DelegateComparer(Comparer comparer) { + this.comparer = comparer; + } + + public int Compare(T? x, T? y) => this.comparer(x, y); + } + }