Add AgentInterfacePtr

This commit is contained in:
Haselnussbomber 2025-07-31 00:33:49 +02:00
parent 61b08a90f2
commit 1119fd0ec7
No known key found for this signature in database
GPG key ID: BB905BB49E7295D1
7 changed files with 141 additions and 64 deletions

View file

@ -3,7 +3,6 @@ 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;

View file

@ -170,29 +170,17 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
/// <inheritdoc/>
public IntPtr GetUIModule()
{
var framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance();
if (framework == null)
return IntPtr.Zero;
var uiModule = framework->GetUIModule();
if (uiModule == null)
return IntPtr.Zero;
return (IntPtr)uiModule;
return (nint)UIModule.Instance();
}
/// <inheritdoc/>
public AtkUnitBasePtr GetAddonByName(string name, int index = 1)
{
var atkStage = AtkStage.Instance();
if (atkStage == null)
var unitManager = RaptureAtkUnitManager.Instance();
if (unitManager == null)
return 0;
var unitMgr = atkStage->RaptureAtkUnitManager;
if (unitMgr == null)
return 0;
var addon = unitMgr->GetAddonByName(name, index);
var addon = unitManager->GetAddonByName(name, index);
if (addon == null)
return 0;
@ -200,47 +188,43 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
}
/// <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);
return this.FindAgentInterface(addon);
}
/// <inheritdoc/>
public IntPtr FindAgentInterface(void* addon) => this.FindAgentInterface((IntPtr)addon);
/// <inheritdoc/>
public IntPtr FindAgentInterface(IntPtr addonPtr)
public AgentInterfacePtr FindAgentInterface(AtkUnitBasePtr addon)
{
if (addonPtr == IntPtr.Zero)
return IntPtr.Zero;
if (addon.IsNull)
return 0;
var uiModule = (UIModule*)this.GetUIModule();
if (uiModule == null)
return IntPtr.Zero;
var agentModule = uiModule->GetAgentModule();
var agentModule = AgentModule.Instance();
if (agentModule == null)
return IntPtr.Zero;
var addon = (AtkUnitBase*)addonPtr;
var addonId = addon->ParentId == 0 ? addon->Id : addon->ParentId;
return 0;
var addonId = addon.ParentId == 0 ? addon.Id : addon.ParentId;
if (addonId == 0)
return IntPtr.Zero;
return 0;
var index = 0;
while (true)
foreach (AgentInterface* agent in agentModule->Agents)
{
var agent = agentModule->GetAgentByInternalId((AgentId)index++);
if (agent == uiModule || agent == null)
break;
if (agent->AddonId == addonId)
return new IntPtr(agent);
if (agent != null && agent->AddonId == addonId)
return (nint)agent;
}
return IntPtr.Zero;
return 0;
}
/// <summary>
@ -463,17 +447,17 @@ internal class GameGuiPluginScoped : IInternalDisposableService, IGameGui
=> this.gameGuiService.GetAddonByName(name, index);
/// <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);
/// <inheritdoc/>
public unsafe IntPtr FindAgentInterface(void* addon)
public AgentInterfacePtr FindAgentInterface(AtkUnitBasePtr 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 HoveredItemForward(object sender, ulong itemId) => this.HoveredItemChanged?.Invoke(sender, itemId);

View file

@ -0,0 +1,94 @@
using System.Runtime.InteropServices;
using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
namespace Dalamud.Game.NativeWrapper;
/// <summary>
/// A 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 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();
}

View file

@ -87,7 +87,7 @@ internal unsafe class UiDebug
{
var isVisible = atkUnitBase->IsVisible;
var addonName = atkUnitBase->NameString;
var agent = Service<GameGui>.Get().FindAgentInterface(atkUnitBase);
var agent = Service<GameGui>.Get().FindAgentInterface((nint)atkUnitBase);
ImGui.Text($"{addonName}");
ImGui.SameLine();
@ -102,8 +102,8 @@ internal unsafe class UiDebug
}
ImGui.Separator();
ImGuiHelpers.ClickToCopyText($"Address: {(ulong)atkUnitBase:X}", $"{(ulong)atkUnitBase:X}");
ImGuiHelpers.ClickToCopyText($"Agent: {(ulong)agent:X}", $"{(ulong)agent:X}");
ImGuiHelpers.ClickToCopyText($"Address: {(nint)atkUnitBase:X}", $"{(nint)atkUnitBase:X}");
ImGuiHelpers.ClickToCopyText($"Agent: {(nint)agent:X}", $"{(nint)agent:X}");
ImGui.Separator();
ImGui.Text($"Position: [ {atkUnitBase->X} , {atkUnitBase->Y} ]");

View file

@ -152,7 +152,7 @@ public unsafe partial class AddonTree : IDisposable
var uldManager = addon->UldManager;
PrintFieldValuePair("Address", $"{(nint)addon:X}");
PrintFieldValuePair("Agent", $"{GameGui.FindAgentInterface(addon):X}");
PrintFieldValuePair("Agent", $"{GameGui.FindAgentInterface((nint)addon):X}");
PrintFieldValuePairs(
("X", $"{addon->X}"),

View file

@ -49,7 +49,7 @@ internal unsafe partial class UiDebug2
/// Gets the base address for all unit lists.
/// </summary>
/// <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()
{

View file

@ -86,27 +86,27 @@ public unsafe interface IGameGui
/// </summary>
/// <param name="name">Name of addon to find.</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 to the addon.</returns>
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 to the agent interface.</returns>
public AgentInterfacePtr GetAgentById(int id);
/// <summary>
/// Find the agent associated with an addon, if possible.
/// </summary>
/// <param name="addonName">The addon name.</param>
/// <returns>A pointer to the agent interface.</returns>
public nint FindAgentInterface(string addonName);
public AgentInterfacePtr FindAgentInterface(string addonName);
/// <summary>
/// Find the agent associated with an addon, if possible.
/// </summary>
/// <param name="addon">The addon address.</param>
/// <returns>A pointer to the agent interface.</returns>
public nint FindAgentInterface(void* 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);
public AgentInterfacePtr FindAgentInterface(AtkUnitBasePtr addon);
}