Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dawntrail update #49

Merged
merged 9 commits into from
Jul 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions FCNameColor/API/FCNameColorProvider.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using Dalamud.Logging;
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
using Dalamud.Plugin.Services;

namespace FCNameColor
{
Expand All @@ -24,7 +24,7 @@ public class FCNameColorProvider
private readonly ICallGateProvider<string, string, object> providerAddPlayerToIgnoredPlayers;
private readonly ICallGateProvider<string, object> providerRemovePlayerFromIgnoredPlayers;

public FCNameColorProvider(DalamudPluginInterface pluginInterface, IFCNameColorAPI api)
public FCNameColorProvider(IDalamudPluginInterface pluginInterface, IFCNameColorAPI api, IPluginLog pluginLog)
{
try
{
Expand Down Expand Up @@ -57,7 +57,7 @@ public FCNameColorProvider(DalamudPluginInterface pluginInterface, IFCNameColorA
}
catch (Exception ex)
{
PluginLog.LogError($"Error registering IPC provider:\n{ex}");
pluginLog.Error($"Error registering IPC provider:\n{ex}");
}
}

Expand Down
4 changes: 2 additions & 2 deletions FCNameColor/Config/ConfigurationMigrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ namespace FCNameColor.Config
{
public class ConfigurationMigrator
{
private DalamudPluginInterface pi;
private IDalamudPluginInterface pi;
private IPluginLog pluginLog;
private IChatGui chat;

public ConfigurationV1 GetConfig(DalamudPluginInterface pi, IPluginLog pluginLog, IChatGui chat)
public ConfigurationV1 GetConfig(IDalamudPluginInterface pi, IPluginLog pluginLog, IChatGui chat)
{
this.pi = pi;
this.pluginLog = pluginLog;
Expand Down
4 changes: 2 additions & 2 deletions FCNameColor/Config/ConfigurationV1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public class ConfigurationV1 : IPluginConfiguration
public Dictionary<string, FC> FCs { get; set; } = new();
#endregion

[NonSerialized] private DalamudPluginInterface pluginInterface;
[NonSerialized] private IDalamudPluginInterface pluginInterface;
[NonSerialized]
public static KeyValuePair<string, Group>[] DefaultGroups =
{
Expand All @@ -100,7 +100,7 @@ public class ConfigurationV1 : IPluginConfiguration
})
};

public void Initialize(DalamudPluginInterface pluginInterface)
public void Initialize(IDalamudPluginInterface pluginInterface)
{
this.pluginInterface = pluginInterface;
}
Expand Down
15 changes: 7 additions & 8 deletions FCNameColor/FCNameColor.csproj
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{13C812E9-0D42-4B95-8646-40EEBF30636F}</ProjectGuid>
<TargetFramework>net7.0-windows</TargetFramework>
<LangVersion>9.0</LangVersion>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<LangVersion>12.0</LangVersion>
<AssemblyTitle>FCNameColor</AssemblyTitle>
<Product>FCNameColor</Product>
<Copyright>Copyright © 2023</Copyright>
<AssemblyVersion>4.0.0.3</AssemblyVersion>
<FileVersion>4.0.0.3</FileVersion>
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<FileVersion>5.0.0.0</FileVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputPath>bin\$(Configuration)\</OutputPath>
<PreserveCompilationContext>false</PreserveCompilationContext>
Expand All @@ -17,11 +17,11 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<LangVersion>10.0</LangVersion>
<LangVersion>12.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<LangVersion>10.0</LangVersion>
<LangVersion>12.0</LangVersion>
</PropertyGroup>
<PropertyGroup>
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
Expand All @@ -30,8 +30,7 @@
<DalamudLibPath>$(DALAMUD_HOME)/</DalamudLibPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DalamudPackager" Version="2.1.12" />
<PackageReference Include="Pilz.Dalamud" Version="0.5.2.1" />
<PackageReference Include="DalamudPackager" Version="2.1.13" />
<Reference Include="FFXIVClientStructs">
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
<Private>false</Private>
Expand Down
2 changes: 1 addition & 1 deletion FCNameColor/FCNameColor.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"CategoryTags": ["ui", "social"],
"Description": "Color your FC’s tag or the entire nameplate if they are in your FC or other specified FCs.\nWorks using Lodestone data, so it can continue working inside duties as well as on different servers!",
"InternalName": "FCNameColor",
"AssemblyVersion": "4.0.0.3",
"AssemblyVersion": "5.0.0.0",
"RepoUrl": "https://github.com/WesselKuipers/FCNameColor",
"IconUrl": "https://github.com/WesselKuipers/FCNameColor/raw/main/images/icon.png",
"Tags": ["nameplate", "FC", "name", "colors"],
Expand Down
35 changes: 35 additions & 0 deletions FCNameColor/NamePlates/INamePlateGui.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Collections.Generic;

namespace FCNameColor.Nameplates;

/// <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>
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. This event is likely to fire every frame even when no nameplates are actually updated, so in most
/// cases <see cref="OnNamePlateUpdate"/> is preferred.
/// </summary>
event OnPlateUpdateDelegate? OnDataUpdate;

/// <summary>
/// Requests that all nameplates should be redrawn on the following frame.
/// </summary>
void RequestRedraw();
}
196 changes: 196 additions & 0 deletions FCNameColor/NamePlates/NamePlateGui.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Dalamud.Game.Addon.Lifecycle;
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
using FFXIVClientStructs.FFXIV.Client.UI;

namespace FCNameColor.Nameplates;

/// <summary>
/// Class used to modify the data used when rendering nameplates.
/// </summary>
internal sealed class NamePlateGui : 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 NamePlateUpdateContext? context;

private NamePlateUpdateHandler[] updateHandlers = [];

public NamePlateGui()
{
Plugin.AddonLifecycleHandler.RegisterListener(AddonEvent.PreRequestedUpdate, "NamePlate", OnPreRequestedUpdate);
}

public void Dispose()
{
Plugin.AddonLifecycleHandler.UnregisterListener(AddonEvent.PreRequestedUpdate, "NamePlate", OnPreRequestedUpdate);
}

/// <inheritdoc/>
public event INamePlateGui.OnPlateUpdateDelegate? OnNamePlateUpdate;

/// <inheritdoc/>
public event INamePlateGui.OnPlateUpdateDelegate? OnDataUpdate;

/// <inheritdoc/>
public unsafe void RequestRedraw()
{
var addon = Plugin.GameGuiHandler.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);
}
}

/// <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(Plugin.Objects, 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);
}
}
}
}
Loading