mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
[Api13] Add native wrapper structs (#2330)
This commit is contained in:
parent
b425ee0a2a
commit
57c6089fc1
23 changed files with 682 additions and 149 deletions
|
|
@ -140,7 +140,7 @@ internal unsafe class PluginEventController : IDisposable
|
||||||
if (currentAddonPointer != eventEntry.Addon) return;
|
if (currentAddonPointer != eventEntry.Addon) return;
|
||||||
|
|
||||||
// Make sure the addon is not unloaded
|
// Make sure the addon is not unloaded
|
||||||
var atkUnitBase = (AtkUnitBase*)currentAddonPointer;
|
var atkUnitBase = currentAddonPointer.Struct;
|
||||||
if (atkUnitBase->UldManager.LoadedState == AtkLoadState.Unloaded) return;
|
if (atkUnitBase->UldManager.LoadedState == AtkLoadState.Unloaded) return;
|
||||||
|
|
||||||
// Does this addon contain the node this event is for? (by address)
|
// Does this addon contain the node this event is for? (by address)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,4 @@
|
||||||
using System.Runtime.CompilerServices;
|
using Dalamud.Game.NativeWrapper;
|
||||||
|
|
||||||
using Dalamud.Memory;
|
|
||||||
|
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
|
||||||
|
|
||||||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||||
|
|
||||||
|
|
@ -17,7 +13,6 @@ public abstract unsafe class AddonArgs
|
||||||
public const string InvalidAddon = "NullAddon";
|
public const string InvalidAddon = "NullAddon";
|
||||||
|
|
||||||
private string? addonName;
|
private string? addonName;
|
||||||
private IntPtr addon;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the addon this args referrers to.
|
/// Gets the name of the addon this args referrers to.
|
||||||
|
|
@ -27,10 +22,10 @@ public abstract unsafe class AddonArgs
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the pointer to the addons AtkUnitBase.
|
/// Gets the pointer to the addons AtkUnitBase.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public nint Addon
|
public AtkUnitBasePtr Addon
|
||||||
{
|
{
|
||||||
get => this.AddonInternal;
|
get;
|
||||||
init => this.AddonInternal = value;
|
internal set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -38,22 +33,6 @@ public abstract unsafe class AddonArgs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract AddonArgsType Type { get; }
|
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>
|
/// <summary>
|
||||||
/// Checks if addon name matches the given span of char.
|
/// Checks if addon name matches the given span of char.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -61,19 +40,27 @@ public abstract unsafe class AddonArgs
|
||||||
/// <returns>Whether it is the case.</returns>
|
/// <returns>Whether it is the case.</returns>
|
||||||
internal bool IsAddon(ReadOnlySpan<char> name)
|
internal bool IsAddon(ReadOnlySpan<char> name)
|
||||||
{
|
{
|
||||||
if (this.Addon == nint.Zero) return false;
|
if (this.Addon.IsNull)
|
||||||
if (name.Length is 0 or > 0x20)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var addonPointer = (AtkUnitBase*)this.Addon;
|
if (name.Length is 0 or > 32)
|
||||||
if (addonPointer->Name[0] == 0) return false;
|
return false;
|
||||||
|
|
||||||
// note: might want to rewrite this to just compare to NameString
|
var addonName = this.Addon.Name;
|
||||||
return MemoryHelper.EqualsZeroTerminatedString(
|
|
||||||
name,
|
if (string.IsNullOrEmpty(addonName))
|
||||||
(nint)Unsafe.AsPointer(ref addonPointer->Name[0]),
|
return false;
|
||||||
null,
|
|
||||||
0x20);
|
return name == addonName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears this AddonArgs values.
|
||||||
|
/// </summary>
|
||||||
|
internal virtual void Clear()
|
||||||
|
{
|
||||||
|
this.addonName = null;
|
||||||
|
this.Addon = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -82,11 +69,13 @@ public abstract unsafe class AddonArgs
|
||||||
/// <returns>The name of the addon for this object. <see cref="InvalidAddon"/> when invalid.</returns>
|
/// <returns>The name of the addon for this object. <see cref="InvalidAddon"/> when invalid.</returns>
|
||||||
private string GetAddonName()
|
private string GetAddonName()
|
||||||
{
|
{
|
||||||
if (this.Addon == nint.Zero) return InvalidAddon;
|
if (this.Addon.IsNull) return InvalidAddon;
|
||||||
|
|
||||||
var addonPointer = (AtkUnitBase*)this.Addon;
|
var name = this.Addon.Name;
|
||||||
if (addonPointer->Name[0] == 0) return InvalidAddon;
|
|
||||||
|
|
||||||
return this.addonName ??= addonPointer->NameString;
|
if (string.IsNullOrEmpty(name))
|
||||||
|
return InvalidAddon;
|
||||||
|
|
||||||
|
return this.addonName ??= name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,4 +41,14 @@ public class AddonReceiveEventArgs : AddonArgs, ICloneable
|
||||||
|
|
||||||
/// <inheritdoc cref="Clone"/>
|
/// <inheritdoc cref="Clone"/>
|
||||||
object ICloneable.Clone() => this.Clone();
|
object ICloneable.Clone() => this.Clone();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="AddonArgs.Clear"/>
|
||||||
|
internal override void Clear()
|
||||||
|
{
|
||||||
|
base.Clear();
|
||||||
|
this.AtkEventType = default;
|
||||||
|
this.EventParam = default;
|
||||||
|
this.AtkEvent = default;
|
||||||
|
this.Data = default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,4 +38,12 @@ public class AddonRefreshArgs : AddonArgs, ICloneable
|
||||||
|
|
||||||
/// <inheritdoc cref="Clone"/>
|
/// <inheritdoc cref="Clone"/>
|
||||||
object ICloneable.Clone() => this.Clone();
|
object ICloneable.Clone() => this.Clone();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="AddonArgs.Clear"/>
|
||||||
|
internal override void Clear()
|
||||||
|
{
|
||||||
|
base.Clear();
|
||||||
|
this.AtkValueCount = default;
|
||||||
|
this.AtkValues = default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Addon argument data for OnRequestedUpdate events.
|
/// Addon argument data for OnRequestedUpdate events.
|
||||||
|
|
@ -31,4 +31,12 @@ public class AddonRequestedUpdateArgs : AddonArgs, ICloneable
|
||||||
|
|
||||||
/// <inheritdoc cref="Clone"/>
|
/// <inheritdoc cref="Clone"/>
|
||||||
object ICloneable.Clone() => this.Clone();
|
object ICloneable.Clone() => this.Clone();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="AddonArgs.Clear"/>
|
||||||
|
internal override void Clear()
|
||||||
|
{
|
||||||
|
base.Clear();
|
||||||
|
this.NumberArrayData = default;
|
||||||
|
this.StringArrayData = default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
|
||||||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||||
|
|
||||||
|
|
@ -38,4 +38,12 @@ public class AddonSetupArgs : AddonArgs, ICloneable
|
||||||
|
|
||||||
/// <inheritdoc cref="Clone"/>
|
/// <inheritdoc cref="Clone"/>
|
||||||
object ICloneable.Clone() => this.Clone();
|
object ICloneable.Clone() => this.Clone();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="AddonArgs.Clear"/>
|
||||||
|
internal override void Clear()
|
||||||
|
{
|
||||||
|
base.Clear();
|
||||||
|
this.AtkValueCount = default;
|
||||||
|
this.AtkValues = default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,4 +35,11 @@ public class AddonUpdateArgs : AddonArgs, ICloneable
|
||||||
|
|
||||||
/// <inheritdoc cref="Clone"/>
|
/// <inheritdoc cref="Clone"/>
|
||||||
object ICloneable.Clone() => this.Clone();
|
object ICloneable.Clone() => this.Clone();
|
||||||
|
|
||||||
|
/// <inheritdoc cref="AddonArgs.Clear"/>
|
||||||
|
internal override void Clear()
|
||||||
|
{
|
||||||
|
base.Clear();
|
||||||
|
this.TimeDeltaInternal = default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
||||||
}
|
}
|
||||||
|
|
||||||
using var returner = this.argsPool.Rent(out AddonSetupArgs arg);
|
using var returner = this.argsPool.Rent(out AddonSetupArgs arg);
|
||||||
arg.AddonInternal = (nint)addon;
|
arg.Clear();
|
||||||
|
arg.Addon = (nint)addon;
|
||||||
arg.AtkValueCount = valueCount;
|
arg.AtkValueCount = valueCount;
|
||||||
arg.AtkValues = (nint)values;
|
arg.AtkValues = (nint)values;
|
||||||
this.InvokeListenersSafely(AddonEvent.PreSetup, arg);
|
this.InvokeListenersSafely(AddonEvent.PreSetup, arg);
|
||||||
|
|
@ -270,7 +271,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
||||||
}
|
}
|
||||||
|
|
||||||
using var returner = this.argsPool.Rent(out AddonFinalizeArgs arg);
|
using var returner = this.argsPool.Rent(out AddonFinalizeArgs arg);
|
||||||
arg.AddonInternal = (nint)atkUnitBase[0];
|
arg.Clear();
|
||||||
|
arg.Addon = (nint)atkUnitBase[0];
|
||||||
this.InvokeListenersSafely(AddonEvent.PreFinalize, arg);
|
this.InvokeListenersSafely(AddonEvent.PreFinalize, arg);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -286,7 +288,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
||||||
private void OnAddonDraw(AtkUnitBase* addon)
|
private void OnAddonDraw(AtkUnitBase* addon)
|
||||||
{
|
{
|
||||||
using var returner = this.argsPool.Rent(out AddonDrawArgs arg);
|
using var returner = this.argsPool.Rent(out AddonDrawArgs arg);
|
||||||
arg.AddonInternal = (nint)addon;
|
arg.Clear();
|
||||||
|
arg.Addon = (nint)addon;
|
||||||
this.InvokeListenersSafely(AddonEvent.PreDraw, arg);
|
this.InvokeListenersSafely(AddonEvent.PreDraw, arg);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -304,7 +307,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
||||||
private void OnAddonUpdate(AtkUnitBase* addon, float delta)
|
private void OnAddonUpdate(AtkUnitBase* addon, float delta)
|
||||||
{
|
{
|
||||||
using var returner = this.argsPool.Rent(out AddonUpdateArgs arg);
|
using var returner = this.argsPool.Rent(out AddonUpdateArgs arg);
|
||||||
arg.AddonInternal = (nint)addon;
|
arg.Clear();
|
||||||
|
arg.Addon = (nint)addon;
|
||||||
arg.TimeDeltaInternal = delta;
|
arg.TimeDeltaInternal = delta;
|
||||||
this.InvokeListenersSafely(AddonEvent.PreUpdate, arg);
|
this.InvokeListenersSafely(AddonEvent.PreUpdate, arg);
|
||||||
|
|
||||||
|
|
@ -325,7 +329,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
||||||
var result = false;
|
var result = false;
|
||||||
|
|
||||||
using var returner = this.argsPool.Rent(out AddonRefreshArgs arg);
|
using var returner = this.argsPool.Rent(out AddonRefreshArgs arg);
|
||||||
arg.AddonInternal = (nint)addon;
|
arg.Clear();
|
||||||
|
arg.Addon = (nint)addon;
|
||||||
arg.AtkValueCount = valueCount;
|
arg.AtkValueCount = valueCount;
|
||||||
arg.AtkValues = (nint)values;
|
arg.AtkValues = (nint)values;
|
||||||
this.InvokeListenersSafely(AddonEvent.PreRefresh, arg);
|
this.InvokeListenersSafely(AddonEvent.PreRefresh, arg);
|
||||||
|
|
@ -348,7 +353,8 @@ internal unsafe class AddonLifecycle : IInternalDisposableService
|
||||||
private void OnRequestedUpdate(AtkUnitBase* addon, NumberArrayData** numberArrayData, StringArrayData** stringArrayData)
|
private void OnRequestedUpdate(AtkUnitBase* addon, NumberArrayData** numberArrayData, StringArrayData** stringArrayData)
|
||||||
{
|
{
|
||||||
using var returner = this.argsPool.Rent(out AddonRequestedUpdateArgs arg);
|
using var returner = this.argsPool.Rent(out AddonRequestedUpdateArgs arg);
|
||||||
arg.AddonInternal = (nint)addon;
|
arg.Clear();
|
||||||
|
arg.Addon = (nint)addon;
|
||||||
arg.NumberArrayData = (nint)numberArrayData;
|
arg.NumberArrayData = (nint)numberArrayData;
|
||||||
arg.StringArrayData = (nint)stringArrayData;
|
arg.StringArrayData = (nint)stringArrayData;
|
||||||
this.InvokeListenersSafely(AddonEvent.PreRequestedUpdate, arg);
|
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.Game.Addon.Lifecycle.AddonArgTypes;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
|
|
@ -86,7 +86,8 @@ internal unsafe class AddonLifecycleReceiveEventListener : IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
using var returner = this.argsPool.Rent(out AddonReceiveEventArgs arg);
|
using var returner = this.argsPool.Rent(out AddonReceiveEventArgs arg);
|
||||||
arg.AddonInternal = (nint)addon;
|
arg.Clear();
|
||||||
|
arg.Addon = (nint)addon;
|
||||||
arg.AtkEventType = (byte)eventType;
|
arg.AtkEventType = (byte)eventType;
|
||||||
arg.EventParam = eventParam;
|
arg.EventParam = eventParam;
|
||||||
arg.AtkEvent = (IntPtr)atkEvent;
|
arg.AtkEvent = (IntPtr)atkEvent;
|
||||||
|
|
|
||||||
|
|
@ -330,7 +330,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
||||||
this.entriesReadOnlyCopy = null;
|
this.entriesReadOnlyCopy = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AtkUnitBase* GetDtr() => (AtkUnitBase*)this.gameGui.GetAddonByName("_DTR").ToPointer();
|
private AtkUnitBase* GetDtr() => this.gameGui.GetAddonByName("_DTR").Struct;
|
||||||
|
|
||||||
private void Update(IFramework unused)
|
private void Update(IFramework unused)
|
||||||
{
|
{
|
||||||
|
|
@ -427,7 +427,7 @@ internal sealed unsafe class DtrBar : IInternalDisposableService, IDtrBar
|
||||||
|
|
||||||
private void FixCollision(AddonEvent eventType, AddonArgs addonInfo)
|
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;
|
if (addon->RootNode is null || addon->UldManager.NodeList is null) return;
|
||||||
|
|
||||||
float minX = addon->RootNode->Width;
|
float minX = addon->RootNode->Width;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using Dalamud.Game.NativeWrapper;
|
||||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
|
|
@ -167,79 +168,59 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr GetUIModule()
|
public UIModulePtr GetUIModule()
|
||||||
{
|
{
|
||||||
var framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance();
|
return (nint)UIModule.Instance();
|
||||||
if (framework == null)
|
|
||||||
return IntPtr.Zero;
|
|
||||||
|
|
||||||
var uiModule = framework->GetUIModule();
|
|
||||||
if (uiModule == null)
|
|
||||||
return IntPtr.Zero;
|
|
||||||
|
|
||||||
return (IntPtr)uiModule;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr GetAddonByName(string name, int index = 1)
|
public AtkUnitBasePtr GetAddonByName(string name, int index = 1)
|
||||||
{
|
{
|
||||||
var atkStage = AtkStage.Instance();
|
var unitManager = RaptureAtkUnitManager.Instance();
|
||||||
if (atkStage == null)
|
if (unitManager == null)
|
||||||
return IntPtr.Zero;
|
return 0;
|
||||||
|
|
||||||
var unitMgr = atkStage->RaptureAtkUnitManager;
|
return (nint)unitManager->GetAddonByName(name, index);
|
||||||
if (unitMgr == null)
|
|
||||||
return IntPtr.Zero;
|
|
||||||
|
|
||||||
var addon = unitMgr->GetAddonByName(name, index);
|
|
||||||
if (addon == null)
|
|
||||||
return IntPtr.Zero;
|
|
||||||
|
|
||||||
return (IntPtr)addon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr FindAgentInterface(string addonName)
|
public AgentInterfacePtr GetAgentById(int id)
|
||||||
|
{
|
||||||
|
var agentModule = AgentModule.Instance();
|
||||||
|
if (agentModule == null || id < 0 || id >= agentModule->Agents.Length)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (nint)agentModule->Agents[id].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AgentInterfacePtr FindAgentInterface(string addonName)
|
||||||
{
|
{
|
||||||
var addon = this.GetAddonByName(addonName);
|
var addon = this.GetAddonByName(addonName);
|
||||||
return this.FindAgentInterface(addon);
|
return this.FindAgentInterface(addon);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr FindAgentInterface(void* addon) => this.FindAgentInterface((IntPtr)addon);
|
public AgentInterfacePtr FindAgentInterface(AtkUnitBasePtr addon)
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public IntPtr FindAgentInterface(IntPtr addonPtr)
|
|
||||||
{
|
{
|
||||||
if (addonPtr == IntPtr.Zero)
|
if (addon.IsNull)
|
||||||
return IntPtr.Zero;
|
return 0;
|
||||||
|
|
||||||
var uiModule = (UIModule*)this.GetUIModule();
|
var agentModule = AgentModule.Instance();
|
||||||
if (uiModule == null)
|
|
||||||
return IntPtr.Zero;
|
|
||||||
|
|
||||||
var agentModule = uiModule->GetAgentModule();
|
|
||||||
if (agentModule == null)
|
if (agentModule == null)
|
||||||
return IntPtr.Zero;
|
return 0;
|
||||||
|
|
||||||
var addon = (AtkUnitBase*)addonPtr;
|
|
||||||
var addonId = addon->ParentId == 0 ? addon->Id : addon->ParentId;
|
|
||||||
|
|
||||||
|
var addonId = addon.ParentId == 0 ? addon.Id : addon.ParentId;
|
||||||
if (addonId == 0)
|
if (addonId == 0)
|
||||||
return IntPtr.Zero;
|
return 0;
|
||||||
|
|
||||||
var index = 0;
|
foreach (AgentInterface* agent in agentModule->Agents)
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
var agent = agentModule->GetAgentByInternalId((AgentId)index++);
|
if (agent != null && agent->AddonId == addonId)
|
||||||
if (agent == uiModule || agent == null)
|
return (nint)agent;
|
||||||
break;
|
|
||||||
|
|
||||||
if (agent->AddonId == addonId)
|
|
||||||
return new IntPtr(agent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return IntPtr.Zero;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -454,25 +435,25 @@ internal class GameGuiPluginScoped : IInternalDisposableService, IGameGui
|
||||||
=> this.gameGuiService.ScreenToWorld(screenPos, out worldPos, rayDistance);
|
=> this.gameGuiService.ScreenToWorld(screenPos, out worldPos, rayDistance);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr GetUIModule()
|
public UIModulePtr GetUIModule()
|
||||||
=> this.gameGuiService.GetUIModule();
|
=> this.gameGuiService.GetUIModule();
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr GetAddonByName(string name, int index = 1)
|
public AtkUnitBasePtr GetAddonByName(string name, int index = 1)
|
||||||
=> this.gameGuiService.GetAddonByName(name, index);
|
=> this.gameGuiService.GetAddonByName(name, index);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public IntPtr FindAgentInterface(string addonName)
|
public AgentInterfacePtr GetAgentById(int id)
|
||||||
|
=> this.gameGuiService.GetAgentById(id);
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AgentInterfacePtr FindAgentInterface(string addonName)
|
||||||
=> this.gameGuiService.FindAgentInterface(addonName);
|
=> this.gameGuiService.FindAgentInterface(addonName);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public unsafe IntPtr FindAgentInterface(void* addon)
|
public AgentInterfacePtr FindAgentInterface(AtkUnitBasePtr addon)
|
||||||
=> this.gameGuiService.FindAgentInterface(addon);
|
=> this.gameGuiService.FindAgentInterface(addon);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public IntPtr FindAgentInterface(IntPtr addonPtr)
|
|
||||||
=> this.gameGuiService.FindAgentInterface(addonPtr);
|
|
||||||
|
|
||||||
private void UiHideToggledForward(object sender, bool toggled) => this.UiHideToggled?.Invoke(sender, toggled);
|
private void UiHideToggledForward(object sender, bool toggled) => this.UiHideToggled?.Invoke(sender, toggled);
|
||||||
|
|
||||||
private void HoveredItemForward(object sender, ulong itemId) => this.HoveredItemChanged?.Invoke(sender, itemId);
|
private void HoveredItemForward(object sender, ulong itemId) => this.HoveredItemChanged?.Invoke(sender, itemId);
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ internal sealed class NamePlateGui : IInternalDisposableService, INamePlateGui
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public unsafe void RequestRedraw()
|
public unsafe void RequestRedraw()
|
||||||
{
|
{
|
||||||
var addon = (AddonNamePlate*)this.gameGui.GetAddonByName("NamePlate");
|
var addon = (AddonNamePlate*)(nint)this.gameGui.GetAddonByName("NamePlate");
|
||||||
if (addon != null)
|
if (addon != null)
|
||||||
{
|
{
|
||||||
addon->DoFullUpdate = 1;
|
addon->DoFullUpdate = 1;
|
||||||
|
|
|
||||||
96
Dalamud/Game/NativeWrapper/AgentInterfacePtr.cs
Normal file
96
Dalamud/Game/NativeWrapper/AgentInterfacePtr.cs
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.NativeWrapper;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A readonly wrapper for AgentInterface.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">The address to the AgentInterface.</param>
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = 0x08)]
|
||||||
|
public readonly unsafe struct AgentInterfacePtr(nint address) : IEquatable<AgentInterfacePtr>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The address to the AgentInterface.
|
||||||
|
/// </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 agents addon is visible.
|
||||||
|
/// </summary>
|
||||||
|
public readonly AtkUnitBasePtr Addon
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.IsNull)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var raptureAtkUnitManager = RaptureAtkUnitManager.Instance();
|
||||||
|
if (raptureAtkUnitManager == null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (nint)raptureAtkUnitManager->GetAddonById(this.AddonId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the agent is active.
|
||||||
|
/// </summary>
|
||||||
|
public readonly ushort AddonId => (ushort)(this.IsNull ? 0 : this.Struct->GetAddonId());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the agent is active.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool IsAgentActive => !this.IsNull && this.Struct->IsAgentActive();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the agents addon is ready.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool IsAddonReady => !this.IsNull && this.Struct->IsAddonReady();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the agents addon is visible.
|
||||||
|
/// </summary>
|
||||||
|
public readonly bool IsAddonShown => !this.IsNull && this.Struct->IsAddonShown();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the AgentInterface*.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks> Internal use only. </remarks>
|
||||||
|
internal readonly AgentInterface* Struct => (AgentInterface*)this.Address;
|
||||||
|
|
||||||
|
public static implicit operator nint(AgentInterfacePtr wrapper) => wrapper.Address;
|
||||||
|
|
||||||
|
public static implicit operator AgentInterfacePtr(nint address) => new(address);
|
||||||
|
|
||||||
|
public static implicit operator AgentInterfacePtr(void* ptr) => new((nint)ptr);
|
||||||
|
|
||||||
|
public static bool operator ==(AgentInterfacePtr left, AgentInterfacePtr right) => left.Address == right.Address;
|
||||||
|
|
||||||
|
public static bool operator !=(AgentInterfacePtr left, AgentInterfacePtr right) => left.Address != right.Address;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Focuses the AtkUnitBase.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns> <c>true</c> when the addon was focused, <c>false</c> otherwise. </returns>
|
||||||
|
public readonly bool FocusAddon() => this.IsNull && this.Struct->FocusAddon();
|
||||||
|
|
||||||
|
/// <summary>Determines whether the specified AgentInterfacePtr is equal to the current AgentInterfacePtr.</summary>
|
||||||
|
/// <param name="other">The AgentInterfacePtr to compare with the current AgentInterfacePtr.</param>
|
||||||
|
/// <returns><c>true</c> if the specified AgentInterfacePtr is equal to the current AgentInterfacePtr; otherwise, <c>false</c>.</returns>
|
||||||
|
public readonly bool Equals(AgentInterfacePtr other) => this.Address == other.Address;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="object.Equals(object?)"/>
|
||||||
|
public override readonly bool Equals(object obj) => obj is AgentInterfacePtr wrapper && this.Equals(wrapper);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="object.GetHashCode()"/>
|
||||||
|
public override readonly int GetHashCode() => ((nuint)this.Address).GetHashCode();
|
||||||
|
}
|
||||||
171
Dalamud/Game/NativeWrapper/AtkUnitBasePtr.cs
Normal file
171
Dalamud/Game/NativeWrapper/AtkUnitBasePtr.cs
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
using FFXIVClientStructs.Interop;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.NativeWrapper;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A readonly 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 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.
|
||||||
|
/// </summary>
|
||||||
|
public readonly string Name => this.IsNull ? string.Empty : this.Struct->NameString;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the id.
|
||||||
|
/// </summary>
|
||||||
|
public readonly ushort Id => this.IsNull ? (ushort)0 : this.Struct->Id;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the parent id.
|
||||||
|
/// </summary>
|
||||||
|
public readonly ushort ParentId => this.IsNull ? (ushort)0 : this.Struct->ParentId;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the host id.
|
||||||
|
/// </summary>
|
||||||
|
public readonly ushort HostId => this.IsNull ? (ushort)0 : this.Struct->HostId;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the scale.
|
||||||
|
/// </summary>
|
||||||
|
public readonly float Scale => this.IsNull ? 0f : this.Struct->Scale;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the x-position.
|
||||||
|
/// </summary>
|
||||||
|
public readonly short X => this.IsNull ? (short)0 : this.Struct->X;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the y-position.
|
||||||
|
/// </summary>
|
||||||
|
public readonly short Y => this.IsNull ? (short)0 : this.Struct->Y;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the width.
|
||||||
|
/// </summary>
|
||||||
|
public readonly float Width => this.IsNull ? 0f : this.Struct->GetScaledWidth(false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the height.
|
||||||
|
/// </summary>
|
||||||
|
public readonly float Height => this.IsNull ? 0f : this.Struct->GetScaledHeight(false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the scaled width.
|
||||||
|
/// </summary>
|
||||||
|
public readonly float ScaledWidth => this.IsNull ? 0f : this.Struct->GetScaledWidth(true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the scaled height.
|
||||||
|
/// </summary>
|
||||||
|
public readonly float ScaledHeight => this.IsNull ? 0f : this.Struct->GetScaledHeight(true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the position.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Vector2 Position => new(this.X, this.Y);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Vector2 Size => new(this.Width, this.Height);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the scaled size.
|
||||||
|
/// </summary>
|
||||||
|
public readonly Vector2 ScaledSize => new(this.ScaledWidth, this.ScaledHeight);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of <see cref="AtkValue"/> entries.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int AtkValuesCount => this.Struct->AtkValuesCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an enumerable collection of <see cref="AtkValuePtr"/> of the addons current AtkValues.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// An <see cref="IEnumerable{T}"/> of <see cref="AtkValuePtr"/> corresponding to the addons AtkValues.
|
||||||
|
/// </returns>
|
||||||
|
public IEnumerable<AtkValuePtr> AtkValues
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (var i = 0; i < this.AtkValuesCount; i++)
|
||||||
|
{
|
||||||
|
AtkValuePtr ptr;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
ptr = new AtkValuePtr((nint)this.Struct->AtkValuesSpan.GetPointer(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 implicit operator AtkUnitBasePtr(void* ptr) => new((nint)ptr);
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
113
Dalamud/Game/NativeWrapper/AtkValuePtr.cs
Normal file
113
Dalamud/Game/NativeWrapper/AtkValuePtr.cs
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using Dalamud.Utility;
|
||||||
|
|
||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.NativeWrapper;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A readonly wrapper for AtkValue.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">The address to the AtkValue.</param>
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = 0x08)]
|
||||||
|
public readonly unsafe struct AtkValuePtr(nint address) : IEquatable<AtkValuePtr>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The address to the AtkValue.
|
||||||
|
/// </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 the value type.
|
||||||
|
/// </summary>
|
||||||
|
public readonly AtkValueType ValueType => (AtkValueType)this.Struct->Type;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the AtkValue*.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks> Internal use only. </remarks>
|
||||||
|
internal readonly AtkValue* Struct => (AtkValue*)this.Address;
|
||||||
|
|
||||||
|
public static implicit operator nint(AtkValuePtr wrapper) => wrapper.Address;
|
||||||
|
|
||||||
|
public static implicit operator AtkValuePtr(nint address) => new(address);
|
||||||
|
|
||||||
|
public static implicit operator AtkValuePtr(void* ptr) => new((nint)ptr);
|
||||||
|
|
||||||
|
public static bool operator ==(AtkValuePtr left, AtkValuePtr right) => left.Address == right.Address;
|
||||||
|
|
||||||
|
public static bool operator !=(AtkValuePtr left, AtkValuePtr right) => left.Address != right.Address;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of the underlying <see cref="AtkValue"/> as a boxed object, based on its <see cref="AtkValueType"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// The boxed value represented by this <see cref="AtkValuePtr"/>, or <c>null</c> if the value is null or undefined.
|
||||||
|
/// </returns>
|
||||||
|
/// <exception cref="NotImplementedException">
|
||||||
|
/// Thrown if the value type is not currently handled by this implementation.
|
||||||
|
/// </exception>
|
||||||
|
public unsafe object? GetValue()
|
||||||
|
{
|
||||||
|
if (this.Struct == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return this.ValueType switch
|
||||||
|
{
|
||||||
|
AtkValueType.Undefined or AtkValueType.Null => null,
|
||||||
|
AtkValueType.Bool => this.Struct->Bool,
|
||||||
|
AtkValueType.Int => this.Struct->Int,
|
||||||
|
AtkValueType.Int64 => this.Struct->Int64,
|
||||||
|
AtkValueType.UInt => this.Struct->UInt,
|
||||||
|
AtkValueType.UInt64 => this.Struct->UInt64,
|
||||||
|
AtkValueType.Float => this.Struct->Float,
|
||||||
|
AtkValueType.String or AtkValueType.String8 or AtkValueType.ManagedString => this.Struct->String == null ? default : this.Struct->String.AsReadOnlySeString(),
|
||||||
|
AtkValueType.WideString => this.Struct->WideString == null ? string.Empty : new string(this.Struct->WideString),
|
||||||
|
AtkValueType.Pointer => (nint)this.Struct->Pointer,
|
||||||
|
_ => throw new NotImplementedException($"AtkValueType {this.ValueType} is currently not supported"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to retrieve the value as a strongly-typed object if the underlying type matches.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The expected value type to extract.</typeparam>
|
||||||
|
/// <param name="result">
|
||||||
|
/// When this method returns <c>true</c>, contains the extracted value of type <typeparamref name="T"/>.
|
||||||
|
/// Otherwise, contains the default value of type <typeparamref name="T"/>.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if the value was successfully extracted and matched <typeparamref name="T"/>; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public unsafe bool TryGet<T>([NotNullWhen(true)] out T? result) where T : struct
|
||||||
|
{
|
||||||
|
object? value = this.GetValue();
|
||||||
|
if (value is T typed)
|
||||||
|
{
|
||||||
|
result = typed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Determines whether the specified AtkValuePtr is equal to the current AtkValuePtr.</summary>
|
||||||
|
/// <param name="other">The AtkValuePtr to compare with the current AtkValuePtr.</param>
|
||||||
|
/// <returns><c>true</c> if the specified AtkValuePtr is equal to the current AtkValuePtr; otherwise, <c>false</c>.</returns>
|
||||||
|
public readonly bool Equals(AtkValuePtr other) => this.Address == other.Address || this.Struct->EqualTo(other.Struct);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="object.Equals(object?)"/>
|
||||||
|
public override readonly bool Equals(object obj) => obj is AtkValuePtr wrapper && this.Equals(wrapper);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="object.GetHashCode()"/>
|
||||||
|
public override readonly int GetHashCode() => ((nuint)this.Address).GetHashCode();
|
||||||
|
}
|
||||||
87
Dalamud/Game/NativeWrapper/AtkValueType.cs
Normal file
87
Dalamud/Game/NativeWrapper/AtkValueType.cs
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
namespace Dalamud.Game.NativeWrapper;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the data type of the AtkValue.
|
||||||
|
/// </summary>
|
||||||
|
public enum AtkValueType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The value is undefined or invalid.
|
||||||
|
/// </summary>
|
||||||
|
Undefined = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is null.
|
||||||
|
/// </summary>
|
||||||
|
Null = 0x1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is a boolean.
|
||||||
|
/// </summary>
|
||||||
|
Bool = 0x2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is a 32-bit signed integer.
|
||||||
|
/// </summary>
|
||||||
|
Int = 0x3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is a 64-bit signed integer.
|
||||||
|
/// </summary>
|
||||||
|
Int64 = 0x4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is a 32-bit unsigned integer.
|
||||||
|
/// </summary>
|
||||||
|
UInt = 0x5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is a 64-bit unsigned integer.
|
||||||
|
/// </summary>
|
||||||
|
UInt64 = 0x6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is a 32-bit floating-point number.
|
||||||
|
/// </summary>
|
||||||
|
Float = 0x7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value points to a null-terminated 8-bit character string (ASCII or UTF-8).
|
||||||
|
/// </summary>
|
||||||
|
String = 0x8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value points to a null-terminated 16-bit character string (UTF-16 / wide string).
|
||||||
|
/// </summary>
|
||||||
|
WideString = 0x9,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value points to a constant null-terminated 8-bit character string (const char*).
|
||||||
|
/// </summary>
|
||||||
|
String8 = 0xA,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is a vector.
|
||||||
|
/// </summary>
|
||||||
|
Vector = 0xB,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is a pointer.
|
||||||
|
/// </summary>
|
||||||
|
Pointer = 0xC,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is pointing to an array of AtkValue entries.
|
||||||
|
/// </summary>
|
||||||
|
AtkValues = 0xD,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is a managed string. See <see cref="String"/>.
|
||||||
|
/// </summary>
|
||||||
|
ManagedString = 0x28,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value is a managed vector. See <see cref="Vector"/>.
|
||||||
|
/// </summary>
|
||||||
|
ManagedVector = 0x2B,
|
||||||
|
}
|
||||||
51
Dalamud/Game/NativeWrapper/UIModulePtr.cs
Normal file
51
Dalamud/Game/NativeWrapper/UIModulePtr.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.NativeWrapper;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A readonly wrapper for UIModule.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address">The address to the UIModule.</param>
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = 0x08)]
|
||||||
|
public readonly unsafe struct UIModulePtr(nint address) : IEquatable<UIModulePtr>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The address to the UIModule.
|
||||||
|
/// </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 the UIModule*.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks> Internal use only. </remarks>
|
||||||
|
internal readonly UIModule* Struct => (UIModule*)this.Address;
|
||||||
|
|
||||||
|
public static implicit operator nint(UIModulePtr wrapper) => wrapper.Address;
|
||||||
|
|
||||||
|
public static implicit operator UIModulePtr(nint address) => new(address);
|
||||||
|
|
||||||
|
public static implicit operator UIModulePtr(void* ptr) => new((nint)ptr);
|
||||||
|
|
||||||
|
public static bool operator ==(UIModulePtr left, UIModulePtr right) => left.Address == right.Address;
|
||||||
|
|
||||||
|
public static bool operator !=(UIModulePtr left, UIModulePtr right) => left.Address != right.Address;
|
||||||
|
|
||||||
|
/// <summary>Determines whether the specified UIModulePtr is equal to the current UIModulePtr.</summary>
|
||||||
|
/// <param name="other">The UIModulePtr to compare with the current UIModulePtr.</param>
|
||||||
|
/// <returns><c>true</c> if the specified UIModulePtr is equal to the current UIModulePtr; otherwise, <c>false</c>.</returns>
|
||||||
|
public readonly bool Equals(UIModulePtr other) => this.Address == other.Address;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="object.Equals(object?)"/>
|
||||||
|
public override readonly bool Equals(object obj) => obj is UIModulePtr wrapper && this.Equals(wrapper);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="object.GetHashCode()"/>
|
||||||
|
public override readonly int GetHashCode() => ((nuint)this.Address).GetHashCode();
|
||||||
|
}
|
||||||
|
|
@ -12,8 +12,6 @@ using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
using Lumina.Text.ReadOnly;
|
|
||||||
|
|
||||||
// Customised version of https://github.com/aers/FFXIVUIDebug
|
// Customised version of https://github.com/aers/FFXIVUIDebug
|
||||||
|
|
||||||
namespace Dalamud.Interface.Internal;
|
namespace Dalamud.Interface.Internal;
|
||||||
|
|
@ -102,8 +100,8 @@ internal unsafe class UiDebug
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
ImGuiHelpers.ClickToCopyText($"Address: {(ulong)atkUnitBase:X}", $"{(ulong)atkUnitBase:X}");
|
ImGuiHelpers.ClickToCopyText($"Address: {(nint)atkUnitBase:X}", $"{(nint)atkUnitBase:X}");
|
||||||
ImGuiHelpers.ClickToCopyText($"Agent: {(ulong)agent:X}", $"{(ulong)agent:X}");
|
ImGuiHelpers.ClickToCopyText($"Agent: {(nint)agent:X}", $"{(nint)agent:X}");
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
|
||||||
ImGui.Text($"Position: [ {atkUnitBase->X} , {atkUnitBase->Y} ]");
|
ImGui.Text($"Position: [ {atkUnitBase->X} , {atkUnitBase->Y} ]");
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ public unsafe partial class AddonTree : IDisposable
|
||||||
{
|
{
|
||||||
var ptr = GameGui.GetAddonByName(name);
|
var ptr = GameGui.GetAddonByName(name);
|
||||||
|
|
||||||
if ((AtkUnitBase*)ptr != null)
|
if (!ptr.IsNull)
|
||||||
{
|
{
|
||||||
if (AddonTrees.TryGetValue(name, out var tree))
|
if (AddonTrees.TryGetValue(name, out var tree))
|
||||||
{
|
{
|
||||||
|
|
@ -152,7 +152,7 @@ public unsafe partial class AddonTree : IDisposable
|
||||||
var uldManager = addon->UldManager;
|
var uldManager = addon->UldManager;
|
||||||
|
|
||||||
PrintFieldValuePair("Address", $"{(nint)addon:X}");
|
PrintFieldValuePair("Address", $"{(nint)addon:X}");
|
||||||
PrintFieldValuePair("Agent", $"{GameGui.FindAgentInterface(addon):X}");
|
PrintFieldValuePair("Agent", $"{(nint)GameGui.FindAgentInterface(addon):X}");
|
||||||
|
|
||||||
PrintFieldValuePairs(
|
PrintFieldValuePairs(
|
||||||
("X", $"{addon->X}"),
|
("X", $"{addon->X}"),
|
||||||
|
|
@ -234,7 +234,7 @@ public unsafe partial class AddonTree : IDisposable
|
||||||
/// <returns>true if the addon is found.</returns>
|
/// <returns>true if the addon is found.</returns>
|
||||||
private bool ValidateAddon(out AtkUnitBase* addon)
|
private bool ValidateAddon(out AtkUnitBase* addon)
|
||||||
{
|
{
|
||||||
addon = (AtkUnitBase*)GameGui.GetAddonByName(this.AddonName);
|
addon = GameGui.GetAddonByName(this.AddonName).Struct;
|
||||||
if (addon == null || (nint)addon != this.InitialPtr)
|
if (addon == null || (nint)addon != this.InitialPtr)
|
||||||
{
|
{
|
||||||
this.Dispose();
|
this.Dispose();
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ internal unsafe partial class UiDebug2
|
||||||
/// Gets the base address for all unit lists.
|
/// Gets the base address for all unit lists.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The address, if found.</returns>
|
/// <returns>The address, if found.</returns>
|
||||||
internal static AtkUnitList* GetUnitListBaseAddr() => &((UIModule*)GameGui.GetUIModule())->GetRaptureAtkModule()->RaptureAtkUnitManager.AtkUnitManager.DepthLayerOneList;
|
internal static AtkUnitList* GetUnitListBaseAddr() => &RaptureAtkUnitManager.Instance()->DepthLayerOneList;
|
||||||
|
|
||||||
private void DrawSidebar()
|
private void DrawSidebar()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Dalamud.Game.Gui;
|
using Dalamud.Game.Gui;
|
||||||
using Dalamud.Memory;
|
using Dalamud.Game.NativeWrapper;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
|
namespace Dalamud.Interface.Internal.Windows.Data.Widgets;
|
||||||
|
|
@ -12,7 +13,7 @@ internal unsafe class AddonWidget : IDataWindowWidget
|
||||||
{
|
{
|
||||||
private string inputAddonName = string.Empty;
|
private string inputAddonName = string.Empty;
|
||||||
private int inputAddonIndex;
|
private int inputAddonIndex;
|
||||||
private nint findAgentInterfacePtr;
|
private AgentInterfacePtr agentInterfacePtr;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string DisplayName { get; init; } = "Addon";
|
public string DisplayName { get; init; } = "Addon";
|
||||||
|
|
@ -40,30 +41,27 @@ internal unsafe class AddonWidget : IDataWindowWidget
|
||||||
if (this.inputAddonName.IsNullOrEmpty())
|
if (this.inputAddonName.IsNullOrEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var address = gameGui.GetAddonByName(this.inputAddonName, this.inputAddonIndex);
|
var addon = gameGui.GetAddonByName(this.inputAddonName, this.inputAddonIndex);
|
||||||
|
if (addon.IsNull)
|
||||||
if (address == nint.Zero)
|
|
||||||
{
|
{
|
||||||
ImGui.Text("Null");
|
ImGui.Text("Null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var addon = (FFXIVClientStructs.FFXIV.Component.GUI.AtkUnitBase*)address;
|
ImGui.TextUnformatted($"{addon.Name} - {Util.DescribeAddress(addon)}\n v:{addon.IsVisible} x:{addon.X} y:{addon.Y} s:{addon.Scale}, w:{addon.Width}, h:{addon.Height}");
|
||||||
var name = addon->NameString;
|
|
||||||
ImGui.TextUnformatted($"{name} - {Util.DescribeAddress(address)}\n v:{addon->IsVisible} x:{addon->X} y:{addon->Y} s:{addon->Scale}, w:{addon->RootNode->Width}, h:{addon->RootNode->Height}");
|
|
||||||
|
|
||||||
if (ImGui.Button("Find Agent"))
|
if (ImGui.Button("Find Agent"))
|
||||||
{
|
{
|
||||||
this.findAgentInterfacePtr = gameGui.FindAgentInterface(address);
|
this.agentInterfacePtr = gameGui.FindAgentInterface(addon);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.findAgentInterfacePtr != nint.Zero)
|
if (!this.agentInterfacePtr.IsNull)
|
||||||
{
|
{
|
||||||
ImGui.TextUnformatted($"Agent: {Util.DescribeAddress(this.findAgentInterfacePtr)}");
|
ImGui.TextUnformatted($"Agent: {Util.DescribeAddress(this.agentInterfacePtr)}");
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
|
||||||
if (ImGui.Button("C"))
|
if (ImGui.Button("C"))
|
||||||
ImGui.SetClipboardText(this.findAgentInterfacePtr.ToInt64().ToString("X"));
|
ImGui.SetClipboardText(this.agentInterfacePtr.Address.ToString("X"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -477,7 +477,7 @@ internal class TitleScreenMenuWindow : Window, IDisposable
|
||||||
{
|
{
|
||||||
if (args is not AddonDrawArgs drawArgs) return;
|
if (args is not AddonDrawArgs drawArgs) return;
|
||||||
|
|
||||||
var addon = (AtkUnitBase*)drawArgs.Addon;
|
var addon = drawArgs.Addon.Struct;
|
||||||
var textNode = addon->GetTextNodeById(3);
|
var textNode = addon->GetTextNodeById(3);
|
||||||
|
|
||||||
// look and feel init. should be harmless to set.
|
// look and feel init. should be harmless to set.
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
using Dalamud.Game.Gui;
|
using Dalamud.Game.Gui;
|
||||||
|
using Dalamud.Game.NativeWrapper;
|
||||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
|
|
||||||
namespace Dalamud.Plugin.Services;
|
namespace Dalamud.Plugin.Services;
|
||||||
|
|
@ -75,37 +76,37 @@ public unsafe interface IGameGui
|
||||||
public bool ScreenToWorld(Vector2 screenPos, out Vector3 worldPos, float rayDistance = 100000.0f);
|
public bool ScreenToWorld(Vector2 screenPos, out Vector3 worldPos, float rayDistance = 100000.0f);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a pointer to the game's UI module.
|
/// Gets a pointer to the game's UIModule instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>IntPtr pointing to UI module.</returns>
|
/// <returns>A pointer wrapper to UIModule.</returns>
|
||||||
public nint GetUIModule();
|
public UIModulePtr GetUIModule();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the pointer to the Addon with the given name and index.
|
/// Gets the pointer to the Addon with the given name and index.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">Name of addon to find.</param>
|
/// <param name="name">Name of addon to find.</param>
|
||||||
/// <param name="index">Index of addon to find (1-indexed).</param>
|
/// <param name="index">Index of addon to find (1-indexed).</param>
|
||||||
/// <returns>nint.Zero if unable to find UI, otherwise nint pointing to the start of the addon.</returns>
|
/// <returns>A pointer wrapper to the addon.</returns>
|
||||||
public nint GetAddonByName(string name, int index = 1);
|
public AtkUnitBasePtr GetAddonByName(string name, int index = 1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Find the agent associated with an addon, if possible.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The agent id.</param>
|
||||||
|
/// <returns>A pointer wrapper to the agent interface.</returns>
|
||||||
|
public AgentInterfacePtr GetAgentById(int id);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Find the agent associated with an addon, if possible.
|
/// Find the agent associated with an addon, if possible.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="addonName">The addon name.</param>
|
/// <param name="addonName">The addon name.</param>
|
||||||
/// <returns>A pointer to the agent interface.</returns>
|
/// <returns>A pointer wrapper to the agent interface.</returns>
|
||||||
public nint FindAgentInterface(string addonName);
|
public AgentInterfacePtr FindAgentInterface(string addonName);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Find the agent associated with an addon, if possible.
|
/// Find the agent associated with an addon, if possible.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="addon">The addon address.</param>
|
/// <param name="addon">The addon address.</param>
|
||||||
/// <returns>A pointer to the agent interface.</returns>
|
/// <returns>A pointer wrapper to the agent interface.</returns>
|
||||||
public nint FindAgentInterface(void* addon);
|
public AgentInterfacePtr FindAgentInterface(AtkUnitBasePtr addon);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Find the agent associated with an addon, if possible.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="addonPtr">The addon address.</param>
|
|
||||||
/// <returns>A pointer to the agent interface.</returns>
|
|
||||||
public IntPtr FindAgentInterface(IntPtr addonPtr);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue