private void FillControlHints()
    {
        Dictionary <HotbarSlotCommand, string> commandControlHints = new Dictionary <HotbarSlotCommand, string>(allActionBars.Length * actionBarLength);

        for (int i = 0; i < Math.Min(recordedControlHints.Length, recordedCommands.Length); i++)
        {
            if (recordedControlHints[i] == null || recordedCommands[i] == null)
            {
                continue;
            }
            for (int j = 0; j < Math.Min(recordedControlHints[i].Length, recordedCommands[i].Length); j++)
            {
                if (recordedCommands[i][j].Type != HotbarSlotType.Empty && recordedControlHints[i][j] != null && recordedControlHints[i][j].Length > 0)
                {
                    commandControlHints.TryAdd(recordedCommands[i][j], recordedControlHints[i][j]);
                }
            }
        }

        foreach (var actionBar in allActionBars)
        {
            AddonActionBarBase *ab = GetActionBarAddon(actionBar);
            if (ab != null && ab->ActionBarSlotsAction != null)
            {
                FillHotbarControlHints(ab, commandControlHints);
            }
        }
    }
    private bool UpdateHotbarRecordedControlHints(AddonActionBarBase *ab, StringArrayData *strArrayData = null)
    {
        if (ab == null || ab->ActionBarSlotsAction == null)
        {
            return(false);
        }

        if (strArrayData == null)
        {
            strArrayData = Framework.Instance()->GetUiModule()->GetRaptureAtkModule()->AtkModule.AtkArrayDataHolder.StringArrays[StrDataIndex];
        }

        var numSlots = ab->HotbarSlotCount;

        var changeFound = false;

        if (recordedControlHints[ab->HotbarID] == null || recordedControlHints[ab->HotbarID].Length != numSlots || recordedControlHints[ab->HotbarID].Length != numSlots)
        {
            recordedControlHints[ab->HotbarID] = new string[numSlots];
            changeFound = true;
        }

        for (int i = 0; i < numSlots; i++)
        {
            var currentControlHint = Marshal.PtrToStringUTF8(new IntPtr(strArrayData->StringArray[(ab->HotbarID * StrDataHotbarLength + i) * StrDataSlotLength + StrDataHintIndex]));
            if (recordedControlHints?[ab->HotbarID]?[i] != currentControlHint)
            {
                recordedControlHints[ab->HotbarID][i] = currentControlHint;
                changeFound = true;
            }
        }

        return(changeFound);
    }
        private byte DoubleCrossBarBaseUpdateDetour(AddonActionBarBase *atkUnitBase, NumberArrayData **numberArrayData, StringArrayData **stringArrayData)
        {
            var ret = doubleCrossBarUpdateHook.Original(atkUnitBase, numberArrayData, stringArrayData);

            try {
                Update(atkUnitBase);
            } catch {
                //
            }
            return(ret);
        }
 private void Reset()
 {
     foreach (var actionBar in allActionBars)
     {
         AddonActionBarBase *ab = GetActionBarAddon(actionBar);
         if (ab != null && ab->ActionBarSlotsAction != null)
         {
             ResetHotbar(ab);
         }
     }
     recordedControlHints = new string[allActionBars.Length][];
     recordedCommands     = new HotbarSlotCommand[allActionBars.Length][];
 }
    private bool UpdateCommands()
    {
        var changeFound = false;

        foreach (var actionBar in allActionBars)
        {
            AddonActionBarBase *ab = GetActionBarAddon(actionBar);
            if (ab != null)
            {
                changeFound |= UpdateHotbarCommands(ab);
            }
        }
        return(changeFound);
    }
    private bool UpdateHotbarRecordedControlHints()
    {
        var changeFound = false;

        foreach (var actionBar in allActionBars)
        {
            AddonActionBarBase *ab = GetActionBarAddon(actionBar);
            if (ab != null && ab->ActionBarSlotsAction != null)
            {
                changeFound |= UpdateHotbarRecordedControlHints(ab);
            }
        }
        return(changeFound);
    }
    private bool UpdateHotbarCommands(AddonActionBarBase *ab)
    {
        if (ab == null)
        {
            return(false);
        }
        var hotbarModule = Framework.Instance()->GetUiModule()->GetRaptureHotbarModule();
        var name         = Marshal.PtrToStringUTF8(new IntPtr(ab->AtkUnitBase.Name));

        if (name == null)
        {
            return(false);
        }
        var hotbar = hotbarModule->HotBar[ab->HotbarID];

        if (hotbar == null)
        {
            return(false);
        }

        var numSlots = ab->HotbarSlotCount;

        var changeFound = false;

        if (recordedCommands[ab->HotbarID] == null || recordedCommands[ab->HotbarID].Length != numSlots)
        {
            recordedCommands[ab->HotbarID] = new HotbarSlotCommand[numSlots];
            changeFound = true;
        }

        for (int i = 0; i < numSlots; i++)
        {
            var command    = new HotbarSlotCommand();
            var slotStruct = hotbar->Slot[i];
            if (slotStruct != null)
            {
                command.Type = slotStruct->CommandType;
                command.Id   = slotStruct->CommandType == HotbarSlotType.Action ? actionManager->GetAdjustedActionId(slotStruct->CommandId) : slotStruct->CommandId;
            }

            if (!command.Equals(recordedCommands[ab->HotbarID][i]))
            {
                recordedCommands[ab->HotbarID][i] = command;
                changeFound = true;
            }
        }

        return(changeFound);
    }
    private void FillHotbarControlHints(AddonActionBarBase *ab, Dictionary <HotbarSlotCommand, string> commandControlHints)
    {
        if (ab == null || ab->ActionBarSlotsAction == null)
        {
            return;
        }
        var hotbarModule = Framework.Instance()->GetUiModule()->GetRaptureHotbarModule();
        var name         = Marshal.PtrToStringUTF8(new IntPtr(ab->AtkUnitBase.Name));

        if (name == null)
        {
            return;
        }
        var hotbar = hotbarModule->HotBar[ab->HotbarID];

        if (hotbar == null)
        {
            return;
        }

        for (int i = 0; i < ab->HotbarSlotCount; i++)
        {
            if (recordedCommands?[ab->HotbarID]?[i] == null)
            {
                continue;
            }

            var slot = ab->ActionBarSlotsAction[i];
            if (slot.ControlHintTextNode != null)
            {
                var controlHint = recordedControlHints?[ab->HotbarID]?[i];
                if (controlHint == null || controlHint.Length == 0)
                {
                    var command = recordedCommands[ab->HotbarID][i];
                    if (commandControlHints.ContainsKey(command))
                    {
                        controlHint = commandControlHints[command];
                    }
                }

                slot.ControlHintTextNode->SetText(controlHint);
            }
        }
    }
    private byte ActionBarBaseUpdateDetour(AddonActionBarBase *addonActionBarBase, NumberArrayData **numberArrayData, StringArrayData **stringArrayData)
    {
        var changesFound = false;

        var hotbarID = addonActionBarBase->HotbarID;

        if (hotbarID < allActionBars.Length)
        {
            changesFound  = UpdateHotbarRecordedControlHints(addonActionBarBase, stringArrayData[StrDataIndex]);
            changesFound |= UpdateHotbarCommands(addonActionBarBase);
        }

        var ret = actionBarBaseUpdateHook.Original(addonActionBarBase, numberArrayData, stringArrayData);

        if (changesFound)
        {
            FillControlHints();
        }
        return(ret);
    }
    private void ResetHotbar(AddonActionBarBase *ab)
    {
        if (ab == null || ab->ActionBarSlotsAction == null)
        {
            return;
        }

        var numSlots = ab->HotbarSlotCount;

        for (int i = 0; i < numSlots; i++)
        {
            var slot = ab->ActionBarSlotsAction[i];
            if (slot.ControlHintTextNode != null)
            {
                var normalControlHint = recordedControlHints?[ab->HotbarID]?[i];
                if (normalControlHint != null)
                {
                    slot.ControlHintTextNode->SetText(normalControlHint);
                }
            }
        }
    }