mirror of
https://github.com/brues-code/pfUI.git
synced 2026-11-03 09:26:57 +00:00
Unit frames: drain update flags on a queued flush, heal prediction from libpredict callbacks, drop the OnUpdate
This commit is contained in:
+172
-175
@@ -362,7 +362,7 @@ pfUI.events:RegisterCallback("aggro:changed", function(_, old, new)
|
||||
if frame.aggro then
|
||||
local guid = UnitGUID(frame.label .. frame.id)
|
||||
if guid and (guid == old or guid == new) then
|
||||
frame.update_combat = true
|
||||
pfUI.uf:QueueUpdate(frame, "combat")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -498,10 +498,18 @@ function pfUI.uf:UpdateVisibility()
|
||||
self.chain = visibility ~= "hide" and unitstr:match("^(.+)target$") or nil
|
||||
if self.chain then
|
||||
local guid = UnitName(unitstr) and UnitGUID(unitstr)
|
||||
if guid ~= self.unitguid then self.update_full = true end
|
||||
if guid ~= self.unitguid then pfUI.uf:QueueUpdate(self, "full") end
|
||||
self.unitguid = guid
|
||||
self:RegisterUnitEvents(guid and CHAIN_TOKENS[unitstr] and unitstr or guid)
|
||||
else
|
||||
-- A pet frame's token gets the pet's unit events, but a new pet behind it
|
||||
-- (summoned, or remapped by raid.lua) comes with none of its own; the
|
||||
-- visibility timer's GUID compare turns it into the full refresh.
|
||||
if self.tick then
|
||||
local guid = UnitGUID(unitstr)
|
||||
if guid ~= self.unitguid then pfUI.uf:QueueUpdate(self, "full") end
|
||||
self.unitguid = guid
|
||||
end
|
||||
self:RegisterUnitEvents(visibility ~= "hide" and unitstr or nil)
|
||||
end
|
||||
self:RegisterChainEvents(self.chain)
|
||||
@@ -786,6 +794,7 @@ function pfUI.uf:UpdateConfig()
|
||||
f.combatfeedback = true
|
||||
else
|
||||
f.feedbackText:Hide()
|
||||
f.feedback:Hide()
|
||||
f.combatfeedback = nil
|
||||
end
|
||||
|
||||
@@ -1035,6 +1044,8 @@ end
|
||||
function pfUI.uf.OnShow()
|
||||
RegisterShownEvents(this)
|
||||
pfUI.uf:RefreshUnit(this, "all")
|
||||
-- flags left from while the frame was off screen, and the portrait's model
|
||||
pfUI.uf:QueueUpdate(this)
|
||||
end
|
||||
|
||||
function pfUI.uf.OnHide()
|
||||
@@ -1051,7 +1062,6 @@ function pfUI.uf.OnEvent()
|
||||
if event == "PLAYER_LOGOUT" then
|
||||
this:UnregisterAllEvents()
|
||||
this:SetScript("OnEvent", nil)
|
||||
this:SetScript("OnUpdate", nil)
|
||||
-- the visibility timer keeps ticking, so leaving this frame on its list
|
||||
-- would have UpdateVisibility re-register the unit events we just
|
||||
-- dropped -- straight back into the crash 132 this branch prevents
|
||||
@@ -1067,13 +1077,13 @@ function pfUI.uf.OnEvent()
|
||||
event == "RAID_ROSTER_UPDATE" or
|
||||
event == "PLAYER_UPDATE_RESTING"
|
||||
then
|
||||
this.update_indicators = true
|
||||
pfUI.uf:QueueUpdate(this, "indicators")
|
||||
end
|
||||
|
||||
-- abort on broken unitframes (e.g focus)
|
||||
if not this.label then return end
|
||||
|
||||
-- a hidden frame runs no OnUpdate, so its unit coming into existence has to
|
||||
-- a hidden frame does not refresh, so its unit coming into existence has to
|
||||
-- show it from here
|
||||
if VISIBILITY_EVENTS[event] then
|
||||
this:UpdateVisibility()
|
||||
@@ -1081,11 +1091,11 @@ function pfUI.uf.OnEvent()
|
||||
|
||||
-- update regular frames
|
||||
if event == "PLAYER_ENTERING_WORLD" then
|
||||
this.update_full = true
|
||||
pfUI.uf:QueueUpdate(this, "full")
|
||||
-- Clear GUID tracking on zone change for full rebuild
|
||||
if pfUI.uf.ClearGuidTracking then pfUI.uf.ClearGuidTracking() end
|
||||
elseif this.label == "target" and event == "PLAYER_TARGET_CHANGED" then
|
||||
this.update_full = true
|
||||
pfUI.uf:QueueUpdate(this, "full")
|
||||
-- immediately update raid icon to avoid delay on target swap
|
||||
if this.raidIcon and this.config and this.config.raidicon == "1" then
|
||||
local raidIcon = UnitName("target") and GetRaidTargetIndex("target")
|
||||
@@ -1104,26 +1114,26 @@ function pfUI.uf.OnEvent()
|
||||
local oldGuid = pfUI.uf.guidTracker.frameToGuid[this]
|
||||
if newGuid ~= oldGuid then
|
||||
pfUI.uf.guidTracker.frameToGuid[this] = newGuid
|
||||
this.update_full = true
|
||||
pfUI.uf:QueueUpdate(this, "full")
|
||||
end
|
||||
else
|
||||
this.update_full = true
|
||||
pfUI.uf:QueueUpdate(this, "full")
|
||||
end
|
||||
elseif ( this.label == "raid" or this.label == "party" ) and event == "RAID_ROSTER_UPDATE" then
|
||||
-- Note: Smart GUID-based updates are handled in raid.lua OnUpdate
|
||||
-- Note: Smart GUID-based updates are handled in raid.lua UpdateRoster
|
||||
-- after frame IDs are reassigned. We don't set update_full here anymore
|
||||
-- for raid frames to avoid the freeze.
|
||||
if this.label == "party" then
|
||||
-- Party frames still need the old logic (no smart tracking yet)
|
||||
this.update_full = true
|
||||
pfUI.uf:QueueUpdate(this, "full")
|
||||
end
|
||||
-- Raid frames: update_full is set by raid.lua GUID tracker
|
||||
elseif this.label == "pet" and event == "UNIT_PET" then
|
||||
this.update_full = true
|
||||
pfUI.uf:QueueUpdate(this, "full")
|
||||
elseif this.label == "player" and (event == "PLAYER_AURAS_CHANGED" or event == "PLAYER_EQUIPMENT_CHANGED") then
|
||||
this.update_aura = true
|
||||
pfUI.uf:QueueUpdate(this, "aura")
|
||||
elseif this.label == "pet" and event == "UNIT_HAPPINESS" then
|
||||
this.update_full = true
|
||||
pfUI.uf:QueueUpdate(this, "full")
|
||||
elseif event == "UNIT_IN_RANGE_UPDATE" then
|
||||
-- registered for the frame's unit alone, and fired in the filter's lower
|
||||
-- case spelling, which a GUID's compare below would miss
|
||||
@@ -1135,211 +1145,194 @@ function pfUI.uf.OnEvent()
|
||||
-- GUID, so filtering on one of the two never wakes the frame twice.
|
||||
elseif arg1 and arg1 == this.eventunit then
|
||||
if event == "UNIT_PORTRAIT_UPDATE" or event == "UNIT_MODEL_CHANGED" then
|
||||
this.update_portrait = true
|
||||
pfUI.uf:QueueUpdate(this, "portrait")
|
||||
elseif event == "UNIT_AURA" then
|
||||
this.update_aura = true
|
||||
pfUI.uf:QueueUpdate(this, "aura")
|
||||
elseif event == "UNIT_AURA_DELTA" then
|
||||
-- an aura that only refreshed or restacked leaves every aura in its
|
||||
-- slot, so the icons need their timers and stacks, not a rebuild
|
||||
if arg2.isFullUpdate or arg2.addedAuraInstanceIDs or arg2.removedAuraInstanceIDs then
|
||||
this.update_aura = true
|
||||
pfUI.uf:QueueUpdate(this, "aura")
|
||||
else
|
||||
this.update_auratime = true
|
||||
pfUI.uf:QueueUpdate(this, "auratime")
|
||||
end
|
||||
elseif event == "UNIT_POWER_UPDATE" or event == "UNIT_MAXPOWER" then
|
||||
-- every power of the unit reports, a cat druid's mana regen too; redraw
|
||||
-- for the one the bar shows, and for mana under a druid mana bar
|
||||
local _, shown = UnitPowerType(arg1)
|
||||
if arg2 == shown or (arg2 == "MANA" and this.druidmana) then
|
||||
this.update_base = true
|
||||
pfUI.uf:QueueUpdate(this, "base")
|
||||
end
|
||||
elseif event == "UNIT_FACTION" then
|
||||
-- the PvP flag, the reaction colour and the tapped grey
|
||||
this.update_indicators = true
|
||||
this.update_base = true
|
||||
pfUI.uf:QueueUpdate(this, "indicators")
|
||||
pfUI.uf:QueueUpdate(this, "base")
|
||||
elseif event == "UNIT_FLAGS" then
|
||||
this.update_combat = true
|
||||
pfUI.uf:QueueUpdate(this, "combat")
|
||||
elseif event == "UNIT_DISTANCE_CHECK_UPDATE" then
|
||||
-- the portrait trades the question mark for the model, the frame fades
|
||||
-- by sight, and an attacker that left with the member is let go
|
||||
this.update_portrait = true
|
||||
this.update_combat = true
|
||||
pfUI.uf:QueueUpdate(this, "portrait")
|
||||
pfUI.uf:QueueUpdate(this, "combat")
|
||||
elseif event == "UNIT_CONNECTION" then
|
||||
this.update_full = true
|
||||
pfUI.uf:QueueUpdate(this, "full")
|
||||
elseif event == "UNIT_COMBAT" then
|
||||
CombatFeedback_OnCombatEvent(arg2, arg3, arg4, arg5)
|
||||
this.feedback:Show()
|
||||
elseif event == "INCOMING_RESURRECT_CHANGED" then
|
||||
this.update_indicators = true
|
||||
pfUI.uf:QueueUpdate(this, "indicators")
|
||||
else
|
||||
this.update_base = true
|
||||
pfUI.uf:QueueUpdate(this, "base")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Local reference for performance
|
||||
local _GetTime = GetTime
|
||||
-- Drain the update flags the events set, then hand a 3D portrait its unit.
|
||||
-- A frame that is not on screen keeps its flags; OnShow flushes them.
|
||||
local function Flush(frame)
|
||||
frame.queued = nil
|
||||
if not frame:IsVisible() then return end
|
||||
|
||||
-- Global cached time for libpredict and other functions
|
||||
pfUI.uf.now = 0
|
||||
|
||||
-- ============================================================================
|
||||
-- OnUpdate - draining the event-set update flags, heal prediction, and the
|
||||
-- two polls no event replaces (a UnitXP range threshold, the pet frames).
|
||||
-- ============================================================================
|
||||
function pfUI.uf.OnUpdate()
|
||||
local now = _GetTime()
|
||||
pfUI.uf.now = now
|
||||
|
||||
-- update combat feedback (no throttle - needs immediate feedback)
|
||||
if this.feedbackText then CombatFeedback_OnUpdate(arg1) end
|
||||
|
||||
-- Throttle raid/party frames for performance
|
||||
if this.label == "raid" or this.label == "party" then
|
||||
if (this.throttleTick or 0) > now then
|
||||
return
|
||||
end
|
||||
this.throttleTick = now + 0.1 -- Default: 10 FPS
|
||||
end
|
||||
|
||||
if this.label then
|
||||
-- what no event reports: a UnitXP range threshold, and the pet frames
|
||||
-- (created with a tick)
|
||||
if this.rangepoll or this.tick then
|
||||
-- Validate tick value - it should be an interval (e.g. 0.5), not a timestamp
|
||||
local tickInterval = this.tick
|
||||
if tickInterval and tickInterval > 10 then
|
||||
-- tick is a timestamp, not an interval - ignore it
|
||||
tickInterval = nil
|
||||
end
|
||||
-- Reset lastTick if it's invalid (much larger than now, e.g. from corrupted state)
|
||||
if this.lastTick and this.lastTick > now + 10 then
|
||||
this.lastTick = nil
|
||||
end
|
||||
if not this.lastTick then this.lastTick = now + (tickInterval or .5) end
|
||||
if this.lastTick < now then
|
||||
local unitstr = this.label .. this.id
|
||||
this.lastTick = now + (tickInterval or .5)
|
||||
|
||||
if this.rangepoll then pfUI.uf:RefreshUnitState(this) end
|
||||
|
||||
-- A pet's full refresh rescans every aura and the portrait, so only
|
||||
-- do it when the unit behind the frame changes or once a second;
|
||||
-- other ticks refresh the bars only.
|
||||
if this.tick then
|
||||
local guid = UnitGUID(unitstr)
|
||||
if guid ~= this.tickGuid or (this.tickFull or 0) < now then
|
||||
this.tickGuid = guid
|
||||
this.tickFull = now + 1
|
||||
pfUI.uf:RefreshUnit(this, "all")
|
||||
else
|
||||
pfUI.uf:RefreshUnit(this, "base")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Heal Prediction (throttled to 0.1s for responsiveness)
|
||||
if libpredict and this.incHeal then
|
||||
if not this.lastHealTick then this.lastHealTick = now end
|
||||
if this.lastHealTick < now then
|
||||
this.lastHealTick = now + 0.1
|
||||
|
||||
local unit = this.label .. this.id
|
||||
local heal = libpredict:UnitGetIncomingHeals(unit)
|
||||
|
||||
local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit)
|
||||
|
||||
if heal - health - maxHealth ~= this.predictstate then
|
||||
local overhealperc = tonumber(this.config.overhealperc)
|
||||
this.predictstate = heal - health - maxHealth
|
||||
|
||||
if heal > 0 and (health < maxHealth or overhealperc > 0 ) then
|
||||
local width = this.config.width
|
||||
local height = this.config.height
|
||||
|
||||
if this.config.verticalbar == "0" then
|
||||
local healthWidth = width * (health / maxHealth)
|
||||
local incWidth = width * heal / maxHealth
|
||||
if healthWidth + incWidth > width * (1+(overhealperc/100)) then
|
||||
incWidth = width * (1+overhealperc/100) - healthWidth
|
||||
end
|
||||
this.incHeal:SetWidth(incWidth)
|
||||
else
|
||||
local healthHeight = height * (health / maxHealth)
|
||||
local incHeight = height * heal / maxHealth
|
||||
if healthHeight + incHeight > height * (1+(overhealperc/100)) then
|
||||
incHeight = height * (1+overhealperc/100) - healthHeight
|
||||
end
|
||||
this.incHeal:SetHeight(incHeight)
|
||||
end
|
||||
|
||||
this.incHeal:Show()
|
||||
else
|
||||
this.incHeal:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
-- EVENT-BASED UPDATES (Health, Mana, Auras, etc.)
|
||||
-- ============================================================================
|
||||
|
||||
|
||||
-- process all queued unit events
|
||||
if this.update_full then
|
||||
if frame.update_full then
|
||||
-- process full updates, indicators and combat state included
|
||||
pfUI.uf:RefreshUnit(this, "all")
|
||||
pfUI.uf:RefreshUnit(frame, "all")
|
||||
|
||||
-- clear update caches
|
||||
this.update_full = nil
|
||||
this.update_base = nil
|
||||
this.update_aura = nil
|
||||
this.update_auratime = nil
|
||||
this.update_portrait = nil
|
||||
this.update_indicators = nil
|
||||
this.update_combat = nil
|
||||
frame.update_full = nil
|
||||
frame.update_base = nil
|
||||
frame.update_aura = nil
|
||||
frame.update_auratime = nil
|
||||
frame.update_portrait = nil
|
||||
frame.update_indicators = nil
|
||||
frame.update_combat = nil
|
||||
else
|
||||
if this.update_indicators then
|
||||
pfUI.uf:RefreshIndicators(this)
|
||||
this.update_indicators = nil
|
||||
if frame.update_indicators then
|
||||
pfUI.uf:RefreshIndicators(frame)
|
||||
frame.update_indicators = nil
|
||||
end
|
||||
|
||||
if this.update_combat then
|
||||
pfUI.uf:RefreshCombat(this)
|
||||
this.update_combat = nil
|
||||
if frame.update_combat then
|
||||
pfUI.uf:RefreshCombat(frame)
|
||||
frame.update_combat = nil
|
||||
end
|
||||
|
||||
-- process individual events; a rebuild re-times the icons as well
|
||||
if this.update_aura then
|
||||
pfUI.uf:RefreshUnit(this, "aura")
|
||||
this.update_aura = nil
|
||||
this.update_auratime = nil
|
||||
this.update_base = true
|
||||
elseif this.update_auratime then
|
||||
pfUI.uf:RefreshUnit(this, "auratime")
|
||||
this.update_auratime = nil
|
||||
if frame.update_aura then
|
||||
pfUI.uf:RefreshUnit(frame, "aura")
|
||||
frame.update_aura = nil
|
||||
frame.update_auratime = nil
|
||||
frame.update_base = true
|
||||
elseif frame.update_auratime then
|
||||
pfUI.uf:RefreshUnit(frame, "auratime")
|
||||
frame.update_auratime = nil
|
||||
end
|
||||
|
||||
if this.update_portrait then
|
||||
pfUI.uf:RefreshUnit(this, "portrait")
|
||||
this.update_portrait = nil
|
||||
this.update_base = true
|
||||
if frame.update_portrait then
|
||||
pfUI.uf:RefreshUnit(frame, "portrait")
|
||||
frame.update_portrait = nil
|
||||
frame.update_base = true
|
||||
end
|
||||
|
||||
if this.update_base then
|
||||
pfUI.uf:RefreshUnit(this, "base")
|
||||
this.update_base = nil
|
||||
if frame.update_base then
|
||||
pfUI.uf:RefreshUnit(frame, "base")
|
||||
frame.update_base = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- update portrait on first visible frame
|
||||
if this.portrait and this.portrait.model and this.portrait.model.update then
|
||||
this.portrait.model.lastUnit = UnitName(this.portrait.model.update)
|
||||
this.portrait.model:SetUnit(this.portrait.model.update)
|
||||
this.portrait.model:SetCamera(0)
|
||||
this.portrait.model.update = nil
|
||||
-- a model takes its unit only once it is on screen, so it waits for this
|
||||
local model = frame.portrait and frame.portrait.model
|
||||
if model and model.update then
|
||||
model.lastUnit = UnitName(model.update)
|
||||
model:SetUnit(model.update)
|
||||
model:SetCamera(0)
|
||||
model.update = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Flag `kind` ("full", "base", "aura", "auratime", "portrait", "indicators",
|
||||
-- "combat", or nil for none) for the frame's next flush, and schedule that
|
||||
-- flush: the next frame, or within 0.1s for the raid and party frames, which
|
||||
-- batch their bursts.
|
||||
function pfUI.uf:QueueUpdate(frame, kind)
|
||||
if kind then frame["update_" .. kind] = true end
|
||||
if frame.queued then return end
|
||||
frame.queued = true
|
||||
if frame.label == "raid" or frame.label == "party" then
|
||||
C_Timer.After(.1, function() Flush(frame) end)
|
||||
else
|
||||
RunNextFrame(function() Flush(frame) end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Size the incoming-heal overlay from libpredict's heals and the unit's
|
||||
-- health. Runs with the bars (RefreshUnit "base") and when libpredict reports
|
||||
-- the heals on the unit changed.
|
||||
function pfUI.uf:RefreshIncomingHeal(frame)
|
||||
local unit = frame.label .. frame.id
|
||||
local heal = libpredict:UnitGetIncomingHeals(unit)
|
||||
local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit)
|
||||
|
||||
if heal - health - maxHealth == frame.predictstate then return end
|
||||
frame.predictstate = heal - health - maxHealth
|
||||
|
||||
local overhealperc = tonumber(frame.config.overhealperc)
|
||||
if heal > 0 and (health < maxHealth or overhealperc > 0 ) then
|
||||
local width = frame.config.width
|
||||
local height = frame.config.height
|
||||
|
||||
if frame.config.verticalbar == "0" then
|
||||
local healthWidth = width * (health / maxHealth)
|
||||
local incWidth = width * heal / maxHealth
|
||||
if healthWidth + incWidth > width * (1+(overhealperc/100)) then
|
||||
incWidth = width * (1+overhealperc/100) - healthWidth
|
||||
end
|
||||
frame.incHeal:SetWidth(incWidth)
|
||||
else
|
||||
local healthHeight = height * (health / maxHealth)
|
||||
local incHeight = height * heal / maxHealth
|
||||
if healthHeight + incHeight > height * (1+(overhealperc/100)) then
|
||||
incHeight = height * (1+overhealperc/100) - healthHeight
|
||||
end
|
||||
frame.incHeal:SetHeight(incHeight)
|
||||
end
|
||||
|
||||
frame.incHeal:Show()
|
||||
else
|
||||
frame.incHeal:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
pfUI.events:RegisterCallback("libpredict:heals", function(_, target)
|
||||
for frame in pairs(visibilityframes) do
|
||||
if frame.namecache == target and frame:IsVisible() then
|
||||
pfUI.uf:RefreshIncomingHeal(frame)
|
||||
end
|
||||
end
|
||||
end, "unitframes")
|
||||
|
||||
-- A UnitXP range threshold has no event, so the frames fading by it poll.
|
||||
C_Timer.NewTicker(.5, function()
|
||||
for frame in pairs(visibilityframes) do
|
||||
if frame.rangepoll and frame:IsVisible() then pfUI.uf:RefreshUnitState(frame) end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Fade the combat feedback text in, hold it, and fade it out -- the timing of
|
||||
-- CombatFeedback_OnUpdate. Runs on a child frame shown only while the text is.
|
||||
local function FeedbackOnUpdate()
|
||||
local frame = this:GetParent()
|
||||
local text = frame.feedbackText
|
||||
local elapsed = GetTime() - frame.feedbackStartTime
|
||||
local fadein, hold = COMBATFEEDBACK_FADEINTIME, COMBATFEEDBACK_HOLDTIME
|
||||
if elapsed < fadein then
|
||||
text:SetAlpha(elapsed / fadein)
|
||||
elseif elapsed < fadein + hold then
|
||||
text:SetAlpha(1)
|
||||
elseif elapsed < fadein + hold + COMBATFEEDBACK_FADEOUTTIME then
|
||||
text:SetAlpha(1 - (elapsed - hold - fadein) / COMBATFEEDBACK_FADEOUTTIME)
|
||||
else
|
||||
text:Hide()
|
||||
this:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1528,7 +1521,6 @@ function pfUI.uf:EnableScripts()
|
||||
f:SetScript("OnShow", pfUI.uf.OnShow)
|
||||
f:SetScript("OnHide", pfUI.uf.OnHide)
|
||||
f:SetScript("OnEvent", pfUI.uf.OnEvent)
|
||||
f:SetScript("OnUpdate", pfUI.uf.OnUpdate)
|
||||
|
||||
visibilityframes[f] = true
|
||||
end
|
||||
@@ -1662,6 +1654,9 @@ function pfUI.uf:CreateUnitFrame(unit, id, config, tick)
|
||||
f.portrait.model = CreateFrame("PlayerModel", "pfPortraitModel" .. f.label .. f.id, f.portrait)
|
||||
f.portrait.model.next = CreateFrame("PlayerModel", nil, nil)
|
||||
f.feedbackText = f:CreateFontString("pfHitIndicator" .. f.label .. f.id, "OVERLAY", "NumberFontNormalHuge")
|
||||
f.feedback = CreateFrame("Frame", nil, f)
|
||||
f.feedback:Hide()
|
||||
f.feedback:SetScript("OnUpdate", FeedbackOnUpdate)
|
||||
|
||||
if f.label == "raid" and mod(f.id, 5) == 1 then
|
||||
local group = math.ceil(f.id/5)
|
||||
@@ -2251,6 +2246,7 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
unit.portrait.model.update = unitstr
|
||||
end
|
||||
end
|
||||
if unit.portrait.model.update then pfUI.uf:QueueUpdate(unit) end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2391,6 +2387,7 @@ function pfUI.uf:RefreshUnit(unit, component)
|
||||
|
||||
if unit.druidmana then pfUI.uf:UpdateDruidMana(unit) end
|
||||
|
||||
pfUI.uf:RefreshIncomingHeal(unit)
|
||||
pfUI.uf:RefreshUnitState(unit)
|
||||
end
|
||||
end
|
||||
|
||||
+29
-15
@@ -36,6 +36,18 @@ local sentTargets = {} -- [castGUID] = target name of an own cast, from UNIT_
|
||||
local resOffers = {} -- [guid] = expiry of a landed resurrection the target has yet to accept
|
||||
local RES_OFFER_TIMEOUT = 60 -- the target's resurrect popup declines itself after 60s
|
||||
|
||||
-- Tell the listeners of "libpredict:heals" that the heals on `target` (a
|
||||
-- name) changed, and again at `expiry`, when a heal that is never stopped
|
||||
-- drops out of UnitGetIncomingHeals.
|
||||
local function HealsChanged(target, expiry)
|
||||
pfUI.events:TriggerEvent("libpredict:heals", target)
|
||||
if expiry then
|
||||
C_Timer.After(expiry - GetTime(), function()
|
||||
pfUI.events:TriggerEvent("libpredict:heals", target)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Localized spell names resolved once from canonical rank-1 spellIDs.
|
||||
-- Every rank shares the same name, so per-rank comparisons elsewhere can
|
||||
-- be done against these constants without per-locale or per-rank tables.
|
||||
@@ -309,7 +321,7 @@ end
|
||||
local function RefreshResFrames(guid)
|
||||
for _, frame in pairs(pfUI.uf.frames) do
|
||||
if frame.unitstr and UnitGUID(frame.unitstr) == guid then
|
||||
frame.update_indicators = true
|
||||
pfUI.uf:QueueUpdate(frame, "indicators")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -439,7 +451,7 @@ function libpredict:ParseChatMessage(sender, msg)
|
||||
end
|
||||
elseif msgtype == "Hot" then
|
||||
-- Duplicate check: ignore same sender+target+spell within DUPLICATE_WINDOW
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local now = GetTime()
|
||||
local key = sender .. target .. heal
|
||||
if recentHots[key] and (now - recentHots[key]) < DUPLICATE_WINDOW then
|
||||
if libpredict.debug then
|
||||
@@ -484,11 +496,11 @@ function libpredict:Heal(sender, target, amount, duration, senderGuid)
|
||||
return
|
||||
end
|
||||
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local timeout = duration/1000 + now
|
||||
local timeout = duration/1000 + GetTime()
|
||||
heals[target] = heals[target] or {}
|
||||
heals[target][sender] = { amount, timeout }
|
||||
if senderGuid then healGuidToName[senderGuid] = sender end
|
||||
HealsChanged(target, timeout)
|
||||
end
|
||||
|
||||
-- Debug flag
|
||||
@@ -512,7 +524,7 @@ function libpredict:Hot(sender, target, spell, duration, startTime, source, rank
|
||||
local existingRank = tonumber(existing.rank) or 0
|
||||
local newRank = tonumber(rank) or 0
|
||||
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local now = GetTime()
|
||||
local existingTimeleft = (existing.start + existing.duration) - now
|
||||
|
||||
-- If existing HoT is still active and has higher rank, don't overwrite
|
||||
@@ -525,7 +537,7 @@ function libpredict:Hot(sender, target, spell, duration, startTime, source, rank
|
||||
end
|
||||
end
|
||||
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local now = GetTime()
|
||||
hots[target][spell].duration = duration
|
||||
hots[target][spell].start = startTime or now
|
||||
hots[target][spell].rank = rank -- Store rank for protection
|
||||
@@ -544,7 +556,7 @@ function libpredict:Hot(sender, target, spell, duration, startTime, source, rank
|
||||
if pfUI and pfUI.uf and pfUI.uf.frames then
|
||||
for _, frame in pairs(pfUI.uf.frames) do
|
||||
if frame.namecache == target then
|
||||
frame.update_aura = true
|
||||
pfUI.uf:QueueUpdate(frame, "aura")
|
||||
if libpredict.debug then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(" |cff00ff00-> Frame update triggered for " .. (frame:GetName() or "?") .. "|r")
|
||||
end
|
||||
@@ -558,6 +570,7 @@ function libpredict:HealStop(sender)
|
||||
for tsender in pairs(heals[ttarget]) do
|
||||
if sender == tsender then
|
||||
heals[ttarget][tsender] = nil
|
||||
HealsChanged(ttarget)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -573,6 +586,7 @@ function libpredict:HealDelay(sender, delay)
|
||||
for tsender, amount in pairs(heals[target]) do
|
||||
if sender == tsender then
|
||||
amount[2] = amount[2] + delay
|
||||
HealsChanged(target, amount[2])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -588,7 +602,7 @@ function libpredict:UnitGetIncomingHeals(unit)
|
||||
if not heals[name] then
|
||||
return sumheal
|
||||
else
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local now = GetTime()
|
||||
for sender, amount in pairs(heals[name]) do
|
||||
if amount[2] <= now then
|
||||
heals[name][sender] = nil
|
||||
@@ -720,7 +734,7 @@ hooksecurefunc("CastSpell", function(id, bookType)
|
||||
|
||||
if effect == REJUVENATION then
|
||||
local target = spell_queue[3]
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local now = GetTime()
|
||||
local key = "Reju" .. target
|
||||
|
||||
-- Cooldown-Check
|
||||
@@ -737,7 +751,7 @@ hooksecurefunc("CastSpell", function(id, bookType)
|
||||
libpredict.sender:SendHealCommMsg("Reju/"..target.."/"..rejuvDuration.."/"..rankStr.."/")
|
||||
elseif effect == RENEW then
|
||||
local target = spell_queue[3]
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local now = GetTime()
|
||||
local key = "Renew" .. target
|
||||
|
||||
-- Cooldown-Check
|
||||
@@ -783,7 +797,7 @@ hooksecurefunc("CastSpellByName", function(effect, target)
|
||||
|
||||
if effect == REJUVENATION then
|
||||
local hotTarget = target or default
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local now = GetTime()
|
||||
local key = "Reju" .. hotTarget
|
||||
|
||||
-- Cooldown-Check
|
||||
@@ -800,7 +814,7 @@ hooksecurefunc("CastSpellByName", function(effect, target)
|
||||
libpredict.sender:SendHealCommMsg("Reju/"..hotTarget.."/"..rejuvDuration.."/"..rankStr.."/")
|
||||
elseif effect == RENEW then
|
||||
local hotTarget = target or default
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local now = GetTime()
|
||||
local key = "Renew" .. hotTarget
|
||||
|
||||
-- Cooldown-Check
|
||||
@@ -843,7 +857,7 @@ hooksecurefunc("UseAction", function(slot, target, selfcast)
|
||||
|
||||
if effect == REJUVENATION then
|
||||
local hotTarget = spell_queue[3]
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local now = GetTime()
|
||||
local key = "Reju" .. hotTarget
|
||||
|
||||
-- Cooldown-Check
|
||||
@@ -860,7 +874,7 @@ hooksecurefunc("UseAction", function(slot, target, selfcast)
|
||||
libpredict.sender:SendHealCommMsg("Reju/"..hotTarget.."/"..rejuvDuration.."/"..rankStr.."/")
|
||||
elseif effect == RENEW then
|
||||
local hotTarget = spell_queue[3]
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local now = GetTime()
|
||||
local key = "Renew" .. hotTarget
|
||||
|
||||
-- Cooldown-Check
|
||||
@@ -1083,7 +1097,7 @@ function libpredict:GetHotDuration(unit, spell)
|
||||
|
||||
-- FALLBACK: the HealComm/cast-fed table, for HoTs C_UnitAuras has no timer for
|
||||
local start, duration, timeleft
|
||||
local now = pfUI.uf.now or GetTime()
|
||||
local now = GetTime()
|
||||
|
||||
local unitName = UnitName(unit)
|
||||
local unitdata = hots[unitName]
|
||||
|
||||
@@ -112,18 +112,6 @@ pfUI:RegisterModule("player", function ()
|
||||
UpdateInfoText()
|
||||
end
|
||||
|
||||
-- Add throttle to player frame OnUpdate
|
||||
-- Throttle the unit frame's existing OnUpdate to ~20 FPS so the per-frame
|
||||
-- work stays cheap.
|
||||
if pfUI.uf.player:GetScript("OnUpdate") then
|
||||
local originalOnUpdate = pfUI.uf.player:GetScript("OnUpdate")
|
||||
pfUI.uf.player:SetScript("OnUpdate", function()
|
||||
if (this.throttleTick or 0) > GetTime() then return end
|
||||
this.throttleTick = GetTime() + 0.05
|
||||
originalOnUpdate()
|
||||
end)
|
||||
end
|
||||
|
||||
-- PLAYER_DAMAGE_DONE_MODS fires on the MOD_DAMAGE_DONE fields that
|
||||
-- GetSpellBonusDamage reads, so gear, buffs and talents all reach it.
|
||||
pfUI.events:RegisterFrameEventAndCallback("PLAYER_ENTERING_WORLD", UpdateInfoText)
|
||||
|
||||
+1
-2
@@ -264,8 +264,7 @@ pfUI:RegisterModule("raid", function ()
|
||||
if newGuid ~= oldGuid then
|
||||
-- GUID changed = different player = need full update
|
||||
tracker.frameToGuid[frame] = newGuid
|
||||
frame.update_full = true
|
||||
frame.update_aura = true -- Force aura refresh!
|
||||
pfUI.uf:QueueUpdate(frame, "full")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user