mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-01-03 14:23:40 +01:00
Add AtkUnitBasePtr
This commit is contained in:
parent
b425ee0a2a
commit
33166804c1
6 changed files with 171 additions and 49 deletions
|
|
@ -1,8 +1,4 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
|
||||
using Dalamud.Memory;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using Dalamud.Game.Gui.NativeWrapper;
|
||||
|
||||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
|
|
@ -17,7 +13,6 @@ public abstract unsafe class AddonArgs
|
|||
public const string InvalidAddon = "NullAddon";
|
||||
|
||||
private string? addonName;
|
||||
private IntPtr addon;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the addon this args referrers to.
|
||||
|
|
@ -27,10 +22,10 @@ public abstract unsafe class AddonArgs
|
|||
/// <summary>
|
||||
/// Gets the pointer to the addons AtkUnitBase.
|
||||
/// </summary>
|
||||
public nint Addon
|
||||
public AtkUnitBasePtr Addon
|
||||
{
|
||||
get => this.AddonInternal;
|
||||
init => this.AddonInternal = value;
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -38,22 +33,6 @@ public abstract unsafe class AddonArgs
|
|||
/// </summary>
|
||||
public abstract AddonArgsType Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the pointer to the addons AtkUnitBase.
|
||||
/// </summary>
|
||||
internal nint AddonInternal
|
||||
{
|
||||
get => this.addon;
|
||||
set
|
||||
{
|
||||
this.addon = value;
|
||||
|
||||
// Note: always clear addonName on updating the addon being pointed.
|
||||
// Same address may point to a different addon.
|
||||
this.addonName = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if addon name matches the given span of char.
|
||||
/// </summary>
|
||||
|
|
@ -61,19 +40,18 @@ public abstract unsafe class AddonArgs
|
|||
/// <returns>Whether it is the case.</returns>
|
||||
internal bool IsAddon(ReadOnlySpan<char> name)
|
||||
{
|
||||
if (this.Addon == nint.Zero) return false;
|
||||
if (name.Length is 0 or > 0x20)
|
||||
if (this.Addon.IsNull)
|
||||
return false;
|
||||
|
||||
var addonPointer = (AtkUnitBase*)this.Addon;
|
||||
if (addonPointer->Name[0] == 0) return false;
|
||||
if (name.Length is 0 or > 32)
|
||||
return false;
|
||||
|
||||
// note: might want to rewrite this to just compare to NameString
|
||||
return MemoryHelper.EqualsZeroTerminatedString(
|
||||
name,
|
||||
(nint)Unsafe.AsPointer(ref addonPointer->Name[0]),
|
||||
null,
|
||||
0x20);
|
||||
var addonName = this.Addon.Name;
|
||||
|
||||
if (string.IsNullOrEmpty(addonName))
|
||||
return false;
|
||||
|
||||
return name == addonName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -82,11 +60,13 @@ public abstract unsafe class AddonArgs
|
|||
/// <returns>The name of the addon for this object. <see cref="InvalidAddon"/> when invalid.</returns>
|
||||
private string GetAddonName()
|
||||
{
|
||||
if (this.Addon == nint.Zero) return InvalidAddon;
|
||||
if (this.Addon.IsNull) return InvalidAddon;
|
||||
|
||||
var addonPointer = (AtkUnitBase*)this.Addon;
|
||||
if (addonPointer->Name[0] == 0) return InvalidAddon;
|
||||
var name = this.Addon.Name;
|
||||
|
||||
return this.addonName ??= addonPointer->NameString;
|
||||
if (string.IsNullOrEmpty(name))
|
||||
return InvalidAddon;
|
||||
|
||||
return this.addonName ??= name;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
|||
using System.Runtime.CompilerServices;
|
||||
|
||||
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
using Dalamud.Game.Gui.NativeWrapper;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Hooking.Internal;
|
||||
using Dalamud.IoC;
|
||||
|
|
@ -238,7 +239,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
}
|
||||
|
||||
using var returner = this.argsPool.Rent(out AddonSetupArgs arg);
|
||||
arg.AddonInternal = (nint)addon;
|
||||
arg.Addon = (nint)addon;
|
||||
arg.AtkValueCount = valueCount;
|
||||
arg.AtkValues = (nint)values;
|
||||
this.InvokeListenersSafely(AddonEvent.PreSetup, arg);
|
||||
|
|
@ -270,7 +271,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
}
|
||||
|
||||
using var returner = this.argsPool.Rent(out AddonFinalizeArgs arg);
|
||||
arg.AddonInternal = (nint)atkUnitBase[0];
|
||||
arg.Addon = (nint)atkUnitBase[0];
|
||||
this.InvokeListenersSafely(AddonEvent.PreFinalize, arg);
|
||||
|
||||
try
|
||||
|
|
@ -286,7 +287,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
private void OnAddonDraw(AtkUnitBase* addon)
|
||||
{
|
||||
using var returner = this.argsPool.Rent(out AddonDrawArgs arg);
|
||||
arg.AddonInternal = (nint)addon;
|
||||
arg.Addon = (nint)addon;
|
||||
this.InvokeListenersSafely(AddonEvent.PreDraw, arg);
|
||||
|
||||
try
|
||||
|
|
@ -304,7 +305,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
private void OnAddonUpdate(AtkUnitBase* addon, float delta)
|
||||
{
|
||||
using var returner = this.argsPool.Rent(out AddonUpdateArgs arg);
|
||||
arg.AddonInternal = (nint)addon;
|
||||
arg.Addon = (nint)addon;
|
||||
arg.TimeDeltaInternal = delta;
|
||||
this.InvokeListenersSafely(AddonEvent.PreUpdate, arg);
|
||||
|
||||
|
|
@ -325,7 +326,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
var result = false;
|
||||
|
||||
using var returner = this.argsPool.Rent(out AddonRefreshArgs arg);
|
||||
arg.AddonInternal = (nint)addon;
|
||||
arg.Addon = (nint)addon;
|
||||
arg.AtkValueCount = valueCount;
|
||||
arg.AtkValues = (nint)values;
|
||||
this.InvokeListenersSafely(AddonEvent.PreRefresh, arg);
|
||||
|
|
@ -348,7 +349,7 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
|||
private void OnRequestedUpdate(AtkUnitBase* addon, NumberArrayData** numberArrayData, StringArrayData** stringArrayData)
|
||||
{
|
||||
using var returner = this.argsPool.Rent(out AddonRequestedUpdateArgs arg);
|
||||
arg.AddonInternal = (nint)addon;
|
||||
arg.Addon = (nint)addon;
|
||||
arg.NumberArrayData = (nint)numberArrayData;
|
||||
arg.StringArrayData = (nint)stringArrayData;
|
||||
this.InvokeListenersSafely(AddonEvent.PreRequestedUpdate, arg);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
using Dalamud.Hooking;
|
||||
|
|
@ -86,7 +86,7 @@ internal unsafe class AddonLifecycleReceiveEventListener : IDisposable
|
|||
}
|
||||
|
||||
using var returner = this.argsPool.Rent(out AddonReceiveEventArgs arg);
|
||||
arg.AddonInternal = (nint)addon;
|
||||
arg.Addon = (nint)addon;
|
||||
arg.AtkEventType = (byte)eventType;
|
||||
arg.EventParam = eventParam;
|
||||
arg.AtkEvent = (IntPtr)atkEvent;
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
|||
|
||||
private void FixCollision(AddonEvent eventType, AddonArgs addonInfo)
|
||||
{
|
||||
var addon = (AtkUnitBase*)addonInfo.Addon;
|
||||
var addon = addonInfo.Addon.Struct;
|
||||
if (addon->RootNode is null || addon->UldManager.NodeList is null) return;
|
||||
|
||||
float minX = addon->RootNode->Width;
|
||||
|
|
|
|||
141
Dalamud/Game/Gui/NativeWrapper/AtkUnitBasePtr.cs
Normal file
141
Dalamud/Game/Gui/NativeWrapper/AtkUnitBasePtr.cs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
using FFXIVClientStructs.Interop;
|
||||
|
||||
namespace Dalamud.Game.Gui.NativeWrapper;
|
||||
|
||||
/// <summary>
|
||||
/// A wrapper for AtkUnitBase.
|
||||
/// </summary>
|
||||
/// <param name="address">The address to the AtkUnitBase.</param>
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x08)]
|
||||
public readonly unsafe struct AtkUnitBasePtr(nint address) : IEquatable<AtkUnitBasePtr>
|
||||
{
|
||||
/// <summary>
|
||||
/// The address to the AtkUnitBase.
|
||||
/// </summary>
|
||||
[FieldOffset(0x00)]
|
||||
public readonly nint Address = address;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the underlying pointer is a nullptr.
|
||||
/// </summary>
|
||||
public readonly bool IsNull => this.Address == 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the OnSetup function of the AtkUnitBase has been called.
|
||||
/// </summary>
|
||||
public readonly bool IsReady => !this.IsNull && this.Struct->IsReady;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the AtkUnitBase is visible.
|
||||
/// </summary>
|
||||
public readonly bool IsVisible => !this.IsNull && this.Struct->IsVisible;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly string Name => this.IsNull ? string.Empty : this.Struct->NameString;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the id of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly ushort Id => this.IsNull ? (ushort)0 : this.Struct->Id;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent id of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly ushort ParentId => this.IsNull ? (ushort)0 : this.Struct->ParentId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the host id of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly ushort HostId => this.IsNull ? (ushort)0 : this.Struct->HostId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scale of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly float Scale => this.IsNull ? 0f : this.Struct->Scale;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the x-position of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly short X => this.IsNull ? (short)0 : this.Struct->X;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the y-position of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly short Y => this.IsNull ? (short)0 : this.Struct->Y;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the width of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly float Width => this.IsNull ? 0f : this.Struct->GetScaledWidth(false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly float Height => this.IsNull ? 0f : this.Struct->GetScaledHeight(false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scaled width of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly float ScaledWidth => this.IsNull ? 0f : this.Struct->GetScaledWidth(true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scaled height of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly float ScaledHeight => this.IsNull ? 0f : this.Struct->GetScaledHeight(true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly Vector2 Position => new(this.X, this.Y);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the size of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly Vector2 Size => new(this.Width, this.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scaled size of the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly Vector2 ScaledSize => new(this.ScaledWidth, this.ScaledHeight);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the AtkUnitBase*.
|
||||
/// </summary>
|
||||
/// <remarks> Internal use only. </remarks>
|
||||
internal readonly AtkUnitBase* Struct => (AtkUnitBase*)this.Address;
|
||||
|
||||
public static implicit operator nint(AtkUnitBasePtr wrapper) => wrapper.Address;
|
||||
|
||||
public static implicit operator AtkUnitBasePtr(nint address) => new(address);
|
||||
|
||||
public static bool operator ==(AtkUnitBasePtr left, AtkUnitBasePtr right) => left.Address == right.Address;
|
||||
|
||||
public static bool operator !=(AtkUnitBasePtr left, AtkUnitBasePtr right) => left.Address != right.Address;
|
||||
|
||||
/// <summary>
|
||||
/// Focuses the AtkUnitBase.
|
||||
/// </summary>
|
||||
public readonly void Focus()
|
||||
{
|
||||
if (!this.IsNull)
|
||||
this.Struct->Focus();
|
||||
}
|
||||
|
||||
/// <summary>Determines whether the specified AtkUnitBasePtr is equal to the current AtkUnitBasePtr.</summary>
|
||||
/// <param name="other">The AtkUnitBasePtr to compare with the current AtkUnitBasePtr.</param>
|
||||
/// <returns><c>true</c> if the specified AtkUnitBasePtr is equal to the current AtkUnitBasePtr; otherwise, <c>false</c>.</returns>
|
||||
public readonly bool Equals(AtkUnitBasePtr other) => this.Address == other.Address;
|
||||
|
||||
/// <inheritdoc cref="object.Equals(object?)"/>
|
||||
public override readonly bool Equals(object obj) => obj is AtkUnitBasePtr wrapper && this.Equals(wrapper);
|
||||
|
||||
/// <inheritdoc cref="object.GetHashCode()"/>
|
||||
public override readonly int GetHashCode() => ((nuint)this.Address).GetHashCode();
|
||||
}
|
||||
|
|
@ -477,7 +477,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
|
|||
{
|
||||
if (args is not AddonDrawArgs drawArgs) return;
|
||||
|
||||
var addon = (AtkUnitBase*)drawArgs.Addon;
|
||||
var addon = drawArgs.Addon.Struct;
|
||||
var textNode = addon->GetTextNodeById(3);
|
||||
|
||||
// look and feel init. should be harmless to set.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue