Compare commits
17 Commits
86686bf0ca
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| d6d746c1ed | |||
| 50a8dc6d09 | |||
| 6ad3faa922 | |||
| 64dd38a2a3 | |||
| e748ba7138 | |||
| 62ce794e8b | |||
| 0f6c3a5332 | |||
| ca638c19a2 | |||
| 2680d24a39 | |||
| 082e9e5580 | |||
| 004056b648 | |||
| ca28a9d6f7 | |||
| 83d705c4c6 | |||
| 5b75e305eb | |||
| 0669b2cecb | |||
| 3df83a8fa7 | |||
| e92662969b |
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Pilzinsel64
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
using Lumina.Excel;
|
using Lumina.Excel;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
using Lumina.Excel.Sheets;
|
||||||
|
|
||||||
namespace Pilz.Dalamud.ActivityContexts;
|
namespace Pilz.Dalamud.ActivityContexts;
|
||||||
|
|
||||||
@@ -36,11 +36,11 @@ public class ActivityContextManager : IDisposable
|
|||||||
|
|
||||||
private void CheckCurrentTerritory()
|
private void CheckCurrentTerritory()
|
||||||
{
|
{
|
||||||
var content = contentFinderConditionsSheet.FirstOrDefault(c => c.TerritoryType.Row == PluginServices.ClientState.TerritoryType);
|
var content = contentFinderConditionsSheet.FirstOrDefault(c => c.TerritoryType.RowId == PluginServices.ClientState.TerritoryType);
|
||||||
ActivityType newActivityContext;
|
ActivityType newActivityContext;
|
||||||
ZoneType newZoneType;
|
ZoneType newZoneType;
|
||||||
|
|
||||||
if (content == null)
|
if (content.RowId == 0)
|
||||||
{
|
{
|
||||||
// No content found, so we must be on the overworld
|
// No content found, so we must be on the overworld
|
||||||
newActivityContext = ActivityType.None;
|
newActivityContext = ActivityType.None;
|
||||||
@@ -58,7 +58,7 @@ public class ActivityContextManager : IDisposable
|
|||||||
newActivityContext = ActivityType.PveDuty;
|
newActivityContext = ActivityType.PveDuty;
|
||||||
|
|
||||||
// Find correct member type
|
// Find correct member type
|
||||||
var memberType = content.ContentMemberType.Row;
|
var memberType = content.ContentMemberType.RowId;
|
||||||
if (content.RowId == 16 || content.RowId == 15)
|
if (content.RowId == 16 || content.RowId == 15)
|
||||||
memberType = 2; // Praetorium and Castrum Meridianum
|
memberType = 2; // Praetorium and Castrum Meridianum
|
||||||
else if (content.RowId == 735 || content.RowId == 778)
|
else if (content.RowId == 735 || content.RowId == 778)
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using Lumina.Text.ReadOnly;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Pilz.Dalamud;
|
namespace Pilz.Dalamud;
|
||||||
|
|
||||||
@@ -32,4 +35,10 @@ public static class Extensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
public static string ParseString(this ReadOnlySeString readOnlySeString)
|
||||||
|
{
|
||||||
|
return Encoding.UTF8.GetString(readOnlySeString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.NamePlate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class used to modify the data used when rendering nameplates.
|
|
||||||
/// </summary>
|
|
||||||
public interface INamePlateGui
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The delegate used for receiving nameplate update events.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">An object containing information about the pending data update.</param>
|
|
||||||
/// <param name="handlers>">A list of handlers used for updating nameplate data.</param>
|
|
||||||
public delegate void OnPlateUpdateDelegate(INamePlateUpdateContext context, IReadOnlyList<INamePlateUpdateHandler> handlers);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Fires after <see cref="OnDataUpdate"/>.
|
|
||||||
/// </remarks>
|
|
||||||
event OnPlateUpdateDelegate? OnNamePlateUpdate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event which fires when nameplate data is updated. The subscriber is provided with a list of handlers for all
|
|
||||||
/// nameplates.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This event is likely to fire every frame even when no nameplates are actually updated, so in most cases
|
|
||||||
/// <see cref="OnNamePlateUpdate"/> is preferred. Fires before <see cref="OnNamePlateUpdate"/>.
|
|
||||||
/// </remarks>
|
|
||||||
event OnPlateUpdateDelegate? OnDataUpdate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Requests that all nameplates should be redrawn on the following frame.
|
|
||||||
/// </summary>
|
|
||||||
void RequestRedraw();
|
|
||||||
|
|
||||||
private static NamePlateGui instance;
|
|
||||||
public static INamePlateGui Instance => instance ??= new ();
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class used to modify the data used when rendering nameplates.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class NamePlateGui : IDisposable, INamePlateGui
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The index for the number array used by the NamePlate addon.
|
|
||||||
/// </summary>
|
|
||||||
public const int NumberArrayIndex = 5;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The index for the string array used by the NamePlate addon.
|
|
||||||
/// </summary>
|
|
||||||
public const int StringArrayIndex = 4;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The index for of the FullUpdate entry in the NamePlate number array.
|
|
||||||
/// </summary>
|
|
||||||
internal const int NumberArrayFullUpdateIndex = 4;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An empty null-terminated string pointer allocated in unmanaged memory, used to tag removed fields.
|
|
||||||
/// </summary>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public event INamePlateGui.OnPlateUpdateDelegate? OnNamePlateUpdate;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public event INamePlateGui.OnPlateUpdateDelegate? OnDataUpdate;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.addonLifecycle.UnregisterListener(AddonEvent.PreRequestedUpdate, "NamePlate", this.OnPreRequestedUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Strips the surrounding quotes from a free company tag. If the quotes are not present in the expected location,
|
|
||||||
/// no modifications will be made.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">A quoted free company tag.</param>
|
|
||||||
/// <returns>A span containing the free company tag without its surrounding quote characters.</returns>
|
|
||||||
internal static ReadOnlySpan<byte> StripFreeCompanyTagQuotes(ReadOnlySpan<byte> text)
|
|
||||||
{
|
|
||||||
if (text.Length > 4 && text.StartsWith(" «"u8) && text.EndsWith("»"u8))
|
|
||||||
{
|
|
||||||
return text[3..^2];
|
|
||||||
}
|
|
||||||
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Strips the surrounding quotes from a title. If the quotes are not present in the expected location, no
|
|
||||||
/// modifications will be made.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">A quoted title.</param>
|
|
||||||
/// <returns>A span containing the title without its surrounding quote characters.</returns>
|
|
||||||
internal static ReadOnlySpan<byte> StripTitleQuotes(ReadOnlySpan<byte> 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<NamePlateUpdateHandler>();
|
|
||||||
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<NamePlateUpdateHandler>(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<NamePlateUpdateHandler> handlers)
|
|
||||||
{
|
|
||||||
foreach (var handler in handlers)
|
|
||||||
{
|
|
||||||
if (handler.PartsContainer is { } container)
|
|
||||||
{
|
|
||||||
container.ApplyBuilders(handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
|
||||||
|
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.NamePlate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides a read-only view of the nameplate info object data for a nameplate. Modifications to
|
|
||||||
/// <see cref="NamePlateUpdateHandler"/> fields do not affect this data.
|
|
||||||
/// </summary>
|
|
||||||
public interface INamePlateInfoView
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the displayed name for this nameplate according to the nameplate info object.
|
|
||||||
/// </summary>
|
|
||||||
SeString Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
SeString FreeCompanyTag { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
SeString QuotedFreeCompanyTag { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
SeString Title { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
SeString QuotedTitle { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the displayed level text for this nameplate according to the nameplate info object.
|
|
||||||
/// </summary>
|
|
||||||
SeString LevelText { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the flags for this nameplate according to the nameplate info object.
|
|
||||||
/// </summary>
|
|
||||||
int Flags { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether this nameplate is considered 'dirty' or not according to the nameplate
|
|
||||||
/// info object.
|
|
||||||
/// </summary>
|
|
||||||
bool IsDirty { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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 <see cref="Flags"/> field.
|
|
||||||
/// </summary>
|
|
||||||
bool IsPrefixTitle { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides a read-only view of the nameplate info object data for a nameplate. Modifications to
|
|
||||||
/// <see cref="NamePlateUpdateHandler"/> fields do not affect this data.
|
|
||||||
/// </summary>
|
|
||||||
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;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString Name => this.name ??= SeString.Parse(info->Name);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString FreeCompanyTag => this.freeCompanyTag ??=
|
|
||||||
SeString.Parse(NamePlateGui.StripFreeCompanyTagQuotes(info->FcName));
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString QuotedFreeCompanyTag => this.quotedFreeCompanyTag ??= SeString.Parse(info->FcName);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString Title => this.title ??= SeString.Parse(info->Title);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString QuotedTitle => this.quotedTitle ??= SeString.Parse(info->DisplayTitle);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString LevelText => this.levelText ??= SeString.Parse(info->LevelText);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int Flags => info->Flags;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool IsDirty => info->IsDirty;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool IsPrefixTitle => ((info->Flags >> (8 * 3)) & 0xFF) == 1;
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
namespace Pilz.Dalamud.NamePlate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An enum describing what kind of game object this nameplate represents.
|
|
||||||
/// </summary>
|
|
||||||
public enum NamePlateKind : byte
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A player character.
|
|
||||||
/// </summary>
|
|
||||||
PlayerCharacter = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event NPC or companion.
|
|
||||||
/// </summary>
|
|
||||||
EventNpcCompanion = 1,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A retainer.
|
|
||||||
/// </summary>
|
|
||||||
Retainer = 2,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An enemy battle NPC.
|
|
||||||
/// </summary>
|
|
||||||
BattleNpcEnemy = 3,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A friendly battle NPC.
|
|
||||||
/// </summary>
|
|
||||||
BattleNpcFriendly = 4,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event object.
|
|
||||||
/// </summary>
|
|
||||||
EventObject = 5,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Treasure.
|
|
||||||
/// </summary>
|
|
||||||
Treasure = 6,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A gathering point.
|
|
||||||
/// </summary>
|
|
||||||
GatheringPoint = 7,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A battle NPC with subkind 6.
|
|
||||||
/// </summary>
|
|
||||||
BattleNpcSubkind6 = 8,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Something else.
|
|
||||||
/// </summary>
|
|
||||||
Other = 9,
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
namespace Pilz.Dalamud.NamePlate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A container for parts.
|
|
||||||
/// </summary>
|
|
||||||
internal class NamePlatePartsContainer
|
|
||||||
{
|
|
||||||
private NamePlateSimpleParts? nameParts;
|
|
||||||
private NamePlateQuotedParts? titleParts;
|
|
||||||
private NamePlateQuotedParts? freeCompanyTagParts;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="NamePlatePartsContainer"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The currently executing update context.</param>
|
|
||||||
public NamePlatePartsContainer(NamePlateUpdateContext context)
|
|
||||||
{
|
|
||||||
context.HasParts = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a parts object for constructing a nameplate name.
|
|
||||||
/// </summary>
|
|
||||||
internal NamePlateSimpleParts Name => this.nameParts ??= new NamePlateSimpleParts(NamePlateStringField.Name);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a parts object for constructing a nameplate title.
|
|
||||||
/// </summary>
|
|
||||||
internal NamePlateQuotedParts Title => this.titleParts ??= new NamePlateQuotedParts(NamePlateStringField.Title, false);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a parts object for constructing a nameplate free company tag.
|
|
||||||
/// </summary>
|
|
||||||
internal NamePlateQuotedParts FreeCompanyTag => this.freeCompanyTagParts ??= new NamePlateQuotedParts(NamePlateStringField.FreeCompanyTag, true);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies all container parts.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handler">The handler to apply the builders to.</param>
|
|
||||||
internal void ApplyBuilders(NamePlateUpdateHandler handler)
|
|
||||||
{
|
|
||||||
this.nameParts?.Apply(handler);
|
|
||||||
this.freeCompanyTagParts?.Apply(handler);
|
|
||||||
this.titleParts?.Apply(handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.NamePlate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A part builder for constructing and setting quoted nameplate fields (i.e. free company tag and title).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field type which should be set.</param>
|
|
||||||
/// <remarks>
|
|
||||||
/// 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
|
|
||||||
/// <see cref="NamePlateInfoView"/>.
|
|
||||||
/// </remarks>
|
|
||||||
public class NamePlateQuotedParts(NamePlateStringField field, bool isFreeCompany)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
public (SeString, SeString)? OuterWrap { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the opening quote string which appears before the text and opening text-wrap.
|
|
||||||
/// </summary>
|
|
||||||
public SeString? LeftQuote { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the closing quote string which appears after the text and closing text-wrap.
|
|
||||||
/// </summary>
|
|
||||||
public SeString? RightQuote { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
public (SeString, SeString)? TextWrap { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets this field's text.
|
|
||||||
/// </summary>
|
|
||||||
public SeString? Text { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies the changes from this builder to the actual field.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handler">The handler to perform the changes on.</param>
|
|
||||||
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)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.NamePlate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A part builder for constructing and setting a simple (unquoted) nameplate field.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field type which should be set.</param>
|
|
||||||
/// <remarks>
|
|
||||||
/// 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
|
|
||||||
/// <see cref="NamePlateInfoView"/>.
|
|
||||||
/// </remarks>
|
|
||||||
public class NamePlateSimpleParts(NamePlateStringField field)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
public (SeString, SeString)? TextWrap { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets this field's text.
|
|
||||||
/// </summary>
|
|
||||||
public SeString? Text { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies the changes from this builder to the actual field.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="handler">The handler to perform the changes on.</param>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
namespace Pilz.Dalamud.NamePlate;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An enum describing the string fields available in nameplate data. The <see cref="NamePlateKind"/> and various flags
|
|
||||||
/// determine which fields will actually be rendered.
|
|
||||||
/// </summary>
|
|
||||||
public enum NamePlateStringField
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The object's name.
|
|
||||||
/// </summary>
|
|
||||||
Name = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The object's title.
|
|
||||||
/// </summary>
|
|
||||||
Title = 50,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The object's free company tag.
|
|
||||||
/// </summary>
|
|
||||||
FreeCompanyTag = 100,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The object's status prefix.
|
|
||||||
/// </summary>
|
|
||||||
StatusPrefix = 150,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The object's target suffix.
|
|
||||||
/// </summary>
|
|
||||||
TargetSuffix = 200,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The object's level prefix.
|
|
||||||
/// </summary>
|
|
||||||
LevelPrefix = 250,
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains information related to the pending nameplate data update. This is only valid for a single frame and should
|
|
||||||
/// not be kept across frames.
|
|
||||||
/// </summary>
|
|
||||||
public interface INamePlateUpdateContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 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).
|
|
||||||
/// </summary>
|
|
||||||
int ActiveNamePlateCount { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the game is currently performing a full update of all active nameplates.
|
|
||||||
/// </summary>
|
|
||||||
bool IsFullUpdate { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the NamePlate addon.
|
|
||||||
/// </summary>
|
|
||||||
nint AddonAddress { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the NamePlate addon's number array data container.
|
|
||||||
/// </summary>
|
|
||||||
nint NumberArrayDataAddress { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the NamePlate addon's string array data container.
|
|
||||||
/// </summary>
|
|
||||||
nint StringArrayDataAddress { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the first entry in the NamePlate addon's int array.
|
|
||||||
/// </summary>
|
|
||||||
nint NumberArrayDataEntryAddress { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains information related to the pending nameplate data update. This is only valid for a single frame and should
|
|
||||||
/// not be kept across frames.
|
|
||||||
/// </summary>
|
|
||||||
internal unsafe class NamePlateUpdateContext : INamePlateUpdateContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="NamePlateUpdateContext"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="objectTable">An object table.</param>
|
|
||||||
/// <param name="args">The addon lifecycle arguments for the update request.</param>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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).
|
|
||||||
/// </summary>
|
|
||||||
public int ActiveNamePlateCount { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether the game is currently performing a full update of all active nameplates.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsFullUpdate { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the NamePlate addon.
|
|
||||||
/// </summary>
|
|
||||||
public nint AddonAddress => (nint)this.Addon;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the NamePlate addon's number array data container.
|
|
||||||
/// </summary>
|
|
||||||
public nint NumberArrayDataAddress => (nint)this.NumberData;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the NamePlate addon's string array data container.
|
|
||||||
/// </summary>
|
|
||||||
public nint StringArrayDataAddress => (nint)this.StringData;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the first entry in the NamePlate addon's int array.
|
|
||||||
/// </summary>
|
|
||||||
public nint NumberArrayDataEntryAddress => (nint)this.NumberStruct;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the RaptureAtkModule.
|
|
||||||
/// </summary>
|
|
||||||
internal RaptureAtkModule* RaptureAtkModule { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the Ui3DModule.
|
|
||||||
/// </summary>
|
|
||||||
internal UI3DModule* Ui3DModule { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ObjectTable.
|
|
||||||
/// </summary>
|
|
||||||
internal IObjectTable ObjectTable { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a pointer to the NamePlate addon.
|
|
||||||
/// </summary>
|
|
||||||
internal AddonNamePlate* Addon { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a pointer to the NamePlate addon's number array data container.
|
|
||||||
/// </summary>
|
|
||||||
internal NumberArrayData* NumberData { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a pointer to the NamePlate addon's string array data container.
|
|
||||||
/// </summary>
|
|
||||||
internal StringArrayData* StringData { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a pointer to the NamePlate addon's number array entries as a struct.
|
|
||||||
/// </summary>
|
|
||||||
internal AddonNamePlate.NamePlateIntArrayData* NumberStruct { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether any handler in the current context has instantiated a part builder.
|
|
||||||
/// </summary>
|
|
||||||
internal bool HasParts { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets the state of the context based on the provided addon lifecycle arguments.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args">The addon lifecycle arguments for the update request.</param>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
public interface INamePlateUpdateHandler
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the GameObjectId of the game object associated with this nameplate.
|
|
||||||
/// </summary>
|
|
||||||
ulong GameObjectId { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="IGameObject"/> associated with this nameplate, if possible. Performs an object table scan
|
|
||||||
/// and caches the result if successful.
|
|
||||||
/// </summary>
|
|
||||||
IGameObject? GameObject { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a read-only view of the nameplate info object data for a nameplate. Modifications to
|
|
||||||
/// <see cref="NamePlateUpdateHandler"/> fields do not affect fields in the returned view.
|
|
||||||
/// </summary>
|
|
||||||
INamePlateInfoView InfoView { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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 <see cref="NamePlateIndex"/>.
|
|
||||||
/// </summary>
|
|
||||||
int ArrayIndex { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="IBattleChara"/> associated with this nameplate, if possible. Returns null if the nameplate
|
|
||||||
/// has an associated <see cref="IGameObject"/>, but that object cannot be assigned to <see cref="IBattleChara"/>.
|
|
||||||
/// </summary>
|
|
||||||
IBattleChara? BattleChara { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="IPlayerCharacter"/> associated with this nameplate, if possible. Returns null if the
|
|
||||||
/// nameplate has an associated <see cref="IGameObject"/>, but that object cannot be assigned to
|
|
||||||
/// <see cref="IPlayerCharacter"/>.
|
|
||||||
/// </summary>
|
|
||||||
IPlayerCharacter? PlayerCharacter { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the nameplate info struct.
|
|
||||||
/// </summary>
|
|
||||||
nint NamePlateInfoAddress { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the first entry associated with this nameplate in the NamePlate addon's int array.
|
|
||||||
/// </summary>
|
|
||||||
nint NamePlateObjectAddress { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating what kind of nameplate this is, based on the kind of object it is associated with.
|
|
||||||
/// </summary>
|
|
||||||
NamePlateKind NamePlateKind { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the update flags for this nameplate.
|
|
||||||
/// </summary>
|
|
||||||
int UpdateFlags { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
uint TextColor { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
uint EdgeColor { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
int MarkerIconId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
int NameIconId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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, <see cref="ArrayIndex"/> is used.
|
|
||||||
/// </summary>
|
|
||||||
int NamePlateIndex { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the draw flags for this nameplate.
|
|
||||||
/// </summary>
|
|
||||||
int DrawFlags { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the visibility flags for this nameplate.
|
|
||||||
/// </summary>
|
|
||||||
int VisibilityFlags { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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).
|
|
||||||
/// </summary>
|
|
||||||
bool IsUpdating { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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).
|
|
||||||
/// </summary>
|
|
||||||
bool IsPrefixTitle { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether the title should be displayed at all.
|
|
||||||
/// </summary>
|
|
||||||
bool DisplayTitle { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the name for this nameplate.
|
|
||||||
/// </summary>
|
|
||||||
SeString Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
NamePlateSimpleParts NameParts { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the title for this nameplate.
|
|
||||||
/// </summary>
|
|
||||||
SeString Title { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
NamePlateQuotedParts TitleParts { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the free company tag for this nameplate.
|
|
||||||
/// </summary>
|
|
||||||
SeString FreeCompanyTag { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
NamePlateQuotedParts FreeCompanyTagParts { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
SeString StatusPrefix { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
SeString TargetSuffix { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
SeString LevelPrefix { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
void RemoveName();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
void RemoveTitle();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
void RemoveFreeCompanyTag();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
void RemoveStatusPrefix();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
void RemoveTargetSuffix();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
void RemoveLevelPrefix();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a pointer to the string array value in the provided field.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field to read from.</param>
|
|
||||||
/// <returns>A pointer to a sequence of non-null bytes.</returns>
|
|
||||||
unsafe byte* GetFieldAsPointer(NamePlateStringField field);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a byte span containing the string array value in the provided field.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field to read from.</param>
|
|
||||||
/// <returns>A ReadOnlySpan containing a sequence of non-null bytes.</returns>
|
|
||||||
ReadOnlySpan<byte> GetFieldAsSpan(NamePlateStringField field);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a UTF8 string copy of the string array value in the provided field.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field to read from.</param>
|
|
||||||
/// <returns>A copy of the string array value as a string.</returns>
|
|
||||||
string GetFieldAsString(NamePlateStringField field);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a parsed SeString copy of the string array value in the provided field.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field to read from.</param>
|
|
||||||
/// <returns>A copy of the string array value as a parsed SeString.</returns>
|
|
||||||
SeString GetFieldAsSeString(NamePlateStringField field);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the string array value for the provided field.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field to write to.</param>
|
|
||||||
/// <param name="value">The string to write.</param>
|
|
||||||
void SetField(NamePlateStringField field, string value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the string array value for the provided field.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field to write to.</param>
|
|
||||||
/// <param name="value">The SeString to write.</param>
|
|
||||||
void SetField(NamePlateStringField field, SeString value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the string array value for the provided field.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field to write to.</param>
|
|
||||||
/// <param name="value">The ReadOnlySpan of bytes to write.</param>
|
|
||||||
void SetField(NamePlateStringField field, ReadOnlySpan<byte> value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the string array value for the provided field.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field to write to.</param>
|
|
||||||
/// <param name="value">The pointer to a null-terminated sequence of bytes to write.</param>
|
|
||||||
unsafe void SetField(NamePlateStringField field, byte* value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field to write to.</param>
|
|
||||||
void RemoveField(NamePlateStringField field);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
internal unsafe class NamePlateUpdateHandler : INamePlateUpdateHandler
|
|
||||||
{
|
|
||||||
private readonly NamePlateUpdateContext context;
|
|
||||||
|
|
||||||
private ulong? gameObjectId;
|
|
||||||
private IGameObject? gameObject;
|
|
||||||
private NamePlateInfoView? infoView;
|
|
||||||
private NamePlatePartsContainer? partsContainer;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="NamePlateUpdateHandler"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The current update context.</param>
|
|
||||||
/// <param name="arrayIndex">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 <see cref="NamePlateIndex"/>.</param>
|
|
||||||
internal NamePlateUpdateHandler(NamePlateUpdateContext context, int arrayIndex)
|
|
||||||
{
|
|
||||||
this.context = context;
|
|
||||||
this.ArrayIndex = arrayIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int ArrayIndex { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public ulong GameObjectId => this.gameObjectId ??= this.NamePlateInfo->ObjectId;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public IGameObject? GameObject => this.gameObject ??= this.context.ObjectTable.CreateObjectReference(
|
|
||||||
(nint)this.context.Ui3DModule->NamePlateObjectInfoPointers[
|
|
||||||
this.ArrayIndex].Value->GameObject);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public IBattleChara? BattleChara => this.GameObject as IBattleChara;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public IPlayerCharacter? PlayerCharacter => this.GameObject as IPlayerCharacter;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public INamePlateInfoView InfoView => this.infoView ??= new NamePlateInfoView(this.NamePlateInfo);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public nint NamePlateInfoAddress => (nint)this.NamePlateInfo;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public nint NamePlateObjectAddress => (nint)this.NamePlateObject;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public NamePlateKind NamePlateKind => (NamePlateKind)this.ObjectData->NamePlateKind;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int UpdateFlags
|
|
||||||
{
|
|
||||||
get => this.ObjectData->UpdateFlags;
|
|
||||||
private set => this.ObjectData->UpdateFlags = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public uint TextColor
|
|
||||||
{
|
|
||||||
get => this.ObjectData->NameTextColor;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value != this.TextColor) this.UpdateFlags |= 2;
|
|
||||||
this.ObjectData->NameTextColor = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public uint EdgeColor
|
|
||||||
{
|
|
||||||
get => this.ObjectData->NameEdgeColor;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value != this.EdgeColor) this.UpdateFlags |= 2;
|
|
||||||
this.ObjectData->NameEdgeColor = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int MarkerIconId
|
|
||||||
{
|
|
||||||
get => this.ObjectData->MarkerIconId;
|
|
||||||
set => this.ObjectData->MarkerIconId = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int NameIconId
|
|
||||||
{
|
|
||||||
get => this.ObjectData->NameIconId;
|
|
||||||
set => this.ObjectData->NameIconId = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int NamePlateIndex => this.ObjectData->NamePlateObjectIndex;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int DrawFlags
|
|
||||||
{
|
|
||||||
get => this.ObjectData->DrawFlags;
|
|
||||||
private set => this.ObjectData->DrawFlags = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int VisibilityFlags
|
|
||||||
{
|
|
||||||
get => ObjectData->VisibilityFlags;
|
|
||||||
set => ObjectData->VisibilityFlags = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool IsUpdating => (this.UpdateFlags & 1) != 0;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool IsPrefixTitle
|
|
||||||
{
|
|
||||||
get => (this.DrawFlags & 1) != 0;
|
|
||||||
set => this.DrawFlags = value ? this.DrawFlags | 1 : this.DrawFlags & ~1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool DisplayTitle
|
|
||||||
{
|
|
||||||
get => (this.DrawFlags & 0x80) == 0;
|
|
||||||
set => this.DrawFlags = value ? this.DrawFlags & ~0x80 : this.DrawFlags | 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString Name
|
|
||||||
{
|
|
||||||
get => this.GetFieldAsSeString(NamePlateStringField.Name);
|
|
||||||
set => this.WeakSetField(NamePlateStringField.Name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public NamePlateSimpleParts NameParts => this.PartsContainer.Name;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString Title
|
|
||||||
{
|
|
||||||
get => this.GetFieldAsSeString(NamePlateStringField.Title);
|
|
||||||
set => this.WeakSetField(NamePlateStringField.Title, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public NamePlateQuotedParts TitleParts => this.PartsContainer.Title;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString FreeCompanyTag
|
|
||||||
{
|
|
||||||
get => this.GetFieldAsSeString(NamePlateStringField.FreeCompanyTag);
|
|
||||||
set => this.WeakSetField(NamePlateStringField.FreeCompanyTag, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public NamePlateQuotedParts FreeCompanyTagParts => this.PartsContainer.FreeCompanyTag;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString StatusPrefix
|
|
||||||
{
|
|
||||||
get => this.GetFieldAsSeString(NamePlateStringField.StatusPrefix);
|
|
||||||
set => this.WeakSetField(NamePlateStringField.StatusPrefix, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString TargetSuffix
|
|
||||||
{
|
|
||||||
get => this.GetFieldAsSeString(NamePlateStringField.TargetSuffix);
|
|
||||||
set => this.WeakSetField(NamePlateStringField.TargetSuffix, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public SeString LevelPrefix
|
|
||||||
{
|
|
||||||
get => this.GetFieldAsSeString(NamePlateStringField.LevelPrefix);
|
|
||||||
set => this.WeakSetField(NamePlateStringField.LevelPrefix, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or (lazily) creates a part builder container for this nameplate.
|
|
||||||
/// </summary>
|
|
||||||
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);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void RemoveName() => this.RemoveField(NamePlateStringField.Name);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void RemoveTitle() => this.RemoveField(NamePlateStringField.Title);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void RemoveFreeCompanyTag() => this.RemoveField(NamePlateStringField.FreeCompanyTag);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void RemoveStatusPrefix() => this.RemoveField(NamePlateStringField.StatusPrefix);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void RemoveTargetSuffix() => this.RemoveField(NamePlateStringField.TargetSuffix);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void RemoveLevelPrefix() => this.RemoveField(NamePlateStringField.LevelPrefix);
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public byte* GetFieldAsPointer(NamePlateStringField field)
|
|
||||||
{
|
|
||||||
return this.context.StringData->StringArray[this.ArrayIndex + (int)field];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public ReadOnlySpan<byte> GetFieldAsSpan(NamePlateStringField field)
|
|
||||||
{
|
|
||||||
return MemoryMarshal.CreateReadOnlySpanFromNullTerminated(this.GetFieldAsPointer(field));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public string GetFieldAsString(NamePlateStringField field)
|
|
||||||
{
|
|
||||||
return Encoding.UTF8.GetString(this.GetFieldAsSpan(field));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public SeString GetFieldAsSeString(NamePlateStringField field)
|
|
||||||
{
|
|
||||||
return SeString.Parse(this.GetFieldAsSpan(field));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void SetField(NamePlateStringField field, string value)
|
|
||||||
{
|
|
||||||
this.context.StringData->SetValue(this.ArrayIndex + (int)field, value, true, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void SetField(NamePlateStringField field, SeString value)
|
|
||||||
{
|
|
||||||
this.context.StringData->SetValue(this.ArrayIndex + (int)field, value.Encode(), true, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void SetField(NamePlateStringField field, ReadOnlySpan<byte> value)
|
|
||||||
{
|
|
||||||
this.context.StringData->SetValue(this.ArrayIndex + (int)field, value, true, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void SetField(NamePlateStringField field, byte* value)
|
|
||||||
{
|
|
||||||
this.context.StringData->SetValue(this.ArrayIndex + (int)field, value, true, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void RemoveField(NamePlateStringField field)
|
|
||||||
{
|
|
||||||
this.context.StringData->SetValue(
|
|
||||||
this.ArrayIndex + (int)field,
|
|
||||||
(byte*)NamePlateGui.EmptyStringPointer,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets the state of this handler for re-use in a new update.
|
|
||||||
/// </summary>
|
|
||||||
internal void ResetState()
|
|
||||||
{
|
|
||||||
this.gameObjectId = null;
|
|
||||||
this.gameObject = null;
|
|
||||||
this.infoView = null;
|
|
||||||
this.partsContainer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="field">The field to write to.</param>
|
|
||||||
/// <param name="value">The SeString to write.</param>
|
|
||||||
[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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +1,33 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Dalamud.NET.Sdk/13.0.0">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0-windows</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>annotations</Nullable>
|
<Nullable>annotations</Nullable>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
|
||||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
|
||||||
<Platforms>x64</Platforms>
|
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
|
<Use_DalamudPackager>false</Use_DalamudPackager>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<Copyright>Pilzinsel64</Copyright>
|
||||||
</PropertyGroup>
|
<PackageProjectUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</PackageProjectUrl>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
<RepositoryUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</RepositoryUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<Version>1.0.3</Version>
|
||||||
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
</PropertyGroup>
|
||||||
<Copyright>Pilzinsel64</Copyright>
|
|
||||||
<PackageProjectUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</PackageProjectUrl>
|
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
|
||||||
<RepositoryUrl>https://github.com/Pilzinsel64/Pilz.Dalamud</RepositoryUrl>
|
|
||||||
<RepositoryType>git</RepositoryType>
|
|
||||||
<Version>0.6.1.1</Version>
|
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<NoWarn>1701;1702;1591</NoWarn>
|
<NoWarn>1701;1702;1591</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemGroup>
|
||||||
<NoWarn>1701;1702;1591</NoWarn>
|
<None Include="..\README.md" Pack="true" PackagePath="\" />
|
||||||
</PropertyGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="FFXIVClientStructs">
|
|
||||||
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Newtonsoft.Json">
|
|
||||||
<HintPath>$(DalamudLibPath)Newtonsoft.Json.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Dalamud">
|
|
||||||
<HintPath>$(DalamudLibPath)Dalamud.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="ImGui.NET">
|
|
||||||
<HintPath>$(DalamudLibPath)ImGui.NET.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="ImGuiScene">
|
|
||||||
<HintPath>$(DalamudLibPath)ImGuiScene.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Lumina">
|
|
||||||
<HintPath>$(DalamudLibPath)Lumina.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Lumina.Excel">
|
|
||||||
<HintPath>$(DalamudLibPath)Lumina.Excel.dll</HintPath>
|
|
||||||
<Private>false</Private>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="..\README.md" Pack="true" PackagePath="\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Pilz.Dalamud.NamePlate;
|
using Dalamud.Game.Gui.NamePlate;
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Tools.NamePlates;
|
namespace Pilz.Dalamud.Tools.NamePlates;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Gui.NamePlate;
|
||||||
using Pilz.Dalamud.NamePlate;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using Pilz.Dalamud.Tools.Strings;
|
using Pilz.Dalamud.Tools.Strings;
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Tools.NamePlates;
|
namespace Pilz.Dalamud.Tools.NamePlates;
|
||||||
|
|||||||
@@ -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 Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
using Pilz.Dalamud.ActivityContexts;
|
using Pilz.Dalamud.ActivityContexts;
|
||||||
using Pilz.Dalamud.Icons;
|
using Pilz.Dalamud.Icons;
|
||||||
using Pilz.Dalamud.NamePlate;
|
|
||||||
|
|
||||||
namespace Pilz.Dalamud.Tools.NamePlates;
|
namespace Pilz.Dalamud.Tools.NamePlates;
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ public static class NameplateUpdateFactory
|
|||||||
if (handler.StatusPrefix is SeString str)
|
if (handler.StatusPrefix is SeString str)
|
||||||
str.Payloads.Insert(0, icon);
|
str.Payloads.Insert(0, icon);
|
||||||
else
|
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
|
// If we moved it, we don't need it as icon anymore, yay :D
|
||||||
isPrio = false;
|
isPrio = false;
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"net8.0-windows7.0": {}
|
"net9.0-windows7.0": {
|
||||||
|
"DotNet.ReproducibleBuilds": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.2.25, )",
|
||||||
|
"resolved": "1.2.25",
|
||||||
|
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
12
README.md
12
README.md
@@ -9,7 +9,7 @@ Install the latest version of `Pilz.Dalamud` via NuGet Package Manager or NuGet
|
|||||||
https://www.nuget.org/packages/Pilz.Dalamud
|
https://www.nuget.org/packages/Pilz.Dalamud
|
||||||
|
|
||||||
Or add the alternative package source for slightly quicker updates:\
|
Or add the alternative package source for slightly quicker updates:\
|
||||||
`<add key="Pilz.Dalamud" value="https://git.pilzinsel64.de/api/v4/projects/8/packages/nuget/index.json" />`\
|
`<add key="Pilz" value="https://git.pilzinsel64.de/api/packages/Pilz.NET/nuget/index.json" />`\
|
||||||
|
|
||||||
## Get started
|
## Get started
|
||||||
|
|
||||||
@@ -30,15 +30,7 @@ public Plugin(DalamudPluginInterface pluginInterface)
|
|||||||
|
|
||||||
### Hook into NamePlates
|
### Hook into NamePlates
|
||||||
|
|
||||||
Nameplates has been reworked by @nebel and will be part of core Dalamud soon.
|
__**DEPRICATED!** Use the ``INameplate`` service wich is now implemented [within Dalamud](https://github.com/goatcorp/Dalamud/pull/1915). The old Nameplate Addon and the new temporary Nameplate service has been removed since v0.7.0 of this library.__
|
||||||
|
|
||||||
Read more at: https://github.com/goatcorp/Dalamud/pull/1915
|
|
||||||
|
|
||||||
Use the new service already now via Pilz.Dalamud:
|
|
||||||
|
|
||||||
```cs
|
|
||||||
var namePlateGui = Pilz.Dalamud.NamePlate.INamePlateGui.Instance;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
set sourceP="https://git.pilzinsel64.de/api/v4/projects/25/packages/nuget/index.json"
|
set sourceP="https://git.pilzinsel64.de/api/packages/Pilz.NET/nuget/index.json"
|
||||||
set apikeyP=%GitLab_git_pilzinsel64_de%
|
set apikeyP=%Gitea_git_pilzinsel64_de%
|
||||||
|
|
||||||
set sourceN="https://api.nuget.org/v3/index.json"
|
set sourceN="https://api.nuget.org/v3/index.json"
|
||||||
set apikeyN=%NuGet_ApiKey%
|
set apikeyN=%NuGet_ApiKey%
|
||||||
13
deploy-nugets.sh
Normal file
13
deploy-nugets.sh
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
sourceP="https://git.pilzinsel64.de/api/packages/Pilz.NET/nuget/index.json"
|
||||||
|
apikeyP="$Gitea_git_pilzinsel64_de"
|
||||||
|
|
||||||
|
sourceN="https://api.nuget.org/v3/index.json"
|
||||||
|
apikeyN="$NuGet_ApiKey"
|
||||||
|
|
||||||
|
for pkg in "$@"; do
|
||||||
|
dotnet nuget push "$pkg" --source "$sourceP" --api-key "$apikeyP" --skip-duplicate
|
||||||
|
dotnet nuget push "$pkg" --source "$sourceN" --api-key "$apikeyN" --skip-duplicate
|
||||||
|
done
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"dependencies": {
|
|
||||||
"net7.0-windows7.0": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user