mirror of
https://github.com/brues-code/pfUI.git
synced 2026-09-25 09:06:03 +00:00
C_NamePlate (#1)
* nameplates: drive discovery + GUID lookup via C_NamePlate ClassicAPI now provides the modern C_NamePlate API and the matching NAME_PLATE_CREATED / NAME_PLATE_UNIT_ADDED / NAME_PLATE_UNIT_REMOVED events. Replace the WorldFrame:GetChildren polling + manual GUID dictionary with event-driven plumbing. - Drop the per-tick WorldFrame:GetNumChildren / GetChildren scan - Delete IsNamePlate() border-texture filter (events only deliver nameplate frames) - Delete the guidRegistry table + its OnShow/OnUpdate maintenance; every lookup now goes through C_NamePlate.GetNamePlateForGUID - Move per-GUID cache cleanup (debuffCache / threatMemory / combatColorCache / libdebuff_casts) from the OnUpdate visibility scan to a NAME_PLATE_UNIT_REMOVED handler — fires exactly once per unit going out of range - NAME_PLATE_CREATED drives nameplates.OnCreate; NAME_PLATE_UNIT_ADDED sets cachedGuid and drives nameplates.OnShow (so OnCreate no longer calls OnShow directly and no longer HookScripts the parent) - visiblePlateCount uses table.getn(C_NamePlate.GetNamePlates()) Net -64 lines, with a meaningful reduction in per-tick CPU (no more WorldFrame child iteration + region/texture filter every 50ms). * nameplates: switch UNIT_ADDED/REMOVED handlers to nameplateN tokens ClassicAPI's NAME_PLATE_UNIT_ADDED / _REMOVED events now ship the "nameplateN" unit token as arg1 (matching modern WoW) instead of the GUID string. - UNIT_ADDED: resolve plate via C_NamePlate.GetNamePlateForUnit(arg1); derive the cache-key GUID via UnitGUID(arg1) - UNIT_REMOVED: same lookup pattern; compute UnitGUID(arg1) inside the handler before the slot recycles (per docs guarantee) The other six GetNamePlateForGUID call sites (libdebuff aura callbacks, UNIT_FLAGS_GUID, PLAYER_TARGET_CHANGED, combo-point handler, castbar frame) stay on the GUID flavor — they receive real GUIDs from other event paths. --------- Co-authored-by: Brues <5278969+brues-code@users.noreply.github.com>
This commit is contained in:
+54
-116
@@ -56,23 +56,13 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
["boss"] = "B"
|
||||
}
|
||||
|
||||
-- catch all nameplates
|
||||
local childs = {} -- PERF: Reuse table instead of creating new one each scan
|
||||
local regions, plate
|
||||
local initialized = 0
|
||||
|
||||
-- Friendly zone nameplate disable state
|
||||
local savedHostileState = nil
|
||||
local savedFriendlyState = nil
|
||||
local inFriendlyZone = false
|
||||
local parentcount = 0
|
||||
local platecount = 0
|
||||
local registry = {}
|
||||
|
||||
-- ============================================================================
|
||||
-- OPTIMIZATION: GUID-based registries for O(1) lookups
|
||||
-- ============================================================================
|
||||
local guidRegistry = {} -- guid -> plate (for direct event routing)
|
||||
local raidGuidCache = {} -- guid -> name (rebuilt on RAID_ROSTER_UPDATE/PARTY_MEMBERS_CHANGED)
|
||||
|
||||
-- Helper function to safely access libdebuff cast data
|
||||
@@ -266,18 +256,6 @@ pfUI:RegisterModule("nameplates", function ()
|
||||
end
|
||||
end
|
||||
|
||||
local function IsNamePlate(frame)
|
||||
if frame:GetObjectType() ~= NAMEPLATE_FRAMETYPE then return nil end
|
||||
regions = plate:GetRegions()
|
||||
|
||||
if not regions then return nil end
|
||||
if not regions.GetObjectType then return nil end
|
||||
if not regions.GetTexture then return nil end
|
||||
|
||||
if regions:GetObjectType() ~= "Texture" then return nil end
|
||||
return regions:GetTexture() == "Interface\\Tooltips\\Nameplate-Border" or nil
|
||||
end
|
||||
|
||||
local function DisableObject(object)
|
||||
if not object then return end
|
||||
if not object.GetObjectType then return end
|
||||
@@ -553,6 +531,9 @@ nameplates:RegisterEvent("PLAYER_COMBO_POINTS")
|
||||
nameplates:RegisterEvent("ZONE_CHANGED_NEW_AREA")
|
||||
nameplates:RegisterEvent("RAID_ROSTER_UPDATE")
|
||||
nameplates:RegisterEvent("PARTY_MEMBERS_CHANGED")
|
||||
nameplates:RegisterEvent("NAME_PLATE_CREATED")
|
||||
nameplates:RegisterEvent("NAME_PLATE_UNIT_ADDED")
|
||||
nameplates:RegisterEvent("NAME_PLATE_UNIT_REMOVED")
|
||||
if GetUnitField then
|
||||
nameplates:RegisterEvent("UNIT_FLAGS_GUID")
|
||||
end
|
||||
@@ -565,7 +546,7 @@ end
|
||||
if not guid then return end
|
||||
|
||||
-- GUID is actual GUID (0xF13000...) from Nampower events
|
||||
local plate = guidRegistry[guid]
|
||||
local plate = C_NamePlate.GetNamePlateForGUID(guid)
|
||||
if plate and plate.nameplate then
|
||||
-- Mark nameplate for aura update in next OnUpdate cycle
|
||||
plate.nameplate.auraUpdate = true
|
||||
@@ -575,7 +556,7 @@ end
|
||||
-- Hook into libdebuff timer signal (fires when slotTimers written or cleared)
|
||||
pfUI.libdebuff_on_unit_updated = pfUI.libdebuff_on_unit_updated or {}
|
||||
table.insert(pfUI.libdebuff_on_unit_updated, function(guid)
|
||||
local plate = guidRegistry[guid]
|
||||
local plate = C_NamePlate.GetNamePlateForGUID(guid)
|
||||
if plate and plate.nameplate then
|
||||
plate.nameplate.auraUpdate = true
|
||||
end
|
||||
@@ -645,10 +626,43 @@ end
|
||||
elseif event == "RAID_ROSTER_UPDATE" or event == "PARTY_MEMBERS_CHANGED" then
|
||||
RebuildRaidGuidCache()
|
||||
|
||||
elseif event == "NAME_PLATE_CREATED" then
|
||||
-- arg1 = the nameplate Frame; build the pfUI overlay once per pool slot
|
||||
if arg1 and not registry[arg1] then
|
||||
nameplates.OnCreate(arg1)
|
||||
registry[arg1] = arg1
|
||||
end
|
||||
|
||||
elseif event == "NAME_PLATE_UNIT_ADDED" then
|
||||
-- arg1 = "nameplateN" unit token; resolve to GUID for cache keys
|
||||
local plate = C_NamePlate.GetNamePlateForUnit(arg1)
|
||||
if plate and plate.nameplate then
|
||||
plate.nameplate.cachedGuid = UnitGUID(arg1)
|
||||
nameplates.OnShow(plate)
|
||||
end
|
||||
|
||||
elseif event == "NAME_PLATE_UNIT_REMOVED" then
|
||||
-- arg1 = "nameplateN" unit token; UnitGUID still resolves inside the
|
||||
-- handler (the slot is freed after dispatch returns)
|
||||
local guid = UnitGUID(arg1)
|
||||
if guid then
|
||||
if debuffCache[guid] then debuffCache[guid] = nil end
|
||||
if threatMemory[guid] then threatMemory[guid] = nil end
|
||||
if combatColorCache[guid] then combatColorCache[guid] = nil end
|
||||
local castInfo = GetCastInfo(guid)
|
||||
if castInfo and castInfo.endTime and castInfo.endTime < GetTime() then
|
||||
if pfUI.libdebuff_casts then pfUI.libdebuff_casts[guid] = nil end
|
||||
end
|
||||
local plate = C_NamePlate.GetNamePlateForUnit(arg1)
|
||||
if plate and plate.nameplate and plate.nameplate.cachedGuid == guid then
|
||||
plate.nameplate.cachedGuid = nil
|
||||
end
|
||||
end
|
||||
|
||||
elseif event == "UNIT_FLAGS_GUID" then
|
||||
-- Nampower: fires instantly when any unit's flags change (e.g. stun, combat enter/leave)
|
||||
-- arg1 = guid — directly flag that nameplate for immediate update, bypassing throttle
|
||||
local plate = guidRegistry[arg1]
|
||||
local plate = C_NamePlate.GetNamePlateForGUID(arg1)
|
||||
if plate and plate.nameplate then
|
||||
plate.nameplate.eventcache = true
|
||||
end
|
||||
@@ -657,7 +671,7 @@ end
|
||||
-- Flag target plate for update via GUID registry
|
||||
local targetGuid = UnitGUID("target")
|
||||
if targetGuid then
|
||||
local plate = guidRegistry[targetGuid]
|
||||
local plate = C_NamePlate.GetNamePlateForGUID(targetGuid)
|
||||
if plate and plate.nameplate then
|
||||
plate.nameplate.targetUpdate = true
|
||||
end
|
||||
@@ -669,7 +683,7 @@ end
|
||||
-- Only flag the target plate for combo point update
|
||||
local targetGuid = UnitGUID("target")
|
||||
if targetGuid then
|
||||
local plate = guidRegistry[targetGuid]
|
||||
local plate = C_NamePlate.GetNamePlateForGUID(targetGuid)
|
||||
if plate and plate.nameplate then
|
||||
plate.nameplate.comboUpdate = true
|
||||
end
|
||||
@@ -702,77 +716,13 @@ end
|
||||
-- PERF: Update visible plate count periodically for adaptive throttling
|
||||
if frameState.now - lastVisibleCheck > 0.5 then
|
||||
lastVisibleCheck = frameState.now
|
||||
local count = 0
|
||||
for plate in pairs(registry) do
|
||||
if plate:IsVisible() then count = count + 1 end
|
||||
end
|
||||
visiblePlateCount = count
|
||||
end
|
||||
|
||||
-- Throttle ONLY the nameplate scanner
|
||||
local scanThrottle = nameplates.combat and nameplates.combat.inCombat and 0.1 or 0.05
|
||||
local shouldScan = (this.tick or 0) <= frameState.now
|
||||
if shouldScan then
|
||||
this.tick = frameState.now + scanThrottle
|
||||
|
||||
-- detect new nameplates
|
||||
parentcount = WorldFrame:GetNumChildren()
|
||||
if initialized < parentcount then
|
||||
-- PERF: Reuse childs table instead of creating new one
|
||||
local newchilds = { WorldFrame:GetChildren() }
|
||||
for i = 1, parentcount do
|
||||
childs[i] = newchilds[i]
|
||||
end
|
||||
|
||||
for i = initialized + 1, parentcount do
|
||||
plate = childs[i]
|
||||
if IsNamePlate(plate) and not registry[plate] then
|
||||
nameplates.OnCreate(plate)
|
||||
registry[plate] = plate
|
||||
end
|
||||
end
|
||||
|
||||
initialized = parentcount
|
||||
end
|
||||
visiblePlateCount = table.getn(C_NamePlate.GetNamePlates())
|
||||
end
|
||||
|
||||
-- Central OnUpdate for all visible plates
|
||||
for plate in pairs(registry) do
|
||||
if plate:IsVisible() then
|
||||
nameplates.OnUpdate(plate, frameState)
|
||||
else
|
||||
-- PERF: Clean up ALL caches for hidden plates to prevent memory leak
|
||||
local guid = plate.nameplate and plate.nameplate.cachedGuid
|
||||
if guid then
|
||||
-- Remove from guidRegistry
|
||||
if guidRegistry[guid] == plate then
|
||||
guidRegistry[guid] = nil
|
||||
end
|
||||
|
||||
-- Clean cast cache ONLY if cast has expired
|
||||
-- (Don't delete active casts just because plate was hidden briefly)
|
||||
local castInfo = GetCastInfo(guid)
|
||||
if castInfo and castInfo.endTime and castInfo.endTime < frameState.now then
|
||||
if pfUI.libdebuff_casts then
|
||||
pfUI.libdebuff_casts[guid] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Clean debuffCache
|
||||
if debuffCache[guid] then
|
||||
debuffCache[guid] = nil
|
||||
end
|
||||
|
||||
-- Clean threatMemory
|
||||
if threatMemory[guid] then
|
||||
threatMemory[guid] = nil
|
||||
end
|
||||
|
||||
-- Clean combatColorCache
|
||||
if combatColorCache[guid] then
|
||||
combatColorCache[guid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -939,12 +889,12 @@ end
|
||||
nameplate.tick = GetTime() + mathmod(platecount, 10) * 0.05
|
||||
|
||||
parent.nameplate = nameplate
|
||||
HookScript(parent, "OnShow", nameplates.OnShow)
|
||||
-- NOTE: OnUpdate is now handled centrally, not per-plate/
|
||||
parent:SetScript("OnUpdate", nil) -- Disable Blizzard's OnUpdate
|
||||
|
||||
nameplates.OnConfigChange(parent)
|
||||
nameplates.OnShow(parent)
|
||||
-- NOTE: OnShow is driven by NAME_PLATE_UNIT_ADDED, not called here.
|
||||
-- At NAME_PLATE_CREATED time the unit hasn't been bound yet.
|
||||
end
|
||||
|
||||
nameplates.OnConfigChange = function(frame)
|
||||
@@ -1413,17 +1363,13 @@ end
|
||||
local frame = frame or this
|
||||
local nameplate = frame.nameplate
|
||||
|
||||
-- Register GUID when plate becomes visible
|
||||
local guid = frame:GetName(1)
|
||||
if guid then
|
||||
nameplate.cachedGuid = guid
|
||||
guidRegistry[guid] = frame
|
||||
-- cachedGuid is set by NAME_PLATE_UNIT_ADDED before this fires
|
||||
local guid = nameplate.cachedGuid
|
||||
if guid and pfUI.api.libunitscan and pfUI.api.libunitscan.ScanGuid then
|
||||
-- notify libunitscan so it can cache unit data without mouseover
|
||||
if pfUI.api.libunitscan and pfUI.api.libunitscan.ScanGuid then
|
||||
local name = frame.nameplate.original.name:GetText()
|
||||
local npcFlags = GetUnitField(guid, "npcFlags") or 0
|
||||
pfUI.api.libunitscan.ScanGuid(guid, name, npcFlags == 0)
|
||||
end
|
||||
local name = nameplate.original.name:GetText()
|
||||
local npcFlags = GetUnitField(guid, "npcFlags") or 0
|
||||
pfUI.api.libunitscan.ScanGuid(guid, name, npcFlags == 0)
|
||||
end
|
||||
|
||||
nameplates:OnDataChanged(nameplate)
|
||||
@@ -1432,17 +1378,9 @@ end
|
||||
nameplates.OnUpdate = function(frame, state)
|
||||
local nameplate = frame.nameplate
|
||||
local now = state and state.now or GetTime()
|
||||
|
||||
-- Update GUID registry (lightweight, needed for event routing)
|
||||
local guid = frame:GetName(1)
|
||||
if guid and guid ~= nameplate.cachedGuid then
|
||||
if nameplate.cachedGuid and guidRegistry[nameplate.cachedGuid] == frame then
|
||||
guidRegistry[nameplate.cachedGuid] = nil
|
||||
end
|
||||
nameplate.cachedGuid = guid
|
||||
guidRegistry[guid] = frame
|
||||
end
|
||||
|
||||
|
||||
-- cachedGuid is maintained by NAME_PLATE_UNIT_ADDED / _REMOVED events.
|
||||
|
||||
-- PERF: Intelligent throttling based on target/castbar status and plate count
|
||||
-- Use GUID comparison as primary target detection: instant, immune to alpha transitions,
|
||||
-- and immediately correct on de-target (unlike istarget which updates one tick later)
|
||||
@@ -1842,7 +1780,7 @@ end
|
||||
local targetGuid = UnitExists("target") and UnitGUID("target")
|
||||
if not targetGuid then return end
|
||||
|
||||
local frame = guidRegistry[targetGuid]
|
||||
local frame = C_NamePlate.GetNamePlateForGUID(targetGuid)
|
||||
if not frame or not frame.nameplate then return end
|
||||
|
||||
nameplates.UpdateCastbar(frame.nameplate, now)
|
||||
|
||||
Reference in New Issue
Block a user