mirror of
https://github.com/brues-code/pfUI.git
synced 2026-11-09 03:38:58 +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
|
if frame.aggro then
|
||||||
local guid = UnitGUID(frame.label .. frame.id)
|
local guid = UnitGUID(frame.label .. frame.id)
|
||||||
if guid and (guid == old or guid == new) then
|
if guid and (guid == old or guid == new) then
|
||||||
frame.update_combat = true
|
pfUI.uf:QueueUpdate(frame, "combat")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -498,10 +498,18 @@ function pfUI.uf:UpdateVisibility()
|
|||||||
self.chain = visibility ~= "hide" and unitstr:match("^(.+)target$") or nil
|
self.chain = visibility ~= "hide" and unitstr:match("^(.+)target$") or nil
|
||||||
if self.chain then
|
if self.chain then
|
||||||
local guid = UnitName(unitstr) and UnitGUID(unitstr)
|
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.unitguid = guid
|
||||||
self:RegisterUnitEvents(guid and CHAIN_TOKENS[unitstr] and unitstr or guid)
|
self:RegisterUnitEvents(guid and CHAIN_TOKENS[unitstr] and unitstr or guid)
|
||||||
else
|
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)
|
self:RegisterUnitEvents(visibility ~= "hide" and unitstr or nil)
|
||||||
end
|
end
|
||||||
self:RegisterChainEvents(self.chain)
|
self:RegisterChainEvents(self.chain)
|
||||||
@@ -786,6 +794,7 @@ function pfUI.uf:UpdateConfig()
|
|||||||
f.combatfeedback = true
|
f.combatfeedback = true
|
||||||
else
|
else
|
||||||
f.feedbackText:Hide()
|
f.feedbackText:Hide()
|
||||||
|
f.feedback:Hide()
|
||||||
f.combatfeedback = nil
|
f.combatfeedback = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1035,6 +1044,8 @@ end
|
|||||||
function pfUI.uf.OnShow()
|
function pfUI.uf.OnShow()
|
||||||
RegisterShownEvents(this)
|
RegisterShownEvents(this)
|
||||||
pfUI.uf:RefreshUnit(this, "all")
|
pfUI.uf:RefreshUnit(this, "all")
|
||||||
|
-- flags left from while the frame was off screen, and the portrait's model
|
||||||
|
pfUI.uf:QueueUpdate(this)
|
||||||
end
|
end
|
||||||
|
|
||||||
function pfUI.uf.OnHide()
|
function pfUI.uf.OnHide()
|
||||||
@@ -1051,7 +1062,6 @@ function pfUI.uf.OnEvent()
|
|||||||
if event == "PLAYER_LOGOUT" then
|
if event == "PLAYER_LOGOUT" then
|
||||||
this:UnregisterAllEvents()
|
this:UnregisterAllEvents()
|
||||||
this:SetScript("OnEvent", nil)
|
this:SetScript("OnEvent", nil)
|
||||||
this:SetScript("OnUpdate", nil)
|
|
||||||
-- the visibility timer keeps ticking, so leaving this frame on its list
|
-- the visibility timer keeps ticking, so leaving this frame on its list
|
||||||
-- would have UpdateVisibility re-register the unit events we just
|
-- would have UpdateVisibility re-register the unit events we just
|
||||||
-- dropped -- straight back into the crash 132 this branch prevents
|
-- dropped -- straight back into the crash 132 this branch prevents
|
||||||
@@ -1067,13 +1077,13 @@ function pfUI.uf.OnEvent()
|
|||||||
event == "RAID_ROSTER_UPDATE" or
|
event == "RAID_ROSTER_UPDATE" or
|
||||||
event == "PLAYER_UPDATE_RESTING"
|
event == "PLAYER_UPDATE_RESTING"
|
||||||
then
|
then
|
||||||
this.update_indicators = true
|
pfUI.uf:QueueUpdate(this, "indicators")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- abort on broken unitframes (e.g focus)
|
-- abort on broken unitframes (e.g focus)
|
||||||
if not this.label then return end
|
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
|
-- show it from here
|
||||||
if VISIBILITY_EVENTS[event] then
|
if VISIBILITY_EVENTS[event] then
|
||||||
this:UpdateVisibility()
|
this:UpdateVisibility()
|
||||||
@@ -1081,11 +1091,11 @@ function pfUI.uf.OnEvent()
|
|||||||
|
|
||||||
-- update regular frames
|
-- update regular frames
|
||||||
if event == "PLAYER_ENTERING_WORLD" then
|
if event == "PLAYER_ENTERING_WORLD" then
|
||||||
this.update_full = true
|
pfUI.uf:QueueUpdate(this, "full")
|
||||||
-- Clear GUID tracking on zone change for full rebuild
|
-- Clear GUID tracking on zone change for full rebuild
|
||||||
if pfUI.uf.ClearGuidTracking then pfUI.uf.ClearGuidTracking() end
|
if pfUI.uf.ClearGuidTracking then pfUI.uf.ClearGuidTracking() end
|
||||||
elseif this.label == "target" and event == "PLAYER_TARGET_CHANGED" then
|
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
|
-- immediately update raid icon to avoid delay on target swap
|
||||||
if this.raidIcon and this.config and this.config.raidicon == "1" then
|
if this.raidIcon and this.config and this.config.raidicon == "1" then
|
||||||
local raidIcon = UnitName("target") and GetRaidTargetIndex("target")
|
local raidIcon = UnitName("target") and GetRaidTargetIndex("target")
|
||||||
@@ -1104,26 +1114,26 @@ function pfUI.uf.OnEvent()
|
|||||||
local oldGuid = pfUI.uf.guidTracker.frameToGuid[this]
|
local oldGuid = pfUI.uf.guidTracker.frameToGuid[this]
|
||||||
if newGuid ~= oldGuid then
|
if newGuid ~= oldGuid then
|
||||||
pfUI.uf.guidTracker.frameToGuid[this] = newGuid
|
pfUI.uf.guidTracker.frameToGuid[this] = newGuid
|
||||||
this.update_full = true
|
pfUI.uf:QueueUpdate(this, "full")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
this.update_full = true
|
pfUI.uf:QueueUpdate(this, "full")
|
||||||
end
|
end
|
||||||
elseif ( this.label == "raid" or this.label == "party" ) and event == "RAID_ROSTER_UPDATE" then
|
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
|
-- after frame IDs are reassigned. We don't set update_full here anymore
|
||||||
-- for raid frames to avoid the freeze.
|
-- for raid frames to avoid the freeze.
|
||||||
if this.label == "party" then
|
if this.label == "party" then
|
||||||
-- Party frames still need the old logic (no smart tracking yet)
|
-- Party frames still need the old logic (no smart tracking yet)
|
||||||
this.update_full = true
|
pfUI.uf:QueueUpdate(this, "full")
|
||||||
end
|
end
|
||||||
-- Raid frames: update_full is set by raid.lua GUID tracker
|
-- Raid frames: update_full is set by raid.lua GUID tracker
|
||||||
elseif this.label == "pet" and event == "UNIT_PET" then
|
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
|
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
|
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
|
elseif event == "UNIT_IN_RANGE_UPDATE" then
|
||||||
-- registered for the frame's unit alone, and fired in the filter's lower
|
-- registered for the frame's unit alone, and fired in the filter's lower
|
||||||
-- case spelling, which a GUID's compare below would miss
|
-- 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.
|
-- GUID, so filtering on one of the two never wakes the frame twice.
|
||||||
elseif arg1 and arg1 == this.eventunit then
|
elseif arg1 and arg1 == this.eventunit then
|
||||||
if event == "UNIT_PORTRAIT_UPDATE" or event == "UNIT_MODEL_CHANGED" 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
|
elseif event == "UNIT_AURA" then
|
||||||
this.update_aura = true
|
pfUI.uf:QueueUpdate(this, "aura")
|
||||||
elseif event == "UNIT_AURA_DELTA" then
|
elseif event == "UNIT_AURA_DELTA" then
|
||||||
-- an aura that only refreshed or restacked leaves every aura in its
|
-- an aura that only refreshed or restacked leaves every aura in its
|
||||||
-- slot, so the icons need their timers and stacks, not a rebuild
|
-- slot, so the icons need their timers and stacks, not a rebuild
|
||||||
if arg2.isFullUpdate or arg2.addedAuraInstanceIDs or arg2.removedAuraInstanceIDs then
|
if arg2.isFullUpdate or arg2.addedAuraInstanceIDs or arg2.removedAuraInstanceIDs then
|
||||||
this.update_aura = true
|
pfUI.uf:QueueUpdate(this, "aura")
|
||||||
else
|
else
|
||||||
this.update_auratime = true
|
pfUI.uf:QueueUpdate(this, "auratime")
|
||||||
end
|
end
|
||||||
elseif event == "UNIT_POWER_UPDATE" or event == "UNIT_MAXPOWER" then
|
elseif event == "UNIT_POWER_UPDATE" or event == "UNIT_MAXPOWER" then
|
||||||
-- every power of the unit reports, a cat druid's mana regen too; redraw
|
-- 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
|
-- for the one the bar shows, and for mana under a druid mana bar
|
||||||
local _, shown = UnitPowerType(arg1)
|
local _, shown = UnitPowerType(arg1)
|
||||||
if arg2 == shown or (arg2 == "MANA" and this.druidmana) then
|
if arg2 == shown or (arg2 == "MANA" and this.druidmana) then
|
||||||
this.update_base = true
|
pfUI.uf:QueueUpdate(this, "base")
|
||||||
end
|
end
|
||||||
elseif event == "UNIT_FACTION" then
|
elseif event == "UNIT_FACTION" then
|
||||||
-- the PvP flag, the reaction colour and the tapped grey
|
-- the PvP flag, the reaction colour and the tapped grey
|
||||||
this.update_indicators = true
|
pfUI.uf:QueueUpdate(this, "indicators")
|
||||||
this.update_base = true
|
pfUI.uf:QueueUpdate(this, "base")
|
||||||
elseif event == "UNIT_FLAGS" then
|
elseif event == "UNIT_FLAGS" then
|
||||||
this.update_combat = true
|
pfUI.uf:QueueUpdate(this, "combat")
|
||||||
elseif event == "UNIT_DISTANCE_CHECK_UPDATE" then
|
elseif event == "UNIT_DISTANCE_CHECK_UPDATE" then
|
||||||
-- the portrait trades the question mark for the model, the frame fades
|
-- 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
|
-- by sight, and an attacker that left with the member is let go
|
||||||
this.update_portrait = true
|
pfUI.uf:QueueUpdate(this, "portrait")
|
||||||
this.update_combat = true
|
pfUI.uf:QueueUpdate(this, "combat")
|
||||||
elseif event == "UNIT_CONNECTION" then
|
elseif event == "UNIT_CONNECTION" then
|
||||||
this.update_full = true
|
pfUI.uf:QueueUpdate(this, "full")
|
||||||
elseif event == "UNIT_COMBAT" then
|
elseif event == "UNIT_COMBAT" then
|
||||||
CombatFeedback_OnCombatEvent(arg2, arg3, arg4, arg5)
|
CombatFeedback_OnCombatEvent(arg2, arg3, arg4, arg5)
|
||||||
|
this.feedback:Show()
|
||||||
elseif event == "INCOMING_RESURRECT_CHANGED" then
|
elseif event == "INCOMING_RESURRECT_CHANGED" then
|
||||||
this.update_indicators = true
|
pfUI.uf:QueueUpdate(this, "indicators")
|
||||||
else
|
else
|
||||||
this.update_base = true
|
pfUI.uf:QueueUpdate(this, "base")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Local reference for performance
|
-- Drain the update flags the events set, then hand a 3D portrait its unit.
|
||||||
local _GetTime = GetTime
|
-- 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
|
if frame.update_full then
|
||||||
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
|
|
||||||
-- process full updates, indicators and combat state included
|
-- process full updates, indicators and combat state included
|
||||||
pfUI.uf:RefreshUnit(this, "all")
|
pfUI.uf:RefreshUnit(frame, "all")
|
||||||
|
|
||||||
-- clear update caches
|
-- clear update caches
|
||||||
this.update_full = nil
|
frame.update_full = nil
|
||||||
this.update_base = nil
|
frame.update_base = nil
|
||||||
this.update_aura = nil
|
frame.update_aura = nil
|
||||||
this.update_auratime = nil
|
frame.update_auratime = nil
|
||||||
this.update_portrait = nil
|
frame.update_portrait = nil
|
||||||
this.update_indicators = nil
|
frame.update_indicators = nil
|
||||||
this.update_combat = nil
|
frame.update_combat = nil
|
||||||
else
|
else
|
||||||
if this.update_indicators then
|
if frame.update_indicators then
|
||||||
pfUI.uf:RefreshIndicators(this)
|
pfUI.uf:RefreshIndicators(frame)
|
||||||
this.update_indicators = nil
|
frame.update_indicators = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if this.update_combat then
|
if frame.update_combat then
|
||||||
pfUI.uf:RefreshCombat(this)
|
pfUI.uf:RefreshCombat(frame)
|
||||||
this.update_combat = nil
|
frame.update_combat = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- process individual events; a rebuild re-times the icons as well
|
-- process individual events; a rebuild re-times the icons as well
|
||||||
if this.update_aura then
|
if frame.update_aura then
|
||||||
pfUI.uf:RefreshUnit(this, "aura")
|
pfUI.uf:RefreshUnit(frame, "aura")
|
||||||
this.update_aura = nil
|
frame.update_aura = nil
|
||||||
this.update_auratime = nil
|
frame.update_auratime = nil
|
||||||
this.update_base = true
|
frame.update_base = true
|
||||||
elseif this.update_auratime then
|
elseif frame.update_auratime then
|
||||||
pfUI.uf:RefreshUnit(this, "auratime")
|
pfUI.uf:RefreshUnit(frame, "auratime")
|
||||||
this.update_auratime = nil
|
frame.update_auratime = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
if this.update_portrait then
|
if frame.update_portrait then
|
||||||
pfUI.uf:RefreshUnit(this, "portrait")
|
pfUI.uf:RefreshUnit(frame, "portrait")
|
||||||
this.update_portrait = nil
|
frame.update_portrait = nil
|
||||||
this.update_base = true
|
frame.update_base = true
|
||||||
end
|
end
|
||||||
|
|
||||||
if this.update_base then
|
if frame.update_base then
|
||||||
pfUI.uf:RefreshUnit(this, "base")
|
pfUI.uf:RefreshUnit(frame, "base")
|
||||||
this.update_base = nil
|
frame.update_base = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- update portrait on first visible frame
|
-- a model takes its unit only once it is on screen, so it waits for this
|
||||||
if this.portrait and this.portrait.model and this.portrait.model.update then
|
local model = frame.portrait and frame.portrait.model
|
||||||
this.portrait.model.lastUnit = UnitName(this.portrait.model.update)
|
if model and model.update then
|
||||||
this.portrait.model:SetUnit(this.portrait.model.update)
|
model.lastUnit = UnitName(model.update)
|
||||||
this.portrait.model:SetCamera(0)
|
model:SetUnit(model.update)
|
||||||
this.portrait.model.update = nil
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1528,7 +1521,6 @@ function pfUI.uf:EnableScripts()
|
|||||||
f:SetScript("OnShow", pfUI.uf.OnShow)
|
f:SetScript("OnShow", pfUI.uf.OnShow)
|
||||||
f:SetScript("OnHide", pfUI.uf.OnHide)
|
f:SetScript("OnHide", pfUI.uf.OnHide)
|
||||||
f:SetScript("OnEvent", pfUI.uf.OnEvent)
|
f:SetScript("OnEvent", pfUI.uf.OnEvent)
|
||||||
f:SetScript("OnUpdate", pfUI.uf.OnUpdate)
|
|
||||||
|
|
||||||
visibilityframes[f] = true
|
visibilityframes[f] = true
|
||||||
end
|
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 = CreateFrame("PlayerModel", "pfPortraitModel" .. f.label .. f.id, f.portrait)
|
||||||
f.portrait.model.next = CreateFrame("PlayerModel", nil, nil)
|
f.portrait.model.next = CreateFrame("PlayerModel", nil, nil)
|
||||||
f.feedbackText = f:CreateFontString("pfHitIndicator" .. f.label .. f.id, "OVERLAY", "NumberFontNormalHuge")
|
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
|
if f.label == "raid" and mod(f.id, 5) == 1 then
|
||||||
local group = math.ceil(f.id/5)
|
local group = math.ceil(f.id/5)
|
||||||
@@ -2251,6 +2246,7 @@ function pfUI.uf:RefreshUnit(unit, component)
|
|||||||
unit.portrait.model.update = unitstr
|
unit.portrait.model.update = unitstr
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if unit.portrait.model.update then pfUI.uf:QueueUpdate(unit) end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2391,6 +2387,7 @@ function pfUI.uf:RefreshUnit(unit, component)
|
|||||||
|
|
||||||
if unit.druidmana then pfUI.uf:UpdateDruidMana(unit) end
|
if unit.druidmana then pfUI.uf:UpdateDruidMana(unit) end
|
||||||
|
|
||||||
|
pfUI.uf:RefreshIncomingHeal(unit)
|
||||||
pfUI.uf:RefreshUnitState(unit)
|
pfUI.uf:RefreshUnitState(unit)
|
||||||
end
|
end
|
||||||
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 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
|
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.
|
-- Localized spell names resolved once from canonical rank-1 spellIDs.
|
||||||
-- Every rank shares the same name, so per-rank comparisons elsewhere can
|
-- Every rank shares the same name, so per-rank comparisons elsewhere can
|
||||||
-- be done against these constants without per-locale or per-rank tables.
|
-- be done against these constants without per-locale or per-rank tables.
|
||||||
@@ -309,7 +321,7 @@ end
|
|||||||
local function RefreshResFrames(guid)
|
local function RefreshResFrames(guid)
|
||||||
for _, frame in pairs(pfUI.uf.frames) do
|
for _, frame in pairs(pfUI.uf.frames) do
|
||||||
if frame.unitstr and UnitGUID(frame.unitstr) == guid then
|
if frame.unitstr and UnitGUID(frame.unitstr) == guid then
|
||||||
frame.update_indicators = true
|
pfUI.uf:QueueUpdate(frame, "indicators")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -439,7 +451,7 @@ function libpredict:ParseChatMessage(sender, msg)
|
|||||||
end
|
end
|
||||||
elseif msgtype == "Hot" then
|
elseif msgtype == "Hot" then
|
||||||
-- Duplicate check: ignore same sender+target+spell within DUPLICATE_WINDOW
|
-- 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
|
local key = sender .. target .. heal
|
||||||
if recentHots[key] and (now - recentHots[key]) < DUPLICATE_WINDOW then
|
if recentHots[key] and (now - recentHots[key]) < DUPLICATE_WINDOW then
|
||||||
if libpredict.debug then
|
if libpredict.debug then
|
||||||
@@ -484,11 +496,11 @@ function libpredict:Heal(sender, target, amount, duration, senderGuid)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local now = pfUI.uf.now or GetTime()
|
local timeout = duration/1000 + GetTime()
|
||||||
local timeout = duration/1000 + now
|
|
||||||
heals[target] = heals[target] or {}
|
heals[target] = heals[target] or {}
|
||||||
heals[target][sender] = { amount, timeout }
|
heals[target][sender] = { amount, timeout }
|
||||||
if senderGuid then healGuidToName[senderGuid] = sender end
|
if senderGuid then healGuidToName[senderGuid] = sender end
|
||||||
|
HealsChanged(target, timeout)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Debug flag
|
-- Debug flag
|
||||||
@@ -512,7 +524,7 @@ function libpredict:Hot(sender, target, spell, duration, startTime, source, rank
|
|||||||
local existingRank = tonumber(existing.rank) or 0
|
local existingRank = tonumber(existing.rank) or 0
|
||||||
local newRank = tonumber(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
|
local existingTimeleft = (existing.start + existing.duration) - now
|
||||||
|
|
||||||
-- If existing HoT is still active and has higher rank, don't overwrite
|
-- 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
|
||||||
end
|
end
|
||||||
|
|
||||||
local now = pfUI.uf.now or GetTime()
|
local now = GetTime()
|
||||||
hots[target][spell].duration = duration
|
hots[target][spell].duration = duration
|
||||||
hots[target][spell].start = startTime or now
|
hots[target][spell].start = startTime or now
|
||||||
hots[target][spell].rank = rank -- Store rank for protection
|
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
|
if pfUI and pfUI.uf and pfUI.uf.frames then
|
||||||
for _, frame in pairs(pfUI.uf.frames) do
|
for _, frame in pairs(pfUI.uf.frames) do
|
||||||
if frame.namecache == target then
|
if frame.namecache == target then
|
||||||
frame.update_aura = true
|
pfUI.uf:QueueUpdate(frame, "aura")
|
||||||
if libpredict.debug then
|
if libpredict.debug then
|
||||||
DEFAULT_CHAT_FRAME:AddMessage(" |cff00ff00-> Frame update triggered for " .. (frame:GetName() or "?") .. "|r")
|
DEFAULT_CHAT_FRAME:AddMessage(" |cff00ff00-> Frame update triggered for " .. (frame:GetName() or "?") .. "|r")
|
||||||
end
|
end
|
||||||
@@ -558,6 +570,7 @@ function libpredict:HealStop(sender)
|
|||||||
for tsender in pairs(heals[ttarget]) do
|
for tsender in pairs(heals[ttarget]) do
|
||||||
if sender == tsender then
|
if sender == tsender then
|
||||||
heals[ttarget][tsender] = nil
|
heals[ttarget][tsender] = nil
|
||||||
|
HealsChanged(ttarget)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -573,6 +586,7 @@ function libpredict:HealDelay(sender, delay)
|
|||||||
for tsender, amount in pairs(heals[target]) do
|
for tsender, amount in pairs(heals[target]) do
|
||||||
if sender == tsender then
|
if sender == tsender then
|
||||||
amount[2] = amount[2] + delay
|
amount[2] = amount[2] + delay
|
||||||
|
HealsChanged(target, amount[2])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -588,7 +602,7 @@ function libpredict:UnitGetIncomingHeals(unit)
|
|||||||
if not heals[name] then
|
if not heals[name] then
|
||||||
return sumheal
|
return sumheal
|
||||||
else
|
else
|
||||||
local now = pfUI.uf.now or GetTime()
|
local now = GetTime()
|
||||||
for sender, amount in pairs(heals[name]) do
|
for sender, amount in pairs(heals[name]) do
|
||||||
if amount[2] <= now then
|
if amount[2] <= now then
|
||||||
heals[name][sender] = nil
|
heals[name][sender] = nil
|
||||||
@@ -720,7 +734,7 @@ hooksecurefunc("CastSpell", function(id, bookType)
|
|||||||
|
|
||||||
if effect == REJUVENATION then
|
if effect == REJUVENATION then
|
||||||
local target = spell_queue[3]
|
local target = spell_queue[3]
|
||||||
local now = pfUI.uf.now or GetTime()
|
local now = GetTime()
|
||||||
local key = "Reju" .. target
|
local key = "Reju" .. target
|
||||||
|
|
||||||
-- Cooldown-Check
|
-- Cooldown-Check
|
||||||
@@ -737,7 +751,7 @@ hooksecurefunc("CastSpell", function(id, bookType)
|
|||||||
libpredict.sender:SendHealCommMsg("Reju/"..target.."/"..rejuvDuration.."/"..rankStr.."/")
|
libpredict.sender:SendHealCommMsg("Reju/"..target.."/"..rejuvDuration.."/"..rankStr.."/")
|
||||||
elseif effect == RENEW then
|
elseif effect == RENEW then
|
||||||
local target = spell_queue[3]
|
local target = spell_queue[3]
|
||||||
local now = pfUI.uf.now or GetTime()
|
local now = GetTime()
|
||||||
local key = "Renew" .. target
|
local key = "Renew" .. target
|
||||||
|
|
||||||
-- Cooldown-Check
|
-- Cooldown-Check
|
||||||
@@ -783,7 +797,7 @@ hooksecurefunc("CastSpellByName", function(effect, target)
|
|||||||
|
|
||||||
if effect == REJUVENATION then
|
if effect == REJUVENATION then
|
||||||
local hotTarget = target or default
|
local hotTarget = target or default
|
||||||
local now = pfUI.uf.now or GetTime()
|
local now = GetTime()
|
||||||
local key = "Reju" .. hotTarget
|
local key = "Reju" .. hotTarget
|
||||||
|
|
||||||
-- Cooldown-Check
|
-- Cooldown-Check
|
||||||
@@ -800,7 +814,7 @@ hooksecurefunc("CastSpellByName", function(effect, target)
|
|||||||
libpredict.sender:SendHealCommMsg("Reju/"..hotTarget.."/"..rejuvDuration.."/"..rankStr.."/")
|
libpredict.sender:SendHealCommMsg("Reju/"..hotTarget.."/"..rejuvDuration.."/"..rankStr.."/")
|
||||||
elseif effect == RENEW then
|
elseif effect == RENEW then
|
||||||
local hotTarget = target or default
|
local hotTarget = target or default
|
||||||
local now = pfUI.uf.now or GetTime()
|
local now = GetTime()
|
||||||
local key = "Renew" .. hotTarget
|
local key = "Renew" .. hotTarget
|
||||||
|
|
||||||
-- Cooldown-Check
|
-- Cooldown-Check
|
||||||
@@ -843,7 +857,7 @@ hooksecurefunc("UseAction", function(slot, target, selfcast)
|
|||||||
|
|
||||||
if effect == REJUVENATION then
|
if effect == REJUVENATION then
|
||||||
local hotTarget = spell_queue[3]
|
local hotTarget = spell_queue[3]
|
||||||
local now = pfUI.uf.now or GetTime()
|
local now = GetTime()
|
||||||
local key = "Reju" .. hotTarget
|
local key = "Reju" .. hotTarget
|
||||||
|
|
||||||
-- Cooldown-Check
|
-- Cooldown-Check
|
||||||
@@ -860,7 +874,7 @@ hooksecurefunc("UseAction", function(slot, target, selfcast)
|
|||||||
libpredict.sender:SendHealCommMsg("Reju/"..hotTarget.."/"..rejuvDuration.."/"..rankStr.."/")
|
libpredict.sender:SendHealCommMsg("Reju/"..hotTarget.."/"..rejuvDuration.."/"..rankStr.."/")
|
||||||
elseif effect == RENEW then
|
elseif effect == RENEW then
|
||||||
local hotTarget = spell_queue[3]
|
local hotTarget = spell_queue[3]
|
||||||
local now = pfUI.uf.now or GetTime()
|
local now = GetTime()
|
||||||
local key = "Renew" .. hotTarget
|
local key = "Renew" .. hotTarget
|
||||||
|
|
||||||
-- Cooldown-Check
|
-- 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
|
-- FALLBACK: the HealComm/cast-fed table, for HoTs C_UnitAuras has no timer for
|
||||||
local start, duration, timeleft
|
local start, duration, timeleft
|
||||||
local now = pfUI.uf.now or GetTime()
|
local now = GetTime()
|
||||||
|
|
||||||
local unitName = UnitName(unit)
|
local unitName = UnitName(unit)
|
||||||
local unitdata = hots[unitName]
|
local unitdata = hots[unitName]
|
||||||
|
|||||||
@@ -112,18 +112,6 @@ pfUI:RegisterModule("player", function ()
|
|||||||
UpdateInfoText()
|
UpdateInfoText()
|
||||||
end
|
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
|
-- PLAYER_DAMAGE_DONE_MODS fires on the MOD_DAMAGE_DONE fields that
|
||||||
-- GetSpellBonusDamage reads, so gear, buffs and talents all reach it.
|
-- GetSpellBonusDamage reads, so gear, buffs and talents all reach it.
|
||||||
pfUI.events:RegisterFrameEventAndCallback("PLAYER_ENTERING_WORLD", UpdateInfoText)
|
pfUI.events:RegisterFrameEventAndCallback("PLAYER_ENTERING_WORLD", UpdateInfoText)
|
||||||
|
|||||||
+1
-2
@@ -264,8 +264,7 @@ pfUI:RegisterModule("raid", function ()
|
|||||||
if newGuid ~= oldGuid then
|
if newGuid ~= oldGuid then
|
||||||
-- GUID changed = different player = need full update
|
-- GUID changed = different player = need full update
|
||||||
tracker.frameToGuid[frame] = newGuid
|
tracker.frameToGuid[frame] = newGuid
|
||||||
frame.update_full = true
|
pfUI.uf:QueueUpdate(frame, "full")
|
||||||
frame.update_aura = true -- Force aura refresh!
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user