diff --git a/PlayerTags/PlayerTags.json b/PlayerTags/PlayerTags.json
index 8817f1e..19b295c 100644
--- a/PlayerTags/PlayerTags.json
+++ b/PlayerTags/PlayerTags.json
@@ -6,7 +6,6 @@
"IconUrl": "https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Icon.png",
"ImageUrls": [
"https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Nameplates_1.png",
- "https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Chat_1.png",
- "https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Chat_2.png"
+ "https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Chat_1.png"
]
}
\ No newline at end of file
diff --git a/PlayerTags/Plugin.cs b/PlayerTags/Plugin.cs
index b8bde6c..e08ed23 100644
--- a/PlayerTags/Plugin.cs
+++ b/PlayerTags/Plugin.cs
@@ -2,6 +2,7 @@
using Dalamud.Game;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Objects;
+using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Command;
using Dalamud.Game.Gui;
@@ -104,7 +105,7 @@ namespace PlayerTags
{
if (m_PluginHooks == null)
{
- m_PluginHooks = new PluginHooks(Framework, ObjectTable, GameGui, SetNameplate);
+ m_PluginHooks = new PluginHooks(Framework, ObjectTable, GameGui, SetPlayerNameplate);
}
}
@@ -146,7 +147,11 @@ namespace PlayerTags
private void UiBuilder_Draw()
{
- m_PluginConfigurationUI.Draw();
+ // Don't bother showing the config unless the player is in the world
+ if (ClientState.LocalPlayer != null)
+ {
+ m_PluginConfigurationUI.Draw();
+ }
}
private void UiBuilder_OpenConfigUi()
@@ -173,9 +178,9 @@ namespace PlayerTags
/// Whether the name was changed.
/// Whether the title was changed.
/// Whether the free company was changed.
- private void SetNameplate(GameObject gameObject, SeString name, SeString title, SeString freeCompany, ref bool isTitleVisible, ref bool isTitleAboveName, ref int iconId, out bool isNameChanged, out bool isTitleChanged, out bool isFreeCompanyChanged)
+ private void SetPlayerNameplate(PlayerCharacter playerCharacter, SeString name, SeString title, SeString freeCompany, ref bool isTitleVisible, ref bool isTitleAboveName, ref int iconId, out bool isNameChanged, out bool isTitleChanged, out bool isFreeCompanyChanged)
{
- AddTagsToNameplate(gameObject, name, title, freeCompany, out isNameChanged, out isTitleChanged, out isFreeCompanyChanged);
+ AddTagsToNameplate(playerCharacter, name, title, freeCompany, out isNameChanged, out isTitleChanged, out isFreeCompanyChanged);
if (m_PluginConfiguration.NameplateTitlePosition == NameplateTitlePosition.AlwaysAboveName)
{
@@ -260,15 +265,15 @@ namespace PlayerTags
newPayloads.Add(new TextPayload(text));
- if (tag.IsTextItalic.InheritedValue != null && tag.IsTextItalic.InheritedValue.Value)
- {
- newPayloads.Add(new EmphasisItalicPayload(false));
- }
-
if (tag.TextColor.InheritedValue != null)
{
newPayloads.Add(new UIForegroundPayload(0));
}
+
+ if (tag.IsTextItalic.InheritedValue != null && tag.IsTextItalic.InheritedValue.Value)
+ {
+ newPayloads.Add(new EmphasisItalicPayload(false));
+ }
}
return newPayloads.ToArray();
diff --git a/PlayerTags/PluginHooks.cs b/PlayerTags/PluginHooks.cs
index 01a9ece..1e29cf8 100644
--- a/PlayerTags/PluginHooks.cs
+++ b/PlayerTags/PluginHooks.cs
@@ -1,5 +1,6 @@
using Dalamud.Game;
using Dalamud.Game.ClientState.Objects;
+using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Game.Gui;
using Dalamud.Game.Text.SeStringHandling;
@@ -14,70 +15,54 @@ namespace PlayerTags
{
public class PluginHooks : IDisposable
{
- [UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Ansi)]
- private delegate IntPtr SetNameplateDelegate_Private(IntPtr nameplateObjectPtr, bool isTitleAboveName, bool isTitleVisible, IntPtr titlePtr, IntPtr namePtr, IntPtr freeCompanyPtr, int iconId);
-
- [UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Ansi)]
- private delegate IntPtr UIModule_GetRaptureAtkModuleDelegate_Private(IntPtr uiModule);
-
- [UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Ansi)]
- private delegate IntPtr Framework_GetUIModuleDelegate_Private(IntPtr framework);
-
private class PluginAddressResolver : BaseAddressResolver
{
private const string SetNameplateSignature = "48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 54 41 56 41 57 48 83 EC 40 44 0F B6 E2";
internal IntPtr SetNameplatePtr;
- private const string Framework_GetUIModuleSignature = "E8 ?? ?? ?? ?? 48 8B C8 48 8B 10 FF 92 ?? ?? ?? ?? 48 8B C8 BA ?? ?? ?? ??";
- internal IntPtr Framework_GetUIModulePtr;
-
protected override void Setup64Bit(SigScanner scanner)
{
SetNameplatePtr = scanner.ScanText(SetNameplateSignature);
- Framework_GetUIModulePtr = scanner.ScanText(Framework_GetUIModuleSignature);
}
}
+ private delegate IntPtr SetPlayerNameplateDelegate_Unmanaged(IntPtr playerNameplateObjectPtr, bool isTitleAboveName, bool isTitleVisible, IntPtr titlePtr, IntPtr namePtr, IntPtr freeCompanyPtr, int iconId);
+
private Framework m_Framework;
private ObjectTable m_ObjectTable;
private GameGui m_GameGui;
- private SetNameplateDelegate m_SetNameplate;
+ private SetPlayerNameplateDelegate m_SetPlayerNameplate;
private PluginAddressResolver m_PluginAddressResolver;
- private Hook m_SetNameplateHook;
- private readonly Framework_GetUIModuleDelegate_Private m_GetUIModule;
- private IntPtr? m_NameplateObjectArrayPtr;
- private IntPtr? m_NameplateInfoArrayPtr;
+ private Hook m_SetPlayerNameplateHook;
- public PluginHooks(Framework framework, ObjectTable objectTable, GameGui gameGui, SetNameplateDelegate setNameplate)
+ public PluginHooks(Framework framework, ObjectTable objectTable, GameGui gameGui, SetPlayerNameplateDelegate setPlayerNameplate)
{
m_Framework = framework;
m_ObjectTable = objectTable;
m_GameGui = gameGui;
- m_SetNameplate = setNameplate;
+ m_SetPlayerNameplate = setPlayerNameplate;
m_PluginAddressResolver = new PluginAddressResolver();
m_PluginAddressResolver.Setup();
- m_GetUIModule = Marshal.GetDelegateForFunctionPointer(m_PluginAddressResolver.Framework_GetUIModulePtr);
-
- m_SetNameplateHook = new Hook(m_PluginAddressResolver.SetNameplatePtr, new SetNameplateDelegate_Private(SetNameplateDetour));
- m_SetNameplateHook.Enable();
+ m_SetPlayerNameplateHook = new Hook(m_PluginAddressResolver.SetNameplatePtr, new SetPlayerNameplateDelegate_Unmanaged(SetPlayerNameplateDetour));
+ m_SetPlayerNameplateHook.Enable();
}
public void Dispose()
{
- m_SetNameplateHook.Disable();
+ m_SetPlayerNameplateHook.Disable();
}
- private IntPtr SetNameplateDetour(IntPtr nameplateObjectPtrOriginal, bool isTitleAboveNameOriginal, bool isTitleVisibleOriginal, IntPtr titlePtrOriginal, IntPtr namePtrOriginal, IntPtr freeCompanyPtrOriginal, int iconIdOriginal)
+ private IntPtr SetPlayerNameplateDetour(IntPtr playerNameplateObjectPtrOriginal, bool isTitleAboveNameOriginal, bool isTitleVisibleOriginal, IntPtr titlePtrOriginal, IntPtr namePtrOriginal, IntPtr freeCompanyPtrOriginal, int iconIdOriginal)
{
- if (m_SetNameplate != null)
+ if (m_SetPlayerNameplate != null)
{
try
{
- GameObject? gameObject = GetNameplateObject(nameplateObjectPtrOriginal);
- if (gameObject != null)
+ PlayerCharacter? playerCharacter = GetNameplateGameObject(playerNameplateObjectPtrOriginal);
+ if (playerCharacter != null)
{
SeString title = ReadSeString(titlePtrOriginal);
SeString name = ReadSeString(namePtrOriginal);
@@ -88,7 +73,7 @@ namespace PlayerTags
bool isTitleChanged;
bool isNameChanged;
bool isFreeCompanyChanged;
- m_SetNameplate(gameObject, name, title, freeCompany, ref isTitleVisible, ref isTitleAboveName, ref iconId, out isNameChanged, out isTitleChanged, out isFreeCompanyChanged);
+ m_SetPlayerNameplate(playerCharacter, name, title, freeCompany, ref isTitleVisible, ref isTitleAboveName, ref iconId, out isNameChanged, out isTitleChanged, out isFreeCompanyChanged);
IntPtr namePtr = namePtrOriginal;
if (isNameChanged)
@@ -108,7 +93,7 @@ namespace PlayerTags
freeCompanyPtr = Allocate(freeCompany);
}
- var result = m_SetNameplateHook.Original(nameplateObjectPtrOriginal, isTitleAboveName, isTitleVisible, titlePtr, namePtr, freeCompanyPtr, iconId);
+ var result = m_SetPlayerNameplateHook.Original(playerNameplateObjectPtrOriginal, isTitleAboveName, isTitleVisible, titlePtr, namePtr, freeCompanyPtr, iconId);
if (isNameChanged)
{
@@ -134,7 +119,7 @@ namespace PlayerTags
}
}
- return m_SetNameplateHook.Original(nameplateObjectPtrOriginal, isTitleAboveNameOriginal, isTitleVisibleOriginal, titlePtrOriginal, namePtrOriginal, freeCompanyPtrOriginal, iconIdOriginal);
+ return m_SetPlayerNameplateHook.Original(playerNameplateObjectPtrOriginal, isTitleAboveNameOriginal, isTitleVisibleOriginal, titlePtrOriginal, namePtrOriginal, freeCompanyPtrOriginal, iconIdOriginal);
}
private static SeString ReadSeString(IntPtr stringPtr)
@@ -175,64 +160,43 @@ namespace PlayerTags
ptr = IntPtr.Zero;
}
- private T? GetNameplateObject(IntPtr nameplateObjectPtr)
+ private T? GetNameplateGameObject(IntPtr nameplateObjectPtr)
where T : GameObject
{
- if (!m_NameplateInfoArrayPtr.HasValue)
+ // Get the nameplate object array
+ var nameplateAddonPtr = m_GameGui.GetAddonByName("NamePlate", 1);
+ var nameplateObjectArrayPtrPtr = nameplateAddonPtr + Marshal.OffsetOf(typeof(AddonNamePlate), nameof(AddonNamePlate.NamePlateObjectArray)).ToInt32();
+ var nameplateObjectArrayPtr = Marshal.ReadIntPtr(nameplateObjectArrayPtrPtr);
+ if (nameplateObjectArrayPtr == IntPtr.Zero)
{
- // Get the nameplate object array
- var namePlateAddonPtr = m_GameGui.GetAddonByName("NamePlate", 1);
- var namePlateObjectArrayPtrPtr = namePlateAddonPtr + Marshal.OffsetOf(typeof(AddonNamePlate), nameof(AddonNamePlate.NamePlateObjectArray)).ToInt32();
- var nameplateObjectArrayPtr = Marshal.ReadIntPtr(namePlateObjectArrayPtrPtr);
- if (nameplateObjectArrayPtr == IntPtr.Zero)
- {
- return null!;
- }
-
- m_NameplateObjectArrayPtr = nameplateObjectArrayPtr;
-
- // Get the nameplate info
- IntPtr raptureAtkModulePtr;
- var frameworkPtr = m_Framework.Address.BaseAddress;
- var uiModulePtr = m_GetUIModule(frameworkPtr);
- unsafe
- {
- var uiModule = *(UIModule*)uiModulePtr;
- var UIModule_GetRaptureAtkModuleAddress = new IntPtr(uiModule.vfunc[7]);
- var GetRaptureAtkModule = Marshal.GetDelegateForFunctionPointer(UIModule_GetRaptureAtkModuleAddress);
- raptureAtkModulePtr = GetRaptureAtkModule(uiModulePtr);
- }
-
- if (raptureAtkModulePtr == IntPtr.Zero)
- {
- return null!;
- }
-
- m_NameplateInfoArrayPtr = raptureAtkModulePtr + Marshal.OffsetOf(typeof(RaptureAtkModule), nameof(RaptureAtkModule.NamePlateInfoArray)).ToInt32();
+ return null;
}
- // Determine the index of this nameplate
+ // Determine the index of the nameplate object within the nameplate object array
var namePlateObjectSize = Marshal.SizeOf(typeof(AddonNamePlate.NamePlateObject));
- var namePlateObjectPtr0 = m_NameplateObjectArrayPtr!.Value + namePlateObjectSize * 0;
+ var namePlateObjectPtr0 = nameplateObjectArrayPtr + namePlateObjectSize * 0;
var namePlateIndex = (nameplateObjectPtr.ToInt64() - namePlateObjectPtr0.ToInt64()) / namePlateObjectSize;
if (namePlateIndex < 0 || namePlateIndex >= 50)
{
- return null!;
+ return null;
}
- var namePlateInfoPtr = new IntPtr(m_NameplateInfoArrayPtr.Value.ToInt64() + Marshal.SizeOf(typeof(RaptureAtkModule.NamePlateInfo)) * namePlateIndex);
+ // Get the nameplate info array
+ IntPtr nameplateInfoArrayPtr = IntPtr.Zero;
+ unsafe
+ {
+ var framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework.Instance();
+ var ui3DModule = framework->GetUiModule()->GetUI3DModule();
+ nameplateInfoArrayPtr = new IntPtr(&(framework->GetUiModule()->GetRaptureAtkModule()->NamePlateInfoArray));
+ }
+
+ // Get the nameplate info for the nameplate object
+ var namePlateInfoPtr = new IntPtr(nameplateInfoArrayPtr.ToInt64() + Marshal.SizeOf(typeof(RaptureAtkModule.NamePlateInfo)) * namePlateIndex);
RaptureAtkModule.NamePlateInfo namePlateInfo = Marshal.PtrToStructure(namePlateInfoPtr);
- // Get the player character for this nameplate info
+ // Return the object for its object id
var objectId = namePlateInfo.ObjectID.ObjectID;
-
- T? gameObject = m_ObjectTable.FirstOrDefault(obj => obj.ObjectId == objectId) as T;
- if (gameObject == null)
- {
- return null!;
- }
-
- return gameObject!;
+ return m_ObjectTable.SearchById(objectId) as T;
}
}
}
diff --git a/PlayerTags/SetNameplateDelegate.cs b/PlayerTags/SetNameplateDelegate.cs
deleted file mode 100644
index 778615e..0000000
--- a/PlayerTags/SetNameplateDelegate.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-using Dalamud.Game.ClientState.Objects.Types;
-using Dalamud.Game.Text.SeStringHandling;
-
-namespace PlayerTags
-{
- public delegate void SetNameplateDelegate(GameObject gameObject, SeString name, SeString title, SeString freeCompany, ref bool isTitleVisible, ref bool isTitleAboveName, ref int iconId, out bool isNameChanged, out bool isTitleChanged, out bool isFreeCompanyChanged);
-}
diff --git a/PlayerTags/SetPlayerNameplateDelegate.cs b/PlayerTags/SetPlayerNameplateDelegate.cs
new file mode 100644
index 0000000..5e38761
--- /dev/null
+++ b/PlayerTags/SetPlayerNameplateDelegate.cs
@@ -0,0 +1,7 @@
+using Dalamud.Game.ClientState.Objects.SubKinds;
+using Dalamud.Game.Text.SeStringHandling;
+
+namespace PlayerTags
+{
+ public delegate void SetPlayerNameplateDelegate(PlayerCharacter playerCharacter, SeString name, SeString title, SeString freeCompany, ref bool isTitleVisible, ref bool isTitleAboveName, ref int iconId, out bool isNameChanged, out bool isTitleChanged, out bool isFreeCompanyChanged);
+}