From f02b0bb47dcd25f4c8fae59ee747eb2b2d2ea76f Mon Sep 17 00:00:00 2001 From: rawoil Date: Mon, 28 Jun 2021 18:04:06 +0800 Subject: [PATCH] 1. fix raid frame shows blizzard default raid frame 2. add healcomm support --- oUF/elements/healthprediction.lua | 109 +- oUF/elements/range.lua | 29 +- .../CallbackHandler-1.0/CallbackHandler-1.0.lua | 212 ++ .../CallbackHandler-1.0/CallbackHandler-1.0.xml | 4 + oUF/libs/LibHealComm-4.0/ChatThrottleLib.lua | 534 ++++ oUF/libs/LibHealComm-4.0/LibHealComm-4.0.lua | 2739 ++++++++++++++++++++ oUF/libs/LibHealComm-4.0/LibHealComm-4.0.xml | 5 + oUF/libs/LibStub/LibStub.lua | 51 + oUF/libs/LibStub/LibStub.toc | 9 + oUF/libs/LibStub/tests/test.lua | 41 + oUF/libs/LibStub/tests/test2.lua | 27 + oUF/libs/LibStub/tests/test3.lua | 14 + oUF/libs/LibStub/tests/test4.lua | 41 + oUF/oUF.toc | 9 +- oUF_Simple/core/functions.lua | 31 +- oUF_Simple/core/spawn.lua | 5 + oUF_Simple/core/style.lua | 1 + oUF_Simple/modules/oUF_Smooth.lua | 53 - oUF_Simple/oUF_Simple.toc | 1 - oUF_Simple/templates/raid.lua | 22 + oUF_SimpleConfig/global.lua | 4 +- 21 files changed, 3865 insertions(+), 76 deletions(-) create mode 100644 oUF/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua create mode 100644 oUF/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml create mode 100644 oUF/libs/LibHealComm-4.0/ChatThrottleLib.lua create mode 100644 oUF/libs/LibHealComm-4.0/LibHealComm-4.0.lua create mode 100644 oUF/libs/LibHealComm-4.0/LibHealComm-4.0.xml create mode 100644 oUF/libs/LibStub/LibStub.lua create mode 100644 oUF/libs/LibStub/LibStub.toc create mode 100644 oUF/libs/LibStub/tests/test.lua create mode 100644 oUF/libs/LibStub/tests/test2.lua create mode 100644 oUF/libs/LibStub/tests/test3.lua create mode 100644 oUF/libs/LibStub/tests/test4.lua delete mode 100644 oUF_Simple/modules/oUF_Smooth.lua diff --git a/oUF/elements/healthprediction.lua b/oUF/elements/healthprediction.lua index 19e61c4..ce19261 100644 --- a/oUF/elements/healthprediction.lua +++ b/oUF/elements/healthprediction.lua @@ -80,6 +80,25 @@ A default texture will be applied to the Texture widgets if they don't have a te local _, ns = ... local oUF = ns.oUF +local myGUID = UnitGUID('player') +local HealComm, ALL_PENDING_HEALS, ALL_OVERTIME_HEALS, HEAL_TICK_INTERVAL + +if oUF.BCC then + HealComm = LibStub("LibHealComm-4.0") + + ALL_PENDING_HEALS = bit.bor(HealComm.DIRECT_HEALS, HealComm.BOMB_HEALS) + ALL_OVERTIME_HEALS = bit.bor(HealComm.CHANNEL_HEALS, HealComm.HOT_HEALS) + HEAL_TICK_INTERVAL = 3 +end + +local function GetHealAmount(targetGUID, currentTime, casterGUID) + local nextTickTime = currentTime + HEAL_TICK_INTERVAL + + local pendingHeal = HealComm:GetHealAmount(targetGUID, ALL_PENDING_HEALS, nil, casterGUID) or 0 + local overtimeHeal = HealComm:GetHealAmount(targetGUID, ALL_OVERTIME_HEALS, nextTickTime, casterGUID) or 0 + + return (pendingHeal + overtimeHeal) * HealComm:GetHealModifier(casterGUID) +end local function Update(self, event, unit) if(self.unit ~= unit) then return end @@ -96,10 +115,13 @@ local function Update(self, event, unit) element:PreUpdate(unit) end - local myIncomingHeal = UnitGetIncomingHeals(unit, 'player') or 0 - local allIncomingHeal = UnitGetIncomingHeals(unit) or 0 - local absorb = UnitGetTotalAbsorbs(unit) or 0 - local healAbsorb = UnitGetTotalHealAbsorbs(unit) or 0 + local guid = UnitGUID(unit) + local currentTime = GetTime() + local isSmoothedEvent = event == "UNIT_MAXHEALTH" or event == "UNIT_HEALTH_FREQUENT" or event == "UNIT_HEALTH" + local myIncomingHeal = oUF.BCC and GetHealAmount(guid, currentTime, myGUID) or UnitGetIncomingHeals(unit, 'player') or 0 + local allIncomingHeal = oUF.BCC and GetHealAmount(guid, currentTime, nil) or UnitGetIncomingHeals(unit) or 0 + local absorb = oUF.Retail and UnitGetTotalAbsorbs(unit) or 0 + local healAbsorb = oUF.Retail and UnitGetTotalHealAbsorbs(unit) or 0 local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit) local otherIncomingHeal = 0 local hasOverHealAbsorb = false @@ -138,15 +160,31 @@ local function Update(self, event, unit) end if(element.myBar) then - element.myBar:SetMinMaxValues(0, maxHealth) - element.myBar:SetValue(myIncomingHeal) - element.myBar:Show() + if element.smoothing then + element.myBar:SetMinMaxSmoothedValue(0, maxHealth) + element.myBar:SetSmoothedValue(myIncomingHeal) + end + + if not element.smoothing or not isSmoothedEvent then + element.myBar:SetMinMaxValues(0, maxHealth) + element.myBar:SetValue(myIncomingHeal) + end + + element.myBar:Show() end if(element.otherBar) then - element.otherBar:SetMinMaxValues(0, maxHealth) - element.otherBar:SetValue(otherIncomingHeal) - element.otherBar:Show() + if element.smoothing then + element.otherBar:SetMinMaxSmoothedValue(0, maxHealth) + element.otherBar:SetSmoothedValue(otherIncomingHeal) + end + + if not element.smoothing or not isSmoothedEvent then + element.otherBar:SetMinMaxValues(0, maxHealth) + element.otherBar:SetValue(otherIncomingHeal) + end + + element.otherBar:Show() end if(element.absorbBar) then @@ -194,7 +232,7 @@ local function Update(self, event, unit) end end -local function Path(self, ...) +local function Path(self, event, ...) --[[ Override: HealthPrediction.Override(self, event, unit) Used to completely override the internal update function. @@ -202,7 +240,16 @@ local function Path(self, ...) * event - the event triggering the update (string) * unit - the unit accompanying the event --]] - return (self.HealthPrediction.Override or Update) (self, ...) + + if not oUF.Retail and self:IsVisible() then + for i = 1, select('#', ...) do + if self.unit and UnitGUID(self.unit) == (UnitGUID(select(i, ...)) or select(i, ...)) then + return (self.HealthPrediction.Override or Update) (self, event, self.unit) + end + end + else + return (self.HealthPrediction.Override or Update) (self, event, ...) + end end local function ForceUpdate(element) @@ -214,24 +261,54 @@ local function Enable(self) if(element) then element.__owner = self element.ForceUpdate = ForceUpdate + + if oUF.Retail then + self:RegisterEvent('UNIT_HEALTH', Path) + self:RegisterEvent('UNIT_HEAL_PREDICTION', Path) + self:RegisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path) + self:RegisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path) + else + self:RegisterEvent('UNIT_HEALTH_FREQUENT', Path) + + local function UpdateHeal(event, casterGUID, spellID, healType, _, ...) + Path(self, event, ...) + end - self:RegisterEvent('UNIT_HEALTH', Path) + local function UpdateModifier(event, guid) + Path(self, event, guid) + end + + HealComm.RegisterCallback(self, "HealComm_HealStarted", UpdateHeal) + HealComm.RegisterCallback(self, "HealComm_HealUpdated", UpdateHeal) + HealComm.RegisterCallback(self, "HealComm_HealDelayed", UpdateHeal) + HealComm.RegisterCallback(self, "HealComm_HealStopped", UpdateHeal) + HealComm.RegisterCallback(self, "HealComm_ModifierChanged", UpdateModifier) + HealComm.RegisterCallback(self, "HealComm_GUIDDisappeared", UpdateModifier) + end + self:RegisterEvent('UNIT_MAXHEALTH', Path) - self:RegisterEvent('UNIT_HEAL_PREDICTION', Path) - self:RegisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path) - self:RegisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path) if(not element.maxOverflow) then element.maxOverflow = 1.05 end if(element.myBar) then + if(element.smoothing) then + element.myBar.SetSmoothedValue = SmoothStatusBarMixin.SetSmoothedValue + element.myBar.SetMinMaxSmoothedValue = SmoothStatusBarMixin.SetMinMaxSmoothedValue + end + if(element.myBar:IsObjectType('StatusBar') and not element.myBar:GetStatusBarTexture()) then element.myBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) end end if(element.otherBar) then + if(element.smoothing) then + element.otherBar.SetSmoothedValue = SmoothStatusBarMixin.SetSmoothedValue + element.otherBar.SetMinMaxSmoothedValue = SmoothStatusBarMixin.SetMinMaxSmoothedValue + end + if(element.otherBar:IsObjectType('StatusBar') and not element.otherBar:GetStatusBarTexture()) then element.otherBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]]) end diff --git a/oUF/elements/range.lua b/oUF/elements/range.lua index 201cab5..f68e920 100644 --- a/oUF/elements/range.lua +++ b/oUF/elements/range.lua @@ -33,6 +33,15 @@ local OnRangeFrame local UnitInRange, UnitIsConnected = UnitInRange, UnitIsConnected +local RangeSpellID = { + ["PALADIN"] = 19750, + ["SHAMAN"] = 25357, + ["DRUID"] = 774, + ["PRIEST"] = 2050, + ["WARLOCK"] = 5697, + ["MAGE"] = 475, +} + local function Update(self, event) local element = self.Range local unit = self.unit @@ -52,8 +61,24 @@ local function Update(self, event) if oUF.Retail then inRange, checkedRange = UnitInRange(unit) else - inRange = CheckInteractDistance(unit, 4) - checkedRange = true + local Spell = RangeSpellID[select(2, UnitClass("player"))] + local IsFriend = UnitIsFriend(unit, "player") + + if IsFriend and Spell and IsSpellKnown(Spell) then + local name, rank, icon, castTime, minRange, maxRange, spellId = GetSpellInfo(Spell) + local IsSpellInRangeFromPlayer = IsSpellInRange(name, unit) + + if IsSpellInRangeFromPlayer == 1 then + inRange = true + checkedRange = true + else + inRange = false + checkedRange = true + end + else + inRange = CheckInteractDistance(unit, 4) + checkedRange = true + end end if(checkedRange and not inRange) then diff --git a/oUF/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua b/oUF/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua new file mode 100644 index 0000000..39e265d --- /dev/null +++ b/oUF/libs/CallbackHandler-1.0/CallbackHandler-1.0.lua @@ -0,0 +1,212 @@ +--[[ $Id: CallbackHandler-1.0.lua 22 2018-07-21 14:17:22Z nevcairiel $ ]] +local MAJOR, MINOR = "CallbackHandler-1.0", 7 +local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR) + +if not CallbackHandler then return end -- No upgrade needed + +local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end} + +-- Lua APIs +local tconcat = table.concat +local assert, error, loadstring = assert, error, loadstring +local setmetatable, rawset, rawget = setmetatable, rawset, rawget +local next, select, pairs, type, tostring = next, select, pairs, type, tostring + +-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded +-- List them here for Mikk's FindGlobals script +-- GLOBALS: geterrorhandler + +local xpcall = xpcall + +local function errorhandler(err) + return geterrorhandler()(err) +end + +local function Dispatch(handlers, ...) + local index, method = next(handlers) + if not method then return end + repeat + xpcall(method, errorhandler, ...) + index, method = next(handlers, index) + until not method +end + +-------------------------------------------------------------------------- +-- CallbackHandler:New +-- +-- target - target object to embed public APIs in +-- RegisterName - name of the callback registration API, default "RegisterCallback" +-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback" +-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API. + +function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName) + + RegisterName = RegisterName or "RegisterCallback" + UnregisterName = UnregisterName or "UnregisterCallback" + if UnregisterAllName==nil then -- false is used to indicate "don't want this method" + UnregisterAllName = "UnregisterAllCallbacks" + end + + -- we declare all objects and exported APIs inside this closure to quickly gain access + -- to e.g. function names, the "target" parameter, etc + + + -- Create the registry object + local events = setmetatable({}, meta) + local registry = { recurse=0, events=events } + + -- registry:Fire() - fires the given event/message into the registry + function registry:Fire(eventname, ...) + if not rawget(events, eventname) or not next(events[eventname]) then return end + local oldrecurse = registry.recurse + registry.recurse = oldrecurse + 1 + + Dispatch(events[eventname], eventname, ...) + + registry.recurse = oldrecurse + + if registry.insertQueue and oldrecurse==0 then + -- Something in one of our callbacks wanted to register more callbacks; they got queued + for eventname,callbacks in pairs(registry.insertQueue) do + local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. + for self,func in pairs(callbacks) do + events[eventname][self] = func + -- fire OnUsed callback? + if first and registry.OnUsed then + registry.OnUsed(registry, target, eventname) + first = nil + end + end + end + registry.insertQueue = nil + end + end + + -- Registration of a callback, handles: + -- self["method"], leads to self["method"](self, ...) + -- self with function ref, leads to functionref(...) + -- "addonId" (instead of self) with function ref, leads to functionref(...) + -- all with an optional arg, which, if present, gets passed as first argument (after self if present) + target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]]) + if type(eventname) ~= "string" then + error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2) + end + + method = method or eventname + + local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten. + + if type(method) ~= "string" and type(method) ~= "function" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2) + end + + local regfunc + + if type(method) == "string" then + -- self["method"] calling style + if type(self) ~= "table" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2) + elseif self==target then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2) + elseif type(self[method]) ~= "function" then + error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2) + end + + if select("#",...)>=1 then -- this is not the same as testing for arg==nil! + local arg=select(1,...) + regfunc = function(...) self[method](self,arg,...) end + else + regfunc = function(...) self[method](self,...) end + end + else + -- function ref with self=object or self="addonId" or self=thread + if type(self)~="table" and type(self)~="string" and type(self)~="thread" then + error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2) + end + + if select("#",...)>=1 then -- this is not the same as testing for arg==nil! + local arg=select(1,...) + regfunc = function(...) method(arg,...) end + else + regfunc = method + end + end + + + if events[eventname][self] or registry.recurse<1 then + -- if registry.recurse<1 then + -- we're overwriting an existing entry, or not currently recursing. just set it. + events[eventname][self] = regfunc + -- fire OnUsed callback? + if registry.OnUsed and first then + registry.OnUsed(registry, target, eventname) + end + else + -- we're currently processing a callback in this registry, so delay the registration of this new entry! + -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency + registry.insertQueue = registry.insertQueue or setmetatable({},meta) + registry.insertQueue[eventname][self] = regfunc + end + end + + -- Unregister a callback + target[UnregisterName] = function(self, eventname) + if not self or self==target then + error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2) + end + if type(eventname) ~= "string" then + error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2) + end + if rawget(events, eventname) and events[eventname][self] then + events[eventname][self] = nil + -- Fire OnUnused callback? + if registry.OnUnused and not next(events[eventname]) then + registry.OnUnused(registry, target, eventname) + end + end + if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then + registry.insertQueue[eventname][self] = nil + end + end + + -- OPTIONAL: Unregister all callbacks for given selfs/addonIds + if UnregisterAllName then + target[UnregisterAllName] = function(...) + if select("#",...)<1 then + error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2) + end + if select("#",...)==1 and ...==target then + error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2) + end + + + for i=1,select("#",...) do + local self = select(i,...) + if registry.insertQueue then + for eventname, callbacks in pairs(registry.insertQueue) do + if callbacks[self] then + callbacks[self] = nil + end + end + end + for eventname, callbacks in pairs(events) do + if callbacks[self] then + callbacks[self] = nil + -- Fire OnUnused callback? + if registry.OnUnused and not next(callbacks) then + registry.OnUnused(registry, target, eventname) + end + end + end + end + end + end + + return registry +end + + +-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it +-- try to upgrade old implicit embeds since the system is selfcontained and +-- relies on closures to work. + diff --git a/oUF/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml b/oUF/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml new file mode 100644 index 0000000..876df83 --- /dev/null +++ b/oUF/libs/CallbackHandler-1.0/CallbackHandler-1.0.xml @@ -0,0 +1,4 @@ + +