Files
ClubPenguinClient/MareSynchronos/Utils/DalamudUtil.cs

129 lines
4.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Penumbra.PlayerWatch;
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
namespace MareSynchronos.Utils
{
public delegate void PlayerChange(Character actor);
public class DalamudUtil : IDisposable
{
private readonly ClientState _clientState;
private readonly ObjectTable _objectTable;
private readonly IPlayerWatcher _watcher;
public event PlayerChange? PlayerChanged;
public DalamudUtil(ClientState clientState, ObjectTable objectTable, IPlayerWatcher watcher)
{
_clientState = clientState;
_objectTable = objectTable;
_watcher = watcher;
_watcher.Enable();
_watcher.PlayerChanged += WatcherOnPlayerChanged;
}
private void WatcherOnPlayerChanged(Character actor)
{
PlayerChanged?.Invoke(actor);
}
public void AddPlayerToWatch(string playerName)
{
_watcher.AddPlayerToWatch(playerName);
}
public void RemovePlayerFromWatch(string playerName)
{
_watcher.RemovePlayerFromWatch(playerName);
}
public bool IsPlayerPresent => _clientState.LocalPlayer != null;
public string PlayerName => _clientState.LocalPlayer?.Name.ToString() ?? "--";
public int PlayerJobId => (int)_clientState.LocalPlayer!.ClassJob.Id;
public IntPtr PlayerPointer => _clientState.LocalPlayer!.Address;
public string PlayerNameHashed => Crypto.GetHash256(PlayerName + _clientState.LocalPlayer!.HomeWorld.Id);
public Dictionary<string, PlayerCharacter> GetLocalPlayers()
{
if (!_clientState.IsLoggedIn)
{
return new Dictionary<string, PlayerCharacter>();
}
Dictionary<string, PlayerCharacter> allLocalPlayers = new();
foreach (var obj in _objectTable)
{
if (obj.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player) continue;
string playerName = obj.Name.ToString();
if (playerName == PlayerName) continue;
var playerObject = (PlayerCharacter)obj;
allLocalPlayers[Crypto.GetHash256(playerObject.Name.ToString() + playerObject.HomeWorld.Id.ToString())] = playerObject;
}
return allLocalPlayers;
}
public List<PlayerCharacter> GetPlayerCharacters()
{
return _objectTable.Where(obj =>
obj.ObjectKind == Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player &&
obj.Name.ToString() != PlayerName).Select(p => (PlayerCharacter)p).ToList();
}
public PlayerCharacter? GetPlayerCharacterFromObjectTableIndex(int index)
{
var objTableObj = _objectTable[index];
if (objTableObj!.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player) return null;
return (PlayerCharacter)objTableObj;
}
public PlayerCharacter? GetPlayerCharacterFromObjectTableByName(string characterName)
{
foreach (var item in _objectTable)
{
if (item.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player) continue;
if (item.Name.ToString() == characterName) return (PlayerCharacter)item;
}
return null;
}
public unsafe void WaitWhileCharacterIsDrawing(IntPtr characterAddress)
{
if (!_clientState.IsLoggedIn) return;
var obj = (GameObject*)characterAddress;
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
while ((obj->RenderFlags & 0b100000000000) == 0b100000000000) // 0b100000000000 is "still rendering" or something
{
Logger.Debug("Waiting for character to finish drawing");
Thread.Sleep(1000);
}
// wait half a second just in case
Thread.Sleep(500);
}
public void WaitWhileSelfIsDrawing() => WaitWhileCharacterIsDrawing(_clientState.LocalPlayer?.Address ?? new IntPtr());
public void Dispose()
{
_watcher.Disable();
_watcher.Dispose();
}
}
}