From f1cdfacdcd5540d08dafc9a162c106186d00b914 Mon Sep 17 00:00:00 2001 From: Caraxi Date: Tue, 10 Oct 2023 00:50:48 +1030 Subject: [PATCH] [`Action Press Mirroring`] Rewrite & Fix --- Tweaks/UiAdjustment/ActionPressMirroring.cs | 160 ++++---------------- 1 file changed, 33 insertions(+), 127 deletions(-) diff --git a/Tweaks/UiAdjustment/ActionPressMirroring.cs b/Tweaks/UiAdjustment/ActionPressMirroring.cs index 16b51b0f..6531da2f 100644 --- a/Tweaks/UiAdjustment/ActionPressMirroring.cs +++ b/Tweaks/UiAdjustment/ActionPressMirroring.cs @@ -1,32 +1,24 @@ -using FFXIVClientStructs.FFXIV.Client.Game; -using FFXIVClientStructs.FFXIV.Client.System.Framework; +using System; +using Dalamud.Utility.Signatures; +using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI.Misc; +using SimpleTweaksPlugin.TweakSystem; using SimpleTweaksPlugin.Utility; -using System; -using System.Runtime.InteropServices; -using FFXIVClientStructs.Interop; namespace SimpleTweaksPlugin.Tweaks.UiAdjustment; -public unsafe class ActionPressMirroring : UiAdjustments.SubTweak -{ +[TweakName("Duplicate Action Presses Between Hotbars")] +[TweakDescription("Shows the pulse effect when activating actions, even if they are duplicated between hotbars.")] +[TweakAuthor("BoredDan")] +[TweakVersion(2)] +public unsafe class ActionPressMirroring : UiAdjustments.SubTweak { + private delegate void PulseActionBarSlot(AddonActionBarBase* addonActionBarBase, uint slotIndex, ulong a3, int a4); - private delegate void PulseActionBarSlot(AddonActionBarBase* addonActionBarBase, int slotIndex); + [TweakHook, Signature("85 d2 78 ?? 48 89 5c 24 ?? 57 48 83 ec ?? 48 63 da 48 8b f9 48 8b 89 ?? ?? ?? ?? ba", DetourName = nameof(PulseActionBarSlotDetour))] + private readonly HookWrapper pulseActionBarSlotHook = null!; - private HookWrapper pulseActionBarSlotHook; - - private static string PulseActionBarSlotSig = "85 d2 78 ?? 48 89 5c 24 ?? 57 48 83 ec ?? 48 63 da 48 8b f9 48 8b 89 ?? ?? ?? ?? ba"; - - private ActionManager* actionManager; - - private bool tweakIsPulsing = false; - - public override string Name => "Duplicate Action Presses Between Hotbars"; - public override string Description => "Shows the pulse effect when activating actions, even if they are duplicated between hotbars."; - protected override string Author => "BoredDan"; - - private static readonly string[] allActionBars = { + private static readonly string[] AllActionBars = { "_ActionBar", "_ActionBar01", "_ActionBar02", @@ -43,121 +35,35 @@ public unsafe class ActionPressMirroring : UiAdjustments.SubTweak "_ActionBarEx", }; - protected override void Enable() + private void PulseActionBarSlotDetour(AddonActionBarBase* ab, uint slotIndex, ulong a3, int a4) { - pulseActionBarSlotHook ??= Common.Hook(PulseActionBarSlotSig, PulseActionBarSlotDetour); - pulseActionBarSlotHook?.Enable(); - actionManager = ActionManager.Instance(); - base.Enable(); + HandlePulse(ab, slotIndex, a3, a4); + pulseActionBarSlotHook.Original(ab, slotIndex, a3, a4); } - private static AddonActionBarBase* GetActionBarAddon(string actionBar) - { - return (AddonActionBarBase*)Service.GameGui.GetAddonByName(actionBar, 1); - } - - private void PulseActionBarSlotDetour(AddonActionBarBase* ab, int slotIndex) - { - if (tweakIsPulsing) goto PulseSlot; - - var hotbarModule = Framework.Instance()->GetUiModule()->GetRaptureHotbarModule(); - var name = Marshal.PtrToStringUTF8(new IntPtr(ab->AtkUnitBase.Name)); - if (name == null) goto PulseSlot; - var hotbar = hotbarModule->HotBarsSpan.GetPointer(ab->RaptureHotbarId); - if (hotbar == null) goto PulseSlot; - var numSlots = ab->SlotCount; - if (numSlots <= slotIndex) goto PulseSlot; - - tweakIsPulsing = true; - - var slot = hotbar->SlotsSpan.GetPointer(slotIndex); - var commandType = slot->CommandType; - var commandId = slot->CommandType == HotbarSlotType.Action ? actionManager->GetAdjustedActionId(slot->CommandId) : slot->CommandId; - - foreach (var actionBar in allActionBars) - { - var currentActionBar = (AddonActionBarBase*)Service.GameGui.GetAddonByName(actionBar, 1); - if (currentActionBar != null) - { - var isCross = actionBar.StartsWith("_ActionCross"); - var crossBar = isCross ? (AddonActionCross*)currentActionBar : null; - var crossExpandedHoldControls = isCross ? crossBar->ExpandedHoldControls : 0; - var isExpandedCross = crossExpandedHoldControls > 0; - - var isDoubleCross = actionBar.StartsWith("_ActionDoubleCross"); - var doubleCrossBar = isDoubleCross ? (AddonActionDoubleCrossBase*)currentActionBar : null; - - numSlots = currentActionBar->SlotCount; - - int currentHotbarId = currentActionBar->RaptureHotbarId; - if (isExpandedCross) - { - // crossExpandedHoldControls value 1-16 = left/right sides of cross bars 1-8 (IDs 10-17) - currentHotbarId = (crossExpandedHoldControls < 17) ? (((crossExpandedHoldControls - 1) >> 1) + 10) : - // 17-20 = "Cycle" options (uses bar before/after main active bar) - (currentActionBar->RaptureHotbarId + (crossExpandedHoldControls < 19 ? 1 : -1) - 2) % 8 + 10; - } - else if (isDoubleCross) - { - currentHotbarId = doubleCrossBar->BarTarget; - } - - var currentHotbar = hotbarModule->HotBarsSpan.GetPointer(currentHotbarId); - - if (currentHotbar != null) - { - var offset = 0; - var from = 0; - var to = numSlots; - - if(isExpandedCross) - { - var exUseLeftSide = crossExpandedHoldControls & 1; - - //expanded cross hotbar uses middle 8 slots with left 4 and right 4 not visible - offset = (exUseLeftSide != 0 ? -4 : 4); - from = 4; - to -= 4; - } - else if(isDoubleCross && doubleCrossBar->UseLeftSide == 0) - { - offset = 8; - } + private uint GetAdjustedId(HotbarSlotType type, uint id) => type switch { + HotbarSlotType.Action => ActionManager.Instance()->GetAdjustedActionId(id), + _ => id + }; - for (int i = from; i < to; i++) { - slot = currentHotbar->SlotsSpan.GetPointer(i + offset); - var currentCommandType = slot->CommandType; - var currentCommandId = slot->CommandType == HotbarSlotType.Action ? actionManager->GetAdjustedActionId(slot->CommandId) : slot->CommandId; - if (currentCommandType == commandType && currentCommandId == commandId) - { - currentActionBar->PulseActionBarSlot(i); + private void HandlePulse(AddonActionBarBase* ab, uint slotIndex, ulong a3, int a4) { + try { + var slot = RaptureHotbarModule.Instance()->GetSlotById(ab->RaptureHotbarId, slotIndex); + var id = GetAdjustedId(slot->CommandType, slot->CommandId); + foreach (var barName in AllActionBars) { + if (Common.GetUnitBase(out var bar, barName)) { + for (var i = 0U; i < bar->SlotCount; i++) { + if (bar == ab && i == slotIndex) continue; + var barSlot = RaptureHotbarModule.Instance()->GetSlotById(bar->RaptureHotbarId, i); + if (barSlot->CommandType == slot->CommandType && GetAdjustedId(barSlot->CommandType, barSlot->CommandId) == id) { + pulseActionBarSlotHook.Original(bar, i, a3, a4); } } } } + } catch (Exception ex) { + SimpleLog.Error(ex, "Error in HandlePulse"); } - tweakIsPulsing = false; - - return; - - PulseSlot: - - pulseActionBarSlotHook.Original(ab, slotIndex); - return; - - } - - protected override void Disable() - { - pulseActionBarSlotHook?.Disable(); - base.Disable(); - } - - public override void Dispose() - { - pulseActionBarSlotHook?.Dispose(); - base.Dispose(); } } -