diff --git a/Dalamud/Game/Addon/Events/AddonEventManagerAddressResolver.cs b/Dalamud/Game/Addon/Events/AddonEventManagerAddressResolver.cs
index 927ed87ab..415e1b169 100644
--- a/Dalamud/Game/Addon/Events/AddonEventManagerAddressResolver.cs
+++ b/Dalamud/Game/Addon/Events/AddonEventManagerAddressResolver.cs
@@ -16,6 +16,6 @@ internal class AddonEventManagerAddressResolver : BaseAddressResolver
/// The signature scanner to facilitate setup.
protected override void Setup64Bit(ISigScanner scanner)
{
- this.UpdateCursor = scanner.ScanText("48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 20 4C 8B F1 E8 ?? ?? ?? ?? 49 8B CE");
+ this.UpdateCursor = scanner.ScanText("48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 20 4C 8B F1 E8 ?? ?? ?? ?? 49 8B CE"); // unnamed in CS
}
}
diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs
index 750ba34c5..364466cce 100644
--- a/Dalamud/Game/ClientState/ClientState.cs
+++ b/Dalamud/Game/ClientState/ClientState.cs
@@ -1,5 +1,4 @@
using System.Linq;
-using System.Runtime.InteropServices;
using Dalamud.Data;
using Dalamud.Game.ClientState.Conditions;
@@ -37,7 +36,7 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
private readonly GameLifecycle lifecycle;
private readonly ClientStateAddressResolver address;
- private readonly Hook setupTerritoryTypeHook;
+ private readonly Hook setupTerritoryTypeHook;
private readonly Hook uiModuleHandlePacketHook;
private readonly Hook processPacketPlayerSetupHook;
private readonly Hook onLogoutHook;
@@ -56,9 +55,10 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
this.ClientLanguage = (ClientLanguage)dalamud.StartInfo.Language;
- Log.Verbose($"SetupTerritoryType address {Util.DescribeAddress(this.address.SetupTerritoryType)}");
+ var setTerritoryTypeAddr = EventFramework.Addresses.SetTerritoryTypeId.Value;
+ Log.Verbose($"SetupTerritoryType address {Util.DescribeAddress(setTerritoryTypeAddr)}");
- this.setupTerritoryTypeHook = Hook.FromAddress(this.address.SetupTerritoryType, this.SetupTerritoryTypeDetour);
+ this.setupTerritoryTypeHook = Hook.FromAddress(setTerritoryTypeAddr, this.SetupTerritoryTypeDetour);
this.uiModuleHandlePacketHook = Hook.FromAddress((nint)UIModule.StaticVirtualTablePointer->HandlePacket, this.UIModuleHandlePacketDetour);
this.processPacketPlayerSetupHook = Hook.FromAddress(this.address.ProcessPacketPlayerSetup, this.ProcessPacketPlayerSetupDetour);
this.onLogoutHook = Hook.FromAddress((nint)LogoutCallbackInterface.StaticVirtualTablePointer->OnLogout, this.OnLogoutDetour);
@@ -71,9 +71,6 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
this.onLogoutHook.Enable();
}
- [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
- private unsafe delegate void SetupTerritoryTypeDelegate(EventFramework* eventFramework, ushort terriType);
-
private unsafe delegate void ProcessPacketPlayerSetupDelegate(nint a1, nint packet);
///
@@ -123,7 +120,14 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
public unsafe ulong LocalContentId => PlayerState.Instance()->ContentId;
///
- public bool IsLoggedIn { get; private set; }
+ public unsafe bool IsLoggedIn
+ {
+ get
+ {
+ var agentLobby = AgentLobby.Instance();
+ return agentLobby != null && agentLobby->IsLoggedIn;
+ }
+ }
///
public bool IsPvP { get; private set; }
@@ -261,7 +265,6 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
try
{
Log.Debug("Login");
- this.IsLoggedIn = true;
this.Login?.InvokeSafely();
gameGui?.ResetUiHideState();
this.lifecycle.ResetLogout();
@@ -285,8 +288,6 @@ internal sealed class ClientState : IInternalDisposableService, IClientState
Log.Debug("Logout: Type {type}, Code {code}", type, code);
- this.IsLoggedIn = false;
-
if (this.Logout is { } callback)
{
foreach (var action in callback.GetInvocationList().Cast())
diff --git a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs
index c7d7837a4..d44275ef8 100644
--- a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs
+++ b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs
@@ -19,11 +19,6 @@ internal sealed class ClientStateAddressResolver : BaseAddressResolver
// Functions
- ///
- /// Gets the address of the method which sets the territory type.
- ///
- public IntPtr SetupTerritoryType { get; private set; }
-
///
/// Gets the address of the method which sets up the player.
///
@@ -41,9 +36,7 @@ internal sealed class ClientStateAddressResolver : BaseAddressResolver
/// The signature scanner to facilitate setup.
protected override void Setup64Bit(ISigScanner sig)
{
- this.SetupTerritoryType = sig.ScanText("48 89 5C 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC ?? 48 8B D9 48 89 6C 24");
-
- this.ProcessPacketPlayerSetup = sig.ScanText("40 53 48 83 EC 20 48 8D 0D ?? ?? ?? ?? 48 8B DA E8 ?? ?? ?? ?? 48 8B D3");
+ this.ProcessPacketPlayerSetup = sig.ScanText("40 53 48 83 EC 20 48 8D 0D ?? ?? ?? ?? 48 8B DA E8 ?? ?? ?? ?? 48 8B D3"); // not in cs struct
// These resolve to fixed offsets only, without the base address added in, so GetStaticAddressFromSig() can't be used.
// lea rcx, ds:1DB9F74h[rax*4] KeyboardState
@@ -51,6 +44,6 @@ internal sealed class ClientStateAddressResolver : BaseAddressResolver
this.KeyboardState = sig.ScanText("48 8D 0C 85 ?? ?? ?? ?? 8B 04 31 85 C2 0F 85") + 0x4;
this.KeyboardStateIndexArray = sig.ScanText("0F B6 94 33 ?? ?? ?? ?? 84 D2") + 0x4;
- this.GamepadPoll = sig.ScanText("40 55 53 57 41 54 41 57 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 44 0F 29 B4 24");
+ this.GamepadPoll = sig.ScanText("40 55 53 57 41 54 41 57 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 44 0F 29 B4 24"); // unnamed in cs
}
}
diff --git a/Dalamud/Game/Config/GameConfigAddressResolver.cs b/Dalamud/Game/Config/GameConfigAddressResolver.cs
index c171932a9..2491c4033 100644
--- a/Dalamud/Game/Config/GameConfigAddressResolver.cs
+++ b/Dalamud/Game/Config/GameConfigAddressResolver.cs
@@ -13,6 +13,6 @@ internal sealed class GameConfigAddressResolver : BaseAddressResolver
///
protected override void Setup64Bit(ISigScanner scanner)
{
- this.ConfigChangeAddress = scanner.ScanText("E8 ?? ?? ?? ?? 48 8B 3F 49 3B 3E");
+ this.ConfigChangeAddress = scanner.ScanText("E8 ?? ?? ?? ?? 48 8B 3F 49 3B 3E"); // unnamed in CS
}
}
diff --git a/Dalamud/Game/DutyState/DutyStateAddressResolver.cs b/Dalamud/Game/DutyState/DutyStateAddressResolver.cs
index 01a0d39b7..1bca93efb 100644
--- a/Dalamud/Game/DutyState/DutyStateAddressResolver.cs
+++ b/Dalamud/Game/DutyState/DutyStateAddressResolver.cs
@@ -16,6 +16,6 @@ internal class DutyStateAddressResolver : BaseAddressResolver
/// The signature scanner to facilitate setup.
protected override void Setup64Bit(ISigScanner sig)
{
- this.ContentDirectorNetworkMessage = sig.ScanText("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 33 FF 48 8B D9 41 0F B7 08");
+ this.ContentDirectorNetworkMessage = sig.ScanText("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 33 FF 48 8B D9 41 0F B7 08"); // unnamed in cs
}
}
diff --git a/Dalamud/Game/Gui/FlyText/FlyTextGui.cs b/Dalamud/Game/Gui/FlyText/FlyTextGui.cs
index b01f8c244..cbf166cfc 100644
--- a/Dalamud/Game/Gui/FlyText/FlyTextGui.cs
+++ b/Dalamud/Game/Gui/FlyText/FlyTextGui.cs
@@ -23,62 +23,21 @@ namespace Dalamud.Game.Gui.FlyText;
internal sealed class FlyTextGui : IInternalDisposableService, IFlyTextGui
{
///
- /// The native function responsible for adding fly text to the UI. See .
+ /// The hook that fires when the game creates a fly text element.
///
- private readonly AddFlyTextDelegate addFlyTextNative;
-
- ///
- /// The hook that fires when the game creates a fly text element. See .
- ///
- private readonly Hook createFlyTextHook;
+ private readonly Hook createFlyTextHook;
[ServiceManager.ServiceConstructor]
private unsafe FlyTextGui(TargetSigScanner sigScanner)
{
- this.Address = new FlyTextGuiAddressResolver();
- this.Address.Setup(sigScanner);
-
- this.addFlyTextNative = Marshal.GetDelegateForFunctionPointer(this.Address.AddFlyText);
- this.createFlyTextHook = Hook.FromAddress(this.Address.CreateFlyText, this.CreateFlyTextDetour);
+ this.createFlyTextHook = Hook.FromAddress(AddonFlyText.Addresses.CreateFlyText.Value, this.CreateFlyTextDetour);
this.createFlyTextHook.Enable();
}
- ///
- /// Private delegate for the native CreateFlyText function's hook.
- ///
- private unsafe delegate nint CreateFlyTextDelegate(
- AtkUnitBase* thisPtr,
- FlyTextKind kind,
- int val1,
- int val2,
- byte* text2,
- uint color,
- uint icon,
- uint damageTypeIcon,
- byte* text1,
- float yOffset);
-
- ///
- /// Private delegate for the native AddFlyText function pointer.
- ///
- private unsafe delegate void AddFlyTextDelegate(
- AtkUnitBase* thisPtr,
- uint actorIndex,
- uint messageMax,
- NumberArrayData* numberArrayData,
- uint offsetNum,
- uint offsetNumMax,
- StringArrayData* stringArrayData,
- uint offsetStr,
- uint offsetStrMax,
- int unknown);
-
///
public event IFlyTextGui.OnFlyTextCreatedDelegate? FlyTextCreated;
- private FlyTextGuiAddressResolver Address { get; }
-
///
/// Disposes of managed and unmanaged resources.
///
@@ -94,7 +53,7 @@ internal sealed class FlyTextGui : IInternalDisposableService, IFlyTextGui
var numOffset = 161u;
var strOffset = 28u;
- var flytext = RaptureAtkUnitManager.Instance()->GetAddonByName("_FlyText");
+ var flytext = (AddonFlyText*)RaptureAtkUnitManager.Instance()->GetAddonByName("_FlyText");
if (flytext == null)
return;
@@ -116,23 +75,13 @@ internal sealed class FlyTextGui : IInternalDisposableService, IFlyTextGui
strArray->SetValue((int)strOffset + 0, text1.EncodeWithNullTerminator(), false, true, false);
strArray->SetValue((int)strOffset + 1, text2.EncodeWithNullTerminator(), false, true, false);
-
- this.addFlyTextNative(
- flytext,
- actorIndex,
- 1,
- numArray,
- numOffset,
- 10,
- strArray,
- strOffset,
- 2,
- 0);
+
+ flytext->AddFlyText(actorIndex, 1, numArray, numOffset, 10, strArray, strOffset, 2, 0);
}
private unsafe nint CreateFlyTextDetour(
- AtkUnitBase* thisPtr,
- FlyTextKind kind,
+ AddonFlyText* thisPtr,
+ int kind,
int val1,
int val2,
byte* text2,
@@ -149,7 +98,7 @@ internal sealed class FlyTextGui : IInternalDisposableService, IFlyTextGui
var handled = false;
- var tmpKind = kind;
+ var tmpKind = (FlyTextKind)kind;
var tmpVal1 = val1;
var tmpVal2 = val2;
var tmpText1 = text1 == null ? string.Empty : MemoryHelper.ReadSeStringNullTerminated((nint)text1);
@@ -193,7 +142,7 @@ internal sealed class FlyTextGui : IInternalDisposableService, IFlyTextGui
var maybeModifiedText2 = tmpText2.EncodeWithNullTerminator();
// Check if any values have changed
- var dirty = tmpKind != kind ||
+ var dirty = (int)tmpKind != kind ||
tmpVal1 != val1 ||
tmpVal2 != val2 ||
!maybeModifiedText1.SequenceEqual(originalText1) ||
@@ -219,7 +168,7 @@ internal sealed class FlyTextGui : IInternalDisposableService, IFlyTextGui
retVal = this.createFlyTextHook.Original(
thisPtr,
- tmpKind,
+ (int)tmpKind,
tmpVal1,
tmpVal2,
(byte*)pText2,
diff --git a/Dalamud/Game/Gui/FlyText/FlyTextGuiAddressResolver.cs b/Dalamud/Game/Gui/FlyText/FlyTextGuiAddressResolver.cs
deleted file mode 100644
index aa7c8026f..000000000
--- a/Dalamud/Game/Gui/FlyText/FlyTextGuiAddressResolver.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-namespace Dalamud.Game.Gui.FlyText;
-
-///
-/// An address resolver for the class.
-///
-internal class FlyTextGuiAddressResolver : BaseAddressResolver
-{
- ///
- /// Gets the address of the native AddFlyText method, which occurs
- /// when the game adds fly text elements to the UI. Multiple fly text
- /// elements can be added in a single AddFlyText call.
- ///
- public IntPtr AddFlyText { get; private set; }
-
- ///
- /// Gets the address of the native CreateFlyText method, which occurs
- /// when the game creates a new fly text element. This method is called
- /// once per fly text element, and can be called multiple times per
- /// AddFlyText call.
- ///
- public IntPtr CreateFlyText { get; private set; }
-
- ///
- protected override void Setup64Bit(ISigScanner sig)
- {
- this.AddFlyText = sig.ScanText("E8 ?? ?? ?? ?? FF C7 41 D1 C7");
- this.CreateFlyText = sig.ScanText("E8 ?? ?? ?? ?? 48 8B F8 48 85 C0 0F 84 ?? ?? ?? ?? 48 8B 18");
- }
-}
diff --git a/Dalamud/Game/Gui/GameGui.cs b/Dalamud/Game/Gui/GameGui.cs
index 74e0a8df3..54f4253cd 100644
--- a/Dalamud/Game/Gui/GameGui.cs
+++ b/Dalamud/Game/Gui/GameGui.cs
@@ -38,11 +38,11 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
private readonly GameGuiAddressResolver address;
private readonly Hook setGlobalBgmHook;
- private readonly Hook handleActionHoverHook;
- private readonly Hook handleActionOutHook;
+ private readonly Hook handleActionHoverHook;
+ private readonly Hook handleActionOutHook;
private readonly Hook handleImmHook;
private readonly Hook setUiVisibilityHook;
- private readonly Hook utf8StringFromSequenceHook;
+ private readonly Hook utf8StringFromSequenceHook;
[ServiceManager.ServiceConstructor]
private GameGui(TargetSigScanner sigScanner)
@@ -57,14 +57,14 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
this.setGlobalBgmHook = Hook.FromAddress(this.address.SetGlobalBgm, this.HandleSetGlobalBgmDetour);
- this.handleActionHoverHook = Hook.FromAddress(this.address.HandleActionHover, this.HandleActionHoverDetour);
- this.handleActionOutHook = Hook.FromAddress(this.address.HandleActionOut, this.HandleActionOutDetour);
+ this.handleActionHoverHook = Hook.FromAddress(AgentActionDetail.Addresses.HandleActionHover.Value, this.HandleActionHoverDetour);
+ this.handleActionOutHook = Hook.FromAddress((nint)AgentActionDetail.StaticVirtualTablePointer->ReceiveEvent, this.HandleActionOutDetour);
this.handleImmHook = Hook.FromAddress(this.address.HandleImm, this.HandleImmDetour);
this.setUiVisibilityHook = Hook.FromAddress((nint)RaptureAtkModule.StaticVirtualTablePointer->SetUiVisibility, this.SetUiVisibilityDetour);
- this.utf8StringFromSequenceHook = Hook.FromAddress(this.address.Utf8StringFromSequence, this.Utf8StringFromSequenceDetour);
+ this.utf8StringFromSequenceHook = Hook.FromAddress(Utf8String.Addresses.Ctor_FromSequence.Value, this.Utf8StringFromSequenceDetour);
this.setGlobalBgmHook.Enable();
this.handleImmHook.Enable();
@@ -77,22 +77,13 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
}
// Hooked delegates
-
- [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
- private delegate Utf8String* Utf8StringFromSequenceDelegate(Utf8String* thisPtr, byte* sourcePtr, nuint sourceLen);
-
+
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate IntPtr SetGlobalBgmDelegate(ushort bgmKey, byte a2, uint a3, uint a4, uint a5, byte a6);
- [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
- private delegate void HandleActionHoverDelegate(IntPtr hoverState, HoverActionKind a2, uint a3, int a4, byte a5);
-
- [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
- private delegate IntPtr HandleActionOutDelegate(IntPtr agentActionDetail, IntPtr a2, IntPtr a3, int a4);
-
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate char HandleImmDelegate(IntPtr framework, char a2, byte a3);
-
+
///
public event EventHandler? UiHideToggled;
@@ -138,7 +129,7 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
inView = false;
return false;
}
-
+
pCoords *= MathF.Abs(1.0f / pCoords.W);
screenPos = new Vector2(pCoords.X, pCoords.Y);
@@ -166,7 +157,7 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
worldPos = default;
return false;
}
-
+
var camera = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CameraManager.Instance()->CurrentCamera;
if (camera == null)
{
@@ -221,7 +212,7 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
///
public IntPtr FindAgentInterface(void* addon) => this.FindAgentInterface((IntPtr)addon);
-
+
///
public IntPtr FindAgentInterface(IntPtr addonPtr)
{
@@ -309,24 +300,24 @@ internal sealed unsafe class GameGui : IInternalDisposableService, IGameGui
return retVal;
}
- private void HandleActionHoverDetour(IntPtr hoverState, HoverActionKind actionKind, uint actionId, int a4, byte a5)
+ private void HandleActionHoverDetour(AgentActionDetail* hoverState, ActionKind actionKind, uint actionId, int a4, byte a5)
{
this.handleActionHoverHook.Original(hoverState, actionKind, actionId, a4, a5);
- this.HoveredAction.ActionKind = actionKind;
+ this.HoveredAction.ActionKind = (HoverActionKind)actionKind;
this.HoveredAction.BaseActionID = actionId;
- this.HoveredAction.ActionID = (uint)Marshal.ReadInt32(hoverState, 0x3C);
+ this.HoveredAction.ActionID = hoverState->ActionId;
this.HoveredActionChanged?.InvokeSafely(this, this.HoveredAction);
- Log.Verbose($"HoverActionId: {actionKind}/{actionId} this:{hoverState.ToInt64():X}");
+ Log.Verbose($"HoverActionId: {actionKind}/{actionId} this:{(nint)hoverState:X}");
}
- private IntPtr HandleActionOutDetour(IntPtr agentActionDetail, IntPtr a2, IntPtr a3, int a4)
+ private AtkValue* HandleActionOutDetour(AgentActionDetail* agentActionDetail, AtkValue* a2, AtkValue* a3, uint a4, ulong a5)
{
- var retVal = this.handleActionOutHook.Original(agentActionDetail, a2, a3, a4);
+ var retVal = this.handleActionOutHook.Original(agentActionDetail, a2, a3, a4, a5);
- if (a3 != IntPtr.Zero && a4 == 1)
+ if (a3 != null && a4 == 1)
{
- var a3Val = Marshal.ReadByte(a3, 0x8);
+ var a3Val = a3->Int;
if (a3Val == 255)
{
@@ -422,13 +413,13 @@ internal class GameGuiPluginScoped : IInternalDisposableService, IGameGui
this.gameGuiService.HoveredItemChanged += this.HoveredItemForward;
this.gameGuiService.HoveredActionChanged += this.HoveredActionForward;
}
-
+
///
public event EventHandler? UiHideToggled;
-
+
///
public event EventHandler? HoveredItemChanged;
-
+
///
public event EventHandler? HoveredActionChanged;
@@ -444,7 +435,7 @@ internal class GameGuiPluginScoped : IInternalDisposableService, IGameGui
///
public HoveredAction HoveredAction => this.gameGuiService.HoveredAction;
-
+
///
void IInternalDisposableService.DisposeService()
{
@@ -456,7 +447,7 @@ internal class GameGuiPluginScoped : IInternalDisposableService, IGameGui
this.HoveredItemChanged = null;
this.HoveredActionChanged = null;
}
-
+
///
public bool OpenMapWithMapLink(MapLinkPayload mapLink)
=> this.gameGuiService.OpenMapWithMapLink(mapLink);
@@ -464,7 +455,7 @@ internal class GameGuiPluginScoped : IInternalDisposableService, IGameGui
///
public bool WorldToScreen(Vector3 worldPos, out Vector2 screenPos)
=> this.gameGuiService.WorldToScreen(worldPos, out screenPos);
-
+
///
public bool WorldToScreen(Vector3 worldPos, out Vector2 screenPos, out bool inView)
=> this.gameGuiService.WorldToScreen(worldPos, out screenPos, out inView);
@@ -476,26 +467,26 @@ internal class GameGuiPluginScoped : IInternalDisposableService, IGameGui
///
public IntPtr GetUIModule()
=> this.gameGuiService.GetUIModule();
-
+
///
public IntPtr GetAddonByName(string name, int index = 1)
=> this.gameGuiService.GetAddonByName(name, index);
-
+
///
public IntPtr FindAgentInterface(string addonName)
=> this.gameGuiService.FindAgentInterface(addonName);
-
+
///
- public unsafe IntPtr FindAgentInterface(void* addon)
+ public unsafe IntPtr FindAgentInterface(void* addon)
=> this.gameGuiService.FindAgentInterface(addon);
///
- public IntPtr FindAgentInterface(IntPtr addonPtr)
+ 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);
-
+
private void HoveredActionForward(object sender, HoveredAction hoverAction) => this.HoveredActionChanged?.Invoke(sender, hoverAction);
}
diff --git a/Dalamud/Game/Gui/GameGuiAddressResolver.cs b/Dalamud/Game/Gui/GameGuiAddressResolver.cs
index a742541ea..bdd579c7e 100644
--- a/Dalamud/Game/Gui/GameGuiAddressResolver.cs
+++ b/Dalamud/Game/Gui/GameGuiAddressResolver.cs
@@ -15,34 +15,15 @@ internal sealed class GameGuiAddressResolver : BaseAddressResolver
///
public IntPtr SetGlobalBgm { get; private set; }
- ///
- /// Gets the address of the native HandleActionHover method.
- ///
- public IntPtr HandleActionHover { get; private set; }
-
- ///
- /// Gets the address of the native HandleActionOut method.
- ///
- public IntPtr HandleActionOut { get; private set; }
-
///
/// Gets the address of the native HandleImm method.
///
public IntPtr HandleImm { get; private set; }
- ///
- /// Gets the address of the native Utf8StringFromSequence method.
- ///
- public IntPtr Utf8StringFromSequence { get; private set; }
-
///
protected override void Setup64Bit(ISigScanner sig)
{
- this.SetGlobalBgm = sig.ScanText("E8 ?? ?? ?? ?? 8B 2F");
- this.HandleActionHover = sig.ScanText("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 83 F8 0F");
- this.HandleActionOut = sig.ScanText("48 89 5C 24 ?? 57 48 83 EC 20 48 8B DA 48 8B F9 4D 85 C0 74 1F");
- this.HandleImm = sig.ScanText("E8 ?? ?? ?? ?? 84 C0 75 10 48 83 FF 09");
-
- this.Utf8StringFromSequence = sig.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8D 41 22 66 C7 41 ?? ?? ?? 48 89 01 49 8B D8");
+ this.SetGlobalBgm = sig.ScanText("E8 ?? ?? ?? ?? 8B 2F"); // unnamed in CS
+ this.HandleImm = sig.ScanText("E8 ?? ?? ?? ?? 84 C0 75 10 48 83 FF 09"); // unnamed in CS
}
}
diff --git a/Dalamud/Game/Gui/HoverActionKind.cs b/Dalamud/Game/Gui/HoverActionKind.cs
index 4c7ae9166..ef8fe6400 100644
--- a/Dalamud/Game/Gui/HoverActionKind.cs
+++ b/Dalamud/Game/Gui/HoverActionKind.cs
@@ -16,6 +16,11 @@ public enum HoverActionKind
///
Action = 28,
+ ///
+ /// A crafting action is hovered.
+ ///
+ CraftingAction = 29,
+
///
/// A general action is hovered.
///
@@ -24,7 +29,7 @@ public enum HoverActionKind
///
/// A companion order type of action is hovered.
///
- CompanionOrder = 31,
+ CompanionOrder = 31, // Game Term: BuddyOrder
///
/// A main command type of action is hovered.
@@ -36,6 +41,11 @@ public enum HoverActionKind
///
ExtraCommand = 33,
+ ///
+ /// A companion action is hovered.
+ ///
+ Companion = 34,
+
///
/// A pet order type of action is hovered.
///
@@ -45,4 +55,99 @@ public enum HoverActionKind
/// A trait is hovered.
///
Trait = 36,
+
+ ///
+ /// A buddy action is hovered.
+ ///
+ BuddyAction = 37,
+
+ ///
+ /// A company action is hovered.
+ ///
+ CompanyAction = 38,
+
+ ///
+ /// A mount is hovered.
+ ///
+ Mount = 39,
+
+ ///
+ /// A chocobo race action is hovered.
+ ///
+ ChocoboRaceAction = 40,
+
+ ///
+ /// A chocobo race item is hovered.
+ ///
+ ChocoboRaceItem = 41,
+
+ ///
+ /// A deep dungeon equipment is hovered.
+ ///
+ DeepDungeonEquipment = 42,
+
+ ///
+ /// A deep dungeon equipment 2 is hovered.
+ ///
+ DeepDungeonEquipment2 = 43,
+
+ ///
+ /// A deep dungeon item is hovered.
+ ///
+ DeepDungeonItem = 44,
+
+ ///
+ /// A quick chat is hovered.
+ ///
+ QuickChat = 45,
+
+ ///
+ /// An action combo route is hovered.
+ ///
+ ActionComboRoute = 46,
+
+ ///
+ /// A pvp trait is hovered.
+ ///
+ PvPSelectTrait = 47,
+
+ ///
+ /// A squadron action is hovered.
+ ///
+ BgcArmyAction = 48,
+
+ ///
+ /// A perform action is hovered.
+ ///
+ Perform = 49,
+
+ ///
+ /// A deep dungeon magic stone is hovered.
+ ///
+ DeepDungeonMagicStone = 50,
+
+ ///
+ /// A deep dungeon demiclone is hovered.
+ ///
+ DeepDungeonDemiclone = 51,
+
+ ///
+ /// An eureka magia action is hovered.
+ ///
+ EurekaMagiaAction = 52,
+
+ ///
+ /// An island sanctuary temporary item is hovered.
+ ///
+ MYCTemporaryItem = 53,
+
+ ///
+ /// An ornament is hovered.
+ ///
+ Ornament = 54,
+
+ ///
+ /// Glasses are hovered.
+ ///
+ Glasses = 55,
}
diff --git a/Dalamud/Game/Gui/PartyFinder/PartyFinderAddressResolver.cs b/Dalamud/Game/Gui/PartyFinder/PartyFinderAddressResolver.cs
deleted file mode 100644
index 0b267694c..000000000
--- a/Dalamud/Game/Gui/PartyFinder/PartyFinderAddressResolver.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Dalamud.Game.Gui.PartyFinder;
-
-///
-/// The address resolver for the class.
-///
-internal class PartyFinderAddressResolver : BaseAddressResolver
-{
- ///
- /// Gets the address of the native ReceiveListing method.
- ///
- public IntPtr ReceiveListing { get; private set; }
-
- ///
- protected override void Setup64Bit(ISigScanner sig)
- {
- this.ReceiveListing = sig.ScanText("40 53 41 57 48 83 EC ?? 48 8B D9 4C 8B FA");
- }
-}
diff --git a/Dalamud/Game/Gui/PartyFinder/PartyFinderGui.cs b/Dalamud/Game/Gui/PartyFinder/PartyFinderGui.cs
index ef4055b29..0b25a87be 100644
--- a/Dalamud/Game/Gui/PartyFinder/PartyFinderGui.cs
+++ b/Dalamud/Game/Gui/PartyFinder/PartyFinderGui.cs
@@ -7,6 +7,8 @@ using Dalamud.IoC;
using Dalamud.IoC.Internal;
using Dalamud.Plugin.Services;
+using FFXIVClientStructs.FFXIV.Client.UI.Info;
+
using Serilog;
namespace Dalamud.Game.Gui.PartyFinder;
@@ -15,12 +17,11 @@ namespace Dalamud.Game.Gui.PartyFinder;
/// This class handles interacting with the native PartyFinder window.
///
[ServiceManager.EarlyLoadedService]
-internal sealed class PartyFinderGui : IInternalDisposableService, IPartyFinderGui
+internal sealed unsafe class PartyFinderGui : IInternalDisposableService, IPartyFinderGui
{
- private readonly PartyFinderAddressResolver address;
private readonly nint memory;
- private readonly Hook receiveListingHook;
+ private readonly Hook receiveListingHook;
///
/// Initializes a new instance of the class.
@@ -29,18 +30,12 @@ internal sealed class PartyFinderGui : IInternalDisposableService, IPartyFinderG
[ServiceManager.ServiceConstructor]
private PartyFinderGui(TargetSigScanner sigScanner)
{
- this.address = new PartyFinderAddressResolver();
- this.address.Setup(sigScanner);
-
this.memory = Marshal.AllocHGlobal(PartyFinderPacket.PacketSize);
- this.receiveListingHook = Hook.FromAddress(this.address.ReceiveListing, this.HandleReceiveListingDetour);
+ this.receiveListingHook = Hook.FromAddress(InfoProxyCrossRealm.Addresses.ReceiveListing.Value, this.HandleReceiveListingDetour);
this.receiveListingHook.Enable();
}
- [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
- private delegate void ReceiveListingDelegate(nint managerPtr, nint data);
-
///
public event IPartyFinderGui.PartyFinderListingEventDelegate? ReceiveListing;
@@ -61,18 +56,18 @@ internal sealed class PartyFinderGui : IInternalDisposableService, IPartyFinderG
}
}
- private void HandleReceiveListingDetour(nint managerPtr, nint data)
+ private void HandleReceiveListingDetour(InfoProxyCrossRealm* infoProxy, nint packet)
{
try
{
- this.HandleListingEvents(data);
+ this.HandleListingEvents(packet);
}
catch (Exception ex)
{
Log.Error(ex, "Exception on ReceiveListing hook.");
}
- this.receiveListingHook.Original(managerPtr, data);
+ this.receiveListingHook.Original(infoProxy, packet);
}
private void HandleListingEvents(nint data)
diff --git a/Dalamud/Game/Internal/DalamudAtkTweaks.cs b/Dalamud/Game/Internal/DalamudAtkTweaks.cs
index c147f76e6..7834ab58f 100644
--- a/Dalamud/Game/Internal/DalamudAtkTweaks.cs
+++ b/Dalamud/Game/Internal/DalamudAtkTweaks.cs
@@ -24,7 +24,7 @@ internal sealed unsafe class DalamudAtkTweaks : IInternalDisposableService
{
private static readonly ModuleLog Log = new("DalamudAtkTweaks");
- private readonly Hook hookAgentHudOpenSystemMenu;
+ private readonly Hook hookAgentHudOpenSystemMenu;
// TODO: Make this into events in Framework.Gui
private readonly Hook hookUiModuleExecuteMainCommand;
@@ -45,9 +45,7 @@ internal sealed unsafe class DalamudAtkTweaks : IInternalDisposableService
[ServiceManager.ServiceConstructor]
private DalamudAtkTweaks(TargetSigScanner sigScanner)
{
- var openSystemMenuAddress = sigScanner.ScanText("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 48 8B CF 4C 89 B4 24 B8 08 00 00");
-
- this.hookAgentHudOpenSystemMenu = Hook.FromAddress(openSystemMenuAddress, this.AgentHudOpenSystemMenuDetour);
+ this.hookAgentHudOpenSystemMenu = Hook.FromAddress(AgentHUD.Addresses.OpenSystemMenu.Value, this.AgentHudOpenSystemMenuDetour);
this.hookUiModuleExecuteMainCommand = Hook.FromAddress((nint)UIModule.StaticVirtualTablePointer->ExecuteMainCommand, this.UiModuleExecuteMainCommandDetour);
this.hookAtkUnitBaseReceiveGlobalEvent = Hook.FromAddress((nint)AtkUnitBase.StaticVirtualTablePointer->ReceiveGlobalEvent, this.AtkUnitBaseReceiveGlobalEventDetour);
diff --git a/Dalamud/Game/Inventory/GameInventoryItem.cs b/Dalamud/Game/Inventory/GameInventoryItem.cs
index 53aa9a9d9..fb27346e0 100644
--- a/Dalamud/Game/Inventory/GameInventoryItem.cs
+++ b/Dalamud/Game/Inventory/GameInventoryItem.cs
@@ -9,7 +9,7 @@ namespace Dalamud.Game.Inventory;
///
/// Dalamud wrapper around a ClientStructs InventoryItem.
///
-[StructLayout(LayoutKind.Explicit, Size = StructSizeInBytes)]
+[StructLayout(LayoutKind.Explicit, Size = InventoryItem.StructSize)]
public unsafe struct GameInventoryItem : IEquatable
{
///
@@ -17,22 +17,12 @@ public unsafe struct GameInventoryItem : IEquatable
///
[FieldOffset(0)]
internal readonly InventoryItem InternalItem;
-
- private const int StructSizeInBytes = 0x40;
-
+
///
/// The view of the backing data, in .
///
[FieldOffset(0)]
- private fixed ulong dataUInt64[StructSizeInBytes / 0x8];
-
- static GameInventoryItem()
- {
- Debug.Assert(
- sizeof(InventoryItem) == StructSizeInBytes,
- $"Definition of {nameof(InventoryItem)} has been changed. " +
- $"Update {nameof(StructSizeInBytes)} to {sizeof(InventoryItem)} to accommodate for the size change.");
- }
+ private fixed ulong dataUInt64[InventoryItem.StructSize / 0x8];
///
/// Initializes a new instance of the struct.
@@ -157,7 +147,7 @@ public unsafe struct GameInventoryItem : IEquatable
/// true if the current object is equal to the parameter; otherwise, false.
public readonly bool Equals(in GameInventoryItem other)
{
- for (var i = 0; i < StructSizeInBytes / 8; i++)
+ for (var i = 0; i < InventoryItem.StructSize / 8; i++)
{
if (this.dataUInt64[i] != other.dataUInt64[i])
return false;
@@ -173,7 +163,7 @@ public unsafe struct GameInventoryItem : IEquatable
public override int GetHashCode()
{
var k = 0x5a8447b91aff51b4UL;
- for (var i = 0; i < StructSizeInBytes / 8; i++)
+ for (var i = 0; i < InventoryItem.StructSize / 8; i++)
k ^= this.dataUInt64[i];
return unchecked((int)(k ^ (k >> 32)));
}
diff --git a/Dalamud/Game/Network/GameNetwork.cs b/Dalamud/Game/Network/GameNetwork.cs
index b51232ece..5022eb93d 100644
--- a/Dalamud/Game/Network/GameNetwork.cs
+++ b/Dalamud/Game/Network/GameNetwork.cs
@@ -6,6 +6,9 @@ using Dalamud.IoC;
using Dalamud.IoC.Internal;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
+
+using FFXIVClientStructs.FFXIV.Client.Network;
+
using Serilog;
namespace Dalamud.Game.Network;
@@ -14,10 +17,10 @@ namespace Dalamud.Game.Network;
/// This class handles interacting with game network events.
///
[ServiceManager.EarlyLoadedService]
-internal sealed class GameNetwork : IInternalDisposableService, IGameNetwork
+internal sealed unsafe class GameNetwork : IInternalDisposableService, IGameNetwork
{
private readonly GameNetworkAddressResolver address;
- private readonly Hook processZonePacketDownHook;
+ private readonly Hook processZonePacketDownHook;
private readonly Hook processZonePacketUpHook;
private readonly HitchDetector hitchDetectorUp;
@@ -25,11 +28,9 @@ internal sealed class GameNetwork : IInternalDisposableService, IGameNetwork
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service.Get();
-
- private IntPtr baseAddress;
-
+
[ServiceManager.ServiceConstructor]
- private GameNetwork(TargetSigScanner sigScanner)
+ private unsafe GameNetwork(TargetSigScanner sigScanner)
{
this.hitchDetectorUp = new HitchDetector("GameNetworkUp", this.configuration.GameNetworkUpHitch);
this.hitchDetectorDown = new HitchDetector("GameNetworkDown", this.configuration.GameNetworkDownHitch);
@@ -37,20 +38,19 @@ internal sealed class GameNetwork : IInternalDisposableService, IGameNetwork
this.address = new GameNetworkAddressResolver();
this.address.Setup(sigScanner);
+ var onReceivePacketAddress = (nint)PacketDispatcher.StaticVirtualTablePointer->OnReceivePacket;
+
Log.Verbose("===== G A M E N E T W O R K =====");
- Log.Verbose($"ProcessZonePacketDown address {Util.DescribeAddress(this.address.ProcessZonePacketDown)}");
+ Log.Verbose($"OnReceivePacket address {Util.DescribeAddress(onReceivePacketAddress)}");
Log.Verbose($"ProcessZonePacketUp address {Util.DescribeAddress(this.address.ProcessZonePacketUp)}");
- this.processZonePacketDownHook = Hook.FromAddress(this.address.ProcessZonePacketDown, this.ProcessZonePacketDownDetour);
+ this.processZonePacketDownHook = Hook.FromAddress(onReceivePacketAddress, this.ProcessZonePacketDownDetour);
this.processZonePacketUpHook = Hook.FromAddress(this.address.ProcessZonePacketUp, this.ProcessZonePacketUpDetour);
this.processZonePacketDownHook.Enable();
this.processZonePacketUpHook.Enable();
}
- [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
- private delegate void ProcessZonePacketDownDelegate(IntPtr a, uint targetId, IntPtr dataPtr);
-
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate byte ProcessZonePacketUpDelegate(IntPtr a1, IntPtr dataPtr, IntPtr a3, byte a4);
@@ -64,10 +64,8 @@ internal sealed class GameNetwork : IInternalDisposableService, IGameNetwork
this.processZonePacketUpHook.Dispose();
}
- private void ProcessZonePacketDownDetour(IntPtr a, uint targetId, IntPtr dataPtr)
+ private void ProcessZonePacketDownDetour(PacketDispatcher* dispatcher, uint targetId, IntPtr dataPtr)
{
- this.baseAddress = a;
-
this.hitchDetectorDown.Start();
// Go back 0x10 to get back to the start of the packet header
@@ -78,7 +76,7 @@ internal sealed class GameNetwork : IInternalDisposableService, IGameNetwork
// Call events
this.NetworkMessage?.Invoke(dataPtr + 0x20, (ushort)Marshal.ReadInt16(dataPtr, 0x12), 0, targetId, NetworkMessageDirection.ZoneDown);
- this.processZonePacketDownHook.Original(a, targetId, dataPtr + 0x10);
+ this.processZonePacketDownHook.Original(dispatcher, targetId, dataPtr + 0x10);
}
catch (Exception ex)
{
@@ -96,7 +94,7 @@ internal sealed class GameNetwork : IInternalDisposableService, IGameNetwork
Log.Error(ex, "Exception on ProcessZonePacketDown hook. Header: " + header);
- this.processZonePacketDownHook.Original(a, targetId, dataPtr + 0x10);
+ this.processZonePacketDownHook.Original(dispatcher, targetId, dataPtr + 0x10);
}
this.hitchDetectorDown.Stop();
diff --git a/Dalamud/Game/Network/GameNetworkAddressResolver.cs b/Dalamud/Game/Network/GameNetworkAddressResolver.cs
index 69b97c59d..de92f7c10 100644
--- a/Dalamud/Game/Network/GameNetworkAddressResolver.cs
+++ b/Dalamud/Game/Network/GameNetworkAddressResolver.cs
@@ -5,11 +5,6 @@ namespace Dalamud.Game.Network;
///
internal sealed class GameNetworkAddressResolver : BaseAddressResolver
{
- ///
- /// Gets the address of the ProcessZonePacketDown method.
- ///
- public IntPtr ProcessZonePacketDown { get; private set; }
-
///
/// Gets the address of the ProcessZonePacketUp method.
///
@@ -18,9 +13,6 @@ internal sealed class GameNetworkAddressResolver : BaseAddressResolver
///
protected override void Setup64Bit(ISigScanner sig)
{
- // ProcessZonePacket = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 7A FF 0F B7 57 02 8D 42 89 3D 5F 02 00 00 0F 87 60 01 00 00 4C 8D 05");
- // ProcessZonePacket = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 73 FF 0F B7 57 02 8D 42 ?? 3D ?? ?? 00 00 0F 87 60 01 00 00 4C 8D 05");
- this.ProcessZonePacketDown = sig.ScanText("40 53 56 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 44 24 ?? 8B F2");
- this.ProcessZonePacketUp = sig.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 4C 89 64 24 ?? 55 41 56 41 57 48 8B EC 48 83 EC 70");
+ this.ProcessZonePacketUp = sig.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 4C 89 64 24 ?? 55 41 56 41 57 48 8B EC 48 83 EC 70"); // unnamed in cs
}
}
diff --git a/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/Types/UniversalisTaxData.cs b/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/Types/UniversalisTaxData.cs
index 72f54773d..2277920a7 100644
--- a/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/Types/UniversalisTaxData.cs
+++ b/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/Types/UniversalisTaxData.cs
@@ -48,4 +48,10 @@ internal class UniversalisTaxData
///
[JsonProperty("sharlayan")]
public uint Sharlayan { get; set; }
+
+ ///
+ /// Gets or sets Tuliyollal's current tax rate.
+ ///
+ [JsonProperty("tuliyollal")]
+ public uint Tuliyollal { get; set; }
}
diff --git a/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs b/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs
index 5215cf030..9528a9b50 100644
--- a/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs
+++ b/Dalamud/Game/Network/Internal/MarketBoardUploaders/Universalis/UniversalisMarketBoardUploader.cs
@@ -131,6 +131,7 @@ internal class UniversalisMarketBoardUploader : IMarketBoardUploader
Kugane = taxRates.KuganeTax,
Crystarium = taxRates.CrystariumTax,
Sharlayan = taxRates.SharlayanTax,
+ Tuliyollal = taxRates.TuliyollalTax,
},
};
diff --git a/Dalamud/Game/Network/Internal/NetworkHandlers.cs b/Dalamud/Game/Network/Internal/NetworkHandlers.cs
index 2017be4bf..a25444f10 100644
--- a/Dalamud/Game/Network/Internal/NetworkHandlers.cs
+++ b/Dalamud/Game/Network/Internal/NetworkHandlers.cs
@@ -15,6 +15,9 @@ using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Hooking;
using Dalamud.Networking.Http;
using Dalamud.Utility;
+
+using FFXIVClientStructs.FFXIV.Client.Game.InstanceContent;
+using FFXIVClientStructs.FFXIV.Client.Network;
using FFXIVClientStructs.FFXIV.Client.UI.Info;
using Lumina.Excel.Sheets;
using Serilog;
@@ -35,13 +38,13 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
private readonly NetworkHandlersAddressResolver addressResolver;
- private readonly Hook cfPopHook;
- private readonly Hook mbPurchaseHook;
- private readonly Hook mbHistoryHook;
+ private readonly Hook cfPopHook;
+ private readonly Hook mbPurchaseHook;
+ private readonly Hook mbHistoryHook;
private readonly Hook customTalkHook; // used for marketboard taxes
- private readonly Hook mbItemRequestStartHook;
- private readonly Hook mbOfferingsHook;
- private readonly Hook mbSendPurchaseRequestHook;
+ private readonly Hook mbItemRequestStartHook;
+ private readonly Hook mbOfferingsHook;
+ private readonly Hook mbSendPurchaseRequestHook;
[ServiceManager.ServiceDependency]
private readonly DalamudConfiguration configuration = Service.Get();
@@ -134,14 +137,14 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
this.handleMarketBoardPurchaseHandler = this.HandleMarketBoardPurchaseHandler();
this.mbPurchaseHook =
- Hook.FromAddress(
- this.addressResolver.MarketBoardPurchasePacketHandler,
+ Hook.FromAddress(
+ PacketDispatcher.Addresses.HandleMarketBoardPurchasePacket.Value,
this.MarketPurchasePacketDetour);
this.mbPurchaseHook.Enable();
this.mbHistoryHook =
- Hook.FromAddress(
- this.addressResolver.MarketBoardHistoryPacketHandler,
+ Hook.FromAddress(
+ InfoProxyItemSearch.Addresses.ProcessItemHistory.Value,
this.MarketHistoryPacketDetour);
this.mbHistoryHook.Enable();
@@ -151,22 +154,22 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
this.CustomTalkReceiveResponseDetour);
this.customTalkHook.Enable();
- this.mbItemRequestStartHook = Hook.FromAddress(
- this.addressResolver.MarketBoardItemRequestStartPacketHandler,
+ this.mbItemRequestStartHook = Hook.FromAddress(
+ PacketDispatcher.Addresses.HandleMarketBoardItemRequestStartPacket.Value,
this.MarketItemRequestStartDetour);
this.mbItemRequestStartHook.Enable();
- this.mbOfferingsHook = Hook.FromAddress(
- this.addressResolver.InfoProxyItemSearchAddPage,
+ this.mbOfferingsHook = Hook.FromAddress(
+ (nint)InfoProxyItemSearch.StaticVirtualTablePointer->AddPage,
this.MarketBoardOfferingsDetour);
this.mbOfferingsHook.Enable();
- this.mbSendPurchaseRequestHook = Hook.FromAddress(
- this.addressResolver.BuildMarketBoardPurchaseHandlerPacket,
+ this.mbSendPurchaseRequestHook = Hook.FromAddress(
+ InfoProxyItemSearch.Addresses.SendPurchaseRequestPacket.Value,
this.MarketBoardSendPurchaseRequestDetour);
this.mbSendPurchaseRequestHook.Enable();
- this.cfPopHook = Hook.FromAddress(this.addressResolver.CfPopPacketHandler, this.CfPopDetour);
+ this.cfPopHook = Hook.FromAddress(PublicContentDirector.Addresses.HandleEnterContentInfoPacket.Value, this.CfPopDetour);
this.cfPopHook.Enable();
}
@@ -183,8 +186,6 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
private delegate byte MarketBoardSendPurchaseRequestPacket(InfoProxyItemSearch* infoProxy);
- private delegate nint CfPopDelegate(nint packetData);
-
///
/// Event which gets fired when a duty is ready.
///
@@ -263,7 +264,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
this.cfPopHook.Dispose();
}
- private unsafe nint CfPopDetour(nint packetData)
+ private unsafe nint CfPopDetour(PublicContentDirector.EnterContentInfoPacket* packetData)
{
var result = this.cfPopHook.OriginalDisposeSafe(packetData);
@@ -529,7 +530,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
return this.configuration.IsMbCollect;
}
- private nint MarketPurchasePacketDetour(nint a1, nint packetData)
+ private void MarketPurchasePacketDetour(PacketDispatcher* a1, nint packetData)
{
try
{
@@ -540,10 +541,10 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
Log.Error(ex, "MarketPurchasePacketHandler threw an exception");
}
- return this.mbPurchaseHook.OriginalDisposeSafe(a1, packetData);
+ this.mbPurchaseHook.OriginalDisposeSafe(a1, packetData);
}
- private nint MarketHistoryPacketDetour(nint a1, nint packetData, uint a3, char a4)
+ private void MarketHistoryPacketDetour(InfoProxyItemSearch* a1, nint packetData)
{
try
{
@@ -554,7 +555,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
Log.Error(ex, "MarketHistoryPacketDetour threw an exception");
}
- return this.mbHistoryHook.OriginalDisposeSafe(a1, packetData, a3, a4);
+ this.mbHistoryHook.OriginalDisposeSafe(a1, packetData);
}
private void CustomTalkReceiveResponseDetour(nuint a1, ushort eventId, byte responseId, uint* args, byte argCount)
@@ -573,7 +574,7 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
this.customTalkHook.OriginalDisposeSafe(a1, eventId, responseId, args, argCount);
}
- private nint MarketItemRequestStartDetour(nint a1, nint packetRef)
+ private void MarketItemRequestStartDetour(PacketDispatcher* a1, nint packetRef)
{
try
{
@@ -584,10 +585,10 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
Log.Error(ex, "MarketItemRequestStartDetour threw an exception");
}
- return this.mbItemRequestStartHook.OriginalDisposeSafe(a1, packetRef);
+ this.mbItemRequestStartHook.OriginalDisposeSafe(a1, packetRef);
}
- private byte MarketBoardOfferingsDetour(nint a1, nint packetRef)
+ private void MarketBoardOfferingsDetour(InfoProxyItemSearch* a1, nint packetRef)
{
try
{
@@ -598,10 +599,10 @@ internal unsafe class NetworkHandlers : IInternalDisposableService
Log.Error(ex, "MarketBoardOfferingsDetour threw an exception");
}
- return this.mbOfferingsHook.OriginalDisposeSafe(a1, packetRef);
+ this.mbOfferingsHook.OriginalDisposeSafe(a1, packetRef);
}
- private byte MarketBoardSendPurchaseRequestDetour(InfoProxyItemSearch* infoProxyItemSearch)
+ private bool MarketBoardSendPurchaseRequestDetour(InfoProxyItemSearch* infoProxyItemSearch)
{
try
{
diff --git a/Dalamud/Game/Network/Internal/NetworkHandlersAddressResolver.cs b/Dalamud/Game/Network/Internal/NetworkHandlersAddressResolver.cs
index 166b4d67a..18c48b67d 100644
--- a/Dalamud/Game/Network/Internal/NetworkHandlersAddressResolver.cs
+++ b/Dalamud/Game/Network/Internal/NetworkHandlersAddressResolver.cs
@@ -5,62 +5,17 @@
///
internal class NetworkHandlersAddressResolver : BaseAddressResolver
{
- ///
- /// Gets or sets the pointer to the method responsible for handling CfPop packets.
- ///
- public nint CfPopPacketHandler { get; set; }
-
- ///
- /// Gets or sets the pointer to the method responsible for handling market board history. In this case, we are
- /// sigging the packet handler method directly.
- ///
- public nint MarketBoardHistoryPacketHandler { get; set; }
-
- ///
- /// Gets or sets the pointer to the method responsible for processing the market board purchase packet. In this
- /// case, we are sigging the packet handler method directly.
- ///
- public nint MarketBoardPurchasePacketHandler { get; set; }
-
///
/// Gets or sets the pointer to the method responsible for custom talk events. Necessary for marketboard tax data,
/// as this isn't really exposed anywhere else.
///
public nint CustomTalkEventResponsePacketHandler { get; set; }
-
- ///
- /// Gets or sets the pointer to the method responsible for the marketboard ItemRequestStart packet.
- ///
- public nint MarketBoardItemRequestStartPacketHandler { get; set; }
-
- ///
- /// Gets or sets the pointer to the InfoProxyItemSearch.AddPage method, used to load market data.
- ///
- public nint InfoProxyItemSearchAddPage { get; set; }
-
- ///
- /// Gets or sets the pointer to the method inside InfoProxyItemSearch that is responsible for building and sending
- /// a purchase request packet.
- ///
- public nint BuildMarketBoardPurchaseHandlerPacket { get; set; }
///
protected override void Setup64Bit(ISigScanner scanner)
{
- this.CfPopPacketHandler = scanner.ScanText("40 53 57 48 83 EC 78 48 8B D9 48 8D 0D");
-
- // TODO: I know this is a CC. I want things working for now. (KW)
- this.MarketBoardHistoryPacketHandler = scanner.ScanText(
- "40 53 48 83 EC 20 48 8B 0D ?? ?? ?? ?? 48 8B DA E8 ?? ?? ?? ?? 48 85 C0 74 2F 4C 8B 00 48 8B C8 41 FF 90 18 01 00 00 48 8B C8 BA 0B 00 00 00 E8 ?? ?? ?? ?? 48 85 C0 74 10 48 8B D3 48 8B C8 48 83 C4 20 5B E9 ?? ?? ?? ?? 48 83 C4 20 5B C3 CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC 40 53");
- this.MarketBoardPurchasePacketHandler =
- scanner.ScanText("40 55 56 41 56 48 8B EC 48 83 EC ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 45 ?? 48 8B 0D ?? ?? ?? ?? 4C 8B F2");
this.CustomTalkEventResponsePacketHandler =
- scanner.ScanText("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC ?? 49 8B D9 41 0F B6 F8 0F B7 F2 8B E9 E8 ?? ?? ?? ?? 48 8B C8 44 0F B6 CF 0F B6 44 24 ?? 44 0F B7 C6 88 44 24 ?? 8B D5 48 89 5C 24");
- this.MarketBoardItemRequestStartPacketHandler =
- scanner.ScanText("48 89 5C 24 08 57 48 83 EC 20 48 8B 0D ?? ?? ?? ?? 48 8B FA E8 ?? ?? ?? ?? 48 8B D8 48 85 C0 74 4A");
- this.InfoProxyItemSearchAddPage =
- scanner.ScanText("48 89 5C 24 ?? 57 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 0F B6 82 ?? ?? ?? ?? 48 8B FA 48 8B D9 38 41 19 74 54");
- this.BuildMarketBoardPurchaseHandlerPacket =
- scanner.ScanText("40 53 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B D9 48 8B 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 4C 8B D0 48 85 C0 0F 84 ?? ?? ?? ?? 8B 8B");
+ scanner.ScanText(
+ "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC ?? 49 8B D9 41 0F B6 F8 0F B7 F2 8B E9 E8 ?? ?? ?? ?? 48 8B C8 44 0F B6 CF 0F B6 44 24 ?? 44 0F B7 C6 88 44 24 ?? 8B D5 48 89 5C 24"); // unnamed in CS
}
}
diff --git a/Dalamud/Interface/Components/ImGuiComponents.ColorPickerWithPalette.cs b/Dalamud/Interface/Components/ImGuiComponents.ColorPickerWithPalette.cs
index aa707aecb..e2f68eab2 100644
--- a/Dalamud/Interface/Components/ImGuiComponents.ColorPickerWithPalette.cs
+++ b/Dalamud/Interface/Components/ImGuiComponents.ColorPickerWithPalette.cs
@@ -1,6 +1,8 @@
using System.Numerics;
using Dalamud.Interface.Utility;
+using Dalamud.Interface.Utility.Raii;
+
using ImGuiNET;
namespace Dalamud.Interface.Components;
@@ -41,7 +43,9 @@ public static partial class ImGuiComponents
ImGui.OpenPopup($"###ColorPickerPopup{id}");
}
- if (ImGui.BeginPopup($"###ColorPickerPopup{id}"))
+ using var popup = ImRaii.Popup($"###ColorPickerPopup{id}");
+
+ if (popup)
{
if (ImGui.ColorPicker4($"###ColorPicker{id}", ref existingColor, flags))
{
@@ -61,8 +65,6 @@ public static partial class ImGuiComponents
ImGui.SameLine();
}
}
-
- ImGui.EndPopup();
}
return selectedColor;
diff --git a/Dalamud/Interface/Components/ImGuiComponents.DisabledButton.cs b/Dalamud/Interface/Components/ImGuiComponents.DisabledButton.cs
index 907ad0aeb..ab2ed4724 100644
--- a/Dalamud/Interface/Components/ImGuiComponents.DisabledButton.cs
+++ b/Dalamud/Interface/Components/ImGuiComponents.DisabledButton.cs
@@ -1,5 +1,7 @@
using System.Numerics;
+using Dalamud.Interface.Utility.Raii;
+
using ImGuiNET;
namespace Dalamud.Interface.Components;
@@ -21,17 +23,16 @@ public static partial class ImGuiComponents
/// Indicator if button is clicked.
public static bool DisabledButton(FontAwesomeIcon icon, int? id = null, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null, float alphaMult = .5f)
{
- ImGui.PushFont(UiBuilder.IconFont);
+ using (ImRaii.PushFont(UiBuilder.IconFont))
+ {
+ var text = icon.ToIconString();
+ if (id.HasValue)
+ {
+ text = $"{text}##{id}";
+ }
- var text = icon.ToIconString();
- if (id.HasValue)
- text = $"{text}##{id}";
-
- var button = DisabledButton(text, defaultColor, activeColor, hoveredColor, alphaMult);
-
- ImGui.PopFont();
-
- return button;
+ return DisabledButton(text, defaultColor, activeColor, hoveredColor, alphaMult);
+ }
}
///
@@ -45,31 +46,28 @@ public static partial class ImGuiComponents
/// Indicator if button is clicked.
public static bool DisabledButton(string labelWithId, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null, float alphaMult = .5f)
{
+ using var col = new ImRaii.Color();
+
if (defaultColor.HasValue)
- ImGui.PushStyleColor(ImGuiCol.Button, defaultColor.Value);
+ {
+ col.Push(ImGuiCol.Button, defaultColor.Value);
+ }
if (activeColor.HasValue)
- ImGui.PushStyleColor(ImGuiCol.ButtonActive, activeColor.Value);
+ {
+ col.Push(ImGuiCol.ButtonActive, activeColor.Value);
+ }
if (hoveredColor.HasValue)
- ImGui.PushStyleColor(ImGuiCol.ButtonHovered, hoveredColor.Value);
+ {
+ col.Push(ImGuiCol.ButtonHovered, hoveredColor.Value);
+ }
var style = ImGui.GetStyle();
- ImGui.PushStyleVar(ImGuiStyleVar.Alpha, style.Alpha * alphaMult);
- var button = ImGui.Button(labelWithId);
-
- ImGui.PopStyleVar();
-
- if (defaultColor.HasValue)
- ImGui.PopStyleColor();
-
- if (activeColor.HasValue)
- ImGui.PopStyleColor();
-
- if (hoveredColor.HasValue)
- ImGui.PopStyleColor();
-
- return button;
+ using (ImRaii.PushStyle(ImGuiStyleVar.Alpha, style.Alpha * alphaMult))
+ {
+ return ImGui.Button(labelWithId);
+ }
}
}
diff --git a/Dalamud/Interface/Components/ImGuiComponents.HelpMarker.cs b/Dalamud/Interface/Components/ImGuiComponents.HelpMarker.cs
index f0ecf2f2f..3392136d1 100644
--- a/Dalamud/Interface/Components/ImGuiComponents.HelpMarker.cs
+++ b/Dalamud/Interface/Components/ImGuiComponents.HelpMarker.cs
@@ -1,3 +1,7 @@
+using Dalamud.Interface.Utility.Raii;
+
+using FFXIVClientStructs.FFXIV.Common.Math;
+
using ImGuiNET;
namespace Dalamud.Interface.Components;
@@ -18,17 +22,32 @@ public static partial class ImGuiComponents
///
/// The text to display on hover.
/// The icon to use.
- public static void HelpMarker(string helpText, FontAwesomeIcon icon)
+ /// The color of the icon.
+ public static void HelpMarker(string helpText, FontAwesomeIcon icon, Vector4? color = null)
{
+ using var col = new ImRaii.Color();
+
+ if (color.HasValue)
+ {
+ col.Push(ImGuiCol.TextDisabled, color.Value);
+ }
+
ImGui.SameLine();
- ImGui.PushFont(UiBuilder.IconFont);
- ImGui.TextDisabled(icon.ToIconString());
- ImGui.PopFont();
- if (!ImGui.IsItemHovered()) return;
- ImGui.BeginTooltip();
- ImGui.PushTextWrapPos(ImGui.GetFontSize() * 35.0f);
- ImGui.TextUnformatted(helpText);
- ImGui.PopTextWrapPos();
- ImGui.EndTooltip();
+
+ using (ImRaii.PushFont(UiBuilder.IconFont))
+ {
+ ImGui.TextDisabled(icon.ToIconString());
+ }
+
+ if (ImGui.IsItemHovered())
+ {
+ using (ImRaii.Tooltip())
+ {
+ using (ImRaii.TextWrapPos(ImGui.GetFontSize() * 35.0f))
+ {
+ ImGui.TextUnformatted(helpText);
+ }
+ }
+ }
}
}
diff --git a/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs b/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs
index dc2c99608..5e64fe463 100644
--- a/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs
+++ b/Dalamud/Interface/Components/ImGuiComponents.IconButton.cs
@@ -1,6 +1,8 @@
using System.Numerics;
using Dalamud.Interface.Utility;
+using Dalamud.Interface.Utility.Raii;
+
using ImGuiNET;
namespace Dalamud.Interface.Components;
@@ -15,8 +17,26 @@ public static partial class ImGuiComponents
///
/// The icon for the button.
/// Indicator if button is clicked.
- public static bool IconButton(FontAwesomeIcon icon)
- => IconButton(icon, null, null, null);
+ public static bool IconButton(FontAwesomeIcon icon) => IconButton(icon, null);
+
+ ///
+ /// IconButton component to use an icon as a button.
+ ///
+ /// The icon for the button.
+ /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.
+ /// Indicator if button is clicked.
+ public static bool IconButton(FontAwesomeIcon icon, Vector2 size) => IconButton(icon, null, null, null, size);
+
+ ///
+ /// IconButton component to use an icon as a button.
+ ///
+ /// The icon for the button.
+ /// The default color of the button.
+ /// The color of the button when active.
+ /// The color of the button when hovered.
+ /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.
+ /// Indicator if button is clicked.
+ public static bool IconButton(FontAwesomeIcon icon, Vector4? defaultColor, Vector4? activeColor = null, Vector4? hoveredColor = null, Vector2? size = null) => IconButton($"{icon.ToIconString()}", defaultColor, activeColor, hoveredColor, size);
///
/// IconButton component to use an icon as a button.
@@ -24,8 +44,28 @@ public static partial class ImGuiComponents
/// The ID of the button.
/// The icon for the button.
/// Indicator if button is clicked.
- public static bool IconButton(int id, FontAwesomeIcon icon)
- => IconButton(id, icon, null, null, null);
+ public static bool IconButton(int id, FontAwesomeIcon icon) => IconButton(id, icon, null);
+
+ ///
+ /// IconButton component to use an icon as a button.
+ ///
+ /// The ID of the button.
+ /// The icon for the button.
+ /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.
+ /// Indicator if button is clicked.
+ public static bool IconButton(int id, FontAwesomeIcon icon, Vector2 size) => IconButton(id, icon, null, null, null, size);
+
+ ///
+ /// IconButton component to use an icon as a button with color options.
+ ///
+ /// The ID of the button.
+ /// The icon for the button.
+ /// The default color of the button.
+ /// The color of the button when active.
+ /// The color of the button when hovered.
+ /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.
+ /// Indicator if button is clicked.
+ public static bool IconButton(int id, FontAwesomeIcon icon, Vector4? defaultColor, Vector4? activeColor = null, Vector4? hoveredColor = null, Vector2? size = null) => IconButton($"{icon.ToIconString()}##{id}", defaultColor, activeColor, hoveredColor, size);
///
/// IconButton component to use an icon as a button.
@@ -33,51 +73,45 @@ public static partial class ImGuiComponents
/// The ID of the button.
/// The icon for the button.
/// Indicator if button is clicked.
- public static bool IconButton(string id, FontAwesomeIcon icon)
- => IconButton(id, icon, null, null, null);
+ public static bool IconButton(string id, FontAwesomeIcon icon) => IconButton(id, icon, null);
+
+ ///
+ /// IconButton component to use an icon as a button.
+ ///
+ /// The ID of the button.
+ /// The icon for the button.
+ /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.
+ /// Indicator if button is clicked.
+ public static bool IconButton(string id, FontAwesomeIcon icon, Vector2 size)
+ => IconButton(id, icon, null, null, null, size);
+
+ ///
+ /// IconButton component to use an icon as a button with color options.
+ ///
+ /// The ID of the button.
+ /// The icon for the button.
+ /// The default color of the button.
+ /// The color of the button when active.
+ /// The color of the button when hovered.
+ /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.
+ /// Indicator if button is clicked.
+ public static bool IconButton(string id, FontAwesomeIcon icon, Vector4? defaultColor, Vector4? activeColor = null, Vector4? hoveredColor = null, Vector2? size = null)
+ => IconButton($"{icon.ToIconString()}##{id}", defaultColor, activeColor, hoveredColor, size);
///
/// IconButton component to use an icon as a button.
///
/// Text already containing the icon string.
/// Indicator if button is clicked.
- public static bool IconButton(string iconText)
- => IconButton(iconText, null, null, null);
+ public static bool IconButton(string iconText) => IconButton(iconText, null);
///
/// IconButton component to use an icon as a button.
///
- /// The icon for the button.
- /// The default color of the button.
- /// The color of the button when active.
- /// The color of the button when hovered.
+ /// Text already containing the icon string.
+ /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.
/// Indicator if button is clicked.
- public static bool IconButton(FontAwesomeIcon icon, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
- => IconButton($"{icon.ToIconString()}", defaultColor, activeColor, hoveredColor);
-
- ///
- /// IconButton component to use an icon as a button with color options.
- ///
- /// The ID of the button.
- /// The icon for the button.
- /// The default color of the button.
- /// The color of the button when active.
- /// The color of the button when hovered.
- /// Indicator if button is clicked.
- public static bool IconButton(int id, FontAwesomeIcon icon, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
- => IconButton($"{icon.ToIconString()}##{id}", defaultColor, activeColor, hoveredColor);
-
- ///
- /// IconButton component to use an icon as a button with color options.
- ///
- /// The ID of the button.
- /// The icon for the button.
- /// The default color of the button.
- /// The color of the button when active.
- /// The color of the button when hovered.
- /// Indicator if button is clicked.
- public static bool IconButton(string id, FontAwesomeIcon icon, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
- => IconButton($"{icon.ToIconString()}##{id}", defaultColor, activeColor, hoveredColor);
+ public static bool IconButton(string iconText, Vector2 size) => IconButton(iconText, null, null, null, size);
///
/// IconButton component to use an icon as a button with color options.
@@ -86,62 +120,72 @@ public static partial class ImGuiComponents
/// The default color of the button.
/// The color of the button when active.
/// The color of the button when hovered.
+ /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon.
/// Indicator if button is clicked.
- public static bool IconButton(string iconText, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
+ public static bool IconButton(string iconText, Vector4? defaultColor, Vector4? activeColor = null, Vector4? hoveredColor = null, Vector2? size = null)
{
- var numColors = 0;
+ using var col = new ImRaii.Color();
if (defaultColor.HasValue)
{
- ImGui.PushStyleColor(ImGuiCol.Button, defaultColor.Value);
- numColors++;
+ col.Push(ImGuiCol.Button, defaultColor.Value);
}
if (activeColor.HasValue)
{
- ImGui.PushStyleColor(ImGuiCol.ButtonActive, activeColor.Value);
- numColors++;
+ col.Push(ImGuiCol.ButtonActive, activeColor.Value);
}
if (hoveredColor.HasValue)
{
- ImGui.PushStyleColor(ImGuiCol.ButtonHovered, hoveredColor.Value);
- numColors++;
+ col.Push(ImGuiCol.ButtonHovered, hoveredColor.Value);
+ }
+
+ if (size.HasValue)
+ {
+ size *= ImGuiHelpers.GlobalScale;
}
var icon = iconText;
- if (icon.Contains("#"))
- icon = icon[..icon.IndexOf("#", StringComparison.Ordinal)];
+ if (icon.Contains('#'))
+ {
+ icon = icon[..icon.IndexOf('#', StringComparison.Ordinal)];
+ }
- ImGui.PushID(iconText);
+ bool button;
- ImGui.PushFont(UiBuilder.IconFont);
- var iconSize = ImGui.CalcTextSize(icon);
- ImGui.PopFont();
-
- var dl = ImGui.GetWindowDrawList();
- var cursor = ImGui.GetCursorScreenPos();
-
- // Draw an ImGui button with the icon and text
- var buttonWidth = iconSize.X + (ImGui.GetStyle().FramePadding.X * 2);
- var buttonHeight = ImGui.GetFrameHeight();
- var button = ImGui.Button(string.Empty, new Vector2(buttonWidth, buttonHeight));
-
- // Draw the icon on the window drawlist
- var iconPos = new Vector2(cursor.X + ImGui.GetStyle().FramePadding.X, cursor.Y + ImGui.GetStyle().FramePadding.Y);
-
- ImGui.PushFont(UiBuilder.IconFont);
- dl.AddText(iconPos, ImGui.GetColorU32(ImGuiCol.Text), icon);
- ImGui.PopFont();
+ using (ImRaii.PushFont(UiBuilder.IconFont))
+ {
+ var iconSize = ImGui.CalcTextSize(icon);
+ var cursor = ImGui.GetCursorScreenPos();
- ImGui.PopID();
+ var width = size is { X: not 0 } ? size.Value.X : iconSize.X + (ImGui.GetStyle().FramePadding.X * 2);
+ var height = size is { Y: not 0 } ? size.Value.Y : ImGui.GetFrameHeight();
- if (numColors > 0)
- ImGui.PopStyleColor(numColors);
+ var buttonSize = new Vector2(width, height);
+
+ using (ImRaii.PushId(iconText))
+ {
+ button = ImGui.Button(string.Empty, buttonSize);
+ }
+
+ var iconPos = cursor + ((buttonSize - iconSize) / 2f);
+
+ ImGui.GetWindowDrawList().AddText(iconPos, ImGui.GetColorU32(ImGuiCol.Text), icon);
+ }
return button;
}
+ ///
+ /// IconButton component to use an icon as a button with color options.
+ ///
+ /// Icon to show.
+ /// Text to show.
+ /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon & text.
+ /// Indicator if button is clicked.
+ public static bool IconButtonWithText(FontAwesomeIcon icon, string text, Vector2 size) => IconButtonWithText(icon, text, null, null, null, size);
+
///
/// IconButton component to use an icon as a button with color options.
///
@@ -150,61 +194,72 @@ public static partial class ImGuiComponents
/// The default color of the button.
/// The color of the button when active.
/// The color of the button when hovered.
+ /// Sets the size of the button. If either dimension is set to 0, that dimension will conform to the size of the icon & text.
/// Indicator if button is clicked.
- public static bool IconButtonWithText(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
+ public static bool IconButtonWithText(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null, Vector2? size = null)
{
- var numColors = 0;
+ using var col = new ImRaii.Color();
if (defaultColor.HasValue)
{
- ImGui.PushStyleColor(ImGuiCol.Button, defaultColor.Value);
- numColors++;
+ col.Push(ImGuiCol.Button, defaultColor.Value);
}
if (activeColor.HasValue)
{
- ImGui.PushStyleColor(ImGuiCol.ButtonActive, activeColor.Value);
- numColors++;
+ col.Push(ImGuiCol.ButtonActive, activeColor.Value);
}
if (hoveredColor.HasValue)
{
- ImGui.PushStyleColor(ImGuiCol.ButtonHovered, hoveredColor.Value);
- numColors++;
+ col.Push(ImGuiCol.ButtonHovered, hoveredColor.Value);
}
- ImGui.PushID(text);
+ if (size.HasValue)
+ {
+ size *= ImGuiHelpers.GlobalScale;
+ }
+
+ bool button;
+
+ Vector2 iconSize;
+ using (ImRaii.PushFont(UiBuilder.IconFont))
+ {
+ iconSize = ImGui.CalcTextSize(icon.ToIconString());
+ }
+
+ var textStr = text;
+ if (textStr.Contains('#'))
+ {
+ textStr = textStr[..textStr.IndexOf('#', StringComparison.Ordinal)];
+ }
+
+ var framePadding = ImGui.GetStyle().FramePadding;
+ var iconPadding = 3 * ImGuiHelpers.GlobalScale;
- ImGui.PushFont(UiBuilder.IconFont);
- var iconSize = ImGui.CalcTextSize(icon.ToIconString());
- ImGui.PopFont();
-
- var textSize = ImGui.CalcTextSize(text);
- var dl = ImGui.GetWindowDrawList();
var cursor = ImGui.GetCursorScreenPos();
- var iconPadding = 3 * ImGuiHelpers.GlobalScale;
-
- // Draw an ImGui button with the icon and text
- var buttonWidth = iconSize.X + textSize.X + (ImGui.GetStyle().FramePadding.X * 2) + iconPadding;
- var buttonHeight = ImGui.GetFrameHeight();
- var button = ImGui.Button(string.Empty, new Vector2(buttonWidth, buttonHeight));
-
- // Draw the icon on the window drawlist
- var iconPos = new Vector2(cursor.X + ImGui.GetStyle().FramePadding.X, cursor.Y + ImGui.GetStyle().FramePadding.Y);
-
- ImGui.PushFont(UiBuilder.IconFont);
- dl.AddText(iconPos, ImGui.GetColorU32(ImGuiCol.Text), icon.ToIconString());
- ImGui.PopFont();
-
- // Draw the text on the window drawlist
- var textPos = new Vector2(iconPos.X + iconSize.X + iconPadding, cursor.Y + ImGui.GetStyle().FramePadding.Y);
- dl.AddText(textPos, ImGui.GetColorU32(ImGuiCol.Text), text);
+ using (ImRaii.PushId(text))
+ {
+ var textSize = ImGui.CalcTextSize(textStr);
- ImGui.PopID();
+ var width = size is { X: not 0 } ? size.Value.X : iconSize.X + textSize.X + (framePadding.X * 2) + iconPadding;
+ var height = size is { Y: not 0 } ? size.Value.Y : ImGui.GetFrameHeight();
- if (numColors > 0)
- ImGui.PopStyleColor(numColors);
+ button = ImGui.Button(string.Empty, new Vector2(width, height));
+ }
+
+ var iconPos = cursor + framePadding;
+ var textPos = new Vector2(iconPos.X + iconSize.X + iconPadding, cursor.Y + framePadding.Y);
+
+ var dl = ImGui.GetWindowDrawList();
+
+ using (ImRaii.PushFont(UiBuilder.IconFont))
+ {
+ dl.AddText(iconPos, ImGui.GetColorU32(ImGuiCol.Text), icon.ToIconString());
+ }
+
+ dl.AddText(textPos, ImGui.GetColorU32(ImGuiCol.Text), textStr);
return button;
}
@@ -217,16 +272,15 @@ public static partial class ImGuiComponents
/// Width.
internal static float GetIconButtonWithTextWidth(FontAwesomeIcon icon, string text)
{
- ImGui.PushFont(UiBuilder.IconFont);
- var iconSize = ImGui.CalcTextSize(icon.ToIconString());
- ImGui.PopFont();
-
- var textSize = ImGui.CalcTextSize(text);
- var dl = ImGui.GetWindowDrawList();
- var cursor = ImGui.GetCursorScreenPos();
+ using (ImRaii.PushFont(UiBuilder.IconFont))
+ {
+ var iconSize = ImGui.CalcTextSize(icon.ToIconString());
- var iconPadding = 3 * ImGuiHelpers.GlobalScale;
-
- return iconSize.X + textSize.X + (ImGui.GetStyle().FramePadding.X * 2) + iconPadding;
+ var textSize = ImGui.CalcTextSize(text);
+
+ var iconPadding = 3 * ImGuiHelpers.GlobalScale;
+
+ return iconSize.X + textSize.X + (ImGui.GetStyle().FramePadding.X * 2) + iconPadding;
+ }
}
}
diff --git a/Dalamud/Interface/Components/ImGuiComponents.IconButtonSelect.cs b/Dalamud/Interface/Components/ImGuiComponents.IconButtonSelect.cs
new file mode 100644
index 000000000..3f9c469bb
--- /dev/null
+++ b/Dalamud/Interface/Components/ImGuiComponents.IconButtonSelect.cs
@@ -0,0 +1,87 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+
+using Dalamud.Interface.Utility;
+
+using ImGuiNET;
+
+namespace Dalamud.Interface.Components;
+
+public static partial class ImGuiComponents
+{
+ ///
+ /// A radio-like input that uses icon buttons.
+ ///
+ /// The type of the value being set.
+ /// Text that will be used to generate individual labels for the buttons.
+ /// The value to set.
+ /// The icons that will be displayed on each button.
+ /// The options that each button will apply.
+ /// Arranges the buttons in a grid with the given number of columns. 0 = ignored (all buttons drawn in one row).
+ /// Sets the size of all buttons. If either dimension is set to 0, that dimension will conform to the size of the icon.
+ /// The default color of the button range.
+ /// The color of the actively-selected button.
+ /// The color of the buttons when hovered.
+ /// True if any button is clicked.
+ internal static bool IconButtonSelect(string label, ref T val, IEnumerable optionIcons, IEnumerable optionValues, uint columns = 0, Vector2? buttonSize = null, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
+ {
+ var options = optionIcons.Zip(optionValues, static (icon, value) => new KeyValuePair(icon, value));
+ return IconButtonSelect(label, ref val, options, columns, buttonSize, defaultColor, activeColor, hoveredColor);
+ }
+
+ ///
+ /// A radio-like input that uses icon buttons.
+ ///
+ /// The type of the value being set.
+ /// Text that will be used to generate individual labels for the buttons.
+ /// The value to set.
+ /// A list of all icon/option pairs.
+ /// Arranges the buttons in a grid with the given number of columns. 0 = ignored (all buttons drawn in one row).
+ /// Sets the size of all buttons. If either dimension is set to 0, that dimension will conform to the size of the icon.
+ /// The default color of the button range.
+ /// The color of the actively-selected button.
+ /// The color of the buttons when hovered.
+ /// True if any button is clicked.
+ internal static unsafe bool IconButtonSelect(string label, ref T val, IEnumerable> options, uint columns = 0, Vector2? buttonSize = null, Vector4? defaultColor = null, Vector4? activeColor = null, Vector4? hoveredColor = null)
+ {
+ defaultColor ??= *ImGui.GetStyleColorVec4(ImGuiCol.Button);
+ activeColor ??= *ImGui.GetStyleColorVec4(ImGuiCol.ButtonActive);
+ hoveredColor ??= *ImGui.GetStyleColorVec4(ImGuiCol.ButtonHovered);
+
+ var result = false;
+
+ var innerSpacing = ImGui.GetStyle().ItemInnerSpacing;
+ var y = ImGui.GetCursorPosY();
+
+ var optArr = options.ToArray();
+ for (var i = 0; i < optArr.Length; i++)
+ {
+ if (i > 0)
+ {
+ if (columns == 0 || i % columns != 0)
+ {
+ ImGui.SameLine(0, innerSpacing.X);
+ }
+ else
+ {
+ y += (buttonSize is { Y: not 0 } ? buttonSize.Value.Y * ImGuiHelpers.GlobalScale : ImGui.GetFrameHeight()) + innerSpacing.Y;
+
+ ImGui.SetCursorPosY(y);
+ }
+ }
+
+ optArr[i].Deconstruct(out var icon, out var option);
+
+ var selected = val is not null && val.Equals(option);
+
+ if (IconButton($"{label}{option}{i}", icon, selected ? activeColor : defaultColor, activeColor, hoveredColor, buttonSize))
+ {
+ val = option;
+ result = true;
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/Dalamud/Interface/Components/ImGuiComponents.TextWithLabel.cs b/Dalamud/Interface/Components/ImGuiComponents.TextWithLabel.cs
index 597b472c6..43b54fc93 100644
--- a/Dalamud/Interface/Components/ImGuiComponents.TextWithLabel.cs
+++ b/Dalamud/Interface/Components/ImGuiComponents.TextWithLabel.cs
@@ -1,3 +1,5 @@
+using Dalamud.Interface.Utility.Raii;
+
using ImGuiNET;
namespace Dalamud.Interface.Components;
@@ -24,7 +26,13 @@ public static partial class ImGuiComponents
else
{
ImGui.Text(value + "*");
- if (ImGui.IsItemHovered()) ImGui.SetTooltip(hint);
+ if (ImGui.IsItemHovered())
+ {
+ using (ImRaii.Tooltip())
+ {
+ ImGui.TextUnformatted(hint);
+ }
+ }
}
}
}
diff --git a/Dalamud/Interface/Components/ImGuiComponents.ToggleSwitch.cs b/Dalamud/Interface/Components/ImGuiComponents.ToggleSwitch.cs
index 64f3d01eb..6d6e0f6c3 100644
--- a/Dalamud/Interface/Components/ImGuiComponents.ToggleSwitch.cs
+++ b/Dalamud/Interface/Components/ImGuiComponents.ToggleSwitch.cs
@@ -36,9 +36,14 @@ public static partial class ImGuiComponents
}
if (ImGui.IsItemHovered())
+ {
drawList.AddRectFilled(p, new Vector2(p.X + width, p.Y + height), ImGui.GetColorU32(!v ? colors[(int)ImGuiCol.ButtonActive] : new Vector4(0.78f, 0.78f, 0.78f, 1.0f)), height * 0.5f);
+ }
else
+ {
drawList.AddRectFilled(p, new Vector2(p.X + width, p.Y + height), ImGui.GetColorU32(!v ? colors[(int)ImGuiCol.Button] * 0.6f : new Vector4(0.35f, 0.35f, 0.35f, 1.0f)), height * 0.50f);
+ }
+
drawList.AddCircleFilled(new Vector2(p.X + radius + ((v ? 1 : 0) * (width - (radius * 2.0f))), p.Y + radius), radius - 1.5f, ImGui.ColorConvertFloat4ToU32(new Vector4(1, 1, 1, 1)));
return changed;
@@ -62,7 +67,7 @@ public static partial class ImGuiComponents
// TODO: animate
ImGui.InvisibleButton(id, new Vector2(width, height));
- var dimFactor = 0.5f;
+ const float dimFactor = 0.5f;
drawList.AddRectFilled(p, new Vector2(p.X + width, p.Y + height), ImGui.GetColorU32(v ? colors[(int)ImGuiCol.Button] * dimFactor : new Vector4(0.55f, 0.55f, 0.55f, 1.0f) * dimFactor), height * 0.50f);
drawList.AddCircleFilled(new Vector2(p.X + radius + ((v ? 1 : 0) * (width - (radius * 2.0f))), p.Y + radius), radius - 1.5f, ImGui.ColorConvertFloat4ToU32(new Vector4(1, 1, 1, 1) * dimFactor));
diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs
new file mode 100644
index 000000000..4b7a531c0
--- /dev/null
+++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.AtkValues.cs
@@ -0,0 +1,124 @@
+using Dalamud.Interface.Internal.UiDebug2.Utility;
+using Dalamud.Interface.Utility.Raii;
+using Dalamud.Memory;
+using Dalamud.Utility;
+
+using FFXIVClientStructs.FFXIV.Component.GUI;
+
+using ImGuiNET;
+
+using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
+
+namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
+
+public unsafe partial class AddonTree
+{
+ ///
+ /// Prints a table of AtkValues associated with a given addon.
+ ///
+ /// The addon to look up.
+ internal static void PrintAtkValues(AtkUnitBase* addon)
+ {
+ var atkValue = addon->AtkValues;
+ if (addon->AtkValuesCount > 0 && atkValue != null)
+ {
+ using var tree = ImRaii.TreeNode($"Atk Values [{addon->AtkValuesCount}]###atkValues_{addon->NameString}");
+ if (tree)
+ {
+ using (ImRaii.Table(
+ "atkUnitBase_atkValueTable",
+ 3,
+ ImGuiTableFlags.Borders | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg))
+ {
+ ImGui.TableSetupColumn("Index");
+ ImGui.TableSetupColumn("Type");
+ ImGui.TableSetupColumn("Value");
+ ImGui.TableHeadersRow();
+
+ try
+ {
+ for (var i = 0; i < addon->AtkValuesCount; i++)
+ {
+ ImGui.TableNextColumn();
+ if (atkValue->Type == 0)
+ {
+ ImGui.TextDisabled($"#{i}");
+ }
+ else
+ {
+ ImGui.Text($"#{i}");
+ }
+
+ ImGui.TableNextColumn();
+ if (atkValue->Type == 0)
+ {
+ ImGui.TextDisabled("Not Set");
+ }
+ else
+ {
+ ImGui.Text($"{atkValue->Type}");
+ }
+
+ ImGui.TableNextColumn();
+
+ switch (atkValue->Type)
+ {
+ case 0:
+ break;
+ case ValueType.Int:
+ case ValueType.UInt:
+ {
+ ImGui.TextUnformatted($"{atkValue->Int}");
+ break;
+ }
+
+ case ValueType.ManagedString:
+ case ValueType.String8:
+ case ValueType.String:
+ {
+ if (atkValue->String == null)
+ {
+ ImGui.TextDisabled("null");
+ }
+ else
+ {
+ var str = MemoryHelper.ReadSeStringNullTerminated(new nint(atkValue->String));
+ Util.ShowStruct(str, (ulong)atkValue);
+ }
+
+ break;
+ }
+
+ case ValueType.Bool:
+ {
+ ImGui.TextUnformatted($"{atkValue->Byte != 0}");
+ break;
+ }
+
+ case ValueType.Pointer:
+ ImGui.TextUnformatted($"{(nint)atkValue->Pointer}");
+ break;
+
+ default:
+ {
+ ImGui.TextDisabled("Unhandled Type");
+ ImGui.SameLine();
+ Util.ShowStruct(atkValue);
+ break;
+ }
+ }
+
+ atkValue++;
+ }
+ }
+ catch (Exception ex)
+ {
+ ImGui.TextColored(new(1, 0, 0, 1), $"{ex}");
+ }
+ }
+ }
+
+ Gui.PaddedSeparator();
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs
index 8affa1eac..0b1dcb66c 100644
--- a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs
+++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.FieldNames.cs
@@ -23,6 +23,11 @@ public unsafe partial class AddonTree
///
internal Dictionary> FieldNames { get; set; } = [];
+ ///
+ /// Gets or sets the size of the addon according to its Attributes in FFXIVClientStructs.
+ ///
+ internal int AddonSize { get; set; }
+
private object? GetAddonObj(AtkUnitBase* addon)
{
if (addon == null)
@@ -42,6 +47,13 @@ public unsafe partial class AddonTree
select t)
{
AddonTypeDict[this.AddonName] = t;
+
+ var size = t.StructLayoutAttribute?.Size;
+ if (size != null)
+ {
+ this.AddonSize = size.Value;
+ }
+
break;
}
}
diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs
index 2823a2058..9d6575a55 100644
--- a/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs
+++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/AddonTree.cs
@@ -3,6 +3,7 @@ using System.Linq;
using System.Numerics;
using Dalamud.Interface.Components;
+
using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
@@ -19,14 +20,12 @@ namespace Dalamud.Interface.Internal.UiDebug2.Browsing;
///
public unsafe partial class AddonTree : IDisposable
{
- private readonly nint initialPtr;
-
private AddonPopoutWindow? window;
private AddonTree(string name, nint ptr)
{
this.AddonName = name;
- this.initialPtr = ptr;
+ this.InitialPtr = ptr;
this.PopulateFieldNames(ptr);
}
@@ -35,6 +34,11 @@ public unsafe partial class AddonTree : IDisposable
///
internal string AddonName { get; init; }
+ ///
+ /// Gets the addon's pointer at the time this was created.
+ ///
+ internal nint InitialPtr { get; init; }
+
///
/// Gets or sets a collection of trees representing nodes within this addon.
///
@@ -81,7 +85,7 @@ public unsafe partial class AddonTree : IDisposable
{
if (AddonTrees.TryGetValue(name, out var tree))
{
- if (tree.initialPtr == ptr)
+ if (tree.InitialPtr == ptr)
{
return tree;
}
@@ -143,34 +147,47 @@ public unsafe partial class AddonTree : IDisposable
ImGui.SetTooltip("Toggle Popout Window");
}
- ImGui.Separator();
-
- PrintFieldValuePair("Address", $"{(nint)addon:X}");
+ PaddedSeparator(1);
var uldManager = addon->UldManager;
+
+ PrintFieldValuePair("Address", $"{(nint)addon:X}");
+ PrintFieldValuePair("Agent", $"{GameGui.FindAgentInterface(addon):X}");
+
PrintFieldValuePairs(
("X", $"{addon->X}"),
- ("Y", $"{addon->X}"),
+ ("Y", $"{addon->Y}"),
("Scale", $"{addon->Scale}"),
("Widget Count", $"{uldManager.ObjectCount}"));
- ImGui.Separator();
-
var addonObj = this.GetAddonObj(addon);
if (addonObj != null)
{
+ PaddedSeparator();
ShowStruct(addonObj, (ulong)addon);
}
- ImGui.Dummy(new(25 * ImGui.GetIO().FontGlobalScale));
- ImGui.Separator();
+ PaddedSeparator();
- ResNodeTree.PrintNodeList(uldManager.NodeList, uldManager.NodeListCount, this);
+ PrintAtkValues(addon);
- ImGui.Dummy(new(25 * ImGui.GetIO().FontGlobalScale));
- ImGui.Separator();
+ if (addon->RootNode != null)
+ {
+ ResNodeTree.GetOrCreate(addon->RootNode, this).Print(0);
+ PaddedSeparator();
+ }
- ResNodeTree.PrintNodeListAsTree(addon->CollisionNodeList, (int)addon->CollisionNodeListCount, "Collision List", this, new(0.5F, 0.7F, 1F, 1F));
+ if (uldManager.NodeList != null)
+ {
+ var count = uldManager.NodeListCount;
+ ResNodeTree.PrintNodeListAsTree(uldManager.NodeList, count, $"Node List [{count}]:", this, new(0, 0.85F, 1, 1));
+ PaddedSeparator();
+ }
+
+ if (addon->CollisionNodeList != null)
+ {
+ ResNodeTree.PrintNodeListAsTree(addon->CollisionNodeList, (int)addon->CollisionNodeListCount, "Collision List", this, new(0.5F, 0.7F, 1F, 1F));
+ }
if (SearchResults.Length > 0 && Countdown <= 0)
{
@@ -218,7 +235,7 @@ public unsafe partial class AddonTree : IDisposable
private bool ValidateAddon(out AtkUnitBase* addon)
{
addon = (AtkUnitBase*)GameGui.GetAddonByName(this.AddonName);
- if (addon == null || (nint)addon != this.initialPtr)
+ if (addon == null || (nint)addon != this.InitialPtr)
{
this.Dispose();
return false;
@@ -231,7 +248,7 @@ public unsafe partial class AddonTree : IDisposable
{
if (this.window == null)
{
- this.window = new AddonPopoutWindow(this, $"{this.AddonName}###addonPopout{this.initialPtr}");
+ this.window = new AddonPopoutWindow(this, $"{this.AddonName}###addonPopout{this.InitialPtr}");
PopoutWindows.AddWindow(this.window);
}
else
diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs
index 0c3a947dd..45a2d90eb 100644
--- a/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs
+++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/Events.cs
@@ -1,4 +1,6 @@
-using Dalamud.Interface.Internal.UiDebug2.Utility;
+using System.Numerics;
+
+using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Component.GUI;
@@ -56,9 +58,9 @@ public static class Events
ImGui.TableNextColumn();
ImGui.TextUnformatted($"{evt->State.UnkFlags1}");
ImGui.TableNextColumn();
- Gui.ClickToCopyText($"{(nint)evt->Target:X}");
+ ImGuiHelpers.ClickToCopyText($"{(nint)evt->Target:X}", null, new Vector4(0.6f, 0.6f, 0.6f, 1));
ImGui.TableNextColumn();
- Gui.ClickToCopyText($"{(nint)evt->Listener:X}");
+ ImGuiHelpers.ClickToCopyText($"{(nint)evt->Listener:X}", null, new Vector4(0.6f, 0.6f, 0.6f, 1));
evt = evt->NextEvent;
}
}
diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs
index d9fcf52cc..4a1989441 100644
--- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs
+++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Component.cs
@@ -34,11 +34,13 @@ internal unsafe class ComponentNodeTree : ResNodeTree
private AtkUldManager* UldManager => &this.Component->UldManager;
+ private int? ComponentFieldOffset { get; set; }
+
///
private protected override string GetHeaderText()
{
var childCount = (int)this.UldManager->NodeListCount;
- return $"{this.componentType} Component Node{(childCount > 0 ? $" [+{childCount}]" : string.Empty)} (Node: {(nint)this.Node:X} / Comp: {(nint)this.Component:X})";
+ return $"{this.componentType} Component Node{(childCount > 0 ? $" [+{childCount}]" : string.Empty)}";
}
///
@@ -62,10 +64,10 @@ internal unsafe class ComponentNodeTree : ResNodeTree
}
///
- private protected override void PrintFieldNames()
+ private protected override void PrintFieldLabels()
{
- this.PrintFieldName((nint)this.Node, new(0, 0.85F, 1, 1));
- this.PrintFieldName((nint)this.Component, new(0f, 0.5f, 0.8f, 1f));
+ this.PrintFieldLabel((nint)this.Node, new(0, 0.85F, 1, 1), this.NodeFieldOffset);
+ this.PrintFieldLabel((nint)this.Component, new(0f, 0.5f, 0.8f, 1f), this.ComponentFieldOffset);
}
///
@@ -108,6 +110,34 @@ internal unsafe class ComponentNodeTree : ResNodeTree
}
}
+ ///
+ private protected override void GetFieldOffset()
+ {
+ var nodeFound = false;
+ var componentFound = false;
+ for (var i = 0; i < this.AddonTree.AddonSize; i += 0x8)
+ {
+ var readPtr = Marshal.ReadIntPtr(this.AddonTree.InitialPtr + i);
+
+ if (readPtr == (nint)this.Node)
+ {
+ this.NodeFieldOffset = i;
+ nodeFound = true;
+ }
+
+ if (readPtr == (nint)this.Component)
+ {
+ this.ComponentFieldOffset = i;
+ componentFound = true;
+ }
+
+ if (nodeFound && componentFound)
+ {
+ break;
+ }
+ }
+ }
+
private void PrintComponentObject()
{
PrintFieldValuePair("Component", $"{(nint)this.Component:X}");
diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs
index 6cb178bd7..6b6522bb4 100644
--- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs
+++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Editor.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Numerics;
+using Dalamud.Interface.Components;
using Dalamud.Interface.Internal.UiDebug2.Utility;
using Dalamud.Interface.Utility.Raii;
@@ -370,8 +371,8 @@ internal unsafe partial class TextNodeTree
var hAlign = (int)alignment % 3;
var vAlign = ((int)alignment - hAlign) / 3;
- var hAlignInput = IconButtonSelect($"{label}H", ref hAlign, [0, 1, 2], [AlignLeft, AlignCenter, AlignRight]);
- var vAlignInput = IconButtonSelect($"{label}V", ref vAlign, [0, 1, 2], [ArrowsUpToLine, GripLines, ArrowsDownToLine]);
+ var hAlignInput = ImGuiComponents.IconButtonSelect($"{label}H", ref hAlign, [AlignLeft, AlignCenter, AlignRight], [0, 1, 2], 3u, new(25, 0));
+ var vAlignInput = ImGuiComponents.IconButtonSelect($"{label}V", ref vAlign, [ArrowsUpToLine, GripLines, ArrowsDownToLine], [0, 1, 2], 3u, new(25, 0));
if (hAlignInput || vAlignInput)
{
diff --git a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs
index a333940c1..2edf4e570 100644
--- a/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs
+++ b/Dalamud/Interface/Internal/UiDebug2/Browsing/NodeTree.Res.cs
@@ -1,5 +1,6 @@
using System.Linq;
using System.Numerics;
+using System.Runtime.InteropServices;
using Dalamud.Interface.Components;
using Dalamud.Interface.Internal.UiDebug2.Utility;
@@ -60,6 +61,11 @@ internal unsafe partial class ResNodeTree : IDisposable
///
private protected NodeType NodeType { get; init; }
+ ///
+ /// Gets or sets the offset of this node within its parent Addon.
+ ///
+ private protected int? NodeFieldOffset { get; set; }
+
///
/// Clears this NodeTree's popout window, if it has one.
///
@@ -164,19 +170,26 @@ internal unsafe partial class ResNodeTree : IDisposable
internal void WriteTreeHeading()
{
ImGui.TextUnformatted(this.GetHeaderText());
- this.PrintFieldNames();
+ this.PrintFieldLabels();
}
///
- /// If the given pointer has been identified as a field within the addon struct, this method prints that field's name.
+ /// If the given pointer is referenced with the addon struct, the offset within the addon will be printed. If the given pointer has been identified as a field within the addon struct, this method also prints that field's name.
///
/// The pointer to check.
/// The text color to use.
- private protected void PrintFieldName(nint ptr, Vector4 color)
+ /// The field offset of the pointer, if it was found in the addon.
+ private protected void PrintFieldLabel(nint ptr, Vector4 color, int? fieldOffset)
{
+ if (fieldOffset != null)
+ {
+ ImGui.SameLine(0, -1);
+ ImGui.TextColored(color * 0.85f, $"[0x{fieldOffset:X}]");
+ }
+
if (this.AddonTree.FieldNames.TryGetValue(ptr, out var result))
{
- ImGui.SameLine();
+ ImGui.SameLine(0, -1);
ImGui.TextColored(color, string.Join(".", result));
}
}
@@ -188,7 +201,15 @@ internal unsafe partial class ResNodeTree : IDisposable
private protected virtual string GetHeaderText()
{
var count = this.GetDirectChildCount();
- return $"{this.NodeType} Node{(count > 0 ? $" [+{count}]" : string.Empty)} ({(nint)this.Node:X})";
+ return $"{this.NodeType} Node{(count > 0 ? $" [+{count}]" : string.Empty)}";
+ }
+
+ ///
+ /// Prints any field names for the node.
+ ///
+ private protected virtual void PrintFieldLabels()
+ {
+ this.PrintFieldLabel((nint)this.Node, new(0, 0.85F, 1, 1), this.NodeFieldOffset);
}
///
@@ -201,11 +222,6 @@ internal unsafe partial class ResNodeTree : IDisposable
ImGui.NewLine();
}
- ///
- /// Prints any field names for the node.
- ///
- private protected virtual void PrintFieldNames() => this.PrintFieldName((nint)this.Node, new(0, 0.85F, 1, 1));
-
///
/// Prints all direct children of this node.
///
@@ -227,6 +243,21 @@ internal unsafe partial class ResNodeTree : IDisposable
{
}
+ ///
+ /// Attempts to retrieve the field offset of the given pointer within the parent addon.
+ ///
+ private protected virtual void GetFieldOffset()
+ {
+ for (var i = 0; i < this.AddonTree.AddonSize; i += 0x8)
+ {
+ if (Marshal.ReadIntPtr(this.AddonTree.InitialPtr + i) == (nint)this.Node)
+ {
+ this.NodeFieldOffset = i;
+ break;
+ }
+ }
+ }
+
private int GetDirectChildCount()
{
var count = 0;
@@ -273,6 +304,8 @@ internal unsafe partial class ResNodeTree : IDisposable
ImGui.SetNextItemOpen(true, ImGuiCond.Always);
}
+ this.GetFieldOffset();
+
using var col = ImRaii.PushColor(Text, displayColor);
using var tree = ImRaii.TreeNode(label, SpanFullWidth);
@@ -281,7 +314,7 @@ internal unsafe partial class ResNodeTree : IDisposable
new NodeBounds(this.Node).Draw(visible ? new(0.1f, 1f, 0.1f, 1f) : new(1f, 0f, 0.2f, 1f));
}
- ImGui.SameLine();
+ ImGui.SameLine(0, -1);
this.WriteTreeHeading();
col.Pop();
diff --git a/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs b/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs
index 7f603fdac..6693c3fb0 100644
--- a/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs
+++ b/Dalamud/Interface/Internal/UiDebug2/ElementSelector.cs
@@ -79,7 +79,7 @@ internal unsafe class ElementSelector : IDisposable
///
internal void DrawInterface()
{
- using (ImRaii.Child("###sidebar_elementSelector", new(250, 0), true))
+ using (ImRaii.Child("###sidebar_elementSelector", new(250, -1), true))
{
using (ImRaii.PushFont(IconFont))
{
diff --git a/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs b/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs
index 954e5cb72..cc73b79c6 100644
--- a/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs
+++ b/Dalamud/Interface/Internal/UiDebug2/Utility/Gui.cs
@@ -1,7 +1,6 @@
-using System.Collections.Generic;
using System.Numerics;
-using Dalamud.Interface.Components;
+using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using FFXIVClientStructs.FFXIV.Client.Graphics;
@@ -17,40 +16,6 @@ namespace Dalamud.Interface.Internal.UiDebug2.Utility;
///
internal static class Gui
{
- ///
- /// A radio-button-esque input that uses Fontawesome icon buttons.
- ///
- /// The type of value being set.
- /// The label for the inputs.
- /// The value being set.
- /// A list of all options.
- /// A list of icons corresponding to the options.
- /// true if a button is clicked.
- internal static unsafe bool IconButtonSelect(string label, ref T val, List options, List icons)
- {
- var ret = false;
-
- for (var i = 0; i < options.Count; i++)
- {
- if (i > 0)
- {
- ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X);
- }
-
- var option = options[i];
- var icon = icons.Count > i ? icons[i] : FontAwesomeIcon.Question;
- var color = *ImGui.GetStyleColorVec4(val is not null && val.Equals(option) ? ButtonActive : Button);
-
- if (ImGuiComponents.IconButton($"{label}{option}{i}", icon, color))
- {
- val = option;
- ret = true;
- }
- }
-
- return ret;
- }
-
///
/// Prints field name and its value.
///
@@ -61,13 +26,14 @@ internal static class Gui
{
ImGui.TextUnformatted($"{fieldName}:");
ImGui.SameLine();
+ var grey60 = new Vector4(0.6f, 0.6f, 0.6f, 1);
if (copy)
{
- ClickToCopyText(value);
+ ImGuiHelpers.ClickToCopyText(value, null, grey60);
}
else
{
- ImGui.TextColored(new(0.6f, 0.6f, 0.6f, 1), value);
+ ImGui.TextColored(grey60, value);
}
}
@@ -102,7 +68,10 @@ internal static class Gui
/// Colors the text itself either white or black, depending on the luminosity of the background color.
internal static void PrintColor(Vector4 color, string fmt)
{
- using (new ImRaii.Color().Push(Text, Luminosity(color) < 0.5f ? new Vector4(1) : new(0, 0, 0, 1)).Push(Button, color).Push(ButtonActive, color).Push(ButtonHovered, color))
+ using (new ImRaii.Color().Push(Text, Luminosity(color) < 0.5f ? new Vector4(1) : new(0, 0, 0, 1))
+ .Push(Button, color)
+ .Push(ButtonActive, color)
+ .Push(ButtonHovered, color))
{
ImGui.SmallButton(fmt);
}
@@ -117,39 +86,6 @@ internal static class Gui
0.5f) * vector4.W;
}
- ///
- /// Print out text that can be copied when clicked.
- ///
- /// The text to show.
- /// The text to copy when clicked.
- internal static void ClickToCopyText(string text, string? textCopy = null)
- {
- using (ImRaii.PushColor(Text, new Vector4(0.6f, 0.6f, 0.6f, 1)))
- {
- textCopy ??= text;
- ImGui.TextUnformatted($"{text}");
- }
-
- if (ImGui.IsItemHovered())
- {
- using (ImRaii.Tooltip())
- {
- using (ImRaii.PushFont(UiBuilder.IconFont))
- {
- ImGui.TextUnformatted(FontAwesomeIcon.Copy.ToIconString());
- }
-
- ImGui.SameLine();
- ImGui.TextUnformatted($"{textCopy}");
- }
- }
-
- if (ImGui.IsItemClicked())
- {
- ImGui.SetClipboardText($"{textCopy}");
- }
- }
-
///
/// Draws a tooltip that changes based on the cursor's x-position within the hovered item.
///
@@ -176,4 +112,23 @@ internal static class Gui
return true;
}
+
+ ///
+ /// Draws a separator with some padding above and below.
+ ///
+ /// Governs whether to pad above, below, or both.
+ /// The amount of padding.
+ internal static void PaddedSeparator(uint mask = 0b11, float padding = 5f)
+ {
+ if ((mask & 0b10) > 0)
+ {
+ ImGui.Dummy(new(padding * ImGui.GetIO().FontGlobalScale));
+ }
+
+ ImGui.Separator();
+ if ((mask & 0b01) > 0)
+ {
+ ImGui.Dummy(new(padding * ImGui.GetIO().FontGlobalScale));
+ }
+ }
}
diff --git a/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs b/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs
index cffd676f7..3d28cb836 100644
--- a/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs
+++ b/Dalamud/Interface/Internal/UiDebug2/Utility/NodeBounds.cs
@@ -6,7 +6,7 @@ using Dalamud.Interface.Utility;
using FFXIVClientStructs.FFXIV.Component.GUI;
using ImGuiNET;
-using static System.Math;
+using static System.MathF;
using static Dalamud.Interface.ColorHelpers;
namespace Dalamud.Interface.Internal.UiDebug2.Utility;
@@ -133,7 +133,7 @@ public unsafe struct NodeBounds
if (p.Y > Min(p1.Y, p2.Y) &&
p.Y <= Max(p1.Y, p2.Y) &&
p.X <= Max(p1.X, p2.X) &&
- (p1.X.Equals(p2.X) || p.X <= ((p.Y - p1.Y) * (p2.X - p1.X) / (p2.Y - p1.Y)) + p1.X))
+ (p1.X.Equals(p2.X) || p.X <= (((p.Y - p1.Y) * (p2.X - p1.X)) / (p2.Y - p1.Y)) + p1.X))
{
inside = !inside;
}
@@ -144,12 +144,12 @@ public unsafe struct NodeBounds
private static Vector2 TransformPoint(Vector2 p, Vector2 o, float r, Vector2 s)
{
- var cosR = (float)Cos(r);
- var sinR = (float)Sin(r);
+ var cosR = Cos(r);
+ var sinR = Sin(r);
var d = (p - o) * s;
return new(
- o.X + (d.X * cosR) - (d.Y * sinR),
+ (o.X + (d.X * cosR)) - (d.Y * sinR),
o.Y + (d.X * sinR) + (d.Y * cosR));
}
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/FateTableAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/FateTableAgingStep.cs
index a8fe60aa9..eef986302 100644
--- a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/FateTableAgingStep.cs
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/FateTableAgingStep.cs
@@ -9,7 +9,7 @@ namespace Dalamud.Interface.Internal.Windows.SelfTest.AgingSteps;
///
internal class FateTableAgingStep : IAgingStep
{
- private int index = 0;
+ private byte index = 0;
///
public string Name => "Test FateTable";
@@ -21,6 +21,12 @@ internal class FateTableAgingStep : IAgingStep
ImGui.Text("Checking fate table...");
+ if (fateTable.Length == 0)
+ {
+ ImGui.Text("Go to a zone that has FATEs currently up.");
+ return SelfTestStepResult.Waiting;
+ }
+
if (this.index == fateTable.Length - 1)
{
return SelfTestStepResult.Pass;
diff --git a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/MarketBoardAgingStep.cs b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/MarketBoardAgingStep.cs
index 78d43662c..513141fa9 100644
--- a/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/MarketBoardAgingStep.cs
+++ b/Dalamud/Interface/Internal/Windows/SelfTest/AgingSteps/MarketBoardAgingStep.cs
@@ -169,6 +169,7 @@ internal class MarketBoardAgingStep : IAgingStep
ImGui.Text($"Kugane: {this.marketTaxRate.KuganeTax.ToString()}");
ImGui.Text($"Crystarium: {this.marketTaxRate.CrystariumTax.ToString()}");
ImGui.Text($"Sharlayan: {this.marketTaxRate.SharlayanTax.ToString()}");
+ ImGui.Text($"Tuliyollal: {this.marketTaxRate.TuliyollalTax.ToString()}");
ImGui.Separator();
if (ImGui.Button("Looks Correct / Skip"))
{
diff --git a/Dalamud/Interface/Utility/ImGuiHelpers.cs b/Dalamud/Interface/Utility/ImGuiHelpers.cs
index 8ce7a48d7..8dedae5cd 100644
--- a/Dalamud/Interface/Utility/ImGuiHelpers.cs
+++ b/Dalamud/Interface/Utility/ImGuiHelpers.cs
@@ -167,17 +167,41 @@ public static class ImGuiHelpers
///
/// The text to show.
/// The text to copy when clicked.
- public static void ClickToCopyText(string text, string? textCopy = null)
+ /// The color of the text.
+ public static void ClickToCopyText(string text, string? textCopy = null, Vector4? color = null)
{
textCopy ??= text;
- ImGui.Text($"{text}");
+
+ using (var col = new ImRaii.Color())
+ {
+ if (color.HasValue)
+ {
+ col.Push(ImGuiCol.Text, color.Value);
+ }
+
+ ImGui.TextUnformatted($"{text}");
+ }
+
if (ImGui.IsItemHovered())
{
ImGui.SetMouseCursor(ImGuiMouseCursor.Hand);
- if (textCopy != text) ImGui.SetTooltip(textCopy);
+
+ using (ImRaii.Tooltip())
+ {
+ using (ImRaii.PushFont(UiBuilder.IconFont))
+ {
+ ImGui.TextUnformatted(FontAwesomeIcon.Copy.ToIconString());
+ }
+
+ ImGui.SameLine();
+ ImGui.TextUnformatted(textCopy);
+ }
}
- if (ImGui.IsItemClicked()) ImGui.SetClipboardText($"{textCopy}");
+ if (ImGui.IsItemClicked())
+ {
+ ImGui.SetClipboardText(textCopy);
+ }
}
/// Draws a SeString.
diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs
index 78c39ef13..679b5353c 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit 78c39ef1318525d766cdf31fd9a32e6f1c7cb453
+Subproject commit 679b5353cd61baa03b26d95efcac059f8e29b141