mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Actors and objects
This commit is contained in:
parent
a7d9673bed
commit
3a29603def
32 changed files with 1700 additions and 999 deletions
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This collection represents the currently spawned FFXIV actors.
|
||||
/// </summary>
|
||||
public sealed partial class ActorTable
|
||||
{
|
||||
private const int ActorTableLength = 424;
|
||||
|
||||
private readonly Dalamud dalamud;
|
||||
private readonly ClientStateAddressResolver address;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ActorTable"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">The <see cref="dalamud"/> instance.</param>
|
||||
/// <param name="addressResolver">Client state address resolver.</param>
|
||||
internal ActorTable(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.address = addressResolver;
|
||||
|
||||
Log.Verbose($"Actor table address 0x{this.address.ActorTable.ToInt64():X}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of currently spawned actors.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an actor at the specified spawn index.
|
||||
/// </summary>
|
||||
/// <param name="index">Spawn index.</param>
|
||||
/// <returns>An <see cref="Actor"/> at the specified spawn index.</returns>
|
||||
[CanBeNull]
|
||||
public Actor this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
var address = this.GetActorAddress(index);
|
||||
return this.CreateActorReference(address);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the actor at the specified index of the actor table.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the actor.</param>
|
||||
/// <returns>The memory address of the actor.</returns>
|
||||
public unsafe IntPtr GetActorAddress(int index)
|
||||
{
|
||||
if (index >= ActorTableLength)
|
||||
return IntPtr.Zero;
|
||||
|
||||
return *(IntPtr*)(this.address.ActorTable + (8 * index));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a reference to a FFXIV actor.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of the actor in memory.</param>
|
||||
/// <returns><see cref="Actor"/> object or inheritor containing requested data.</returns>
|
||||
[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),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This collection represents the currently spawned FFXIV actors.
|
||||
/// </summary>
|
||||
public sealed partial class ActorTable : IReadOnlyCollection<Actor>, ICollection
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
int IReadOnlyCollection<Actor>.Count => this.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
int ICollection.Count => this.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool ICollection.IsSynchronized => false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
object ICollection.SyncRoot => this;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<Actor> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < ActorTableLength; i++)
|
||||
{
|
||||
yield return this[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
||||
|
||||
/// <inheritdoc/>
|
||||
void ICollection.CopyTo(Array array, int index)
|
||||
{
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
array.SetValue(this[i], index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Dalamud.Game.ClientState.Actors.Types;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Actors
|
||||
{
|
||||
/// <summary>
|
||||
/// Get and set various kinds of targets for the player.
|
||||
/// </summary>
|
||||
public sealed class Targets
|
||||
{
|
||||
private readonly Dalamud dalamud;
|
||||
private readonly ClientStateAddressResolver address;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Targets"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
/// <param name="addressResolver">The ClientStateAddressResolver instance.</param>
|
||||
internal Targets(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.address = addressResolver;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current target.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public Actor CurrentTarget => this.GetActorByOffset(TargetOffsets.CurrentTarget);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mouseover target.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public Actor MouseOverTarget => this.GetActorByOffset(TargetOffsets.MouseOverTarget);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the focus target.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public Actor FocusTarget => this.GetActorByOffset(TargetOffsets.FocusTarget);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the previous target.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public Actor PreviousTarget => this.GetActorByOffset(TargetOffsets.PreviousTarget);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the soft target.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public Actor SoftTarget => this.GetActorByOffset(TargetOffsets.SoftTarget);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to target.</param>
|
||||
public void SetCurrentTarget(Actor actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero, TargetOffsets.CurrentTarget);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to target.</param>
|
||||
public void SetCurrentTarget(IntPtr actorAddress) => this.SetTarget(actorAddress, TargetOffsets.CurrentTarget);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the focus target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to focus.</param>
|
||||
public void SetFocusTarget(Actor actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero, TargetOffsets.FocusTarget);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the focus target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to focus.</param>
|
||||
public void SetFocusTarget(IntPtr actorAddress) => this.SetTarget(actorAddress, TargetOffsets.FocusTarget);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the current target.
|
||||
/// </summary>
|
||||
public void ClearCurrentTarget() => this.SetCurrentTarget(IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the focus target.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Memory offsets for the <see cref="Targets"/> type.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents a basic actor (GameObject) in FFXIV.
|
||||
/// </summary>
|
||||
public unsafe partial class Actor : IEquatable<Actor>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Actor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of this actor in memory.</param>
|
||||
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
|
||||
internal Actor(IntPtr address, Dalamud dalamud)
|
||||
{
|
||||
this.Dalamud = dalamud;
|
||||
this.Address = address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the actor in memory.
|
||||
/// </summary>
|
||||
public IntPtr Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets Dalamud itself.
|
||||
/// </summary>
|
||||
private protected Dalamud Dalamud { get; }
|
||||
|
||||
/// <summary>
|
||||
/// This allows you to <c>if (actor) {...}</c> to check for validity.
|
||||
/// </summary>
|
||||
/// <param name="actor">The actor to check.</param>
|
||||
/// <returns>True or false.</returns>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this actor is still valid in memory.
|
||||
/// </summary>
|
||||
/// <param name="actor">The actor to check.</param>
|
||||
/// <returns>True or false.</returns>
|
||||
public static bool IsValid(Actor actor)
|
||||
{
|
||||
if (actor == null)
|
||||
return false;
|
||||
|
||||
if (actor.Dalamud.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);
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool IEquatable<Actor>.Equals(Actor other) => this.ActorId == other?.ActorId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj) => ((IEquatable<Actor>)this).Equals(obj as Actor);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode() => this.ActorId.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class represents a basic actor (GameObject) in FFXIV.
|
||||
/// </summary>
|
||||
public unsafe partial class Actor
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the displayname of this <see cref="Actor" />.
|
||||
/// </summary>
|
||||
public SeString Name => MemoryHelper.ReadSeString(this.Address + ActorOffsets.Name, 32);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actor ID of this <see cref="Actor" />.
|
||||
/// </summary>
|
||||
public uint ActorId => *(uint*)(this.Address + ActorOffsets.ActorId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data ID for linking to other respective game data.
|
||||
/// </summary>
|
||||
public uint DataId => *(uint*)(this.Address + ActorOffsets.DataId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ID of this GameObject's owner.
|
||||
/// </summary>
|
||||
public uint OwnerId => *(uint*)(this.Address + ActorOffsets.OwnerId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity kind of this <see cref="Actor" />.
|
||||
/// See <see cref="ObjectKind">the ObjectKind enum</see> for possible values.
|
||||
/// </summary>
|
||||
public ObjectKind ObjectKind => *(ObjectKind*)(this.Address + ActorOffsets.ObjectKind);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sub kind of this Actor.
|
||||
/// </summary>
|
||||
public byte SubKind => *(byte*)(this.Address + ActorOffsets.SubKind);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the actor is friendly.
|
||||
/// </summary>
|
||||
public bool IsFriendly => *(int*)(this.Address + ActorOffsets.IsFriendly) > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the X distance from the local player in yalms.
|
||||
/// </summary>
|
||||
public byte YalmDistanceX => *(byte*)(this.Address + ActorOffsets.YalmDistanceFromObjectX);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target status.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is some kind of enum. It may be <see cref="StatusEffect"/>.
|
||||
/// </remarks>
|
||||
public byte TargetStatus => *(byte*)(this.Address + ActorOffsets.TargetStatus);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Y distance from the local player in yalms.
|
||||
/// </summary>
|
||||
public byte YalmDistanceY => *(byte*)(this.Address + ActorOffsets.YalmDistanceFromObjectY);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position of this <see cref="Actor" />.
|
||||
/// </summary>
|
||||
public Position3 Position => *(Position3*)(this.Address + ActorOffsets.Position);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rotation of this <see cref="Actor" />.
|
||||
/// This ranges from -pi to pi radians.
|
||||
/// </summary>
|
||||
public float Rotation => *(float*)(this.Address + ActorOffsets.Rotation);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hitbox radius of this <see cref="Actor" />.
|
||||
/// </summary>
|
||||
public float HitboxRadius => *(float*)(this.Address + ActorOffsets.HitboxRadius);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current target of the Actor.
|
||||
/// </summary>
|
||||
public virtual uint TargetActorID => 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Actors.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Memory offsets for the <see cref="Actor"/> type and all that inherit from it.
|
||||
/// </summary>
|
||||
[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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents the base for non-static entities.
|
||||
/// </summary>
|
||||
public unsafe class Chara : Actor
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Chara"/> class.
|
||||
/// This represents a non-static entity.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of this actor in memory.</param>
|
||||
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
|
||||
internal Chara(IntPtr address, Dalamud dalamud)
|
||||
: base(address, dalamud)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current HP of this Chara.
|
||||
/// </summary>
|
||||
public uint CurrentHp => *(uint*)(this.Address + ActorOffsets.CurrentHp);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum HP of this Chara.
|
||||
/// </summary>
|
||||
public uint MaxHp => *(uint*)(this.Address + ActorOffsets.MaxHp);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current MP of this Chara.
|
||||
/// </summary>
|
||||
public uint CurrentMp => *(uint*)(this.Address + ActorOffsets.CurrentMp);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum MP of this Chara.
|
||||
/// </summary>
|
||||
public uint MaxMp => *(uint*)(this.Address + ActorOffsets.MaxMp);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current GP of this Chara.
|
||||
/// </summary>
|
||||
public uint CurrentGp => *(uint*)(this.Address + ActorOffsets.CurrentGp);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum GP of this Chara.
|
||||
/// </summary>
|
||||
public uint MaxGp => *(uint*)(this.Address + ActorOffsets.MaxGp);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current CP of this Chara.
|
||||
/// </summary>
|
||||
public uint CurrentCp => *(uint*)(this.Address + ActorOffsets.CurrentCp);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum CP of this Chara.
|
||||
/// </summary>
|
||||
public uint MaxCp => *(uint*)(this.Address + ActorOffsets.MaxCp);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ClassJob of this Chara.
|
||||
/// </summary>
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.ClassJob> ClassJob => new(*(byte*)(this.Address + ActorOffsets.ClassJob), this.Dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the level of this Chara.
|
||||
/// </summary>
|
||||
public byte Level => *(byte*)(this.Address + ActorOffsets.Level);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a byte array describing the visual appearance of this Chara.
|
||||
/// Indexed by <see cref="CustomizeIndex"/>.
|
||||
/// </summary>
|
||||
public byte[] Customize => MemoryHelper.Read<byte>(this.Address + ActorOffsets.Customize, 28);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the status flags.
|
||||
/// </summary>
|
||||
public StatusFlags StatusFlags => *(StatusFlags*)(this.Address + ActorOffsets.StatusFlags);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current status effects.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This copies every time it is invoked, so make sure to only grab it once.
|
||||
/// </remarks>
|
||||
public StatusEffect[] StatusEffects => MemoryHelper.Read<StatusEffect>(this.Address + ActorOffsets.UIStatusEffects, 30, true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the actor is currently casting.
|
||||
/// </summary>
|
||||
public bool IsCasting => *(int*)(this.Address + ActorOffsets.IsCasting) > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the actor is currently casting (again?).
|
||||
/// </summary>
|
||||
public bool IsCasting2 => *(int*)(this.Address + ActorOffsets.IsCasting2) > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the spell action ID currently being cast by the actor.
|
||||
/// </summary>
|
||||
public uint CurrentCastSpellActionId => *(uint*)(this.Address + ActorOffsets.CurrentCastSpellActionId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actor ID of the target currently being cast at by the actor.
|
||||
/// </summary>
|
||||
public uint CurrentCastTargetActorId => *(uint*)(this.Address + ActorOffsets.CurrentCastTargetActorId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current casting time of the spell being cast by the actor.
|
||||
/// </summary>
|
||||
public float CurrentCastTime => *(float*)(this.Address + ActorOffsets.CurrentCastTime);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total casting time of the spell being cast by the actor.
|
||||
/// </summary>
|
||||
public float TotalCastTime => *(float*)(this.Address + ActorOffsets.TotalCastTime);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents an EventObj.
|
||||
/// </summary>
|
||||
public unsafe class EventObj : Actor
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EventObj"/> class.
|
||||
/// Set up a new EventObj with the provided memory representation.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of this actor in memory.</param>
|
||||
/// <param name="dalamud">A dalamud reference needed to access game data in Resolvers.</param>
|
||||
internal EventObj(IntPtr address, Dalamud dalamud)
|
||||
: base(address, dalamud)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the event object ID of the linking to their respective game data.
|
||||
/// </summary>
|
||||
public uint EventObjectId => *(uint*)(this.Address + ActorOffsets.DataId);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Memory;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Actors.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents a party member.
|
||||
/// </summary>
|
||||
public class PartyMember
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PartyMember"/> class.
|
||||
/// </summary>
|
||||
/// <param name="table">The ActorTable instance.</param>
|
||||
/// <param name="rawData">The interop data struct.</param>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the character.
|
||||
/// </summary>
|
||||
public SeString CharacterName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets something unknown.
|
||||
/// </summary>
|
||||
public long Unknown { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actor object that corresponds to this party member.
|
||||
/// </summary>
|
||||
public Actor Actor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the kind or type of actor.
|
||||
/// </summary>
|
||||
public ObjectKind ObjectKind { get; }
|
||||
}
|
||||
}
|
||||
188
Dalamud/Game/ClientState/Buddy/BuddyList.cs
Normal file
188
Dalamud/Game/ClientState/Buddy/BuddyList.cs
Normal file
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This collection represents the buddies present in your squadron or trust party.
|
||||
/// It does not include the local player.
|
||||
/// </summary>
|
||||
public sealed partial class BuddyList
|
||||
{
|
||||
private const uint InvalidObjectID = 0xE0000000;
|
||||
|
||||
private readonly Dalamud dalamud;
|
||||
private readonly ClientStateAddressResolver address;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BuddyList"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">The <see cref="dalamud"/> instance.</param>
|
||||
/// <param name="addressResolver">Client state address resolver.</param>
|
||||
internal BuddyList(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.address = addressResolver;
|
||||
|
||||
Log.Verbose($"Buddy list address 0x{this.address.BuddyList.ToInt64():X}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of battle buddies the local player has.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the local player's companion is present.
|
||||
/// </summary>
|
||||
public bool CompanionBuddyPresent => this.CompanionBuddy != null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the local player's pet is present.
|
||||
/// </summary>
|
||||
public bool PetBuddyPresent => this.PetBuddy != null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the active companion buddy.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public BuddyMember CompanionBuddy
|
||||
{
|
||||
get
|
||||
{
|
||||
var addr = this.GetCompanionBuddyMemberAddress();
|
||||
return this.CreateBuddyMemberReference(addr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the active pet buddy.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public BuddyMember PetBuddy
|
||||
{
|
||||
get
|
||||
{
|
||||
var addr = this.GetPetBuddyMemberAddress();
|
||||
return this.CreateBuddyMemberReference(addr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the buddy list.
|
||||
/// </summary>
|
||||
internal IntPtr BuddyListAddress => this.address.BuddyList;
|
||||
|
||||
private static int BuddyMemberSize { get; } = Marshal.SizeOf<FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy>();
|
||||
|
||||
private unsafe FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy* BuddyListStruct => (FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy*)this.BuddyListAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a battle buddy at the specified spawn index.
|
||||
/// </summary>
|
||||
/// <param name="index">Spawn index.</param>
|
||||
/// <returns>A <see cref="BuddyMember"/> at the specified spawn index.</returns>
|
||||
[CanBeNull]
|
||||
public BuddyMember this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
var address = this.GetBattleBuddyMemberAddress(index);
|
||||
return this.CreateBuddyMemberReference(address);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the companion buddy.
|
||||
/// </summary>
|
||||
/// <returns>The memory address of the companion buddy.</returns>
|
||||
public unsafe IntPtr GetCompanionBuddyMemberAddress()
|
||||
{
|
||||
return (IntPtr)(&this.BuddyListStruct->Companion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the pet buddy.
|
||||
/// </summary>
|
||||
/// <returns>The memory address of the pet buddy.</returns>
|
||||
public unsafe IntPtr GetPetBuddyMemberAddress()
|
||||
{
|
||||
return (IntPtr)(&this.BuddyListStruct->Pet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the battle buddy at the specified index of the buddy list.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the battle buddy.</param>
|
||||
/// <returns>The memory address of the battle buddy.</returns>
|
||||
public unsafe IntPtr GetBattleBuddyMemberAddress(int index)
|
||||
{
|
||||
if (index < 0 || index >= 3)
|
||||
return IntPtr.Zero;
|
||||
|
||||
return (IntPtr)(this.BuddyListStruct->BattleBuddies + (index * BuddyMemberSize));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a reference to a buddy.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of the buddy in memory.</param>
|
||||
/// <returns><see cref="BuddyMember"/> object containing the requested data.</returns>
|
||||
[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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This collection represents the buddies present in your squadron or trust party.
|
||||
/// </summary>
|
||||
public sealed partial class BuddyList : IReadOnlyCollection<BuddyMember>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
int IReadOnlyCollection<BuddyMember>.Count => this.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<BuddyMember> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
yield return this[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
||||
}
|
||||
}
|
||||
78
Dalamud/Game/ClientState/Buddy/BuddyMember.cs
Normal file
78
Dalamud/Game/ClientState/Buddy/BuddyMember.cs
Normal file
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents a buddy such as the chocobo companion, summoned pets, squadron groups and trust parties.
|
||||
/// </summary>
|
||||
public unsafe class BuddyMember
|
||||
{
|
||||
private Dalamud dalamud;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BuddyMember"/> class.
|
||||
/// </summary>
|
||||
/// <param name="address">Buddy address.</param>
|
||||
/// <param name="dalamud">Dalamud instance.</param>
|
||||
internal BuddyMember(IntPtr address, Dalamud dalamud)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.Address = address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the buddy in memory.
|
||||
/// </summary>
|
||||
public IntPtr Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object ID of this buddy.
|
||||
/// </summary>
|
||||
public uint ObjectId => this.Struct->ObjectID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actor associated with this buddy.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This iterates the actor table, it should be used with care.
|
||||
/// </remarks>
|
||||
[CanBeNull]
|
||||
public GameObject Actor => this.dalamud.ClientState.Objects.SearchByID(this.ObjectId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current health of this buddy.
|
||||
/// </summary>
|
||||
public uint CurrentHP => this.Struct->CurrentHealth;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum health of this buddy.
|
||||
/// </summary>
|
||||
public uint MaxHP => this.Struct->MaxHealth;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data ID of this buddy.
|
||||
/// </summary>
|
||||
public uint DataID => this.Struct->DataID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Mount data related to this buddy. It should only be used with companion buddies.
|
||||
/// </summary>
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.Mount> MountData => new(this.DataID, this.dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Pet data related to this buddy. It should only be used with pet buddies.
|
||||
/// </summary>
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.Pet> PetData => new(this.DataID, this.dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Trust data related to this buddy. It should only be used with battle buddies.
|
||||
/// </summary>
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.DawnGrowMember> TrustData => new(this.DataID, this.dalamud);
|
||||
|
||||
private FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy.BuddyMember* Struct => (FFXIVClientStructs.FFXIV.Client.Game.UI.Buddy.BuddyMember*)this.Address;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
|||
/// <summary>
|
||||
/// Gets the table of all present actors.
|
||||
/// </summary>
|
||||
public ActorTable Actors { get; }
|
||||
public ObjectTable Objects { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the table of all present fates.
|
||||
|
|
@ -124,6 +127,11 @@ namespace Dalamud.Game.ClientState
|
|||
/// </summary>
|
||||
public PartyList PartyList { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the class facilitating buddy list data access.
|
||||
/// </summary>
|
||||
public BuddyList BuddyList { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets access to the keypress state of keyboard keys in game.
|
||||
/// </summary>
|
||||
|
|
@ -153,7 +161,7 @@ namespace Dalamud.Game.ClientState
|
|||
/// Gets the local player character, if one is present.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public PlayerCharacter LocalPlayer => this.Actors[0] as PlayerCharacter;
|
||||
public PlayerCharacter LocalPlayer => this.Objects[0] as PlayerCharacter;
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
|||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.PartyList.Dispose();
|
||||
this.setupTerritoryTypeHook.Dispose();
|
||||
this.GamepadState.Dispose();
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|||
/// <summary>
|
||||
/// Gets the address of the actor table.
|
||||
/// </summary>
|
||||
public IntPtr ActorTable { get; private set; }
|
||||
public IntPtr ObjectTable { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the fate table pointer.
|
||||
/// Gets the address of the buddy list.
|
||||
/// </summary>
|
||||
public IntPtr BuddyList { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of a pointer to the fate table.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a static address to a pointer, not the address of the table itself.
|
||||
/// </remarks>
|
||||
public IntPtr FateTablePtr { get; private set; }
|
||||
|
||||
// public IntPtr ViewportActorTable { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets the address of the Group Manager.
|
||||
/// </summary>
|
||||
public IntPtr GroupManager { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
|
||||
namespace Dalamud.Game.ClientState.Objects.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// An Enum describing possible BattleNpc kinds.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.ClientState.Actors.Types
|
||||
namespace Dalamud.Game.ClientState.Objects.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// This enum describes the indices of the Customize array.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Dalamud.Game.ClientState.Actors.Types
|
||||
namespace Dalamud.Game.ClientState.Objects.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum describing possible entity kinds.
|
||||
|
|
@ -6,7 +6,7 @@ namespace Dalamud.Game.ClientState.Actors.Types
|
|||
public enum ObjectKind : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Invalid actor.
|
||||
/// Invalid character.
|
||||
/// </summary>
|
||||
None = 0x00,
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Actors.Types
|
||||
namespace Dalamud.Game.ClientState.Objects.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum describing possible status flags.
|
||||
|
|
@ -14,42 +14,42 @@ namespace Dalamud.Game.ClientState.Actors.Types
|
|||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Hostile actor.
|
||||
/// Hostile character.
|
||||
/// </summary>
|
||||
Hostile = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Actor in combat.
|
||||
/// Character in combat.
|
||||
/// </summary>
|
||||
InCombat = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Actor weapon is out.
|
||||
/// Character weapon is out.
|
||||
/// </summary>
|
||||
WeaponOut = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Actor offhand is out.
|
||||
/// Character offhand is out.
|
||||
/// </summary>
|
||||
OffhandOut = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Actor is a party member.
|
||||
/// Character is a party member.
|
||||
/// </summary>
|
||||
PartyMember = 16,
|
||||
|
||||
/// <summary>
|
||||
/// Actor is a alliance member.
|
||||
/// Character is a alliance member.
|
||||
/// </summary>
|
||||
AllianceMember = 32,
|
||||
|
||||
/// <summary>
|
||||
/// Actor is in friend list.
|
||||
/// Character is in friend list.
|
||||
/// </summary>
|
||||
Friend = 64,
|
||||
|
||||
/// <summary>
|
||||
/// Actor is casting.
|
||||
/// Character is casting.
|
||||
/// </summary>
|
||||
IsCasting = 128,
|
||||
}
|
||||
146
Dalamud/Game/ClientState/Objects/ObjectTable.cs
Normal file
146
Dalamud/Game/ClientState/Objects/ObjectTable.cs
Normal file
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This collection represents the currently spawned FFXIV game objects.
|
||||
/// </summary>
|
||||
public sealed partial class ObjectTable
|
||||
{
|
||||
private const int ObjectTableLength = 424;
|
||||
|
||||
private readonly Dalamud dalamud;
|
||||
private readonly ClientStateAddressResolver address;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ObjectTable"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">The <see cref="dalamud"/> instance.</param>
|
||||
/// <param name="addressResolver">Client state address resolver.</param>
|
||||
internal ObjectTable(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.address = addressResolver;
|
||||
|
||||
Log.Verbose($"Object table address 0x{this.address.ObjectTable.ToInt64():X}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the object table.
|
||||
/// </summary>
|
||||
public IntPtr Address => this.address.ObjectTable;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the object table.
|
||||
/// </summary>
|
||||
public int Length => ObjectTableLength;
|
||||
|
||||
/// <summary>
|
||||
/// Get an object at the specified spawn index.
|
||||
/// </summary>
|
||||
/// <param name="index">Spawn index.</param>
|
||||
/// <returns>An <see cref="GameObject"/> at the specified spawn index.</returns>
|
||||
[CanBeNull]
|
||||
public GameObject this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
var address = this.GetObjectAddress(index);
|
||||
return this.CreateObjectReference(address);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search for a game object by their Object ID.
|
||||
/// </summary>
|
||||
/// <param name="objectID">Object ID to find.</param>
|
||||
/// <returns>A game object or null.</returns>
|
||||
[CanBeNull]
|
||||
public GameObject SearchByID(uint objectID)
|
||||
{
|
||||
foreach (var obj in this)
|
||||
{
|
||||
if (obj == null)
|
||||
continue;
|
||||
|
||||
if (obj.ObjectId == objectID)
|
||||
return obj;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the game object at the specified index of the object table.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the object.</param>
|
||||
/// <returns>The memory address of the object.</returns>
|
||||
public unsafe IntPtr GetObjectAddress(int index)
|
||||
{
|
||||
if (index < 0 || index >= ObjectTableLength)
|
||||
return IntPtr.Zero;
|
||||
|
||||
return *(IntPtr*)(this.address.ObjectTable + (8 * index));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a reference to an FFXIV game object.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of the object in memory.</param>
|
||||
/// <returns><see cref="GameObject"/> object or inheritor containing the requested data.</returns>
|
||||
[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),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This collection represents the currently spawned FFXIV game objects.
|
||||
/// </summary>
|
||||
public sealed partial class ObjectTable : IReadOnlyCollection<GameObject>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
int IReadOnlyCollection<GameObject>.Count => this.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<GameObject> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < ObjectTableLength; i++)
|
||||
{
|
||||
var obj = this[i];
|
||||
|
||||
if (obj == null)
|
||||
continue;
|
||||
|
||||
yield return obj;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents a battle NPC.
|
||||
/// </summary>
|
||||
public unsafe class BattleNpc : Npc
|
||||
public unsafe class BattleNpc : BattleChara
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BattleNpc"/> class.
|
||||
|
|
@ -21,11 +23,6 @@ namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
|
|||
/// <summary>
|
||||
/// Gets the BattleNpc <see cref="BattleNpcSubKind" /> of this BattleNpc.
|
||||
/// </summary>
|
||||
public BattleNpcSubKind BattleNpcKind => *(BattleNpcSubKind*)(this.Address + ActorOffsets.SubKind);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target of the Battle NPC.
|
||||
/// </summary>
|
||||
public override uint TargetActorID => *(uint*)(this.Address + ActorOffsets.BattleNpcTargetActorId);
|
||||
public BattleNpcSubKind BattleNpcKind => (BattleNpcSubKind)this.Struct->Character.GameObject.SubKind;
|
||||
}
|
||||
}
|
||||
23
Dalamud/Game/ClientState/Objects/SubKinds/EventObj.cs
Normal file
23
Dalamud/Game/ClientState/Objects/SubKinds/EventObj.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Objects.SubKinds
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents an EventObj.
|
||||
/// </summary>
|
||||
public unsafe class EventObj : GameObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EventObj"/> class.
|
||||
/// Set up a new EventObj with the provided memory representation.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of this event object in memory.</param>
|
||||
/// <param name="dalamud">A dalamud reference.</param>
|
||||
internal EventObj(IntPtr address, Dalamud dalamud)
|
||||
: base(address, dalamud)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents a NPC.
|
||||
/// </summary>
|
||||
public unsafe class Npc : Chara
|
||||
public unsafe class Npc : Character
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Npc"/> class.
|
||||
|
|
@ -18,14 +20,9 @@ namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer
|
|||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data ID of the NPC linking to their assoicated BNpcBase data.
|
||||
/// </summary>
|
||||
public uint BaseId => *(uint*)(this.Address + ActorOffsets.DataId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name ID of the NPC linking to their respective game data.
|
||||
/// </summary>
|
||||
public uint NameId => *(uint*)(this.Address + ActorOffsets.NameId);
|
||||
public uint NameId => this.Struct->NameID;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents a player character.
|
||||
/// </summary>
|
||||
public unsafe class PlayerCharacter : Chara
|
||||
public unsafe class PlayerCharacter : BattleChara
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlayerCharacter"/> class.
|
||||
|
|
@ -25,21 +24,16 @@ namespace Dalamud.Game.ClientState.Actors.Types
|
|||
/// <summary>
|
||||
/// Gets the current <see cref="ExcelResolver{T}">world</see> of the character.
|
||||
/// </summary>
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.World> CurrentWorld => new(*(ushort*)(this.Address + ActorOffsets.CurrentWorld), this.Dalamud);
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.World> CurrentWorld => new(this.Struct->Character.CurrentWorld, this.Dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the home <see cref="ExcelResolver{T}">world</see> of the character.
|
||||
/// </summary>
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.World> HomeWorld => new(*(ushort*)(this.Address + ActorOffsets.HomeWorld), this.Dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Free Company tag of this player.
|
||||
/// </summary>
|
||||
public SeString CompanyTag => MemoryHelper.ReadSeString(this.Address + ActorOffsets.CompanyTag, 6);
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.World> HomeWorld => new(this.Struct->Character.HomeWorld, this.Dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target actor ID of the PlayerCharacter.
|
||||
/// </summary>
|
||||
public override uint TargetActorID => *(uint*)(this.Address + ActorOffsets.PlayerCharacterTargetActorId);
|
||||
public override uint TargetObjectId => this.Struct->Character.GameObject.TargetObjectID;
|
||||
}
|
||||
}
|
||||
169
Dalamud/Game/ClientState/Objects/Targets.cs
Normal file
169
Dalamud/Game/ClientState/Objects/Targets.cs
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
using System;
|
||||
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Objects
|
||||
{
|
||||
/// <summary>
|
||||
/// Get and set various kinds of targets for the player.
|
||||
/// </summary>
|
||||
public sealed unsafe class Targets
|
||||
{
|
||||
private readonly Dalamud dalamud;
|
||||
private readonly ClientStateAddressResolver address;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Targets"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
/// <param name="addressResolver">The ClientStateAddressResolver instance.</param>
|
||||
internal Targets(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.address = addressResolver;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the target manager.
|
||||
/// </summary>
|
||||
public IntPtr Address => this.address.TargetManager;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current target.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public GameObject Target
|
||||
{
|
||||
get => this.dalamud.ClientState.Objects.CreateObjectReference((IntPtr)Struct->Target);
|
||||
set => this.SetTarget(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the mouseover target.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public GameObject MouseOverTarget
|
||||
{
|
||||
get => this.dalamud.ClientState.Objects.CreateObjectReference((IntPtr)Struct->MouseOverTarget);
|
||||
set => this.SetMouseOverTarget(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the focus target.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public GameObject FocusTarget
|
||||
{
|
||||
get => this.dalamud.ClientState.Objects.CreateObjectReference((IntPtr)Struct->FocusTarget);
|
||||
set => this.SetFocusTarget(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the previous target.
|
||||
/// </summary>
|
||||
[CanBeNull]
|
||||
public GameObject PreviousTarget
|
||||
{
|
||||
get => this.dalamud.ClientState.Objects.CreateObjectReference((IntPtr)Struct->PreviousTarget);
|
||||
set => this.SetPreviousTarget(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the soft target.
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to target.</param>
|
||||
public void SetTarget(GameObject actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the mouseover target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to target.</param>
|
||||
public void SetMouseOverTarget(GameObject actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the focus target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to target.</param>
|
||||
public void SetFocusTarget(GameObject actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the previous target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to target.</param>
|
||||
public void SetPreviousTarget(GameObject actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the soft target.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to target.</param>
|
||||
public void SetSoftTarget(GameObject actor) => this.SetTarget(actor?.Address ?? IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the current target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to target.</param>
|
||||
public void SetTarget(IntPtr actorAddress) => Struct->Target = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the mouseover target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to target.</param>
|
||||
public void SetMouseOverTarget(IntPtr actorAddress) => Struct->MouseOverTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the focus target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to target.</param>
|
||||
public void SetFocusTarget(IntPtr actorAddress) => Struct->FocusTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the previous target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to target.</param>
|
||||
public void SetPreviousTarget(IntPtr actorAddress) => Struct->PreviousTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the soft target.
|
||||
/// </summary>
|
||||
/// <param name="actorAddress">Actor (address) to target.</param>
|
||||
public void SetSoftTarget(IntPtr actorAddress) => Struct->SoftTarget = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)actorAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Clears the current target.
|
||||
/// </summary>
|
||||
public void ClearTarget() => this.SetTarget(IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the mouseover target.
|
||||
/// </summary>
|
||||
public void ClearMouseOverTarget() => this.SetMouseOverTarget(IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the focus target.
|
||||
/// </summary>
|
||||
public void ClearFocusTarget() => this.SetFocusTarget(IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the previous target.
|
||||
/// </summary>
|
||||
public void ClearPreviousTarget() => this.SetPreviousTarget(IntPtr.Zero);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the soft target.
|
||||
/// </summary>
|
||||
public void ClearSoftTarget() => this.SetSoftTarget(IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
68
Dalamud/Game/ClientState/Objects/Types/BattleChara.cs
Normal file
68
Dalamud/Game/ClientState/Objects/Types/BattleChara.cs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
|
||||
using Dalamud.Game.ClientState.Statuses;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Objects.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents the battle characters.
|
||||
/// </summary>
|
||||
public unsafe class BattleChara : Character
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BattleChara"/> class.
|
||||
/// This represents a battle character.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of this character in memory.</param>
|
||||
/// <param name="dalamud">Dalamud itself.</param>
|
||||
internal BattleChara(IntPtr address, Dalamud dalamud)
|
||||
: base(address, dalamud)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current status effects.
|
||||
/// </summary>
|
||||
public StatusList StatusList => new(&this.Struct->StatusManager, this.Dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the chara is currently casting.
|
||||
/// </summary>
|
||||
public bool IsCasting => this.Struct->SpellCastInfo.IsCasting > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the cast is interruptible.
|
||||
/// </summary>
|
||||
public bool IsCastInterruptible => this.Struct->SpellCastInfo.Interruptible > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the spell action type of the spell being cast by the actor.
|
||||
/// </summary>
|
||||
public byte CastActionType => (byte)this.Struct->SpellCastInfo.ActionType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the spell action ID of the spell being cast by the actor.
|
||||
/// </summary>
|
||||
public uint CastActionId => this.Struct->SpellCastInfo.ActionID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object ID of the target currently being cast at by the chara.
|
||||
/// </summary>
|
||||
public uint CastTargetObjectId => this.Struct->SpellCastInfo.CastTargetID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current casting time of the spell being cast by the chara.
|
||||
/// </summary>
|
||||
public float CurrentCastTime => this.Struct->SpellCastInfo.CurrentCastTime;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total casting time of the spell being cast by the chara.
|
||||
/// </summary>
|
||||
public float TotalCastTime => this.Struct->SpellCastInfo.TotalCastTime;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the underlying structure.
|
||||
/// </summary>
|
||||
private protected new FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Character.BattleChara*)this.Address;
|
||||
}
|
||||
}
|
||||
103
Dalamud/Game/ClientState/Objects/Types/Character.cs
Normal file
103
Dalamud/Game/ClientState/Objects/Types/Character.cs
Normal file
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents the base for non-static entities.
|
||||
/// </summary>
|
||||
public unsafe class Character : GameObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Character"/> class.
|
||||
/// This represents a non-static entity.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of this character in memory.</param>
|
||||
/// <param name="dalamud">Dalamud itself.</param>
|
||||
internal Character(IntPtr address, Dalamud dalamud)
|
||||
: base(address, dalamud)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current HP of this Chara.
|
||||
/// </summary>
|
||||
public uint CurrentHp => this.Struct->Health;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum HP of this Chara.
|
||||
/// </summary>
|
||||
public uint MaxHp => this.Struct->MaxHealth;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current MP of this Chara.
|
||||
/// </summary>
|
||||
public uint CurrentMp => this.Struct->Mana;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum MP of this Chara.
|
||||
/// </summary>
|
||||
public uint MaxMp => this.Struct->MaxMana;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current GP of this Chara.
|
||||
/// </summary>
|
||||
public uint CurrentGp => this.Struct->GatheringPoints;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum GP of this Chara.
|
||||
/// </summary>
|
||||
public uint MaxGp => this.Struct->MaxGatheringPoints;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current CP of this Chara.
|
||||
/// </summary>
|
||||
public uint CurrentCp => this.Struct->CraftingPoints;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum CP of this Chara.
|
||||
/// </summary>
|
||||
public uint MaxCp => this.Struct->MaxCraftingPoints;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ClassJob of this Chara.
|
||||
/// </summary>
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.ClassJob> ClassJob => new(this.Struct->ClassJob, this.Dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the level of this Chara.
|
||||
/// </summary>
|
||||
public byte Level => this.Struct->Level;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a byte array describing the visual appearance of this Chara.
|
||||
/// Indexed by <see cref="CustomizeIndex"/>.
|
||||
/// </summary>
|
||||
public byte[] Customize => MemoryHelper.Read<byte>((IntPtr)this.Struct->CustomizeData, 28);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Free Company tag of this chara.
|
||||
/// </summary>
|
||||
public SeString CompanyTag => MemoryHelper.ReadSeString((IntPtr)this.Struct->FreeCompanyTag, 6);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target object ID of the character.
|
||||
/// </summary>
|
||||
public override uint TargetObjectId => this.Struct->GameObject.TargetObjectID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the status flags.
|
||||
/// </summary>
|
||||
public StatusFlags StatusFlags => (StatusFlags)this.Struct->StatusFlags;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the underlying structure.
|
||||
/// </summary>
|
||||
private protected new FFXIVClientStructs.FFXIV.Client.Game.Character.Character* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)this.Address;
|
||||
}
|
||||
}
|
||||
168
Dalamud/Game/ClientState/Objects/Types/GameObject.cs
Normal file
168
Dalamud/Game/ClientState/Objects/Types/GameObject.cs
Normal file
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents a GameObject in FFXIV.
|
||||
/// </summary>
|
||||
public unsafe partial class GameObject : IEquatable<GameObject>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GameObject"/> class.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of this game object in memory.</param>
|
||||
/// <param name="dalamud">Dalamud itself.</param>
|
||||
internal GameObject(IntPtr address, Dalamud dalamud)
|
||||
{
|
||||
this.Address = address;
|
||||
this.Dalamud = dalamud;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the game object in memory.
|
||||
/// </summary>
|
||||
public IntPtr Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Dalamud instance.
|
||||
/// </summary>
|
||||
private protected Dalamud Dalamud { get; }
|
||||
|
||||
/// <summary>
|
||||
/// This allows you to <c>if (obj) {...}</c> to check for validity.
|
||||
/// </summary>
|
||||
/// <param name="gameObject">The actor to check.</param>
|
||||
/// <returns>True or false.</returns>
|
||||
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);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this actor is still valid in memory.
|
||||
/// </summary>
|
||||
/// <param name="actor">The actor to check.</param>
|
||||
/// <returns>True or false.</returns>
|
||||
public static bool IsValid(GameObject? actor)
|
||||
{
|
||||
if (actor is null)
|
||||
return false;
|
||||
|
||||
if (actor.Dalamud.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);
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool IEquatable<GameObject>.Equals(GameObject other) => this.ObjectId == other?.ObjectId;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj) => ((IEquatable<GameObject>)this).Equals(obj as GameObject);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode() => this.ObjectId.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class represents a basic actor (GameObject) in FFXIV.
|
||||
/// </summary>
|
||||
public unsafe partial class GameObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name of this <see cref="GameObject" />.
|
||||
/// </summary>
|
||||
public SeString Name => MemoryHelper.ReadSeString((IntPtr)this.Struct->Name, 32);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object ID of this <see cref="GameObject" />.
|
||||
/// </summary>
|
||||
public uint ObjectId => this.Struct->ObjectID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data ID for linking to other respective game data.
|
||||
/// </summary>
|
||||
public uint DataId => this.Struct->DataID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ID of this GameObject's owner.
|
||||
/// </summary>
|
||||
public uint OwnerId => this.Struct->OwnerID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity kind of this <see cref="GameObject" />.
|
||||
/// See <see cref="ObjectKind">the ObjectKind enum</see> for possible values.
|
||||
/// </summary>
|
||||
public ObjectKind ObjectKind => (ObjectKind)this.Struct->ObjectKind;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sub kind of this Actor.
|
||||
/// </summary>
|
||||
public byte SubKind => this.Struct->SubKind;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the X distance from the local player in yalms.
|
||||
/// </summary>
|
||||
public byte YalmDistanceX => this.Struct->YalmDistanceFromPlayerX;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Y distance from the local player in yalms.
|
||||
/// </summary>
|
||||
public byte YalmDistanceZ => this.Struct->YalmDistanceFromPlayerZ;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position of this <see cref="GameObject" />.
|
||||
/// </summary>
|
||||
public Vector3 Position => new(this.Struct->Position.X, this.Struct->Position.Y, this.Struct->Position.Z);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rotation of this <see cref="GameObject" />.
|
||||
/// This ranges from -pi to pi radians.
|
||||
/// </summary>
|
||||
public float Rotation => this.Struct->Rotation;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hitbox radius of this <see cref="GameObject" />.
|
||||
/// </summary>
|
||||
public float HitboxRadius => this.Struct->HitboxRadius;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current target of the game object.
|
||||
/// </summary>
|
||||
public virtual uint TargetObjectId => 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target object of the game object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This iterates the actor table, it should be used with care.
|
||||
/// </remarks>
|
||||
[CanBeNull]
|
||||
public virtual GameObject TargetObject => this.Dalamud.ClientState.Objects.SearchByID(this.TargetObjectId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the underlying structure.
|
||||
/// </summary>
|
||||
private protected FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)this.Address;
|
||||
}
|
||||
}
|
||||
183
Dalamud/Game/ClientState/Party/PartyList.cs
Normal file
183
Dalamud/Game/ClientState/Party/PartyList.cs
Normal file
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This collection represents the actors present in your party or alliance.
|
||||
/// </summary>
|
||||
public sealed unsafe partial class PartyList
|
||||
{
|
||||
private const int GroupLength = 8;
|
||||
private const int AllianceLength = 20;
|
||||
|
||||
private readonly Dalamud dalamud;
|
||||
private readonly ClientStateAddressResolver address;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PartyList"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">The <see cref="dalamud"/> instance.</param>
|
||||
/// <param name="addressResolver">Client state address resolver.</param>
|
||||
internal PartyList(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.address = addressResolver;
|
||||
|
||||
Log.Verbose($"Group manager address 0x{this.address.GroupManager.ToInt64():X}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of party members the local player has.
|
||||
/// </summary>
|
||||
public int Length => this.GroupManagerStruct->MemberCount;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index of the party leader.
|
||||
/// </summary>
|
||||
public uint PartyLeaderIndex => this.GroupManagerStruct->PartyLeaderIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this group is an alliance.
|
||||
/// </summary>
|
||||
public bool IsAlliance => this.GroupManagerStruct->IsAlliance;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the Group Manager.
|
||||
/// </summary>
|
||||
public IntPtr GroupManagerAddress => this.address.GroupManager;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the party list within the group manager.
|
||||
/// </summary>
|
||||
public IntPtr GroupListAddress => (IntPtr)GroupManagerStruct->PartyMembers;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the alliance member list within the group manager.
|
||||
/// </summary>
|
||||
public IntPtr AllianceListAddress => (IntPtr)this.GroupManagerStruct->AllianceMembers;
|
||||
|
||||
private static int PartyMemberSize { get; } = Marshal.SizeOf<FFXIVClientStructs.FFXIV.Client.Game.Group.PartyMember>();
|
||||
|
||||
private FFXIVClientStructs.FFXIV.Client.Game.Group.GroupManager* GroupManagerStruct => (FFXIVClientStructs.FFXIV.Client.Game.Group.GroupManager*)this.GroupManagerAddress;
|
||||
|
||||
/// <summary>
|
||||
/// Get a party member at the specified spawn index.
|
||||
/// </summary>
|
||||
/// <param name="index">Spawn index.</param>
|
||||
/// <returns>A <see cref="PartyMember"/> at the specified spawn index.</returns>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the party member at the specified index of the party list.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the party member.</param>
|
||||
/// <returns>The memory address of the party member.</returns>
|
||||
public IntPtr GetPartyMemberAddress(int index)
|
||||
{
|
||||
if (index < 0 || index >= GroupLength)
|
||||
return IntPtr.Zero;
|
||||
|
||||
return this.GroupListAddress + (index * PartyMemberSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a reference to an FFXIV party member.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of the party member in memory.</param>
|
||||
/// <returns>The party member object containing the requested data.</returns>
|
||||
[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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the alliance member at the specified index of the alliance list.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the alliance member.</param>
|
||||
/// <returns>The memory address of the alliance member.</returns>
|
||||
public IntPtr GetAllianceMemberAddress(int index)
|
||||
{
|
||||
if (index < 0 || index >= AllianceLength)
|
||||
return IntPtr.Zero;
|
||||
|
||||
return this.AllianceListAddress + (index * PartyMemberSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a reference to an FFXIV alliance member.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of the alliance member in memory.</param>
|
||||
/// <returns>The party member object containing the requested data.</returns>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This collection represents the party members present in your party or alliance.
|
||||
/// </summary>
|
||||
public sealed partial class PartyList : IReadOnlyCollection<PartyMember>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
int IReadOnlyCollection<PartyMember>.Count => this.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<PartyMember> 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
||||
}
|
||||
}
|
||||
117
Dalamud/Game/ClientState/Party/PartyMember.cs
Normal file
117
Dalamud/Game/ClientState/Party/PartyMember.cs
Normal file
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents a party member in the group manager.
|
||||
/// </summary>
|
||||
public unsafe class PartyMember
|
||||
{
|
||||
private Dalamud dalamud;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PartyMember"/> class.
|
||||
/// </summary>
|
||||
/// <param name="address">Address of the party member.</param>
|
||||
/// <param name="dalamud">Dalamud itself.</param>
|
||||
internal PartyMember(IntPtr address, Dalamud dalamud)
|
||||
{
|
||||
this.Address = address;
|
||||
this.dalamud = dalamud;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of this party member in memory.
|
||||
/// </summary>
|
||||
public IntPtr Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of buffs or debuffs applied to this party member.
|
||||
/// </summary>
|
||||
public StatusList Statuses => new(&this.Struct->StatusManager, this.dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position of the party member.
|
||||
/// </summary>
|
||||
public Vector3 Position => new(this.Struct->X, this.Struct->Y, this.Struct->Z);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content ID of the party member.
|
||||
/// </summary>
|
||||
public long ContentId => this.Struct->ContentID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actor ID of this party member.
|
||||
/// </summary>
|
||||
public uint ObjectId => this.Struct->ObjectID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the actor associated with this buddy.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This iterates the actor table, it should be used with care.
|
||||
/// </remarks>
|
||||
[CanBeNull]
|
||||
public GameObject GameObject => this.dalamud.ClientState.Objects.SearchByID(this.ObjectId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current HP of this party member.
|
||||
/// </summary>
|
||||
public uint CurrentHP => this.Struct->CurrentHP;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum HP of this party member.
|
||||
/// </summary>
|
||||
public uint MaxHP => this.Struct->MaxHP;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current MP of this party member.
|
||||
/// </summary>
|
||||
public ushort CurrentMP => this.Struct->CurrentMP;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the maximum MP of this party member.
|
||||
/// </summary>
|
||||
public ushort MaxMP => this.Struct->MaxMP;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the territory this party member is located in.
|
||||
/// </summary>
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.TerritoryType> Territory => new(this.Struct->TerritoryType, this.dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the World this party member resides in.
|
||||
/// </summary>
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.World> World => new(this.Struct->HomeWorld, this.dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the displayname of this party member.
|
||||
/// </summary>
|
||||
public SeString Name => MemoryHelper.ReadSeString((IntPtr)Struct->Name, 0x40);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sex of this party member.
|
||||
/// </summary>
|
||||
public byte Sex => this.Struct->Sex;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the classjob of this party member.
|
||||
/// </summary>
|
||||
public ExcelResolver<Lumina.Excel.GeneratedSheets.ClassJob> ClassJob => new(this.Struct->ClassJob, this.dalamud);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the level of this party member.
|
||||
/// </summary>
|
||||
public byte Level => this.Struct->Level;
|
||||
|
||||
private FFXIVClientStructs.FFXIV.Client.Game.Group.PartyMember* Struct => (FFXIVClientStructs.FFXIV.Client.Game.Group.PartyMember*)this.Address;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents the members of your party.
|
||||
/// </summary>
|
||||
public sealed partial class PartyList
|
||||
{
|
||||
private readonly Dalamud dalamud;
|
||||
private readonly ClientStateAddressResolver address;
|
||||
|
||||
// private bool isReady = false;
|
||||
// private IntPtr partyListBegin;
|
||||
// private Hook<PartyListUpdateDelegate> partyListUpdateHook;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PartyList"/> class.
|
||||
/// </summary>
|
||||
/// <param name="dalamud">The Dalamud instance.</param>
|
||||
/// <param name="addressResolver">The ClientStateAddressResolver instance.</param>
|
||||
internal PartyList(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||
{
|
||||
this.address = addressResolver;
|
||||
this.dalamud = dalamud;
|
||||
// this.partyListUpdateHook = new Hook<PartyListUpdateDelegate>(Address.PartyListUpdate, new PartyListUpdateDelegate(PartyListUpdateDetour), this);
|
||||
}
|
||||
|
||||
private delegate long PartyListUpdateDelegate(IntPtr structBegin, long param2, char param3);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the PartyList.
|
||||
/// </summary>
|
||||
public int Length => 0; // !this.isReady ? 0 : Marshal.ReadByte(this.partyListBegin + 0xF0);
|
||||
|
||||
/// <summary>
|
||||
/// Get the nth party member.
|
||||
/// </summary>
|
||||
/// <param name="index">Index of the party member.</param>
|
||||
/// <returns>The party member.</returns>
|
||||
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<Structs.PartyMember>(tblIndex);
|
||||
// return new PartyMember(this.dalamud.ClientState.Actors, memberStruct);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable this module.
|
||||
/// </summary>
|
||||
public void Enable()
|
||||
{
|
||||
// TODO Fix for 5.3
|
||||
// this.partyListUpdateHook.Enable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose of managed and unmanaged resources.
|
||||
/// </summary>
|
||||
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;
|
||||
// }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements IReadOnlyCollection, IEnumerable.
|
||||
/// </summary>
|
||||
public sealed partial class PartyList : IReadOnlyCollection<PartyMember>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
int IReadOnlyCollection<PartyMember>.Count => this.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<PartyMember> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
if (this[i] != null)
|
||||
{
|
||||
yield return this[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements ICollection.
|
||||
/// </summary>
|
||||
public sealed partial class PartyList : ICollection
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public int Count => this.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object SyncRoot => this;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsSynchronized => false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void CopyTo(Array array, int index)
|
||||
{
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
array.SetValue(this[i], index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
73
Dalamud/Game/ClientState/Statuses/Status.cs
Normal file
73
Dalamud/Game/ClientState/Statuses/Status.cs
Normal file
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents a status effect an actor is afflicted by.
|
||||
/// </summary>
|
||||
public unsafe class Status
|
||||
{
|
||||
private Dalamud dalamud;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Status"/> class.
|
||||
/// </summary>
|
||||
/// <param name="address">Status address.</param>
|
||||
/// <param name="dalamud">Dalamud instance.</param>
|
||||
internal Status(IntPtr address, Dalamud dalamud)
|
||||
{
|
||||
this.dalamud = dalamud;
|
||||
this.Address = address;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the status in memory.
|
||||
/// </summary>
|
||||
public IntPtr Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the status ID of this status.
|
||||
/// </summary>
|
||||
public uint StatusID => this.Struct->StatusID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the GameData associated with this status.
|
||||
/// </summary>
|
||||
public Lumina.Excel.GeneratedSheets.Status GameData => new ExcelResolver<Lumina.Excel.GeneratedSheets.Status>(this.Struct->StatusID, this.dalamud).GameData;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parameter value of the status.
|
||||
/// </summary>
|
||||
public byte Param => this.Struct->Param;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the stack count of this status.
|
||||
/// </summary>
|
||||
public byte StackCount => this.Struct->StackCount;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time remaining of this status.
|
||||
/// </summary>
|
||||
public float RemainingTime => this.Struct->RemainingTime;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the source ID of this status.
|
||||
/// </summary>
|
||||
public uint SourceID => this.Struct->SourceID;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the source actor associated with this status.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This iterates the actor table, it should be used with care.
|
||||
/// </remarks>
|
||||
[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;
|
||||
}
|
||||
}
|
||||
161
Dalamud/Game/ClientState/Statuses/StatusList.cs
Normal file
161
Dalamud/Game/ClientState/Statuses/StatusList.cs
Normal file
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// This collection represents the status effects an actor is afflicted by.
|
||||
/// </summary>
|
||||
public sealed unsafe partial class StatusList
|
||||
{
|
||||
private const int StatusListLength = 30;
|
||||
|
||||
private readonly Dalamud dalamud;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StatusList"/> class.
|
||||
/// </summary>
|
||||
/// <param name="address">Address of the status list.</param>
|
||||
/// <param name="dalamud">The <see cref="dalamud"/> instance.</param>
|
||||
internal StatusList(IntPtr address, Dalamud dalamud)
|
||||
{
|
||||
this.Address = address;
|
||||
this.dalamud = dalamud;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StatusList"/> class.
|
||||
/// </summary>
|
||||
/// <param name="pointer">Pointer to the status list.</param>
|
||||
/// <param name="dalamud">The <see cref="dalamud"/> instance.</param>
|
||||
internal unsafe StatusList(void* pointer, Dalamud dalamud)
|
||||
: this((IntPtr)pointer, dalamud)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the status list in memory.
|
||||
/// </summary>
|
||||
public IntPtr Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of status effects the actor has.
|
||||
/// </summary>
|
||||
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<FFXIVClientStructs.FFXIV.Client.Game.Status>();
|
||||
|
||||
private FFXIVClientStructs.FFXIV.Client.Game.StatusManager* Struct => (FFXIVClientStructs.FFXIV.Client.Game.StatusManager*)this.Address;
|
||||
|
||||
/// <summary>
|
||||
/// Get a status effect at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Status Index.</param>
|
||||
/// <returns>The status at the specified index.</returns>
|
||||
[CanBeNull]
|
||||
public Status this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < 0 || index > StatusListLength)
|
||||
return null;
|
||||
|
||||
var addr = this.GetStatusAddress(index);
|
||||
return this.CreateStatusReference(addr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the party member at the specified index of the party list.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the party member.</param>
|
||||
/// <returns>The memory address of the party member.</returns>
|
||||
public IntPtr GetStatusAddress(int index)
|
||||
{
|
||||
if (index < 0 || index >= StatusListLength)
|
||||
return IntPtr.Zero;
|
||||
|
||||
return (IntPtr)(this.Struct->Status + (index * StatusSize));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a reference to an FFXIV actor status.
|
||||
/// </summary>
|
||||
/// <param name="address">The address of the status effect in memory.</param>
|
||||
/// <returns>The status object containing the requested data.</returns>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This collection represents the status effects an actor is afflicted by.
|
||||
/// </summary>
|
||||
public sealed partial class StatusList : IReadOnlyCollection<Status>, ICollection
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
int IReadOnlyCollection<Status>.Count => this.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
int ICollection.Count => this.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool ICollection.IsSynchronized => false;
|
||||
|
||||
/// <inheritdoc/>
|
||||
object ICollection.SyncRoot => this;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<Status> GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < StatusListLength; i++)
|
||||
{
|
||||
var status = this[i];
|
||||
|
||||
if (status == null || status.StatusID == 0)
|
||||
continue;
|
||||
|
||||
yield return status;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
|
||||
|
||||
/// <inheritdoc/>
|
||||
void ICollection.CopyTo(Array array, int index)
|
||||
{
|
||||
for (var i = 0; i < this.Length; i++)
|
||||
{
|
||||
array.SetValue(this[i], index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Dalamud.Game.ClientState.Actors.Types;
|
||||
|
||||
namespace Dalamud.Game.ClientState.Structs
|
||||
{
|
||||
/// <summary>
|
||||
/// This represents a native PartyMember class in memory.
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<DataKind>()
|
||||
.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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue