mirror of
https://github.com/brues-code/pfUI.git
synced 2026-10-17 10:10:50 +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"
|
["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
|
-- Friendly zone nameplate disable state
|
||||||
local savedHostileState = nil
|
local savedHostileState = nil
|
||||||
local savedFriendlyState = nil
|
local savedFriendlyState = nil
|
||||||
local inFriendlyZone = false
|
local inFriendlyZone = false
|
||||||
local parentcount = 0
|
|
||||||
local platecount = 0
|
local platecount = 0
|
||||||
local registry = {}
|
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)
|
local raidGuidCache = {} -- guid -> name (rebuilt on RAID_ROSTER_UPDATE/PARTY_MEMBERS_CHANGED)
|
||||||
|
|
||||||
-- Helper function to safely access libdebuff cast data
|
-- Helper function to safely access libdebuff cast data
|
||||||
@@ -266,18 +256,6 @@ pfUI:RegisterModule("nameplates", function ()
|
|||||||
end
|
end
|
||||||
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)
|
local function DisableObject(object)
|
||||||
if not object then return end
|
if not object then return end
|
||||||
if not object.GetObjectType 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("ZONE_CHANGED_NEW_AREA")
|
||||||
nameplates:RegisterEvent("RAID_ROSTER_UPDATE")
|
nameplates:RegisterEvent("RAID_ROSTER_UPDATE")
|
||||||
nameplates:RegisterEvent("PARTY_MEMBERS_CHANGED")
|
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
|
if GetUnitField then
|
||||||
nameplates:RegisterEvent("UNIT_FLAGS_GUID")
|
nameplates:RegisterEvent("UNIT_FLAGS_GUID")
|
||||||
end
|
end
|
||||||
@@ -565,7 +546,7 @@ end
|
|||||||
if not guid then return end
|
if not guid then return end
|
||||||
|
|
||||||
-- GUID is actual GUID (0xF13000...) from Nampower events
|
-- GUID is actual GUID (0xF13000...) from Nampower events
|
||||||
local plate = guidRegistry[guid]
|
local plate = C_NamePlate.GetNamePlateForGUID(guid)
|
||||||
if plate and plate.nameplate then
|
if plate and plate.nameplate then
|
||||||
-- Mark nameplate for aura update in next OnUpdate cycle
|
-- Mark nameplate for aura update in next OnUpdate cycle
|
||||||
plate.nameplate.auraUpdate = true
|
plate.nameplate.auraUpdate = true
|
||||||
@@ -575,7 +556,7 @@ end
|
|||||||
-- Hook into libdebuff timer signal (fires when slotTimers written or cleared)
|
-- Hook into libdebuff timer signal (fires when slotTimers written or cleared)
|
||||||
pfUI.libdebuff_on_unit_updated = pfUI.libdebuff_on_unit_updated or {}
|
pfUI.libdebuff_on_unit_updated = pfUI.libdebuff_on_unit_updated or {}
|
||||||
table.insert(pfUI.libdebuff_on_unit_updated, function(guid)
|
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
|
if plate and plate.nameplate then
|
||||||
plate.nameplate.auraUpdate = true
|
plate.nameplate.auraUpdate = true
|
||||||
end
|
end
|
||||||
@@ -645,10 +626,43 @@ end
|
|||||||
elseif event == "RAID_ROSTER_UPDATE" or event == "PARTY_MEMBERS_CHANGED" then
|
elseif event == "RAID_ROSTER_UPDATE" or event == "PARTY_MEMBERS_CHANGED" then
|
||||||
RebuildRaidGuidCache()
|
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
|
elseif event == "UNIT_FLAGS_GUID" then
|
||||||
-- Nampower: fires instantly when any unit's flags change (e.g. stun, combat enter/leave)
|
-- 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
|
-- 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
|
if plate and plate.nameplate then
|
||||||
plate.nameplate.eventcache = true
|
plate.nameplate.eventcache = true
|
||||||
end
|
end
|
||||||
@@ -657,7 +671,7 @@ end
|
|||||||
-- Flag target plate for update via GUID registry
|
-- Flag target plate for update via GUID registry
|
||||||
local targetGuid = UnitGUID("target")
|
local targetGuid = UnitGUID("target")
|
||||||
if targetGuid then
|
if targetGuid then
|
||||||
local plate = guidRegistry[targetGuid]
|
local plate = C_NamePlate.GetNamePlateForGUID(targetGuid)
|
||||||
if plate and plate.nameplate then
|
if plate and plate.nameplate then
|
||||||
plate.nameplate.targetUpdate = true
|
plate.nameplate.targetUpdate = true
|
||||||
end
|
end
|
||||||
@@ -669,7 +683,7 @@ end
|
|||||||
-- Only flag the target plate for combo point update
|
-- Only flag the target plate for combo point update
|
||||||
local targetGuid = UnitGUID("target")
|
local targetGuid = UnitGUID("target")
|
||||||
if targetGuid then
|
if targetGuid then
|
||||||
local plate = guidRegistry[targetGuid]
|
local plate = C_NamePlate.GetNamePlateForGUID(targetGuid)
|
||||||
if plate and plate.nameplate then
|
if plate and plate.nameplate then
|
||||||
plate.nameplate.comboUpdate = true
|
plate.nameplate.comboUpdate = true
|
||||||
end
|
end
|
||||||
@@ -702,77 +716,13 @@ end
|
|||||||
-- PERF: Update visible plate count periodically for adaptive throttling
|
-- PERF: Update visible plate count periodically for adaptive throttling
|
||||||
if frameState.now - lastVisibleCheck > 0.5 then
|
if frameState.now - lastVisibleCheck > 0.5 then
|
||||||
lastVisibleCheck = frameState.now
|
lastVisibleCheck = frameState.now
|
||||||
local count = 0
|
visiblePlateCount = table.getn(C_NamePlate.GetNamePlates())
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Central OnUpdate for all visible plates
|
-- Central OnUpdate for all visible plates
|
||||||
for plate in pairs(registry) do
|
for plate in pairs(registry) do
|
||||||
if plate:IsVisible() then
|
if plate:IsVisible() then
|
||||||
nameplates.OnUpdate(plate, frameState)
|
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
|
end
|
||||||
end)
|
end)
|
||||||
@@ -939,12 +889,12 @@ end
|
|||||||
nameplate.tick = GetTime() + mathmod(platecount, 10) * 0.05
|
nameplate.tick = GetTime() + mathmod(platecount, 10) * 0.05
|
||||||
|
|
||||||
parent.nameplate = nameplate
|
parent.nameplate = nameplate
|
||||||
HookScript(parent, "OnShow", nameplates.OnShow)
|
|
||||||
-- NOTE: OnUpdate is now handled centrally, not per-plate/
|
-- NOTE: OnUpdate is now handled centrally, not per-plate/
|
||||||
parent:SetScript("OnUpdate", nil) -- Disable Blizzard's OnUpdate
|
parent:SetScript("OnUpdate", nil) -- Disable Blizzard's OnUpdate
|
||||||
|
|
||||||
nameplates.OnConfigChange(parent)
|
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
|
end
|
||||||
|
|
||||||
nameplates.OnConfigChange = function(frame)
|
nameplates.OnConfigChange = function(frame)
|
||||||
@@ -1413,17 +1363,13 @@ end
|
|||||||
local frame = frame or this
|
local frame = frame or this
|
||||||
local nameplate = frame.nameplate
|
local nameplate = frame.nameplate
|
||||||
|
|
||||||
-- Register GUID when plate becomes visible
|
-- cachedGuid is set by NAME_PLATE_UNIT_ADDED before this fires
|
||||||
local guid = frame:GetName(1)
|
local guid = nameplate.cachedGuid
|
||||||
if guid then
|
if guid and pfUI.api.libunitscan and pfUI.api.libunitscan.ScanGuid then
|
||||||
nameplate.cachedGuid = guid
|
|
||||||
guidRegistry[guid] = frame
|
|
||||||
-- notify libunitscan so it can cache unit data without mouseover
|
-- notify libunitscan so it can cache unit data without mouseover
|
||||||
if pfUI.api.libunitscan and pfUI.api.libunitscan.ScanGuid then
|
local name = nameplate.original.name:GetText()
|
||||||
local name = frame.nameplate.original.name:GetText()
|
local npcFlags = GetUnitField(guid, "npcFlags") or 0
|
||||||
local npcFlags = GetUnitField(guid, "npcFlags") or 0
|
pfUI.api.libunitscan.ScanGuid(guid, name, npcFlags == 0)
|
||||||
pfUI.api.libunitscan.ScanGuid(guid, name, npcFlags == 0)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
nameplates:OnDataChanged(nameplate)
|
nameplates:OnDataChanged(nameplate)
|
||||||
@@ -1432,17 +1378,9 @@ end
|
|||||||
nameplates.OnUpdate = function(frame, state)
|
nameplates.OnUpdate = function(frame, state)
|
||||||
local nameplate = frame.nameplate
|
local nameplate = frame.nameplate
|
||||||
local now = state and state.now or GetTime()
|
local now = state and state.now or GetTime()
|
||||||
|
|
||||||
-- Update GUID registry (lightweight, needed for event routing)
|
-- cachedGuid is maintained by NAME_PLATE_UNIT_ADDED / _REMOVED events.
|
||||||
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
|
|
||||||
|
|
||||||
-- PERF: Intelligent throttling based on target/castbar status and plate count
|
-- PERF: Intelligent throttling based on target/castbar status and plate count
|
||||||
-- Use GUID comparison as primary target detection: instant, immune to alpha transitions,
|
-- 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)
|
-- 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")
|
local targetGuid = UnitExists("target") and UnitGUID("target")
|
||||||
if not targetGuid then return end
|
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
|
if not frame or not frame.nameplate then return end
|
||||||
|
|
||||||
nameplates.UpdateCastbar(frame.nameplate, now)
|
nameplates.UpdateCastbar(frame.nameplate, now)
|
||||||
|
|||||||
Reference in New Issue
Block a user