libpredict: stop the sender's per-frame work

The Regrowth HoT now goes out on a one-shot timer instead of an always-running OnUpdate, and other units' spellcast events are filtered to the group's tokens, the only casters libpredict can resolve; solo, no one else's casts arrive.
This commit is contained in:
Brues
2026-11-01 20:54:40 -06:00
parent 8b239a5532
commit 66171d5354
+42 -63
View File
@@ -134,19 +134,6 @@ local function OnOwnCastStart(spellId, castGUID)
local amount = cache[spell_queue[2]][1]
local casttime = castTime
if spellName == REGROWTH then
local fullSpell = spell_queue[2]
local _, _, rankStr = fullSpell and string.find(fullSpell, "Rank (%d+)")
local rankNum = rankStr and tonumber(rankStr) or nil
if libpredict.sender.regrowth_timer then
libpredict.sender.regrowth_target_next = target
libpredict.sender.regrowth_rank_next = rankNum
else
libpredict.sender.regrowth_target = target
libpredict.sender.regrowth_rank = rankNum
end
end
if spellName == PRAYER_OF_HEALING then
-- target is already correctly set from spell_queue[3]:
-- selfcast (ALT) = player, otherwise = current target
@@ -207,34 +194,35 @@ local function OnOwnCastSucceeded(spellId, castGUID)
libpredict:HealStop(player)
local spellName = C_Spell.GetSpellName(spellId)
if spellName == REGROWTH then
local now = pfUI.uf.now or GetTime()
if libpredict.sender.regrowth_timer then
libpredict.sender.regrowth_start_next = now
else
libpredict.sender.regrowth_start = now
end
libpredict.sender.regrowth_timer = now + 0.1
end
libpredict.sender.castGUID = nil
libpredict.sender.current_cast = nil
libpredict.sender.current_cast_target = nil
if not target then return end
-- Instant HoTs — classify by name (rank-independent) instead of a
-- hardcoded per-rank ID table.
-- HoTs — classify by name (rank-independent) instead of a hardcoded
-- per-rank ID table.
local hotType
if spellName == REJUVENATION then hotType = "Reju"
elseif spellName == RENEW then hotType = "Renew"
elseif spellName == REGROWTH then hotType = "Regr"
end
if hotType then
local duration = hotType == "Reju" and rejuvDuration or renewDuration
local rank = 0
local rankSub = C_Spell.GetSpellSubtext(spellId)
if rankSub and rankSub ~= "" then
rank = tonumber((string.gsub(rankSub, "Rank ", ""))) or 0
end
if hotType == "Regr" then
-- Regrowth's HoT follows its direct heal a moment later
local start = GetTime()
C_Timer.After(0.1, function()
libpredict:Hot(player, target, hotType, 20, start, "UNIT_SPELLCAST_SUCCEEDED", rank)
libpredict.sender:SendHealCommMsg(hotType .. "/" .. target .. "/20/" .. rank .. "/")
end)
return
end
local duration = hotType == "Reju" and rejuvDuration or renewDuration
libpredict:Hot(player, target, hotType, duration, nil, "UNIT_SPELLCAST_SUCCEEDED", rank)
libpredict.sender:SendHealCommMsg(hotType .. "/" .. target .. "/" .. duration .. "/" .. rank .. "/")
end
@@ -932,39 +920,33 @@ libpredict.sender.SendResCommMsg = function(self, msg)
-- BG groups are handled by RAID channel
end
libpredict.sender:SetScript("OnUpdate", function()
-- trigger delayed regrowth timers
local now = pfUI.uf.now or GetTime()
if this.regrowth_timer and now > this.regrowth_timer then
local target = this.regrowth_target or player
local duration = 20
local startTime = this.regrowth_start
local rank = this.regrowth_rank
libpredict:Hot(player, target, "Regr", duration, startTime, "OnUpdate", rank)
local rankStr = rank and tostring(rank) or "0"
libpredict.sender:SendHealCommMsg("Regr/"..target.."/"..duration.."/"..rankStr.."/")
-- Apply next queued Regrowth if available
this.regrowth_target = this.regrowth_target_next
this.regrowth_start = this.regrowth_start_next
this.regrowth_rank = this.regrowth_rank_next
this.regrowth_target_next = nil
this.regrowth_start_next = nil
this.regrowth_rank_next = nil
this.regrowth_timer = nil
-- Own casts arrive as "player". Other casters only matter as group members
-- (the only names resolveNameFromGuid knows), so their events are filtered to
-- the group's tokens, and solo nobody else's casts arrive at all. A member in
-- a raid also fires as raidN for its own casts; the handler drops those by
-- UnitIsUnit, and other repeats by castGUID.
local GROUP_CAST_EVENTS = {
"UNIT_SPELLCAST_START", "UNIT_SPELLCAST_SUCCEEDED", "UNIT_SPELLCAST_INTERRUPTED",
}
local castunits = {}
local function RegisterCastEvents()
local n, token = 0, IsInRaid() and "raid" or "party"
castunits[1] = "player"
for i = 1, IsInRaid() and GetNumRaidMembers() or GetNumPartyMembers() do
castunits[i + 1] = token .. i
n = i
end
end)
-- Own casts arrive as "player"; every other caster fires once per unit token
-- it currently holds (raidN, target, nameplateN, ...), so other-unit handlers
-- drop the repeats by castGUID.
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_SENT")
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_START")
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_DELAYED")
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_FAILED")
libpredict.sender:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
for i = table.getn(castunits), n + 2, -1 do castunits[i] = nil end
for i = 1, table.getn(GROUP_CAST_EVENTS) do
libpredict.sender:RegisterUnitEvent(GROUP_CAST_EVENTS[i], unpack(castunits))
end
end
RegisterCastEvents()
libpredict.sender:RegisterUnitEvent("UNIT_SPELLCAST_SENT", "player")
libpredict.sender:RegisterUnitEvent("UNIT_SPELLCAST_DELAYED", "player")
libpredict.sender:RegisterUnitEvent("UNIT_SPELLCAST_FAILED", "player")
libpredict.sender:RegisterEvent("PARTY_MEMBERS_CHANGED")
libpredict.sender:RegisterEvent("RAID_ROSTER_UPDATE")
libpredict.sender:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
-- Shared cleanup helper for failed/interrupted casts
@@ -980,12 +962,6 @@ local function onCastFailed()
s:SendResCommMsg("RESNO " .. (target or ""))
s.resurrecting = nil
end
if s.current_cast == REGROWTH then
s.regrowth_timer = nil
s.regrowth_start = nil
s.regrowth_target_next = nil
s.regrowth_start_next = nil
end
s.castGUID = nil
s.current_cast = nil
s.current_cast_target = nil
@@ -1041,6 +1017,9 @@ libpredict.sender:SetScript("OnEvent", function()
if arg2 == "SPELL_HEAL" then OnHeal()
elseif arg2 == "SPELL_RESURRECT" then OnResurrect() end
return
elseif event == "PARTY_MEMBERS_CHANGED" or event == "RAID_ROSTER_UPDATE" then
RegisterCastEvents()
return
end
-- UNIT_SPELLCAST_SENT: arg1=unit, arg2=target token, arg3=castGUID, arg4=spellID