From 5ee511181e4d34a6236c273911aeedb8096eed6e Mon Sep 17 00:00:00 2001 From: scorpzor Date: Wed, 24 Dec 2025 18:16:58 -0500 Subject: [PATCH] HealComm: Add toggle for Absorbs and reduce redundant updates (#94) * HealComm: Add toggle for Absorbs and reduce redundant updates * HealComm: Throttle updates, cache anchors --- ElvUI/Core/ReversibleStatusBar.lua | 26 ++++++--- .../oUF_HealComm4/oUF_HealComm4.lua | 58 +++++++++++++++---- ElvUI/Modules/Nameplates/Elements/Health.lua | 41 ++++++++++++- .../Modules/UnitFrames/Elements/HealComm.lua | 39 ++++++++++++- ElvUI/Settings/Profile.lua | 29 +++++++--- ElvUI_OptionsUI/Nameplates.lua | 6 +- ElvUI_OptionsUI/UnitFrames.lua | 7 ++- 7 files changed, 169 insertions(+), 37 deletions(-) diff --git a/ElvUI/Core/ReversibleStatusBar.lua b/ElvUI/Core/ReversibleStatusBar.lua index 6169aa5..936c232 100644 --- a/ElvUI/Core/ReversibleStatusBar.lua +++ b/ElvUI/Core/ReversibleStatusBar.lua @@ -100,6 +100,8 @@ local reversibleBar = setmetatable({ "Usage: StatusBar:SetMinMaxValues(number, number)" ) + if self.MINVALUE == minValue and self.MAXVALUE == maxValue then return end + if maxValue > minValue then self.MINVALUE = minValue self.MAXVALUE = maxValue @@ -122,6 +124,7 @@ local reversibleBar = setmetatable({ SetValue = function(self, value) assert(type(value) == "number", "Usage: StatusBar:SetValue(number)") if WithinRange(value, self.MINVALUE, self.MAXVALUE) then + if self.VALUE == value then return end self.VALUE = value reversibleBar_Update(self) end @@ -131,6 +134,7 @@ local reversibleBar = setmetatable({ end, SetOrientation = function(self, orientation) if orientation == "HORIZONTAL" or orientation == "VERTICAL" then + if self.ORIENTATION == orientation then return end self.ORIENTATION = orientation reversibleBar_Update(self) end @@ -139,14 +143,18 @@ local reversibleBar = setmetatable({ return self.ORIENTATION end, SetRotatesTexture = function(self, rotate) - self.ROTATE = (rotate ~= nil and rotate ~= false) + local newRotate = (rotate ~= nil and rotate ~= false) + if self.ROTATE == newRotate then return end + self.ROTATE = newRotate reversibleBar_Update(self) end, GetRotatesTexture = function(self) return self.ROTATE end, SetReverseFill = function(self, reverse) - self.REVERSE = (reverse == true) + local newReverse = (reverse == true) + if self.REVERSE == newReverse then return end + self.REVERSE = newReverse reversibleBar_Update(self) end, GetReverseFill = function(self) @@ -154,16 +162,16 @@ local reversibleBar = setmetatable({ end, SetFillStyle = function(self, style) assert(type(style) == "string" or style == nil, "Usage: StatusBar:SetFillStyle(string)") + local newStyle = "STANDARD" if style and style:lower() == "center" then - self.FILLSTYLE = "CENTER" - reversibleBar_Update(self) + newStyle = "CENTER" elseif style and style:lower() == "reverse" then - self.FILLSTYLE = "REVERSE" - reversibleBar_Update(self) - else - self.FILLSTYLE = "STANDARD" - reversibleBar_Update(self) + newStyle = "REVERSE" end + + if self.FILLSTYLE == newStyle then return end + self.FILLSTYLE = newStyle + reversibleBar_Update(self) end, GetFillStyle = function(self) return self.FILLSTYLE diff --git a/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/oUF_HealComm4.lua b/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/oUF_HealComm4.lua index 107569f..ba46dd4 100644 --- a/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/oUF_HealComm4.lua +++ b/ElvUI/Libraries/oUF_Plugins/oUF_HealComm4/oUF_HealComm4.lua @@ -55,6 +55,7 @@ local UnitName = UnitName local UnitGetIncomingHeals = UnitGetIncomingHeals local UnitGetTotalAbsorbs = UnitGetTotalAbsorbs local UnitGetTotalHealAbsorbs = UnitGetTotalHealAbsorbs +local GetTime = GetTime local enabledUF, enabled = {}, nil @@ -62,6 +63,13 @@ local function Update(self) local unit = self.unit local element = self.HealCommBar + local now = GetTime() + local lastUpdate = element.lastUpdate or 0 + if now - lastUpdate < 0.05 then + return + end + element.lastUpdate = now + --[[ Callback: HealthPrediction:PreUpdate(unit) Called before the element has been updated. @@ -74,8 +82,8 @@ local function Update(self) local myIncomingHeal = UnitGetIncomingHeals(unit, UnitName("player")) or 0 local allIncomingHeal = UnitGetIncomingHeals(unit) or 0 - local absorb = UnitGetTotalAbsorbs and UnitGetTotalAbsorbs(unit) or 0 - local healAbsorb = UnitGetTotalHealAbsorbs and UnitGetTotalHealAbsorbs(unit) or 0 + local absorb = (element.absorbs and UnitGetTotalAbsorbs and UnitGetTotalAbsorbs(unit)) or 0 + local healAbsorb = (element.absorbs and UnitGetTotalHealAbsorbs and UnitGetTotalHealAbsorbs(unit)) or 0 local health = UnitHealth(unit) local maxHealth = UnitHealthMax(unit) local maxOverflowHP = maxHealth * element.maxOverflow @@ -110,32 +118,48 @@ local function Update(self) end if element.myBar then - element.myBar:SetMinMaxValues(0, maxHealth) + if element.maxHealth ~= maxHealth then + element.myBar:SetMinMaxValues(0, maxHealth) + end element.myBar:SetValue(myIncomingHeal) element.myBar:Show() end if element.otherBar then - element.otherBar:SetMinMaxValues(0, maxHealth) + if element.maxHealth ~= maxHealth then + element.otherBar:SetMinMaxValues(0, maxHealth) + end element.otherBar:SetValue(otherIncomingHeal) element.otherBar:Show() end if element.absorbBar then - element.absorbBar:SetMinMaxValues(0, maxHealth) - element.absorbBar:SetValue(absorb) - if absorb > 0 then - element.absorbBar:Show() + if element.absorbs then + if element.maxHealth ~= maxHealth then + element.absorbBar:SetMinMaxValues(0, maxHealth) + end + element.absorbBar:SetValue(absorb) + if absorb > 0 then + element.absorbBar:Show() + else + element.absorbBar:Hide() + end else element.absorbBar:Hide() end end if element.healAbsorbBar then - element.healAbsorbBar:SetMinMaxValues(0, maxHealth) - element.healAbsorbBar:SetValue(healAbsorb) - if healAbsorb > 0 then - element.healAbsorbBar:Show() + if element.absorbs then + if element.maxHealth ~= maxHealth then + element.healAbsorbBar:SetMinMaxValues(0, maxHealth) + end + element.healAbsorbBar:SetValue(healAbsorb) + if healAbsorb > 0 then + element.healAbsorbBar:Show() + else + element.healAbsorbBar:Hide() + end else element.healAbsorbBar:Hide() end @@ -154,6 +178,8 @@ local function Update(self) if element.PostUpdate then return element:PostUpdate(unit, myIncomingHeal, otherIncomingHeal, absorb, healAbsorb) end + + element.maxHealth = maxHealth end local function Path(self, ...) @@ -205,6 +231,14 @@ local function Enable(self) element.maxOverflow = 1.05 end + if element.myBar and element.myBar:IsObjectType("StatusBar") and not element.myBar:GetStatusBarTexture() then + element.myBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) + end + + if element.otherBar and element.otherBar:IsObjectType("StatusBar") and not element.otherBar:GetStatusBarTexture() then + element.otherBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) + end + if element.absorbBar and element.absorbBar:IsObjectType("StatusBar") and not element.absorbBar:GetStatusBarTexture() then element.absorbBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) end diff --git a/ElvUI/Modules/Nameplates/Elements/Health.lua b/ElvUI/Modules/Nameplates/Elements/Health.lua index 7a43d8b..8d8c108 100644 --- a/ElvUI/Modules/Nameplates/Elements/Health.lua +++ b/ElvUI/Modules/Nameplates/Elements/Health.lua @@ -135,7 +135,7 @@ end function NP:Update_HealComm(nameplate) local db = NP:PlateDB(nameplate) - if db.health.enable and db.health.healPrediction then + if db.health.enable and db.health.healPrediction and db.health.healPrediction.enable then if not nameplate:IsElementEnabled('HealCommBar') then nameplate:EnableElement('HealCommBar') end @@ -232,6 +232,15 @@ function NP:Construct_HealComm(frame) absorbBar:SetStatusBarTexture(texture) healAbsorbBar:SetStatusBarTexture(texture) + myBar:SetMinMaxValues(0, 1) + myBar:SetValue(0) + otherBar:SetMinMaxValues(0, 1) + otherBar:SetValue(0) + absorbBar:SetMinMaxValues(0, 1) + absorbBar:SetValue(0) + healAbsorbBar:SetMinMaxValues(0, 1) + healAbsorbBar:SetValue(0) + local healPrediction = { myBar = myBar, otherBar = otherBar, @@ -267,6 +276,7 @@ function NP:Configure_HealComm(frame) healPrediction.maxOverflow = 1 + (c.maxOverflow or 0) healPrediction.overflowHeals = c.overflowHeals healPrediction.overflowAbsorbs = c.overflowAbsorbs + healPrediction.absorbs = frame.db.healPrediction.absorbs if healPrediction.allowClippingUpdate then NP:SetVisibility_HealComm(healPrediction) @@ -289,6 +299,13 @@ function NP:Configure_HealComm(frame) absorbBar:SetOrientation(orientation) healAbsorbBar:SetOrientation(orientation) + healPrediction.cachedOrientation = orientation + + myBar._anchorState = nil + otherBar._anchorState = nil + absorbBar._anchorState = nil + healAbsorbBar._anchorState = nil + if orientation == "HORIZONTAL" then local p1 = "LEFT" local p2 = "RIGHT" @@ -364,12 +381,26 @@ function NP:Configure_HealComm(frame) frame.HealCommBar.otherBar:SetStatusBarColor(hpc.others.r, hpc.others.g, hpc.others.b) frame.HealCommBar.absorbBar:SetStatusBarColor(hpc.absorbs.r, hpc.absorbs.g, hpc.absorbs.b, hpc.absorbs.a) frame.HealCommBar.healAbsorbBar:SetStatusBarColor(hpc.healAbsorbs.r, hpc.healAbsorbs.g, hpc.healAbsorbs.b, hpc.healAbsorbs.a) + + if not healPrediction.absorbs then + absorbBar:Hide() + healAbsorbBar:Hide() + end elseif frame:IsElementEnabled('HealComm4') then frame:DisableElement('HealComm4') end end local function AnchorPredictionBar(bar, health, orientation, anchorTexture, hasEnoughSpace, overflowMode, p1, p2, reverseAnchorTexture) + local needsReverse = not overflowMode and not hasEnoughSpace + local anchorKey = orientation .. (overflowMode and "O" or (hasEnoughSpace and "E" or "R")) + if bar._anchorState == anchorKey and bar._reverseFill == needsReverse then + return + end + + bar._anchorState = anchorKey + bar._reverseFill = needsReverse + bar:ClearAllPoints() if orientation == "HORIZONTAL" then @@ -397,8 +428,11 @@ function NP:UpdateHealComm(unit, myIncomingHeal, allIncomingHeal, totalAbsorb, m if not self.frame or not self.health then return end local health = self.health - local healthTexture = self.healthBarTexture or health:GetStatusBarTexture() - local orientation = health:GetOrientation() + local healthTexture = self.healthBarTexture + if not healthTexture then + healthTexture = health:GetStatusBarTexture() + self.healthBarTexture = healthTexture + end local currentHealth = UnitHealth(unit) or 0 local maxHealth = UnitHealthMax(unit) or 1 @@ -406,6 +440,7 @@ function NP:UpdateHealComm(unit, myIncomingHeal, allIncomingHeal, totalAbsorb, m local otherIncomingHeal = allIncomingHeal - myIncomingHeal local totalIncomingHeal = myIncomingHeal + otherIncomingHeal + local orientation = self.cachedOrientation or health:GetOrientation() local p1 = self.anchor1 or (orientation == "HORIZONTAL" and "LEFT" or "BOTTOM") local p2 = self.anchor2 or (orientation == "HORIZONTAL" and "RIGHT" or "TOP") diff --git a/ElvUI/Modules/UnitFrames/Elements/HealComm.lua b/ElvUI/Modules/UnitFrames/Elements/HealComm.lua index b6b9b6a..b0124b6 100644 --- a/ElvUI/Modules/UnitFrames/Elements/HealComm.lua +++ b/ElvUI/Modules/UnitFrames/Elements/HealComm.lua @@ -61,6 +61,15 @@ function UF:Construct_HealComm(frame) absorbBar:SetStatusBarTexture(texture) healAbsorbBar:SetStatusBarTexture(texture) + myBar:SetMinMaxValues(0, 1) + myBar:SetValue(0) + otherBar:SetMinMaxValues(0, 1) + otherBar:SetValue(0) + absorbBar:SetMinMaxValues(0, 1) + absorbBar:SetValue(0) + healAbsorbBar:SetMinMaxValues(0, 1) + healAbsorbBar:SetValue(0) + local healPrediction = { myBar = myBar, otherBar = otherBar, @@ -90,6 +99,7 @@ function UF:Configure_HealComm(frame) healPrediction.maxOverflow = 1 + (c.maxOverflow or 0) healPrediction.overflowHeals = c.overflowHeals healPrediction.overflowAbsorbs = c.overflowAbsorbs + healPrediction.absorbs = frame.db.healPrediction.absorbs if healPrediction.allowClippingUpdate then UF:SetVisibility_HealComm(healPrediction) @@ -117,6 +127,13 @@ function UF:Configure_HealComm(frame) absorbBar:SetOrientation(orientation) healAbsorbBar:SetOrientation(orientation) + healPrediction.cachedOrientation = orientation + + myBar._anchorState = nil + otherBar._anchorState = nil + absorbBar._anchorState = nil + healAbsorbBar._anchorState = nil + if orientation == "HORIZONTAL" then local p1 = "LEFT" local p2 = "RIGHT" @@ -192,12 +209,26 @@ function UF:Configure_HealComm(frame) otherBar:SetStatusBarColor(c.others.r, c.others.g, c.others.b, c.others.a) absorbBar:SetStatusBarColor(c.absorbs.r, c.absorbs.g, c.absorbs.b, c.absorbs.a) healAbsorbBar:SetStatusBarColor(c.healAbsorbs.r, c.healAbsorbs.g, c.healAbsorbs.b, c.healAbsorbs.a) + + if not healPrediction.absorbs then + absorbBar:Hide() + healAbsorbBar:Hide() + end elseif frame:IsElementEnabled("HealComm4") then frame:DisableElement("HealComm4") end end local function AnchorPredictionBar(bar, health, orientation, anchorTexture, hasEnoughSpace, overflowMode, p1, p2, reverseAnchorTexture) + local needsReverse = not overflowMode and not hasEnoughSpace + local anchorKey = orientation .. (overflowMode and "O" or (hasEnoughSpace and "E" or "R")) + if bar._anchorState == anchorKey and bar._reverseFill == needsReverse then + return + end + + bar._anchorState = anchorKey + bar._reverseFill = needsReverse + bar:ClearAllPoints() if orientation == "HORIZONTAL" then @@ -225,8 +256,11 @@ function UF:UpdateHealComm(unit, myIncomingHeal, allIncomingHeal, totalAbsorb, m if not self.frame or not self.health then return end local health = self.health - local healthTexture = self.healthBarTexture or health:GetStatusBarTexture() - local orientation = health:GetOrientation() + local healthTexture = self.healthBarTexture + if not healthTexture then + healthTexture = health:GetStatusBarTexture() + self.healthBarTexture = healthTexture + end local currentHealth = UnitHealth(unit) or 0 local maxHealth = UnitHealthMax(unit) or 1 @@ -234,6 +268,7 @@ function UF:UpdateHealComm(unit, myIncomingHeal, allIncomingHeal, totalAbsorb, m local otherIncomingHeal = allIncomingHeal - myIncomingHeal local totalIncomingHeal = myIncomingHeal + otherIncomingHeal + local orientation = self.cachedOrientation or health:GetOrientation() local p1 = self.anchor1 or (orientation == "HORIZONTAL" and "LEFT" or "BOTTOM") local p2 = self.anchor2 or (orientation == "HORIZONTAL" and "RIGHT" or "TOP") diff --git a/ElvUI/Settings/Profile.lua b/ElvUI/Settings/Profile.lua index a734f48..6987cf5 100644 --- a/ElvUI/Settings/Profile.lua +++ b/ElvUI/Settings/Profile.lua @@ -304,7 +304,10 @@ local NP_Auras = { local NP_Health = { enable = true, - healPrediction = true, + healPrediction = { + enable = true, + absorbs = false, + }, height = 10, useClassColor = true, text = { @@ -1166,7 +1169,8 @@ P.unitframe = { height = 54, lowmana = 30, healPrediction = { - enable = true + enable = true, + absorbs = true, }, threatStyle = "GLOW", smartAuraPosition = "DISABLED", @@ -1449,7 +1453,8 @@ P.unitframe = { smartAuraPosition = "DISABLED", colorOverride = "USE_DEFAULT", healPrediction = { - enable = true + enable = true, + absorbs = false, }, middleClickFocus = true, disableMouseoverGlow = false, @@ -1908,7 +1913,8 @@ P.unitframe = { width = 190, height = 36, healPrediction = { - enable = true + enable = true, + absorbs = false, }, disableMouseoverGlow = false, disableTargetGlow = false, @@ -2208,7 +2214,8 @@ P.unitframe = { width = 130, height = 36, healPrediction = { - enable = true + enable = true, + absorbs = false, }, disableMouseoverGlow = false, disableTargetGlow = true, @@ -2643,7 +2650,8 @@ P.unitframe = { width = 246, height = 47, healPrediction = { - enable = true + enable = true, + absorbs = false, }, colorOverride = "USE_DEFAULT", disableMouseoverGlow = false, @@ -2805,7 +2813,8 @@ P.unitframe = { startFromCenter = false, showPlayer = true, healPrediction = { - enable = true + enable = true, + absorbs = false, }, colorOverride = "USE_DEFAULT", width = 184, @@ -3074,7 +3083,8 @@ P.unitframe = { sortDir = "ASC", showPlayer = true, healPrediction = { - enable = true + enable = true, + absorbs = false, }, colorOverride = "USE_DEFAULT", width = 80, @@ -3271,7 +3281,8 @@ P.unitframe = { sortDir = "ASC", showPlayer = true, healPrediction = { - enable = true + enable = true, + absorbs = false, }, colorOverride = "USE_DEFAULT", width = 80, diff --git a/ElvUI_OptionsUI/Nameplates.lua b/ElvUI_OptionsUI/Nameplates.lua index 908464f..07ae746 100644 --- a/ElvUI_OptionsUI/Nameplates.lua +++ b/ElvUI_OptionsUI/Nameplates.lua @@ -76,7 +76,11 @@ local function GetUnitSettings(unit, name) group.args.healthGroup.args.enable = ACH:Toggle(L["Enable"], nil, 1, nil, nil, nil, nil, nil, nil, function() return unit == 'PLAYER' end) group.args.healthGroup.args.height = ACH:Range(L["Height"], nil, 3, { min = minHeight, max = MaxHeight(unit), step = 1 }) group.args.healthGroup.args.width = ACH:Execute(L["Width"], nil, 4, function() ACD:SelectGroup('ElvUI', 'nameplates', 'generalGroup', 'clickableRange') end) - group.args.healthGroup.args.healPrediction = ACH:Toggle(L["Heal Prediction"], nil, 5) + + group.args.healthGroup.args.healPredictionGroup = ACH:Group(L["Heal Prediction"], nil, 5, nil, function(info) return E.db.nameplates.units[unit].health.healPrediction[info[#info]] end, function(info, value) E.db.nameplates.units[unit].health.healPrediction[info[#info]] = value NP:ConfigureAll() end) + group.args.healthGroup.args.healPredictionGroup.inline = true + group.args.healthGroup.args.healPredictionGroup.args.enable = ACH:Toggle(L["Enable"], nil, 1) + group.args.healthGroup.args.healPredictionGroup.args.absorbs = ACH:Toggle(L["Enable Absorbs"], nil, 2) group.args.healthGroup.args.textGroup = ACH:Group(L["Text"], nil, 200, nil, function(info) return E.db.nameplates.units[unit].health.text[info[#info]] end, function(info, value) E.db.nameplates.units[unit].health.text[info[#info]] = value NP:ConfigureAll() end) group.args.healthGroup.args.textGroup.inline = true diff --git a/ElvUI_OptionsUI/UnitFrames.lua b/ElvUI_OptionsUI/UnitFrames.lua index d7a391f..9f79d88 100644 --- a/ElvUI_OptionsUI/UnitFrames.lua +++ b/ElvUI_OptionsUI/UnitFrames.lua @@ -2349,8 +2349,13 @@ local function GetOptionsTable_HealPrediction(updateFunc, groupName, numGroup) type = "toggle", name = L["Enable"] }, - colors = { + absorbs = { order = 3, + type = "toggle", + name = L["Enable Absorbs"] + }, + colors = { + order = 4, type = "execute", name = L["COLORS"], func = function() ACD:SelectGroup("ElvUI", "unitframe", "generalOptionsGroup", "allColorsGroup", "healPrediction") end,