qstbak/LLib/LLib.GameData/GameStateHelper.cs
2026-08-17 20:29:32 +10:00

224 lines
6.5 KiB
C#

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Component.GUI;
using LLib.GameUI;
using Lumina.Excel.Sheets;
using Microsoft.Extensions.Logging;
namespace LLib.GameData;
public sealed class GameStateHelper
{
private readonly IDataManager _dataManager;
private readonly IClientState _clientState;
private readonly ICondition _condition;
private readonly IObjectTable _objectTable;
private readonly IGameGui _gameGui;
private readonly ILogger<GameStateHelper> _logger;
private readonly ReadOnlyDictionary<uint, uint> _territoryToAetherCurrentCompFlgSet;
public GameStateHelper(IDataManager dataManager, IClientState clientState, ICondition condition, IObjectTable objectTable, IGameGui gameGui, ILogger<GameStateHelper> logger)
{
_dataManager = dataManager;
_clientState = clientState;
_condition = condition;
_objectTable = objectTable;
_gameGui = gameGui;
_logger = logger;
_territoryToAetherCurrentCompFlgSet = (from x in dataManager.GetExcelSheet<TerritoryType>()
where x.RowId != 0
where x.AetherCurrentCompFlgSet.RowId != 0
select x).ToDictionary((TerritoryType x) => x.RowId, (TerritoryType x) => x.AetherCurrentCompFlgSet.RowId).AsReadOnly();
}
public bool IsFlyingUnlocked(uint territoryId)
{
if (_territoryToAetherCurrentCompFlgSet.TryGetValue(territoryId, out var value))
{
return PlayerStateHelper.IsAetherCurrentZoneComplete(value);
}
return false;
}
public bool IsFlyingUnlockedInCurrentZone()
{
return IsFlyingUnlocked(_clientState.TerritoryType);
}
public unsafe ushort? GetMountId()
{
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
if (localPlayer == null)
{
return null;
}
BattleChara* address = (BattleChara*)localPlayer.Address;
if (address == null || address->Mount.MountId == 0)
{
return null;
}
return address->Mount.MountId;
}
public unsafe bool HasStatusPreventingMount()
{
if (_condition[ConditionFlag.Swimming] && !IsFlyingUnlockedInCurrentZone())
{
return true;
}
if (!PlayerStateHelper.IsAnyMountUnlocked())
{
return true;
}
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
if (localPlayer == null)
{
return false;
}
BattleChara* address = (BattleChara*)localPlayer.Address;
StatusManager* statusManager = address->GetStatusManager();
if (statusManager->HasStatus(1151u) || statusManager->HasStatus(1945u))
{
return true;
}
return HasStatusPreventingMountOrSprint();
}
public bool HasStatusPreventingSprint()
{
return HasStatusPreventingMountOrSprint();
}
public unsafe bool Mount(uint preferredMountId = 0u)
{
if (_condition[ConditionFlag.Mounted])
{
return true;
}
if (HasStatusPreventingMount())
{
_logger.LogDebug("Cannot mount: status or condition prevents it");
return false;
}
if (preferredMountId != 0 && PlayerStateHelper.IsMountUnlocked(preferredMountId))
{
if (ActionManager.Instance()->GetActionStatus(ActionType.Mount, preferredMountId, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) == 0)
{
_logger.LogDebug("Attempting preferred mount {Id}", preferredMountId);
if (ActionManager.Instance()->UseAction(ActionType.Mount, preferredMountId, 3758096384uL, 0u, ActionManager.UseActionMode.None, 0u, null))
{
_logger.LogInformation("Mounted (preferred {Id})", preferredMountId);
return true;
}
}
return false;
}
if (ActionManager.Instance()->GetActionStatus(ActionType.GeneralAction, 9u, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) == 0)
{
_logger.LogDebug("Attempting mount roulette");
if (ActionManager.Instance()->UseAction(ActionType.GeneralAction, 9u, 3758096384uL, 0u, ActionManager.UseActionMode.None, 0u, null))
{
_logger.LogInformation("Mounted (roulette)");
return true;
}
}
return false;
}
public unsafe bool Unmount()
{
if (!_condition[ConditionFlag.Mounted])
{
return true;
}
if (ActionManager.Instance()->GetActionStatus(ActionType.GeneralAction, 23u, 3758096384uL, checkRecastActive: true, checkCastingActive: true, null) != 0)
{
_logger.LogDebug("Cannot unmount: action on cooldown");
return false;
}
_logger.LogDebug("Attempting dismount");
if (ActionManager.Instance()->UseAction(ActionType.GeneralAction, 23u, 3758096384uL, 0u, ActionManager.UseActionMode.None, 0u, null))
{
_logger.LogInformation("Unmounted");
return true;
}
return false;
}
public unsafe int? GetFreeInventorySlots()
{
InventoryManager* ptr = InventoryManager.Instance();
if (ptr == null)
{
return null;
}
int num = 0;
for (InventoryType inventoryType = InventoryType.Inventory1; inventoryType <= InventoryType.Inventory4; inventoryType++)
{
InventoryContainer* inventoryContainer = ptr->GetInventoryContainer(inventoryType);
if (inventoryContainer == null)
{
return null;
}
for (int i = 0; i < inventoryContainer->Size; i++)
{
InventoryItem* inventorySlot = inventoryContainer->GetInventorySlot(i);
if (inventorySlot == null || inventorySlot->ItemId == 0)
{
num++;
}
}
}
return num;
}
public uint GetItemLevel(uint itemId)
{
return _dataManager.GetExcelSheet<Item>().GetRowOrDefault(itemId)?.LevelItem.RowId ?? 0;
}
public unsafe bool IsLoadingScreenVisible()
{
if (_gameGui.TryGetAddonByName<AtkUnitBase>("FadeMiddle", out var addonPtr) && LAddon.IsAddonReady(addonPtr) && addonPtr->IsVisible)
{
return true;
}
if (_gameGui.TryGetAddonByName<AtkUnitBase>("FadeBack", out addonPtr) && LAddon.IsAddonReady(addonPtr) && addonPtr->IsVisible)
{
return true;
}
if (_gameGui.TryGetAddonByName<AtkUnitBase>("NowLoading", out addonPtr) && LAddon.IsAddonReady(addonPtr) && addonPtr->IsVisible)
{
return true;
}
return false;
}
private unsafe bool HasStatusPreventingMountOrSprint()
{
IPlayerCharacter localPlayer = _objectTable.LocalPlayer;
if (localPlayer == null)
{
return false;
}
BattleChara* address = (BattleChara*)localPlayer.Address;
StatusManager* statusManager = address->GetStatusManager();
if (!statusManager->HasStatus(565u) && !statusManager->HasStatus(404u) && !statusManager->HasStatus(416u) && !statusManager->HasStatus(2729u))
{
return statusManager->HasStatus(2730u);
}
return true;
}
}