Route target/focus castbars through remote UNIT_SPELLCAST_*

ClassicAPI now fires UNIT_SPELLCAST_* for remote tokens (target/focus/...)
via PollRemote, so drop the nampower SPELL_*_OTHER path and drive all three
bars off one event model. The gate is now token-based (arg1 == this.unitstr,
plus the arg1=="player" + UnitIsUnit case for target=self); the RunNextFrame
defer is gone since the remote poll fires after UnitCastingInfo is readable.
Cast detection is now nampower-free across every bar.

Use the event's rank payload (arg5): thread it through RefreshBar into
StampBar, which now only calls C_Spell.GetSpellSubtext as a fallback on the
retarget re-poll (PLAYER_TARGET/FOCUS_CHANGED) where no event is in hand.
This commit is contained in:
Brues
2026-08-01 13:12:33 -05:00
parent 63b9756de2
commit e8764a4b56
+27 -43
View File
@@ -86,7 +86,7 @@ pfUI:RegisterModule("castbar", function ()
-- Stamp the bar with cast data and render text/icon/lag once. OnUpdate -- Stamp the bar with cast data and render text/icon/lag once. OnUpdate
-- then animates the fill from this state without touching C_Spell. -- then animates the fill from this state without touching C_Spell.
local function StampBar(cb, name, tex, startMs, endMs, spellID, isChannel, delayMs, isTradeskill) local function StampBar(cb, name, tex, startMs, endMs, spellID, isChannel, delayMs, isTradeskill, rank)
cb.startTime = startMs cb.startTime = startMs
cb.endTime = endMs cb.endTime = endMs
cb.isChannel = isChannel cb.isChannel = isChannel
@@ -99,10 +99,13 @@ pfUI:RegisterModule("castbar", function ()
cb.bar:SetStatusBarColor(GetStringColor(C.appearance.castbar[isChannel and "channelcolor" or "castbarcolor"])) cb.bar:SetStatusBarColor(GetStringColor(C.appearance.castbar[isChannel and "channelcolor" or "castbarcolor"]))
local rank = "" -- Rank: prefer the value the UNIT_SPELLCAST_* event delivered (arg5, passed
if spellID then -- through by RefreshBar). Only the retarget re-poll has no event in hand, so
-- it falls back to a lookup.
if not rank and spellID then
rank = C_Spell.GetSpellSubtext(spellID) or "" rank = C_Spell.GetSpellSubtext(spellID) or ""
end end
rank = rank or ""
local spellname = (cb.showname and name) and (name .. " ") or "" local spellname = (cb.showname and name) and (name .. " ") or ""
local rankstr = (cb.showrank and rank ~= "") and string.format("|cffaaffcc[%s]|r", rank) or "" local rankstr = (cb.showrank and rank ~= "") and string.format("|cffaaffcc[%s]|r", rank) or ""
cb.bar.left:SetText(spellname .. rankstr) cb.bar.left:SetText(spellname .. rankstr)
@@ -143,7 +146,7 @@ pfUI:RegisterModule("castbar", function ()
-- One-shot poll: read C_Spell for the bar's unit, stamp or clear. Called -- One-shot poll: read C_Spell for the bar's unit, stamp or clear. Called
-- from event handlers (cast start, target/focus change), never per-frame. -- from event handlers (cast start, target/focus change), never per-frame.
local function RefreshBar(cb) local function RefreshBar(cb, rank)
local query = cb.unitstr ~= "" and cb.unitstr or cb.unitname local query = cb.unitstr ~= "" and cb.unitstr or cb.unitname
if not query or (cb.unitstr ~= "" and not UnitExists(cb.unitstr)) then if not query or (cb.unitstr ~= "" and not UnitExists(cb.unitstr)) then
ClearBar(cb) ClearBar(cb)
@@ -166,7 +169,7 @@ pfUI:RegisterModule("castbar", function ()
end end
end end
if name and startMs and endMs then if name and startMs and endMs then
StampBar(cb, name, tex, startMs, endMs, spellID, isChan, delayMs, isTradeskill) StampBar(cb, name, tex, startMs, endMs, spellID, isChan, delayMs, isTradeskill, rank)
else else
ClearBar(cb) ClearBar(cb)
end end
@@ -311,15 +314,14 @@ pfUI:RegisterModule("castbar", function ()
end end
end) end)
-- Cast lifecycle. The player's own casts come from ClassicAPI's -- Cast lifecycle, entirely on ClassicAPI's UNIT_SPELLCAST_* events. They
-- UNIT_SPELLCAST_* (player-only, synthesized engine-side); remote units -- fire per unit token: arg1=="player" for the player's own casts, and the
-- (target/focus not resolving to the player) come from Nampower -- remote token(s) ("target", "focus", ...) for other units -- so one set of
-- SPELL_*_OTHER, gated by the NP_EnableSpell{Start,Go}Events CVars enabled -- events drives every bar with no Nampower dependency. The handler routes an
-- by libdebuff, plus the retarget event. The player feed is registered on -- event to this bar when arg1 matches its unit, or -- since the player's own
-- every bar so target=self / focus=self casts show too (UnitIsUnit gate in -- casts only ever fire arg1=="player" -- when the bar's unit resolves to the
-- the handler). UNIT_SPELLCAST_START fires for chained same-spell recasts, -- player (target=self). PLAYER_TARGET/FOCUS_CHANGED re-polls so a unit
-- pushback and completion, so it replaces the vanilla SPELLCAST_* plus the -- already mid-cast when it becomes the target/focus still shows.
-- nampower SPELL_{START,GO,DELAYED}_SELF workarounds.
cb:RegisterEvent("UNIT_SPELLCAST_START") cb:RegisterEvent("UNIT_SPELLCAST_START")
cb:RegisterEvent("UNIT_SPELLCAST_STOP") cb:RegisterEvent("UNIT_SPELLCAST_STOP")
cb:RegisterEvent("UNIT_SPELLCAST_FAILED") cb:RegisterEvent("UNIT_SPELLCAST_FAILED")
@@ -329,14 +331,10 @@ pfUI:RegisterModule("castbar", function ()
cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START") cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP") cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE") cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
if unitstr ~= "player" and unitstr ~= "" then if unitstr == "target" then
cb:RegisterEvent("SPELL_START_OTHER") cb:RegisterEvent("PLAYER_TARGET_CHANGED")
cb:RegisterEvent("SPELL_FAILED_OTHER") elseif unitstr == "focus" then
if unitstr == "target" then cb:RegisterEvent("PLAYER_FOCUS_CHANGED")
cb:RegisterEvent("PLAYER_TARGET_CHANGED")
elseif unitstr == "focus" then
cb:RegisterEvent("PLAYER_FOCUS_CHANGED")
end
end end
cb:SetScript("OnEvent", function() cb:SetScript("OnEvent", function()
@@ -347,36 +345,22 @@ pfUI:RegisterModule("castbar", function ()
return return
end end
if event == "SPELL_START_OTHER" then -- UNIT_SPELLCAST_* fire per unit token (arg1). Handle an event when it's
-- arg3=casterGuid. Defer one frame so ClassicAPI's UnitChannelInfo -- for this bar's unit, or -- since the player's own casts only ever fire
-- can see the engine's +0x228 broadcast for remote-unit channels -- arg1=="player" -- when this bar's unit currently resolves to the player
-- (the cohook+packet handler runs in the same frame; the broadcast -- (target=self / focus=self).
-- propagates after). -- Args: arg1=unit, arg2=castGUID, arg3=spellID, arg4=name, arg5=rank.
if arg3 == UnitGUID(unit) then if arg1 ~= unit and not (arg1 == "player" and UnitIsUnit(unit, "player")) then
local target = this
RunNextFrame(function() RefreshBar(target) end)
end
return return
end end
if event == "SPELL_FAILED_OTHER" then
if arg1 == UnitGUID(unit) then ClearBar(this, true) end
return
end
-- UNIT_SPELLCAST_* are player-only (arg1 == "player"). Non-player bars
-- consume them only when their unit currently resolves to the player
-- (target=self / focus=self); the remote path is SPELL_*_OTHER above.
-- Args: arg1="player", arg2=castGUID, arg3=spellID, arg4=name, arg5=rank.
if not UnitIsUnit(unit, 'player') then return end
if event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_CHANNEL_START" then if event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_CHANNEL_START" then
-- START also fires per craft in a same-spell chain, so an active merge -- START also fires per craft in a same-spell chain, so an active merge
-- just resyncs the current craft's spark/label instead of restamping. -- just resyncs the current craft's spark/label instead of restamping.
if this.tradeskillTotal then if this.tradeskillTotal then
StartTradeskillCraft(this) StartTradeskillCraft(this)
else else
RefreshBar(this) RefreshBar(this, arg5)
if this.isTradeskill and (this.pendingTradeskillCount or 0) > 1 if this.isTradeskill and (this.pendingTradeskillCount or 0) > 1
and C.castbar.player.mergetradeskill == "1" then and C.castbar.player.mergetradeskill == "1" then
EnterTradeskillMerge(this, this.startTime, this.endTime, this.pendingTradeskillCount) EnterTradeskillMerge(this, this.startTime, this.endTime, this.pendingTradeskillCount)