diff --git a/Dalamud/Game/ClientState/Actors/ActorTable.cs b/Dalamud/Game/ClientState/Actors/ActorTable.cs
deleted file mode 100644
index a139f8b48..000000000
--- a/Dalamud/Game/ClientState/Actors/ActorTable.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-
-using Dalamud.Game.ClientState.Actors.Types;
-using Dalamud.Game.ClientState.Actors.Types.NonPlayer;
-using JetBrains.Annotations;
-using Serilog;
-
-namespace Dalamud.Game.ClientState.Actors
-{
- ///
- /// This collection represents the currently spawned FFXIV actors.
- ///
- public sealed partial class ActorTable
- {
- private const int ActorTableLength = 424;
-
- private readonly Dalamud dalamud;
- private readonly ClientStateAddressResolver address;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The instance.
- /// Client state address resolver.
- internal ActorTable(Dalamud dalamud, ClientStateAddressResolver addressResolver)
- {
- this.dalamud = dalamud;
- this.address = addressResolver;
-
- Log.Verbose($"Actor table address 0x{this.address.ActorTable.ToInt64():X}");
- }
-
- ///
- /// Gets the amount of currently spawned actors.
- ///
- public int Length
- {
- get
- {
- var count = 0;
- for (var i = 0; i < ActorTableLength; i++)
- {
- var ptr = this.GetActorAddress(i);
- if (ptr != IntPtr.Zero)
- {
- count++;
- }
- }
-
- return count;
- }
- }
-
- ///
- /// Get an actor at the specified spawn index.
- ///
- /// Spawn index.
- /// An at the specified spawn index.
- [CanBeNull]
- public Actor this[int index]
- {
- get
- {
- var address = this.GetActorAddress(index);
- return this.CreateActorReference(address);
- }
- }
-
- ///
- /// Gets the address of the actor at the specified index of the actor table.
- ///
- /// The index of the actor.
- /// The memory address of the actor.
- public unsafe IntPtr GetActorAddress(int index)
- {
- if (index >= ActorTableLength)
- return IntPtr.Zero;
-
- return *(IntPtr*)(this.address.ActorTable + (8 * index));
- }
-
- ///
- /// Create a reference to a FFXIV actor.
- ///
- /// The address of the actor in memory.
- /// object or inheritor containing requested data.
- [CanBeNull]
- public unsafe Actor CreateActorReference(IntPtr address)
- {
- if (this.dalamud.ClientState.LocalContentId == 0)
- return null;
-
- if (address == IntPtr.Zero)
- return null;
-
- var objKind = *(ObjectKind*)(address + ActorOffsets.ObjectKind);
- return objKind switch
- {
- ObjectKind.Player => new PlayerCharacter(address, this.dalamud),
- ObjectKind.BattleNpc => new BattleNpc(address, this.dalamud),
- ObjectKind.EventObj => new EventObj(address, this.dalamud),
- ObjectKind.Companion => new Npc(address, this.dalamud),
- _ => new Actor(address, this.dalamud),
- };
- }
- }
-
- ///
- /// This collection represents the currently spawned FFXIV actors.
- ///
- public sealed partial class ActorTable : IReadOnlyCollection, ICollection
- {
- ///
- int IReadOnlyCollection.Count => this.Length;
-
- ///
- int ICollection.Count => this.Length;
-
- ///
- bool ICollection.IsSynchronized => false;
-
- ///
- object ICollection.SyncRoot => this;
-
- ///
- public IEnumerator GetEnumerator()
- {
- for (var i = 0; i < ActorTableLength; i++)
- {
- yield return this[i];
- }
- }
-
- ///
- IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
-
- ///
- void ICollection.CopyTo(Array array, int index)
- {
- for (var i = 0; i < this.Length; i++)
- {
- array.SetValue(this[i], index);
- index++;
- }
- }
- }
-}
diff --git a/Dalamud/Game/ClientState/Actors/Targets.cs b/Dalamud/Game/ClientState/Actors/Targets.cs
deleted file mode 100644
index 154aa446d..000000000
--- a/Dalamud/Game/ClientState/Actors/Targets.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-using Dalamud.Game.ClientState.Actors.Types;
-using JetBrains.Annotations;
-
-namespace Dalamud.Game.ClientState.Actors
-{
- ///
- /// Get and set various kinds of targets for the player.
- ///
- public sealed class Targets
- {
- private readonly Dalamud dalamud;
- private readonly ClientStateAddressResolver address;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The Dalamud instance.
- /// The ClientStateAddressResolver instance.
- internal Targets(Dalamud dalamud, ClientStateAddressResolver addressResolver)
- {
- this.dalamud = dalamud;
- this.address = addressResolver;
- }
-
- ///
- /// Gets the current target.
- ///
- [CanBeNull]
- public Actor CurrentTarget => this.GetActorByOffset(TargetOffsets.CurrentTarget);
-
- ///
- /// Gets the mouseover target.
- ///
- [CanBeNull]
- public Actor MouseOverTarget => this.GetActorByOffset(TargetOffsets.MouseOverTarget);
-
- ///
- /// Gets the focus target.
- ///
- [CanBeNull]
- public Actor FocusTarget => this.GetActorByOffset(TargetOffsets.FocusTarget);
-
- ///
- /// Gets the previous target.
- ///
- [CanBeNull]
- public Actor PreviousTarget => this.GetActorByOffset(TargetOffsets.PreviousTarget);
-
- ///
- /// Gets the soft target.
- ///
- [CanBeNull]
- public Actor SoftTarget => this.GetActorByOffset(TargetOffsets.SoftTarget);
-
- ///
- /// Sets the current target.
- ///
- /// Actor to target.
- public void SetCurrentTarget(Actor actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero, TargetOffsets.CurrentTarget);
-
- ///
- /// Sets the current target.
- ///
- /// Actor (address) to target.
- public void SetCurrentTarget(IntPtr actorAddress) => this.SetTarget(actorAddress, TargetOffsets.CurrentTarget);
-
- ///
- /// Sets the focus target.
- ///
- /// Actor to focus.
- public void SetFocusTarget(Actor actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero, TargetOffsets.FocusTarget);
-
- ///
- /// Sets the focus target.
- ///
- /// Actor (address) to focus.
- public void SetFocusTarget(IntPtr actorAddress) => this.SetTarget(actorAddress, TargetOffsets.FocusTarget);
-
- ///
- /// Clears the current target.
- ///
- public void ClearCurrentTarget() => this.SetCurrentTarget(IntPtr.Zero);
-
- ///
- /// Clears the focus target.
- ///
- public void ClearFocusTarget() => this.SetFocusTarget(IntPtr.Zero);
-
- private void SetTarget(IntPtr actorAddress, int offset)
- {
- if (this.address.TargetManager == IntPtr.Zero)
- return;
-
- Marshal.WriteIntPtr(this.address.TargetManager, offset, actorAddress);
- }
-
- [CanBeNull]
- private Actor GetActorByOffset(int offset)
- {
- if (this.address.TargetManager == IntPtr.Zero)
- return null;
-
- var actorAddress = Marshal.ReadIntPtr(this.address.TargetManager + offset);
- if (actorAddress == IntPtr.Zero)
- return null;
-
- return this.dalamud.ClientState.Actors.CreateActorReference(actorAddress);
- }
- }
-
- ///
- /// Memory offsets for the type.
- ///
- public static class TargetOffsets
- {
- public const int CurrentTarget = 0x80;
- public const int SoftTarget = 0x88;
- public const int MouseOverTarget = 0xD0;
- public const int FocusTarget = 0xF8;
- public const int PreviousTarget = 0x110;
- }
-}
diff --git a/Dalamud/Game/ClientState/Actors/Types/Actor.cs b/Dalamud/Game/ClientState/Actors/Types/Actor.cs
deleted file mode 100644
index f98d8932e..000000000
--- a/Dalamud/Game/ClientState/Actors/Types/Actor.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-using Dalamud.Game.ClientState.Structs;
-using Dalamud.Game.Text.SeStringHandling;
-using Dalamud.Memory;
-
-namespace Dalamud.Game.ClientState.Actors.Types
-{
- ///
- /// This class represents a basic actor (GameObject) in FFXIV.
- ///
- public unsafe partial class Actor : IEquatable
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The address of this actor in memory.
- /// A dalamud reference needed to access game data in Resolvers.
- internal Actor(IntPtr address, Dalamud dalamud)
- {
- this.Dalamud = dalamud;
- this.Address = address;
- }
-
- ///
- /// Gets the address of the actor in memory.
- ///
- public IntPtr Address { get; }
-
- ///
- /// Gets Dalamud itself.
- ///
- private protected Dalamud Dalamud { get; }
-
- ///
- /// This allows you to if (actor) {...} to check for validity.
- ///
- /// The actor to check.
- /// True or false.
- public static implicit operator bool(Actor actor) => IsValid(actor);
-
- public static bool operator ==(Actor actor1, Actor actor2)
- {
- if (actor1 is null || actor2 is null)
- return Equals(actor1, actor2);
-
- return actor1.Equals(actor2);
- }
-
- public static bool operator !=(Actor actor1, Actor actor2) => !(actor1 == actor2);
-
- ///
- /// Gets a value indicating whether this actor is still valid in memory.
- ///
- /// The actor to check.
- /// True or false.
- public static bool IsValid(Actor actor)
- {
- if (actor == null)
- return false;
-
- if (actor.Dalamud.ClientState.LocalContentId == 0)
- return false;
-
- return true;
- }
-
- ///
- /// Gets a value indicating whether this actor is still valid in memory.
- ///
- /// True or false.
- public bool IsValid() => IsValid(this);
-
- ///
- bool IEquatable.Equals(Actor other) => this.ActorId == other?.ActorId;
-
- ///
- public override bool Equals(object obj) => ((IEquatable)this).Equals(obj as Actor);
-
- ///
- public override int GetHashCode() => this.ActorId.GetHashCode();
- }
-
- ///
- /// This class represents a basic actor (GameObject) in FFXIV.
- ///
- public unsafe partial class Actor
- {
- ///
- /// Gets the displayname of this .
- ///
- public SeString Name => MemoryHelper.ReadSeString(this.Address + ActorOffsets.Name, 32);
-
- ///
- /// Gets the actor ID of this .
- ///
- public uint ActorId => *(uint*)(this.Address + ActorOffsets.ActorId);
-
- ///
- /// Gets the data ID for linking to other respective game data.
- ///
- public uint DataId => *(uint*)(this.Address + ActorOffsets.DataId);
-
- ///
- /// Gets the ID of this GameObject's owner.
- ///
- public uint OwnerId => *(uint*)(this.Address + ActorOffsets.OwnerId);
-
- ///
- /// Gets the entity kind of this .
- /// See the ObjectKind enum for possible values.
- ///
- public ObjectKind ObjectKind => *(ObjectKind*)(this.Address + ActorOffsets.ObjectKind);
-
- ///
- /// Gets the sub kind of this Actor.
- ///
- public byte SubKind => *(byte*)(this.Address + ActorOffsets.SubKind);
-
- ///
- /// Gets a value indicating whether the actor is friendly.
- ///
- public bool IsFriendly => *(int*)(this.Address + ActorOffsets.IsFriendly) > 0;
-
- ///
- /// Gets the X distance from the local player in yalms.
- ///
- public byte YalmDistanceX => *(byte*)(this.Address + ActorOffsets.YalmDistanceFromObjectX);
-
- ///
- /// Gets the target status.
- ///
- ///
- /// This is some kind of enum. It may be .
- ///
- public byte TargetStatus => *(byte*)(this.Address + ActorOffsets.TargetStatus);
-
- ///
- /// Gets the Y distance from the local player in yalms.
- ///
- public byte YalmDistanceY => *(byte*)(this.Address + ActorOffsets.YalmDistanceFromObjectY);
-
- ///
- /// Gets the position of this .
- ///
- public Position3 Position => *(Position3*)(this.Address + ActorOffsets.Position);
-
- ///
- /// Gets the rotation of this .
- /// This ranges from -pi to pi radians.
- ///
- public float Rotation => *(float*)(this.Address + ActorOffsets.Rotation);
-
- ///
- /// Gets the hitbox radius of this .
- ///
- public float HitboxRadius => *(float*)(this.Address + ActorOffsets.HitboxRadius);
-
- ///
- /// Gets the current target of the Actor.
- ///
- public virtual uint TargetActorID => 0;
- }
-}
diff --git a/Dalamud/Game/ClientState/Actors/Types/ActorOffsets.cs b/Dalamud/Game/ClientState/Actors/Types/ActorOffsets.cs
deleted file mode 100644
index e3ef26a5c..000000000
--- a/Dalamud/Game/ClientState/Actors/Types/ActorOffsets.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-
-namespace Dalamud.Game.ClientState.Actors.Types
-{
- ///
- /// Memory offsets for the type and all that inherit from it.
- ///
- [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the offset usage instead.")]
- public static class ActorOffsets
- {
- // GameObject(Actor)
- // GameObject :: Character
- // GameObject :: Character :: BattleChara
- // GameObject :: Character :: Companion
-
- public const int Name = 0x30;
- public const int ActorId = 0x74;
- public const int DataId = 0x80;
- public const int OwnerId = 0x84;
- public const int ObjectKind = 0x8C;
- public const int SubKind = 0x8D;
- public const int IsFriendly = 0x8E;
- public const int YalmDistanceFromObjectX = 0x90;
- public const int TargetStatus = 0x91;
- public const int YalmDistanceFromObjectY = 0x92;
- public const int Position = 0xA0;
- public const int Rotation = 0xB0;
- public const int HitboxRadius = 0xC0;
- // End GameObject 0x1A0
-
- public const int CurrentHp = 0x1C4;
- public const int MaxHp = 0x1C8;
- public const int CurrentMp = 0x1CC;
- public const int MaxMp = 0x1D0;
- public const int CurrentGp = 0x1D4;
- public const int MaxGp = 0x1D6;
- public const int CurrentCp = 0x1D8;
- public const int MaxCp = 0x1DA;
- public const int ClassJob = 0x1E2;
- public const int Level = 0x1E3;
- public const int PlayerCharacterTargetActorId = 0x230;
- public const int Customize = 0x1898;
- public const int CompanyTag = 0x18B2;
- public const int BattleNpcTargetActorId = 0x18D8;
- public const int NameId = 0x1940;
- public const int CurrentWorld = 0x195C;
- public const int HomeWorld = 0x195E;
- public const int StatusFlags = 0x19A0;
- // End Character 0x19B0
- // End Companion 0x19C0
-
- public const int UIStatusEffects = 0x19F8;
- public const int IsCasting = 0x1B80;
- public const int IsCasting2 = 0x1B82;
- public const int CurrentCastSpellActionId = 0x1B84;
- public const int CurrentCastTargetActorId = 0x1B90;
- public const int CurrentCastTime = 0x1BB4;
- public const int TotalCastTime = 0x1BB8;
- // End BattleChara 0x2C00
- }
-}
diff --git a/Dalamud/Game/ClientState/Actors/Types/Chara.cs b/Dalamud/Game/ClientState/Actors/Types/Chara.cs
deleted file mode 100644
index 5c8dca228..000000000
--- a/Dalamud/Game/ClientState/Actors/Types/Chara.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-using System;
-
-using Dalamud.Game.ClientState.Resolvers;
-using Dalamud.Game.ClientState.Structs;
-using Dalamud.Memory;
-
-namespace Dalamud.Game.ClientState.Actors.Types
-{
- ///
- /// This class represents the base for non-static entities.
- ///
- public unsafe class Chara : Actor
- {
- ///
- /// Initializes a new instance of the class.
- /// This represents a non-static entity.
- ///
- /// The address of this actor in memory.
- /// A dalamud reference needed to access game data in Resolvers.
- internal Chara(IntPtr address, Dalamud dalamud)
- : base(address, dalamud)
- {
- }
-
- ///
- /// Gets the current HP of this Chara.
- ///
- public uint CurrentHp => *(uint*)(this.Address + ActorOffsets.CurrentHp);
-
- ///
- /// Gets the maximum HP of this Chara.
- ///
- public uint MaxHp => *(uint*)(this.Address + ActorOffsets.MaxHp);
-
- ///
- /// Gets the current MP of this Chara.
- ///
- public uint CurrentMp => *(uint*)(this.Address + ActorOffsets.CurrentMp);
-
- ///
- /// Gets the maximum MP of this Chara.
- ///
- public uint MaxMp => *(uint*)(this.Address + ActorOffsets.MaxMp);
-
- ///
- /// Gets the current GP of this Chara.
- ///
- public uint CurrentGp => *(uint*)(this.Address + ActorOffsets.CurrentGp);
-
- ///
- /// Gets the maximum GP of this Chara.
- ///
- public uint MaxGp => *(uint*)(this.Address + ActorOffsets.MaxGp);
-
- ///
- /// Gets the current CP of this Chara.
- ///
- public uint CurrentCp => *(uint*)(this.Address + ActorOffsets.CurrentCp);
-
- ///
- /// Gets the maximum CP of this Chara.
- ///
- public uint MaxCp => *(uint*)(this.Address + ActorOffsets.MaxCp);
-
- ///
- /// Gets the ClassJob of this Chara.
- ///
- public ExcelResolver ClassJob => new(*(byte*)(this.Address + ActorOffsets.ClassJob), this.Dalamud);
-
- ///
- /// Gets the level of this Chara.
- ///
- public byte Level => *(byte*)(this.Address + ActorOffsets.Level);
-
- ///
- /// Gets a byte array describing the visual appearance of this Chara.
- /// Indexed by .
- ///
- public byte[] Customize => MemoryHelper.Read(this.Address + ActorOffsets.Customize, 28);
-
- ///
- /// Gets the status flags.
- ///
- public StatusFlags StatusFlags => *(StatusFlags*)(this.Address + ActorOffsets.StatusFlags);
-
- ///
- /// Gets the current status effects.
- ///
- ///
- /// This copies every time it is invoked, so make sure to only grab it once.
- ///
- public StatusEffect[] StatusEffects => MemoryHelper.Read(this.Address + ActorOffsets.UIStatusEffects, 30, true);
-
- ///
- /// Gets a value indicating whether the actor is currently casting.
- ///
- public bool IsCasting => *(int*)(this.Address + ActorOffsets.IsCasting) > 0;
-
- ///
- /// Gets a value indicating whether the actor is currently casting (again?).
- ///
- public bool IsCasting2 => *(int*)(this.Address + ActorOffsets.IsCasting2) > 0;
-
- ///
- /// Gets the spell action ID currently being cast by the actor.
- ///
- public uint CurrentCastSpellActionId => *(uint*)(this.Address + ActorOffsets.CurrentCastSpellActionId);
-
- ///
- /// Gets the actor ID of the target currently being cast at by the actor.
- ///
- public uint CurrentCastTargetActorId => *(uint*)(this.Address + ActorOffsets.CurrentCastTargetActorId);
-
- ///
- /// Gets the current casting time of the spell being cast by the actor.
- ///
- public float CurrentCastTime => *(float*)(this.Address + ActorOffsets.CurrentCastTime);
-
- ///
- /// Gets the total casting time of the spell being cast by the actor.
- ///
- public float TotalCastTime => *(float*)(this.Address + ActorOffsets.TotalCastTime);
- }
-}
diff --git a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/EventObj.cs b/Dalamud/Game/ClientState/Actors/Types/NonPlayer/EventObj.cs
deleted file mode 100644
index 7d9dce443..000000000
--- a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/EventObj.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-
-namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
-{
- ///
- /// This class represents an EventObj.
- ///
- public unsafe class EventObj : Actor
- {
- ///
- /// Initializes a new instance of the class.
- /// Set up a new EventObj with the provided memory representation.
- ///
- /// The address of this actor in memory.
- /// A dalamud reference needed to access game data in Resolvers.
- internal EventObj(IntPtr address, Dalamud dalamud)
- : base(address, dalamud)
- {
- }
-
- ///
- /// Gets the event object ID of the linking to their respective game data.
- ///
- public uint EventObjectId => *(uint*)(this.Address + ActorOffsets.DataId);
- }
-}
diff --git a/Dalamud/Game/ClientState/Actors/Types/PartyMember.cs b/Dalamud/Game/ClientState/Actors/Types/PartyMember.cs
deleted file mode 100644
index 2e2d67f54..000000000
--- a/Dalamud/Game/ClientState/Actors/Types/PartyMember.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using Dalamud.Game.Text.SeStringHandling;
-using Dalamud.Memory;
-
-namespace Dalamud.Game.ClientState.Actors.Types
-{
- ///
- /// This class represents a party member.
- ///
- public class PartyMember
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The ActorTable instance.
- /// The interop data struct.
- public PartyMember(ActorTable table, Structs.PartyMember rawData)
- {
- this.CharacterName = MemoryHelper.ReadSeString(rawData.namePtr);
- this.Unknown = rawData.unknown;
- this.Actor = null;
-
- for (var i = 0; i < table.Length; i++)
- {
- if (table[i] != null && table[i].ActorId == rawData.actorId)
- {
- this.Actor = table[i];
- break;
- }
- }
-
- this.ObjectKind = rawData.objectKind;
- }
-
- ///
- /// Gets the name of the character.
- ///
- public SeString CharacterName { get; }
-
- ///
- /// Gets something unknown.
- ///
- public long Unknown { get; }
-
- ///
- /// Gets the actor object that corresponds to this party member.
- ///
- public Actor Actor { get; }
-
- ///
- /// Gets the kind or type of actor.
- ///
- public ObjectKind ObjectKind { get; }
- }
-}
diff --git a/Dalamud/Game/ClientState/Buddy/BuddyList.cs b/Dalamud/Game/ClientState/Buddy/BuddyList.cs
new file mode 100644
index 000000000..3080283a5
--- /dev/null
+++ b/Dalamud/Game/ClientState/Buddy/BuddyList.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+using JetBrains.Annotations;
+using Serilog;
+
+namespace Dalamud.Game.ClientState.Buddy
+{
+ ///
+ /// This collection represents the buddies present in your squadron or trust party.
+ /// It does not include the local player.
+ ///
+ public sealed partial class BuddyList
+ {
+ private const uint InvalidObjectID = 0xE0000000;
+
+ private readonly Dalamud dalamud;
+ private readonly ClientStateAddressResolver address;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The instance.
+ /// Client state address resolver.
+ internal BuddyList(Dalamud dalamud, ClientStateAddressResolver addressResolver)
+ {
+ this.dalamud = dalamud;
+ this.address = addressResolver;
+
+ Log.Verbose($"Buddy list address 0x{this.address.BuddyList.ToInt64():X}");
+ }
+
+ ///
+ /// Gets the amount of battle buddies the local player has.
+ ///
+ public int Length
+ {
+ get
+ {
+ var i = 0;
+ for (; i < 3; i++)
+ {
+ var addr = this.GetBattleBuddyMemberAddress(i);
+ var member = this.CreateBuddyMemberReference(addr);
+ if (member == null)
+ break;
+ }
+
+ return i;
+ }
+ }
+
+ ///
+ /// Gets a value indicating whether the local player's companion is present.
+ ///
+ public bool CompanionBuddyPresent => this.CompanionBuddy != null;
+
+ ///
+ /// Gets a value indicating whether the local player's pet is present.
+ ///
+ public bool PetBuddyPresent => this.PetBuddy != null;
+
+ ///
+ /// Gets the active companion buddy.
+ ///
+ [CanBeNull]
+ public BuddyMember CompanionBuddy
+ {
+ get
+ {
+ var addr = this.GetCompanionBuddyMemberAddress();
+ return this.CreateBuddyMemberReference(addr);
+ }
+ }
+
+ ///
+ /// Gets the active pet buddy.
+ ///
+ [CanBeNull]
+ public BuddyMember PetBuddy
+ {
+ get
+ {
+ var addr = this.GetPetBuddyMemberAddress();
+ return this.CreateBuddyMemberReference(addr);
+ }
+ }
+
+ ///
+ /// Gets the address of the buddy list.
+ ///
+ internal IntPtr BuddyListAddress => this.address.BuddyList;
+
+ private static int BuddyMemberSize { get; } = Marshal.SizeOf();
+
+ private unsafe FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy* BuddyListStruct => (FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy*)this.BuddyListAddress;
+
+ ///
+ /// Gets a battle buddy at the specified spawn index.
+ ///
+ /// Spawn index.
+ /// A at the specified spawn index.
+ [CanBeNull]
+ public BuddyMember this[int index]
+ {
+ get
+ {
+ var address = this.GetBattleBuddyMemberAddress(index);
+ return this.CreateBuddyMemberReference(address);
+ }
+ }
+
+ ///
+ /// Gets the address of the companion buddy.
+ ///
+ /// The memory address of the companion buddy.
+ public unsafe IntPtr GetCompanionBuddyMemberAddress()
+ {
+ return (IntPtr)(&this.BuddyListStruct->Companion);
+ }
+
+ ///
+ /// Gets the address of the pet buddy.
+ ///
+ /// The memory address of the pet buddy.
+ public unsafe IntPtr GetPetBuddyMemberAddress()
+ {
+ return (IntPtr)(&this.BuddyListStruct->Pet);
+ }
+
+ ///
+ /// Gets the address of the battle buddy at the specified index of the buddy list.
+ ///
+ /// The index of the battle buddy.
+ /// The memory address of the battle buddy.
+ public unsafe IntPtr GetBattleBuddyMemberAddress(int index)
+ {
+ if (index < 0 || index >= 3)
+ return IntPtr.Zero;
+
+ return (IntPtr)(this.BuddyListStruct->BattleBuddies + (index * BuddyMemberSize));
+ }
+
+ ///
+ /// Create a reference to a buddy.
+ ///
+ /// The address of the buddy in memory.
+ /// object containing the requested data.
+ [CanBeNull]
+ public BuddyMember CreateBuddyMemberReference(IntPtr address)
+ {
+ if (this.dalamud.ClientState.LocalContentId == 0)
+ return null;
+
+ if (address == IntPtr.Zero)
+ return null;
+
+ var buddy = new BuddyMember(address, this.dalamud);
+ if (buddy.ObjectId == InvalidObjectID)
+ return null;
+
+ return buddy;
+ }
+ }
+
+ ///
+ /// This collection represents the buddies present in your squadron or trust party.
+ ///
+ public sealed partial class BuddyList : IReadOnlyCollection
+ {
+ ///
+ int IReadOnlyCollection.Count => this.Length;
+
+ ///
+ public IEnumerator GetEnumerator()
+ {
+ for (var i = 0; i < this.Length; i++)
+ {
+ yield return this[i];
+ }
+ }
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
+ }
+}
diff --git a/Dalamud/Game/ClientState/Buddy/BuddyMember.cs b/Dalamud/Game/ClientState/Buddy/BuddyMember.cs
new file mode 100644
index 000000000..1cb40f39f
--- /dev/null
+++ b/Dalamud/Game/ClientState/Buddy/BuddyMember.cs
@@ -0,0 +1,78 @@
+using System;
+
+using Dalamud.Game.ClientState.Objects.Types;
+using Dalamud.Game.ClientState.Resolvers;
+using JetBrains.Annotations;
+
+namespace Dalamud.Game.ClientState.Buddy
+{
+ ///
+ /// This class represents a buddy such as the chocobo companion, summoned pets, squadron groups and trust parties.
+ ///
+ public unsafe class BuddyMember
+ {
+ private Dalamud dalamud;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Buddy address.
+ /// Dalamud instance.
+ internal BuddyMember(IntPtr address, Dalamud dalamud)
+ {
+ this.dalamud = dalamud;
+ this.Address = address;
+ }
+
+ ///
+ /// Gets the address of the buddy in memory.
+ ///
+ public IntPtr Address { get; }
+
+ ///
+ /// Gets the object ID of this buddy.
+ ///
+ public uint ObjectId => this.Struct->ObjectID;
+
+ ///
+ /// Gets the actor associated with this buddy.
+ ///
+ ///
+ /// This iterates the actor table, it should be used with care.
+ ///
+ [CanBeNull]
+ public GameObject Actor => this.dalamud.ClientState.Objects.SearchByID(this.ObjectId);
+
+ ///
+ /// Gets the current health of this buddy.
+ ///
+ public uint CurrentHP => this.Struct->CurrentHealth;
+
+ ///
+ /// Gets the maximum health of this buddy.
+ ///
+ public uint MaxHP => this.Struct->MaxHealth;
+
+ ///
+ /// Gets the data ID of this buddy.
+ ///
+ public uint DataID => this.Struct->DataID;
+
+ ///
+ /// Gets the Mount data related to this buddy. It should only be used with companion buddies.
+ ///
+ public ExcelResolver MountData => new(this.DataID, this.dalamud);
+
+ ///
+ /// Gets the Pet data related to this buddy. It should only be used with pet buddies.
+ ///
+ public ExcelResolver PetData => new(this.DataID, this.dalamud);
+
+ ///
+ /// Gets the Trust data related to this buddy. It should only be used with battle buddies.
+ ///
+ public ExcelResolver TrustData => new(this.DataID, this.dalamud);
+
+ private FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy.BuddyMember* Struct => (FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy.BuddyMember*)this.Address;
+ }
+}
diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs
index 2da9eddac..4a82b96d5 100644
--- a/Dalamud/Game/ClientState/ClientState.cs
+++ b/Dalamud/Game/ClientState/ClientState.cs
@@ -3,14 +3,15 @@ using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
-using Dalamud.Game.ClientState.Actors;
-using Dalamud.Game.ClientState.Actors.Types;
+using Dalamud.Game.ClientState.Buddy;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Fates;
using Dalamud.Game.ClientState.GamePad;
using Dalamud.Game.ClientState.JobGauge;
using Dalamud.Game.ClientState.Keys;
-using Dalamud.Game.Internal;
+using Dalamud.Game.ClientState.Objects;
+using Dalamud.Game.ClientState.Objects.SubKinds;
+using Dalamud.Game.ClientState.Party;
using Dalamud.Hooking;
using JetBrains.Annotations;
using Serilog;
@@ -45,12 +46,14 @@ namespace Dalamud.Game.ClientState
this.ClientLanguage = startInfo.Language;
- this.Actors = new ActorTable(dalamud, this.address);
+ this.Objects = new ObjectTable(dalamud, this.address);
this.Fates = new FateTable(dalamud, this.address);
this.PartyList = new PartyList(dalamud, this.address);
+ this.BuddyList = new BuddyList(dalamud, this.address);
+
this.JobGauges = new JobGauges(this.address);
this.KeyState = new KeyState(this.address, scanner.Module.BaseAddress);
@@ -102,7 +105,7 @@ namespace Dalamud.Game.ClientState
///
/// Gets the table of all present actors.
///
- public ActorTable Actors { get; }
+ public ObjectTable Objects { get; }
///
/// Gets the table of all present fates.
@@ -124,6 +127,11 @@ namespace Dalamud.Game.ClientState
///
public PartyList PartyList { get; }
+ ///
+ /// Gets the class facilitating buddy list data access.
+ ///
+ public BuddyList BuddyList { get; }
+
///
/// Gets access to the keypress state of keyboard keys in game.
///
@@ -153,7 +161,7 @@ namespace Dalamud.Game.ClientState
/// Gets the local player character, if one is present.
///
[CanBeNull]
- public PlayerCharacter LocalPlayer => this.Actors[0] as PlayerCharacter;
+ public PlayerCharacter LocalPlayer => this.Objects[0] as PlayerCharacter;
///
/// Gets the content ID of the local character.
@@ -171,7 +179,6 @@ namespace Dalamud.Game.ClientState
public void Enable()
{
this.GamepadState.Enable();
- this.PartyList.Enable();
this.setupTerritoryTypeHook.Enable();
}
@@ -180,7 +187,6 @@ namespace Dalamud.Game.ClientState
///
public void Dispose()
{
- this.PartyList.Dispose();
this.setupTerritoryTypeHook.Dispose();
this.GamepadState.Dispose();
diff --git a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs
index 1b6a86454..334bf0198 100644
--- a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs
+++ b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs
@@ -1,7 +1,4 @@
using System;
-using System.Runtime.InteropServices;
-
-using Dalamud.Game.Internal;
namespace Dalamud.Game.ClientState
{
@@ -15,17 +12,25 @@ namespace Dalamud.Game.ClientState
///
/// Gets the address of the actor table.
///
- public IntPtr ActorTable { get; private set; }
+ public IntPtr ObjectTable { get; private set; }
///
- /// Gets the address of the fate table pointer.
+ /// Gets the address of the buddy list.
+ ///
+ public IntPtr BuddyList { get; private set; }
+
+ ///
+ /// Gets the address of a pointer to the fate table.
///
///
/// This is a static address to a pointer, not the address of the table itself.
///
public IntPtr FateTablePtr { get; private set; }
- // public IntPtr ViewportActorTable { get; private set; }
+ ///
+ /// Gets the address of the Group Manager.
+ ///
+ public IntPtr GroupManager { get; private set; }
///
/// Gets the address of the local content id.
@@ -75,12 +80,16 @@ namespace Dalamud.Game.ClientState
// ViewportActorTable = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? 85 ED", 0) + 0x148;
// SomeActorTableAccess = sig.ScanText("E8 ?? ?? ?? ?? 48 8D 55 A0 48 8D 8E ?? ?? ?? ??");
- this.ActorTable = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 44 0F B6 83");
+ this.ObjectTable = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 44 0F B6 83");
+
+ this.BuddyList = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 45 84 E4 75 1A F6 45 12 04");
this.FateTablePtr = sig.GetStaticAddressFromSig("48 8B 15 ?? ?? ?? ?? 48 8B F9 44 0F B7 41 ??");
+ this.GroupManager = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 80 B8 ?? ?? ?? ?? ?? 76 50");
+
this.LocalContentId = sig.GetStaticAddressFromSig("48 0F 44 05 ?? ?? ?? ?? 48 39 07");
- this.JobGaugeData = sig.GetStaticAddressFromSig("48 8B 0D ?? ?? ?? ?? 48 85 C9 74 43") + 0x10;
+ this.JobGaugeData = sig.GetStaticAddressFromSig("48 8B 0D ?? ?? ?? ?? 48 85 C9 74 43") + 0x8;
this.SetupTerritoryType = sig.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B F9 66 89 91 ?? ?? ?? ??");
@@ -88,11 +97,9 @@ namespace Dalamud.Game.ClientState
// so GetStaticAddressFromSig() can't be used. lea rcx, ds:1DB9F74h[rax*4]
this.KeyboardState = sig.ScanText("48 8D 0C 85 ?? ?? ?? ?? 8B 04 31 85 C2 0F 85") + 0x4;
- // PartyListUpdate = sig.ScanText("E8 ?? ?? ?? ?? 49 8B D7 4C 8D 86 ?? ?? ?? ??");
-
this.ConditionFlags = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? BA ?? ?? ?? ?? E8 ?? ?? ?? ?? B0 01 48 83 C4 30");
- this.TargetManager = sig.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? FF 50 ?? 48 85 DB", 3);
+ this.TargetManager = sig.GetStaticAddressFromSig("48 8B 05 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? FF 50 ?? 48 85 DB");
this.GamepadPoll = sig.ScanText("40 ?? 57 41 ?? 48 81 EC ?? ?? ?? ?? 44 0F ?? ?? ?? ?? ?? ?? ?? 48 8B");
}
diff --git a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpcSubKind.cs b/Dalamud/Game/ClientState/Objects/Enums/BattleNpcSubKind.cs
similarity index 88%
rename from Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpcSubKind.cs
rename to Dalamud/Game/ClientState/Objects/Enums/BattleNpcSubKind.cs
index 1f437b315..c10cc6cfc 100644
--- a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpcSubKind.cs
+++ b/Dalamud/Game/ClientState/Objects/Enums/BattleNpcSubKind.cs
@@ -1,4 +1,4 @@
-namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
+namespace Dalamud.Game.ClientState.Objects.Enums
{
///
/// An Enum describing possible BattleNpc kinds.
diff --git a/Dalamud/Game/ClientState/Actors/Types/CustomizeIndex.cs b/Dalamud/Game/ClientState/Objects/Enums/CustomizeIndex.cs
similarity index 98%
rename from Dalamud/Game/ClientState/Actors/Types/CustomizeIndex.cs
rename to Dalamud/Game/ClientState/Objects/Enums/CustomizeIndex.cs
index 23618ae24..b1827c0c5 100644
--- a/Dalamud/Game/ClientState/Actors/Types/CustomizeIndex.cs
+++ b/Dalamud/Game/ClientState/Objects/Enums/CustomizeIndex.cs
@@ -1,4 +1,4 @@
-namespace Dalamud.Game.ClientState.Actors.Types
+namespace Dalamud.Game.ClientState.Objects.Enums
{
///
/// This enum describes the indices of the Customize array.
diff --git a/Dalamud/Game/ClientState/Actors/Types/ObjectKind.cs b/Dalamud/Game/ClientState/Objects/Enums/ObjectKind.cs
similarity index 95%
rename from Dalamud/Game/ClientState/Actors/Types/ObjectKind.cs
rename to Dalamud/Game/ClientState/Objects/Enums/ObjectKind.cs
index b79adb784..038bce143 100644
--- a/Dalamud/Game/ClientState/Actors/Types/ObjectKind.cs
+++ b/Dalamud/Game/ClientState/Objects/Enums/ObjectKind.cs
@@ -1,4 +1,4 @@
-namespace Dalamud.Game.ClientState.Actors.Types
+namespace Dalamud.Game.ClientState.Objects.Enums
{
///
/// Enum describing possible entity kinds.
@@ -6,7 +6,7 @@ namespace Dalamud.Game.ClientState.Actors.Types
public enum ObjectKind : byte
{
///
- /// Invalid actor.
+ /// Invalid character.
///
None = 0x00,
diff --git a/Dalamud/Game/ClientState/Actors/Types/StatusFlags.cs b/Dalamud/Game/ClientState/Objects/Enums/StatusFlags.cs
similarity index 70%
rename from Dalamud/Game/ClientState/Actors/Types/StatusFlags.cs
rename to Dalamud/Game/ClientState/Objects/Enums/StatusFlags.cs
index a1101ceca..43587c66b 100644
--- a/Dalamud/Game/ClientState/Actors/Types/StatusFlags.cs
+++ b/Dalamud/Game/ClientState/Objects/Enums/StatusFlags.cs
@@ -1,6 +1,6 @@
using System;
-namespace Dalamud.Game.ClientState.Actors.Types
+namespace Dalamud.Game.ClientState.Objects.Enums
{
///
/// Enum describing possible status flags.
@@ -14,42 +14,42 @@ namespace Dalamud.Game.ClientState.Actors.Types
None = 0,
///
- /// Hostile actor.
+ /// Hostile character.
///
Hostile = 1,
///
- /// Actor in combat.
+ /// Character in combat.
///
InCombat = 2,
///
- /// Actor weapon is out.
+ /// Character weapon is out.
///
WeaponOut = 4,
///
- /// Actor offhand is out.
+ /// Character offhand is out.
///
OffhandOut = 8,
///
- /// Actor is a party member.
+ /// Character is a party member.
///
PartyMember = 16,
///
- /// Actor is a alliance member.
+ /// Character is a alliance member.
///
AllianceMember = 32,
///
- /// Actor is in friend list.
+ /// Character is in friend list.
///
Friend = 64,
///
- /// Actor is casting.
+ /// Character is casting.
///
IsCasting = 128,
}
diff --git a/Dalamud/Game/ClientState/Objects/ObjectTable.cs b/Dalamud/Game/ClientState/Objects/ObjectTable.cs
new file mode 100644
index 000000000..7e11d8e6f
--- /dev/null
+++ b/Dalamud/Game/ClientState/Objects/ObjectTable.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+using Dalamud.Game.ClientState.Objects.Enums;
+using Dalamud.Game.ClientState.Objects.SubKinds;
+using Dalamud.Game.ClientState.Objects.Types;
+using JetBrains.Annotations;
+using Serilog;
+
+namespace Dalamud.Game.ClientState.Objects
+{
+ ///
+ /// This collection represents the currently spawned FFXIV game objects.
+ ///
+ public sealed partial class ObjectTable
+ {
+ private const int ObjectTableLength = 424;
+
+ private readonly Dalamud dalamud;
+ private readonly ClientStateAddressResolver address;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The instance.
+ /// Client state address resolver.
+ internal ObjectTable(Dalamud dalamud, ClientStateAddressResolver addressResolver)
+ {
+ this.dalamud = dalamud;
+ this.address = addressResolver;
+
+ Log.Verbose($"Object table address 0x{this.address.ObjectTable.ToInt64():X}");
+ }
+
+ ///
+ /// Gets the address of the object table.
+ ///
+ public IntPtr Address => this.address.ObjectTable;
+
+ ///
+ /// Gets the length of the object table.
+ ///
+ public int Length => ObjectTableLength;
+
+ ///
+ /// Get an object at the specified spawn index.
+ ///
+ /// Spawn index.
+ /// An at the specified spawn index.
+ [CanBeNull]
+ public GameObject this[int index]
+ {
+ get
+ {
+ var address = this.GetObjectAddress(index);
+ return this.CreateObjectReference(address);
+ }
+ }
+
+ ///
+ /// Search for a game object by their Object ID.
+ ///
+ /// Object ID to find.
+ /// A game object or null.
+ [CanBeNull]
+ public GameObject SearchByID(uint objectID)
+ {
+ foreach (var obj in this)
+ {
+ if (obj == null)
+ continue;
+
+ if (obj.ObjectId == objectID)
+ return obj;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Gets the address of the game object at the specified index of the object table.
+ ///
+ /// The index of the object.
+ /// The memory address of the object.
+ public unsafe IntPtr GetObjectAddress(int index)
+ {
+ if (index < 0 || index >= ObjectTableLength)
+ return IntPtr.Zero;
+
+ return *(IntPtr*)(this.address.ObjectTable + (8 * index));
+ }
+
+ ///
+ /// Create a reference to an FFXIV game object.
+ ///
+ /// The address of the object in memory.
+ /// object or inheritor containing the requested data.
+ [CanBeNull]
+ public unsafe GameObject CreateObjectReference(IntPtr address)
+ {
+ if (this.dalamud.ClientState.LocalContentId == 0)
+ return null;
+
+ if (address == IntPtr.Zero)
+ return null;
+
+ var obj = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)address;
+ var objKind = (ObjectKind)obj->ObjectKind;
+ return objKind switch
+ {
+ ObjectKind.Player => new PlayerCharacter(address, this.dalamud),
+ ObjectKind.BattleNpc => new BattleNpc(address, this.dalamud),
+ ObjectKind.EventObj => new EventObj(address, this.dalamud),
+ ObjectKind.Companion => new Npc(address, this.dalamud),
+ _ => new GameObject(address, this.dalamud),
+ };
+ }
+ }
+
+ ///
+ /// This collection represents the currently spawned FFXIV game objects.
+ ///
+ public sealed partial class ObjectTable : IReadOnlyCollection
+ {
+ ///
+ int IReadOnlyCollection.Count => this.Length;
+
+ ///
+ public IEnumerator GetEnumerator()
+ {
+ for (var i = 0; i < ObjectTableLength; i++)
+ {
+ var obj = this[i];
+
+ if (obj == null)
+ continue;
+
+ yield return obj;
+ }
+ }
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
+ }
+}
diff --git a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpc.cs b/Dalamud/Game/ClientState/Objects/SubKinds/BattleNpc.cs
similarity index 64%
rename from Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpc.cs
rename to Dalamud/Game/ClientState/Objects/SubKinds/BattleNpc.cs
index 3fa8f0c28..ea5fc64fa 100644
--- a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpc.cs
+++ b/Dalamud/Game/ClientState/Objects/SubKinds/BattleNpc.cs
@@ -1,11 +1,13 @@
using System;
-namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
+using Dalamud.Game.ClientState.Objects.Enums;
+
+namespace Dalamud.Game.ClientState.Objects.Types
{
///
/// This class represents a battle NPC.
///
- public unsafe class BattleNpc : Npc
+ public unsafe class BattleNpc : BattleChara
{
///
/// Initializes a new instance of the class.
@@ -21,11 +23,6 @@ namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
///
/// Gets the BattleNpc of this BattleNpc.
///
- public BattleNpcSubKind BattleNpcKind => *(BattleNpcSubKind*)(this.Address + ActorOffsets.SubKind);
-
- ///
- /// Gets the target of the Battle NPC.
- ///
- public override uint TargetActorID => *(uint*)(this.Address + ActorOffsets.BattleNpcTargetActorId);
+ public BattleNpcSubKind BattleNpcKind => (BattleNpcSubKind)this.Struct->Character.GameObject.SubKind;
}
}
diff --git a/Dalamud/Game/ClientState/Objects/SubKinds/EventObj.cs b/Dalamud/Game/ClientState/Objects/SubKinds/EventObj.cs
new file mode 100644
index 000000000..55e0b3f97
--- /dev/null
+++ b/Dalamud/Game/ClientState/Objects/SubKinds/EventObj.cs
@@ -0,0 +1,23 @@
+using System;
+
+using Dalamud.Game.ClientState.Objects.Types;
+
+namespace Dalamud.Game.ClientState.Objects.SubKinds
+{
+ ///
+ /// This class represents an EventObj.
+ ///
+ public unsafe class EventObj : GameObject
+ {
+ ///
+ /// Initializes a new instance of the class.
+ /// Set up a new EventObj with the provided memory representation.
+ ///
+ /// The address of this event object in memory.
+ /// A dalamud reference.
+ internal EventObj(IntPtr address, Dalamud dalamud)
+ : base(address, dalamud)
+ {
+ }
+ }
+}
diff --git a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/Npc.cs b/Dalamud/Game/ClientState/Objects/SubKinds/Npc.cs
similarity index 65%
rename from Dalamud/Game/ClientState/Actors/Types/NonPlayer/Npc.cs
rename to Dalamud/Game/ClientState/Objects/SubKinds/Npc.cs
index a3597570c..cf582a11f 100644
--- a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/Npc.cs
+++ b/Dalamud/Game/ClientState/Objects/SubKinds/Npc.cs
@@ -1,11 +1,13 @@
using System;
-namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
+using Dalamud.Game.ClientState.Objects.Types;
+
+namespace Dalamud.Game.ClientState.Objects.SubKinds
{
///
/// This class represents a NPC.
///
- public unsafe class Npc : Chara
+ public unsafe class Npc : Character
{
///
/// Initializes a new instance of the class.
@@ -18,14 +20,9 @@ namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
{
}
- ///
- /// Gets the data ID of the NPC linking to their assoicated BNpcBase data.
- ///
- public uint BaseId => *(uint*)(this.Address + ActorOffsets.DataId);
-
///
/// Gets the name ID of the NPC linking to their respective game data.
///
- public uint NameId => *(uint*)(this.Address + ActorOffsets.NameId);
+ public uint NameId => this.Struct->NameID;
}
}
diff --git a/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs b/Dalamud/Game/ClientState/Objects/SubKinds/PlayerCharacter.cs
similarity index 63%
rename from Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs
rename to Dalamud/Game/ClientState/Objects/SubKinds/PlayerCharacter.cs
index e04c36d32..9b33e6ce5 100644
--- a/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs
+++ b/Dalamud/Game/ClientState/Objects/SubKinds/PlayerCharacter.cs
@@ -1,15 +1,14 @@
using System;
+using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.ClientState.Resolvers;
-using Dalamud.Game.Text.SeStringHandling;
-using Dalamud.Memory;
-namespace Dalamud.Game.ClientState.Actors.Types
+namespace Dalamud.Game.ClientState.Objects.SubKinds
{
///
/// This class represents a player character.
///
- public unsafe class PlayerCharacter : Chara
+ public unsafe class PlayerCharacter : BattleChara
{
///
/// Initializes a new instance of the class.
@@ -25,21 +24,16 @@ namespace Dalamud.Game.ClientState.Actors.Types
///
/// Gets the current world of the character.
///
- public ExcelResolver CurrentWorld => new(*(ushort*)(this.Address + ActorOffsets.CurrentWorld), this.Dalamud);
+ public ExcelResolver CurrentWorld => new(this.Struct->Character.CurrentWorld, this.Dalamud);
///
/// Gets the home world of the character.
///
- public ExcelResolver HomeWorld => new(*(ushort*)(this.Address + ActorOffsets.HomeWorld), this.Dalamud);
-
- ///
- /// Gets the Free Company tag of this player.
- ///
- public SeString CompanyTag => MemoryHelper.ReadSeString(this.Address + ActorOffsets.CompanyTag, 6);
+ public ExcelResolver HomeWorld => new(this.Struct->Character.HomeWorld, this.Dalamud);
///
/// Gets the target actor ID of the PlayerCharacter.
///
- public override uint TargetActorID => *(uint*)(this.Address + ActorOffsets.PlayerCharacterTargetActorId);
+ public override uint TargetObjectId => this.Struct->Character.GameObject.TargetObjectID;
}
}
diff --git a/Dalamud/Game/ClientState/Objects/Targets.cs b/Dalamud/Game/ClientState/Objects/Targets.cs
new file mode 100644
index 000000000..1c9527221
--- /dev/null
+++ b/Dalamud/Game/ClientState/Objects/Targets.cs
@@ -0,0 +1,169 @@
+using System;
+
+using Dalamud.Game.ClientState.Objects.Types;
+using JetBrains.Annotations;
+
+namespace Dalamud.Game.ClientState.Objects
+{
+ ///
+ /// Get and set various kinds of targets for the player.
+ ///
+ public sealed unsafe class Targets
+ {
+ private readonly Dalamud dalamud;
+ private readonly ClientStateAddressResolver address;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Dalamud instance.
+ /// The ClientStateAddressResolver instance.
+ internal Targets(Dalamud dalamud, ClientStateAddressResolver addressResolver)
+ {
+ this.dalamud = dalamud;
+ this.address = addressResolver;
+ }
+
+ ///
+ /// Gets the address of the target manager.
+ ///
+ public IntPtr Address => this.address.TargetManager;
+
+ ///
+ /// Gets or sets the current target.
+ ///
+ [CanBeNull]
+ public GameObject Target
+ {
+ get => this.dalamud.ClientState.Objects.CreateObjectReference((IntPtr)Struct->Target);
+ set => this.SetTarget(value);
+ }
+
+ ///
+ /// Gets or sets the mouseover target.
+ ///
+ [CanBeNull]
+ public GameObject MouseOverTarget
+ {
+ get => this.dalamud.ClientState.Objects.CreateObjectReference((IntPtr)Struct->MouseOverTarget);
+ set => this.SetMouseOverTarget(value);
+ }
+
+ ///
+ /// Gets or sets the focus target.
+ ///
+ [CanBeNull]
+ public GameObject FocusTarget
+ {
+ get => this.dalamud.ClientState.Objects.CreateObjectReference((IntPtr)Struct->FocusTarget);
+ set => this.SetFocusTarget(value);
+ }
+
+ ///
+ /// Gets or sets the previous target.
+ ///
+ [CanBeNull]
+ public GameObject PreviousTarget
+ {
+ get => this.dalamud.ClientState.Objects.CreateObjectReference((IntPtr)Struct->PreviousTarget);
+ set => this.SetPreviousTarget(value);
+ }
+
+ ///
+ /// Gets or sets the soft target.
+ ///
+ [CanBeNull]
+ public GameObject SoftTarget
+ {
+ get => this.dalamud.ClientState.Objects.CreateObjectReference((IntPtr)Struct->SoftTarget);
+ set => this.SetSoftTarget(value);
+ }
+
+ private FFXIVClientStructs.FFXIV.Client.Game.Control.TargetSystem* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Control.TargetSystem*)this.Address;
+
+ ///
+ /// Sets the current target.
+ ///
+ /// Actor to target.
+ public void SetTarget(GameObject actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
+
+ ///
+ /// Sets the mouseover target.
+ ///
+ /// Actor to target.
+ public void SetMouseOverTarget(GameObject actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
+
+ ///
+ /// Sets the focus target.
+ ///
+ /// Actor to target.
+ public void SetFocusTarget(GameObject actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
+
+ ///
+ /// Sets the previous target.
+ ///
+ /// Actor to target.
+ public void SetPreviousTarget(GameObject actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
+
+ ///
+ /// Sets the soft target.
+ ///
+ /// Actor to target.
+ public void SetSoftTarget(GameObject actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
+
+ ///
+ /// Sets the current target.
+ ///
+ /// Actor (address) to target.
+ public void SetTarget(IntPtr actorAddress) => Struct->Target = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
+
+ ///
+ /// Sets the mouseover target.
+ ///
+ /// Actor (address) to target.
+ public void SetMouseOverTarget(IntPtr actorAddress) => Struct->MouseOverTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
+
+ ///
+ /// Sets the focus target.
+ ///
+ /// Actor (address) to target.
+ public void SetFocusTarget(IntPtr actorAddress) => Struct->FocusTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
+
+ ///
+ /// Sets the previous target.
+ ///
+ /// Actor (address) to target.
+ public void SetPreviousTarget(IntPtr actorAddress) => Struct->PreviousTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
+
+ ///
+ /// Sets the soft target.
+ ///
+ /// Actor (address) to target.
+ public void SetSoftTarget(IntPtr actorAddress) => Struct->SoftTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
+
+ ///
+ /// Clears the current target.
+ ///
+ public void ClearTarget() => this.SetTarget(IntPtr.Zero);
+
+ ///
+ /// Clears the mouseover target.
+ ///
+ public void ClearMouseOverTarget() => this.SetMouseOverTarget(IntPtr.Zero);
+
+ ///
+ /// Clears the focus target.
+ ///
+ public void ClearFocusTarget() => this.SetFocusTarget(IntPtr.Zero);
+
+ ///
+ /// Clears the previous target.
+ ///
+ public void ClearPreviousTarget() => this.SetPreviousTarget(IntPtr.Zero);
+
+ ///
+ /// Clears the soft target.
+ ///
+ public void ClearSoftTarget() => this.SetSoftTarget(IntPtr.Zero);
+ }
+}
diff --git a/Dalamud/Game/ClientState/Objects/Types/BattleChara.cs b/Dalamud/Game/ClientState/Objects/Types/BattleChara.cs
new file mode 100644
index 000000000..5a553b215
--- /dev/null
+++ b/Dalamud/Game/ClientState/Objects/Types/BattleChara.cs
@@ -0,0 +1,68 @@
+using System;
+
+using Dalamud.Game.ClientState.Statuses;
+
+namespace Dalamud.Game.ClientState.Objects.Types
+{
+ ///
+ /// This class represents the battle characters.
+ ///
+ public unsafe class BattleChara : Character
+ {
+ ///
+ /// Initializes a new instance of the class.
+ /// This represents a battle character.
+ ///
+ /// The address of this character in memory.
+ /// Dalamud itself.
+ internal BattleChara(IntPtr address, Dalamud dalamud)
+ : base(address, dalamud)
+ {
+ }
+
+ ///
+ /// Gets the current status effects.
+ ///
+ public StatusList StatusList => new(&this.Struct->StatusManager, this.Dalamud);
+
+ ///
+ /// Gets a value indicating whether the chara is currently casting.
+ ///
+ public bool IsCasting => this.Struct->SpellCastInfo.IsCasting > 0;
+
+ ///
+ /// Gets a value indicating whether the cast is interruptible.
+ ///
+ public bool IsCastInterruptible => this.Struct->SpellCastInfo.Interruptible > 0;
+
+ ///
+ /// Gets the spell action type of the spell being cast by the actor.
+ ///
+ public byte CastActionType => (byte)this.Struct->SpellCastInfo.ActionType;
+
+ ///
+ /// Gets the spell action ID of the spell being cast by the actor.
+ ///
+ public uint CastActionId => this.Struct->SpellCastInfo.ActionID;
+
+ ///
+ /// Gets the object ID of the target currently being cast at by the chara.
+ ///
+ public uint CastTargetObjectId => this.Struct->SpellCastInfo.CastTargetID;
+
+ ///
+ /// Gets the current casting time of the spell being cast by the chara.
+ ///
+ public float CurrentCastTime => this.Struct->SpellCastInfo.CurrentCastTime;
+
+ ///
+ /// Gets the total casting time of the spell being cast by the chara.
+ ///
+ public float TotalCastTime => this.Struct->SpellCastInfo.TotalCastTime;
+
+ ///
+ /// Gets the underlying structure.
+ ///
+ private protected new FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara*)this.Address;
+ }
+}
diff --git a/Dalamud/Game/ClientState/Objects/Types/Character.cs b/Dalamud/Game/ClientState/Objects/Types/Character.cs
new file mode 100644
index 000000000..2ebcbd1c5
--- /dev/null
+++ b/Dalamud/Game/ClientState/Objects/Types/Character.cs
@@ -0,0 +1,103 @@
+using System;
+
+using Dalamud.Game.ClientState.Objects.Enums;
+using Dalamud.Game.ClientState.Resolvers;
+using Dalamud.Game.Text.SeStringHandling;
+using Dalamud.Memory;
+using JetBrains.Annotations;
+
+namespace Dalamud.Game.ClientState.Objects.Types
+{
+ ///
+ /// This class represents the base for non-static entities.
+ ///
+ public unsafe class Character : GameObject
+ {
+ ///
+ /// Initializes a new instance of the class.
+ /// This represents a non-static entity.
+ ///
+ /// The address of this character in memory.
+ /// Dalamud itself.
+ internal Character(IntPtr address, Dalamud dalamud)
+ : base(address, dalamud)
+ {
+ }
+
+ ///
+ /// Gets the current HP of this Chara.
+ ///
+ public uint CurrentHp => this.Struct->Health;
+
+ ///
+ /// Gets the maximum HP of this Chara.
+ ///
+ public uint MaxHp => this.Struct->MaxHealth;
+
+ ///
+ /// Gets the current MP of this Chara.
+ ///
+ public uint CurrentMp => this.Struct->Mana;
+
+ ///
+ /// Gets the maximum MP of this Chara.
+ ///
+ public uint MaxMp => this.Struct->MaxMana;
+
+ ///
+ /// Gets the current GP of this Chara.
+ ///
+ public uint CurrentGp => this.Struct->GatheringPoints;
+
+ ///
+ /// Gets the maximum GP of this Chara.
+ ///
+ public uint MaxGp => this.Struct->MaxGatheringPoints;
+
+ ///
+ /// Gets the current CP of this Chara.
+ ///
+ public uint CurrentCp => this.Struct->CraftingPoints;
+
+ ///
+ /// Gets the maximum CP of this Chara.
+ ///
+ public uint MaxCp => this.Struct->MaxCraftingPoints;
+
+ ///
+ /// Gets the ClassJob of this Chara.
+ ///
+ public ExcelResolver ClassJob => new(this.Struct->ClassJob, this.Dalamud);
+
+ ///
+ /// Gets the level of this Chara.
+ ///
+ public byte Level => this.Struct->Level;
+
+ ///
+ /// Gets a byte array describing the visual appearance of this Chara.
+ /// Indexed by .
+ ///
+ public byte[] Customize => MemoryHelper.Read((IntPtr)this.Struct->CustomizeData, 28);
+
+ ///
+ /// Gets the Free Company tag of this chara.
+ ///
+ public SeString CompanyTag => MemoryHelper.ReadSeString((IntPtr)this.Struct->FreeCompanyTag, 6);
+
+ ///
+ /// Gets the target object ID of the character.
+ ///
+ public override uint TargetObjectId => this.Struct->GameObject.TargetObjectID;
+
+ ///
+ /// Gets the status flags.
+ ///
+ public StatusFlags StatusFlags => (StatusFlags)this.Struct->StatusFlags;
+
+ ///
+ /// Gets the underlying structure.
+ ///
+ private protected new FFXIVClientStructs.FFXIV.Client.Game.Character.Character* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)this.Address;
+ }
+}
diff --git a/Dalamud/Game/ClientState/Objects/Types/GameObject.cs b/Dalamud/Game/ClientState/Objects/Types/GameObject.cs
new file mode 100644
index 000000000..68e41ef3f
--- /dev/null
+++ b/Dalamud/Game/ClientState/Objects/Types/GameObject.cs
@@ -0,0 +1,168 @@
+using System;
+using System.Numerics;
+
+using Dalamud.Game.ClientState.Objects.Enums;
+using Dalamud.Game.Text.SeStringHandling;
+using Dalamud.Memory;
+using JetBrains.Annotations;
+
+namespace Dalamud.Game.ClientState.Objects.Types
+{
+ ///
+ /// This class represents a GameObject in FFXIV.
+ ///
+ public unsafe partial class GameObject : IEquatable
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The address of this game object in memory.
+ /// Dalamud itself.
+ internal GameObject(IntPtr address, Dalamud dalamud)
+ {
+ this.Address = address;
+ this.Dalamud = dalamud;
+ }
+
+ ///
+ /// Gets the address of the game object in memory.
+ ///
+ public IntPtr Address { get; }
+
+ ///
+ /// Gets the Dalamud instance.
+ ///
+ private protected Dalamud Dalamud { get; }
+
+ ///
+ /// This allows you to if (obj) {...} to check for validity.
+ ///
+ /// The actor to check.
+ /// True or false.
+ public static implicit operator bool(GameObject? gameObject) => IsValid(gameObject);
+
+ public static bool operator ==(GameObject? gameObject1, GameObject? gameObject2)
+ {
+ // Using == results in a stack overflow.
+ if (gameObject1 is null || gameObject2 is null)
+ return Equals(gameObject1, gameObject2);
+
+ return gameObject1.Equals(gameObject2);
+ }
+
+ public static bool operator !=(GameObject? actor1, GameObject? actor2) => !(actor1 == actor2);
+
+ ///
+ /// Gets a value indicating whether this actor is still valid in memory.
+ ///
+ /// The actor to check.
+ /// True or false.
+ public static bool IsValid(GameObject? actor)
+ {
+ if (actor is null)
+ return false;
+
+ if (actor.Dalamud.ClientState.LocalContentId == 0)
+ return false;
+
+ return true;
+ }
+
+ ///
+ /// Gets a value indicating whether this actor is still valid in memory.
+ ///
+ /// True or false.
+ public bool IsValid() => IsValid(this);
+
+ ///
+ bool IEquatable.Equals(GameObject other) => this.ObjectId == other?.ObjectId;
+
+ ///
+ public override bool Equals(object obj) => ((IEquatable)this).Equals(obj as GameObject);
+
+ ///
+ public override int GetHashCode() => this.ObjectId.GetHashCode();
+ }
+
+ ///
+ /// This class represents a basic actor (GameObject) in FFXIV.
+ ///
+ public unsafe partial class GameObject
+ {
+ ///
+ /// Gets the name of this .
+ ///
+ public SeString Name => MemoryHelper.ReadSeString((IntPtr)this.Struct->Name, 32);
+
+ ///
+ /// Gets the object ID of this .
+ ///
+ public uint ObjectId => this.Struct->ObjectID;
+
+ ///
+ /// Gets the data ID for linking to other respective game data.
+ ///
+ public uint DataId => this.Struct->DataID;
+
+ ///
+ /// Gets the ID of this GameObject's owner.
+ ///
+ public uint OwnerId => this.Struct->OwnerID;
+
+ ///
+ /// Gets the entity kind of this .
+ /// See the ObjectKind enum for possible values.
+ ///
+ public ObjectKind ObjectKind => (ObjectKind)this.Struct->ObjectKind;
+
+ ///
+ /// Gets the sub kind of this Actor.
+ ///
+ public byte SubKind => this.Struct->SubKind;
+
+ ///
+ /// Gets the X distance from the local player in yalms.
+ ///
+ public byte YalmDistanceX => this.Struct->YalmDistanceFromPlayerX;
+
+ ///
+ /// Gets the Y distance from the local player in yalms.
+ ///
+ public byte YalmDistanceZ => this.Struct->YalmDistanceFromPlayerZ;
+
+ ///
+ /// Gets the position of this .
+ ///
+ public Vector3 Position => new(this.Struct->Position.X, this.Struct->Position.Y, this.Struct->Position.Z);
+
+ ///
+ /// Gets the rotation of this .
+ /// This ranges from -pi to pi radians.
+ ///
+ public float Rotation => this.Struct->Rotation;
+
+ ///
+ /// Gets the hitbox radius of this .
+ ///
+ public float HitboxRadius => this.Struct->HitboxRadius;
+
+ ///
+ /// Gets the current target of the game object.
+ ///
+ public virtual uint TargetObjectId => 0;
+
+ ///
+ /// Gets the target object of the game object.
+ ///
+ ///
+ /// This iterates the actor table, it should be used with care.
+ ///
+ [CanBeNull]
+ public virtual GameObject TargetObject => this.Dalamud.ClientState.Objects.SearchByID(this.TargetObjectId);
+
+ ///
+ /// Gets the underlying structure.
+ ///
+ private protected FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)this.Address;
+ }
+}
diff --git a/Dalamud/Game/ClientState/Party/PartyList.cs b/Dalamud/Game/ClientState/Party/PartyList.cs
new file mode 100644
index 000000000..8de1ad1ea
--- /dev/null
+++ b/Dalamud/Game/ClientState/Party/PartyList.cs
@@ -0,0 +1,183 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+using JetBrains.Annotations;
+using Serilog;
+
+namespace Dalamud.Game.ClientState.Party
+{
+ ///
+ /// This collection represents the actors present in your party or alliance.
+ ///
+ public sealed unsafe partial class PartyList
+ {
+ private const int GroupLength = 8;
+ private const int AllianceLength = 20;
+
+ private readonly Dalamud dalamud;
+ private readonly ClientStateAddressResolver address;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The instance.
+ /// Client state address resolver.
+ internal PartyList(Dalamud dalamud, ClientStateAddressResolver addressResolver)
+ {
+ this.dalamud = dalamud;
+ this.address = addressResolver;
+
+ Log.Verbose($"Group manager address 0x{this.address.GroupManager.ToInt64():X}");
+ }
+
+ ///
+ /// Gets the amount of party members the local player has.
+ ///
+ public int Length => this.GroupManagerStruct->MemberCount;
+
+ ///
+ /// Gets the index of the party leader.
+ ///
+ public uint PartyLeaderIndex => this.GroupManagerStruct->PartyLeaderIndex;
+
+ ///
+ /// Gets a value indicating whether this group is an alliance.
+ ///
+ public bool IsAlliance => this.GroupManagerStruct->IsAlliance;
+
+ ///
+ /// Gets the address of the Group Manager.
+ ///
+ public IntPtr GroupManagerAddress => this.address.GroupManager;
+
+ ///
+ /// Gets the address of the party list within the group manager.
+ ///
+ public IntPtr GroupListAddress => (IntPtr)GroupManagerStruct->PartyMembers;
+
+ ///
+ /// Gets the address of the alliance member list within the group manager.
+ ///
+ public IntPtr AllianceListAddress => (IntPtr)this.GroupManagerStruct->AllianceMembers;
+
+ private static int PartyMemberSize { get; } = Marshal.SizeOf();
+
+ private FFXIVClientStructs.FFXIV.Client.Game.Group.GroupManager* GroupManagerStruct => (FFXIVClientStructs.FFXIV.Client.Game.Group.GroupManager*)this.GroupManagerAddress;
+
+ ///
+ /// Get a party member at the specified spawn index.
+ ///
+ /// Spawn index.
+ /// A at the specified spawn index.
+ [CanBeNull]
+ public PartyMember this[int index]
+ {
+ get
+ {
+ // Normally using Length results in a recursion crash, however we know the party size via ptr.
+ if (index < 0 || index >= this.Length)
+ return null;
+
+ if (this.Length > GroupLength)
+ {
+ var addr = this.GetAllianceMemberAddress(index);
+ return this.CreateAllianceMemberReference(addr);
+ }
+ else
+ {
+ var addr = this.GetPartyMemberAddress(index);
+ return this.CreatePartyMemberReference(addr);
+ }
+ }
+ }
+
+ ///
+ /// Gets the address of the party member at the specified index of the party list.
+ ///
+ /// The index of the party member.
+ /// The memory address of the party member.
+ public IntPtr GetPartyMemberAddress(int index)
+ {
+ if (index < 0 || index >= GroupLength)
+ return IntPtr.Zero;
+
+ return this.GroupListAddress + (index * PartyMemberSize);
+ }
+
+ ///
+ /// Create a reference to an FFXIV party member.
+ ///
+ /// The address of the party member in memory.
+ /// The party member object containing the requested data.
+ [CanBeNull]
+ public PartyMember CreatePartyMemberReference(IntPtr address)
+ {
+ if (this.dalamud.ClientState.LocalContentId == 0)
+ return null;
+
+ if (address == IntPtr.Zero)
+ return null;
+
+ return new PartyMember(address, this.dalamud);
+ }
+
+ ///
+ /// Gets the address of the alliance member at the specified index of the alliance list.
+ ///
+ /// The index of the alliance member.
+ /// The memory address of the alliance member.
+ public IntPtr GetAllianceMemberAddress(int index)
+ {
+ if (index < 0 || index >= AllianceLength)
+ return IntPtr.Zero;
+
+ return this.AllianceListAddress + (index * PartyMemberSize);
+ }
+
+ ///
+ /// Create a reference to an FFXIV alliance member.
+ ///
+ /// The address of the alliance member in memory.
+ /// The party member object containing the requested data.
+ [CanBeNull]
+ public PartyMember CreateAllianceMemberReference(IntPtr address)
+ {
+ if (this.dalamud.ClientState.LocalContentId == 0)
+ return null;
+
+ if (address == IntPtr.Zero)
+ return null;
+
+ return new PartyMember(address, this.dalamud);
+ }
+ }
+
+ ///
+ /// This collection represents the party members present in your party or alliance.
+ ///
+ public sealed partial class PartyList : IReadOnlyCollection
+ {
+ ///
+ int IReadOnlyCollection.Count => this.Length;
+
+ ///
+ public IEnumerator 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;
+ }
+ }
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
+ }
+}
diff --git a/Dalamud/Game/ClientState/Party/PartyMember.cs b/Dalamud/Game/ClientState/Party/PartyMember.cs
new file mode 100644
index 000000000..8cbd2dd84
--- /dev/null
+++ b/Dalamud/Game/ClientState/Party/PartyMember.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Numerics;
+
+using Dalamud.Game.ClientState.Objects.Types;
+using Dalamud.Game.ClientState.Resolvers;
+using Dalamud.Game.ClientState.Statuses;
+using Dalamud.Game.Text.SeStringHandling;
+using Dalamud.Memory;
+using JetBrains.Annotations;
+
+namespace Dalamud.Game.ClientState.Party
+{
+ ///
+ /// This class represents a party member in the group manager.
+ ///
+ public unsafe class PartyMember
+ {
+ private Dalamud dalamud;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Address of the party member.
+ /// Dalamud itself.
+ internal PartyMember(IntPtr address, Dalamud dalamud)
+ {
+ this.Address = address;
+ this.dalamud = dalamud;
+ }
+
+ ///
+ /// Gets the address of this party member in memory.
+ ///
+ public IntPtr Address { get; }
+
+ ///
+ /// Gets a list of buffs or debuffs applied to this party member.
+ ///
+ public StatusList Statuses => new(&this.Struct->StatusManager, this.dalamud);
+
+ ///
+ /// Gets the position of the party member.
+ ///
+ public Vector3 Position => new(this.Struct->X, this.Struct->Y, this.Struct->Z);
+
+ ///
+ /// Gets the content ID of the party member.
+ ///
+ public long ContentId => this.Struct->ContentID;
+
+ ///
+ /// Gets the actor ID of this party member.
+ ///
+ public uint ObjectId => this.Struct->ObjectID;
+
+ ///
+ /// Gets the actor associated with this buddy.
+ ///
+ ///
+ /// This iterates the actor table, it should be used with care.
+ ///
+ [CanBeNull]
+ public GameObject GameObject => this.dalamud.ClientState.Objects.SearchByID(this.ObjectId);
+
+ ///
+ /// Gets the current HP of this party member.
+ ///
+ public uint CurrentHP => this.Struct->CurrentHP;
+
+ ///
+ /// Gets the maximum HP of this party member.
+ ///
+ public uint MaxHP => this.Struct->MaxHP;
+
+ ///
+ /// Gets the current MP of this party member.
+ ///
+ public ushort CurrentMP => this.Struct->CurrentMP;
+
+ ///
+ /// Gets the maximum MP of this party member.
+ ///
+ public ushort MaxMP => this.Struct->MaxMP;
+
+ ///
+ /// Gets the territory this party member is located in.
+ ///
+ public ExcelResolver Territory => new(this.Struct->TerritoryType, this.dalamud);
+
+ ///
+ /// Gets the World this party member resides in.
+ ///
+ public ExcelResolver World => new(this.Struct->HomeWorld, this.dalamud);
+
+ ///
+ /// Gets the displayname of this party member.
+ ///
+ public SeString Name => MemoryHelper.ReadSeString((IntPtr)Struct->Name, 0x40);
+
+ ///
+ /// Gets the sex of this party member.
+ ///
+ public byte Sex => this.Struct->Sex;
+
+ ///
+ /// Gets the classjob of this party member.
+ ///
+ public ExcelResolver ClassJob => new(this.Struct->ClassJob, this.dalamud);
+
+ ///
+ /// Gets the level of this party member.
+ ///
+ public byte Level => this.Struct->Level;
+
+ private FFXIVClientStructs.FFXIV.Client.Game.Group.PartyMember* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Group.PartyMember*)this.Address;
+ }
+}
diff --git a/Dalamud/Game/ClientState/PartyList.cs b/Dalamud/Game/ClientState/PartyList.cs
deleted file mode 100644
index 2aa4b95ed..000000000
--- a/Dalamud/Game/ClientState/PartyList.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Runtime.InteropServices;
-
-using Dalamud.Game.ClientState.Actors.Types;
-// using Dalamud.Hooking;
-
-namespace Dalamud.Game.ClientState
-{
- ///
- /// This class represents the members of your party.
- ///
- public sealed partial class PartyList
- {
- private readonly Dalamud dalamud;
- private readonly ClientStateAddressResolver address;
-
- // private bool isReady = false;
- // private IntPtr partyListBegin;
- // private Hook partyListUpdateHook;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The Dalamud instance.
- /// The ClientStateAddressResolver instance.
- internal PartyList(Dalamud dalamud, ClientStateAddressResolver addressResolver)
- {
- this.address = addressResolver;
- this.dalamud = dalamud;
- // this.partyListUpdateHook = new Hook(Address.PartyListUpdate, new PartyListUpdateDelegate(PartyListUpdateDetour), this);
- }
-
- private delegate long PartyListUpdateDelegate(IntPtr structBegin, long param2, char param3);
-
- ///
- /// Gets the length of the PartyList.
- ///
- public int Length => 0; // !this.isReady ? 0 : Marshal.ReadByte(this.partyListBegin + 0xF0);
-
- ///
- /// Get the nth party member.
- ///
- /// Index of the party member.
- /// The party member.
- public PartyMember this[int index]
- {
- get
- {
- return null;
- // if (!this.isReady)
- // return null;
- // if (index >= this.Length)
- // return null;
- // var tblIndex = this.partyListBegin + (index * 24);
- // var memberStruct = Marshal.PtrToStructure(tblIndex);
- // return new PartyMember(this.dalamud.ClientState.Actors, memberStruct);
- }
- }
-
- ///
- /// Enable this module.
- ///
- public void Enable()
- {
- // TODO Fix for 5.3
- // this.partyListUpdateHook.Enable();
- }
-
- ///
- /// Dispose of managed and unmanaged resources.
- ///
- public void Dispose()
- {
- // if (!this.isReady)
- // this.partyListUpdateHook.Dispose();
- // this.isReady = false;
- }
-
- // private long PartyListUpdateDetour(IntPtr structBegin, long param2, char param3)
- // {
- // var result = this.partyListUpdateHook.Original(structBegin, param2, param3);
- // this.partyListBegin = structBegin + 0xB48;
- // this.partyListUpdateHook.Dispose();
- // this.isReady = true;
- // return result;
- // }
- }
-
- ///
- /// Implements IReadOnlyCollection, IEnumerable.
- ///
- public sealed partial class PartyList : IReadOnlyCollection
- {
- ///
- int IReadOnlyCollection.Count => this.Length;
-
- ///
- public IEnumerator GetEnumerator()
- {
- for (var i = 0; i < this.Length; i++)
- {
- if (this[i] != null)
- {
- yield return this[i];
- }
- }
- }
-
- ///
- IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
- }
-
- ///
- /// Implements ICollection.
- ///
- public sealed partial class PartyList : ICollection
- {
- ///
- public int Count => this.Length;
-
- ///
- public object SyncRoot => this;
-
- ///
- public bool IsSynchronized => false;
-
- ///
- public void CopyTo(Array array, int index)
- {
- for (var i = 0; i < this.Length; i++)
- {
- array.SetValue(this[i], index);
- index++;
- }
- }
- }
-}
diff --git a/Dalamud/Game/ClientState/Statuses/Status.cs b/Dalamud/Game/ClientState/Statuses/Status.cs
new file mode 100644
index 000000000..9570c79a9
--- /dev/null
+++ b/Dalamud/Game/ClientState/Statuses/Status.cs
@@ -0,0 +1,73 @@
+using System;
+
+using Dalamud.Game.ClientState.Objects.Types;
+using Dalamud.Game.ClientState.Resolvers;
+using JetBrains.Annotations;
+
+namespace Dalamud.Game.ClientState.Statuses
+{
+ ///
+ /// This class represents a status effect an actor is afflicted by.
+ ///
+ public unsafe class Status
+ {
+ private Dalamud dalamud;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Status address.
+ /// Dalamud instance.
+ internal Status(IntPtr address, Dalamud dalamud)
+ {
+ this.dalamud = dalamud;
+ this.Address = address;
+ }
+
+ ///
+ /// Gets the address of the status in memory.
+ ///
+ public IntPtr Address { get; }
+
+ ///
+ /// Gets the status ID of this status.
+ ///
+ public uint StatusID => this.Struct->StatusID;
+
+ ///
+ /// Gets the GameData associated with this status.
+ ///
+ public Lumina.Excel.GeneratedSheets.Status GameData => new ExcelResolver(this.Struct->StatusID, this.dalamud).GameData;
+
+ ///
+ /// Gets the parameter value of the status.
+ ///
+ public byte Param => this.Struct->Param;
+
+ ///
+ /// Gets the stack count of this status.
+ ///
+ public byte StackCount => this.Struct->StackCount;
+
+ ///
+ /// Gets the time remaining of this status.
+ ///
+ public float RemainingTime => this.Struct->RemainingTime;
+
+ ///
+ /// Gets the source ID of this status.
+ ///
+ public uint SourceID => this.Struct->SourceID;
+
+ ///
+ /// Gets the source actor associated with this status.
+ ///
+ ///
+ /// This iterates the actor table, it should be used with care.
+ ///
+ [CanBeNull]
+ public GameObject SourceActor => this.dalamud.ClientState.Objects.SearchByID(this.SourceID);
+
+ private FFXIVClientStructs.FFXIV.Client.Game.Status* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Status*)this.Address;
+ }
+}
diff --git a/Dalamud/Game/ClientState/Statuses/StatusList.cs b/Dalamud/Game/ClientState/Statuses/StatusList.cs
new file mode 100644
index 000000000..a617d900d
--- /dev/null
+++ b/Dalamud/Game/ClientState/Statuses/StatusList.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+using JetBrains.Annotations;
+
+namespace Dalamud.Game.ClientState.Statuses
+{
+ ///
+ /// This collection represents the status effects an actor is afflicted by.
+ ///
+ public sealed unsafe partial class StatusList
+ {
+ private const int StatusListLength = 30;
+
+ private readonly Dalamud dalamud;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Address of the status list.
+ /// The instance.
+ internal StatusList(IntPtr address, Dalamud dalamud)
+ {
+ this.Address = address;
+ this.dalamud = dalamud;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Pointer to the status list.
+ /// The instance.
+ internal unsafe StatusList(void* pointer, Dalamud dalamud)
+ : this((IntPtr)pointer, dalamud)
+ {
+ }
+
+ ///
+ /// Gets the address of the status list in memory.
+ ///
+ public IntPtr Address { get; }
+
+ ///
+ /// Gets the amount of status effects the actor has.
+ ///
+ public int Length
+ {
+ get
+ {
+ var i = 0;
+ for (; i < StatusListLength; i++)
+ {
+ var status = this[i];
+ if (status == null || status.StatusID == 0)
+ break;
+ }
+
+ return i;
+ }
+ }
+
+ private static int StatusSize { get; } = Marshal.SizeOf();
+
+ private FFXIVClientStructs.FFXIV.Client.Game.StatusManager* Struct => (FFXIVClientStructs.FFXIV.Client.Game.StatusManager*)this.Address;
+
+ ///
+ /// Get a status effect at the specified index.
+ ///
+ /// Status Index.
+ /// The status at the specified index.
+ [CanBeNull]
+ public Status this[int index]
+ {
+ get
+ {
+ if (index < 0 || index > StatusListLength)
+ return null;
+
+ var addr = this.GetStatusAddress(index);
+ return this.CreateStatusReference(addr);
+ }
+ }
+
+ ///
+ /// Gets the address of the party member at the specified index of the party list.
+ ///
+ /// The index of the party member.
+ /// The memory address of the party member.
+ public IntPtr GetStatusAddress(int index)
+ {
+ if (index < 0 || index >= StatusListLength)
+ return IntPtr.Zero;
+
+ return (IntPtr)(this.Struct->Status + (index * StatusSize));
+ }
+
+ ///
+ /// Create a reference to an FFXIV actor status.
+ ///
+ /// The address of the status effect in memory.
+ /// The status object containing the requested data.
+ [CanBeNull]
+ public Status CreateStatusReference(IntPtr address)
+ {
+ if (this.dalamud.ClientState.LocalContentId == 0)
+ return null;
+
+ if (address == IntPtr.Zero)
+ return null;
+
+ return new Status(address, this.dalamud);
+ }
+ }
+
+ ///
+ /// This collection represents the status effects an actor is afflicted by.
+ ///
+ public sealed partial class StatusList : IReadOnlyCollection, ICollection
+ {
+ ///
+ int IReadOnlyCollection.Count => this.Length;
+
+ ///
+ int ICollection.Count => this.Length;
+
+ ///
+ bool ICollection.IsSynchronized => false;
+
+ ///
+ object ICollection.SyncRoot => this;
+
+ ///
+ public IEnumerator GetEnumerator()
+ {
+ for (var i = 0; i < StatusListLength; i++)
+ {
+ var status = this[i];
+
+ if (status == null || status.StatusID == 0)
+ continue;
+
+ yield return status;
+ }
+ }
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
+
+ ///
+ void ICollection.CopyTo(Array array, int index)
+ {
+ for (var i = 0; i < this.Length; i++)
+ {
+ array.SetValue(this[i], index);
+ index++;
+ }
+ }
+ }
+}
diff --git a/Dalamud/Game/ClientState/Structs/PartyMember.cs b/Dalamud/Game/ClientState/Structs/PartyMember.cs
deleted file mode 100644
index 926730e54..000000000
--- a/Dalamud/Game/ClientState/Structs/PartyMember.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-using Dalamud.Game.ClientState.Actors.Types;
-
-namespace Dalamud.Game.ClientState.Structs
-{
- ///
- /// This represents a native PartyMember class in memory.
- ///
- [StructLayout(LayoutKind.Explicit)]
- public struct PartyMember
- {
- [FieldOffset(0x0)]
- public IntPtr namePtr;
-
- [FieldOffset(0x8)]
- public long unknown;
-
- [FieldOffset(0x10)]
- public int actorId;
-
- [FieldOffset(0x14)]
- public ObjectKind objectKind;
- }
-}
diff --git a/Dalamud/Interface/Internal/Windows/DataWindow.cs b/Dalamud/Interface/Internal/Windows/DataWindow.cs
index 96473d879..96c5f11e3 100644
--- a/Dalamud/Interface/Internal/Windows/DataWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/DataWindow.cs
@@ -5,13 +5,12 @@ using System.Linq;
using System.Numerics;
using Dalamud.Game;
-using Dalamud.Game.ClientState;
-using Dalamud.Game.ClientState.Actors.Types;
-using Dalamud.Game.ClientState.Actors.Types.NonPlayer;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.GamePad;
using Dalamud.Game.ClientState.JobGauge.Enums;
using Dalamud.Game.ClientState.JobGauge.Types;
+using Dalamud.Game.ClientState.Objects.SubKinds;
+using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Gui.Addons;
using Dalamud.Game.Gui.Toast;
using Dalamud.Game.Text;
@@ -37,8 +36,8 @@ namespace Dalamud.Interface.Internal.Windows
private string serverOpString;
private DataKind currentKind;
- private bool drawActors = false;
- private float maxActorDrawDistance = 20;
+ private bool drawCharas = false;
+ private float maxCharaDrawDistance = 20;
private string inputSig = string.Empty;
private IntPtr sigResult = IntPtr.Zero;
@@ -50,6 +49,7 @@ namespace Dalamud.Interface.Internal.Windows
private IntPtr findAgentInterfacePtr;
private bool resolveGameData = false;
+ private bool resolveObjects = false;
private UIDebug addonInspector = null;
@@ -89,10 +89,11 @@ namespace Dalamud.Interface.Internal.Windows
{
Server_OpCode,
Address,
- Actor_Table,
+ Object_Table,
Fate_Table,
Font_Test,
Party_List,
+ Buddy_List,
Plugin_IPC,
Condition,
Gauge,
@@ -127,18 +128,23 @@ namespace Dalamud.Interface.Internal.Windows
if (string.IsNullOrEmpty(dataKind))
return;
- if (dataKind == "ai")
- dataKind = "Addon Inspector";
+ dataKind = dataKind switch
+ {
+ "ai" => "Addon Inspector",
+ "at" => "Object Table", // Actor Table
+ "ot" => "Object Table",
+ _ => dataKind,
+ };
dataKind = dataKind.Replace(" ", string.Empty).ToLower();
- var dataKinds = Enum.GetValues(typeof(DataKind))
+ var matched = Enum.GetValues(typeof(DataKind))
.Cast()
- .Where(k => nameof(k).Replace("_", string.Empty).ToLower() == dataKind)
- .ToList();
+ .Where(k => Enum.GetName(typeof(DataKind), k).Replace("_", string.Empty).ToLower() == dataKind)
+ .FirstOrDefault();
- if (dataKinds.Count > 0)
+ if (matched != default)
{
- this.currentKind = dataKinds.First();
+ this.currentKind = matched;
}
else
{
@@ -189,8 +195,8 @@ namespace Dalamud.Interface.Internal.Windows
this.DrawAddress();
break;
- case DataKind.Actor_Table:
- this.DrawActorTable();
+ case DataKind.Object_Table:
+ this.DrawObjectTable();
break;
case DataKind.Fate_Table:
@@ -205,6 +211,10 @@ namespace Dalamud.Interface.Internal.Windows
this.DrawPartyList();
break;
+ case DataKind.Buddy_List:
+ this.DrawBuddyList();
+ break;
+
case DataKind.Plugin_IPC:
this.DrawPluginIPC();
break;
@@ -309,24 +319,18 @@ namespace Dalamud.Interface.Internal.Windows
}
}
- private void DrawActorTable()
+ private void DrawObjectTable()
{
var stateString = string.Empty;
- // LocalPlayer is null in a number of situations (at least with the current visible-actors list)
- // which would crash here.
- if (this.dalamud.ClientState.Actors.Length == 0)
- {
- ImGui.TextUnformatted("Data not ready.");
- }
- else if (this.dalamud.ClientState.LocalPlayer == null)
+ if (this.dalamud.ClientState.LocalPlayer == null)
{
ImGui.TextUnformatted("LocalPlayer null.");
}
else
{
stateString += $"FrameworkBase: {this.dalamud.Framework.Address.BaseAddress.ToInt64():X}\n";
- stateString += $"ActorTableLen: {this.dalamud.ClientState.Actors.Length}\n";
+ stateString += $"ObjectTableLen: {this.dalamud.ClientState.Objects.Length}\n";
stateString += $"LocalPlayerName: {this.dalamud.ClientState.LocalPlayer.Name}\n";
stateString += $"CurrentWorldName: {(this.resolveGameData ? this.dalamud.ClientState.LocalPlayer.CurrentWorld.GameData.Name : this.dalamud.ClientState.LocalPlayer.CurrentWorld.Id.ToString())}\n";
stateString += $"HomeWorldName: {(this.resolveGameData ? this.dalamud.ClientState.LocalPlayer.HomeWorld.GameData.Name : this.dalamud.ClientState.LocalPlayer.HomeWorld.Id.ToString())}\n";
@@ -336,29 +340,29 @@ namespace Dalamud.Interface.Internal.Windows
ImGui.TextUnformatted(stateString);
- ImGui.Checkbox("Draw actors on screen", ref this.drawActors);
- ImGui.SliderFloat("Draw Distance", ref this.maxActorDrawDistance, 2f, 40f);
+ ImGui.Checkbox("Draw characters on screen", ref this.drawCharas);
+ ImGui.SliderFloat("Draw Distance", ref this.maxCharaDrawDistance, 2f, 40f);
- for (var i = 0; i < this.dalamud.ClientState.Actors.Length; i++)
+ for (var i = 0; i < this.dalamud.ClientState.Objects.Length; i++)
{
- var actor = this.dalamud.ClientState.Actors[i];
+ var obj = this.dalamud.ClientState.Objects[i];
- if (actor == null)
+ if (obj == null)
continue;
- this.PrintActor(actor, i.ToString());
+ this.PrintGameObject(obj, i.ToString());
- if (this.drawActors && this.dalamud.Framework.Gui.WorldToScreen(actor.Position, out var screenCoords))
+ if (this.drawCharas && this.dalamud.Framework.Gui.WorldToScreen(obj.Position, out var screenCoords))
{
// So, while WorldToScreen will return false if the point is off of game client screen, to
// to avoid performance issues, we have to manually determine if creating a window would
// produce a new viewport, and skip rendering it if so
- var actorText = $"{actor.Address.ToInt64():X}:{actor.ActorId:X}[{i}] - {actor.ObjectKind} - {actor.Name}";
+ var objectText = $"{obj.Address.ToInt64():X}:{obj.ObjectId:X}[{i}] - {obj.ObjectKind} - {obj.Name}";
var screenPos = ImGui.GetMainViewport().Pos;
var screenSize = ImGui.GetMainViewport().Size;
- var windowSize = ImGui.CalcTextSize(actorText);
+ var windowSize = ImGui.CalcTextSize(objectText);
// Add some extra safety padding
windowSize.X += ImGui.GetStyle().WindowPadding.X + 10;
@@ -368,12 +372,12 @@ namespace Dalamud.Interface.Internal.Windows
screenCoords.Y + windowSize.Y > screenPos.Y + screenSize.Y)
continue;
- if (actor.YalmDistanceX > this.maxActorDrawDistance)
+ if (obj.YalmDistanceX > this.maxCharaDrawDistance)
continue;
ImGui.SetNextWindowPos(new Vector2(screenCoords.X, screenCoords.Y));
- ImGui.SetNextWindowBgAlpha(Math.Max(1f - (actor.YalmDistanceX / this.maxActorDrawDistance), 0.2f));
+ ImGui.SetNextWindowBgAlpha(Math.Max(1f - (obj.YalmDistanceX / this.maxCharaDrawDistance), 0.2f));
if (ImGui.Begin(
$"Actor{i}##ActorWindow{i}",
ImGuiWindowFlags.NoDecoration |
@@ -384,7 +388,7 @@ namespace Dalamud.Interface.Internal.Windows
ImGuiWindowFlags.NoDocking |
ImGuiWindowFlags.NoFocusOnAppearing |
ImGuiWindowFlags.NoNav))
- ImGui.Text(actorText);
+ ImGui.Text(objectText);
ImGui.End();
}
}
@@ -453,30 +457,118 @@ namespace Dalamud.Interface.Internal.Windows
private void DrawPartyList()
{
- var partyString = string.Empty;
+ ImGui.Checkbox("Resolve Actors", ref this.resolveObjects);
- if (this.dalamud.ClientState.PartyList.Length == 0)
+ ImGui.Text($"GroupManager: {this.dalamud.ClientState.PartyList.GroupManagerAddress.ToInt64():X}");
+ ImGui.Text($"GroupList: {this.dalamud.ClientState.PartyList.GroupListAddress.ToInt64():X}");
+ ImGui.Text($"AllianceList: {this.dalamud.ClientState.PartyList.AllianceListAddress.ToInt64():X}");
+
+ ImGui.Text($"{this.dalamud.ClientState.PartyList.Length} Members");
+
+ for (var i = 0; i < this.dalamud.ClientState.PartyList.Length; i++)
{
- ImGui.TextUnformatted("Data not ready.");
- }
- else
- {
- partyString += $"{this.dalamud.ClientState.PartyList.Count} Members\n";
- for (var i = 0; i < this.dalamud.ClientState.PartyList.Count; i++)
+ var member = this.dalamud.ClientState.PartyList[i];
+ if (member == null)
{
- var member = this.dalamud.ClientState.PartyList[i];
- if (member == null)
- {
- partyString +=
- $"[{i}] was null\n";
- continue;
- }
-
- partyString +=
- $"[{i}] {member.CharacterName} - {member.ObjectKind} - {member.Actor.ActorId}\n";
+ ImGui.Text($"[{i}] was null");
+ continue;
}
- ImGui.TextUnformatted(partyString);
+ ImGui.Text($"[{i}] {member.Address.ToInt64():X} - {member.Name} - {member.GameObject.ObjectId}");
+ if (this.resolveObjects)
+ {
+ var actor = member.GameObject;
+ if (actor == null)
+ {
+ ImGui.Text("Actor was null");
+ }
+ else
+ {
+ this.PrintGameObject(actor, "-");
+ }
+ }
+ }
+ }
+
+ private void DrawBuddyList()
+ {
+ ImGui.Checkbox("Resolve Actors", ref this.resolveObjects);
+
+ ImGui.Text($"BuddyList: {this.dalamud.ClientState.BuddyList.BuddyListAddress.ToInt64():X}");
+ {
+ var member = this.dalamud.ClientState.BuddyList.CompanionBuddy;
+ if (member == null)
+ {
+ ImGui.Text("[Companion] null");
+ }
+ else
+ {
+ ImGui.Text($"[Companion] {member.Address.ToInt64():X} - {member.ObjectId} - {member.DataID}");
+ if (this.resolveObjects)
+ {
+ var actor = member.Actor;
+ if (actor == null)
+ {
+ ImGui.Text("Actor was null");
+ }
+ else
+ {
+ this.PrintGameObject(actor, "-");
+ }
+ }
+ }
+ }
+
+ {
+ var member = this.dalamud.ClientState.BuddyList.PetBuddy;
+ if (member == null)
+ {
+ ImGui.Text("[Pet] null");
+ }
+ else
+ {
+ ImGui.Text($"[Pet] {member.Address.ToInt64():X} - {member.ObjectId} - {member.DataID}");
+ if (this.resolveObjects)
+ {
+ var actor = member.Actor;
+ if (actor == null)
+ {
+ ImGui.Text("Actor was null");
+ }
+ else
+ {
+ this.PrintGameObject(actor, "-");
+ }
+ }
+ }
+ }
+
+ {
+ var count = this.dalamud.ClientState.BuddyList.Length;
+ if (count == 0)
+ {
+ ImGui.Text("[BattleBuddy] None present");
+ }
+ else
+ {
+ for (var i = 0; i < count; i++)
+ {
+ var member = this.dalamud.ClientState.BuddyList[i];
+ ImGui.Text($"[BattleBuddy] [{i}] {member.Address.ToInt64():X} - {member.ObjectId} - {member.DataID}");
+ if (this.resolveObjects)
+ {
+ var actor = member.Actor;
+ if (actor == null)
+ {
+ ImGui.Text("Actor was null");
+ }
+ else
+ {
+ this.PrintGameObject(actor, "-");
+ }
+ }
+ }
+ }
}
}
@@ -783,26 +875,26 @@ namespace Dalamud.Interface.Internal.Windows
{
var targetMgr = this.dalamud.ClientState.Targets;
- if (targetMgr.CurrentTarget != null)
+ if (targetMgr.Target != null)
{
- this.PrintActor(targetMgr.CurrentTarget, "CurrentTarget");
- Util.ShowObject(targetMgr.CurrentTarget);
+ this.PrintGameObject(targetMgr.Target, "CurrentTarget");
+ Util.ShowObject(targetMgr.Target);
}
if (targetMgr.FocusTarget != null)
- this.PrintActor(targetMgr.FocusTarget, "FocusTarget");
+ this.PrintGameObject(targetMgr.FocusTarget, "FocusTarget");
if (targetMgr.MouseOverTarget != null)
- this.PrintActor(targetMgr.MouseOverTarget, "MouseOverTarget");
+ this.PrintGameObject(targetMgr.MouseOverTarget, "MouseOverTarget");
if (targetMgr.PreviousTarget != null)
- this.PrintActor(targetMgr.PreviousTarget, "PreviousTarget");
+ this.PrintGameObject(targetMgr.PreviousTarget, "PreviousTarget");
if (targetMgr.SoftTarget != null)
- this.PrintActor(targetMgr.SoftTarget, "SoftTarget");
+ this.PrintGameObject(targetMgr.SoftTarget, "SoftTarget");
if (ImGui.Button("Clear CT"))
- targetMgr.ClearCurrentTarget();
+ targetMgr.ClearTarget();
if (ImGui.Button("Clear FT"))
targetMgr.ClearFocusTarget();
@@ -812,7 +904,7 @@ namespace Dalamud.Interface.Internal.Windows
if (localPlayer != null)
{
if (ImGui.Button("Set CT"))
- targetMgr.SetCurrentTarget(localPlayer);
+ targetMgr.SetTarget(localPlayer);
if (ImGui.Button("Set FT"))
targetMgr.SetFocusTarget(localPlayer);
@@ -924,9 +1016,10 @@ namespace Dalamud.Interface.Internal.Windows
$"L3 {resolve(GamepadButtons.L3)} " +
$"R3 {resolve(GamepadButtons.R3)} ");
}
-#if DEBUG
+
ImGui.Text($"GamepadInput 0x{this.dalamud.ClientState.GamepadState.GamepadInputAddress.ToInt64():X}");
+#if DEBUG
if (ImGui.IsItemHovered())
ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
@@ -969,15 +1062,15 @@ namespace Dalamud.Interface.Internal.Windows
}
}
- private void PrintActor(Actor actor, string tag)
+ private void PrintGameObject(GameObject actor, string tag)
{
var actorString =
- $"{actor.Address.ToInt64():X}:{actor.ActorId:X}[{tag}] - {actor.ObjectKind} - {actor.Name} - X{actor.Position.X} Y{actor.Position.Y} Z{actor.Position.Z} D{actor.YalmDistanceX} R{actor.Rotation} - Target: {actor.TargetActorID:X}\n";
+ $"{actor.Address.ToInt64():X}:{actor.ObjectId:X}[{tag}] - {actor.ObjectKind} - {actor.Name} - X{actor.Position.X} Y{actor.Position.Y} Z{actor.Position.Z} D{actor.YalmDistanceX} R{actor.Rotation} - Target: {actor.TargetObjectId:X}\n";
if (actor is Npc npc)
- actorString += $" DataId: {npc.BaseId} NameId:{npc.NameId}\n";
+ actorString += $" DataId: {npc.DataId} NameId:{npc.NameId}\n";
- if (actor is Chara chara)
+ if (actor is Character chara)
{
actorString +=
$" Level: {chara.Level} ClassJob: {(this.resolveGameData ? chara.ClassJob.GameData.Name : chara.ClassJob.Id.ToString())} CHP: {chara.CurrentHp} MHP: {chara.MaxHp} CMP: {chara.CurrentMp} MMP: {chara.MaxMp}\n Customize: {BitConverter.ToString(chara.Customize).Replace("-", " ")} StatusFlags: {chara.StatusFlags}\n";
diff --git a/Dalamud/Interface/UiBuilder.cs b/Dalamud/Interface/UiBuilder.cs
index 71ce244f7..adf404978 100644
--- a/Dalamud/Interface/UiBuilder.cs
+++ b/Dalamud/Interface/UiBuilder.cs
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
-using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Interface.Internal;
using ImGuiNET;