mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Merge pull request #2458 from Haselnussbomber/struct-enumerators
[API14] Use struct enumerators/types
This commit is contained in:
commit
ba0cf4c990
12 changed files with 424 additions and 344 deletions
|
|
@ -63,47 +63,37 @@ public interface IAetheryteEntry
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class representing an aetheryte entry available to the game.
|
||||
/// This struct represents an aetheryte entry available to the game.
|
||||
/// </summary>
|
||||
internal sealed class AetheryteEntry : IAetheryteEntry
|
||||
/// <param name="data">Data read from the Aetheryte List.</param>
|
||||
internal readonly struct AetheryteEntry(TeleportInfo data) : IAetheryteEntry
|
||||
{
|
||||
private readonly TeleportInfo data;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AetheryteEntry"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">Data read from the Aetheryte List.</param>
|
||||
internal AetheryteEntry(TeleportInfo data)
|
||||
{
|
||||
this.data = data;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public uint AetheryteId => data.AetheryteId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public uint AetheryteId => this.data.AetheryteId;
|
||||
public uint TerritoryId => data.TerritoryId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public uint TerritoryId => this.data.TerritoryId;
|
||||
public byte SubIndex => data.SubIndex;
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte SubIndex => this.data.SubIndex;
|
||||
public byte Ward => data.Ward;
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte Ward => this.data.Ward;
|
||||
public byte Plot => data.Plot;
|
||||
|
||||
/// <inheritdoc />
|
||||
public byte Plot => this.data.Plot;
|
||||
public uint GilCost => data.GilCost;
|
||||
|
||||
/// <inheritdoc />
|
||||
public uint GilCost => this.data.GilCost;
|
||||
public bool IsFavourite => data.IsFavourite;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsFavourite => this.data.IsFavourite;
|
||||
public bool IsSharedHouse => data.IsSharedHouse;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsSharedHouse => this.data.IsSharedHouse;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsApartment => this.data.IsApartment;
|
||||
public bool IsApartment => data.IsApartment;
|
||||
|
||||
/// <inheritdoc />
|
||||
public RowRef<Lumina.Excel.Sheets.Aetheryte> AetheryteData => LuminaUtils.CreateRef<Lumina.Excel.Sheets.Aetheryte>(this.AetheryteId);
|
||||
|
|
|
|||
|
|
@ -87,10 +87,7 @@ internal sealed partial class AetheryteList
|
|||
/// <inheritdoc/>
|
||||
public IEnumerator<IAetheryteEntry> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
yield return this[i];
|
||||
}
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -98,4 +95,30 @@ internal sealed partial class AetheryteList
|
|||
{
|
||||
return this.GetEnumerator();
|
||||
}
|
||||
|
||||
private struct Enumerator(AetheryteList aetheryteList) : IEnumerator<IAetheryteEntry>
|
||||
{
|
||||
private int index = 0;
|
||||
|
||||
public IAetheryteEntry Current { get; private set; }
|
||||
|
||||
object IEnumerator.Current => this.Current;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (this.index == aetheryteList.Length) return false;
|
||||
this.Current = aetheryteList[this.index];
|
||||
this.index++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ using Dalamud.Plugin.Services;
|
|||
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
|
||||
using CSBuddy = FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy;
|
||||
using CSBuddyMember = FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy.BuddyMember;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Buddy;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -21,7 +24,7 @@ namespace Dalamud.Game.ClientState.Buddy;
|
|||
#pragma warning restore SA1015
|
||||
internal sealed partial class BuddyList : IServiceType, IBuddyList
|
||||
{
|
||||
private const uint InvalidObjectID = 0xE0000000;
|
||||
private const uint InvalidEntityId = 0xE0000000;
|
||||
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly ClientState clientState = Service<ClientState>.Get();
|
||||
|
|
@ -69,7 +72,7 @@ internal sealed partial class BuddyList : IServiceType, IBuddyList
|
|||
}
|
||||
}
|
||||
|
||||
private unsafe FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy* BuddyListStruct => &UIState.Instance()->Buddy;
|
||||
private unsafe CSBuddy* BuddyListStruct => &UIState.Instance()->Buddy;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IBuddyMember? this[int index]
|
||||
|
|
@ -82,37 +85,37 @@ internal sealed partial class BuddyList : IServiceType, IBuddyList
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe IntPtr GetCompanionBuddyMemberAddress()
|
||||
public unsafe nint GetCompanionBuddyMemberAddress()
|
||||
{
|
||||
return (IntPtr)this.BuddyListStruct->CompanionInfo.Companion;
|
||||
return (nint)this.BuddyListStruct->CompanionInfo.Companion;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe IntPtr GetPetBuddyMemberAddress()
|
||||
public unsafe nint GetPetBuddyMemberAddress()
|
||||
{
|
||||
return (IntPtr)this.BuddyListStruct->PetInfo.Pet;
|
||||
return (nint)this.BuddyListStruct->PetInfo.Pet;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe IntPtr GetBattleBuddyMemberAddress(int index)
|
||||
public unsafe nint GetBattleBuddyMemberAddress(int index)
|
||||
{
|
||||
if (index < 0 || index >= 3)
|
||||
return IntPtr.Zero;
|
||||
return 0;
|
||||
|
||||
return (IntPtr)Unsafe.AsPointer(ref this.BuddyListStruct->BattleBuddies[index]);
|
||||
return (nint)Unsafe.AsPointer(ref this.BuddyListStruct->BattleBuddies[index]);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IBuddyMember? CreateBuddyMemberReference(IntPtr address)
|
||||
public unsafe IBuddyMember? CreateBuddyMemberReference(nint address)
|
||||
{
|
||||
if (address == 0)
|
||||
return null;
|
||||
|
||||
if (this.clientState.LocalContentId == 0)
|
||||
return null;
|
||||
|
||||
if (address == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
var buddy = new BuddyMember(address);
|
||||
if (buddy.ObjectId == InvalidObjectID)
|
||||
var buddy = new BuddyMember((CSBuddyMember*)address);
|
||||
if (buddy.EntityId == InvalidEntityId)
|
||||
return null;
|
||||
|
||||
return buddy;
|
||||
|
|
@ -130,12 +133,35 @@ internal sealed partial class BuddyList
|
|||
/// <inheritdoc/>
|
||||
public IEnumerator<IBuddyMember> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
yield return this[i];
|
||||
}
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
||||
|
||||
private struct Enumerator(BuddyList buddyList) : IEnumerator<IBuddyMember>
|
||||
{
|
||||
private int index = 0;
|
||||
|
||||
public IBuddyMember Current { get; private set; }
|
||||
|
||||
object IEnumerator.Current => this.Current;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (this.index == buddyList.Length) return false;
|
||||
this.Current = buddyList[this.index];
|
||||
this.index++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,24 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
|
||||
using Lumina.Excel;
|
||||
|
||||
using CSBuddyMember = FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy.BuddyMember;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Buddy;
|
||||
|
||||
/// <summary>
|
||||
/// Interface representing represents a buddy such as the chocobo companion, summoned pets, squadron groups and trust parties.
|
||||
/// </summary>
|
||||
public interface IBuddyMember
|
||||
public interface IBuddyMember : IEquatable<IBuddyMember>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of the buddy in memory.
|
||||
/// </summary>
|
||||
IntPtr Address { get; }
|
||||
nint Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object ID of this buddy.
|
||||
|
|
@ -67,42 +71,34 @@ public interface IBuddyMember
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class represents a buddy such as the chocobo companion, summoned pets, squadron groups and trust parties.
|
||||
/// This struct represents a buddy such as the chocobo companion, summoned pets, squadron groups and trust parties.
|
||||
/// </summary>
|
||||
internal unsafe class BuddyMember : IBuddyMember
|
||||
/// <param name="ptr">A pointer to the BuddyMember.</param>
|
||||
internal readonly unsafe struct BuddyMember(CSBuddyMember* ptr) : IBuddyMember
|
||||
{
|
||||
[ServiceManager.ServiceDependency]
|
||||
private readonly ObjectTable objectTable = Service<ObjectTable>.Get();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BuddyMember"/> class.
|
||||
/// </summary>
|
||||
/// <param name="address">Buddy address.</param>
|
||||
internal BuddyMember(IntPtr address)
|
||||
{
|
||||
this.Address = address;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public nint Address => (nint)ptr;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IntPtr Address { get; }
|
||||
public uint ObjectId => this.EntityId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public uint ObjectId => this.Struct->EntityId;
|
||||
public uint EntityId => ptr->EntityId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public uint EntityId => this.Struct->EntityId;
|
||||
public IGameObject? GameObject => this.objectTable.SearchById(this.EntityId);
|
||||
|
||||
/// <inheritdoc />
|
||||
public IGameObject? GameObject => this.objectTable.SearchById(this.ObjectId);
|
||||
public uint CurrentHP => ptr->CurrentHealth;
|
||||
|
||||
/// <inheritdoc />
|
||||
public uint CurrentHP => this.Struct->CurrentHealth;
|
||||
public uint MaxHP => ptr->MaxHealth;
|
||||
|
||||
/// <inheritdoc />
|
||||
public uint MaxHP => this.Struct->MaxHealth;
|
||||
|
||||
/// <inheritdoc />
|
||||
public uint DataID => this.Struct->DataId;
|
||||
public uint DataID => ptr->DataId;
|
||||
|
||||
/// <inheritdoc />
|
||||
public RowRef<Lumina.Excel.Sheets.Mount> MountData => LuminaUtils.CreateRef<Lumina.Excel.Sheets.Mount>(this.DataID);
|
||||
|
|
@ -113,5 +109,25 @@ internal unsafe class BuddyMember : IBuddyMember
|
|||
/// <inheritdoc />
|
||||
public RowRef<Lumina.Excel.Sheets.DawnGrowMember> TrustData => LuminaUtils.CreateRef<Lumina.Excel.Sheets.DawnGrowMember>(this.DataID);
|
||||
|
||||
private FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy.BuddyMember* Struct => (FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy.BuddyMember*)this.Address;
|
||||
public static bool operator ==(BuddyMember x, BuddyMember y) => x.Equals(y);
|
||||
|
||||
public static bool operator !=(BuddyMember x, BuddyMember y) => !(x == y);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(IBuddyMember? other)
|
||||
{
|
||||
return this.EntityId == other.EntityId;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
return obj is BuddyMember fate && this.Equals(fate);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.EntityId.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Numerics;
|
||||
|
||||
using Dalamud.Data;
|
||||
|
|
@ -6,10 +7,12 @@ using Dalamud.Memory;
|
|||
|
||||
using Lumina.Excel;
|
||||
|
||||
using CSFateContext = FFXIVClientStructs.FFXIV.Client.Game.Fate.FateContext;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Fates;
|
||||
|
||||
/// <summary>
|
||||
/// Interface representing an fate entry that can be seen in the current area.
|
||||
/// Interface representing a fate entry that can be seen in the current area.
|
||||
/// </summary>
|
||||
public interface IFate : IEquatable<IFate>
|
||||
{
|
||||
|
|
@ -111,133 +114,96 @@ public interface IFate : IEquatable<IFate>
|
|||
/// <summary>
|
||||
/// Gets the address of this Fate in memory.
|
||||
/// </summary>
|
||||
IntPtr Address { get; }
|
||||
nint Address { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class represents an FFXIV Fate.
|
||||
/// This struct represents a Fate.
|
||||
/// </summary>
|
||||
internal unsafe partial class Fate
|
||||
/// <param name="ptr">A pointer to the FateContext.</param>
|
||||
internal readonly unsafe struct Fate(CSFateContext* ptr) : IFate
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Fate"/> class.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of this fate in memory.</param>
|
||||
internal Fate(IntPtr address)
|
||||
{
|
||||
this.Address = address;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IntPtr Address { get; }
|
||||
|
||||
private FFXIVClientStructs.FFXIV.Client.Game.Fate.FateContext* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Fate.FateContext*)this.Address;
|
||||
|
||||
public static bool operator ==(Fate fate1, Fate fate2)
|
||||
{
|
||||
if (fate1 is null || fate2 is null)
|
||||
return Equals(fate1, fate2);
|
||||
|
||||
return fate1.Equals(fate2);
|
||||
}
|
||||
|
||||
public static bool operator !=(Fate fate1, Fate fate2) => !(fate1 == fate2);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this Fate is still valid in memory.
|
||||
/// </summary>
|
||||
/// <param name="fate">The fate to check.</param>
|
||||
/// <returns>True or false.</returns>
|
||||
public static bool IsValid(Fate fate)
|
||||
{
|
||||
var clientState = Service<ClientState>.GetNullable();
|
||||
|
||||
if (fate == null || clientState == null)
|
||||
return false;
|
||||
|
||||
if (clientState.LocalContentId == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this actor is still valid in memory.
|
||||
/// </summary>
|
||||
/// <returns>True or false.</returns>
|
||||
public bool IsValid() => IsValid(this);
|
||||
public nint Address => (nint)ptr;
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool IEquatable<IFate>.Equals(IFate other) => this.FateId == other?.FateId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj) => ((IEquatable<IFate>)this).Equals(obj as IFate);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode() => this.FateId.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class represents an FFXIV Fate.
|
||||
/// </summary>
|
||||
internal unsafe partial class Fate : IFate
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ushort FateId => this.Struct->FateId;
|
||||
public ushort FateId => ptr->FateId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public RowRef<Lumina.Excel.Sheets.Fate> GameData => LuminaUtils.CreateRef<Lumina.Excel.Sheets.Fate>(this.FateId);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int StartTimeEpoch => this.Struct->StartTimeEpoch;
|
||||
public int StartTimeEpoch => ptr->StartTimeEpoch;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public short Duration => this.Struct->Duration;
|
||||
public short Duration => ptr->Duration;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public long TimeRemaining => this.StartTimeEpoch + this.Duration - DateTimeOffset.Now.ToUnixTimeSeconds();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SeString Name => MemoryHelper.ReadSeString(&this.Struct->Name);
|
||||
public SeString Name => MemoryHelper.ReadSeString(&ptr->Name);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SeString Description => MemoryHelper.ReadSeString(&this.Struct->Description);
|
||||
public SeString Description => MemoryHelper.ReadSeString(&ptr->Description);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SeString Objective => MemoryHelper.ReadSeString(&this.Struct->Objective);
|
||||
public SeString Objective => MemoryHelper.ReadSeString(&ptr->Objective);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public FateState State => (FateState)this.Struct->State;
|
||||
public FateState State => (FateState)ptr->State;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte HandInCount => this.Struct->HandInCount;
|
||||
public byte HandInCount => ptr->HandInCount;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte Progress => this.Struct->Progress;
|
||||
public byte Progress => ptr->Progress;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool HasBonus => this.Struct->IsBonus;
|
||||
public bool HasBonus => ptr->IsBonus;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint IconId => this.Struct->IconId;
|
||||
public uint IconId => ptr->IconId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte Level => this.Struct->Level;
|
||||
public byte Level => ptr->Level;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte MaxLevel => this.Struct->MaxLevel;
|
||||
public byte MaxLevel => ptr->MaxLevel;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Vector3 Position => this.Struct->Location;
|
||||
public Vector3 Position => ptr->Location;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float Radius => this.Struct->Radius;
|
||||
public float Radius => ptr->Radius;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint MapIconId => this.Struct->MapIconId;
|
||||
public uint MapIconId => ptr->MapIconId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the territory this <see cref="Fate"/> is located in.
|
||||
/// </summary>
|
||||
public RowRef<Lumina.Excel.Sheets.TerritoryType> TerritoryType => LuminaUtils.CreateRef<Lumina.Excel.Sheets.TerritoryType>(this.Struct->MapMarkers[0].MapMarkerData.TerritoryTypeId);
|
||||
public RowRef<Lumina.Excel.Sheets.TerritoryType> TerritoryType => LuminaUtils.CreateRef<Lumina.Excel.Sheets.TerritoryType>(ptr->MapMarkers[0].MapMarkerData.TerritoryTypeId);
|
||||
|
||||
public static bool operator ==(Fate x, Fate y) => x.Equals(y);
|
||||
|
||||
public static bool operator !=(Fate x, Fate y) => !(x == y);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(IFate? other)
|
||||
{
|
||||
return this.FateId == other.FateId;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
return obj is Fate fate && this.Equals(fate);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.FateId.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Dalamud.IoC;
|
|||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
|
||||
using CSFateContext = FFXIVClientStructs.FFXIV.Client.Game.Fate.FateContext;
|
||||
using CSFateManager = FFXIVClientStructs.FFXIV.Client.Game.Fate.FateManager;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Fates;
|
||||
|
|
@ -25,7 +26,7 @@ internal sealed partial class FateTable : IServiceType, IFateTable
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe IntPtr Address => (nint)CSFateManager.Instance();
|
||||
public unsafe nint Address => (nint)CSFateManager.Instance();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe int Length
|
||||
|
|
@ -72,30 +73,29 @@ internal sealed partial class FateTable : IServiceType, IFateTable
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe IntPtr GetFateAddress(int index)
|
||||
public unsafe nint GetFateAddress(int index)
|
||||
{
|
||||
if (index >= this.Length)
|
||||
return IntPtr.Zero;
|
||||
return 0;
|
||||
|
||||
var fateManager = CSFateManager.Instance();
|
||||
if (fateManager == null)
|
||||
return IntPtr.Zero;
|
||||
return 0;
|
||||
|
||||
return (IntPtr)fateManager->Fates[index].Value;
|
||||
return (nint)fateManager->Fates[index].Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IFate? CreateFateReference(IntPtr offset)
|
||||
public unsafe IFate? CreateFateReference(IntPtr address)
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
if (address == 0)
|
||||
return null;
|
||||
|
||||
var clientState = Service<ClientState>.Get();
|
||||
if (clientState.LocalContentId == 0)
|
||||
return null;
|
||||
|
||||
if (offset == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
return new Fate(offset);
|
||||
return new Fate((CSFateContext*)address);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,12 +110,35 @@ internal sealed partial class FateTable
|
|||
/// <inheritdoc/>
|
||||
public IEnumerator<IFate> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
yield return this[i];
|
||||
}
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
||||
|
||||
private struct Enumerator(FateTable fateTable) : IEnumerator<IFate>
|
||||
{
|
||||
private int index = 0;
|
||||
|
||||
public IFate Current { get; private set; }
|
||||
|
||||
object IEnumerator.Current => this.Current;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (this.index == fateTable.Length) return false;
|
||||
this.Current = fateTable[this.index];
|
||||
this.index++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ using Dalamud.Utility;
|
|||
|
||||
using FFXIVClientStructs.Interop;
|
||||
|
||||
using Microsoft.Extensions.ObjectPool;
|
||||
|
||||
using CSGameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
||||
using CSGameObjectManager = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObjectManager;
|
||||
|
||||
|
|
@ -34,8 +32,6 @@ internal sealed partial class ObjectTable : IServiceType, IObjectTable
|
|||
private readonly ClientState clientState;
|
||||
private readonly CachedEntry[] cachedObjectTable;
|
||||
|
||||
private readonly Enumerator?[] frameworkThreadEnumerators = new Enumerator?[4];
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private unsafe ObjectTable(ClientState clientState)
|
||||
{
|
||||
|
|
@ -47,9 +43,6 @@ internal sealed partial class ObjectTable : IServiceType, IObjectTable
|
|||
this.cachedObjectTable = new CachedEntry[objectTableLength];
|
||||
for (var i = 0; i < this.cachedObjectTable.Length; i++)
|
||||
this.cachedObjectTable[i] = new(nativeObjectTable.GetPointer(i));
|
||||
|
||||
for (var i = 0; i < this.frameworkThreadEnumerators.Length; i++)
|
||||
this.frameworkThreadEnumerators[i] = new(this, i);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -239,30 +232,14 @@ internal sealed partial class ObjectTable
|
|||
public IEnumerator<IGameObject> GetEnumerator()
|
||||
{
|
||||
ThreadSafety.AssertMainThread();
|
||||
|
||||
// If we're on the framework thread, see if there's an already allocated enumerator available for use.
|
||||
foreach (ref var x in this.frameworkThreadEnumerators.AsSpan())
|
||||
{
|
||||
if (x is not null)
|
||||
{
|
||||
var t = x;
|
||||
x = null;
|
||||
t.Reset();
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
// No reusable enumerator is available; allocate a new temporary one.
|
||||
return new Enumerator(this, -1);
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
||||
|
||||
private sealed class Enumerator(ObjectTable owner, int slotId) : IEnumerator<IGameObject>, IResettable
|
||||
private struct Enumerator(ObjectTable owner) : IEnumerator<IGameObject>
|
||||
{
|
||||
private ObjectTable? owner = owner;
|
||||
|
||||
private int index = -1;
|
||||
|
||||
public IGameObject Current { get; private set; } = null!;
|
||||
|
|
@ -274,7 +251,7 @@ internal sealed partial class ObjectTable
|
|||
if (this.index == objectTableLength)
|
||||
return false;
|
||||
|
||||
var cache = this.owner!.cachedObjectTable.AsSpan();
|
||||
var cache = owner.cachedObjectTable.AsSpan();
|
||||
for (this.index++; this.index < objectTableLength; this.index++)
|
||||
{
|
||||
if (cache[this.index].Update() is { } ao)
|
||||
|
|
@ -291,17 +268,6 @@ internal sealed partial class ObjectTable
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.owner is not { } o)
|
||||
return;
|
||||
|
||||
if (slotId != -1)
|
||||
o.frameworkThreadEnumerators[slotId] = this;
|
||||
}
|
||||
|
||||
public bool TryReset()
|
||||
{
|
||||
this.Reset();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using Dalamud.IoC.Internal;
|
|||
using Dalamud.Plugin.Services;
|
||||
|
||||
using CSGroupManager = FFXIVClientStructs.FFXIV.Client.Game.Group.GroupManager;
|
||||
using CSPartyMember = FFXIVClientStructs.FFXIV.Client.Game.Group.PartyMember;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Party;
|
||||
|
||||
|
|
@ -42,20 +43,20 @@ internal sealed unsafe partial class PartyList : IServiceType, IPartyList
|
|||
public bool IsAlliance => this.GroupManagerStruct->MainGroup.AllianceFlags > 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public unsafe IntPtr GroupManagerAddress => (nint)CSGroupManager.Instance();
|
||||
public unsafe nint GroupManagerAddress => (nint)CSGroupManager.Instance();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IntPtr GroupListAddress => (IntPtr)Unsafe.AsPointer(ref GroupManagerStruct->MainGroup.PartyMembers[0]);
|
||||
public nint GroupListAddress => (nint)Unsafe.AsPointer(ref GroupManagerStruct->MainGroup.PartyMembers[0]);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IntPtr AllianceListAddress => (IntPtr)Unsafe.AsPointer(ref this.GroupManagerStruct->MainGroup.AllianceMembers[0]);
|
||||
public nint AllianceListAddress => (nint)Unsafe.AsPointer(ref this.GroupManagerStruct->MainGroup.AllianceMembers[0]);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public long PartyId => this.GroupManagerStruct->MainGroup.PartyId;
|
||||
|
||||
private static int PartyMemberSize { get; } = Marshal.SizeOf<FFXIVClientStructs.FFXIV.Client.Game.Group.PartyMember>();
|
||||
private static int PartyMemberSize { get; } = Marshal.SizeOf<CSPartyMember>();
|
||||
|
||||
private FFXIVClientStructs.FFXIV.Client.Game.Group.GroupManager* GroupManagerStruct => (FFXIVClientStructs.FFXIV.Client.Game.Group.GroupManager*)this.GroupManagerAddress;
|
||||
private CSGroupManager* GroupManagerStruct => (CSGroupManager*)this.GroupManagerAddress;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPartyMember? this[int index]
|
||||
|
|
@ -80,45 +81,45 @@ internal sealed unsafe partial class PartyList : IServiceType, IPartyList
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IntPtr GetPartyMemberAddress(int index)
|
||||
public nint GetPartyMemberAddress(int index)
|
||||
{
|
||||
if (index < 0 || index >= GroupLength)
|
||||
return IntPtr.Zero;
|
||||
return 0;
|
||||
|
||||
return this.GroupListAddress + (index * PartyMemberSize);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPartyMember? CreatePartyMemberReference(IntPtr address)
|
||||
public IPartyMember? CreatePartyMemberReference(nint address)
|
||||
{
|
||||
if (this.clientState.LocalContentId == 0)
|
||||
return null;
|
||||
|
||||
if (address == IntPtr.Zero)
|
||||
if (address == 0)
|
||||
return null;
|
||||
|
||||
return new PartyMember(address);
|
||||
return new PartyMember((CSPartyMember*)address);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IntPtr GetAllianceMemberAddress(int index)
|
||||
public nint GetAllianceMemberAddress(int index)
|
||||
{
|
||||
if (index < 0 || index >= AllianceLength)
|
||||
return IntPtr.Zero;
|
||||
return 0;
|
||||
|
||||
return this.AllianceListAddress + (index * PartyMemberSize);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IPartyMember? CreateAllianceMemberReference(IntPtr address)
|
||||
public IPartyMember? CreateAllianceMemberReference(nint address)
|
||||
{
|
||||
if (this.clientState.LocalContentId == 0)
|
||||
return null;
|
||||
|
||||
if (address == IntPtr.Zero)
|
||||
if (address == 0)
|
||||
return null;
|
||||
|
||||
return new PartyMember(address);
|
||||
return new PartyMember((CSPartyMember*)address);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -133,18 +134,44 @@ internal sealed partial class PartyList
|
|||
/// <inheritdoc/>
|
||||
public IEnumerator<IPartyMember> GetEnumerator()
|
||||
{
|
||||
// Normally using Length results in a recursion crash, however we know the party size via ptr.
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
var member = this[i];
|
||||
|
||||
if (member == null)
|
||||
break;
|
||||
|
||||
yield return member;
|
||||
}
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
||||
|
||||
private struct Enumerator(PartyList partyList) : IEnumerator<IPartyMember>
|
||||
{
|
||||
private int index = 0;
|
||||
|
||||
public IPartyMember Current { get; private set; }
|
||||
|
||||
object IEnumerator.Current => this.Current;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (this.index == partyList.Length) return false;
|
||||
|
||||
for (; this.index < partyList.Length; this.index++)
|
||||
{
|
||||
var partyMember = partyList[this.index];
|
||||
if (partyMember != null)
|
||||
{
|
||||
this.Current = partyMember;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,27 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.ClientState.Statuses;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Memory;
|
||||
|
||||
using Lumina.Excel;
|
||||
|
||||
using CSPartyMember = FFXIVClientStructs.FFXIV.Client.Game.Group.PartyMember;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Party;
|
||||
|
||||
/// <summary>
|
||||
/// Interface representing a party member.
|
||||
/// </summary>
|
||||
public interface IPartyMember
|
||||
public interface IPartyMember : IEquatable<IPartyMember>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of this party member in memory.
|
||||
/// </summary>
|
||||
IntPtr Address { get; }
|
||||
nint Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of buffs or debuffs applied to this party member.
|
||||
|
|
@ -108,69 +109,81 @@ public interface IPartyMember
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class represents a party member in the group manager.
|
||||
/// This struct represents a party member in the group manager.
|
||||
/// </summary>
|
||||
internal unsafe class PartyMember : IPartyMember
|
||||
/// <param name="ptr">A pointer to the PartyMember.</param>
|
||||
internal unsafe readonly struct PartyMember(CSPartyMember* ptr) : IPartyMember
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PartyMember"/> class.
|
||||
/// </summary>
|
||||
/// <param name="address">Address of the party member.</param>
|
||||
internal PartyMember(IntPtr address)
|
||||
{
|
||||
this.Address = address;
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
public nint Address => (nint)ptr;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IntPtr Address { get; }
|
||||
public StatusList Statuses => new(&ptr->StatusManager);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public StatusList Statuses => new(&this.Struct->StatusManager);
|
||||
public Vector3 Position => ptr->Position;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Vector3 Position => this.Struct->Position;
|
||||
public long ContentId => (long)ptr->ContentId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public long ContentId => (long)this.Struct->ContentId;
|
||||
public uint ObjectId => ptr->EntityId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint ObjectId => this.Struct->EntityId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint EntityId => this.Struct->EntityId;
|
||||
public uint EntityId => ptr->EntityId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IGameObject? GameObject => Service<ObjectTable>.Get().SearchById(this.EntityId);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint CurrentHP => this.Struct->CurrentHP;
|
||||
public uint CurrentHP => ptr->CurrentHP;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint MaxHP => this.Struct->MaxHP;
|
||||
public uint MaxHP => ptr->MaxHP;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ushort CurrentMP => this.Struct->CurrentMP;
|
||||
public ushort CurrentMP => ptr->CurrentMP;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ushort MaxMP => this.Struct->MaxMP;
|
||||
public ushort MaxMP => ptr->MaxMP;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public RowRef<Lumina.Excel.Sheets.TerritoryType> Territory => LuminaUtils.CreateRef<Lumina.Excel.Sheets.TerritoryType>(this.Struct->TerritoryType);
|
||||
public RowRef<Lumina.Excel.Sheets.TerritoryType> Territory => LuminaUtils.CreateRef<Lumina.Excel.Sheets.TerritoryType>(ptr->TerritoryType);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public RowRef<Lumina.Excel.Sheets.World> World => LuminaUtils.CreateRef<Lumina.Excel.Sheets.World>(this.Struct->HomeWorld);
|
||||
public RowRef<Lumina.Excel.Sheets.World> World => LuminaUtils.CreateRef<Lumina.Excel.Sheets.World>(ptr->HomeWorld);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public SeString Name => SeString.Parse(this.Struct->Name);
|
||||
public SeString Name => SeString.Parse(ptr->Name);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte Sex => this.Struct->Sex;
|
||||
public byte Sex => ptr->Sex;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public RowRef<Lumina.Excel.Sheets.ClassJob> ClassJob => LuminaUtils.CreateRef<Lumina.Excel.Sheets.ClassJob>(this.Struct->ClassJob);
|
||||
public RowRef<Lumina.Excel.Sheets.ClassJob> ClassJob => LuminaUtils.CreateRef<Lumina.Excel.Sheets.ClassJob>(ptr->ClassJob);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte Level => this.Struct->Level;
|
||||
public byte Level => ptr->Level;
|
||||
|
||||
private FFXIVClientStructs.FFXIV.Client.Game.Group.PartyMember* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Group.PartyMember*)this.Address;
|
||||
public static bool operator ==(PartyMember x, PartyMember y) => x.Equals(y);
|
||||
|
||||
public static bool operator !=(PartyMember x, PartyMember y) => !(x == y);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(IPartyMember? other)
|
||||
{
|
||||
return this.EntityId == other.EntityId;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
return obj is PartyMember fate && this.Equals(fate);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.EntityId.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,61 +1,49 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using Dalamud.Data;
|
||||
using Dalamud.Game.ClientState.Objects;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
|
||||
using Lumina.Excel;
|
||||
|
||||
using CSStatus = FFXIVClientStructs.FFXIV.Client.Game.Status;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Statuses;
|
||||
|
||||
/// <summary>
|
||||
/// This class represents a status effect an actor is afflicted by.
|
||||
/// Interface representing a status.
|
||||
/// </summary>
|
||||
public unsafe class Status
|
||||
public interface IStatus : IEquatable<IStatus>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Status"/> class.
|
||||
/// </summary>
|
||||
/// <param name="address">Status address.</param>
|
||||
internal Status(IntPtr address)
|
||||
{
|
||||
this.Address = address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the status in memory.
|
||||
/// </summary>
|
||||
public IntPtr Address { get; }
|
||||
nint Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the status ID of this status.
|
||||
/// </summary>
|
||||
public uint StatusId => this.Struct->StatusId;
|
||||
uint StatusId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the GameData associated with this status.
|
||||
/// </summary>
|
||||
public RowRef<Lumina.Excel.Sheets.Status> GameData => LuminaUtils.CreateRef<Lumina.Excel.Sheets.Status>(this.Struct->StatusId);
|
||||
RowRef<Lumina.Excel.Sheets.Status> GameData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameter value of the status.
|
||||
/// </summary>
|
||||
public ushort Param => this.Struct->Param;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stack count of this status.
|
||||
/// Only valid if this is a non-food status.
|
||||
/// </summary>
|
||||
[Obsolete($"Replaced with {nameof(Param)}", true)]
|
||||
public byte StackCount => (byte)this.Struct->Param;
|
||||
ushort Param { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time remaining of this status.
|
||||
/// </summary>
|
||||
public float RemainingTime => this.Struct->RemainingTime;
|
||||
float RemainingTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the source ID of this status.
|
||||
/// </summary>
|
||||
public uint SourceId => this.Struct->SourceObject.ObjectId;
|
||||
uint SourceId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the source actor associated with this status.
|
||||
|
|
@ -63,7 +51,55 @@ public unsafe class Status
|
|||
/// <remarks>
|
||||
/// This iterates the actor table, it should be used with care.
|
||||
/// </remarks>
|
||||
IGameObject? SourceObject { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This struct represents a status effect an actor is afflicted by.
|
||||
/// </summary>
|
||||
/// <param name="ptr">A pointer to the Status.</param>
|
||||
internal unsafe readonly struct Status(CSStatus* ptr) : IStatus
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public nint Address => (nint)ptr;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint StatusId => ptr->StatusId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public RowRef<Lumina.Excel.Sheets.Status> GameData => LuminaUtils.CreateRef<Lumina.Excel.Sheets.Status>(ptr->StatusId);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ushort Param => ptr->Param;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public float RemainingTime => ptr->RemainingTime;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint SourceId => ptr->SourceObject.ObjectId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IGameObject? SourceObject => Service<ObjectTable>.Get().SearchById(this.SourceId);
|
||||
|
||||
private FFXIVClientStructs.FFXIV.Client.Game.Status* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Status*)this.Address;
|
||||
public static bool operator ==(Status x, Status y) => x.Equals(y);
|
||||
|
||||
public static bool operator !=(Status x, Status y) => !(x == y);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(IStatus? other)
|
||||
{
|
||||
return this.StatusId == other.StatusId && this.SourceId == other.SourceId && this.Param == other.Param && this.RemainingTime == other.RemainingTime;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
return obj is Status fate && this.Equals(fate);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(this.StatusId, this.SourceId, this.Param, this.RemainingTime);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
|||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using CSStatus = FFXIVClientStructs.FFXIV.Client.Game.Status;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Statuses;
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -14,7 +16,7 @@ public sealed unsafe partial class StatusList
|
|||
/// Initializes a new instance of the <see cref="StatusList"/> class.
|
||||
/// </summary>
|
||||
/// <param name="address">Address of the status list.</param>
|
||||
internal StatusList(IntPtr address)
|
||||
internal StatusList(nint address)
|
||||
{
|
||||
this.Address = address;
|
||||
}
|
||||
|
|
@ -24,14 +26,14 @@ public sealed unsafe partial class StatusList
|
|||
/// </summary>
|
||||
/// <param name="pointer">Pointer to the status list.</param>
|
||||
internal unsafe StatusList(void* pointer)
|
||||
: this((IntPtr)pointer)
|
||||
: this((nint)pointer)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the status list in memory.
|
||||
/// </summary>
|
||||
public IntPtr Address { get; }
|
||||
public nint Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of status effect slots the actor has.
|
||||
|
|
@ -47,7 +49,7 @@ public sealed unsafe partial class StatusList
|
|||
/// </summary>
|
||||
/// <param name="index">Status Index.</param>
|
||||
/// <returns>The status at the specified index.</returns>
|
||||
public Status? this[int index]
|
||||
public IStatus? this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
@ -64,7 +66,7 @@ public sealed unsafe partial class StatusList
|
|||
/// </summary>
|
||||
/// <param name="address">The address of the status list in memory.</param>
|
||||
/// <returns>The status object containing the requested data.</returns>
|
||||
public static StatusList? CreateStatusListReference(IntPtr address)
|
||||
public static StatusList? CreateStatusListReference(nint address)
|
||||
{
|
||||
// The use case for CreateStatusListReference and CreateStatusReference to be static is so
|
||||
// fake status lists can be generated. Since they aren't exposed as services, it's either
|
||||
|
|
@ -74,7 +76,7 @@ public sealed unsafe partial class StatusList
|
|||
if (clientState.LocalContentId == 0)
|
||||
return null;
|
||||
|
||||
if (address == IntPtr.Zero)
|
||||
if (address == 0)
|
||||
return null;
|
||||
|
||||
return new StatusList(address);
|
||||
|
|
@ -85,17 +87,17 @@ public sealed unsafe partial class StatusList
|
|||
/// </summary>
|
||||
/// <param name="address">The address of the status effect in memory.</param>
|
||||
/// <returns>The status object containing the requested data.</returns>
|
||||
public static Status? CreateStatusReference(IntPtr address)
|
||||
public static IStatus? CreateStatusReference(nint address)
|
||||
{
|
||||
var clientState = Service<ClientState>.Get();
|
||||
|
||||
if (clientState.LocalContentId == 0)
|
||||
return null;
|
||||
|
||||
if (address == IntPtr.Zero)
|
||||
if (address == 0)
|
||||
return null;
|
||||
|
||||
return new Status(address);
|
||||
return new Status((CSStatus*)address);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -103,22 +105,22 @@ public sealed unsafe partial class StatusList
|
|||
/// </summary>
|
||||
/// <param name="index">The index of the status.</param>
|
||||
/// <returns>The memory address of the status.</returns>
|
||||
public IntPtr GetStatusAddress(int index)
|
||||
public nint GetStatusAddress(int index)
|
||||
{
|
||||
if (index < 0 || index >= this.Length)
|
||||
return IntPtr.Zero;
|
||||
return 0;
|
||||
|
||||
return (IntPtr)Unsafe.AsPointer(ref this.Struct->Status[index]);
|
||||
return (nint)Unsafe.AsPointer(ref this.Struct->Status[index]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This collection represents the status effects an actor is afflicted by.
|
||||
/// </summary>
|
||||
public sealed partial class StatusList : IReadOnlyCollection<Status>, ICollection
|
||||
public sealed partial class StatusList : IReadOnlyCollection<IStatus>, ICollection
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
int IReadOnlyCollection<Status>.Count => this.Length;
|
||||
int IReadOnlyCollection<IStatus>.Count => this.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
int ICollection.Count => this.Length;
|
||||
|
|
@ -130,17 +132,9 @@ public sealed partial class StatusList : IReadOnlyCollection<Status>, ICollectio
|
|||
object ICollection.SyncRoot => this;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<Status> GetEnumerator()
|
||||
public IEnumerator<IStatus> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
var status = this[i];
|
||||
|
||||
if (status == null || status.StatusId == 0)
|
||||
continue;
|
||||
|
||||
yield return status;
|
||||
}
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -155,4 +149,39 @@ public sealed partial class StatusList : IReadOnlyCollection<Status>, ICollectio
|
|||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
private struct Enumerator(StatusList statusList) : IEnumerator<IStatus>
|
||||
{
|
||||
private int index = 0;
|
||||
|
||||
public IStatus Current { get; private set; }
|
||||
|
||||
object IEnumerator.Current => this.Current;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (this.index == statusList.Length) return false;
|
||||
|
||||
for (; this.index < statusList.Length; this.index++)
|
||||
{
|
||||
var status = statusList[this.index];
|
||||
if (status != null && status.StatusId != 0)
|
||||
{
|
||||
this.Current = status;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Structs;
|
||||
|
||||
/// <summary>
|
||||
/// Native memory representation of a FFXIV status effect.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct StatusEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The effect ID.
|
||||
/// </summary>
|
||||
public short EffectId;
|
||||
|
||||
/// <summary>
|
||||
/// How many stacks are present.
|
||||
/// </summary>
|
||||
public byte StackCount;
|
||||
|
||||
/// <summary>
|
||||
/// Additional parameters.
|
||||
/// </summary>
|
||||
public byte Param;
|
||||
|
||||
/// <summary>
|
||||
/// The duration remaining.
|
||||
/// </summary>
|
||||
public float Duration;
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the actor that caused this effect.
|
||||
/// </summary>
|
||||
public int OwnerId;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue