using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game; using FFXIVClientStructs.FFXIV.Client.Game.UI; using Lumina.Excel.Sheets; using Microsoft.Extensions.Logging; namespace LLib.GameData; public sealed class TeleportHelper { private const uint TeleportAction = 5u; private readonly GameStateHelper _gameState; private readonly ILogger _logger; private readonly uint _teleportUnlockLink; public TeleportHelper(IDataManager dataManager, GameStateHelper gameState, ILogger logger) { _gameState = gameState; _logger = logger; _teleportUnlockLink = dataManager.GetExcelSheet().GetRow(5u).UnlockLink.RowId; } public unsafe bool IsAetheryteUnlocked(uint aetheryteId) { UIState* ptr = UIState.Instance(); if (ptr != null) { return ptr->IsAetheryteUnlocked(aetheryteId); } return false; } public unsafe bool CanTeleport() { ActionManager* ptr = ActionManager.Instance(); if (ptr != null) { return ptr->GetActionStatus(ActionType.Action, 5u, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) == 0; } return false; } public unsafe bool IsTeleportUnlocked() { UIState* ptr = UIState.Instance(); if (ptr != null) { return ptr->IsUnlockLinkUnlocked(_teleportUnlockLink); } return false; } public unsafe bool IsFreeAetheryte(uint aetheryteId) { PlayerState* ptr = PlayerState.Instance(); if (ptr != null) { if (ptr->FreeAetheryteId != aetheryteId && ptr->FreeAetherytePSPlus != aetheryteId) { return ptr->FreeAetheryteNSO == aetheryteId; } return true; } return false; } public unsafe bool Teleport(uint aetheryteId, byte subIndex = 0) { if (!IsTeleportUnlocked()) { _logger.LogWarning("Teleport action is not unlocked; skipping teleport to {Id}", aetheryteId); return false; } if (!CanTeleport()) { _logger.LogDebug("Teleport to {Id} blocked: action on cooldown", aetheryteId); return false; } if (!IsAetheryteUnlocked(aetheryteId)) { _logger.LogWarning("Aetheryte {Id} is not unlocked; skipping teleport", aetheryteId); return false; } if (_gameState.IsLoadingScreenVisible()) { _logger.LogDebug("Skipping teleport to {Id}: loading screen visible", aetheryteId); return false; } Telepo* ptr = Telepo.Instance(); if (ptr == null) { return false; } _logger.LogInformation("Teleporting to aetheryte {Id}", aetheryteId); return ptr->Teleport(aetheryteId, subIndex); } }