using System; using System.Threading; using Dalamud.Game.Addon.Lifecycle; using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; using LLib.GameUI; using Microsoft.Extensions.Logging; namespace Questionable.Controller.GameUi; internal sealed class CraftworksSupplyController : IDisposable { private readonly QuestController _questController; private readonly IAddonLifecycle _addonLifecycle; private readonly IGameGui _gameGui; private readonly IFramework _framework; private readonly ILogger _logger; private bool ShouldHandleUiInteractions => _questController.IsRunning; public CraftworksSupplyController(QuestController questController, IAddonLifecycle addonLifecycle, IGameGui gameGui, IFramework framework, ILogger logger) { _questController = questController; _addonLifecycle = addonLifecycle; _gameGui = gameGui; _framework = framework; _logger = logger; _addonLifecycle.RegisterListener(AddonEvent.PostReceiveEvent, "ContextIconMenu", ContextIconMenuPostReceiveEvent); _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "BankaCraftworksSupply", BankaCraftworksSupplyPostUpdate); } private unsafe void BankaCraftworksSupplyPostUpdate(AddonEvent type, AddonArgs args) { if (ShouldHandleUiInteractions) { AtkUnitBase* address = (AtkUnitBase*)args.Addon.Address; InteractWithBankaCraftworksSupply(address); } } private unsafe void InteractWithBankaCraftworksSupply() { if (_gameGui.TryGetAddonByName("BankaCraftworksSupply", out var addonPtr)) { InteractWithBankaCraftworksSupply(addonPtr); } } private unsafe void InteractWithBankaCraftworksSupply(AtkUnitBase* addon) { AtkValue* atkValues = addon->AtkValues; uint uInt = atkValues[7].UInt; uint num = 6 - uInt; for (int i = 0; i < num; i++) { if (atkValues[31 + i].UInt == 0) { _logger.LogInformation("Selecting an item for slot {Slot}", i); AtkValue* values = stackalloc AtkValue[2] { new AtkValue { Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int, Int = 2 }, new AtkValue { Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int, Int = i } }; addon->FireCallback(2u, values); return; } } if (atkValues[31].UInt != 0) { _logger.LogInformation("Confirming turn-in"); addon->FireCallbackInt(0); } } private unsafe void ContextIconMenuPostReceiveEvent(AddonEvent type, AddonArgs args) { if (!ShouldHandleUiInteractions) { return; } AddonContextIconMenu* address = (AddonContextIconMenu*)args.Addon.Address; if (!address->IsVisible) { return; } ushort contextMenuParentId = address->ContextMenuParentId; if (contextMenuParentId == 0) { return; } AtkUnitBase* addonById = AtkStage.Instance()->RaptureAtkUnitManager->GetAddonById(contextMenuParentId); if (addonById->NameString == "BankaCraftworksSupply") { _logger.LogInformation("Picking item for {AddonName}", addonById->NameString); AtkValue* values = stackalloc AtkValue[5] { new AtkValue { Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int, Int = 0 }, new AtkValue { Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int, Int = 0 }, new AtkValue { Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.UInt, UInt = 20802u }, new AtkValue { Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.UInt, UInt = 0u }, new AtkValue { Type = FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Undefined, Int = 0 } }; address->FireCallback(5u, values); address->Close(fireCallback: true); if (addonById->NameString == "BankaCraftworksSupply") { _framework.RunOnTick((Action)InteractWithBankaCraftworksSupply, TimeSpan.FromMilliseconds(50L, 0L), 0, default(CancellationToken)); } } else { _logger.LogTrace("Ignoring contextmenu event for {AddonName}", addonById->NameString); } } public void Dispose() { _addonLifecycle.UnregisterListener(AddonEvent.PostSetup, "BankaCraftworksSupply", BankaCraftworksSupplyPostUpdate); _addonLifecycle.UnregisterListener(AddonEvent.PostReceiveEvent, "ContextIconMenu", ContextIconMenuPostReceiveEvent); } }