From e92662969b0d26eddface32d3d95d90fa05d8546 Mon Sep 17 00:00:00 2001 From: Pilzinsel64 Date: Thu, 25 Jul 2024 05:51:37 +0200 Subject: [PATCH] remove temporary NamePlate service -> INamePlateGui has been implemented within Dalamud and release recently --- Pilz.Dalamud/NamePlate/INamePlateGui.cs | 43 -- Pilz.Dalamud/NamePlate/NamePlateGui.cs | 202 ------ Pilz.Dalamud/NamePlate/NamePlateInfoView.cs | 105 --- Pilz.Dalamud/NamePlate/NamePlateKind.cs | 57 -- .../NamePlate/NamePlatePartsContainer.cs | 46 -- .../NamePlate/NamePlateQuotedParts.cs | 104 --- .../NamePlate/NamePlateSimpleParts.cs | 51 -- .../NamePlate/NamePlateStringField.cs | 38 -- .../NamePlate/NamePlateUpdateContext.cs | 152 ----- .../NamePlate/NamePlateUpdateHandler.cs | 606 ------------------ .../Tools/NamePlates/NameplateChanges.cs | 2 +- .../NamePlates/NameplateElementChange.cs | 4 +- .../NamePlates/NameplateUpdateFactory.cs | 6 +- 13 files changed, 6 insertions(+), 1410 deletions(-) delete mode 100644 Pilz.Dalamud/NamePlate/INamePlateGui.cs delete mode 100644 Pilz.Dalamud/NamePlate/NamePlateGui.cs delete mode 100644 Pilz.Dalamud/NamePlate/NamePlateInfoView.cs delete mode 100644 Pilz.Dalamud/NamePlate/NamePlateKind.cs delete mode 100644 Pilz.Dalamud/NamePlate/NamePlatePartsContainer.cs delete mode 100644 Pilz.Dalamud/NamePlate/NamePlateQuotedParts.cs delete mode 100644 Pilz.Dalamud/NamePlate/NamePlateSimpleParts.cs delete mode 100644 Pilz.Dalamud/NamePlate/NamePlateStringField.cs delete mode 100644 Pilz.Dalamud/NamePlate/NamePlateUpdateContext.cs delete mode 100644 Pilz.Dalamud/NamePlate/NamePlateUpdateHandler.cs diff --git a/Pilz.Dalamud/NamePlate/INamePlateGui.cs b/Pilz.Dalamud/NamePlate/INamePlateGui.cs deleted file mode 100644 index 0d34c8a..0000000 --- a/Pilz.Dalamud/NamePlate/INamePlateGui.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Collections.Generic; - -namespace Pilz.Dalamud.NamePlate; - -/// -/// Class used to modify the data used when rendering nameplates. -/// -public interface INamePlateGui -{ - /// - /// The delegate used for receiving nameplate update events. - /// - /// An object containing information about the pending data update. - /// A list of handlers used for updating nameplate data. - public delegate void OnPlateUpdateDelegate(INamePlateUpdateContext context, IReadOnlyList handlers); - - /// - /// An event which fires when nameplate data is updated and at least one nameplate has important updates. The - /// subscriber is provided with a list of handlers for nameplates with important updates. - /// - /// - /// Fires after . - /// - event OnPlateUpdateDelegate? OnNamePlateUpdate; - - /// - /// An event which fires when nameplate data is updated. The subscriber is provided with a list of handlers for all - /// nameplates. - /// - /// - /// This event is likely to fire every frame even when no nameplates are actually updated, so in most cases - /// is preferred. Fires before . - /// - event OnPlateUpdateDelegate? OnDataUpdate; - - /// - /// Requests that all nameplates should be redrawn on the following frame. - /// - void RequestRedraw(); - - private static NamePlateGui instance; - public static INamePlateGui Instance => instance ??= new (); -} diff --git a/Pilz.Dalamud/NamePlate/NamePlateGui.cs b/Pilz.Dalamud/NamePlate/NamePlateGui.cs deleted file mode 100644 index b44c2d2..0000000 --- a/Pilz.Dalamud/NamePlate/NamePlateGui.cs +++ /dev/null @@ -1,202 +0,0 @@ -using Dalamud.Game.Addon.Lifecycle; -using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; -using Dalamud.Plugin.Services; -using FFXIVClientStructs.FFXIV.Client.UI; -using System.Runtime.InteropServices; - -namespace Pilz.Dalamud.NamePlate; - -/// -/// Class used to modify the data used when rendering nameplates. -/// -public sealed class NamePlateGui : IDisposable, INamePlateGui -{ - /// - /// The index for the number array used by the NamePlate addon. - /// - public const int NumberArrayIndex = 5; - - /// - /// The index for the string array used by the NamePlate addon. - /// - public const int StringArrayIndex = 4; - - /// - /// The index for of the FullUpdate entry in the NamePlate number array. - /// - internal const int NumberArrayFullUpdateIndex = 4; - - /// - /// An empty null-terminated string pointer allocated in unmanaged memory, used to tag removed fields. - /// - internal static readonly nint EmptyStringPointer = CreateEmptyStringPointer(); - - private readonly IAddonLifecycle addonLifecycle = PluginServices.AddonLifecycle; - - private readonly IGameGui gameGui = PluginServices.GameGui; - - private readonly IObjectTable objectTable = PluginServices.ObjectTable; - - private NamePlateUpdateContext? context; - - private NamePlateUpdateHandler[] updateHandlers = []; - - internal NamePlateGui() - { - this.addonLifecycle.RegisterListener(AddonEvent.PreRequestedUpdate, "NamePlate", this.OnPreRequestedUpdate); - } - - /// - public event INamePlateGui.OnPlateUpdateDelegate? OnNamePlateUpdate; - - /// - public event INamePlateGui.OnPlateUpdateDelegate? OnDataUpdate; - - /// - public unsafe void RequestRedraw() - { - var addon = this.gameGui.GetAddonByName("NamePlate"); - if (addon != 0) - { - var raptureAtkModule = RaptureAtkModule.Instance(); - if (raptureAtkModule == null) - { - return; - } - - ((AddonNamePlate*)addon)->DoFullUpdate = 1; - var namePlateNumberArrayData = raptureAtkModule->AtkArrayDataHolder.NumberArrays[NumberArrayIndex]; - namePlateNumberArrayData->SetValue(NumberArrayFullUpdateIndex, 1); - } - } - - /// - public void Dispose() - { - this.addonLifecycle.UnregisterListener(AddonEvent.PreRequestedUpdate, "NamePlate", this.OnPreRequestedUpdate); - } - - /// - /// Strips the surrounding quotes from a free company tag. If the quotes are not present in the expected location, - /// no modifications will be made. - /// - /// A quoted free company tag. - /// A span containing the free company tag without its surrounding quote characters. - internal static ReadOnlySpan StripFreeCompanyTagQuotes(ReadOnlySpan text) - { - if (text.Length > 4 && text.StartsWith(" «"u8) && text.EndsWith("»"u8)) - { - return text[3..^2]; - } - - return text; - } - - /// - /// Strips the surrounding quotes from a title. If the quotes are not present in the expected location, no - /// modifications will be made. - /// - /// A quoted title. - /// A span containing the title without its surrounding quote characters. - internal static ReadOnlySpan StripTitleQuotes(ReadOnlySpan text) - { - if (text.Length > 5 && text.StartsWith("《"u8) && text.EndsWith("》"u8)) - { - return text[3..^3]; - } - - return text; - } - - private static nint CreateEmptyStringPointer() - { - var pointer = Marshal.AllocHGlobal(1); - Marshal.WriteByte(pointer, 0, 0); - return pointer; - } - - private void CreateHandlers(NamePlateUpdateContext createdContext) - { - var handlers = new List(); - for (var i = 0; i < AddonNamePlate.NumNamePlateObjects; i++) - { - handlers.Add(new NamePlateUpdateHandler(createdContext, i)); - } - - this.updateHandlers = handlers.ToArray(); - } - - private void OnPreRequestedUpdate(AddonEvent type, AddonArgs args) - { - if (this.OnDataUpdate == null && this.OnNamePlateUpdate == null) - { - return; - } - - var reqArgs = (AddonRequestedUpdateArgs)args; - if (this.context == null) - { - this.context = new NamePlateUpdateContext(this.objectTable, reqArgs); - this.CreateHandlers(this.context); - } - else - { - this.context.ResetState(reqArgs); - } - - var activeNamePlateCount = this.context.ActiveNamePlateCount; - if (activeNamePlateCount == 0) - return; - - var activeHandlers = this.updateHandlers[..activeNamePlateCount]; - - if (this.context.IsFullUpdate) - { - foreach (var handler in activeHandlers) - { - handler.ResetState(); - } - - this.OnDataUpdate?.Invoke(this.context, activeHandlers); - this.OnNamePlateUpdate?.Invoke(this.context, activeHandlers); - if (this.context.HasParts) - this.ApplyBuilders(activeHandlers); - } - else - { - var udpatedHandlers = new List(activeNamePlateCount); - foreach (var handler in activeHandlers) - { - handler.ResetState(); - if (handler.IsUpdating) - udpatedHandlers.Add(handler); - } - - if (this.OnDataUpdate is not null) - { - this.OnDataUpdate?.Invoke(this.context, activeHandlers); - this.OnNamePlateUpdate?.Invoke(this.context, udpatedHandlers); - if (this.context.HasParts) - this.ApplyBuilders(activeHandlers); - } - else if (udpatedHandlers.Count != 0) - { - var changedHandlersSpan = udpatedHandlers.ToArray().AsSpan(); - this.OnNamePlateUpdate?.Invoke(this.context, udpatedHandlers); - if (this.context.HasParts) - this.ApplyBuilders(changedHandlersSpan); - } - } - } - - private void ApplyBuilders(Span handlers) - { - foreach (var handler in handlers) - { - if (handler.PartsContainer is { } container) - { - container.ApplyBuilders(handler); - } - } - } -} \ No newline at end of file diff --git a/Pilz.Dalamud/NamePlate/NamePlateInfoView.cs b/Pilz.Dalamud/NamePlate/NamePlateInfoView.cs deleted file mode 100644 index e64f3b4..0000000 --- a/Pilz.Dalamud/NamePlate/NamePlateInfoView.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Dalamud.Game.Text.SeStringHandling; - -using FFXIVClientStructs.FFXIV.Client.UI; - -namespace Pilz.Dalamud.NamePlate; - -/// -/// Provides a read-only view of the nameplate info object data for a nameplate. Modifications to -/// fields do not affect this data. -/// -public interface INamePlateInfoView -{ - /// - /// Gets the displayed name for this nameplate according to the nameplate info object. - /// - SeString Name { get; } - - /// - /// Gets the displayed free company tag for this nameplate according to the nameplate info object. For this field, - /// the quote characters which appear on either side of the title are NOT included. - /// - SeString FreeCompanyTag { get; } - - /// - /// Gets the displayed free company tag for this nameplate according to the nameplate info object. For this field, - /// the quote characters which appear on either side of the title ARE included. - /// - SeString QuotedFreeCompanyTag { get; } - - /// - /// Gets the displayed title for this nameplate according to the nameplate info object. For this field, the quote - /// characters which appear on either side of the title are NOT included. - /// - SeString Title { get; } - - /// - /// Gets the displayed title for this nameplate according to the nameplate info object. For this field, the quote - /// characters which appear on either side of the title ARE included. - /// - SeString QuotedTitle { get; } - - /// - /// Gets the displayed level text for this nameplate according to the nameplate info object. - /// - SeString LevelText { get; } - - /// - /// Gets the flags for this nameplate according to the nameplate info object. - /// - int Flags { get; } - - /// - /// Gets a value indicating whether this nameplate is considered 'dirty' or not according to the nameplate - /// info object. - /// - bool IsDirty { get; } - - /// - /// Gets a value indicating whether the title for this nameplate is a prefix title or not according to the nameplate - /// info object. This value is derived from the field. - /// - bool IsPrefixTitle { get; } -} - -/// -/// Provides a read-only view of the nameplate info object data for a nameplate. Modifications to -/// fields do not affect this data. -/// -internal unsafe class NamePlateInfoView(RaptureAtkModule.NamePlateInfo* info) : INamePlateInfoView -{ - private SeString? name; - private SeString? freeCompanyTag; - private SeString? quotedFreeCompanyTag; - private SeString? title; - private SeString? quotedTitle; - private SeString? levelText; - - /// - public SeString Name => this.name ??= SeString.Parse(info->Name); - - /// - public SeString FreeCompanyTag => this.freeCompanyTag ??= - SeString.Parse(NamePlateGui.StripFreeCompanyTagQuotes(info->FcName)); - - /// - public SeString QuotedFreeCompanyTag => this.quotedFreeCompanyTag ??= SeString.Parse(info->FcName); - - /// - public SeString Title => this.title ??= SeString.Parse(info->Title); - - /// - public SeString QuotedTitle => this.quotedTitle ??= SeString.Parse(info->DisplayTitle); - - /// - public SeString LevelText => this.levelText ??= SeString.Parse(info->LevelText); - - /// - public int Flags => info->Flags; - - /// - public bool IsDirty => info->IsDirty; - - /// - public bool IsPrefixTitle => ((info->Flags >> (8 * 3)) & 0xFF) == 1; -} diff --git a/Pilz.Dalamud/NamePlate/NamePlateKind.cs b/Pilz.Dalamud/NamePlate/NamePlateKind.cs deleted file mode 100644 index 09b4159..0000000 --- a/Pilz.Dalamud/NamePlate/NamePlateKind.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace Pilz.Dalamud.NamePlate; - -/// -/// An enum describing what kind of game object this nameplate represents. -/// -public enum NamePlateKind : byte -{ - /// - /// A player character. - /// - PlayerCharacter = 0, - - /// - /// An event NPC or companion. - /// - EventNpcCompanion = 1, - - /// - /// A retainer. - /// - Retainer = 2, - - /// - /// An enemy battle NPC. - /// - BattleNpcEnemy = 3, - - /// - /// A friendly battle NPC. - /// - BattleNpcFriendly = 4, - - /// - /// An event object. - /// - EventObject = 5, - - /// - /// Treasure. - /// - Treasure = 6, - - /// - /// A gathering point. - /// - GatheringPoint = 7, - - /// - /// A battle NPC with subkind 6. - /// - BattleNpcSubkind6 = 8, - - /// - /// Something else. - /// - Other = 9, -} diff --git a/Pilz.Dalamud/NamePlate/NamePlatePartsContainer.cs b/Pilz.Dalamud/NamePlate/NamePlatePartsContainer.cs deleted file mode 100644 index bc3be1b..0000000 --- a/Pilz.Dalamud/NamePlate/NamePlatePartsContainer.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Pilz.Dalamud.NamePlate; - -/// -/// A container for parts. -/// -internal class NamePlatePartsContainer -{ - private NamePlateSimpleParts? nameParts; - private NamePlateQuotedParts? titleParts; - private NamePlateQuotedParts? freeCompanyTagParts; - - /// - /// Initializes a new instance of the class. - /// - /// The currently executing update context. - public NamePlatePartsContainer(NamePlateUpdateContext context) - { - context.HasParts = true; - } - - /// - /// Gets a parts object for constructing a nameplate name. - /// - internal NamePlateSimpleParts Name => this.nameParts ??= new NamePlateSimpleParts(NamePlateStringField.Name); - - /// - /// Gets a parts object for constructing a nameplate title. - /// - internal NamePlateQuotedParts Title => this.titleParts ??= new NamePlateQuotedParts(NamePlateStringField.Title, false); - - /// - /// Gets a parts object for constructing a nameplate free company tag. - /// - internal NamePlateQuotedParts FreeCompanyTag => this.freeCompanyTagParts ??= new NamePlateQuotedParts(NamePlateStringField.FreeCompanyTag, true); - - /// - /// Applies all container parts. - /// - /// The handler to apply the builders to. - internal void ApplyBuilders(NamePlateUpdateHandler handler) - { - this.nameParts?.Apply(handler); - this.freeCompanyTagParts?.Apply(handler); - this.titleParts?.Apply(handler); - } -} diff --git a/Pilz.Dalamud/NamePlate/NamePlateQuotedParts.cs b/Pilz.Dalamud/NamePlate/NamePlateQuotedParts.cs deleted file mode 100644 index c82c046..0000000 --- a/Pilz.Dalamud/NamePlate/NamePlateQuotedParts.cs +++ /dev/null @@ -1,104 +0,0 @@ -using Dalamud.Game.Text.SeStringHandling; - -namespace Pilz.Dalamud.NamePlate; - -/// -/// A part builder for constructing and setting quoted nameplate fields (i.e. free company tag and title). -/// -/// The field type which should be set. -/// -/// This class works as a lazy writer initialized with empty parts, where an empty part signifies no change should be -/// performed. Only after all handler processing is complete does it write out any parts which were set to the -/// associated field. Reading fields from this class is usually not what you want to do, as you'll only be reading the -/// contents of parts which other plugins have written to. Prefer reading from the base handler's properties or using -/// . -/// -public class NamePlateQuotedParts(NamePlateStringField field, bool isFreeCompany) -{ - /// - /// Gets or sets the opening and closing SeStrings which will wrap the entire contents, which can be used to apply - /// colors or styling to the entire field. - /// - public (SeString, SeString)? OuterWrap { get; set; } - - /// - /// Gets or sets the opening quote string which appears before the text and opening text-wrap. - /// - public SeString? LeftQuote { get; set; } - - /// - /// Gets or sets the closing quote string which appears after the text and closing text-wrap. - /// - public SeString? RightQuote { get; set; } - - /// - /// Gets or sets the opening and closing SeStrings which will wrap the text, which can be used to apply colors or - /// styling to the field's text. - /// - public (SeString, SeString)? TextWrap { get; set; } - - /// - /// Gets or sets this field's text. - /// - public SeString? Text { get; set; } - - /// - /// Applies the changes from this builder to the actual field. - /// - /// The handler to perform the changes on. - internal unsafe void Apply(NamePlateUpdateHandler handler) - { - if ((nint)handler.GetFieldAsPointer(field) == NamePlateGui.EmptyStringPointer) - return; - - var sb = new SeStringBuilder(); - if (this.OuterWrap is { Item1: var outerLeft }) - { - sb.Append(outerLeft); - } - - if (this.LeftQuote is not null) - { - sb.Append(this.LeftQuote); - } - else - { - sb.Append(isFreeCompany ? " «" : "《"); - } - - if (this.TextWrap is { Item1: var left, Item2: var right }) - { - sb.Append(left); - sb.Append(this.Text ?? this.GetStrippedField(handler)); - sb.Append(right); - } - else - { - sb.Append(this.Text ?? this.GetStrippedField(handler)); - } - - if (this.RightQuote is not null) - { - sb.Append(this.RightQuote); - } - else - { - sb.Append(isFreeCompany ? "»" : "》"); - } - - if (this.OuterWrap is { Item2: var outerRight }) - { - sb.Append(outerRight); - } - - handler.SetField(field, sb.Build()); - } - - private SeString GetStrippedField(NamePlateUpdateHandler handler) - { - return SeString.Parse( - isFreeCompany - ? NamePlateGui.StripFreeCompanyTagQuotes(handler.GetFieldAsSpan(field)) - : NamePlateGui.StripTitleQuotes(handler.GetFieldAsSpan(field))); - } -} diff --git a/Pilz.Dalamud/NamePlate/NamePlateSimpleParts.cs b/Pilz.Dalamud/NamePlate/NamePlateSimpleParts.cs deleted file mode 100644 index 4c58881..0000000 --- a/Pilz.Dalamud/NamePlate/NamePlateSimpleParts.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Dalamud.Game.Text.SeStringHandling; - -namespace Pilz.Dalamud.NamePlate; - -/// -/// A part builder for constructing and setting a simple (unquoted) nameplate field. -/// -/// The field type which should be set. -/// -/// This class works as a lazy writer initialized with empty parts, where an empty part signifies no change should be -/// performed. Only after all handler processing is complete does it write out any parts which were set to the -/// associated field. Reading fields from this class is usually not what you want to do, as you'll only be reading the -/// contents of parts which other plugins have written to. Prefer reading from the base handler's properties or using -/// . -/// -public class NamePlateSimpleParts(NamePlateStringField field) -{ - /// - /// Gets or sets the opening and closing SeStrings which will wrap the text, which can be used to apply colors or - /// styling to the field's text. - /// - public (SeString, SeString)? TextWrap { get; set; } - - /// - /// Gets or sets this field's text. - /// - public SeString? Text { get; set; } - - /// - /// Applies the changes from this builder to the actual field. - /// - /// The handler to perform the changes on. - internal unsafe void Apply(NamePlateUpdateHandler handler) - { - if ((nint)handler.GetFieldAsPointer(field) == NamePlateGui.EmptyStringPointer) - return; - - if (this.TextWrap is { Item1: var left, Item2: var right }) - { - var sb = new SeStringBuilder(); - sb.Append(left); - sb.Append(this.Text ?? handler.GetFieldAsSeString(field)); - sb.Append(right); - handler.SetField(field, sb.Build()); - } - else if (this.Text is not null) - { - handler.SetField(field, this.Text); - } - } -} diff --git a/Pilz.Dalamud/NamePlate/NamePlateStringField.cs b/Pilz.Dalamud/NamePlate/NamePlateStringField.cs deleted file mode 100644 index a64e552..0000000 --- a/Pilz.Dalamud/NamePlate/NamePlateStringField.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Pilz.Dalamud.NamePlate; - -/// -/// An enum describing the string fields available in nameplate data. The and various flags -/// determine which fields will actually be rendered. -/// -public enum NamePlateStringField -{ - /// - /// The object's name. - /// - Name = 0, - - /// - /// The object's title. - /// - Title = 50, - - /// - /// The object's free company tag. - /// - FreeCompanyTag = 100, - - /// - /// The object's status prefix. - /// - StatusPrefix = 150, - - /// - /// The object's target suffix. - /// - TargetSuffix = 200, - - /// - /// The object's level prefix. - /// - LevelPrefix = 250, -} diff --git a/Pilz.Dalamud/NamePlate/NamePlateUpdateContext.cs b/Pilz.Dalamud/NamePlate/NamePlateUpdateContext.cs deleted file mode 100644 index c30cb18..0000000 --- a/Pilz.Dalamud/NamePlate/NamePlateUpdateContext.cs +++ /dev/null @@ -1,152 +0,0 @@ -using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; -using Dalamud.Game.ClientState.Objects; -using Dalamud.Plugin.Services; -using FFXIVClientStructs.FFXIV.Client.UI; -using FFXIVClientStructs.FFXIV.Component.GUI; - -namespace Pilz.Dalamud.NamePlate; - -/// -/// Contains information related to the pending nameplate data update. This is only valid for a single frame and should -/// not be kept across frames. -/// -public interface INamePlateUpdateContext -{ - /// - /// Gets the number of active nameplates. The actual number visible may be lower than this in cases where some - /// nameplates are hidden by default (based on in-game "Display Name Settings" and so on). - /// - int ActiveNamePlateCount { get; } - - /// - /// Gets a value indicating whether the game is currently performing a full update of all active nameplates. - /// - bool IsFullUpdate { get; } - - /// - /// Gets the address of the NamePlate addon. - /// - nint AddonAddress { get; } - - /// - /// Gets the address of the NamePlate addon's number array data container. - /// - nint NumberArrayDataAddress { get; } - - /// - /// Gets the address of the NamePlate addon's string array data container. - /// - nint StringArrayDataAddress { get; } - - /// - /// Gets the address of the first entry in the NamePlate addon's int array. - /// - nint NumberArrayDataEntryAddress { get; } -} - -/// -/// Contains information related to the pending nameplate data update. This is only valid for a single frame and should -/// not be kept across frames. -/// -internal unsafe class NamePlateUpdateContext : INamePlateUpdateContext -{ - /// - /// Initializes a new instance of the class. - /// - /// An object table. - /// The addon lifecycle arguments for the update request. - internal NamePlateUpdateContext(IObjectTable objectTable, AddonRequestedUpdateArgs args) - { - this.ObjectTable = objectTable; - this.RaptureAtkModule = FFXIVClientStructs.FFXIV.Client.UI.RaptureAtkModule.Instance(); - this.Ui3DModule = UIModule.Instance()->GetUI3DModule(); - this.ResetState(args); - } - - /// - /// Gets the number of active nameplates. The actual number visible may be lower than this in cases where some - /// nameplates are hidden by default (based on in-game "Display Name Settings" and so on). - /// - public int ActiveNamePlateCount { get; private set; } - - /// - /// Gets a value indicating whether the game is currently performing a full update of all active nameplates. - /// - public bool IsFullUpdate { get; private set; } - - /// - /// Gets the address of the NamePlate addon. - /// - public nint AddonAddress => (nint)this.Addon; - - /// - /// Gets the address of the NamePlate addon's number array data container. - /// - public nint NumberArrayDataAddress => (nint)this.NumberData; - - /// - /// Gets the address of the NamePlate addon's string array data container. - /// - public nint StringArrayDataAddress => (nint)this.StringData; - - /// - /// Gets the address of the first entry in the NamePlate addon's int array. - /// - public nint NumberArrayDataEntryAddress => (nint)this.NumberStruct; - - /// - /// Gets the RaptureAtkModule. - /// - internal RaptureAtkModule* RaptureAtkModule { get; } - - /// - /// Gets the Ui3DModule. - /// - internal UI3DModule* Ui3DModule { get; } - - /// - /// Gets the ObjectTable. - /// - internal IObjectTable ObjectTable { get; } - - /// - /// Gets a pointer to the NamePlate addon. - /// - internal AddonNamePlate* Addon { get; private set; } - - /// - /// Gets a pointer to the NamePlate addon's number array data container. - /// - internal NumberArrayData* NumberData { get; private set; } - - /// - /// Gets a pointer to the NamePlate addon's string array data container. - /// - internal StringArrayData* StringData { get; private set; } - - /// - /// Gets a pointer to the NamePlate addon's number array entries as a struct. - /// - internal AddonNamePlate.NamePlateIntArrayData* NumberStruct { get; private set; } - - /// - /// Gets or sets a value indicating whether any handler in the current context has instantiated a part builder. - /// - internal bool HasParts { get; set; } - - /// - /// Resets the state of the context based on the provided addon lifecycle arguments. - /// - /// The addon lifecycle arguments for the update request. - internal void ResetState(AddonRequestedUpdateArgs args) - { - this.Addon = (AddonNamePlate*)args.Addon; - this.NumberData = ((NumberArrayData**)args.NumberArrayData)![NamePlateGui.NumberArrayIndex]; - this.NumberStruct = (AddonNamePlate.NamePlateIntArrayData*)this.NumberData->IntArray; - this.StringData = ((StringArrayData**)args.StringArrayData)![NamePlateGui.StringArrayIndex]; - this.HasParts = false; - - this.ActiveNamePlateCount = this.NumberStruct->ActiveNamePlateCount; - this.IsFullUpdate = this.Addon->DoFullUpdate != 0; - } -} diff --git a/Pilz.Dalamud/NamePlate/NamePlateUpdateHandler.cs b/Pilz.Dalamud/NamePlate/NamePlateUpdateHandler.cs deleted file mode 100644 index cd300f9..0000000 --- a/Pilz.Dalamud/NamePlate/NamePlateUpdateHandler.cs +++ /dev/null @@ -1,606 +0,0 @@ -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; - -using Dalamud.Game.ClientState.Objects.SubKinds; -using Dalamud.Game.ClientState.Objects.Types; -using Dalamud.Game.Text.SeStringHandling; - -using FFXIVClientStructs.FFXIV.Client.UI; -using FFXIVClientStructs.Interop; - -namespace Pilz.Dalamud.NamePlate; - -/// -/// A class representing a single nameplate. Provides mechanisms to look up the game object associated with the -/// nameplate and allows for modification of various backing fields in number and string array data, which in turn -/// affect aspects of the nameplate's appearance when drawn. Instances of this class are only valid for a single frame -/// and should not be kept across frames. -/// -public interface INamePlateUpdateHandler -{ - /// - /// Gets the GameObjectId of the game object associated with this nameplate. - /// - ulong GameObjectId { get; } - - /// - /// Gets the associated with this nameplate, if possible. Performs an object table scan - /// and caches the result if successful. - /// - IGameObject? GameObject { get; } - - /// - /// Gets a read-only view of the nameplate info object data for a nameplate. Modifications to - /// fields do not affect fields in the returned view. - /// - INamePlateInfoView InfoView { get; } - - /// - /// Gets the index for this nameplate data in the backing number and string array data. This is not the same as the - /// rendered or object index, which can be retrieved from . - /// - int ArrayIndex { get; } - - /// - /// Gets the associated with this nameplate, if possible. Returns null if the nameplate - /// has an associated , but that object cannot be assigned to . - /// - IBattleChara? BattleChara { get; } - - /// - /// Gets the associated with this nameplate, if possible. Returns null if the - /// nameplate has an associated , but that object cannot be assigned to - /// . - /// - IPlayerCharacter? PlayerCharacter { get; } - - /// - /// Gets the address of the nameplate info struct. - /// - nint NamePlateInfoAddress { get; } - - /// - /// Gets the address of the first entry associated with this nameplate in the NamePlate addon's int array. - /// - nint NamePlateObjectAddress { get; } - - /// - /// Gets a value indicating what kind of nameplate this is, based on the kind of object it is associated with. - /// - NamePlateKind NamePlateKind { get; } - - /// - /// Gets the update flags for this nameplate. - /// - int UpdateFlags { get; } - - /// - /// Gets or sets the overall text color for this nameplate. If this value is changed, the appropriate update flag - /// will be set so that the game will reflect this change immediately. - /// - uint TextColor { get; set; } - - /// - /// Gets or sets the overall text edge color for this nameplate. If this value is changed, the appropriate update - /// flag will be set so that the game will reflect this change immediately. - /// - uint EdgeColor { get; set; } - - /// - /// Gets or sets the icon ID for the nameplate's marker icon, which is the large icon used to indicate quest - /// availability and so on. This value is read from and reset by the game every frame, not just when a nameplate - /// changes. Setting this to 0 disables the icon. - /// - int MarkerIconId { get; set; } - - /// - /// Gets or sets the icon ID for the nameplate's name icon, which is the small icon shown to the left of the name. - /// Setting this to -1 disables the icon. - /// - int NameIconId { get; set; } - - /// - /// Gets the nameplate index, which is the index used for rendering and looking up entries in the object array. For - /// number and string array data, is used. - /// - int NamePlateIndex { get; } - - /// - /// Gets the draw flags for this nameplate. - /// - int DrawFlags { get; } - - /// - /// Gets or sets the visibility flags for this nameplate. - /// - int VisibilityFlags { get; set; } - - /// - /// Gets a value indicating whether this nameplate is undergoing a major update or not. This is usually true when a - /// nameplate has just appeared or something meaningful about the entity has changed (e.g. its job or status). This - /// flag is reset by the game during the update process (during requested update and before draw). - /// - bool IsUpdating { get; } - - /// - /// Gets or sets a value indicating whether the title (when visible) will be displayed above the object's name (a - /// prefix title) instead of below the object's name (a suffix title). - /// - bool IsPrefixTitle { get; set; } - - /// - /// Gets or sets a value indicating whether the title should be displayed at all. - /// - bool DisplayTitle { get; set; } - - /// - /// Gets or sets the name for this nameplate. - /// - SeString Name { get; set; } - - /// - /// Gets a builder which can be used to help cooperatively build a new name for this nameplate even when other - /// plugins modifying the name are present. Specifically, this builder allows setting text and text-wrapping - /// payloads (e.g. for setting text color) separately. - /// - NamePlateSimpleParts NameParts { get; } - - /// - /// Gets or sets the title for this nameplate. - /// - SeString Title { get; set; } - - /// - /// Gets a builder which can be used to help cooperatively build a new title for this nameplate even when other - /// plugins modifying the title are present. Specifically, this builder allows setting text, text-wrapping - /// payloads (e.g. for setting text color), and opening and closing quote sequences separately. - /// - NamePlateQuotedParts TitleParts { get; } - - /// - /// Gets or sets the free company tag for this nameplate. - /// - SeString FreeCompanyTag { get; set; } - - /// - /// Gets a builder which can be used to help cooperatively build a new FC tag for this nameplate even when other - /// plugins modifying the FC tag are present. Specifically, this builder allows setting text, text-wrapping - /// payloads (e.g. for setting text color), and opening and closing quote sequences separately. - /// - NamePlateQuotedParts FreeCompanyTagParts { get; } - - /// - /// Gets or sets the status prefix for this nameplate. This prefix is used by the game to add BitmapFontIcon-based - /// online status icons to player nameplates. - /// - SeString StatusPrefix { get; set; } - - /// - /// Gets or sets the target suffix for this nameplate. This suffix is used by the game to add the squared-letter - /// target tags to the end of combat target nameplates. - /// - SeString TargetSuffix { get; set; } - - /// - /// Gets or sets the level prefix for this nameplate. This "Lv60" style prefix is added to enemy and friendly battle - /// NPC nameplates to indicate the NPC level. - /// - SeString LevelPrefix { get; set; } - - /// - /// Removes the contents of the name field for this nameplate. This differs from simply setting the field - /// to an empty string because it writes a special value to memory, and other setters (except SetField variants) - /// will refuse to overwrite this value. Therefore, fields removed this way are more likely to stay removed. - /// - void RemoveName(); - - /// - /// Removes the contents of the title field for this nameplate. This differs from simply setting the field - /// to an empty string because it writes a special value to memory, and other setters (except SetField variants) - /// will refuse to overwrite this value. Therefore, fields removed this way are more likely to stay removed. - /// - void RemoveTitle(); - - /// - /// Removes the contents of the FC tag field for this nameplate. This differs from simply setting the field - /// to an empty string because it writes a special value to memory, and other setters (except SetField variants) - /// will refuse to overwrite this value. Therefore, fields removed this way are more likely to stay removed. - /// - void RemoveFreeCompanyTag(); - - /// - /// Removes the contents of the status prefix field for this nameplate. This differs from simply setting the field - /// to an empty string because it writes a special value to memory, and other setters (except SetField variants) - /// will refuse to overwrite this value. Therefore, fields removed this way are more likely to stay removed. - /// - void RemoveStatusPrefix(); - - /// - /// Removes the contents of the target suffix field for this nameplate. This differs from simply setting the field - /// to an empty string because it writes a special value to memory, and other setters (except SetField variants) - /// will refuse to overwrite this value. Therefore, fields removed this way are more likely to stay removed. - /// - void RemoveTargetSuffix(); - - /// - /// Removes the contents of the level prefix field for this nameplate. This differs from simply setting the field - /// to an empty string because it writes a special value to memory, and other setters (except SetField variants) - /// will refuse to overwrite this value. Therefore, fields removed this way are more likely to stay removed. - /// - void RemoveLevelPrefix(); - - /// - /// Gets a pointer to the string array value in the provided field. - /// - /// The field to read from. - /// A pointer to a sequence of non-null bytes. - unsafe byte* GetFieldAsPointer(NamePlateStringField field); - - /// - /// Gets a byte span containing the string array value in the provided field. - /// - /// The field to read from. - /// A ReadOnlySpan containing a sequence of non-null bytes. - ReadOnlySpan GetFieldAsSpan(NamePlateStringField field); - - /// - /// Gets a UTF8 string copy of the string array value in the provided field. - /// - /// The field to read from. - /// A copy of the string array value as a string. - string GetFieldAsString(NamePlateStringField field); - - /// - /// Gets a parsed SeString copy of the string array value in the provided field. - /// - /// The field to read from. - /// A copy of the string array value as a parsed SeString. - SeString GetFieldAsSeString(NamePlateStringField field); - - /// - /// Sets the string array value for the provided field. - /// - /// The field to write to. - /// The string to write. - void SetField(NamePlateStringField field, string value); - - /// - /// Sets the string array value for the provided field. - /// - /// The field to write to. - /// The SeString to write. - void SetField(NamePlateStringField field, SeString value); - - /// - /// Sets the string array value for the provided field. - /// - /// The field to write to. - /// The ReadOnlySpan of bytes to write. - void SetField(NamePlateStringField field, ReadOnlySpan value); - - /// - /// Sets the string array value for the provided field. - /// - /// The field to write to. - /// The pointer to a null-terminated sequence of bytes to write. - unsafe void SetField(NamePlateStringField field, byte* value); - - /// - /// Sets the string array value for the provided field to a fixed pointer to an empty string in unmanaged memory. - /// Other methods may notice this fixed pointer and refuse to overwrite it, preserving the emptiness of the field. - /// - /// The field to write to. - void RemoveField(NamePlateStringField field); -} - -/// -/// A class representing a single nameplate. Provides mechanisms to look up the game object associated with the -/// nameplate and allows for modification of various backing fields in number and string array data, which in turn -/// affect aspects of the nameplate's appearance when drawn. Instances of this class are only valid for a single frame -/// and should not be kept across frames. -/// -internal unsafe class NamePlateUpdateHandler : INamePlateUpdateHandler -{ - private readonly NamePlateUpdateContext context; - - private ulong? gameObjectId; - private IGameObject? gameObject; - private NamePlateInfoView? infoView; - private NamePlatePartsContainer? partsContainer; - - /// - /// Initializes a new instance of the class. - /// - /// The current update context. - /// The index for this nameplate data in the backing number and string array data. This is - /// not the same as the rendered index, which can be retrieved from . - internal NamePlateUpdateHandler(NamePlateUpdateContext context, int arrayIndex) - { - this.context = context; - this.ArrayIndex = arrayIndex; - } - - /// - public int ArrayIndex { get; } - - /// - public ulong GameObjectId => this.gameObjectId ??= this.NamePlateInfo->ObjectId; - - /// - public IGameObject? GameObject => this.gameObject ??= this.context.ObjectTable.CreateObjectReference( - (nint)this.context.Ui3DModule->NamePlateObjectInfoPointers[ - this.ArrayIndex].Value->GameObject); - - /// - public IBattleChara? BattleChara => this.GameObject as IBattleChara; - - /// - public IPlayerCharacter? PlayerCharacter => this.GameObject as IPlayerCharacter; - - /// - public INamePlateInfoView InfoView => this.infoView ??= new NamePlateInfoView(this.NamePlateInfo); - - /// - public nint NamePlateInfoAddress => (nint)this.NamePlateInfo; - - /// - public nint NamePlateObjectAddress => (nint)this.NamePlateObject; - - /// - public NamePlateKind NamePlateKind => (NamePlateKind)this.ObjectData->NamePlateKind; - - /// - public int UpdateFlags - { - get => this.ObjectData->UpdateFlags; - private set => this.ObjectData->UpdateFlags = value; - } - - /// - public uint TextColor - { - get => this.ObjectData->NameTextColor; - set - { - if (value != this.TextColor) this.UpdateFlags |= 2; - this.ObjectData->NameTextColor = value; - } - } - - /// - public uint EdgeColor - { - get => this.ObjectData->NameEdgeColor; - set - { - if (value != this.EdgeColor) this.UpdateFlags |= 2; - this.ObjectData->NameEdgeColor = value; - } - } - - /// - public int MarkerIconId - { - get => this.ObjectData->MarkerIconId; - set => this.ObjectData->MarkerIconId = value; - } - - /// - public int NameIconId - { - get => this.ObjectData->NameIconId; - set => this.ObjectData->NameIconId = value; - } - - /// - public int NamePlateIndex => this.ObjectData->NamePlateObjectIndex; - - /// - public int DrawFlags - { - get => this.ObjectData->DrawFlags; - private set => this.ObjectData->DrawFlags = value; - } - - /// - public int VisibilityFlags - { - get => ObjectData->VisibilityFlags; - set => ObjectData->VisibilityFlags = value; - } - - /// - public bool IsUpdating => (this.UpdateFlags & 1) != 0; - - /// - public bool IsPrefixTitle - { - get => (this.DrawFlags & 1) != 0; - set => this.DrawFlags = value ? this.DrawFlags | 1 : this.DrawFlags & ~1; - } - - /// - public bool DisplayTitle - { - get => (this.DrawFlags & 0x80) == 0; - set => this.DrawFlags = value ? this.DrawFlags & ~0x80 : this.DrawFlags | 0x80; - } - - /// - public SeString Name - { - get => this.GetFieldAsSeString(NamePlateStringField.Name); - set => this.WeakSetField(NamePlateStringField.Name, value); - } - - /// - public NamePlateSimpleParts NameParts => this.PartsContainer.Name; - - /// - public SeString Title - { - get => this.GetFieldAsSeString(NamePlateStringField.Title); - set => this.WeakSetField(NamePlateStringField.Title, value); - } - - /// - public NamePlateQuotedParts TitleParts => this.PartsContainer.Title; - - /// - public SeString FreeCompanyTag - { - get => this.GetFieldAsSeString(NamePlateStringField.FreeCompanyTag); - set => this.WeakSetField(NamePlateStringField.FreeCompanyTag, value); - } - - /// - public NamePlateQuotedParts FreeCompanyTagParts => this.PartsContainer.FreeCompanyTag; - - /// - public SeString StatusPrefix - { - get => this.GetFieldAsSeString(NamePlateStringField.StatusPrefix); - set => this.WeakSetField(NamePlateStringField.StatusPrefix, value); - } - - /// - public SeString TargetSuffix - { - get => this.GetFieldAsSeString(NamePlateStringField.TargetSuffix); - set => this.WeakSetField(NamePlateStringField.TargetSuffix, value); - } - - /// - public SeString LevelPrefix - { - get => this.GetFieldAsSeString(NamePlateStringField.LevelPrefix); - set => this.WeakSetField(NamePlateStringField.LevelPrefix, value); - } - - /// - /// Gets or (lazily) creates a part builder container for this nameplate. - /// - internal NamePlatePartsContainer PartsContainer => - this.partsContainer ??= new NamePlatePartsContainer(this.context); - - private RaptureAtkModule.NamePlateInfo* NamePlateInfo => - this.context.RaptureAtkModule->NamePlateInfoEntries.GetPointer(this.NamePlateIndex); - - private AddonNamePlate.NamePlateObject* NamePlateObject => - &this.context.Addon->NamePlateObjectArray[this.NamePlateIndex]; - - private AddonNamePlate.NamePlateIntArrayData.NamePlateObjectIntArrayData* ObjectData => - this.context.NumberStruct->ObjectData.GetPointer(this.ArrayIndex); - - /// - public void RemoveName() => this.RemoveField(NamePlateStringField.Name); - - /// - public void RemoveTitle() => this.RemoveField(NamePlateStringField.Title); - - /// - public void RemoveFreeCompanyTag() => this.RemoveField(NamePlateStringField.FreeCompanyTag); - - /// - public void RemoveStatusPrefix() => this.RemoveField(NamePlateStringField.StatusPrefix); - - /// - public void RemoveTargetSuffix() => this.RemoveField(NamePlateStringField.TargetSuffix); - - /// - public void RemoveLevelPrefix() => this.RemoveField(NamePlateStringField.LevelPrefix); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public byte* GetFieldAsPointer(NamePlateStringField field) - { - return this.context.StringData->StringArray[this.ArrayIndex + (int)field]; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan GetFieldAsSpan(NamePlateStringField field) - { - return MemoryMarshal.CreateReadOnlySpanFromNullTerminated(this.GetFieldAsPointer(field)); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public string GetFieldAsString(NamePlateStringField field) - { - return Encoding.UTF8.GetString(this.GetFieldAsSpan(field)); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public SeString GetFieldAsSeString(NamePlateStringField field) - { - return SeString.Parse(this.GetFieldAsSpan(field)); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetField(NamePlateStringField field, string value) - { - this.context.StringData->SetValue(this.ArrayIndex + (int)field, value, true, true, true); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetField(NamePlateStringField field, SeString value) - { - this.context.StringData->SetValue(this.ArrayIndex + (int)field, value.Encode(), true, true, true); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetField(NamePlateStringField field, ReadOnlySpan value) - { - this.context.StringData->SetValue(this.ArrayIndex + (int)field, value, true, true, true); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetField(NamePlateStringField field, byte* value) - { - this.context.StringData->SetValue(this.ArrayIndex + (int)field, value, true, true, true); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveField(NamePlateStringField field) - { - this.context.StringData->SetValue( - this.ArrayIndex + (int)field, - (byte*)NamePlateGui.EmptyStringPointer, - true, - false, - true); - } - - /// - /// Resets the state of this handler for re-use in a new update. - /// - internal void ResetState() - { - this.gameObjectId = null; - this.gameObject = null; - this.infoView = null; - this.partsContainer = null; - } - - /// - /// Sets the string array value for the provided field, unless it was already set to the special empty string - /// pointer used by the Remove methods. - /// - /// The field to write to. - /// The SeString to write. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WeakSetField(NamePlateStringField field, SeString value) - { - if ((nint)this.GetFieldAsPointer(field) == NamePlateGui.EmptyStringPointer) - return; - this.context.StringData->SetValue(this.ArrayIndex + (int)field, value.Encode(), true, true, true); - } -} diff --git a/Pilz.Dalamud/Tools/NamePlates/NameplateChanges.cs b/Pilz.Dalamud/Tools/NamePlates/NameplateChanges.cs index 2a8cc7b..2a56815 100644 --- a/Pilz.Dalamud/Tools/NamePlates/NameplateChanges.cs +++ b/Pilz.Dalamud/Tools/NamePlates/NameplateChanges.cs @@ -1,4 +1,4 @@ -using Pilz.Dalamud.NamePlate; +using Dalamud.Game.Gui.NamePlate; namespace Pilz.Dalamud.Tools.NamePlates; diff --git a/Pilz.Dalamud/Tools/NamePlates/NameplateElementChange.cs b/Pilz.Dalamud/Tools/NamePlates/NameplateElementChange.cs index 53a7c3a..5cf4a4f 100644 --- a/Pilz.Dalamud/Tools/NamePlates/NameplateElementChange.cs +++ b/Pilz.Dalamud/Tools/NamePlates/NameplateElementChange.cs @@ -1,5 +1,5 @@ -using Dalamud.Game.Text.SeStringHandling; -using Pilz.Dalamud.NamePlate; +using Dalamud.Game.Gui.NamePlate; +using Dalamud.Game.Text.SeStringHandling; using Pilz.Dalamud.Tools.Strings; namespace Pilz.Dalamud.Tools.NamePlates; diff --git a/Pilz.Dalamud/Tools/NamePlates/NameplateUpdateFactory.cs b/Pilz.Dalamud/Tools/NamePlates/NameplateUpdateFactory.cs index fd6d1e3..3b07913 100644 --- a/Pilz.Dalamud/Tools/NamePlates/NameplateUpdateFactory.cs +++ b/Pilz.Dalamud/Tools/NamePlates/NameplateUpdateFactory.cs @@ -1,8 +1,8 @@ -using Dalamud.Game.Text.SeStringHandling; +using Dalamud.Game.Gui.NamePlate; +using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling.Payloads; using Pilz.Dalamud.ActivityContexts; using Pilz.Dalamud.Icons; -using Pilz.Dalamud.NamePlate; namespace Pilz.Dalamud.Tools.NamePlates; @@ -31,7 +31,7 @@ public static class NameplateUpdateFactory if (handler.StatusPrefix is SeString str) str.Payloads.Insert(0, icon); else - handler.StatusPrefix = SeString.Empty.Append(icon); + handler.StatusPrefix = SeString.Empty.Append(icon); // If we moved it, we don't need it as icon anymore, yay :D isPrio = false;