Reduce debuff tracking hot-path overhead
This commit is contained in:
+93
-24
@@ -17,7 +17,13 @@ if GetLocale() == "ruRU" then
|
||||
end
|
||||
|
||||
local libdebuff = CreateFrame("Frame", "ShaguTweaksDebuffsScanner", UIParent)
|
||||
local scanner = libtipscan:GetScanner("libdebuff")
|
||||
local scanner
|
||||
local function GetScanner()
|
||||
if not scanner then
|
||||
scanner = libtipscan:GetScanner("libdebuff")
|
||||
end
|
||||
return scanner
|
||||
end
|
||||
local _, class = UnitClass("player")
|
||||
local lastspell
|
||||
|
||||
@@ -81,11 +87,12 @@ function libdebuff:AddPending(unit, unitlevel, effect, duration)
|
||||
if not unit then return end
|
||||
if not L["debuffs"][effect] then return end
|
||||
|
||||
duration = duration or libdebuff:GetDuration(effect)
|
||||
if duration > 0 and libdebuff.pending[3] ~= effect then
|
||||
libdebuff.pending[1] = unit
|
||||
libdebuff.pending[2] = unitlevel or 0
|
||||
libdebuff.pending[3] = effect
|
||||
libdebuff.pending[4] = duration or libdebuff:GetDuration(effect)
|
||||
libdebuff.pending[4] = duration
|
||||
end
|
||||
end
|
||||
|
||||
@@ -110,7 +117,7 @@ function libdebuff:RevertLastAction()
|
||||
libdebuff:UpdateUnits()
|
||||
end
|
||||
|
||||
function libdebuff:AddEffect(unit, unitlevel, effect, duration)
|
||||
function libdebuff:AddEffect(unit, unitlevel, effect, duration, deferUpdate)
|
||||
if not unit or not effect then return end
|
||||
unitlevel = unitlevel or 0
|
||||
if not libdebuff.objects[unit] then libdebuff.objects[unit] = {} end
|
||||
@@ -125,12 +132,22 @@ function libdebuff:AddEffect(unit, unitlevel, effect, duration)
|
||||
libdebuff.objects[unit][unitlevel][effect].start = GetTime()
|
||||
libdebuff.objects[unit][unitlevel][effect].duration = duration or libdebuff:GetDuration(effect)
|
||||
|
||||
libdebuff:UpdateUnits()
|
||||
if not deferUpdate then
|
||||
libdebuff:UpdateUnits()
|
||||
end
|
||||
end
|
||||
|
||||
-- scan for debuff application
|
||||
libdebuff:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE")
|
||||
libdebuff:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE")
|
||||
-- ClassicAPI exposes aura identity and timing directly. The old periodic
|
||||
-- combat-text parser only exists to reconstruct off-target applications on
|
||||
-- older ClassicAPI builds; current ClassicAPI does not register those noisy
|
||||
-- events at all.
|
||||
if not (API and API.aurapositional and API.UnitDebuff) then
|
||||
libdebuff:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE")
|
||||
libdebuff:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE")
|
||||
end
|
||||
|
||||
-- These events still support the legacy estimated-duration fallback when an
|
||||
-- exact expiration time is unavailable.
|
||||
libdebuff:RegisterEvent("CHAT_MSG_SPELL_FAILED_LOCALPLAYER")
|
||||
libdebuff:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE")
|
||||
libdebuff:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||||
@@ -183,25 +200,40 @@ libdebuff:SetScript("OnEvent", function()
|
||||
|
||||
-- Add Missing Buffs by Iteration
|
||||
elseif ( event == "UNIT_AURA" and arg1 == "target" ) or event == "PLAYER_TARGET_CHANGED" then
|
||||
local unit = UnitName("target")
|
||||
if not unit then return end
|
||||
|
||||
local unitlevel = UnitLevel("target") or 0
|
||||
local changed = false
|
||||
|
||||
for i=1, 16 do
|
||||
local effect, rank, texture, stacks, dtype, duration, timeleft = libdebuff:UnitDebuff("target", i)
|
||||
|
||||
-- abort when no further debuff was found
|
||||
if not texture then return end
|
||||
if not texture then break end
|
||||
|
||||
if texture and effect and effect ~= "" then
|
||||
-- don't overwrite existing timers
|
||||
local unitlevel = UnitLevel("target") or 0
|
||||
local unit = UnitName("target")
|
||||
if effect and effect ~= "" then
|
||||
-- Don't overwrite existing timers. Defer the expensive target-frame
|
||||
-- refresh until the complete aura pass is done.
|
||||
if not libdebuff.objects[unit] or not libdebuff.objects[unit][unitlevel] or not libdebuff.objects[unit][unitlevel][effect] then
|
||||
libdebuff:AddEffect(unit, unitlevel, effect)
|
||||
libdebuff:AddEffect(unit, unitlevel, effect, nil, true)
|
||||
changed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if changed then
|
||||
libdebuff:UpdateUnits()
|
||||
end
|
||||
|
||||
-- Update Pending Spells
|
||||
elseif event == "CHAT_MSG_SPELL_FAILED_LOCALPLAYER" or event == "CHAT_MSG_SPELL_SELF_DAMAGE" then
|
||||
-- Remove pending spell
|
||||
-- Most combat messages cannot affect libdebuff. Avoid running the whole
|
||||
-- miss/resist/immune pattern set unless there is state to repair.
|
||||
if not libdebuff.pending[3] and not (lastspell and lastspell.start_old) then
|
||||
return
|
||||
end
|
||||
|
||||
for _, msg in pairs(libdebuff.rp) do
|
||||
local effect = cmatch(arg1, msg)
|
||||
if effect and libdebuff.pending[3] == effect then
|
||||
@@ -215,28 +247,64 @@ libdebuff:SetScript("OnEvent", function()
|
||||
end
|
||||
end
|
||||
elseif event == "SPELLCAST_STOP" then
|
||||
QueueFunction(libdebuff.PersistPending)
|
||||
if libdebuff.pending[3] then
|
||||
QueueFunction(libdebuff.PersistPending)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Gather Data by User Actions
|
||||
hooksecurefunc("CastSpell", function(id, bookType)
|
||||
local effect = GetSpellName(id, bookType)
|
||||
local _, rank = libspell.GetSpellInfo(id, bookType)
|
||||
local effect, rank = GetSpellName(id, bookType)
|
||||
if not effect or not L["debuffs"][effect] then return end
|
||||
|
||||
local duration = libdebuff:GetDuration(effect, rank)
|
||||
libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration)
|
||||
end)
|
||||
|
||||
hooksecurefunc("CastSpellByName", function(effect, target)
|
||||
local _, rank = libspell.GetSpellInfo(effect)
|
||||
local duration = libdebuff:GetDuration(effect, rank)
|
||||
libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration)
|
||||
if not effect then return end
|
||||
|
||||
-- Strip an explicit rank before checking the duration database. Reject
|
||||
-- ordinary damage/heal casts before doing any spell metadata work.
|
||||
local _, _, baseEffect, explicitRank = string.find(effect, "(.+)%((.+)%)")
|
||||
local name = baseEffect or effect
|
||||
if not L["debuffs"][name] then return end
|
||||
if libdebuff.pending[3] == name then return end
|
||||
|
||||
local rank = explicitRank
|
||||
if not rank then
|
||||
_, rank = libspell.GetSpellInfo(name)
|
||||
end
|
||||
|
||||
local duration = libdebuff:GetDuration(name, rank)
|
||||
libdebuff:AddPending(UnitName("target"), UnitLevel("target"), name, duration)
|
||||
end)
|
||||
|
||||
hooksecurefunc("UseAction", function(slot, target, button)
|
||||
-- Macros are intentionally left to CastSpellByName: conditional macros can
|
||||
-- select a different spell than their first /cast line.
|
||||
if API and API.actioninfo and API.GetActionInfo then
|
||||
local actionType, actionID = API.GetActionInfo(slot)
|
||||
if actionType == "macro" or actionType == "item" then return end
|
||||
|
||||
if actionType == "spell" and actionID then
|
||||
if not IsCurrentAction(slot) then return end
|
||||
local effect, rank = API.GetSpellInfo(actionID)
|
||||
if not effect or not L["debuffs"][effect] then return end
|
||||
local duration = libdebuff:GetDuration(effect, rank)
|
||||
libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration)
|
||||
return
|
||||
elseif actionType then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if GetActionText(slot) or not IsCurrentAction(slot) then return end
|
||||
scanner:SetAction(slot)
|
||||
local effect, rank = scanner:Line(1)
|
||||
local tip = GetScanner()
|
||||
tip:SetAction(slot)
|
||||
local effect, rank = tip:Line(1)
|
||||
if not effect or not L["debuffs"][effect] then return end
|
||||
local duration = libdebuff:GetDuration(effect, rank)
|
||||
libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration)
|
||||
end)
|
||||
@@ -262,8 +330,9 @@ function libdebuff:UnitDebuff(unit, id)
|
||||
end
|
||||
|
||||
if texture and (not effect or effect == "") then
|
||||
scanner:SetUnitDebuff(unit, id)
|
||||
effect = scanner:Line(1) or ""
|
||||
local tip = GetScanner()
|
||||
tip:SetUnitDebuff(unit, id)
|
||||
effect = tip:Line(1) or ""
|
||||
end
|
||||
|
||||
if libdebuff.objects[unitname] and libdebuff.objects[unitname][unitlevel] and libdebuff.objects[unitname][unitlevel][effect] then
|
||||
|
||||
Reference in New Issue
Block a user