Skip to content

Commit

Permalink
Libs: Embedded some dependencies for testing purposes
Browse files Browse the repository at this point in the history
These are added by the CurseForge packager before creating a release archive, but that doesn't allow testing them locally or pinning their versions. It might be worth embedding some of the smaller dependencies that rarely ever change just to make things more reproducible.

Example: LibStub is tiny and hasn't been updated in 7 years.
  • Loading branch information
rdw-software committed Aug 3, 2023
1 parent 68df836 commit 90edc79
Show file tree
Hide file tree
Showing 31 changed files with 4,795 additions and 822 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# Embedded libraries that are used for local testing only
Libs/
*.CMD
*.suo
*.json
Expand Down
649 changes: 649 additions & 0 deletions Libs/AceAddon-3.0/AceAddon-3.0.lua

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions Libs/AceAddon-3.0/AceAddon-3.0.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="AceAddon-3.0.lua"/>
</Ui>
260 changes: 260 additions & 0 deletions Libs/AceBucket-3.0/AceBucket-3.0.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
--- A bucket to catch events in. **AceBucket-3.0** provides throttling of events that fire in bursts and
-- your addon only needs to know about the full burst.
--
-- This Bucket implementation works as follows:\\
-- Initially, no schedule is running, and its waiting for the first event to happen.\\
-- The first event will start the bucket, and get the scheduler running, which will collect all
-- events in the given interval. When that interval is reached, the bucket is pushed to the
-- callback and a new schedule is started. When a bucket is empty after its interval, the scheduler is
-- stopped, and the bucket is only listening for the next event to happen, basically back in its initial state.
--
-- In addition, the buckets collect information about the "arg1" argument of the events that fire, and pass those as a
-- table to your callback. This functionality was mostly designed for the UNIT_* events.\\
-- The table will have the different values of "arg1" as keys, and the number of occurances as their value, e.g.\\
-- { ["player"] = 2, ["target"] = 1, ["party1"] = 1 }
--
-- **AceBucket-3.0** can be embeded into your addon, either explicitly by calling AceBucket:Embed(MyAddon) or by
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
-- and can be accessed directly, without having to explicitly call AceBucket itself.\\
-- It is recommended to embed AceBucket, otherwise you'll have to specify a custom `self` on all calls you
-- make into AceBucket.
-- @usage
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("BucketExample", "AceBucket-3.0")
--
-- function MyAddon:OnEnable()
-- -- Register a bucket that listens to all the HP related events,
-- -- and fires once per second
-- self:RegisterBucketEvent({"UNIT_HEALTH", "UNIT_MAXHEALTH"}, 1, "UpdateHealth")
-- end
--
-- function MyAddon:UpdateHealth(units)
-- if units.player then
-- print("Your HP changed!")
-- end
-- end
-- @class file
-- @name AceBucket-3.0.lua
-- @release $Id: AceBucket-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $

local MAJOR, MINOR = "AceBucket-3.0", 4
local AceBucket, oldminor = LibStub:NewLibrary(MAJOR, MINOR)

if not AceBucket then return end -- No Upgrade needed

AceBucket.buckets = AceBucket.buckets or {}
AceBucket.embeds = AceBucket.embeds or {}

-- the libraries will be lazyly bound later, to avoid errors due to loading order issues
local AceEvent, AceTimer

-- Lua APIs
local tconcat = table.concat
local type, next, pairs, select = type, next, pairs, select
local tonumber, tostring, rawset = tonumber, tostring, rawset
local assert, loadstring, error = assert, loadstring, error

local bucketCache = setmetatable({}, {__mode='k'})

--[[
xpcall safecall implementation
]]
local xpcall = xpcall

local function errorhandler(err)
return geterrorhandler()(err)
end

local function safecall(func, ...)
if func then
return xpcall(func, errorhandler, ...)
end
end

-- FireBucket ( bucket )
--
-- send the bucket to the callback function and schedule the next FireBucket in interval seconds
local function FireBucket(bucket)
local received = bucket.received

-- we dont want to fire empty buckets
if next(received) ~= nil then
local callback = bucket.callback
if type(callback) == "string" then
safecall(bucket.object[callback], bucket.object, received)
else
safecall(callback, received)
end

for k in pairs(received) do
received[k] = nil
end

-- if the bucket was not empty, schedule another FireBucket in interval seconds
bucket.timer = AceTimer.ScheduleTimer(bucket, FireBucket, bucket.interval, bucket)
else -- if it was empty, clear the timer and wait for the next event
bucket.timer = nil
end
end

-- BucketHandler ( event, arg1 )
--
-- callback func for AceEvent
-- stores arg1 in the received table, and schedules the bucket if necessary
local function BucketHandler(self, event, arg1)
if arg1 == nil then
arg1 = "nil"
end

self.received[arg1] = (self.received[arg1] or 0) + 1

-- if we are not scheduled yet, start a timer on the interval for our bucket to be cleared
if not self.timer then
self.timer = AceTimer.ScheduleTimer(self, FireBucket, self.interval, self)
end
end

-- RegisterBucket( event, interval, callback, isMessage )
--
-- event(string or table) - the event, or a table with the events, that this bucket listens to
-- interval(int) - time between bucket fireings
-- callback(func or string) - function pointer, or method name of the object, that gets called when the bucket is cleared
-- isMessage(boolean) - register AceEvent Messages instead of game events
local function RegisterBucket(self, event, interval, callback, isMessage)
-- try to fetch the librarys
if not AceEvent or not AceTimer then
AceEvent = LibStub:GetLibrary("AceEvent-3.0", true)
AceTimer = LibStub:GetLibrary("AceTimer-3.0", true)
if not AceEvent or not AceTimer then
error(MAJOR .. " requires AceEvent-3.0 and AceTimer-3.0", 3)
end
end

if type(event) ~= "string" and type(event) ~= "table" then error("Usage: RegisterBucket(event, interval, callback): 'event' - string or table expected.", 3) end
if not callback then
if type(event) == "string" then
callback = event
else
error("Usage: RegisterBucket(event, interval, callback): cannot omit callback when event is not a string.", 3)
end
end
if not tonumber(interval) then error("Usage: RegisterBucket(event, interval, callback): 'interval' - number expected.", 3) end
if type(callback) ~= "string" and type(callback) ~= "function" then error("Usage: RegisterBucket(event, interval, callback): 'callback' - string or function or nil expected.", 3) end
if type(callback) == "string" and type(self[callback]) ~= "function" then error("Usage: RegisterBucket(event, interval, callback): 'callback' - method not found on target object.", 3) end

local bucket = next(bucketCache)
if bucket then
bucketCache[bucket] = nil
else
bucket = { handler = BucketHandler, received = {} }
end
bucket.object, bucket.callback, bucket.interval = self, callback, tonumber(interval)

local regFunc = isMessage and AceEvent.RegisterMessage or AceEvent.RegisterEvent

if type(event) == "table" then
for _,e in pairs(event) do
regFunc(bucket, e, "handler")
end
else
regFunc(bucket, event, "handler")
end

local handle = tostring(bucket)
AceBucket.buckets[handle] = bucket

return handle
end

--- Register a Bucket for an event (or a set of events)
-- @param event The event to listen for, or a table of events.
-- @param interval The Bucket interval (burst interval)
-- @param callback The callback function, either as a function reference, or a string pointing to a method of the addon object.
-- @return The handle of the bucket (for unregistering)
-- @usage
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceBucket-3.0")
-- MyAddon:RegisterBucketEvent("BAG_UPDATE", 0.2, "UpdateBags")
--
-- function MyAddon:UpdateBags()
-- -- do stuff
-- end
function AceBucket:RegisterBucketEvent(event, interval, callback)
return RegisterBucket(self, event, interval, callback, false)
end

--- Register a Bucket for an AceEvent-3.0 addon message (or a set of messages)
-- @param message The message to listen for, or a table of messages.
-- @param interval The Bucket interval (burst interval)
-- @param callback The callback function, either as a function reference, or a string pointing to a method of the addon object.
-- @return The handle of the bucket (for unregistering)
-- @usage
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceBucket-3.0")
-- MyAddon:RegisterBucketEvent("SomeAddon_InformationMessage", 0.2, "ProcessData")
--
-- function MyAddon:ProcessData()
-- -- do stuff
-- end
function AceBucket:RegisterBucketMessage(message, interval, callback)
return RegisterBucket(self, message, interval, callback, true)
end

--- Unregister any events and messages from the bucket and clear any remaining data.
-- @param handle The handle of the bucket as returned by RegisterBucket*
function AceBucket:UnregisterBucket(handle)
local bucket = AceBucket.buckets[handle]
if bucket then
AceEvent.UnregisterAllEvents(bucket)
AceEvent.UnregisterAllMessages(bucket)

-- clear any remaining data in the bucket
for k in pairs(bucket.received) do
bucket.received[k] = nil
end

if bucket.timer then
AceTimer.CancelTimer(bucket, bucket.timer)
bucket.timer = nil
end

AceBucket.buckets[handle] = nil
-- store our bucket in the cache
bucketCache[bucket] = true
end
end

--- Unregister all buckets of the current addon object (or custom "self").
function AceBucket:UnregisterAllBuckets()
-- hmm can we do this more efficient? (it is not done often so shouldn't matter much)
for handle, bucket in pairs(AceBucket.buckets) do
if bucket.object == self then
AceBucket.UnregisterBucket(self, handle)
end
end
end



-- embedding and embed handling
local mixins = {
"RegisterBucketEvent",
"RegisterBucketMessage",
"UnregisterBucket",
"UnregisterAllBuckets",
}

-- Embeds AceBucket into the target object making the functions from the mixins list available on target:..
-- @param target target object to embed AceBucket in
function AceBucket:Embed( target )
for _, v in pairs( mixins ) do
target[v] = self[v]
end
self.embeds[target] = true
return target
end

function AceBucket:OnEmbedDisable( target )
target:UnregisterAllBuckets()
end

for addon in pairs(AceBucket.embeds) do
AceBucket:Embed(addon)
end
4 changes: 4 additions & 0 deletions Libs/AceBucket-3.0/AceBucket-3.0.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="AceBucket-3.0.lua"/>
</Ui>
Loading

0 comments on commit 90edc79

Please sign in to comment.