diff --git a/WeakAuras/RegionTypes/AuraBar.lua b/WeakAuras/RegionTypes/AuraBar.lua index fae8774..bb785c8 100644 --- a/WeakAuras/RegionTypes/AuraBar.lua +++ b/WeakAuras/RegionTypes/AuraBar.lua @@ -1246,6 +1246,7 @@ local function modify(parent, region, data) return region.currentMin or 0, region.currentMax or 0 end + region.TimerTick = nil function region:Update() local state = region.state region:UpdateMinMax() @@ -1257,7 +1258,7 @@ local function modify(parent, region, data) end if region.TimerTick then region.TimerTick = nil - region:UpdateRegionHasTimerTick() + region.subRegionEvents:RemoveSubscriber("TimerTick", self) end expirationTime = GetTime() + (state.remaining or 0) else @@ -1266,7 +1267,7 @@ local function modify(parent, region, data) end if not region.TimerTick then region.TimerTick = TimerTick - region:UpdateRegionHasTimerTick() + region.subRegionEvents:AddSubscriber("TimerTick", self, true) end expirationTime = state.expirationTime and state.expirationTime > 0 and state.expirationTime or math.huge; end @@ -1283,7 +1284,7 @@ local function modify(parent, region, data) region:SetValue(value - region.currentMin, region.currentMax - region.currentMin); if region.TimerTick then region.TimerTick = nil - region:UpdateRegionHasTimerTick() + region.subRegionEvents:RemoveSubscriber("TimerTick", region) end else if region.paused then @@ -1292,7 +1293,7 @@ local function modify(parent, region, data) region:SetTime(0, math.huge) if region.TimerTick then region.TimerTick = nil - region:UpdateRegionHasTimerTick() + region.subRegionEvents:RemoveSubscriber("TimerTick", region) end end diff --git a/WeakAuras/RegionTypes/ProgressTexture.lua b/WeakAuras/RegionTypes/ProgressTexture.lua index e7ad55d..436e494 100644 --- a/WeakAuras/RegionTypes/ProgressTexture.lua +++ b/WeakAuras/RegionTypes/ProgressTexture.lua @@ -878,6 +878,7 @@ local function modify(parent, region, data) end end + region.TimerTick = nil function region:Update() local state = region.state @@ -890,7 +891,7 @@ local function modify(parent, region, data) end if region.TimerTick then region.TimerTick = nil - region:UpdateRegionHasTimerTick() + region.subRegionEvents:RemoveSubscriber("TimerTick", region) end expirationTime = GetTime() + (state.remaining or 0) else @@ -899,7 +900,7 @@ local function modify(parent, region, data) end if not region.TimerTick then region.TimerTick = TimerTick - region:UpdateRegionHasTimerTick() + region.subRegionEvents:AddSubscriber("TimerTick", region, true) end expirationTime = state.expirationTime and state.expirationTime > 0 and state.expirationTime or math.huge; end @@ -945,7 +946,7 @@ local function modify(parent, region, data) region:SetValue(value - adjustMin, max - adjustMin); if region.TimerTick then region.TimerTick = nil - region:UpdateRegionHasTimerTick() + region.subRegionEvents:RemoveSubscriber("TimerTick", region) end else if region.paused then @@ -954,7 +955,7 @@ local function modify(parent, region, data) region:SetTime(0, math.huge) if region.TimerTick then region.TimerTick = nil - region:UpdateRegionHasTimerTick() + region.subRegionEvents:RemoveSubscriber("TimerTick", region) end end diff --git a/WeakAuras/RegionTypes/RegionPrototype.lua b/WeakAuras/RegionTypes/RegionPrototype.lua index cf5a902..2ba84de 100644 --- a/WeakAuras/RegionTypes/RegionPrototype.lua +++ b/WeakAuras/RegionTypes/RegionPrototype.lua @@ -6,47 +6,6 @@ local L = WeakAuras.L; WeakAuras.regionPrototype = {}; - -local SubRegionEventSystem = -{ - ClearSubscribers = function(self) - self.events = {} - end, - - AddSubscriber = function(self, event, subRegion) - if not subRegion[event] then - print("Can't register subregion for ", event, " ", subRegion.type) - return - end - - self.events[event] = self.events[event] or {} - tinsert(self.events[event], subRegion) - end, - - RemoveSubscriber = function(self, event, subRegion) - if self.events[event] then - tremove(self.events[event], tIndexOf(self.events[event], subRegion)) - end - end, - - Notify = function(self, event, ...) - if self.events[event] then - for _, subRegion in ipairs(self.events[event]) do - subRegion[event](subRegion, ...) - end - end - end -} - -local function CreateSubRegionEventSystem() - local system = {} - for f, func in pairs(SubRegionEventSystem) do - system[f] = func - system.events = {} - end - return system -end - -- Alpha function WeakAuras.regionPrototype.AddAlphaToDefault(default) default.alpha = 1.0; @@ -391,29 +350,9 @@ local function SetTriggerProvidesTimer(self, timerTick) self:UpdateTimerTick() end -local function UpdateRegionHasTimerTick(self) - local hasTimerTick = false - if self.TimerTick then - hasTimerTick = true - elseif (self.subRegions) then - for index, subRegion in pairs(self.subRegions) do - if subRegion.TimerTick then - hasTimerTick = true - break; - end - end - end - - self.regionHasTimer = hasTimerTick - self:UpdateTimerTick() -end - local function TimerTickForRegion(region) Private.StartProfileSystem("timer tick") Private.StartProfileAura(region.id); - if region.TimerTick then - region:TimerTick(); - end region.subRegionEvents:Notify("TimerTick") Private.StopProfileAura(region.id); @@ -421,7 +360,7 @@ local function TimerTickForRegion(region) end local function UpdateTimerTick(self) - if self.triggerProvidesTimer and self.regionHasTimer and self.toShow then + if self.triggerProvidesTimer and self.subRegionEvents:HasSubscribers("TimerTick") and self.toShow then if not self:GetScript("OnUpdate") then self:SetScript("OnUpdate", function() TimerTickForRegion(self) @@ -434,6 +373,20 @@ local function UpdateTimerTick(self) end end +local function UpdateFrameTick(self) + if self.subRegionEvents:HasSubscribers("FrameTick") and self.toShow then + Private.FrameTick:AddSubscriber("FrameTick", self) + else + Private.FrameTick:RemoveSubscriber("FrameTick", self) + end +end + +local function FrameTick(self) + Private.StartProfileAura(self.id) + self.subRegionEvents:Notify("FrameTick") + Private.StopProfileAura(self.id) +end + local function AnchorSubRegion(self, subRegion, anchorType, selfPoint, anchorPoint, anchorXOffset, anchorYOffset) subRegion:ClearAllPoints() @@ -486,10 +439,11 @@ function WeakAuras.regionPrototype.create(region) region.SetAnimAlpha = SetAnimAlpha; region.SetTriggerProvidesTimer = SetTriggerProvidesTimer - region.UpdateRegionHasTimerTick = UpdateRegionHasTimerTick region.UpdateTimerTick = UpdateTimerTick + region.UpdateFrameTick = UpdateFrameTick + region.FrameTick = FrameTick - region.subRegionEvents = CreateSubRegionEventSystem() + region.subRegionEvents = Private.CreateSubscribableObject() region.AnchorSubRegion = AnchorSubRegion region.values = {} -- For SubText @@ -502,6 +456,8 @@ function WeakAuras.regionPrototype.modify(parent, region, data) region.state = nil region.states = nil region.subRegionEvents:ClearSubscribers() + region.subRegionEvents:ClearCallbacks() + Private.FrameTick:RemoveSubscriber("FrameTick", region) local defaultsForRegion = Private.regionTypes[data.regionType] and Private.regionTypes[data.regionType].default; @@ -581,7 +537,6 @@ function WeakAuras.regionPrototype.modify(parent, region, data) end return data.actions.finish[fullKey] end, true) - end function WeakAuras.regionPrototype.modifyFinish(parent, region, data) @@ -612,7 +567,15 @@ function WeakAuras.regionPrototype.modifyFinish(parent, region, data) end end - region:UpdateRegionHasTimerTick() + region.subRegionEvents:SetOnSubscriptionStatusChanged("TimerTick", function() + region:UpdateTimerTick() + end) + region:UpdateTimerTick() + + region.subRegionEvents:SetOnSubscriptionStatusChanged("FrameTick", function() + region:UpdateFrameTick() + end) + region:UpdateFrameTick() Private.ApplyFrameLevel(region) end @@ -627,55 +590,25 @@ end local regionsForFrameTick = {} local frameForFrameTick = CreateFrame("Frame"); - Private.frames["Frame Tick Frame"] = frameForFrameTick -local function FrameTick() +Private.FrameTick = Private.CreateSubscribableObject() +Private.FrameTick.OnUpdateHandler = function() if WeakAuras.IsOptionsOpen() then return end Private.StartProfileSystem("frame tick") - for region in pairs(regionsForFrameTick) do - Private.StartProfileAura(region.id); - if region.FrameTick then - region.FrameTick() - end - region.subRegionEvents:Notify("FrameTick") - Private.StopProfileAura(region.id); - end + Private.FrameTick:Notify("FrameTick") Private.StopProfileSystem("frame tick") end -local function RegisterForFrameTick(region) - -- Check for a Frame Tick function - local hasFrameTick = region.FrameTick - if not hasFrameTick then - if (region.subRegions) then - for index, subRegion in pairs(region.subRegions) do - if subRegion.FrameTick then - hasFrameTick = true - break - end - end - end - end - - if not hasFrameTick then - return - end - - regionsForFrameTick[region] = true - if not frameForFrameTick:GetScript("OnUpdate") then - frameForFrameTick:SetScript("OnUpdate", FrameTick); - end -end - -local function UnRegisterForFrameTick(region) - regionsForFrameTick[region] = nil - if not next(regionsForFrameTick) then +Private.FrameTick:SetOnSubscriptionStatusChanged("FrameTick", function() + if Private.FrameTick:HasSubscribers("FrameTick") then + frameForFrameTick:SetScript("OnUpdate", Private.FrameTick.OnUpdateHandler); + else frameForFrameTick:SetScript("OnUpdate", nil) end -end +end) local function TimerTickForSetDuration(self) local duration = self.duration @@ -707,13 +640,13 @@ function WeakAuras.regionPrototype.AddSetDurationInfo(region) if customValue then SetProgressValue(region, duration, expirationTime); region.TimerTick = nil - region:UpdateRegionHasTimerTick() + region.subRegionEvents:RemoveSubscriber("TimerTick", self) else local adjustMin = region.adjustedMin or 0; region:SetTime((duration ~= 0 and region.adjustedMax or duration) - adjustMin, expirationTime - adjustMin, inverse); region.TimerTick = TimerTickForSetDuration - region:UpdateRegionHasTimerTick() + region.subRegionEvents:AddSubscriber("TimerTick", self, true) end end elseif (region.generatedSetDurationInfo) then @@ -827,7 +760,7 @@ function WeakAuras.regionPrototype.AddExpandFunction(data, region, cloneId, pare region:SoundRepeatStop(); end - UnRegisterForFrameTick(region) + region:UpdateFrameTick() region:UpdateTimerTick() end function region:Expand() @@ -863,7 +796,7 @@ function WeakAuras.regionPrototype.AddExpandFunction(data, region, cloneId, pare end parent:ActivateChild(data.id, cloneId); - RegisterForFrameTick(region) + region:UpdateFrameTick() region:UpdateTimerTick() end elseif not(data.controlledChildren) then @@ -886,7 +819,7 @@ function WeakAuras.regionPrototype.AddExpandFunction(data, region, cloneId, pare region:SoundRepeatStop(); end - UnRegisterForFrameTick(region) + region:UpdateFrameTick() region:UpdateTimerTick() end function region:Expand() @@ -934,7 +867,7 @@ function WeakAuras.regionPrototype.AddExpandFunction(data, region, cloneId, pare parent:UpdateBorder(region); end - RegisterForFrameTick(region) + region:UpdateFrameTick() region:UpdateTimerTick() end end diff --git a/WeakAuras/RegionTypes/StopMotion.lua b/WeakAuras/RegionTypes/StopMotion.lua index aa51c66..07bfb2a 100644 --- a/WeakAuras/RegionTypes/StopMotion.lua +++ b/WeakAuras/RegionTypes/StopMotion.lua @@ -444,6 +444,9 @@ local function modify(parent, region, data) end; region.FrameTick = onUpdate; + if region.FrameTick then + region.subRegionEvents:AddSubscriber("FrameTick", region, true) + end function region:Update() if region.state.paused then diff --git a/WeakAuras/RegionTypes/Text.lua b/WeakAuras/RegionTypes/Text.lua index 30768ee..71b153c 100644 --- a/WeakAuras/RegionTypes/Text.lua +++ b/WeakAuras/RegionTypes/Text.lua @@ -226,6 +226,11 @@ local function modify(parent, region, data) region.Update = Update region.FrameTick = FrameTick region.TimerTick = TimerTick + if TimerTick then + region.subRegionEvents:AddSubscriber("TimerTick", region, true) + else + region.subRegionEvents:RemoveSubscriber("TimerTick", region) + end if not UpdateText then local textStr = data.displayText diff --git a/WeakAuras/SubRegionTypes/Tick.lua b/WeakAuras/SubRegionTypes/Tick.lua index 9aa6ae8..8737d94 100644 --- a/WeakAuras/SubRegionTypes/Tick.lua +++ b/WeakAuras/SubRegionTypes/Tick.lua @@ -199,13 +199,11 @@ local funcs = { if self.tick_placement_mode == "ValueOffset" and self.state and self.state.progressType == "timed" and not self.paused then if not self.TimerTick then self.TimerTick = self.UpdateTickPlacement - self.parent:UpdateRegionHasTimerTick() self.parent.subRegionEvents:AddSubscriber("TimerTick", self) end else if self.TimerTick then self.TimerTick = nil - self.parent:UpdateRegionHasTimerTick() self.parent.subRegionEvents:RemoveSubscriber("TimerTick", self) end end diff --git a/WeakAuras/SubscribableObject.lua b/WeakAuras/SubscribableObject.lua new file mode 100644 index 0000000..07b3045 --- /dev/null +++ b/WeakAuras/SubscribableObject.lua @@ -0,0 +1,74 @@ +if not WeakAuras.IsLibsOK() then return end +local AddonName, Private = ... + +local WeakAuras = WeakAuras +local L = WeakAuras.L + +local SubscribableObject = +{ + ClearSubscribers = function(self) + self.events = {} + end, + + ClearCallbacks = function(self) + self.callbacks = {} + end, + + AddSubscriber = function(self, event, subscriber, highPriority) + if not subscriber[event] then + print("Can't register for ", event, " ", subscriber, subscriber.type) + return + end + + self.events[event] = self.events[event] or {} + local pos = highPriority and 1 or (#self.events[event] + 1) + if TableHasAnyEntries(self.events[event]) then + tinsert(self.events[event], pos, subscriber) + else + tinsert(self.events[event], pos, subscriber) + if self.callbacks[event] then + self.callbacks[event]() + end + end + end, + + RemoveSubscriber = function(self, event, subscriber) + if self.events[event] then + local index = tIndexOf(self.events[event], subscriber) + if index then + tremove(self.events[event], index) + if not TableHasAnyEntries(self.events[event]) then + if self.callbacks[event] then + self.callbacks[event]() + end + end + end + end + end, + + SetOnSubscriptionStatusChanged = function(self, event, cb) + self.callbacks[event] = cb + end, + + Notify = function(self, event, ...) + if self.events[event] then + for _, subscriber in ipairs(self.events[event]) do + subscriber[event](subscriber, ...) + end + end + end, + + HasSubscribers = function(self, event) + return self.events[event] and TableHasAnyEntries(self.events[event]) + end +} + +function Private.CreateSubscribableObject() + local system = {} + for f, func in pairs(SubscribableObject) do + system[f] = func + system.events = {} + system.callbacks = {} + end + return system +end diff --git a/WeakAuras/WeakAuras.toc b/WeakAuras/WeakAuras.toc index 9d299e5..7ae40e3 100644 --- a/WeakAuras/WeakAuras.toc +++ b/WeakAuras/WeakAuras.toc @@ -49,6 +49,7 @@ GenericTrigger.lua AuraWarnings.lua AuraEnvironment.lua DebugLog.lua +SubscribableObject.lua # Region support RegionTypes\RegionPrototype.lua diff --git a/WeakAuras/compat.lua b/WeakAuras/compat.lua index 801e333..1172119 100644 --- a/WeakAuras/compat.lua +++ b/WeakAuras/compat.lua @@ -44,6 +44,15 @@ function tIndexOf(tbl, item) end end +function TableHasAnyEntries(tbl) + if tbl and type(tbl) == "table" then + for _ in pairs(tbl) do + return true + end + end + return false +end + function IsInGroup() return GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0 end diff --git a/WeakAurasOptions/AuthorOptions.lua b/WeakAurasOptions/AuthorOptions.lua index dafdd7c..15c4e61 100644 --- a/WeakAurasOptions/AuthorOptions.lua +++ b/WeakAurasOptions/AuthorOptions.lua @@ -1021,7 +1021,7 @@ typeControlAdders = { set = function(_, value) if option.mediaType == "sound" then -- do this outside the deref loop, so we don't play the sound a million times - PlaySoundFile(value) + PlaySoundFile(value, "Master") end for _, optionData in pairs(option.references) do local childOption = optionData.options[optionData.index] @@ -2353,7 +2353,7 @@ local function addUserModeOption(options, args, data, order, prefix, i) end userOption.set = function(_, value) if option.mediaType == "sound" then - PlaySoundFile(value) + PlaySoundFile(value, "Master") end for _, optionData in pairs(option.references) do local childData = optionData.data