Skip to content

Commit

Permalink
[Action Press Mirroring] Rewrite & Fix
Browse files Browse the repository at this point in the history
  • Loading branch information
Caraxi committed Oct 9, 2023
1 parent 262cd70 commit f1cdfac
Showing 1 changed file with 33 additions and 127 deletions.
160 changes: 33 additions & 127 deletions Tweaks/UiAdjustment/ActionPressMirroring.cs
Original file line number Diff line number Diff line change
@@ -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<PulseActionBarSlot> pulseActionBarSlotHook = null!;

private HookWrapper<PulseActionBarSlot> 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",
Expand All @@ -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<PulseActionBarSlot>(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<AddonActionBarBase>(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();
}
}

0 comments on commit f1cdfac

Please sign in to comment.