Files
BlizzNameplatesPlus/modules/otherdebuffs.lua
T
2026-09-30 19:07:47 +02:00

153 lines
5.1 KiB
Lua

BNP = BNP or {}
-- Optional live debuffs from other players/classes.
-- Kept outside auras.lua because that file is already close to Vanilla Lua's
-- per-chunk local-variable limit. This module owns only the foreign live cache;
-- BNP's proven own-cast tracker remains completely separate.
BNP.guidOtherDebuffs = BNP.guidOtherDebuffs or {}
local SEEN = {}
local seenGeneration = 0
function BNP:WantsOtherDebuffs()
return self.AreOtherDebuffsEnabled and self:AreOtherDebuffsEnabled()
and self.HasSelectedOtherDebuffs and self:HasSelectedOtherDebuffs()
and self.OtherDebuffByID ~= nil
end
function BNP:IsOtherDebuffDefSelected(def)
return def and self.IsOtherDebuffSelected and self:IsOtherDebuffSelected(def.key)
end
function BNP:SyncOtherDebuffs(unit, guid, now, snapshot, eventAuthoritative)
if not unit or not guid then return end
if not self:WantsOtherDebuffs() then
self.guidOtherDebuffs[guid] = nil
return
end
seenGeneration = seenGeneration + 1
local generation = seenGeneration
local live = self.guidOtherDebuffs[guid]
local i
local maxIndex = snapshot and snapshot.count or 64
for i = 1, maxIndex do
local texture, stacks, auraSpellID, duration, expirationTime, source
if snapshot then
local entry = snapshot.entries[i]
if not entry then break end
texture = entry[1]
stacks = entry[2]
auraSpellID = entry[4]
duration = entry[5]
expirationTime = entry[6]
source = entry[7]
else
local dtype
texture, stacks, dtype, auraSpellID, duration, expirationTime, source = self:_ReadClassicDebuff(unit, i)
if not texture then break end
end
local def = auraSpellID and self.OtherDebuffByID and self.OtherDebuffByID[auraSpellID] or nil
-- This feature is specifically for auras from other players/classes. When
-- ClassicAPI positively identifies our own source, let the proven own-cast
-- tracker remain the only owner of that icon/timer.
if def and self:IsOtherDebuffDefSelected(def) and not self:_IsOwnClassicAuraSource(source) then
SEEN[def.key] = generation
if not live then
live = {}
self.guidOtherDebuffs[guid] = live
end
local aura = live[def.key]
if not aura then
aura = {
firstSeen = now,
order = def.order or (1000 + i),
}
live[def.key] = aura
end
local previousStacks = tonumber(aura.stacks) or 0
local currentStacks = tonumber(stacks) or 0
aura.def = def
aura.spellID = auraSpellID
aura.texture = texture or (self.GetOtherDebuffTexture and self:GetOtherDebuffTexture(def)) or def.texture
aura.stacks = currentStacks
aura.lastSeen = now
aura.livePresence = true
aura.eventDriven = eventAuthoritative and true or false
aura.missingScans = nil
local fallbackDuration = self.GetOtherDebuffDuration and self:GetOtherDebuffDuration(def, auraSpellID) or def.duration
local liveDuration = tonumber(duration)
local liveExpires = tonumber(expirationTime)
if liveExpires and liveExpires > now then
aura.duration = liveDuration and liveDuration > 0 and liveDuration or fallbackDuration
aura.expires = liveExpires
aura.estimated = nil
elseif not aura.expires then
aura.duration = fallbackDuration
if fallbackDuration and fallbackDuration > 0 then
aura.expires = now + fallbackDuration
aura.estimated = true
end
elseif currentStacks > previousStacks and fallbackDuration and fallbackDuration > 0 then
-- Stack-building raid debuffs commonly refresh their duration when a
-- new stack lands. Only use this estimate when ClassicAPI supplied no
-- authoritative expiration timestamp.
aura.duration = fallbackDuration
aura.expires = now + fallbackDuration
aura.estimated = true
end
end
end
if live then
local key, aura
for key, aura in pairs(live) do
local def = aura and aura.def
if not def or not self:IsOtherDebuffDefSelected(def) then
live[key] = nil
elseif SEEN[key] ~= generation then
aura.missingScans = (aura.missingScans or 0) + 1
if eventAuthoritative or (aura.missingScans >= 3 and now - (aura.lastSeen or 0) >= 0.40) then
live[key] = nil
end
else
aura.missingScans = nil
end
end
end
end
function BNP:RefreshOtherDebuffs()
if not self:AreOtherDebuffsEnabled() then
self.guidOtherDebuffs = {}
else
local guid, live, key, aura
for guid, live in pairs(self.guidOtherDebuffs or {}) do
for key, aura in pairs(live or {}) do
if not aura or not aura.def or not self:IsOtherDebuffSelected(aura.def.key) then
live[key] = nil
end
end
end
end
if self.RefreshDebuffVisibility then self:RefreshDebuffVisibility() end
end
function BNP:ActiveAuraHasSpellID(active, count, spellID)
if not spellID then return false end
local i
for i = 1, count do
local entry = active[i]
if entry and entry.aura and entry.aura.spellID == spellID then return true end
end
return false
end