mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-13 12:14:16 +01:00
feat: Fate Table
This commit is contained in:
parent
a18bcc385c
commit
4e24c8fa3a
8 changed files with 465 additions and 1 deletions
|
|
@ -4,6 +4,7 @@ using System.Runtime.InteropServices;
|
||||||
|
|
||||||
using Dalamud.Game.ClientState.Actors;
|
using Dalamud.Game.ClientState.Actors;
|
||||||
using Dalamud.Game.ClientState.Actors.Types;
|
using Dalamud.Game.ClientState.Actors.Types;
|
||||||
|
using Dalamud.Game.ClientState.Fates;
|
||||||
using Dalamud.Game.Internal;
|
using Dalamud.Game.Internal;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
@ -42,6 +43,8 @@ namespace Dalamud.Game.ClientState
|
||||||
|
|
||||||
this.Actors = new ActorTable(dalamud, this.address);
|
this.Actors = new ActorTable(dalamud, this.address);
|
||||||
|
|
||||||
|
this.Fates = new FateTable(dalamud, this.address);
|
||||||
|
|
||||||
this.PartyList = new PartyList(dalamud, this.address);
|
this.PartyList = new PartyList(dalamud, this.address);
|
||||||
|
|
||||||
this.JobGauges = new JobGauges(this.address);
|
this.JobGauges = new JobGauges(this.address);
|
||||||
|
|
@ -97,6 +100,11 @@ namespace Dalamud.Game.ClientState
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ActorTable Actors { get; }
|
public ActorTable Actors { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the table of all present fates.
|
||||||
|
/// </summary>
|
||||||
|
public FateTable Fates { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the language of the client.
|
/// Gets the language of the client.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
using Dalamud.Game.Internal;
|
using Dalamud.Game.Internal;
|
||||||
|
|
||||||
|
|
@ -9,6 +10,8 @@ namespace Dalamud.Game.ClientState
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ClientStateAddressResolver : BaseAddressResolver
|
public sealed class ClientStateAddressResolver : BaseAddressResolver
|
||||||
{
|
{
|
||||||
|
private delegate IntPtr GetFateTableDelegate();
|
||||||
|
|
||||||
// Static offsets
|
// Static offsets
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -16,6 +19,14 @@ namespace Dalamud.Game.ClientState
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IntPtr ActorTable { get; private set; }
|
public IntPtr ActorTable { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the address of the fate table pointer.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is a static address into the table, not the address of the table itself.
|
||||||
|
/// </remarks>
|
||||||
|
public IntPtr FateTablePtr { get; private set; }
|
||||||
|
|
||||||
// public IntPtr ViewportActorTable { get; private set; }
|
// public IntPtr ViewportActorTable { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -68,8 +79,13 @@ namespace Dalamud.Game.ClientState
|
||||||
// We don't need those anymore, but maybe someone else will - let's leave them here for good measure
|
// We don't need those anymore, but maybe someone else will - let's leave them here for good measure
|
||||||
// ViewportActorTable = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? 85 ED", 0) + 0x148;
|
// ViewportActorTable = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? 85 ED", 0) + 0x148;
|
||||||
// SomeActorTableAccess = sig.ScanText("E8 ?? ?? ?? ?? 48 8D 55 A0 48 8D 8E ?? ?? ?? ??");
|
// SomeActorTableAccess = sig.ScanText("E8 ?? ?? ?? ?? 48 8D 55 A0 48 8D 8E ?? ?? ?? ??");
|
||||||
|
|
||||||
this.ActorTable = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 44 0F B6 83");
|
this.ActorTable = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 44 0F B6 83");
|
||||||
|
|
||||||
|
var getFateTableAddr = sig.ScanText("E8 ?? ?? ?? ?? 48 8B C8 E8 ?? ?? ?? ?? 80 BF ?? ?? ?? ?? ??");
|
||||||
|
var getFateTable = Marshal.GetDelegateForFunctionPointer<GetFateTableDelegate>(getFateTableAddr);
|
||||||
|
this.FateTablePtr = getFateTable();
|
||||||
|
|
||||||
this.LocalContentId = sig.GetStaticAddressFromSig("48 0F 44 05 ?? ?? ?? ?? 48 39 07");
|
this.LocalContentId = sig.GetStaticAddressFromSig("48 0F 44 05 ?? ?? ?? ?? 48 39 07");
|
||||||
this.JobGaugeData = sig.GetStaticAddressFromSig("E8 ?? ?? ?? ?? FF C6 48 8D 5B 0C", 0xB9) + 0x10;
|
this.JobGaugeData = sig.GetStaticAddressFromSig("E8 ?? ?? ?? ?? FF C6 48 8D 5B 0C", 0xB9) + 0x10;
|
||||||
|
|
||||||
|
|
|
||||||
178
Dalamud/Game/ClientState/Fates/FateTable.cs
Normal file
178
Dalamud/Game/ClientState/Fates/FateTable.cs
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Dalamud.Game.ClientState.Fates.Types;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.ClientState.Fates
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This collection represents the currently available Fate events.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class FateTable
|
||||||
|
{
|
||||||
|
// If the pointer at this offset is 0, do not scan the table
|
||||||
|
private const int CheckPtrOffset = 0x80;
|
||||||
|
private const int FirstPtrOffset = 0x90;
|
||||||
|
private const int LastPtrOffset = 0x98;
|
||||||
|
|
||||||
|
private readonly Dalamud dalamud;
|
||||||
|
private readonly ClientStateAddressResolver address;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="FateTable"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dalamud">The <see cref="dalamud"/> instance.</param>
|
||||||
|
/// <param name="addressResolver">Client state address resolver.</param>
|
||||||
|
internal FateTable(Dalamud dalamud, ClientStateAddressResolver addressResolver)
|
||||||
|
{
|
||||||
|
this.address = addressResolver;
|
||||||
|
this.dalamud = dalamud;
|
||||||
|
|
||||||
|
Log.Verbose($"Fate table address 0x{this.address.FateTablePtr.ToInt64():X}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the amount of currently active Fates.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe int Length
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var fateTable = this.FateTableAddress;
|
||||||
|
if (fateTable == IntPtr.Zero)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var check = *(long*)(fateTable + CheckPtrOffset);
|
||||||
|
if (check == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var start = *(long*)(fateTable + FirstPtrOffset);
|
||||||
|
var end = *(long*)(fateTable + LastPtrOffset);
|
||||||
|
if (start == 0 || end == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (int)((end - start) / 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe IntPtr FateTableAddress
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.address.FateTablePtr == IntPtr.Zero)
|
||||||
|
return IntPtr.Zero;
|
||||||
|
|
||||||
|
return *(IntPtr*)this.address.FateTablePtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get an actor at the specified spawn index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">Spawn index.</param>
|
||||||
|
/// <returns>A <see cref="Fate"/> at the specified spawn index.</returns>
|
||||||
|
[CanBeNull]
|
||||||
|
public Fate this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var address = this.GetFateAddress(index);
|
||||||
|
return this[address];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a Fate at the specified address.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">The Fate address.</param>
|
||||||
|
/// <returns>A <see cref="Fate"/> at the specified address.</returns>
|
||||||
|
public Fate this[IntPtr address]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (address == IntPtr.Zero)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return this.CreateFateReference(address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the address of the Fate at the specified index of the fate table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The index of the Fate.</param>
|
||||||
|
/// <returns>The memory address of the Fate.</returns>
|
||||||
|
public unsafe IntPtr GetFateAddress(int index)
|
||||||
|
{
|
||||||
|
if (index >= this.Length)
|
||||||
|
return IntPtr.Zero;
|
||||||
|
|
||||||
|
var fateTable = this.FateTableAddress;
|
||||||
|
if (fateTable == IntPtr.Zero)
|
||||||
|
return IntPtr.Zero;
|
||||||
|
|
||||||
|
var firstFate = *(IntPtr*)(fateTable + FirstPtrOffset);
|
||||||
|
return *(IntPtr*)(firstFate + (8 * index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a reference to a FFXIV actor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">The offset of the actor in memory.</param>
|
||||||
|
/// <returns><see cref="Fate"/> object containing requested data.</returns>
|
||||||
|
[CanBeNull]
|
||||||
|
internal unsafe Fate CreateFateReference(IntPtr offset)
|
||||||
|
{
|
||||||
|
if (this.dalamud.ClientState.LocalContentId == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (offset == IntPtr.Zero)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new Fate(offset, this.dalamud);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This collection represents the currently available Fate events.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class FateTable : IReadOnlyCollection<Fate>, ICollection
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
int IReadOnlyCollection<Fate>.Count => this.Length;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
int ICollection.Count => this.Length;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
bool ICollection.IsSynchronized => false;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
object ICollection.SyncRoot => this;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public IEnumerator<Fate> GetEnumerator()
|
||||||
|
{
|
||||||
|
for (var i = 0; i < this.Length; 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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
138
Dalamud/Game/ClientState/Fates/Types/Fate.cs
Normal file
138
Dalamud/Game/ClientState/Fates/Types/Fate.cs
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using Dalamud.Game.ClientState.Resolvers;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using Dalamud.Memory;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.System.String;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.ClientState.Fates.Types
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This class represents an FFXIV Fate.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe partial class Fate : IEquatable<Fate>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Fate"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">The address of this fate in memory.</param>
|
||||||
|
/// <param name="dalamud">Dalamud instance.</param>
|
||||||
|
internal Fate(IntPtr address, Dalamud dalamud)
|
||||||
|
{
|
||||||
|
this.Address = address;
|
||||||
|
this.Dalamud = dalamud;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the address of this Fate in memory.
|
||||||
|
/// </summary>
|
||||||
|
public IntPtr Address { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets Dalamud itself.
|
||||||
|
/// </summary>
|
||||||
|
private protected Dalamud Dalamud { get; }
|
||||||
|
|
||||||
|
public static bool operator ==(Fate fate1, Fate fate2)
|
||||||
|
{
|
||||||
|
if (fate1 is null || fate2 is null)
|
||||||
|
return Equals(fate1, fate2);
|
||||||
|
|
||||||
|
return fate1.Equals(fate2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Fate fate1, Fate fate2) => !(fate1 == fate2);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this Fate is still valid in memory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fate">The fate to check.</param>
|
||||||
|
/// <returns>True or false.</returns>
|
||||||
|
public static bool IsValid(Fate fate)
|
||||||
|
{
|
||||||
|
if (fate == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (fate.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<Fate>.Equals(Fate other) => this.FateId == other?.FateId;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool Equals(object obj) => ((IEquatable<Fate>)this).Equals(obj as Fate);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override int GetHashCode() => this.FateId.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class represents an FFXIV Fate.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe partial class Fate
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Fate ID of this <see cref="Fate" />.
|
||||||
|
/// </summary>
|
||||||
|
public ushort FateId => *(ushort*)(this.Address + FateOffsets.FateId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets game data linked to this Fate.
|
||||||
|
/// </summary>
|
||||||
|
public Lumina.Excel.GeneratedSheets.Fate GameData => this.Dalamud.Data.GetExcelSheet<Lumina.Excel.GeneratedSheets.Fate>().GetRow(this.FateId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the time this <see cref="Fate"/> started.
|
||||||
|
/// </summary>
|
||||||
|
public int StartTimeEpoch => *(int*)(this.Address + FateOffsets.StartTimeEpoch);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets how long this <see cref="Fate"/> will run.
|
||||||
|
/// </summary>
|
||||||
|
public short Duration => *(short*)(this.Address + FateOffsets.Duration);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the remaining time in seconds for this <see cref="Fate"/>.
|
||||||
|
/// </summary>
|
||||||
|
public long TimeRemaining => this.StartTimeEpoch + this.Duration - DateTimeOffset.Now.ToUnixTimeSeconds();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the displayname of this <see cref="Fate" />.
|
||||||
|
/// </summary>
|
||||||
|
public SeString Name => MemoryHelper.ReadSeString((Utf8String*)(this.Address + FateOffsets.Name));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the state of this <see cref="Fate"/> (Running, Ended, Failed, Preparation, WaitingForEnd).
|
||||||
|
/// </summary>
|
||||||
|
public FateState State => *(FateState*)(this.Address + FateOffsets.State);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the progress amount of this <see cref="Fate"/>.
|
||||||
|
/// </summary>
|
||||||
|
public byte Progress => *(byte*)(this.Address + FateOffsets.Progress);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the level of this <see cref="Fate"/>.
|
||||||
|
/// </summary>
|
||||||
|
public byte Level => *(byte*)(this.Address + FateOffsets.Level);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the position of this <see cref="Fate"/>.
|
||||||
|
/// </summary>
|
||||||
|
public Position3 Position => *(Position3*)(this.Address + FateOffsets.Position);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the territory this <see cref="Fate"/> is located in.
|
||||||
|
/// </summary>
|
||||||
|
public TerritoryTypeResolver TerritoryType => new(*(ushort*)(this.Address + FateOffsets.Territory), this.Dalamud);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Dalamud/Game/ClientState/Fates/Types/FateOffsets.cs
Normal file
21
Dalamud/Game/ClientState/Fates/Types/FateOffsets.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.ClientState.Fates.Types
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Memory offsets for the <see cref="Fate"/> type.
|
||||||
|
/// </summary>
|
||||||
|
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Document the offset usage instead.")]
|
||||||
|
public static class FateOffsets
|
||||||
|
{
|
||||||
|
public const int FateId = 0x18;
|
||||||
|
public const int StartTimeEpoch = 0x20;
|
||||||
|
public const int Duration = 0x28;
|
||||||
|
public const int Name = 0xC0;
|
||||||
|
public const int State = 0x3AC;
|
||||||
|
public const int Progress = 0x3B8;
|
||||||
|
public const int Level = 0x3F9;
|
||||||
|
public const int Position = 0x450;
|
||||||
|
public const int Territory = 0x74E;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
Dalamud/Game/ClientState/Fates/Types/FateState.cs
Normal file
33
Dalamud/Game/ClientState/Fates/Types/FateState.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
namespace Dalamud.Game.ClientState.Fates.Types
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This represents the state of a single Fate.
|
||||||
|
/// </summary>
|
||||||
|
public enum FateState : byte
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The Fate is active.
|
||||||
|
/// </summary>
|
||||||
|
Running = 0x02,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Fate has ended.
|
||||||
|
/// </summary>
|
||||||
|
Ended = 0x04,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The player failed the Fate.
|
||||||
|
/// </summary>
|
||||||
|
Failed = 0x05,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Fate is preparing to run.
|
||||||
|
/// </summary>
|
||||||
|
Preparation = 0x07,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Fate is preparing to end.
|
||||||
|
/// </summary>
|
||||||
|
WaitingForEnd = 0x08,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -86,6 +86,7 @@ namespace Dalamud.Interface.Internal.Windows
|
||||||
Server_OpCode,
|
Server_OpCode,
|
||||||
Address,
|
Address,
|
||||||
Actor_Table,
|
Actor_Table,
|
||||||
|
Fate_Table,
|
||||||
Font_Test,
|
Font_Test,
|
||||||
Party_List,
|
Party_List,
|
||||||
Plugin_IPC,
|
Plugin_IPC,
|
||||||
|
|
@ -177,6 +178,8 @@ namespace Dalamud.Interface.Internal.Windows
|
||||||
this.DrawActorTable();
|
this.DrawActorTable();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DataKind.Fate_Table:
|
||||||
|
this.DrawFateTable();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DataKind.Font_Test:
|
case DataKind.Font_Test:
|
||||||
|
|
@ -373,6 +376,46 @@ namespace Dalamud.Interface.Internal.Windows
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawFateTable()
|
||||||
|
{
|
||||||
|
var stateString = string.Empty;
|
||||||
|
if (this.dalamud.ClientState.Fates.Length == 0)
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted("No fates or data not ready.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stateString += $"FrameworkBase: {this.dalamud.Framework.Address.BaseAddress.ToInt64():X}\n";
|
||||||
|
stateString += $"FateTableLen: {this.dalamud.ClientState.Fates.Length}\n";
|
||||||
|
|
||||||
|
ImGui.TextUnformatted(stateString);
|
||||||
|
|
||||||
|
for (var i = 0; i < this.dalamud.ClientState.Fates.Length; i++)
|
||||||
|
{
|
||||||
|
var fate = this.dalamud.ClientState.Fates[i];
|
||||||
|
if (fate == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var fateString = $"{fate.Address.ToInt64():X}:[{i}]" +
|
||||||
|
$" - Lv.{fate.Level} {fate.Name} ({fate.Progress}%)" +
|
||||||
|
$" - X{fate.Position.X} Y{fate.Position.Y} Z{fate.Position.Z}" +
|
||||||
|
$" - Territory {(this.resolveGameData ? (fate.TerritoryType.GameData?.Name ?? fate.TerritoryType.Id.ToString()) : fate.TerritoryType.Id.ToString())}\n";
|
||||||
|
|
||||||
|
fateString += $" StartTimeEpoch: {fate.StartTimeEpoch}" +
|
||||||
|
$" - Duration: {fate.Duration}" +
|
||||||
|
$" - State: {fate.State}" +
|
||||||
|
$" - GameData name: {(this.resolveGameData ? (fate.GameData?.Name ?? fate.FateId.ToString()) : fate.FateId.ToString())}";
|
||||||
|
|
||||||
|
ImGui.TextUnformatted(fateString);
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGui.Button("C"))
|
||||||
|
{
|
||||||
|
ImGui.SetClipboardText(fate.Address.ToString("X"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawFontTest()
|
private void DrawFontTest()
|
||||||
{
|
{
|
||||||
var specialChars = string.Empty;
|
var specialChars = string.Empty;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Text;
|
||||||
|
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using Dalamud.Memory.Exceptions;
|
using Dalamud.Memory.Exceptions;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.System.String;
|
||||||
using static Dalamud.NativeFunctions;
|
using static Dalamud.NativeFunctions;
|
||||||
|
|
||||||
// Heavily inspired from Reloaded (https://github.com/Reloaded-Project/Reloaded.Memory)
|
// Heavily inspired from Reloaded (https://github.com/Reloaded-Project/Reloaded.Memory)
|
||||||
|
|
@ -237,6 +237,25 @@ namespace Dalamud.Memory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read an SeString from a specified Utf8String structure.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="utf8String">The memory address to read from.</param>
|
||||||
|
/// <returns>The read in string.</returns>
|
||||||
|
public static unsafe SeString ReadSeString(Utf8String* utf8String)
|
||||||
|
{
|
||||||
|
if (utf8String == null)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var ptr = utf8String->StringPtr;
|
||||||
|
if (ptr == null)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var len = Math.Max(utf8String->BufUsed, utf8String->StringLength);
|
||||||
|
|
||||||
|
return ReadSeString((IntPtr)ptr, (int)len);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region ReadString(out)
|
#region ReadString(out)
|
||||||
|
|
@ -306,6 +325,14 @@ namespace Dalamud.Memory
|
||||||
public static void ReadSeString(IntPtr memoryAddress, int maxLength, out SeString value)
|
public static void ReadSeString(IntPtr memoryAddress, int maxLength, out SeString value)
|
||||||
=> value = ReadSeString(memoryAddress, maxLength);
|
=> value = ReadSeString(memoryAddress, maxLength);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read an SeString from a specified Utf8String structure.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="utf8String">The memory address to read from.</param>
|
||||||
|
/// <param name="value">The read in string.</param>
|
||||||
|
public static unsafe void ReadSeString(Utf8String* utf8String, out SeString value)
|
||||||
|
=> value = ReadSeString(utf8String);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Write
|
#region Write
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue