Reduce debuff tracking hot-path overhead
This commit is contained in:
+93
-24
@@ -17,7 +17,13 @@ if GetLocale() == "ruRU" then
|
|||||||
end
|
end
|
||||||
|
|
||||||
local libdebuff = CreateFrame("Frame", "ShaguTweaksDebuffsScanner", UIParent)
|
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 _, class = UnitClass("player")
|
||||||
local lastspell
|
local lastspell
|
||||||
|
|
||||||
@@ -81,11 +87,12 @@ function libdebuff:AddPending(unit, unitlevel, effect, duration)
|
|||||||
if not unit then return end
|
if not unit then return end
|
||||||
if not L["debuffs"][effect] 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
|
if duration > 0 and libdebuff.pending[3] ~= effect then
|
||||||
libdebuff.pending[1] = unit
|
libdebuff.pending[1] = unit
|
||||||
libdebuff.pending[2] = unitlevel or 0
|
libdebuff.pending[2] = unitlevel or 0
|
||||||
libdebuff.pending[3] = effect
|
libdebuff.pending[3] = effect
|
||||||
libdebuff.pending[4] = duration or libdebuff:GetDuration(effect)
|
libdebuff.pending[4] = duration
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -110,7 +117,7 @@ function libdebuff:RevertLastAction()
|
|||||||
libdebuff:UpdateUnits()
|
libdebuff:UpdateUnits()
|
||||||
end
|
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
|
if not unit or not effect then return end
|
||||||
unitlevel = unitlevel or 0
|
unitlevel = unitlevel or 0
|
||||||
if not libdebuff.objects[unit] then libdebuff.objects[unit] = {} end
|
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].start = GetTime()
|
||||||
libdebuff.objects[unit][unitlevel][effect].duration = duration or libdebuff:GetDuration(effect)
|
libdebuff.objects[unit][unitlevel][effect].duration = duration or libdebuff:GetDuration(effect)
|
||||||
|
|
||||||
libdebuff:UpdateUnits()
|
if not deferUpdate then
|
||||||
|
libdebuff:UpdateUnits()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- scan for debuff application
|
-- ClassicAPI exposes aura identity and timing directly. The old periodic
|
||||||
libdebuff:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE")
|
-- combat-text parser only exists to reconstruct off-target applications on
|
||||||
libdebuff:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE")
|
-- 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_FAILED_LOCALPLAYER")
|
||||||
libdebuff:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE")
|
libdebuff:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE")
|
||||||
libdebuff:RegisterEvent("PLAYER_TARGET_CHANGED")
|
libdebuff:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||||||
@@ -183,25 +200,40 @@ libdebuff:SetScript("OnEvent", function()
|
|||||||
|
|
||||||
-- Add Missing Buffs by Iteration
|
-- Add Missing Buffs by Iteration
|
||||||
elseif ( event == "UNIT_AURA" and arg1 == "target" ) or event == "PLAYER_TARGET_CHANGED" then
|
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
|
for i=1, 16 do
|
||||||
local effect, rank, texture, stacks, dtype, duration, timeleft = libdebuff:UnitDebuff("target", i)
|
local effect, rank, texture, stacks, dtype, duration, timeleft = libdebuff:UnitDebuff("target", i)
|
||||||
|
|
||||||
-- abort when no further debuff was found
|
-- 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
|
if effect and effect ~= "" then
|
||||||
-- don't overwrite existing timers
|
-- Don't overwrite existing timers. Defer the expensive target-frame
|
||||||
local unitlevel = UnitLevel("target") or 0
|
-- refresh until the complete aura pass is done.
|
||||||
local unit = UnitName("target")
|
|
||||||
if not libdebuff.objects[unit] or not libdebuff.objects[unit][unitlevel] or not libdebuff.objects[unit][unitlevel][effect] then
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if changed then
|
||||||
|
libdebuff:UpdateUnits()
|
||||||
|
end
|
||||||
|
|
||||||
-- Update Pending Spells
|
-- Update Pending Spells
|
||||||
elseif event == "CHAT_MSG_SPELL_FAILED_LOCALPLAYER" or event == "CHAT_MSG_SPELL_SELF_DAMAGE" then
|
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
|
for _, msg in pairs(libdebuff.rp) do
|
||||||
local effect = cmatch(arg1, msg)
|
local effect = cmatch(arg1, msg)
|
||||||
if effect and libdebuff.pending[3] == effect then
|
if effect and libdebuff.pending[3] == effect then
|
||||||
@@ -215,28 +247,64 @@ libdebuff:SetScript("OnEvent", function()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif event == "SPELLCAST_STOP" then
|
elseif event == "SPELLCAST_STOP" then
|
||||||
QueueFunction(libdebuff.PersistPending)
|
if libdebuff.pending[3] then
|
||||||
|
QueueFunction(libdebuff.PersistPending)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Gather Data by User Actions
|
-- Gather Data by User Actions
|
||||||
hooksecurefunc("CastSpell", function(id, bookType)
|
hooksecurefunc("CastSpell", function(id, bookType)
|
||||||
local effect = GetSpellName(id, bookType)
|
local effect, rank = GetSpellName(id, bookType)
|
||||||
local _, rank = libspell.GetSpellInfo(id, bookType)
|
if not effect or not L["debuffs"][effect] then return end
|
||||||
|
|
||||||
local duration = libdebuff:GetDuration(effect, rank)
|
local duration = libdebuff:GetDuration(effect, rank)
|
||||||
libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration)
|
libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
hooksecurefunc("CastSpellByName", function(effect, target)
|
hooksecurefunc("CastSpellByName", function(effect, target)
|
||||||
local _, rank = libspell.GetSpellInfo(effect)
|
if not effect then return end
|
||||||
local duration = libdebuff:GetDuration(effect, rank)
|
|
||||||
libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration)
|
-- 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)
|
end)
|
||||||
|
|
||||||
hooksecurefunc("UseAction", function(slot, target, button)
|
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
|
if GetActionText(slot) or not IsCurrentAction(slot) then return end
|
||||||
scanner:SetAction(slot)
|
local tip = GetScanner()
|
||||||
local effect, rank = scanner:Line(1)
|
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)
|
local duration = libdebuff:GetDuration(effect, rank)
|
||||||
libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration)
|
libdebuff:AddPending(UnitName("target"), UnitLevel("target"), effect, duration)
|
||||||
end)
|
end)
|
||||||
@@ -262,8 +330,9 @@ function libdebuff:UnitDebuff(unit, id)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if texture and (not effect or effect == "") then
|
if texture and (not effect or effect == "") then
|
||||||
scanner:SetUnitDebuff(unit, id)
|
local tip = GetScanner()
|
||||||
effect = scanner:Line(1) or ""
|
tip:SetUnitDebuff(unit, id)
|
||||||
|
effect = tip:Line(1) or ""
|
||||||
end
|
end
|
||||||
|
|
||||||
if libdebuff.objects[unitname] and libdebuff.objects[unitname][unitlevel] and libdebuff.objects[unitname][unitlevel][effect] then
|
if libdebuff.objects[unitname] and libdebuff.objects[unitname][unitlevel] and libdebuff.objects[unitname][unitlevel][effect] then
|
||||||
|
|||||||
Reference in New Issue
Block a user