libdebuff/nameplates: drop dead per-aura readers and debuff cache

With every external caller of libdebuff:UnitDebuff / :UnitOwnDebuff
now on C_UnitAuras, the two public per-aura readers and the
nameplate-side cache they were feeding have no consumers.

- libs/libdebuff.lua: removes libdebuff:UnitDebuff (~120 lines),
  libdebuff:UnitOwnDebuff (~75 lines), the _ownDebuffSortFunc helper,
  and the local cache table. The slotOwnership / ownDebuffs /
  allAuraCasts / pendingCasts bookkeeping stays — GetBestAuraCast
  (libpredict) and GetEnhancedDebuffs (CleveRoids) still read it, and
  the event handlers maintain it. GetSlotCaster / GetDebuffSlotMap
  stay too; the DEBUFF_ADDED_OTHER handler and the debug printer use
  them. File goes 2010 → 1870 lines.
- modules/nameplates.lua: deletes PlateCacheDebuffs (was already
  rewritten on C_UnitAuras and unused once the display loop bypassed
  the cache), PlateUnitDebuff, the cachedVerify scaffolding, and the
  nameplate.UnitDebuff / nameplate.CacheDebuffs registrations.
- api/config.lua + modules/gui.lua: drops the now-defunct
  "guessdebuffs" knob — its only effect was gating the dead cache.
This commit is contained in:
Brues
2026-06-24 22:41:36 -05:00
parent d6951b386e
commit be6ae25315
4 changed files with 5 additions and 289 deletions
-1
View File
@@ -818,7 +818,6 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("nameplates", nil, "showdebuffs_hostile", "1")
pfUI:UpdateConfig("nameplates", nil, "showdebuffs_friendly", "0")
pfUI:UpdateConfig("nameplates", nil, "owndebuffs", "0")
pfUI:UpdateConfig("nameplates", nil, "guessdebuffs", "1")
pfUI:UpdateConfig("nameplates", nil, "clickthrough", "0")
pfUI:UpdateConfig("nameplates", nil, "rightclick", "1")
pfUI:UpdateConfig("nameplates", nil, "clickthreshold", "0.5")
+5 -216
View File
@@ -11,9 +11,11 @@ setfenv(1, pfUI:GetEnvironment())
-- This eliminates ~400 lines of error-prone shift logic while maintaining full
-- multi-caster tracking support.
--
-- libdebuff:UnitDebuff(unit, id)
-- Returns debuff informations on the given effect of the specified unit.
-- name, rank, texture, stacks, dtype, duration, timeleft, caster
-- The public per-aura readers (UnitDebuff, UnitOwnDebuff) were retired in favor
-- of ClassicAPI's C_UnitAuras (which now provides sourceUnit/sourceGUID and
-- non-player expirationTime). What remains in libdebuff is the cast-event
-- bookkeeping consumed by GetBestAuraCast / GetEnhancedDebuffs and the
-- libdebuff_casts / libdebuff_*_hooks broadcast surface.
-- return instantly when another libdebuff is already active
if pfUI.api.libdebuff then return end
@@ -787,219 +789,6 @@ function libdebuff:AddEffect(unit, unitlevel, effect, duration, caster, rank)
lastspell = libdebuff.objects[unit][unitlevel][effect]
end
-- ============================================================================
-- MAIN API: UnitDebuff (GetUnitField-based)
-- ============================================================================
local cache = {}
function libdebuff:UnitDebuff(unit, displaySlot)
local unitname = UnitName(unit)
local unitlevel = UnitLevel(unit)
local duration, timeleft = nil, -1
local rank = nil
local caster = nil
local effect = nil
local texture = nil
local stacks = 0
local dtype = nil
-- Nampower: Use GetUnitField for ALL debuff data (no Blizzard UnitDebuff needed)
if hasNampower and UnitGUID then
local guid = UnitGUID(unit)
if not guid then
-- Safety fallback: no GUID available (should not happen with Nampower)
local aura = C_UnitAuras.GetDebuffDataByIndex(unit, displaySlot)
if aura then
return aura.name, rank, aura.icon, aura.applications, aura.dispelName, duration, timeleft, caster
end
return effect, rank, texture, stacks, dtype, duration, timeleft, caster
end
-- Get current slot map from GetUnitField (cached 50ms)
local slotMap = GetDebuffSlotMap(guid)
if not slotMap or not slotMap[displaySlot] then
return nil
end
local slotData = slotMap[displaySlot]
effect = slotData.spellName
texture = slotData.texture
stacks = slotData.stacks
dtype = slotData.dtype
local auraSlot = slotData.auraSlot
-- Get caster info for this slot
local slotCasterGuid, isOurs = GetSlotCaster(guid, auraSlot, effect)
if isOurs then
-- OUR debuff - get timer from ownDebuffs
if ownDebuffs[guid] and ownDebuffs[guid][effect] then
local data = ownDebuffs[guid][effect]
local remaining = (data.startTime + data.duration) - GetTime()
if remaining > 0 then
duration = data.duration
timeleft = remaining
caster = "player"
rank = data.rank
elseif remaining > -1 then
-- Grace period - show 0 timeleft
duration = data.duration
timeleft = 0
caster = "player"
rank = data.rank
end
end
else
-- OTHER player's debuff - get timer from allAuraCasts
if slotCasterGuid and allAuraCasts[guid] and allAuraCasts[guid][effect] then
local data = allAuraCasts[guid][effect][slotCasterGuid]
if data then
local remaining = (data.startTime + data.duration) - GetTime()
if remaining > 0 and data.duration > 0 then
duration = data.duration
timeleft = remaining
caster = "other"
rank = data.rank
end
end
end
-- Fallback: Search all casters if specific one not found
if not duration and allAuraCasts[guid] and allAuraCasts[guid][effect] then
for anyCasterGuid, data in pairs(allAuraCasts[guid][effect]) do
local remaining = (data.startTime + data.duration) - GetTime()
if remaining > 0 and data.duration > 0 then
duration = data.duration
timeleft = remaining
caster = "other"
rank = data.rank
break
end
end
end
end
return effect, rank, texture, stacks, dtype, duration, timeleft, caster
end
-- ============================================================================
-- FALLBACK: Legacy (non-Nampower) system
-- ============================================================================
local aura = C_UnitAuras.GetDebuffDataByIndex(unit, displaySlot)
if aura then
texture = aura.icon
stacks = aura.applications
dtype = aura.dispelName
effect = aura.name
end
if effect and libdebuff.objects[unitname] then
for level, effects in pairs(libdebuff.objects[unitname]) do
if effects[effect] and effects[effect].duration then
local timeleft = effects[effect].start and
effects[effect].start + effects[effect].duration - GetTime()
if timeleft and timeleft > 0 then
return effect, effects[effect].rank, texture, stacks, dtype,
effects[effect].duration, timeleft, effects[effect].caster
end
end
end
end
return effect, rank, texture, stacks, dtype, duration, timeleft, caster
end
-- ============================================================================
-- API: UnitOwnDebuff (only OUR debuffs)
-- ============================================================================
-- Pre-defined sort function for UnitOwnDebuff (avoids closure creation per call)
local _ownDebuffSortFunc = function(a, b)
if a.data.startTime == b.data.startTime then
return a.spellName < b.spellName
end
return a.data.startTime < b.data.startTime
end
function libdebuff:UnitOwnDebuff(unit, id)
if hasNampower and UnitGUID then
local guid = UnitGUID(unit)
if guid and ownDebuffs[guid] then
-- Build sorted list of our active debuffs
local sortedDebuffs = {}
local now = GetTime()
local toRemove = nil
for spellName, data in pairs(ownDebuffs[guid]) do
local timeleft = (data.startTime + data.duration) - now
if timeleft > 0 then
local count = table.getn(sortedDebuffs) + 1
sortedDebuffs[count] = {
spellName = spellName,
data = data,
timeleft = timeleft
}
elseif data.pending then
if timeleft < -2 then
toRemove = toRemove or {}
toRemove[spellName] = true
end
else
toRemove = toRemove or {}
toRemove[spellName] = true
end
end
if toRemove then
for spellName in pairs(toRemove) do
ownDebuffs[guid][spellName] = nil
end
end
-- Sort by startTime (oldest first = lowest display slot)
-- If startTime is equal (e.g. after Carnage refresh), use spellName for stable sorting
table.sort(sortedDebuffs, _ownDebuffSortFunc)
-- Return debuff at position 'id'
if sortedDebuffs[id] then
local entry = sortedDebuffs[id]
local texture = entry.data.texture or "Interface\\Icons\\INV_Misc_QuestionMark"
local displayTimeleft = entry.timeleft > 0 and entry.timeleft or 0
-- Get dtype from SpellRec DBC via stored spellId
local entryDtype = nil
if entry.data.spellId and GetSpellRecField then
local dispelId = GetSpellRecField(entry.data.spellId, "dispel")
if dispelId and dispelId > 0 then
entryDtype = dispelTypeMap[dispelId]
end
end
return entry.spellName, entry.data.rank, texture, 1, entryDtype, entry.data.duration, displayTimeleft, "player"
end
end
return nil
end
-- Fallback: Iterate through all debuffs and filter
for k in pairs(cache) do cache[k] = nil end
local count = 1
for i=1,16 do
local effect, rank, texture, stacks, dtype, duration, timeleft, caster = libdebuff:UnitDebuff(unit, i)
if effect and not cache[effect] and caster and caster == "player" then
cache[effect] = true
if count == id then
return effect, rank, texture, stacks, dtype, duration, timeleft, caster
else
count = count + 1
end
end
end
end
-- ============================================================================
-- API: GetBestAuraCast (for libpredict HoT tracking)
-- ============================================================================
-1
View File
@@ -2899,7 +2899,6 @@ pfUI:RegisterModule("gui", function ()
CreateConfig(U["nameplates"], T["Debuff Position"], C.nameplates.debuffs, "position", "dropdown", pfUI.gui.dropdowns.debuffposition)
CreateConfig(U["nameplates"], T["Debuff Icon Offset"], C.nameplates, "debuffoffset")
CreateConfig(U["nameplates"], T["Debuff Icon Size"], C.nameplates, "debuffsize")
CreateConfig(U["nameplates"], T["Estimate Debuffs"], C.nameplates, "guessdebuffs", "checkbox")
CreateConfig(U["nameplates"], T["Show Debuff Stacks"], C.nameplates.debuffs, "showstacks", "checkbox")
CreateConfig(U["nameplates"], T["Enable Debuff Timers"], C.nameplates, "debufftimers", "checkbox")
CreateConfig(U["nameplates"], T["Show Timer Text"], C.nameplates, "debufftext", "checkbox")
-71
View File
@@ -371,62 +371,6 @@ pfUI:RegisterModule("nameplates", function ()
end
end
local function PlateCacheDebuffs(self, unitstr, verify)
if not self.debuffcache then self.debuffcache = {} end
if not libdebuff then return end
local now = GetTime()
-- Clear existing cache slots
for id = 1, 16 do
if self.debuffcache[id] then
self.debuffcache[id].empty = true
end
end
-- Pull debuffs straight from C_UnitAuras. The HARMFUL filter restricts to
-- the debuff range; PLAYER (added when cfg.owndebuffs is on) further
-- restricts to auras whose cached caster GUID matches the local player.
-- expirationTime comes from ClassicAPI's Aura::Source cache (SMSG_SPELL_GO
-- observation) — best-effort, so auras applied before login won't carry
-- timing and we treat them as durationless.
local filter = cfg.owndebuffs and "HARMFUL|PLAYER" or "HARMFUL"
local auras = unitstr and C_UnitAuras.GetUnitAuras(unitstr, filter) or {}
for id, aura in ipairs(auras) do
if id > 16 then break end
local duration = aura.duration or 0
local stop = (aura.expirationTime and aura.expirationTime > 0) and aura.expirationTime or nil
local start = stop and (stop - duration) or now
local cache = self.debuffcache[id] or {}
cache.effect = aura.name
cache.texture = aura.icon
cache.stacks = aura.applications
cache.dtype = aura.dispelName
cache.duration = duration
cache.start = start
cache.stop = stop
cache.empty = nil
self.debuffcache[id] = cache
end
self.verify = verify
end
local function PlateUnitDebuff(self, id)
-- break on unknown data
if not self.debuffcache then return end
if not self.debuffcache[id] then return end
if not self.debuffcache[id].stop then return end
-- break on timeout debuffs
if self.debuffcache[id].empty then return end
if self.debuffcache[id].stop < GetTime() then return end
-- return cached debuff
local c = self.debuffcache[id]
return c.effect, c.rank, c.texture, c.stacks, c.dtype, c.duration, (c.stop - GetTime())
end
local function CreateDebuffIcon(plate, index)
plate.debuffs[index] = CreateFrame("Frame", plate.platename.."Debuff"..index, plate)
plate.debuffs[index]:Hide()
@@ -734,8 +678,6 @@ end
nameplate:EnableMouse(0)
nameplate.parent = parent
nameplate.cache = {}
nameplate.UnitDebuff = PlateUnitDebuff
nameplate.CacheDebuffs = PlateCacheDebuffs
nameplate.original = {}
-- create shortcuts for all known elements and disable them
@@ -1239,19 +1181,6 @@ end
local isFriendly = unittype == "FRIENDLY_PLAYER" or unittype == "FRIENDLY_NPC"
local showDebuffsForType = cfg.showdebuffs and (isFriendly and cfg.showdebuffs_friendly or (not isFriendly and cfg.showdebuffs_hostile))
if showDebuffsForType then
-- PERF: Cache verify string - only allocate new string when name/level actually changes
if name ~= plate.cachedVerifyName or level ~= plate.cachedVerifyLevel then
plate.cachedVerifyName = name
plate.cachedVerifyLevel = level
plate.cachedVerify = (name or "") .. ":" .. (level or "")
end
local verify = plate.cachedVerify
-- update cached debuffs
if C.nameplates["guessdebuffs"] == "1" and unitstr then
plate:CacheDebuffs(unitstr, verify)
end
-- Pull debuffs from C_UnitAuras (HARMFUL range). owndebuffs adds the
-- PLAYER filter token so only auras whose caster GUID matches the local
-- player come through. debuffDisplayBuf is a module-level reusable