using Dalamud.Hooking; using Dalamud.Plugin.Services; using Dalamud.Utility.Signatures; using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; using Microsoft.Extensions.Logging; namespace LightlessSync.Services; public unsafe sealed class NameplateUpdateHookService : IDisposable { private delegate nint UpdateNameplateDelegate(RaptureAtkModule* raptureAtkModule, RaptureAtkModule.NamePlateInfo* namePlateInfo, NumberArrayData* numArray, StringArrayData* stringArray, BattleChara* battleChara, int numArrayIndex, int stringArrayIndex); public delegate void NameplateUpdatedHandler(RaptureAtkModule* raptureAtkModule, RaptureAtkModule.NamePlateInfo* namePlateInfo, NumberArrayData* numArray, StringArrayData* stringArray, BattleChara* battleChara, int numArrayIndex, int stringArrayIndex); // Glyceri, Thanks :bow: [Signature("40 53 55 57 41 56 48 81 EC ?? ?? ?? ?? 48 8B 84 24", DetourName = nameof(UpdateNameplateDetour))] private readonly Hook? _nameplateHook = null; private readonly ILogger _logger; public NameplateUpdateHookService(ILogger logger, IGameInteropProvider interop) { _logger = logger; interop.InitializeFromAttributes(this); _nameplateHook?.Enable(); } public event NameplateUpdatedHandler? NameplateUpdated; /// /// Detour for the game's internal nameplate update function. /// This will be called whenever the client updates any nameplate. /// private nint UpdateNameplateDetour(RaptureAtkModule* raptureAtkModule, RaptureAtkModule.NamePlateInfo* namePlateInfo, NumberArrayData* numArray, StringArrayData* stringArray, BattleChara* battleChara, int numArrayIndex, int stringArrayIndex) { try { NameplateUpdated?.Invoke(raptureAtkModule, namePlateInfo, numArray, stringArray, battleChara, numArrayIndex, stringArrayIndex); } catch (Exception e) { _logger.LogError(e, "Error in NameplateUpdateHookService UpdateNameplateDetour"); } return _nameplateHook!.Original(raptureAtkModule, namePlateInfo, numArray, stringArray, battleChara, numArrayIndex, stringArrayIndex); } public void Dispose() { _nameplateHook?.Dispose(); } }