From b6aa2bebb18a6bfb3cd882b962b7c1d1a0a34c0d Mon Sep 17 00:00:00 2001 From: cake Date: Mon, 3 Nov 2025 19:59:12 +0100 Subject: [PATCH 1/4] Added more checks. --- LightlessSync/Services/NameplateHandler.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/LightlessSync/Services/NameplateHandler.cs b/LightlessSync/Services/NameplateHandler.cs index a28be5f..e302934 100644 --- a/LightlessSync/Services/NameplateHandler.cs +++ b/LightlessSync/Services/NameplateHandler.cs @@ -571,6 +571,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber var nameplateObject = GetNameplateObject(i); return nameplateObject != null ? nameplateObject.Value.RootComponentNode : null; } + private HashSet VisibleUserIds => [.. _pairManager.GetOnlineUserPairs() .Where(u => u.IsVisible && u.PlayerCharacterId != uint.MaxValue) .Select(u => (ulong)u.PlayerCharacterId)]; From 1b686e45dc75dc485bce3d81c6d745e76115103c Mon Sep 17 00:00:00 2001 From: cake Date: Mon, 3 Nov 2025 20:19:02 +0100 Subject: [PATCH 2/4] Added more null checks and redid active broadcasting cache. --- LightlessSync/Services/NameplateHandler.cs | 146 +++++++++++---------- 1 file changed, 79 insertions(+), 67 deletions(-) diff --git a/LightlessSync/Services/NameplateHandler.cs b/LightlessSync/Services/NameplateHandler.cs index e302934..185a81d 100644 --- a/LightlessSync/Services/NameplateHandler.cs +++ b/LightlessSync/Services/NameplateHandler.cs @@ -15,8 +15,8 @@ using LightlessSync.UtilsEnum.Enum; // Created using https://github.com/PunishedPineapple/Distance as a reference, thank you! using Microsoft.Extensions.Logging; +using System.Collections.Immutable; using System.Globalization; -using System.Text; namespace LightlessSync.Services; @@ -32,10 +32,10 @@ public unsafe class NameplateHandler : IMediatorSubscriber private readonly LightlessMediator _mediator; public LightlessMediator Mediator => _mediator; - private bool mEnabled = false; + private bool _mEnabled = false; private bool _needsLabelRefresh = false; - private AddonNamePlate* mpNameplateAddon = null; - private readonly AtkTextNode*[] mTextNodes = new AtkTextNode*[AddonNamePlate.NumNamePlateObjects]; + private AddonNamePlate* _mpNameplateAddon = null; + private readonly AtkTextNode*[] _mTextNodes = new AtkTextNode*[AddonNamePlate.NumNamePlateObjects]; private readonly int[] _cachedNameplateTextWidths = new int[AddonNamePlate.NumNamePlateObjects]; private readonly int[] _cachedNameplateTextHeights = new int[AddonNamePlate.NumNamePlateObjects]; private readonly int[] _cachedNameplateContainerHeights = new int[AddonNamePlate.NumNamePlateObjects]; @@ -44,10 +44,10 @@ public unsafe class NameplateHandler : IMediatorSubscriber internal const uint mNameplateNodeIDBase = 0x7D99D500; private const string DefaultLabelText = "LightFinder"; private const SeIconChar DefaultIcon = SeIconChar.Hyadelyn; - private const int ContainerOffsetX = 50; + private const int _containerOffsetX = 50; private static readonly string DefaultIconGlyph = SeIconCharExtensions.ToIconString(DefaultIcon); - private volatile HashSet _activeBroadcastingCids = []; + private ImmutableHashSet _activeBroadcastingCids = []; public NameplateHandler(ILogger logger, IAddonLifecycle addonLifecycle, IGameGui gameGui, DalamudUtilService dalamudUtil, LightlessConfigService configService, LightlessMediator mediator, IClientState clientState, PairManager pairManager) { @@ -74,17 +74,17 @@ public unsafe class NameplateHandler : IMediatorSubscriber DisableNameplate(); DestroyNameplateNodes(); _mediator.Unsubscribe(this); - mpNameplateAddon = null; + _mpNameplateAddon = null; } internal void EnableNameplate() { - if (!mEnabled) + if (!_mEnabled) { try { _addonLifecycle.RegisterListener(AddonEvent.PostDraw, "NamePlate", NameplateDrawDetour); - mEnabled = true; + _mEnabled = true; } catch (Exception e) { @@ -96,7 +96,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber internal void DisableNameplate() { - if (mEnabled) + if (_mEnabled) { try { @@ -107,7 +107,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber _logger.LogError($"Unknown error while unregistering nameplate listener:\n{e}"); } - mEnabled = false; + _mEnabled = false; HideAllNameplateNodes(); } } @@ -116,15 +116,15 @@ public unsafe class NameplateHandler : IMediatorSubscriber { var pNameplateAddon = (AddonNamePlate*)args.Addon.Address; - if (mpNameplateAddon != pNameplateAddon) + if (_mpNameplateAddon != pNameplateAddon) { - for (int i = 0; i < mTextNodes.Length; ++i) mTextNodes[i] = null; + for (int i = 0; i < _mTextNodes.Length; ++i) _mTextNodes[i] = null; System.Array.Clear(_cachedNameplateTextWidths, 0, _cachedNameplateTextWidths.Length); System.Array.Clear(_cachedNameplateTextHeights, 0, _cachedNameplateTextHeights.Length); System.Array.Clear(_cachedNameplateContainerHeights, 0, _cachedNameplateContainerHeights.Length); System.Array.Fill(_cachedNameplateTextOffsets, int.MinValue); - mpNameplateAddon = pNameplateAddon; - if (mpNameplateAddon != null) CreateNameplateNodes(); + _mpNameplateAddon = pNameplateAddon; + if (_mpNameplateAddon != null) CreateNameplateNodes(); } UpdateNameplateNodes(); @@ -139,6 +139,11 @@ public unsafe class NameplateHandler : IMediatorSubscriber continue; var pNameplateResNode = nameplateObject.Value.NameContainer; + if (pNameplateResNode == null) + continue; + if (pNameplateResNode->ChildNode == null) + continue; + var pNewNode = AtkNodeHelpers.CreateOrphanTextNode(mNameplateNodeIDBase + (uint)i, TextFlags.Edge | TextFlags.Glare); if (pNewNode != null) @@ -150,7 +155,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber pLastChild->PrevSiblingNode = (AtkResNode*)pNewNode; nameplateObject.Value.RootComponentNode->Component->UldManager.UpdateDrawNodeList(); pNewNode->AtkResNode.SetUseDepthBasedPriority(true); - mTextNodes[i] = pNewNode; + _mTextNodes[i] = pNewNode; } } } @@ -158,12 +163,12 @@ public unsafe class NameplateHandler : IMediatorSubscriber private void DestroyNameplateNodes() { var pCurrentNameplateAddon = (AddonNamePlate*)_gameGui.GetAddonByName("NamePlate", 1).Address; - if (mpNameplateAddon == null || mpNameplateAddon != pCurrentNameplateAddon) + if (_mpNameplateAddon == null || _mpNameplateAddon != pCurrentNameplateAddon) return; for (int i = 0; i < AddonNamePlate.NumNamePlateObjects; ++i) { - var pTextNode = mTextNodes[i]; + var pTextNode = _mTextNodes[i]; var pNameplateNode = GetNameplateComponentNode(i); if (pTextNode != null && pNameplateNode != null) { @@ -175,7 +180,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber pTextNode->AtkResNode.NextSiblingNode->PrevSiblingNode = pTextNode->AtkResNode.PrevSiblingNode; pNameplateNode->Component->UldManager.UpdateDrawNodeList(); pTextNode->AtkResNode.Destroy(true); - mTextNodes[i] = null; + _mTextNodes[i] = null; } catch (Exception e) { @@ -192,7 +197,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber private void HideAllNameplateNodes() { - for (int i = 0; i < mTextNodes.Length; ++i) + for (int i = 0; i < _mTextNodes.Length; ++i) { HideNameplateTextNode(i); } @@ -200,22 +205,34 @@ public unsafe class NameplateHandler : IMediatorSubscriber private void UpdateNameplateNodes() { - var framework = Framework.Instance(); - var ui3DModule = framework->GetUIModule()->GetUI3DModule(); + var currentAddon = (AddonNamePlate*)_gameGui.GetAddonByName("NamePlate", 1).Address; + if (_mpNameplateAddon == null || currentAddon == null || currentAddon != _mpNameplateAddon) + return; + var framework = Framework.Instance(); + + var ui3DModule = framework->GetUIModule()->GetUI3DModule(); if (ui3DModule == null) return; - for (int i = 0; i < ui3DModule->NamePlateObjectInfoCount; ++i) + var vec = ui3DModule->NamePlateObjectInfoPointers; + if (vec.IsEmpty) + return; + + var safeCount = System.Math.Min( + ui3DModule->NamePlateObjectInfoCount, + vec.Length + ); + + for (int i = 0; i < safeCount; ++i) { - if (ui3DModule->NamePlateObjectInfoPointers.IsEmpty) continue; + var config = _configService.Current; - var objectInfoPtr = ui3DModule->NamePlateObjectInfoPointers[i]; - - if (objectInfoPtr == null) continue; + var objectInfoPtr = vec[i]; + if (objectInfoPtr == null) + continue; var objectInfo = objectInfoPtr.Value; - if (objectInfo == null || objectInfo->GameObject == null) continue; @@ -223,62 +240,61 @@ public unsafe class NameplateHandler : IMediatorSubscriber if (nameplateIndex < 0 || nameplateIndex >= AddonNamePlate.NumNamePlateObjects) continue; - var pNode = mTextNodes[nameplateIndex]; + var pNode = _mTextNodes[nameplateIndex]; if (pNode == null) continue; - if (mpNameplateAddon == null) - continue; - + // CID gating var cid = DalamudUtilService.GetHashedCIDFromPlayerPointer((nint)objectInfo->GameObject); - if (cid == null || !_activeBroadcastingCids.Contains(cid)) { pNode->AtkResNode.ToggleVisibility(false); continue; } - if (!_configService.Current.LightfinderLabelShowOwn && (objectInfo->GameObject->GetGameObjectId() == _clientState.LocalPlayer.GameObjectId)) + var local = _clientState.LocalPlayer; + if (!config.LightfinderLabelShowOwn && local != null && + objectInfo->GameObject->GetGameObjectId() == local.GameObjectId) { pNode->AtkResNode.ToggleVisibility(false); continue; } - if (!_configService.Current.LightfinderLabelShowPaired && VisibleUserIds.Any(u => u == objectInfo->GameObject->GetGameObjectId())) - { - pNode->AtkResNode.ToggleVisibility(false); - continue; - } - - var nameplateObject = mpNameplateAddon->NamePlateObjectArray[nameplateIndex]; - nameplateObject.RootComponentNode->Component->UldManager.UpdateDrawNodeList(); - - var pNameplateIconNode = nameplateObject.MarkerIcon; - var pNameplateResNode = nameplateObject.NameContainer; - var pNameplateTextNode = nameplateObject.NameText; - bool IsVisible = pNameplateIconNode->AtkResNode.IsVisible() || (pNameplateResNode->IsVisible() && pNameplateTextNode->AtkResNode.IsVisible()) || _configService.Current.LightfinderLabelShowHidden; - pNode->AtkResNode.ToggleVisibility(IsVisible); - - if (nameplateObject.RootComponentNode == null || - nameplateObject.NameContainer == null || - nameplateObject.NameText == null) + var visibleUserIds = VisibleUserIds; + var hidePaired = !config.LightfinderLabelShowPaired; + + var goId = (ulong)objectInfo->GameObject->GetGameObjectId(); + if (hidePaired && visibleUserIds.Contains(goId)) { pNode->AtkResNode.ToggleVisibility(false); continue; } + var nameplateObject = _mpNameplateAddon->NamePlateObjectArray[nameplateIndex]; + var root = nameplateObject.RootComponentNode; var nameContainer = nameplateObject.NameContainer; var nameText = nameplateObject.NameText; + var marker = nameplateObject.MarkerIcon; - if (nameContainer == null || nameText == null) + if (root == null || nameContainer == null || nameText == null) { pNode->AtkResNode.ToggleVisibility(false); continue; } + + root->Component->UldManager.UpdateDrawNodeList(); + + bool isVisible = + ((marker != null) && marker->AtkResNode.IsVisible()) || + (nameContainer->IsVisible() && nameText->AtkResNode.IsVisible()) || + config.LightfinderLabelShowHidden; + + pNode->AtkResNode.ToggleVisibility(isVisible); + if (!isVisible) + continue; var labelColor = UIColors.Get("Lightfinder"); var edgeColor = UIColors.Get("LightfinderEdge"); - var config = _configService.Current; var scaleMultiplier = System.Math.Clamp(config.LightfinderLabelScale, 0.5f, 2.0f); var baseScale = config.LightfinderLabelUseIcon ? 1.0f : 0.5f; @@ -545,7 +561,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber } private void HideNameplateTextNode(int i) { - var pNode = mTextNodes[i]; + var pNode = _mTextNodes[i]; if (pNode != null) { pNode->AtkResNode.ToggleVisibility(false); @@ -555,10 +571,10 @@ public unsafe class NameplateHandler : IMediatorSubscriber private AddonNamePlate.NamePlateObject? GetNameplateObject(int i) { if (i < AddonNamePlate.NumNamePlateObjects && - mpNameplateAddon != null && - mpNameplateAddon->NamePlateObjectArray[i].RootComponentNode != null) + _mpNameplateAddon != null && + _mpNameplateAddon->NamePlateObjectArray[i].RootComponentNode != null) { - return mpNameplateAddon->NamePlateObjectArray[i]; + return _mpNameplateAddon->NamePlateObjectArray[i]; } else { @@ -576,6 +592,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber .Where(u => u.IsVisible && u.PlayerCharacterId != uint.MaxValue) .Select(u => (ulong)u.PlayerCharacterId)]; + public void FlagRefresh() { _needsLabelRefresh = true; @@ -592,18 +609,13 @@ public unsafe class NameplateHandler : IMediatorSubscriber public void UpdateBroadcastingCids(IEnumerable cids) { - var newSet = cids.ToHashSet(); - - var changed = !_activeBroadcastingCids.SetEquals(newSet); - if (!changed) + var newSet = cids.ToImmutableHashSet(StringComparer.Ordinal); + if (ReferenceEquals(_activeBroadcastingCids, newSet) || _activeBroadcastingCids.SetEquals(newSet)) return; - _activeBroadcastingCids.Clear(); - foreach (var cid in newSet) - _activeBroadcastingCids.Add(cid); - + // single atomic swap – readers always see a consistent snapshot + _activeBroadcastingCids = newSet; _logger.LogInformation("Active broadcast CIDs: {Cids}", string.Join(",", _activeBroadcastingCids)); - FlagRefresh(); } From 35636f27f6b8b38e6864b6f8d4a6e8e09a857680 Mon Sep 17 00:00:00 2001 From: cake Date: Mon, 3 Nov 2025 21:47:15 +0100 Subject: [PATCH 3/4] Cleanup --- LightlessSync/Services/NameplateHandler.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/LightlessSync/Services/NameplateHandler.cs b/LightlessSync/Services/NameplateHandler.cs index 185a81d..5e83683 100644 --- a/LightlessSync/Services/NameplateHandler.cs +++ b/LightlessSync/Services/NameplateHandler.cs @@ -205,7 +205,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber private void UpdateNameplateNodes() { - var currentAddon = (AddonNamePlate*)_gameGui.GetAddonByName("NamePlate", 1).Address; + var currentAddon = (AddonNamePlate*)_gameGui.GetAddonByName("NamePlate").Address; if (_mpNameplateAddon == null || currentAddon == null || currentAddon != _mpNameplateAddon) return; @@ -248,7 +248,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber var cid = DalamudUtilService.GetHashedCIDFromPlayerPointer((nint)objectInfo->GameObject); if (cid == null || !_activeBroadcastingCids.Contains(cid)) { - pNode->AtkResNode.ToggleVisibility(false); + pNode->AtkResNode.ToggleVisibility(enable: false); continue; } @@ -256,7 +256,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber if (!config.LightfinderLabelShowOwn && local != null && objectInfo->GameObject->GetGameObjectId() == local.GameObjectId) { - pNode->AtkResNode.ToggleVisibility(false); + pNode->AtkResNode.ToggleVisibility(enable: false); continue; } @@ -266,7 +266,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber var goId = (ulong)objectInfo->GameObject->GetGameObjectId(); if (hidePaired && visibleUserIds.Contains(goId)) { - pNode->AtkResNode.ToggleVisibility(false); + pNode->AtkResNode.ToggleVisibility(enable: false); continue; } @@ -278,7 +278,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber if (root == null || nameContainer == null || nameText == null) { - pNode->AtkResNode.ToggleVisibility(false); + pNode->AtkResNode.ToggleVisibility(enable: false); continue; } @@ -453,7 +453,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber positionY += config.LightfinderLabelOffsetY; alignment = (AlignmentType)System.Math.Clamp((int)alignment, 0, 8); - pNode->AtkResNode.SetUseDepthBasedPriority(true); + pNode->AtkResNode.SetUseDepthBasedPriority(enable: true); pNode->AtkResNode.Color.A = 255; @@ -613,9 +613,8 @@ public unsafe class NameplateHandler : IMediatorSubscriber if (ReferenceEquals(_activeBroadcastingCids, newSet) || _activeBroadcastingCids.SetEquals(newSet)) return; - // single atomic swap – readers always see a consistent snapshot _activeBroadcastingCids = newSet; - _logger.LogInformation("Active broadcast CIDs: {Cids}", string.Join(",", _activeBroadcastingCids)); + _logger.LogInformation("Active broadcast CIDs: {Cids}", string.Join(',', _activeBroadcastingCids)); FlagRefresh(); } From 1d672d25520f4aee9b6c2b88ee486d82e821967a Mon Sep 17 00:00:00 2001 From: azyges <229218900+azyges@users.noreply.github.com> Date: Thu, 6 Nov 2025 23:40:58 +0900 Subject: [PATCH 4/4] improve checks and add logging --- LightlessSync/Services/NameplateHandler.cs | 94 ++++++++++++++++++---- 1 file changed, 80 insertions(+), 14 deletions(-) diff --git a/LightlessSync/Services/NameplateHandler.cs b/LightlessSync/Services/NameplateHandler.cs index 5e83683..11af974 100644 --- a/LightlessSync/Services/NameplateHandler.cs +++ b/LightlessSync/Services/NameplateHandler.cs @@ -1,5 +1,6 @@ using Dalamud.Game.Addon.Lifecycle; using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; +using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.Text; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.System.Framework; @@ -15,6 +16,7 @@ using LightlessSync.UtilsEnum.Enum; // Created using https://github.com/PunishedPineapple/Distance as a reference, thank you! using Microsoft.Extensions.Logging; +using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; @@ -114,6 +116,12 @@ public unsafe class NameplateHandler : IMediatorSubscriber private void NameplateDrawDetour(AddonEvent type, AddonArgs args) { + if (args.Addon.Address == nint.Zero) + { + _logger.LogWarning("Nameplate draw detour received a null addon address, skipping update."); + return; + } + var pNameplateAddon = (AddonNamePlate*)args.Addon.Address; if (_mpNameplateAddon != pNameplateAddon) @@ -138,6 +146,10 @@ public unsafe class NameplateHandler : IMediatorSubscriber if (nameplateObject == null) continue; + var rootNode = nameplateObject.Value.RootComponentNode; + if (rootNode == null || rootNode->Component == null) + continue; + var pNameplateResNode = nameplateObject.Value.NameContainer; if (pNameplateResNode == null) continue; @@ -153,7 +165,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber pNewNode->AtkResNode.NextSiblingNode = pLastChild; pNewNode->AtkResNode.ParentNode = pNameplateResNode; pLastChild->PrevSiblingNode = (AtkResNode*)pNewNode; - nameplateObject.Value.RootComponentNode->Component->UldManager.UpdateDrawNodeList(); + rootNode->Component->UldManager.UpdateDrawNodeList(); pNewNode->AtkResNode.SetUseDepthBasedPriority(true); _mTextNodes[i] = pNewNode; } @@ -162,15 +174,34 @@ public unsafe class NameplateHandler : IMediatorSubscriber private void DestroyNameplateNodes() { - var pCurrentNameplateAddon = (AddonNamePlate*)_gameGui.GetAddonByName("NamePlate", 1).Address; - if (_mpNameplateAddon == null || _mpNameplateAddon != pCurrentNameplateAddon) + var currentHandle = _gameGui.GetAddonByName("NamePlate", 1); + if (currentHandle.Address == nint.Zero) + { + _logger.LogWarning("Unable to destroy nameplate nodes because the NamePlate addon is not available."); return; + } + + var pCurrentNameplateAddon = (AddonNamePlate*)currentHandle.Address; + if (_mpNameplateAddon == null) + return; + + if (_mpNameplateAddon != pCurrentNameplateAddon) + { + _logger.LogWarning("Skipping nameplate node destroy due to addon address mismatch (cached {Cached:X}, current {Current:X}).", (IntPtr)_mpNameplateAddon, (IntPtr)pCurrentNameplateAddon); + return; + } for (int i = 0; i < AddonNamePlate.NumNamePlateObjects; ++i) { var pTextNode = _mTextNodes[i]; var pNameplateNode = GetNameplateComponentNode(i); - if (pTextNode != null && pNameplateNode != null) + if (pTextNode != null && (pNameplateNode == null || pNameplateNode->Component == null)) + { + _logger.LogDebug("Skipping destroy for nameplate {Index} because its component node is unavailable.", i); + continue; + } + + if (pTextNode != null && pNameplateNode != null && pNameplateNode->Component != null) { try { @@ -205,20 +236,48 @@ public unsafe class NameplateHandler : IMediatorSubscriber private void UpdateNameplateNodes() { - var currentAddon = (AddonNamePlate*)_gameGui.GetAddonByName("NamePlate").Address; - if (_mpNameplateAddon == null || currentAddon == null || currentAddon != _mpNameplateAddon) + var currentHandle = _gameGui.GetAddonByName("NamePlate"); + if (currentHandle.Address == nint.Zero) + { + _logger.LogDebug("NamePlate addon unavailable during update, skipping label refresh."); return; + } + + var currentAddon = (AddonNamePlate*)currentHandle.Address; + if (_mpNameplateAddon == null || currentAddon == null || currentAddon != _mpNameplateAddon) + { + if (_mpNameplateAddon != null) + _logger.LogDebug("Cached NamePlate addon pointer differs from current: waiting for new hook (cached {Cached:X}, current {Current:X}).", (IntPtr)_mpNameplateAddon, (IntPtr)currentAddon); + return; + } var framework = Framework.Instance(); - - var ui3DModule = framework->GetUIModule()->GetUI3DModule(); - if (ui3DModule == null) + if (framework == null) + { + _logger.LogDebug("Framework instance unavailable during nameplate update, skipping."); return; + } + + var uiModule = framework->GetUIModule(); + if (uiModule == null) + { + _logger.LogDebug("UI module unavailable during nameplate update, skipping."); + return; + } + + var ui3DModule = uiModule->GetUI3DModule(); + if (ui3DModule == null) + { + _logger.LogDebug("UI3D module unavailable during nameplate update, skipping."); + return; + } var vec = ui3DModule->NamePlateObjectInfoPointers; if (vec.IsEmpty) return; + var visibleUserIdsSnapshot = VisibleUserIds; + var safeCount = System.Math.Min( ui3DModule->NamePlateObjectInfoCount, vec.Length @@ -244,8 +303,15 @@ public unsafe class NameplateHandler : IMediatorSubscriber if (pNode == null) continue; + var gameObject = objectInfo->GameObject; + if ((ObjectKind)gameObject->ObjectKind != ObjectKind.Player) + { + pNode->AtkResNode.ToggleVisibility(enable: false); + continue; + } + // CID gating - var cid = DalamudUtilService.GetHashedCIDFromPlayerPointer((nint)objectInfo->GameObject); + var cid = DalamudUtilService.GetHashedCIDFromPlayerPointer((nint)gameObject); if (cid == null || !_activeBroadcastingCids.Contains(cid)) { pNode->AtkResNode.ToggleVisibility(enable: false); @@ -260,11 +326,10 @@ public unsafe class NameplateHandler : IMediatorSubscriber continue; } - var visibleUserIds = VisibleUserIds; var hidePaired = !config.LightfinderLabelShowPaired; - var goId = (ulong)objectInfo->GameObject->GetGameObjectId(); - if (hidePaired && visibleUserIds.Contains(goId)) + var goId = (ulong)gameObject->GetGameObjectId(); + if (hidePaired && visibleUserIdsSnapshot.Contains(goId)) { pNode->AtkResNode.ToggleVisibility(enable: false); continue; @@ -276,8 +341,9 @@ public unsafe class NameplateHandler : IMediatorSubscriber var nameText = nameplateObject.NameText; var marker = nameplateObject.MarkerIcon; - if (root == null || nameContainer == null || nameText == null) + if (root == null || root->Component == null || nameContainer == null || nameText == null) { + _logger.LogDebug("Nameplate {Index} missing required nodes during update, skipping.", nameplateIndex); pNode->AtkResNode.ToggleVisibility(enable: false); continue; }