diff --git a/MythicPlusDrop/Libs/AceAddon-3.0/AceAddon-3.0.lua b/MythicPlusDrop/Libs/AceAddon-3.0/AceAddon-3.0.lua
index a7f7279..00e4e48 100644
--- a/MythicPlusDrop/Libs/AceAddon-3.0/AceAddon-3.0.lua
+++ b/MythicPlusDrop/Libs/AceAddon-3.0/AceAddon-3.0.lua
@@ -6,31 +6,31 @@
-- * **OnEnable** which gets called during the PLAYER_LOGIN event, when most of the data provided by the game is already present.
-- * **OnDisable**, which is only called when your addon is manually being disabled.
-- @usage
--- -- A small (but complete) addon, that doesn't do anything,
+-- -- A small (but complete) addon, that doesn't do anything,
-- -- but shows usage of the callbacks.
-- local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
---
+--
-- function MyAddon:OnInitialize()
--- -- do init tasks here, like loading the Saved Variables,
+-- -- do init tasks here, like loading the Saved Variables,
-- -- or setting up slash commands.
-- end
---
+--
-- function MyAddon:OnEnable()
-- -- Do more initialization here, that really enables the use of your addon.
--- -- Register Events, Hook functions, Create Frames, Get information from
+-- -- Register Events, Hook functions, Create Frames, Get information from
-- -- the game that wasn't available in OnInitialize
-- end
--
-- function MyAddon:OnDisable()
-- -- Unhook, Unregister Events, Hide frames that you created.
--- -- You would probably only use an OnDisable if you want to
+-- -- You would probably only use an OnDisable if you want to
-- -- build a "standby" mode, or be able to toggle modules on/off.
-- end
-- @class file
-- @name AceAddon-3.0.lua
--- @release $Id: AceAddon-3.0.lua 1084 2013-04-27 20:14:11Z nevcairiel $
+-- @release $Id$
-local MAJOR, MINOR = "AceAddon-3.0", 12
+local MAJOR, MINOR = "AceAddon-3.0", 13
local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceAddon then return end -- No Upgrade needed.
@@ -49,10 +49,6 @@ local select, pairs, next, type, unpack = select, pairs, next, type, unpack
local loadstring, assert, error = loadstring, assert, error
local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
--- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
--- List them here for Mikk's FindGlobals script
--- GLOBALS: LibStub, IsLoggedIn, geterrorhandler
-
--[[
xpcall safecall implementation
]]
@@ -62,43 +58,12 @@ local function errorhandler(err)
return geterrorhandler()(err)
end
-local function CreateDispatcher(argCount)
- local code = [[
- local xpcall, eh = ...
- local method, ARGS
- local function call() return method(ARGS) end
-
- local function dispatch(func, ...)
- method = func
- if not method then return end
- ARGS = ...
- return xpcall(call, eh)
- end
-
- return dispatch
- ]]
-
- local ARGS = {}
- for i = 1, argCount do ARGS[i] = "arg"..i end
- code = code:gsub("ARGS", tconcat(ARGS, ", "))
- return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
-end
-
-local Dispatchers = setmetatable({}, {__index=function(self, argCount)
- local dispatcher = CreateDispatcher(argCount)
- rawset(self, argCount, dispatcher)
- return dispatcher
-end})
-Dispatchers[0] = function(func)
- return xpcall(func, errorhandler)
-end
-
local function safecall(func, ...)
-- we check to see if the func is passed is actually a function here and don't error when it isn't
-- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
-- present execution should continue without hinderance
if type(func) == "function" then
- return Dispatchers[select('#', ...)](func, ...)
+ return xpcall(func, errorhandler, ...)
end
end
@@ -106,7 +71,7 @@ end
local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype
-- used in the addon metatable
-local function addontostring( self ) return self.name end
+local function addontostring( self ) return self.name end
-- Check if the addon is queued for initialization
local function queuedForInitialization(addon)
@@ -119,14 +84,14 @@ local function queuedForInitialization(addon)
end
--- Create a new AceAddon-3.0 addon.
--- Any libraries you specified will be embeded, and the addon will be scheduled for
+-- Any libraries you specified will be embeded, and the addon will be scheduled for
-- its OnInitialize and OnEnable callbacks.
-- The final addon object, with all libraries embeded, will be returned.
-- @paramsig [object ,]name[, lib, ...]
-- @param object Table to use as a base for the addon (optional)
-- @param name Name of the addon object to create
-- @param lib List of libraries to embed into the addon
--- @usage
+-- @usage
-- -- Create a simple addon object
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceEvent-3.0")
--
@@ -146,10 +111,10 @@ function AceAddon:NewAddon(objectorname, ...)
if type(name)~="string" then
error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2)
end
- if self.addons[name] then
+ if self.addons[name] then
error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2)
end
-
+
object = object or {}
object.name = name
@@ -159,7 +124,7 @@ function AceAddon:NewAddon(objectorname, ...)
for k, v in pairs(oldmeta) do addonmeta[k] = v end
end
addonmeta.__tostring = addontostring
-
+
setmetatable( object, addonmeta )
self.addons[name] = object
object.modules = {}
@@ -167,7 +132,7 @@ function AceAddon:NewAddon(objectorname, ...)
object.defaultModuleLibraries = {}
Embed( object ) -- embed NewModule, GetModule methods
self:EmbedLibraries(object, select(i,...))
-
+
-- add to queue of addons to be initialized upon ADDON_LOADED
tinsert(self.initializequeue, object)
return object
@@ -178,7 +143,7 @@ end
-- Throws an error if the addon object cannot be found (except if silent is set).
-- @param name unique name of the addon object
-- @param silent if true, the addon is optional, silently return nil if its not found
--- @usage
+-- @usage
-- -- Get the Addon
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
function AceAddon:GetAddon(name, silent)
@@ -233,7 +198,7 @@ end
-- @paramsig name[, silent]
-- @param name unique name of the module
-- @param silent if true, the module is optional, silently return nil if its not found (optional)
--- @usage
+-- @usage
-- -- Get the Addon
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- -- Get the Module
@@ -256,23 +221,23 @@ local function IsModuleTrue(self) return true end
-- @param name unique name of the module
-- @param prototype object to derive this module from, methods and values from this table will be mixed into the module (optional)
-- @param lib List of libraries to embed into the addon
--- @usage
+-- @usage
-- -- Create a module with some embeded libraries
-- MyModule = MyAddon:NewModule("MyModule", "AceEvent-3.0", "AceHook-3.0")
---
+--
-- -- Create a module with a prototype
-- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
-- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0")
function NewModule(self, name, prototype, ...)
if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end
if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end
-
+
if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end
-
+
-- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well.
-- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is.
local module = AceAddon:NewAddon(fmt("%s_%s", self.name or tostring(self), name))
-
+
module.IsModule = IsModuleTrue
module:SetEnabledState(self.defaultModuleState)
module.moduleName = name
@@ -287,24 +252,24 @@ function NewModule(self, name, prototype, ...)
if not prototype or type(prototype) == "string" then
prototype = self.defaultModulePrototype or nil
end
-
+
if type(prototype) == "table" then
local mt = getmetatable(module)
mt.__index = prototype
setmetatable(module, mt) -- More of a Base class type feel.
end
-
+
safecall(self.OnModuleCreated, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy.
self.modules[name] = module
tinsert(self.orderedModules, module)
-
+
return module
end
--- Returns the real name of the addon or module, without any prefix.
-- @name //addon//:GetName
--- @paramsig
--- @usage
+-- @paramsig
+-- @usage
-- print(MyAddon:GetName())
-- -- prints "MyAddon"
function GetName(self)
@@ -316,8 +281,8 @@ end
-- and enabling all modules of the addon (unless explicitly disabled).\\
-- :Enable() also sets the internal `enableState` variable to true
-- @name //addon//:Enable
--- @paramsig
--- @usage
+-- @paramsig
+-- @usage
-- -- Enable MyModule
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- MyModule = MyAddon:GetModule("MyModule")
@@ -337,8 +302,8 @@ end
-- and disabling all modules of the addon.\\
-- :Disable() also sets the internal `enableState` variable to false
-- @name //addon//:Disable
--- @paramsig
--- @usage
+-- @paramsig
+-- @usage
-- -- Disable MyAddon
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- MyAddon:Disable()
@@ -351,7 +316,7 @@ end
-- Short-hand function that retrieves the module via `:GetModule` and calls `:Enable` on the module object.
-- @name //addon//:EnableModule
-- @paramsig name
--- @usage
+-- @usage
-- -- Enable MyModule using :GetModule
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- MyModule = MyAddon:GetModule("MyModule")
@@ -369,7 +334,7 @@ end
-- Short-hand function that retrieves the module via `:GetModule` and calls `:Disable` on the module object.
-- @name //addon//:DisableModule
-- @paramsig name
--- @usage
+-- @usage
-- -- Disable MyModule using :GetModule
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
-- MyModule = MyAddon:GetModule("MyModule")
@@ -388,7 +353,7 @@ end
-- @name //addon//:SetDefaultModuleLibraries
-- @paramsig lib[, lib, ...]
-- @param lib List of libraries to embed into the addon
--- @usage
+-- @usage
-- -- Create the addon object
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
-- -- Configure default libraries for modules (all modules need AceEvent-3.0)
@@ -407,7 +372,7 @@ end
-- @name //addon//:SetDefaultModuleState
-- @paramsig state
-- @param state Default state for new modules, true for enabled, false for disabled
--- @usage
+-- @usage
-- -- Create the addon object
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
-- -- Set the default state to "disabled"
@@ -427,7 +392,7 @@ end
-- @name //addon//:SetDefaultModulePrototype
-- @paramsig prototype
-- @param prototype Default prototype for the new modules (table)
--- @usage
+-- @usage
-- -- Define a prototype
-- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
-- -- Set the default prototype
@@ -459,8 +424,8 @@ end
--- Return an iterator of all modules associated to the addon.
-- @name //addon//:IterateModules
--- @paramsig
--- @usage
+-- @paramsig
+-- @usage
-- -- Enable all modules
-- for name, module in MyAddon:IterateModules() do
-- module:Enable()
@@ -469,13 +434,13 @@ local function IterateModules(self) return pairs(self.modules) end
-- Returns an iterator of all embeds in the addon
-- @name //addon//:IterateEmbeds
--- @paramsig
+-- @paramsig
local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) end
--- Query the enabledState of an addon.
-- @name //addon//:IsEnabled
--- @paramsig
--- @usage
+-- @paramsig
+-- @usage
-- if MyAddon:IsEnabled() then
-- MyAddon:Disable()
-- end
@@ -520,20 +485,20 @@ end
-- - Initialize the addon after creation.
-- This function is only used internally during the ADDON_LOADED event
--- It will call the **OnInitialize** function on the addon object (if present),
+-- It will call the **OnInitialize** function on the addon object (if present),
-- and the **OnEmbedInitialize** function on all embeded libraries.
---
+--
-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
-- @param addon addon object to intialize
function AceAddon:InitializeAddon(addon)
safecall(addon.OnInitialize, addon)
-
+
local embeds = self.embeds[addon]
for i = 1, #embeds do
local lib = LibStub:GetLibrary(embeds[i], true)
if lib then safecall(lib.OnEmbedInitialize, lib, addon) end
end
-
+
-- we don't call InitializeAddon on modules specifically, this is handled
-- from the event handler and only done _once_
end
@@ -541,7 +506,7 @@ end
-- - Enable the addon after creation.
-- Note: This function is only used internally during the PLAYER_LOGIN event, or during ADDON_LOADED,
-- if IsLoggedIn() already returns true at that point, e.g. for LoD Addons.
--- It will call the **OnEnable** function on the addon object (if present),
+-- It will call the **OnEnable** function on the addon object (if present),
-- and the **OnEmbedEnable** function on all embeded libraries.\\
-- This function does not toggle the enable state of the addon itself, and will return early if the addon is disabled.
--
@@ -551,12 +516,12 @@ end
function AceAddon:EnableAddon(addon)
if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
if self.statuses[addon.name] or not addon.enabledState then return false end
-
+
-- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable.
self.statuses[addon.name] = true
-
+
safecall(addon.OnEnable, addon)
-
+
-- make sure we're still enabled before continueing
if self.statuses[addon.name] then
local embeds = self.embeds[addon]
@@ -564,7 +529,7 @@ function AceAddon:EnableAddon(addon)
local lib = LibStub:GetLibrary(embeds[i], true)
if lib then safecall(lib.OnEmbedEnable, lib, addon) end
end
-
+
-- enable possible modules.
local modules = addon.orderedModules
for i = 1, #modules do
@@ -576,24 +541,24 @@ end
-- - Disable the addon
-- Note: This function is only used internally.
--- It will call the **OnDisable** function on the addon object (if present),
+-- It will call the **OnDisable** function on the addon object (if present),
-- and the **OnEmbedDisable** function on all embeded libraries.\\
-- This function does not toggle the enable state of the addon itself, and will return early if the addon is still enabled.
--
--- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
+-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
-- Use :Disable on the addon itself instead.
-- @param addon addon object to enable
function AceAddon:DisableAddon(addon)
if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
if not self.statuses[addon.name] then return false end
-
+
-- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable.
self.statuses[addon.name] = false
-
+
safecall( addon.OnDisable, addon )
-
+
-- make sure we're still disabling...
- if not self.statuses[addon.name] then
+ if not self.statuses[addon.name] then
local embeds = self.embeds[addon]
for i = 1, #embeds do
local lib = LibStub:GetLibrary(embeds[i], true)
@@ -605,12 +570,12 @@ function AceAddon:DisableAddon(addon)
self:DisableAddon(modules[i])
end
end
-
+
return not self.statuses[addon.name] -- return true if we're disabled
end
--- Get an iterator over all registered addons.
--- @usage
+-- @usage
-- -- Print a list of all installed AceAddon's
-- for name, addon in AceAddon:IterateAddons() do
-- print("Addon: " .. name)
@@ -618,7 +583,7 @@ end
function AceAddon:IterateAddons() return pairs(self.addons) end
--- Get an iterator over the internal status registry.
--- @usage
+-- @usage
-- -- Print a list of all enabled addons
-- for name, status in AceAddon:IterateAddonStatus() do
-- if status then
@@ -632,10 +597,20 @@ function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
+-- Blizzard AddOns which can load very early in the loading process and mess with Ace3 addon loading
+local BlizzardEarlyLoadAddons = {
+ Blizzard_DebugTools = true,
+ Blizzard_TimeManager = true,
+ Blizzard_BattlefieldMap = true,
+ Blizzard_MapCanvas = true,
+ Blizzard_SharedMapDataProviders = true,
+ Blizzard_CombatLog = true,
+}
+
-- Event Handling
local function onEvent(this, event, arg1)
- -- 2011-08-17 nevcairiel - ignore the load event of Blizzard_DebugTools, so a potential startup error isn't swallowed up
- if (event == "ADDON_LOADED" and arg1 ~= "Blizzard_DebugTools") or event == "PLAYER_LOGIN" then
+ -- 2020-08-28 nevcairiel - ignore the load event of Blizzard addons which occur early in the loading process
+ if (event == "ADDON_LOADED" and (arg1 == nil or not BlizzardEarlyLoadAddons[arg1])) or event == "PLAYER_LOGIN" then
-- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration
while(#AceAddon.initializequeue > 0) do
local addon = tremove(AceAddon.initializequeue, 1)
@@ -644,7 +619,7 @@ local function onEvent(this, event, arg1)
AceAddon:InitializeAddon(addon)
tinsert(AceAddon.enablequeue, addon)
end
-
+
if IsLoggedIn() then
while(#AceAddon.enablequeue > 0) do
local addon = tremove(AceAddon.enablequeue, 1)
diff --git a/MythicPlusDrop/Libs/AceBucket-3.0/AceBucket-3.0.lua b/MythicPlusDrop/Libs/AceBucket-3.0/AceBucket-3.0.lua
new file mode 100644
index 0000000..d89dcee
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceBucket-3.0/AceBucket-3.0.lua
@@ -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$
+
+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
diff --git a/MythicPlusDrop/Libs/AceBucket-3.0/AceBucket-3.0.xml b/MythicPlusDrop/Libs/AceBucket-3.0/AceBucket-3.0.xml
new file mode 100644
index 0000000..43c6bee
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceBucket-3.0/AceBucket-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/MythicPlusDrop/Libs/AceComm-3.0/AceComm-3.0.lua b/MythicPlusDrop/Libs/AceComm-3.0/AceComm-3.0.lua
new file mode 100644
index 0000000..60d72d9
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceComm-3.0/AceComm-3.0.lua
@@ -0,0 +1,301 @@
+--- **AceComm-3.0** allows you to send messages of unlimited length over the addon comm channels.
+-- It'll automatically split the messages into multiple parts and rebuild them on the receiving end.\\
+-- **ChatThrottleLib** is of course being used to avoid being disconnected by the server.
+--
+-- **AceComm-3.0** can be embeded into your addon, either explicitly by calling AceComm: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 AceComm itself.\\
+-- It is recommended to embed AceComm, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceComm.
+-- @class file
+-- @name AceComm-3.0
+-- @release $Id$
+
+--[[ AceComm-3.0
+
+TODO: Time out old data rotting around from dead senders? Not a HUGE deal since the number of possible sender names is somewhat limited.
+
+]]
+
+local CallbackHandler = LibStub("CallbackHandler-1.0")
+local CTL = assert(ChatThrottleLib, "AceComm-3.0 requires ChatThrottleLib")
+
+local MAJOR, MINOR = "AceComm-3.0", 12
+local AceComm,oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceComm then return end
+
+-- Lua APIs
+local type, next, pairs, tostring = type, next, pairs, tostring
+local strsub, strfind = string.sub, string.find
+local match = string.match
+local tinsert, tconcat = table.insert, table.concat
+local error, assert = error, assert
+
+-- WoW APIs
+local Ambiguate = Ambiguate
+
+AceComm.embeds = AceComm.embeds or {}
+
+-- for my sanity and yours, let's give the message type bytes some names
+local MSG_MULTI_FIRST = "\001"
+local MSG_MULTI_NEXT = "\002"
+local MSG_MULTI_LAST = "\003"
+local MSG_ESCAPE = "\004"
+
+-- remove old structures (pre WoW 4.0)
+AceComm.multipart_origprefixes = nil
+AceComm.multipart_reassemblers = nil
+
+-- the multipart message spool: indexed by a combination of sender+distribution+
+AceComm.multipart_spool = AceComm.multipart_spool or {}
+
+--- Register for Addon Traffic on a specified prefix
+-- @param prefix A printable character (\032-\255) classification of the message (typically AddonName or AddonNameEvent), max 16 characters
+-- @param method Callback to call on message reception: Function reference, or method name (string) to call on self. Defaults to "OnCommReceived"
+function AceComm:RegisterComm(prefix, method)
+ if method == nil then
+ method = "OnCommReceived"
+ end
+
+ if #prefix > 16 then -- TODO: 15?
+ error("AceComm:RegisterComm(prefix,method): prefix length is limited to 16 characters")
+ end
+ if C_ChatInfo then
+ C_ChatInfo.RegisterAddonMessagePrefix(prefix)
+ else
+ RegisterAddonMessagePrefix(prefix)
+ end
+
+ return AceComm._RegisterComm(self, prefix, method) -- created by CallbackHandler
+end
+
+local warnedPrefix=false
+
+--- Send a message over the Addon Channel
+-- @param prefix A printable character (\032-\255) classification of the message (typically AddonName or AddonNameEvent)
+-- @param text Data to send, nils (\000) not allowed. Any length.
+-- @param distribution Addon channel, e.g. "RAID", "GUILD", etc; see SendAddonMessage API
+-- @param target Destination for some distributions; see SendAddonMessage API
+-- @param prio OPTIONAL: ChatThrottleLib priority, "BULK", "NORMAL" or "ALERT". Defaults to "NORMAL".
+-- @param callbackFn OPTIONAL: callback function to be called as each chunk is sent. receives 3 args: the user supplied arg (see next), the number of bytes sent so far, and the number of bytes total to send.
+-- @param callbackArg: OPTIONAL: first arg to the callback function. nil will be passed if not specified.
+function AceComm:SendCommMessage(prefix, text, distribution, target, prio, callbackFn, callbackArg)
+ prio = prio or "NORMAL" -- pasta's reference implementation had different prio for singlepart and multipart, but that's a very bad idea since that can easily lead to out-of-sequence delivery!
+ if not( type(prefix)=="string" and
+ type(text)=="string" and
+ type(distribution)=="string" and
+ (target==nil or type(target)=="string" or type(target)=="number") and
+ (prio=="BULK" or prio=="NORMAL" or prio=="ALERT")
+ ) then
+ error('Usage: SendCommMessage(addon, "prefix", "text", "distribution"[, "target"[, "prio"[, callbackFn, callbackarg]]])', 2)
+ end
+
+ local textlen = #text
+ local maxtextlen = 255 -- Yes, the max is 255 even if the dev post said 256. I tested. Char 256+ get silently truncated. /Mikk, 20110327
+ local queueName = prefix..distribution..(target or "")
+
+ local ctlCallback = nil
+ if callbackFn then
+ ctlCallback = function(sent)
+ return callbackFn(callbackArg, sent, textlen)
+ end
+ end
+
+ local forceMultipart
+ if match(text, "^[\001-\009]") then -- 4.1+: see if the first character is a control character
+ -- we need to escape the first character with a \004
+ if textlen+1 > maxtextlen then -- would we go over the size limit?
+ forceMultipart = true -- just make it multipart, no escape problems then
+ else
+ text = "\004" .. text
+ end
+ end
+
+ if not forceMultipart and textlen <= maxtextlen then
+ -- fits all in one message
+ CTL:SendAddonMessage(prio, prefix, text, distribution, target, queueName, ctlCallback, textlen)
+ else
+ maxtextlen = maxtextlen - 1 -- 1 extra byte for part indicator in prefix(4.0)/start of message(4.1)
+
+ -- first part
+ local chunk = strsub(text, 1, maxtextlen)
+ CTL:SendAddonMessage(prio, prefix, MSG_MULTI_FIRST..chunk, distribution, target, queueName, ctlCallback, maxtextlen)
+
+ -- continuation
+ local pos = 1+maxtextlen
+
+ while pos+maxtextlen <= textlen do
+ chunk = strsub(text, pos, pos+maxtextlen-1)
+ CTL:SendAddonMessage(prio, prefix, MSG_MULTI_NEXT..chunk, distribution, target, queueName, ctlCallback, pos+maxtextlen-1)
+ pos = pos + maxtextlen
+ end
+
+ -- final part
+ chunk = strsub(text, pos)
+ CTL:SendAddonMessage(prio, prefix, MSG_MULTI_LAST..chunk, distribution, target, queueName, ctlCallback, textlen)
+ end
+end
+
+
+----------------------------------------
+-- Message receiving
+----------------------------------------
+
+do
+ local compost = setmetatable({}, {__mode = "k"})
+ local function new()
+ local t = next(compost)
+ if t then
+ compost[t]=nil
+ for i=#t,3,-1 do -- faster than pairs loop. don't even nil out 1/2 since they'll be overwritten
+ t[i]=nil
+ end
+ return t
+ end
+
+ return {}
+ end
+
+ local function lostdatawarning(prefix,sender,where)
+ DEFAULT_CHAT_FRAME:AddMessage(MAJOR..": Warning: lost network data regarding '"..tostring(prefix).."' from '"..tostring(sender).."' (in "..where..")")
+ end
+
+ function AceComm:OnReceiveMultipartFirst(prefix, message, distribution, sender)
+ local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender
+ local spool = AceComm.multipart_spool
+
+ --[[
+ if spool[key] then
+ lostdatawarning(prefix,sender,"First")
+ -- continue and overwrite
+ end
+ --]]
+
+ spool[key] = message -- plain string for now
+ end
+
+ function AceComm:OnReceiveMultipartNext(prefix, message, distribution, sender)
+ local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender
+ local spool = AceComm.multipart_spool
+ local olddata = spool[key]
+
+ if not olddata then
+ --lostdatawarning(prefix,sender,"Next")
+ return
+ end
+
+ if type(olddata)~="table" then
+ -- ... but what we have is not a table. So make it one. (Pull a composted one if available)
+ local t = new()
+ t[1] = olddata -- add old data as first string
+ t[2] = message -- and new message as second string
+ spool[key] = t -- and put the table in the spool instead of the old string
+ else
+ tinsert(olddata, message)
+ end
+ end
+
+ function AceComm:OnReceiveMultipartLast(prefix, message, distribution, sender)
+ local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender
+ local spool = AceComm.multipart_spool
+ local olddata = spool[key]
+
+ if not olddata then
+ --lostdatawarning(prefix,sender,"End")
+ return
+ end
+
+ spool[key] = nil
+
+ if type(olddata) == "table" then
+ -- if we've received a "next", the spooled data will be a table for rapid & garbage-free tconcat
+ tinsert(olddata, message)
+ AceComm.callbacks:Fire(prefix, tconcat(olddata, ""), distribution, sender)
+ compost[olddata] = true
+ else
+ -- if we've only received a "first", the spooled data will still only be a string
+ AceComm.callbacks:Fire(prefix, olddata..message, distribution, sender)
+ end
+ end
+end
+
+
+
+
+
+
+----------------------------------------
+-- Embed CallbackHandler
+----------------------------------------
+
+if not AceComm.callbacks then
+ AceComm.callbacks = CallbackHandler:New(AceComm,
+ "_RegisterComm",
+ "UnregisterComm",
+ "UnregisterAllComm")
+end
+
+AceComm.callbacks.OnUsed = nil
+AceComm.callbacks.OnUnused = nil
+
+local function OnEvent(self, event, prefix, message, distribution, sender)
+ if event == "CHAT_MSG_ADDON" then
+ sender = Ambiguate(sender, "none")
+ local control, rest = match(message, "^([\001-\009])(.*)")
+ if control then
+ if control==MSG_MULTI_FIRST then
+ AceComm:OnReceiveMultipartFirst(prefix, rest, distribution, sender)
+ elseif control==MSG_MULTI_NEXT then
+ AceComm:OnReceiveMultipartNext(prefix, rest, distribution, sender)
+ elseif control==MSG_MULTI_LAST then
+ AceComm:OnReceiveMultipartLast(prefix, rest, distribution, sender)
+ elseif control==MSG_ESCAPE then
+ AceComm.callbacks:Fire(prefix, rest, distribution, sender)
+ else
+ -- unknown control character, ignore SILENTLY (dont warn unnecessarily about future extensions!)
+ end
+ else
+ -- single part: fire it off immediately and let CallbackHandler decide if it's registered or not
+ AceComm.callbacks:Fire(prefix, message, distribution, sender)
+ end
+ else
+ assert(false, "Received "..tostring(event).." event?!")
+ end
+end
+
+AceComm.frame = AceComm.frame or CreateFrame("Frame", "AceComm30Frame")
+AceComm.frame:SetScript("OnEvent", OnEvent)
+AceComm.frame:UnregisterAllEvents()
+AceComm.frame:RegisterEvent("CHAT_MSG_ADDON")
+
+
+----------------------------------------
+-- Base library stuff
+----------------------------------------
+
+local mixins = {
+ "RegisterComm",
+ "UnregisterComm",
+ "UnregisterAllComm",
+ "SendCommMessage",
+}
+
+-- Embeds AceComm-3.0 into the target object making the functions from the mixins list available on target:..
+-- @param target target object to embed AceComm-3.0 in
+function AceComm:Embed(target)
+ for k, v in pairs(mixins) do
+ target[v] = self[v]
+ end
+ self.embeds[target] = true
+ return target
+end
+
+function AceComm:OnEmbedDisable(target)
+ target:UnregisterAllComm()
+end
+
+-- Update embeds
+for target, v in pairs(AceComm.embeds) do
+ AceComm:Embed(target)
+end
diff --git a/MythicPlusDrop/Libs/AceComm-3.0/AceComm-3.0.xml b/MythicPlusDrop/Libs/AceComm-3.0/AceComm-3.0.xml
new file mode 100644
index 0000000..09e8d87
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceComm-3.0/AceComm-3.0.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/MythicPlusDrop/Libs/AceComm-3.0/ChatThrottleLib.lua b/MythicPlusDrop/Libs/AceComm-3.0/ChatThrottleLib.lua
new file mode 100644
index 0000000..d1dd8a0
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceComm-3.0/ChatThrottleLib.lua
@@ -0,0 +1,534 @@
+--
+-- ChatThrottleLib by Mikk
+--
+-- Manages AddOn chat output to keep player from getting kicked off.
+--
+-- ChatThrottleLib:SendChatMessage/:SendAddonMessage functions that accept
+-- a Priority ("BULK", "NORMAL", "ALERT") as well as prefix for SendChatMessage.
+--
+-- Priorities get an equal share of available bandwidth when fully loaded.
+-- Communication channels are separated on extension+chattype+destination and
+-- get round-robinned. (Destination only matters for whispers and channels,
+-- obviously)
+--
+-- Will install hooks for SendChatMessage and SendAddonMessage to measure
+-- bandwidth bypassing the library and use less bandwidth itself.
+--
+--
+-- Fully embeddable library. Just copy this file into your addon directory,
+-- add it to the .toc, and it's done.
+--
+-- Can run as a standalone addon also, but, really, just embed it! :-)
+--
+-- LICENSE: ChatThrottleLib is released into the Public Domain
+--
+
+local CTL_VERSION = 24
+
+local _G = _G
+
+if _G.ChatThrottleLib then
+ if _G.ChatThrottleLib.version >= CTL_VERSION then
+ -- There's already a newer (or same) version loaded. Buh-bye.
+ return
+ elseif not _G.ChatThrottleLib.securelyHooked then
+ print("ChatThrottleLib: Warning: There's an ANCIENT ChatThrottleLib.lua (pre-wow 2.0, =v16) in it!")
+ -- ATTEMPT to unhook; this'll behave badly if someone else has hooked...
+ -- ... and if someone has securehooked, they can kiss that goodbye too... >.<
+ _G.SendChatMessage = _G.ChatThrottleLib.ORIG_SendChatMessage
+ if _G.ChatThrottleLib.ORIG_SendAddonMessage then
+ _G.SendAddonMessage = _G.ChatThrottleLib.ORIG_SendAddonMessage
+ end
+ end
+ _G.ChatThrottleLib.ORIG_SendChatMessage = nil
+ _G.ChatThrottleLib.ORIG_SendAddonMessage = nil
+end
+
+if not _G.ChatThrottleLib then
+ _G.ChatThrottleLib = {}
+end
+
+ChatThrottleLib = _G.ChatThrottleLib -- in case some addon does "local ChatThrottleLib" above us and we're copypasted (AceComm-2, sigh)
+local ChatThrottleLib = _G.ChatThrottleLib
+
+ChatThrottleLib.version = CTL_VERSION
+
+
+
+------------------ TWEAKABLES -----------------
+
+ChatThrottleLib.MAX_CPS = 800 -- 2000 seems to be safe if NOTHING ELSE is happening. let's call it 800.
+ChatThrottleLib.MSG_OVERHEAD = 40 -- Guesstimate overhead for sending a message; source+dest+chattype+protocolstuff
+
+ChatThrottleLib.BURST = 4000 -- WoW's server buffer seems to be about 32KB. 8KB should be safe, but seen disconnects on _some_ servers. Using 4KB now.
+
+ChatThrottleLib.MIN_FPS = 20 -- Reduce output CPS to half (and don't burst) if FPS drops below this value
+
+
+local setmetatable = setmetatable
+local table_remove = table.remove
+local tostring = tostring
+local GetTime = GetTime
+local math_min = math.min
+local math_max = math.max
+local next = next
+local strlen = string.len
+local GetFramerate = GetFramerate
+local strlower = string.lower
+local unpack,type,pairs,wipe = unpack,type,pairs,table.wipe
+local UnitInRaid,UnitInParty = UnitInRaid,UnitInParty
+
+
+-----------------------------------------------------------------------
+-- Double-linked ring implementation
+
+local Ring = {}
+local RingMeta = { __index = Ring }
+
+function Ring:New()
+ local ret = {}
+ setmetatable(ret, RingMeta)
+ return ret
+end
+
+function Ring:Add(obj) -- Append at the "far end" of the ring (aka just before the current position)
+ if self.pos then
+ obj.prev = self.pos.prev
+ obj.prev.next = obj
+ obj.next = self.pos
+ obj.next.prev = obj
+ else
+ obj.next = obj
+ obj.prev = obj
+ self.pos = obj
+ end
+end
+
+function Ring:Remove(obj)
+ obj.next.prev = obj.prev
+ obj.prev.next = obj.next
+ if self.pos == obj then
+ self.pos = obj.next
+ if self.pos == obj then
+ self.pos = nil
+ end
+ end
+end
+
+
+
+-----------------------------------------------------------------------
+-- Recycling bin for pipes
+-- A pipe is a plain integer-indexed queue of messages
+-- Pipes normally live in Rings of pipes (3 rings total, one per priority)
+
+ChatThrottleLib.PipeBin = nil -- pre-v19, drastically different
+local PipeBin = setmetatable({}, {__mode="k"})
+
+local function DelPipe(pipe)
+ PipeBin[pipe] = true
+end
+
+local function NewPipe()
+ local pipe = next(PipeBin)
+ if pipe then
+ wipe(pipe)
+ PipeBin[pipe] = nil
+ return pipe
+ end
+ return {}
+end
+
+
+
+
+-----------------------------------------------------------------------
+-- Recycling bin for messages
+
+ChatThrottleLib.MsgBin = nil -- pre-v19, drastically different
+local MsgBin = setmetatable({}, {__mode="k"})
+
+local function DelMsg(msg)
+ msg[1] = nil
+ -- there's more parameters, but they're very repetetive so the string pool doesn't suffer really, and it's faster to just not delete them.
+ MsgBin[msg] = true
+end
+
+local function NewMsg()
+ local msg = next(MsgBin)
+ if msg then
+ MsgBin[msg] = nil
+ return msg
+ end
+ return {}
+end
+
+
+-----------------------------------------------------------------------
+-- ChatThrottleLib:Init
+-- Initialize queues, set up frame for OnUpdate, etc
+
+
+function ChatThrottleLib:Init()
+
+ -- Set up queues
+ if not self.Prio then
+ self.Prio = {}
+ self.Prio["ALERT"] = { ByName = {}, Ring = Ring:New(), avail = 0 }
+ self.Prio["NORMAL"] = { ByName = {}, Ring = Ring:New(), avail = 0 }
+ self.Prio["BULK"] = { ByName = {}, Ring = Ring:New(), avail = 0 }
+ end
+
+ -- v4: total send counters per priority
+ for _, Prio in pairs(self.Prio) do
+ Prio.nTotalSent = Prio.nTotalSent or 0
+ end
+
+ if not self.avail then
+ self.avail = 0 -- v5
+ end
+ if not self.nTotalSent then
+ self.nTotalSent = 0 -- v5
+ end
+
+
+ -- Set up a frame to get OnUpdate events
+ if not self.Frame then
+ self.Frame = CreateFrame("Frame")
+ self.Frame:Hide()
+ end
+ self.Frame:SetScript("OnUpdate", self.OnUpdate)
+ self.Frame:SetScript("OnEvent", self.OnEvent) -- v11: Monitor P_E_W so we can throttle hard for a few seconds
+ self.Frame:RegisterEvent("PLAYER_ENTERING_WORLD")
+ self.OnUpdateDelay = 0
+ self.LastAvailUpdate = GetTime()
+ self.HardThrottlingBeginTime = GetTime() -- v11: Throttle hard for a few seconds after startup
+
+ -- Hook SendChatMessage and SendAddonMessage so we can measure unpiped traffic and avoid overloads (v7)
+ if not self.securelyHooked then
+ -- Use secure hooks as of v16. Old regular hook support yanked out in v21.
+ self.securelyHooked = true
+ --SendChatMessage
+ hooksecurefunc("SendChatMessage", function(...)
+ return ChatThrottleLib.Hook_SendChatMessage(...)
+ end)
+ --SendAddonMessage
+ if _G.C_ChatInfo then
+ hooksecurefunc(_G.C_ChatInfo, "SendAddonMessage", function(...)
+ return ChatThrottleLib.Hook_SendAddonMessage(...)
+ end)
+ else
+ hooksecurefunc("SendAddonMessage", function(...)
+ return ChatThrottleLib.Hook_SendAddonMessage(...)
+ end)
+ end
+ end
+ self.nBypass = 0
+end
+
+
+-----------------------------------------------------------------------
+-- ChatThrottleLib.Hook_SendChatMessage / .Hook_SendAddonMessage
+
+local bMyTraffic = false
+
+function ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destination, ...)
+ if bMyTraffic then
+ return
+ end
+ local self = ChatThrottleLib
+ local size = strlen(tostring(text or "")) + strlen(tostring(destination or "")) + self.MSG_OVERHEAD
+ self.avail = self.avail - size
+ self.nBypass = self.nBypass + size -- just a statistic
+end
+function ChatThrottleLib.Hook_SendAddonMessage(prefix, text, chattype, destination, ...)
+ if bMyTraffic then
+ return
+ end
+ local self = ChatThrottleLib
+ local size = tostring(text or ""):len() + tostring(prefix or ""):len();
+ size = size + tostring(destination or ""):len() + self.MSG_OVERHEAD
+ self.avail = self.avail - size
+ self.nBypass = self.nBypass + size -- just a statistic
+end
+
+
+
+-----------------------------------------------------------------------
+-- ChatThrottleLib:UpdateAvail
+-- Update self.avail with how much bandwidth is currently available
+
+function ChatThrottleLib:UpdateAvail()
+ local now = GetTime()
+ local MAX_CPS = self.MAX_CPS;
+ local newavail = MAX_CPS * (now - self.LastAvailUpdate)
+ local avail = self.avail
+
+ if now - self.HardThrottlingBeginTime < 5 then
+ -- First 5 seconds after startup/zoning: VERY hard clamping to avoid irritating the server rate limiter, it seems very cranky then
+ avail = math_min(avail + (newavail*0.1), MAX_CPS*0.5)
+ self.bChoking = true
+ elseif GetFramerate() < self.MIN_FPS then -- GetFrameRate call takes ~0.002 secs
+ avail = math_min(MAX_CPS, avail + newavail*0.5)
+ self.bChoking = true -- just a statistic
+ else
+ avail = math_min(self.BURST, avail + newavail)
+ self.bChoking = false
+ end
+
+ avail = math_max(avail, 0-(MAX_CPS*2)) -- Can go negative when someone is eating bandwidth past the lib. but we refuse to stay silent for more than 2 seconds; if they can do it, we can.
+
+ self.avail = avail
+ self.LastAvailUpdate = now
+
+ return avail
+end
+
+
+-----------------------------------------------------------------------
+-- Despooling logic
+-- Reminder:
+-- - We have 3 Priorities, each containing a "Ring" construct ...
+-- - ... made up of N "Pipe"s (1 for each destination/pipename)
+-- - and each pipe contains messages
+
+function ChatThrottleLib:Despool(Prio)
+ local ring = Prio.Ring
+ while ring.pos and Prio.avail > ring.pos[1].nSize do
+ local msg = table_remove(ring.pos, 1)
+ if not ring.pos[1] then -- did we remove last msg in this pipe?
+ local pipe = Prio.Ring.pos
+ Prio.Ring:Remove(pipe)
+ Prio.ByName[pipe.name] = nil
+ DelPipe(pipe)
+ else
+ Prio.Ring.pos = Prio.Ring.pos.next
+ end
+ local didSend=false
+ local lowerDest = strlower(msg[3] or "")
+ if lowerDest == "raid" and not UnitInRaid("player") then
+ -- do nothing
+ elseif lowerDest == "party" and not UnitInParty("player") then
+ -- do nothing
+ else
+ Prio.avail = Prio.avail - msg.nSize
+ bMyTraffic = true
+ msg.f(unpack(msg, 1, msg.n))
+ bMyTraffic = false
+ Prio.nTotalSent = Prio.nTotalSent + msg.nSize
+ DelMsg(msg)
+ didSend = true
+ end
+ -- notify caller of delivery (even if we didn't send it)
+ if msg.callbackFn then
+ msg.callbackFn (msg.callbackArg, didSend)
+ end
+ -- USER CALLBACK MAY ERROR
+ end
+end
+
+
+function ChatThrottleLib.OnEvent(this,event)
+ -- v11: We know that the rate limiter is touchy after login. Assume that it's touchy after zoning, too.
+ local self = ChatThrottleLib
+ if event == "PLAYER_ENTERING_WORLD" then
+ self.HardThrottlingBeginTime = GetTime() -- Throttle hard for a few seconds after zoning
+ self.avail = 0
+ end
+end
+
+
+function ChatThrottleLib.OnUpdate(this,delay)
+ local self = ChatThrottleLib
+
+ self.OnUpdateDelay = self.OnUpdateDelay + delay
+ if self.OnUpdateDelay < 0.08 then
+ return
+ end
+ self.OnUpdateDelay = 0
+
+ self:UpdateAvail()
+
+ if self.avail < 0 then
+ return -- argh. some bastard is spewing stuff past the lib. just bail early to save cpu.
+ end
+
+ -- See how many of our priorities have queued messages (we only have 3, don't worry about the loop)
+ local n = 0
+ for prioname,Prio in pairs(self.Prio) do
+ if Prio.Ring.pos or Prio.avail < 0 then
+ n = n + 1
+ end
+ end
+
+ -- Anything queued still?
+ if n<1 then
+ -- Nope. Move spillover bandwidth to global availability gauge and clear self.bQueueing
+ for prioname, Prio in pairs(self.Prio) do
+ self.avail = self.avail + Prio.avail
+ Prio.avail = 0
+ end
+ self.bQueueing = false
+ self.Frame:Hide()
+ return
+ end
+
+ -- There's stuff queued. Hand out available bandwidth to priorities as needed and despool their queues
+ local avail = self.avail/n
+ self.avail = 0
+
+ for prioname, Prio in pairs(self.Prio) do
+ if Prio.Ring.pos or Prio.avail < 0 then
+ Prio.avail = Prio.avail + avail
+ if Prio.Ring.pos and Prio.avail > Prio.Ring.pos[1].nSize then
+ self:Despool(Prio)
+ -- Note: We might not get here if the user-supplied callback function errors out! Take care!
+ end
+ end
+ end
+
+end
+
+
+
+
+-----------------------------------------------------------------------
+-- Spooling logic
+
+function ChatThrottleLib:Enqueue(prioname, pipename, msg)
+ local Prio = self.Prio[prioname]
+ local pipe = Prio.ByName[pipename]
+ if not pipe then
+ self.Frame:Show()
+ pipe = NewPipe()
+ pipe.name = pipename
+ Prio.ByName[pipename] = pipe
+ Prio.Ring:Add(pipe)
+ end
+
+ pipe[#pipe + 1] = msg
+
+ self.bQueueing = true
+end
+
+function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, language, destination, queueName, callbackFn, callbackArg)
+ if not self or not prio or not prefix or not text or not self.Prio[prio] then
+ error('Usage: ChatThrottleLib:SendChatMessage("{BULK||NORMAL||ALERT}", "prefix", "text"[, "chattype"[, "language"[, "destination"]]]', 2)
+ end
+ if callbackFn and type(callbackFn)~="function" then
+ error('ChatThrottleLib:ChatMessage(): callbackFn: expected function, got '..type(callbackFn), 2)
+ end
+
+ local nSize = text:len()
+
+ if nSize>255 then
+ error("ChatThrottleLib:SendChatMessage(): message length cannot exceed 255 bytes", 2)
+ end
+
+ nSize = nSize + self.MSG_OVERHEAD
+
+ -- Check if there's room in the global available bandwidth gauge to send directly
+ if not self.bQueueing and nSize < self:UpdateAvail() then
+ self.avail = self.avail - nSize
+ bMyTraffic = true
+ _G.SendChatMessage(text, chattype, language, destination)
+ bMyTraffic = false
+ self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize
+ if callbackFn then
+ callbackFn (callbackArg, true)
+ end
+ -- USER CALLBACK MAY ERROR
+ return
+ end
+
+ -- Message needs to be queued
+ local msg = NewMsg()
+ msg.f = _G.SendChatMessage
+ msg[1] = text
+ msg[2] = chattype or "SAY"
+ msg[3] = language
+ msg[4] = destination
+ msg.n = 4
+ msg.nSize = nSize
+ msg.callbackFn = callbackFn
+ msg.callbackArg = callbackArg
+
+ self:Enqueue(prio, queueName or (prefix..(chattype or "SAY")..(destination or "")), msg)
+end
+
+
+function ChatThrottleLib:SendAddonMessage(prio, prefix, text, chattype, target, queueName, callbackFn, callbackArg)
+ if not self or not prio or not prefix or not text or not chattype or not self.Prio[prio] then
+ error('Usage: ChatThrottleLib:SendAddonMessage("{BULK||NORMAL||ALERT}", "prefix", "text", "chattype"[, "target"])', 2)
+ end
+ if callbackFn and type(callbackFn)~="function" then
+ error('ChatThrottleLib:SendAddonMessage(): callbackFn: expected function, got '..type(callbackFn), 2)
+ end
+
+ local nSize = text:len();
+
+ if C_ChatInfo or RegisterAddonMessagePrefix then
+ if nSize>255 then
+ error("ChatThrottleLib:SendAddonMessage(): message length cannot exceed 255 bytes", 2)
+ end
+ else
+ nSize = nSize + prefix:len() + 1
+ if nSize>255 then
+ error("ChatThrottleLib:SendAddonMessage(): prefix + message length cannot exceed 254 bytes", 2)
+ end
+ end
+
+ nSize = nSize + self.MSG_OVERHEAD;
+
+ -- Check if there's room in the global available bandwidth gauge to send directly
+ if not self.bQueueing and nSize < self:UpdateAvail() then
+ self.avail = self.avail - nSize
+ bMyTraffic = true
+ if _G.C_ChatInfo then
+ _G.C_ChatInfo.SendAddonMessage(prefix, text, chattype, target)
+ else
+ _G.SendAddonMessage(prefix, text, chattype, target)
+ end
+ bMyTraffic = false
+ self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize
+ if callbackFn then
+ callbackFn (callbackArg, true)
+ end
+ -- USER CALLBACK MAY ERROR
+ return
+ end
+
+ -- Message needs to be queued
+ local msg = NewMsg()
+ msg.f = _G.C_ChatInfo and _G.C_ChatInfo.SendAddonMessage or _G.SendAddonMessage
+ msg[1] = prefix
+ msg[2] = text
+ msg[3] = chattype
+ msg[4] = target
+ msg.n = (target~=nil) and 4 or 3;
+ msg.nSize = nSize
+ msg.callbackFn = callbackFn
+ msg.callbackArg = callbackArg
+
+ self:Enqueue(prio, queueName or (prefix..chattype..(target or "")), msg)
+end
+
+
+
+
+-----------------------------------------------------------------------
+-- Get the ball rolling!
+
+ChatThrottleLib:Init()
+
+--[[ WoWBench debugging snippet
+if(WOWB_VER) then
+ local function SayTimer()
+ print("SAY: "..GetTime().." "..arg1)
+ end
+ ChatThrottleLib.Frame:SetScript("OnEvent", SayTimer)
+ ChatThrottleLib.Frame:RegisterEvent("CHAT_MSG_SAY")
+end
+]]
+
+
diff --git a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfig-3.0.lua b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfig-3.0.lua
index 5071cdc..2233c4c 100644
--- a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfig-3.0.lua
+++ b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfig-3.0.lua
@@ -3,7 +3,7 @@
-- as well as associate it with a slash command.
-- @class file
-- @name AceConfig-3.0
--- @release $Id: AceConfig-3.0.lua 1202 2019-05-15 23:11:22Z nevcairiel $
+-- @release $Id$
--[[
AceConfig-3.0
diff --git a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfig-3.0.xml b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfig-3.0.xml
index a3569b7..87972ad 100644
--- a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfig-3.0.xml
+++ b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfig-3.0.xml
@@ -5,4 +5,4 @@
-
+
\ No newline at end of file
diff --git a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua
index 6dd6438..9e883a2 100644
--- a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua
+++ b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.lua
@@ -1,7 +1,7 @@
--- AceConfigCmd-3.0 handles access to an options table through the "command line" interface via the ChatFrames.
-- @class file
-- @name AceConfigCmd-3.0
--- @release $Id: AceConfigCmd-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
+-- @release $Id$
--[[
AceConfigCmd-3.0
diff --git a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml
index 9e157b5..188d354 100644
--- a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml
+++ b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigCmd-3.0/AceConfigCmd-3.0.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
index 4649c73..4446f4c 100644
--- a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
+++ b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua
@@ -1,13 +1,13 @@
--- AceConfigDialog-3.0 generates AceGUI-3.0 based windows based on option tables.
-- @class file
-- @name AceConfigDialog-3.0
--- @release $Id: AceConfigDialog-3.0.lua 1292 2022-09-29 08:00:11Z nevcairiel $
+-- @release $Id$
local LibStub = LibStub
local gui = LibStub("AceGUI-3.0")
local reg = LibStub("AceConfigRegistry-3.0")
-local MAJOR, MINOR = "AceConfigDialog-3.0", 85
+local MAJOR, MINOR = "AceConfigDialog-3.0", 86
local AceConfigDialog, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfigDialog then return end
@@ -147,6 +147,7 @@ local stringIsLiteral = {
width = true,
image = true,
fontSize = true,
+ tooltipHyperlink = true
}
--Is Never a function or method
@@ -501,6 +502,14 @@ local function OptionOnMouseOver(widget, event)
local tooltip = AceConfigDialog.tooltip
tooltip:SetOwner(widget.frame, "ANCHOR_TOPRIGHT")
+
+ local tooltipHyperlink = GetOptionsMemberValue("tooltipHyperlink", opt, options, path, appName)
+ if tooltipHyperlink then
+ tooltip:SetHyperlink(tooltipHyperlink)
+ tooltip:Show()
+ return
+ end
+
local name = GetOptionsMemberValue("name", opt, options, path, appName)
local desc = GetOptionsMemberValue("desc", opt, options, path, appName)
local usage = GetOptionsMemberValue("usage", opt, options, path, appName)
diff --git a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml
index 8e1e606..86ce057 100644
--- a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml
+++ b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua
index f8d9225..7d0d108 100644
--- a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua
+++ b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.lua
@@ -8,10 +8,10 @@
-- :IterateOptionsTables() (and :GetOptionsTable() if only given one argument) return a function reference that the requesting config handling addon must call with valid "uiType", "uiName".
-- @class file
-- @name AceConfigRegistry-3.0
--- @release $Id: AceConfigRegistry-3.0.lua 1207 2019-06-23 12:08:33Z nevcairiel $
+-- @release $Id$
local CallbackHandler = LibStub("CallbackHandler-1.0")
-local MAJOR, MINOR = "AceConfigRegistry-3.0", 20
+local MAJOR, MINOR = "AceConfigRegistry-3.0", 21
local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR)
if not AceConfigRegistry then return end
@@ -83,6 +83,7 @@ local basekeys={
dialogHidden=optmethodbool,
dropdownHidden=optmethodbool,
cmdHidden=optmethodbool,
+ tooltipHyperlink=optstringfunc,
icon=optstringnumberfunc,
iconCoords=optmethodtable,
handler=opttable,
diff --git a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml
index 4ea69ca..101bfda 100644
--- a/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml
+++ b/MythicPlusDrop/Libs/AceConfig-3.0/AceConfigRegistry-3.0/AceConfigRegistry-3.0.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/MythicPlusDrop/Libs/AceConsole-3.0/AceConsole-3.0.lua b/MythicPlusDrop/Libs/AceConsole-3.0/AceConsole-3.0.lua
index 2361a3b..8e5ec81 100644
--- a/MythicPlusDrop/Libs/AceConsole-3.0/AceConsole-3.0.lua
+++ b/MythicPlusDrop/Libs/AceConsole-3.0/AceConsole-3.0.lua
@@ -9,7 +9,7 @@
-- make into AceConsole.
-- @class file
-- @name AceConsole-3.0
--- @release $Id: AceConsole-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
+-- @release $Id$
local MAJOR,MINOR = "AceConsole-3.0", 7
local AceConsole, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
diff --git a/MythicPlusDrop/Libs/AceConsole-3.0/AceConsole-3.0.xml b/MythicPlusDrop/Libs/AceConsole-3.0/AceConsole-3.0.xml
index 4f4699a..be9f47c 100644
--- a/MythicPlusDrop/Libs/AceConsole-3.0/AceConsole-3.0.xml
+++ b/MythicPlusDrop/Libs/AceConsole-3.0/AceConsole-3.0.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/MythicPlusDrop/Libs/AceDB-3.0/AceDB-3.0.lua b/MythicPlusDrop/Libs/AceDB-3.0/AceDB-3.0.lua
index 804cf2b..43c64c4 100644
--- a/MythicPlusDrop/Libs/AceDB-3.0/AceDB-3.0.lua
+++ b/MythicPlusDrop/Libs/AceDB-3.0/AceDB-3.0.lua
@@ -40,7 +40,7 @@
-- end
-- @class file
-- @name AceDB-3.0.lua
--- @release $Id: AceDB-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
+-- @release $Id$
local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 27
local AceDB = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
diff --git a/MythicPlusDrop/Libs/AceDB-3.0/AceDB-3.0.xml b/MythicPlusDrop/Libs/AceDB-3.0/AceDB-3.0.xml
index 108fc70..46b20ba 100644
--- a/MythicPlusDrop/Libs/AceDB-3.0/AceDB-3.0.xml
+++ b/MythicPlusDrop/Libs/AceDB-3.0/AceDB-3.0.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/MythicPlusDrop/Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua b/MythicPlusDrop/Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua
index 9029c66..236cf7b 100644
--- a/MythicPlusDrop/Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua
+++ b/MythicPlusDrop/Libs/AceDBOptions-3.0/AceDBOptions-3.0.lua
@@ -1,7 +1,7 @@
--- AceDBOptions-3.0 provides a universal AceConfig options screen for managing AceDB-3.0 profiles.
-- @class file
-- @name AceDBOptions-3.0
--- @release $Id: AceDBOptions-3.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $
+-- @release $Id$
local ACEDBO_MAJOR, ACEDBO_MINOR = "AceDBOptions-3.0", 15
local AceDBOptions = LibStub:NewLibrary(ACEDBO_MAJOR, ACEDBO_MINOR)
diff --git a/MythicPlusDrop/Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml b/MythicPlusDrop/Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml
index 51305f9..2668fb0 100644
--- a/MythicPlusDrop/Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml
+++ b/MythicPlusDrop/Libs/AceDBOptions-3.0/AceDBOptions-3.0.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/MythicPlusDrop/Libs/AceEvent-3.0/AceEvent-3.0.lua b/MythicPlusDrop/Libs/AceEvent-3.0/AceEvent-3.0.lua
index 578ae25..9f96bf3 100644
--- a/MythicPlusDrop/Libs/AceEvent-3.0/AceEvent-3.0.lua
+++ b/MythicPlusDrop/Libs/AceEvent-3.0/AceEvent-3.0.lua
@@ -2,15 +2,17 @@
-- All dispatching is done using **CallbackHandler-1.0**. AceEvent is a simple wrapper around
-- CallbackHandler, and dispatches all game events or addon message to the registrees.
--
--- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent:Embed(MyAddon) or by
+-- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent: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 AceEvent itself.\\
-- It is recommended to embed AceEvent, otherwise you'll have to specify a custom `self` on all calls you
-- make into AceEvent.
-- @class file
-- @name AceEvent-3.0
--- @release $Id: AceEvent-3.0.lua 975 2010-10-23 11:26:18Z nevcairiel $
-local MAJOR, MINOR = "AceEvent-3.0", 3
+-- @release $Id$
+local CallbackHandler = LibStub("CallbackHandler-1.0")
+
+local MAJOR, MINOR = "AceEvent-3.0", 4
local AceEvent = LibStub:NewLibrary(MAJOR, MINOR)
if not AceEvent then return end
@@ -18,29 +20,27 @@ if not AceEvent then return end
-- Lua APIs
local pairs = pairs
-local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
-
AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame
AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib
-- APIs and registry for blizzard events, using CallbackHandler lib
if not AceEvent.events then
- AceEvent.events = CallbackHandler:New(AceEvent,
+ AceEvent.events = CallbackHandler:New(AceEvent,
"RegisterEvent", "UnregisterEvent", "UnregisterAllEvents")
end
-function AceEvent.events:OnUsed(target, eventname)
+function AceEvent.events:OnUsed(target, eventname)
AceEvent.frame:RegisterEvent(eventname)
end
-function AceEvent.events:OnUnused(target, eventname)
+function AceEvent.events:OnUnused(target, eventname)
AceEvent.frame:UnregisterEvent(eventname)
end
-- APIs and registry for IPC messages, using CallbackHandler lib
if not AceEvent.messages then
- AceEvent.messages = CallbackHandler:New(AceEvent,
+ AceEvent.messages = CallbackHandler:New(AceEvent,
"RegisterMessage", "UnregisterMessage", "UnregisterAllMessages"
)
AceEvent.SendMessage = AceEvent.messages.Fire
diff --git a/MythicPlusDrop/Libs/AceGUI-3.0/AceGUI-3.0.lua b/MythicPlusDrop/Libs/AceGUI-3.0/AceGUI-3.0.lua
index f05b1ed..35b176e 100644
--- a/MythicPlusDrop/Libs/AceGUI-3.0/AceGUI-3.0.lua
+++ b/MythicPlusDrop/Libs/AceGUI-3.0/AceGUI-3.0.lua
@@ -24,7 +24,7 @@
-- f:AddChild(btn)
-- @class file
-- @name AceGUI-3.0
--- @release $Id: AceGUI-3.0.lua 1288 2022-09-25 14:19:00Z funkehdude $
+-- @release $Id$
local ACEGUI_MAJOR, ACEGUI_MINOR = "AceGUI-3.0", 41
local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
diff --git a/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-Button-ElvUI.lua b/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-Button-ElvUI.lua
new file mode 100644
index 0000000..185cf9b
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-Button-ElvUI.lua
@@ -0,0 +1,182 @@
+--[[-----------------------------------------------------------------------------
+Button Widget (Modified to change text color on SetDisabled method)
+Graphical Button.
+-------------------------------------------------------------------------------]]
+local Type, Version = "Button-ElvUI", 3
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local pairs = pairs
+
+-- WoW APIs
+local _G = _G
+local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent
+local IsShiftKeyDown = IsShiftKeyDown
+local PlaySoundKitID = PlaySoundKitID
+-- GLOBALS: GameTooltip, ElvUI
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local dragdropButton
+local function lockTooltip()
+ GameTooltip:ClearAllPoints()
+ GameTooltip:SetOwner(UIParent, "ANCHOR_CURSOR")
+ GameTooltip:SetText(" ")
+ GameTooltip:Show()
+end
+local function dragdrop_OnMouseDown(frame, ...)
+ if frame.obj.dragOnMouseDown then
+ dragdropButton.mouseDownFrame = frame
+ dragdropButton:SetText(frame.obj.value or "Unknown")
+ dragdropButton:SetSize(frame:GetSize())
+ frame.obj.dragOnMouseDown(frame, ...)
+ end
+end
+local function dragdrop_OnMouseUp(frame, ...)
+ if frame.obj.dragOnMouseUp then
+ frame:SetAlpha(1)
+ if dragdropButton.enteredFrame and dragdropButton.enteredFrame ~= frame and dragdropButton.enteredFrame:IsMouseOver() then
+ frame.obj.dragOnMouseUp(frame, ...)
+ frame.obj.ActivateMultiControl(frame.obj, ...)
+ end
+
+ GameTooltip:Hide()
+ dragdropButton:Hide()
+ dragdropButton.enteredFrame = nil
+ dragdropButton.mouseDownFrame = nil
+ end
+end
+local function dragdrop_OnLeave(frame, ...)
+ if frame.obj.dragOnLeave then
+ if dragdropButton.mouseDownFrame then
+ lockTooltip()
+ end
+ if frame == dragdropButton.mouseDownFrame then
+ frame:SetAlpha(0)
+ dragdropButton:Show()
+ frame.obj.dragOnLeave(frame, ...)
+ end
+ end
+end
+local function dragdrop_OnEnter(frame, ...)
+ if frame.obj.dragOnEnter and dragdropButton:IsShown() then
+ dragdropButton.enteredFrame = frame
+ lockTooltip()
+ frame.obj.dragOnEnter(frame, ...)
+ end
+end
+local function dragdrop_OnClick(frame, ...)
+ local button = ...
+ if frame.obj.dragOnClick and button == "RightButton" then
+ frame.obj.dragOnClick(frame, ...)
+ frame.obj.ActivateMultiControl(frame.obj, ...)
+ elseif frame.obj.stateSwitchOnClick and (button == "LeftButton") and IsShiftKeyDown() then
+ frame.obj.stateSwitchOnClick(frame, ...)
+ frame.obj.ActivateMultiControl(frame.obj, ...)
+ end
+end
+
+local function Button_OnClick(frame, ...)
+ AceGUI:ClearFocus()
+ PlaySound(PlaySoundKitID and "igMainMenuOption" or 852) -- SOUNDKIT.IG_MAINMENU_OPTION
+ frame.obj:Fire("OnClick", ...)
+end
+
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ -- restore default values
+ self:SetHeight(24)
+ self:SetWidth(200)
+ self:SetDisabled(false)
+ self:SetAutoWidth(false)
+ self:SetText()
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetText"] = function(self, text)
+ self.text:SetText(text)
+ if self.autoWidth then
+ self:SetWidth(self.text:GetStringWidth() + 30)
+ end
+ end,
+
+ ["SetAutoWidth"] = function(self, autoWidth)
+ self.autoWidth = autoWidth
+ if self.autoWidth then
+ self:SetWidth(self.text:GetStringWidth() + 30)
+ end
+ end,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.frame:Disable()
+ self.text:SetTextColor(0.4, 0.4, 0.4)
+ else
+ self.frame:Enable()
+ self.text:SetTextColor(1, 0.82, 0)
+ end
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local function Constructor()
+ local name = "AceGUI30Button" .. AceGUI:GetNextWidgetNum(Type)
+ local frame = CreateFrame("Button", name, UIParent, "UIPanelButtonTemplate")
+ frame:Hide()
+ frame:EnableMouse(true)
+ frame:RegisterForClicks("AnyUp")
+ frame:SetScript("OnClick", Button_OnClick)
+ frame:SetScript("OnEnter", Control_OnEnter)
+ frame:SetScript("OnLeave", Control_OnLeave)
+
+ -- dragdrop
+ if not dragdropButton then
+ dragdropButton = CreateFrame("Button", "ElvUIAceGUI30DragDropButton", UIParent, "UIPanelButtonTemplate")
+ dragdropButton:SetFrameStrata("TOOLTIP")
+ dragdropButton:SetFrameLevel(5)
+ dragdropButton:SetPoint('BOTTOM', GameTooltip, "BOTTOM", 0, 10)
+ dragdropButton:Hide()
+ ElvUI[1]:GetModule('Skins'):HandleButton(dragdropButton)
+ end
+ frame:HookScript("OnClick", dragdrop_OnClick)
+ frame:HookScript("OnEnter", dragdrop_OnEnter)
+ frame:HookScript("OnLeave", dragdrop_OnLeave)
+ frame:HookScript("OnMouseUp", dragdrop_OnMouseUp)
+ frame:HookScript("OnMouseDown", dragdrop_OnMouseDown)
+
+ local text = frame:GetFontString()
+ text:ClearAllPoints()
+ text:SetPoint("TOPLEFT", 15, -1)
+ text:SetPoint("BOTTOMRIGHT", -15, 1)
+ text:SetJustifyV("MIDDLE")
+
+ local widget = {
+ text = text,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type, Constructor, Version)
diff --git a/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua b/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua
index 947184c..6fe30ea 100644
--- a/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua
+++ b/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown-Items.lua
@@ -1,4 +1,4 @@
---[[ $Id: AceGUIWidget-DropDown-Items.lua 1272 2022-08-29 15:56:35Z nevcairiel $ ]]--
+--[[ $Id$ ]]--
local AceGUI = LibStub("AceGUI-3.0")
diff --git a/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua b/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua
index 59c7f53..9fde707 100644
--- a/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua
+++ b/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-DropDown.lua
@@ -1,4 +1,4 @@
---[[ $Id: AceGUIWidget-DropDown.lua 1284 2022-09-25 09:15:30Z nevcairiel $ ]]--
+--[[ $Id$ ]]--
local AceGUI = LibStub("AceGUI-3.0")
-- Lua APIs
diff --git a/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-Slider-ElvUI.lua b/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-Slider-ElvUI.lua
new file mode 100644
index 0000000..40f6ab7
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceGUI-3.0/widgets/AceGUIWidget-Slider-ElvUI.lua
@@ -0,0 +1,287 @@
+--[[-----------------------------------------------------------------------------
+Slider Widget
+Graphical Slider, like, for Range values.
+-------------------------------------------------------------------------------]]
+local Type, Version = "Slider-ElvUI", 1
+local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
+if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
+
+-- Lua APIs
+local min, max, floor = math.min, math.max, math.floor
+local tonumber, pairs = tonumber, pairs
+
+-- WoW APIs
+local PlaySound = PlaySound
+local CreateFrame, UIParent = CreateFrame, UIParent
+
+-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
+-- List them here for Mikk's FindGlobals script
+-- GLOBALS: GameFontHighlightSmall
+
+--[[-----------------------------------------------------------------------------
+Support functions
+-------------------------------------------------------------------------------]]
+local function UpdateText(self)
+ local value = self.value or 0
+ if self.ispercent then
+ self.editbox:SetText(("%s%%"):format(floor(value * 1000 + 0.5) / 10))
+ else
+ self.editbox:SetText(floor(value * 100 + 0.5) / 100)
+ end
+end
+
+local function UpdateLabels(self)
+ local min, max = (self.min or 0), (self.max or 100)
+ if self.ispercent then
+ self.lowtext:SetFormattedText("%s%%", (min * 100))
+ self.hightext:SetFormattedText("%s%%", (max * 100))
+ else
+ self.lowtext:SetText(min)
+ self.hightext:SetText(max)
+ end
+end
+
+--[[-----------------------------------------------------------------------------
+Scripts
+-------------------------------------------------------------------------------]]
+local function Control_OnEnter(frame)
+ frame.obj:Fire("OnEnter")
+end
+
+local function Control_OnLeave(frame)
+ frame.obj:Fire("OnLeave")
+end
+
+local function Frame_OnMouseDown(frame)
+ frame.obj.slider:EnableMouseWheel(true)
+ AceGUI:ClearFocus()
+end
+
+local function Slider_OnValueChanged(frame, newvalue)
+ local self = frame.obj
+ if not frame.setup then
+ if self.step and self.step > 0 then
+ local min_value = self.min or 0
+ newvalue = floor((newvalue - min_value) / self.step + 0.5) * self.step + min_value
+ end
+ if newvalue ~= self.value and not self.disabled then
+ self.value = newvalue
+ self:Fire("OnValueChanged", newvalue)
+ end
+ if self.value then
+ UpdateText(self)
+ end
+ end
+end
+
+local function Slider_OnMouseUp(frame)
+ local self = frame.obj
+ self:Fire("OnMouseUp", self.value)
+end
+
+local function Slider_OnMouseWheel(frame, v)
+ local self = frame.obj
+ if not self.disabled then
+ local value = self.value
+ if v > 0 then
+ value = min(value + (self.step or 1), self.max)
+ else
+ value = max(value - (self.step or 1), self.min)
+ end
+ self.slider:SetValue(value)
+ end
+end
+
+local function EditBox_OnEscapePressed(frame)
+ frame:ClearFocus()
+end
+
+local function EditBox_OnEnterPressed(frame)
+ local self = frame.obj
+ local value = frame:GetText()
+ if self.ispercent then
+ value = value:gsub('%%', '')
+ value = tonumber(value) / 100
+ else
+ value = tonumber(value)
+ end
+
+ if value then
+ PlaySound(856) -- SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON
+ self.slider:SetValue(value)
+ self:Fire("OnMouseUp", value)
+ end
+end
+
+local function EditBox_OnEnter(frame)
+ frame:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
+end
+
+local function EditBox_OnLeave(frame)
+ frame:SetBackdropBorderColor(0.3, 0.3, 0.3, 0.8)
+end
+
+--[[-----------------------------------------------------------------------------
+Methods
+-------------------------------------------------------------------------------]]
+local methods = {
+ ["OnAcquire"] = function(self)
+ self:SetWidth(200)
+ self:SetHeight(44)
+ self:SetDisabled(false)
+ self:SetIsPercent(nil)
+ self:SetSliderValues(0,100,1)
+ self:SetValue(0)
+ self.slider:EnableMouseWheel(false)
+ end,
+
+ -- ["OnRelease"] = nil,
+
+ ["SetDisabled"] = function(self, disabled)
+ self.disabled = disabled
+ if disabled then
+ self.slider:EnableMouse(false)
+ self.label:SetTextColor(.5, .5, .5)
+ self.hightext:SetTextColor(.5, .5, .5)
+ self.lowtext:SetTextColor(.5, .5, .5)
+ --self.valuetext:SetTextColor(.5, .5, .5)
+ self.editbox:SetTextColor(.5, .5, .5)
+ self.editbox:EnableMouse(false)
+ self.editbox:ClearFocus()
+ else
+ self.slider:EnableMouse(true)
+ self.label:SetTextColor(1, .82, 0)
+ self.hightext:SetTextColor(1, 1, 1)
+ self.lowtext:SetTextColor(1, 1, 1)
+ --self.valuetext:SetTextColor(1, 1, 1)
+ self.editbox:SetTextColor(1, 1, 1)
+ self.editbox:EnableMouse(true)
+ end
+ end,
+
+ ["SetValue"] = function(self, value)
+ self.slider.setup = true
+ self.slider:SetValue(value)
+ self.value = value
+ UpdateText(self)
+ self.slider.setup = nil
+ end,
+
+ ["GetValue"] = function(self)
+ return self.value
+ end,
+
+ ["SetLabel"] = function(self, text)
+ self.label:SetText(text)
+ end,
+
+ ["SetSliderValues"] = function(self, min, max, step)
+ if type(min) == 'function' then min = min() end
+ if type(max) == 'function' then max = max() end
+
+ local frame = self.slider
+ frame.setup = true
+ self.min = min
+ self.max = max
+ self.step = step
+ frame:SetMinMaxValues(min or 0, max or 100)
+ UpdateLabels(self)
+ frame:SetValueStep(step or 1)
+ if self.value then
+ frame:SetValue(self.value)
+ end
+ frame.setup = nil
+ end,
+
+ ["SetIsPercent"] = function(self, value)
+ self.ispercent = value
+ UpdateLabels(self)
+ UpdateText(self)
+ end
+}
+
+--[[-----------------------------------------------------------------------------
+Constructor
+-------------------------------------------------------------------------------]]
+local SliderBackdrop = {
+ bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
+ edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
+ tile = true, tileSize = 8, edgeSize = 8,
+ insets = { left = 3, right = 3, top = 6, bottom = 6 }
+}
+
+local ManualBackdrop = {
+ bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ edgeFile = "Interface\\ChatFrame\\ChatFrameBackground",
+ tile = true, edgeSize = 1, tileSize = 5,
+}
+
+local function Constructor()
+ local frame = CreateFrame("Frame", nil, UIParent)
+
+ frame:EnableMouse(true)
+ frame:SetScript("OnMouseDown", Frame_OnMouseDown)
+
+ local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
+ label:SetPoint("TOPLEFT")
+ label:SetPoint("TOPRIGHT")
+ label:SetJustifyH("CENTER")
+ label:SetHeight(15)
+
+ local slider = CreateFrame("Slider", nil, frame)
+ slider:SetOrientation("HORIZONTAL")
+ slider:SetHeight(15)
+ slider:SetHitRectInsets(0, 0, -10, 0)
+ slider:SetBackdrop(SliderBackdrop)
+ slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Horizontal")
+ slider:SetPoint("TOP", label, "BOTTOM")
+ slider:SetPoint("LEFT", 3, 0)
+ slider:SetPoint("RIGHT", -3, 0)
+ slider:SetValue(0)
+ slider:SetScript("OnValueChanged",Slider_OnValueChanged)
+ slider:SetScript("OnEnter", Control_OnEnter)
+ slider:SetScript("OnLeave", Control_OnLeave)
+ slider:SetScript("OnMouseUp", Slider_OnMouseUp)
+ slider:SetScript("OnMouseWheel", Slider_OnMouseWheel)
+
+ local lowtext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ lowtext:SetPoint("TOPLEFT", slider, "BOTTOMLEFT", 2, 3)
+
+ local hightext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ hightext:SetPoint("TOPRIGHT", slider, "BOTTOMRIGHT", -2, 3)
+
+ local editbox = CreateFrame("EditBox", nil, frame)
+ editbox:SetAutoFocus(false)
+ editbox:SetFontObject(GameFontHighlightSmall)
+ editbox:SetPoint("TOP", slider, "BOTTOM")
+ editbox:SetHeight(14)
+ editbox:SetWidth(70)
+ editbox:SetJustifyH("CENTER")
+ editbox:EnableMouse(true)
+ editbox:SetBackdrop(ManualBackdrop)
+ editbox:SetBackdropColor(0, 0, 0, 0.5)
+ editbox:SetBackdropBorderColor(0.3, 0.3, 0.30, 0.80)
+ editbox:SetScript("OnEnter", EditBox_OnEnter)
+ editbox:SetScript("OnLeave", EditBox_OnLeave)
+ editbox:SetScript("OnEnterPressed", EditBox_OnEnterPressed)
+ editbox:SetScript("OnEscapePressed", EditBox_OnEscapePressed)
+
+ local widget = {
+ label = label,
+ slider = slider,
+ lowtext = lowtext,
+ hightext = hightext,
+ editbox = editbox,
+ alignoffset = 25,
+ frame = frame,
+ type = Type
+ }
+ for method, func in pairs(methods) do
+ widget[method] = func
+ end
+ slider.obj, editbox.obj = widget, widget
+
+ return AceGUI:RegisterAsWidget(widget)
+end
+
+AceGUI:RegisterWidgetType(Type,Constructor,Version)
diff --git a/MythicPlusDrop/Libs/AceHook-3.0/AceHook-3.0.lua b/MythicPlusDrop/Libs/AceHook-3.0/AceHook-3.0.lua
new file mode 100644
index 0000000..3410f2c
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceHook-3.0/AceHook-3.0.lua
@@ -0,0 +1,510 @@
+--- **AceHook-3.0** offers safe Hooking/Unhooking of functions, methods and frame scripts.
+-- Using AceHook-3.0 is recommended when you need to unhook your hooks again, so the hook chain isn't broken
+-- when you manually restore the original function.
+--
+-- **AceHook-3.0** can be embeded into your addon, either explicitly by calling AceHook: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 AceHook itself.\\
+-- It is recommended to embed AceHook, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceHook.
+-- @class file
+-- @name AceHook-3.0
+-- @release $Id$
+local ACEHOOK_MAJOR, ACEHOOK_MINOR = "AceHook-3.0", 9
+local AceHook, oldminor = LibStub:NewLibrary(ACEHOOK_MAJOR, ACEHOOK_MINOR)
+
+if not AceHook then return end -- No upgrade needed
+
+AceHook.embeded = AceHook.embeded or {}
+AceHook.registry = AceHook.registry or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end })
+AceHook.handlers = AceHook.handlers or {}
+AceHook.actives = AceHook.actives or {}
+AceHook.scripts = AceHook.scripts or {}
+AceHook.onceSecure = AceHook.onceSecure or {}
+AceHook.hooks = AceHook.hooks or {}
+
+-- local upvalues
+local registry = AceHook.registry
+local handlers = AceHook.handlers
+local actives = AceHook.actives
+local scripts = AceHook.scripts
+local onceSecure = AceHook.onceSecure
+
+-- Lua APIs
+local pairs, next, type = pairs, next, type
+local format = string.format
+local assert, error = assert, error
+
+-- WoW APIs
+local issecurevariable, hooksecurefunc = issecurevariable, hooksecurefunc
+local _G = _G
+
+-- functions for later definition
+local donothing, createHook, hook
+
+local protectedScripts = {
+ OnClick = true,
+}
+
+-- upgrading of embeded is done at the bottom of the file
+
+local mixins = {
+ "Hook", "SecureHook",
+ "HookScript", "SecureHookScript",
+ "Unhook", "UnhookAll",
+ "IsHooked",
+ "RawHook", "RawHookScript"
+}
+
+-- AceHook:Embed( target )
+-- target (object) - target object to embed AceHook in
+--
+-- Embeds AceEevent into the target object making the functions from the mixins list available on target:..
+function AceHook:Embed( target )
+ for k, v in pairs( mixins ) do
+ target[v] = self[v]
+ end
+ self.embeded[target] = true
+ -- inject the hooks table safely
+ target.hooks = target.hooks or {}
+ return target
+end
+
+-- AceHook:OnEmbedDisable( target )
+-- target (object) - target object that is being disabled
+--
+-- Unhooks all hooks when the target disables.
+-- this method should be called by the target manually or by an addon framework
+function AceHook:OnEmbedDisable( target )
+ target:UnhookAll()
+end
+
+function createHook(self, handler, orig, secure, failsafe)
+ local uid
+ local method = type(handler) == "string"
+ if failsafe and not secure then
+ -- failsafe hook creation
+ uid = function(...)
+ if actives[uid] then
+ if method then
+ self[handler](self, ...)
+ else
+ handler(...)
+ end
+ end
+ return orig(...)
+ end
+ -- /failsafe hook
+ else
+ -- all other hooks
+ uid = function(...)
+ if actives[uid] then
+ if method then
+ return self[handler](self, ...)
+ else
+ return handler(...)
+ end
+ elseif not secure then -- backup on non secure
+ return orig(...)
+ end
+ end
+ -- /hook
+ end
+ return uid
+end
+
+function donothing() end
+
+function hook(self, obj, method, handler, script, secure, raw, forceSecure, usage)
+ if not handler then handler = method end
+
+ -- These asserts make sure AceHooks's devs play by the rules.
+ assert(not script or type(script) == "boolean")
+ assert(not secure or type(secure) == "boolean")
+ assert(not raw or type(raw) == "boolean")
+ assert(not forceSecure or type(forceSecure) == "boolean")
+ assert(usage)
+
+ -- Error checking Battery!
+ if obj and type(obj) ~= "table" then
+ error(format("%s: 'object' - nil or table expected got %s", usage, type(obj)), 3)
+ end
+ if type(method) ~= "string" then
+ error(format("%s: 'method' - string expected got %s", usage, type(method)), 3)
+ end
+ if type(handler) ~= "string" and type(handler) ~= "function" then
+ error(format("%s: 'handler' - nil, string, or function expected got %s", usage, type(handler)), 3)
+ end
+ if type(handler) == "string" and type(self[handler]) ~= "function" then
+ error(format("%s: 'handler' - Handler specified does not exist at self[handler]", usage), 3)
+ end
+ if script then
+ if not obj or not obj.GetScript or not obj:HasScript(method) then
+ error(format("%s: You can only hook a script on a frame object", usage), 3)
+ end
+ if not secure and obj.IsProtected and obj:IsProtected() and protectedScripts[method] then
+ error(format("Cannot hook secure script %q; Use SecureHookScript(obj, method, [handler]) instead.", method), 3)
+ end
+ else
+ local issecure
+ if obj then
+ issecure = onceSecure[obj] and onceSecure[obj][method] or issecurevariable(obj, method)
+ else
+ issecure = onceSecure[method] or issecurevariable(method)
+ end
+ if issecure then
+ if forceSecure then
+ if obj then
+ onceSecure[obj] = onceSecure[obj] or {}
+ onceSecure[obj][method] = true
+ else
+ onceSecure[method] = true
+ end
+ elseif not secure then
+ error(format("%s: Attempt to hook secure function %s. Use `SecureHook' or add `true' to the argument list to override.", usage, method), 3)
+ end
+ end
+ end
+
+ local uid
+ if obj then
+ uid = registry[self][obj] and registry[self][obj][method]
+ else
+ uid = registry[self][method]
+ end
+
+ if uid then
+ if actives[uid] then
+ -- Only two sane choices exist here. We either a) error 100% of the time or b) always unhook and then hook
+ -- choice b would likely lead to odd debuging conditions or other mysteries so we're going with a.
+ error(format("Attempting to rehook already active hook %s.", method))
+ end
+
+ if handlers[uid] == handler then -- turn on a decative hook, note enclosures break this ability, small memory leak
+ actives[uid] = true
+ return
+ elseif obj then -- is there any reason not to call unhook instead of doing the following several lines?
+ if self.hooks and self.hooks[obj] then
+ self.hooks[obj][method] = nil
+ end
+ registry[self][obj][method] = nil
+ else
+ if self.hooks then
+ self.hooks[method] = nil
+ end
+ registry[self][method] = nil
+ end
+ handlers[uid], actives[uid], scripts[uid] = nil, nil, nil
+ end
+
+ local orig
+ if script then
+ orig = obj:GetScript(method) or donothing
+ elseif obj then
+ orig = obj[method]
+ else
+ orig = _G[method]
+ end
+
+ if not orig then
+ error(format("%s: Attempting to hook a non existing target", usage), 3)
+ end
+
+ uid = createHook(self, handler, orig, secure, not (raw or secure))
+
+ if obj then
+ self.hooks[obj] = self.hooks[obj] or {}
+ registry[self][obj] = registry[self][obj] or {}
+ registry[self][obj][method] = uid
+
+ if not secure then
+ self.hooks[obj][method] = orig
+ end
+
+ if script then
+ if not secure then
+ obj:SetScript(method, uid)
+ else
+ obj:HookScript(method, uid)
+ end
+ else
+ if not secure then
+ obj[method] = uid
+ else
+ hooksecurefunc(obj, method, uid)
+ end
+ end
+ else
+ registry[self][method] = uid
+
+ if not secure then
+ _G[method] = uid
+ self.hooks[method] = orig
+ else
+ hooksecurefunc(method, uid)
+ end
+ end
+
+ actives[uid], handlers[uid], scripts[uid] = true, handler, script and true or nil
+end
+
+--- Hook a function or a method on an object.
+-- The hook created will be a "safe hook", that means that your handler will be called
+-- before the hooked function ("Pre-Hook"), and you don't have to call the original function yourself,
+-- however you cannot stop the execution of the function, or modify any of the arguments/return values.\\
+-- This type of hook is typically used if you need to know if some function got called, and don't want to modify it.
+-- @paramsig [object], method, [handler], [hookSecure]
+-- @param object The object to hook a method from
+-- @param method If object was specified, the name of the method, or the name of the function to hook.
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked function)
+-- @param hookSecure If true, AceHook will allow hooking of secure functions.
+-- @usage
+-- -- create an addon with AceHook embeded
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
+--
+-- function MyAddon:OnEnable()
+-- -- Hook ActionButton_UpdateHotkeys, overwriting the secure status
+-- self:Hook("ActionButton_UpdateHotkeys", true)
+-- end
+--
+-- function MyAddon:ActionButton_UpdateHotkeys(button, type)
+-- print(button:GetName() .. " is updating its HotKey")
+-- end
+function AceHook:Hook(object, method, handler, hookSecure)
+ if type(object) == "string" then
+ method, handler, hookSecure, object = object, method, handler, nil
+ end
+
+ if handler == true then
+ handler, hookSecure = nil, true
+ end
+
+ hook(self, object, method, handler, false, false, false, hookSecure or false, "Usage: Hook([object], method, [handler], [hookSecure])")
+end
+
+--- RawHook a function or a method on an object.
+-- The hook created will be a "raw hook", that means that your handler will completly replace
+-- the original function, and your handler has to call the original function (or not, depending on your intentions).\\
+-- The original function will be stored in `self.hooks[object][method]` or `self.hooks[functionName]` respectively.\\
+-- This type of hook can be used for all purposes, and is usually the most common case when you need to modify arguments
+-- or want to control execution of the original function.
+-- @paramsig [object], method, [handler], [hookSecure]
+-- @param object The object to hook a method from
+-- @param method If object was specified, the name of the method, or the name of the function to hook.
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked function)
+-- @param hookSecure If true, AceHook will allow hooking of secure functions.
+-- @usage
+-- -- create an addon with AceHook embeded
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
+--
+-- function MyAddon:OnEnable()
+-- -- Hook ActionButton_UpdateHotkeys, overwriting the secure status
+-- self:RawHook("ActionButton_UpdateHotkeys", true)
+-- end
+--
+-- function MyAddon:ActionButton_UpdateHotkeys(button, type)
+-- if button:GetName() == "MyButton" then
+-- -- do stuff here
+-- else
+-- self.hooks.ActionButton_UpdateHotkeys(button, type)
+-- end
+-- end
+function AceHook:RawHook(object, method, handler, hookSecure)
+ if type(object) == "string" then
+ method, handler, hookSecure, object = object, method, handler, nil
+ end
+
+ if handler == true then
+ handler, hookSecure = nil, true
+ end
+
+ hook(self, object, method, handler, false, false, true, hookSecure or false, "Usage: RawHook([object], method, [handler], [hookSecure])")
+end
+
+--- SecureHook a function or a method on an object.
+-- This function is a wrapper around the `hooksecurefunc` function in the WoW API. Using AceHook
+-- extends the functionality of secure hooks, and adds the ability to unhook once the hook isn't
+-- required anymore, or the addon is being disabled.\\
+-- Secure Hooks should be used if the secure-status of the function is vital to its function,
+-- and taint would block execution. Secure Hooks are always called after the original function was called
+-- ("Post Hook"), and you cannot modify the arguments, return values or control the execution.
+-- @paramsig [object], method, [handler]
+-- @param object The object to hook a method from
+-- @param method If object was specified, the name of the method, or the name of the function to hook.
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked function)
+function AceHook:SecureHook(object, method, handler)
+ if type(object) == "string" then
+ method, handler, object = object, method, nil
+ end
+
+ hook(self, object, method, handler, false, true, false, false, "Usage: SecureHook([object], method, [handler])")
+end
+
+--- Hook a script handler on a frame.
+-- The hook created will be a "safe hook", that means that your handler will be called
+-- before the hooked script ("Pre-Hook"), and you don't have to call the original function yourself,
+-- however you cannot stop the execution of the function, or modify any of the arguments/return values.\\
+-- This is the frame script equivalent of the :Hook safe-hook. It would typically be used to be notified
+-- when a certain event happens to a frame.
+-- @paramsig frame, script, [handler]
+-- @param frame The Frame to hook the script on
+-- @param script The script to hook
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked script)
+-- @usage
+-- -- create an addon with AceHook embeded
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
+--
+-- function MyAddon:OnEnable()
+-- -- Hook the OnShow of FriendsFrame
+-- self:HookScript(FriendsFrame, "OnShow", "FriendsFrameOnShow")
+-- end
+--
+-- function MyAddon:FriendsFrameOnShow(frame)
+-- print("The FriendsFrame was shown!")
+-- end
+function AceHook:HookScript(frame, script, handler)
+ hook(self, frame, script, handler, true, false, false, false, "Usage: HookScript(object, method, [handler])")
+end
+
+--- RawHook a script handler on a frame.
+-- The hook created will be a "raw hook", that means that your handler will completly replace
+-- the original script, and your handler has to call the original script (or not, depending on your intentions).\\
+-- The original script will be stored in `self.hooks[frame][script]`.\\
+-- This type of hook can be used for all purposes, and is usually the most common case when you need to modify arguments
+-- or want to control execution of the original script.
+-- @paramsig frame, script, [handler]
+-- @param frame The Frame to hook the script on
+-- @param script The script to hook
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked script)
+-- @usage
+-- -- create an addon with AceHook embeded
+-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
+--
+-- function MyAddon:OnEnable()
+-- -- Hook the OnShow of FriendsFrame
+-- self:RawHookScript(FriendsFrame, "OnShow", "FriendsFrameOnShow")
+-- end
+--
+-- function MyAddon:FriendsFrameOnShow(frame)
+-- -- Call the original function
+-- self.hooks[frame].OnShow(frame)
+-- -- Do our processing
+-- -- .. stuff
+-- end
+function AceHook:RawHookScript(frame, script, handler)
+ hook(self, frame, script, handler, true, false, true, false, "Usage: RawHookScript(object, method, [handler])")
+end
+
+--- SecureHook a script handler on a frame.
+-- This function is a wrapper around the `frame:HookScript` function in the WoW API. Using AceHook
+-- extends the functionality of secure hooks, and adds the ability to unhook once the hook isn't
+-- required anymore, or the addon is being disabled.\\
+-- Secure Hooks should be used if the secure-status of the function is vital to its function,
+-- and taint would block execution. Secure Hooks are always called after the original function was called
+-- ("Post Hook"), and you cannot modify the arguments, return values or control the execution.
+-- @paramsig frame, script, [handler]
+-- @param frame The Frame to hook the script on
+-- @param script The script to hook
+-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked script)
+function AceHook:SecureHookScript(frame, script, handler)
+ hook(self, frame, script, handler, true, true, false, false, "Usage: SecureHookScript(object, method, [handler])")
+end
+
+--- Unhook from the specified function, method or script.
+-- @paramsig [obj], method
+-- @param obj The object or frame to unhook from
+-- @param method The name of the method, function or script to unhook from.
+function AceHook:Unhook(obj, method)
+ local usage = "Usage: Unhook([obj], method)"
+ if type(obj) == "string" then
+ method, obj = obj, nil
+ end
+
+ if obj and type(obj) ~= "table" then
+ error(format("%s: 'obj' - expecting nil or table got %s", usage, type(obj)), 2)
+ end
+ if type(method) ~= "string" then
+ error(format("%s: 'method' - expeting string got %s", usage, type(method)), 2)
+ end
+
+ local uid
+ if obj then
+ uid = registry[self][obj] and registry[self][obj][method]
+ else
+ uid = registry[self][method]
+ end
+
+ if not uid or not actives[uid] then
+ -- Declining to error on an unneeded unhook since the end effect is the same and this would just be annoying.
+ return false
+ end
+
+ actives[uid], handlers[uid] = nil, nil
+
+ if obj then
+ registry[self][obj][method] = nil
+ registry[self][obj] = next(registry[self][obj]) and registry[self][obj] or nil
+
+ -- if the hook reference doesnt exist, then its a secure hook, just bail out and dont do any unhooking
+ if not self.hooks[obj] or not self.hooks[obj][method] then return true end
+
+ if scripts[uid] and obj:GetScript(method) == uid then -- unhooks scripts
+ obj:SetScript(method, self.hooks[obj][method] ~= donothing and self.hooks[obj][method] or nil)
+ scripts[uid] = nil
+ elseif obj and self.hooks[obj] and self.hooks[obj][method] and obj[method] == uid then -- unhooks methods
+ obj[method] = self.hooks[obj][method]
+ end
+
+ self.hooks[obj][method] = nil
+ self.hooks[obj] = next(self.hooks[obj]) and self.hooks[obj] or nil
+ else
+ registry[self][method] = nil
+
+ -- if self.hooks[method] doesn't exist, then this is a SecureHook, just bail out
+ if not self.hooks[method] then return true end
+
+ if self.hooks[method] and _G[method] == uid then -- unhooks functions
+ _G[method] = self.hooks[method]
+ end
+
+ self.hooks[method] = nil
+ end
+ return true
+end
+
+--- Unhook all existing hooks for this addon.
+function AceHook:UnhookAll()
+ for key, value in pairs(registry[self]) do
+ if type(key) == "table" then
+ for method in pairs(value) do
+ AceHook.Unhook(self, key, method)
+ end
+ else
+ AceHook.Unhook(self, key)
+ end
+ end
+end
+
+--- Check if the specific function, method or script is already hooked.
+-- @paramsig [obj], method
+-- @param obj The object or frame to unhook from
+-- @param method The name of the method, function or script to unhook from.
+function AceHook:IsHooked(obj, method)
+ -- we don't check if registry[self] exists, this is done by evil magicks in the metatable
+ if type(obj) == "string" then
+ if registry[self][obj] and actives[registry[self][obj]] then
+ return true, handlers[registry[self][obj]]
+ end
+ else
+ if registry[self][obj] and registry[self][obj][method] and actives[registry[self][obj][method]] then
+ return true, handlers[registry[self][obj][method]]
+ end
+ end
+
+ return false, nil
+end
+
+--- Upgrade our old embeded
+for target, v in pairs( AceHook.embeded ) do
+ AceHook:Embed( target )
+end
diff --git a/MythicPlusDrop/Libs/AceHook-3.0/AceHook-3.0.xml b/MythicPlusDrop/Libs/AceHook-3.0/AceHook-3.0.xml
new file mode 100644
index 0000000..add0f26
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceHook-3.0/AceHook-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/MythicPlusDrop/Libs/AceLocale-3.0/AceLocale-3.0.lua b/MythicPlusDrop/Libs/AceLocale-3.0/AceLocale-3.0.lua
index e133781..bb0438d 100644
--- a/MythicPlusDrop/Libs/AceLocale-3.0/AceLocale-3.0.lua
+++ b/MythicPlusDrop/Libs/AceLocale-3.0/AceLocale-3.0.lua
@@ -1,7 +1,7 @@
--- **AceLocale-3.0** manages localization in addons, allowing for multiple locale to be registered with fallback to the base locale for untranslated strings.
-- @class file
-- @name AceLocale-3.0
--- @release $Id: AceLocale-3.0.lua 1035 2011-07-09 03:20:13Z kaelten $
+-- @release $Id$
local MAJOR,MINOR = "AceLocale-3.0", 6
local AceLocale, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
@@ -12,10 +12,6 @@ if not AceLocale then return end -- no upgrade needed
local assert, tostring, error = assert, tostring, error
local getmetatable, setmetatable, rawset, rawget = getmetatable, setmetatable, rawset, rawget
--- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
--- List them here for Mikk's FindGlobals script
--- GLOBALS: GAME_LOCALE, geterrorhandler
-
local gameLocale = GetLocale()
if gameLocale == "enGB" then
gameLocale = "enUS"
@@ -93,7 +89,7 @@ local writedefaultproxy = setmetatable({}, {
function AceLocale:NewLocale(application, locale, isDefault, silent)
-- GAME_LOCALE allows translators to test translations of addons without having that wow client installed
- local gameLocale = GAME_LOCALE or gameLocale
+ local activeGameLocale = GAME_LOCALE or gameLocale
local app = AceLocale.apps[application]
@@ -111,7 +107,7 @@ function AceLocale:NewLocale(application, locale, isDefault, silent)
AceLocale.appnames[app] = application
end
- if locale ~= gameLocale and not isDefault then
+ if locale ~= activeGameLocale and not isDefault then
return -- nop, we don't need these translations
end
diff --git a/MythicPlusDrop/Libs/AceSerializer-3.0/AceSerializer-3.0.lua b/MythicPlusDrop/Libs/AceSerializer-3.0/AceSerializer-3.0.lua
new file mode 100644
index 0000000..ae0f7f9
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceSerializer-3.0/AceSerializer-3.0.lua
@@ -0,0 +1,287 @@
+--- **AceSerializer-3.0** can serialize any variable (except functions or userdata) into a string format,
+-- that can be send over the addon comm channel. AceSerializer was designed to keep all data intact, especially
+-- very large numbers or floating point numbers, and table structures. The only caveat currently is, that multiple
+-- references to the same table will be send individually.
+--
+-- **AceSerializer-3.0** can be embeded into your addon, either explicitly by calling AceSerializer: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 AceSerializer itself.\\
+-- It is recommended to embed AceSerializer, otherwise you'll have to specify a custom `self` on all calls you
+-- make into AceSerializer.
+-- @class file
+-- @name AceSerializer-3.0
+-- @release $Id$
+local MAJOR,MINOR = "AceSerializer-3.0", 5
+local AceSerializer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
+
+if not AceSerializer then return end
+
+-- Lua APIs
+local strbyte, strchar, gsub, gmatch, format = string.byte, string.char, string.gsub, string.gmatch, string.format
+local assert, error, pcall = assert, error, pcall
+local type, tostring, tonumber = type, tostring, tonumber
+local pairs, select, frexp = pairs, select, math.frexp
+local tconcat = table.concat
+
+-- quick copies of string representations of wonky numbers
+local inf = math.huge
+
+local serNaN -- can't do this in 4.3, see ace3 ticket 268
+local serInf, serInfMac = "1.#INF", "inf"
+local serNegInf, serNegInfMac = "-1.#INF", "-inf"
+
+
+-- Serialization functions
+
+local function SerializeStringHelper(ch) -- Used by SerializeValue for strings
+ -- We use \126 ("~") as an escape character for all nonprints plus a few more
+ local n = strbyte(ch)
+ if n==30 then -- v3 / ticket 115: catch a nonprint that ends up being "~^" when encoded... DOH
+ return "\126\122"
+ elseif n<=32 then -- nonprint + space
+ return "\126"..strchar(n+64)
+ elseif n==94 then -- value separator
+ return "\126\125"
+ elseif n==126 then -- our own escape character
+ return "\126\124"
+ elseif n==127 then -- nonprint (DEL)
+ return "\126\123"
+ else
+ assert(false) -- can't be reached if caller uses a sane regex
+ end
+end
+
+local function SerializeValue(v, res, nres)
+ -- We use "^" as a value separator, followed by one byte for type indicator
+ local t=type(v)
+
+ if t=="string" then -- ^S = string (escaped to remove nonprints, "^"s, etc)
+ res[nres+1] = "^S"
+ res[nres+2] = gsub(v,"[%c \94\126\127]", SerializeStringHelper)
+ nres=nres+2
+
+ elseif t=="number" then -- ^N = number (just tostring()ed) or ^F (float components)
+ local str = tostring(v)
+ if tonumber(str)==v --[[not in 4.3 or str==serNaN]] then
+ -- translates just fine, transmit as-is
+ res[nres+1] = "^N"
+ res[nres+2] = str
+ nres=nres+2
+ elseif v == inf or v == -inf then
+ res[nres+1] = "^N"
+ res[nres+2] = v == inf and serInf or serNegInf
+ nres=nres+2
+ else
+ local m,e = frexp(v)
+ res[nres+1] = "^F"
+ res[nres+2] = format("%.0f",m*2^53) -- force mantissa to become integer (it's originally 0.5--0.9999)
+ res[nres+3] = "^f"
+ res[nres+4] = tostring(e-53) -- adjust exponent to counteract mantissa manipulation
+ nres=nres+4
+ end
+
+ elseif t=="table" then -- ^T...^t = table (list of key,value pairs)
+ nres=nres+1
+ res[nres] = "^T"
+ for key,value in pairs(v) do
+ nres = SerializeValue(key, res, nres)
+ nres = SerializeValue(value, res, nres)
+ end
+ nres=nres+1
+ res[nres] = "^t"
+
+ elseif t=="boolean" then -- ^B = true, ^b = false
+ nres=nres+1
+ if v then
+ res[nres] = "^B" -- true
+ else
+ res[nres] = "^b" -- false
+ end
+
+ elseif t=="nil" then -- ^Z = nil (zero, "N" was taken :P)
+ nres=nres+1
+ res[nres] = "^Z"
+
+ else
+ error(MAJOR..": Cannot serialize a value of type '"..t.."'") -- can't produce error on right level, this is wildly recursive
+ end
+
+ return nres
+end
+
+
+
+local serializeTbl = { "^1" } -- "^1" = Hi, I'm data serialized by AceSerializer protocol rev 1
+
+--- Serialize the data passed into the function.
+-- Takes a list of values (strings, numbers, booleans, nils, tables)
+-- and returns it in serialized form (a string).\\
+-- May throw errors on invalid data types.
+-- @param ... List of values to serialize
+-- @return The data in its serialized form (string)
+function AceSerializer:Serialize(...)
+ local nres = 1
+
+ for i=1,select("#", ...) do
+ local v = select(i, ...)
+ nres = SerializeValue(v, serializeTbl, nres)
+ end
+
+ serializeTbl[nres+1] = "^^" -- "^^" = End of serialized data
+
+ return tconcat(serializeTbl, "", 1, nres+1)
+end
+
+-- Deserialization functions
+local function DeserializeStringHelper(escape)
+ if escape<"~\122" then
+ return strchar(strbyte(escape,2,2)-64)
+ elseif escape=="~\122" then -- v3 / ticket 115: special case encode since 30+64=94 ("^") - OOPS.
+ return "\030"
+ elseif escape=="~\123" then
+ return "\127"
+ elseif escape=="~\124" then
+ return "\126"
+ elseif escape=="~\125" then
+ return "\94"
+ end
+ error("DeserializeStringHelper got called for '"..escape.."'?!?") -- can't be reached unless regex is screwed up
+end
+
+local function DeserializeNumberHelper(number)
+ --[[ not in 4.3 if number == serNaN then
+ return 0/0
+ else]]if number == serNegInf or number == serNegInfMac then
+ return -inf
+ elseif number == serInf or number == serInfMac then
+ return inf
+ else
+ return tonumber(number)
+ end
+end
+
+-- DeserializeValue: worker function for :Deserialize()
+-- It works in two modes:
+-- Main (top-level) mode: Deserialize a list of values and return them all
+-- Recursive (table) mode: Deserialize only a single value (_may_ of course be another table with lots of subvalues in it)
+--
+-- The function _always_ works recursively due to having to build a list of values to return
+--
+-- Callers are expected to pcall(DeserializeValue) to trap errors
+
+local function DeserializeValue(iter,single,ctl,data)
+
+ if not single then
+ ctl,data = iter()
+ end
+
+ if not ctl then
+ error("Supplied data misses AceSerializer terminator ('^^')")
+ end
+
+ if ctl=="^^" then
+ -- ignore extraneous data
+ return
+ end
+
+ local res
+
+ if ctl=="^S" then
+ res = gsub(data, "~.", DeserializeStringHelper)
+ elseif ctl=="^N" then
+ res = DeserializeNumberHelper(data)
+ if not res then
+ error("Invalid serialized number: '"..tostring(data).."'")
+ end
+ elseif ctl=="^F" then -- ^F^f
+ local ctl2,e = iter()
+ if ctl2~="^f" then
+ error("Invalid serialized floating-point number, expected '^f', not '"..tostring(ctl2).."'")
+ end
+ local m=tonumber(data)
+ e=tonumber(e)
+ if not (m and e) then
+ error("Invalid serialized floating-point number, expected mantissa and exponent, got '"..tostring(m).."' and '"..tostring(e).."'")
+ end
+ res = m*(2^e)
+ elseif ctl=="^B" then -- yeah yeah ignore data portion
+ res = true
+ elseif ctl=="^b" then -- yeah yeah ignore data portion
+ res = false
+ elseif ctl=="^Z" then -- yeah yeah ignore data portion
+ res = nil
+ elseif ctl=="^T" then
+ -- ignore ^T's data, future extensibility?
+ res = {}
+ local k,v
+ while true do
+ ctl,data = iter()
+ if ctl=="^t" then break end -- ignore ^t's data
+ k = DeserializeValue(iter,true,ctl,data)
+ if k==nil then
+ error("Invalid AceSerializer table format (no table end marker)")
+ end
+ ctl,data = iter()
+ v = DeserializeValue(iter,true,ctl,data)
+ if v==nil then
+ error("Invalid AceSerializer table format (no table end marker)")
+ end
+ res[k]=v
+ end
+ else
+ error("Invalid AceSerializer control code '"..ctl.."'")
+ end
+
+ if not single then
+ return res,DeserializeValue(iter)
+ else
+ return res
+ end
+end
+
+--- Deserializes the data into its original values.
+-- Accepts serialized data, ignoring all control characters and whitespace.
+-- @param str The serialized data (from :Serialize)
+-- @return true followed by a list of values, OR false followed by an error message
+function AceSerializer:Deserialize(str)
+ str = gsub(str, "[%c ]", "") -- ignore all control characters; nice for embedding in email and stuff
+
+ local iter = gmatch(str, "(^.)([^^]*)") -- Any ^x followed by string of non-^
+ local ctl,data = iter()
+ if not ctl or ctl~="^1" then
+ -- we purposefully ignore the data portion of the start code, it can be used as an extension mechanism
+ return false, "Supplied data is not AceSerializer data (rev 1)"
+ end
+
+ return pcall(DeserializeValue, iter)
+end
+
+
+----------------------------------------
+-- Base library stuff
+----------------------------------------
+
+AceSerializer.internals = { -- for test scripts
+ SerializeValue = SerializeValue,
+ SerializeStringHelper = SerializeStringHelper,
+}
+
+local mixins = {
+ "Serialize",
+ "Deserialize",
+}
+
+AceSerializer.embeds = AceSerializer.embeds or {}
+
+function AceSerializer:Embed(target)
+ for k, v in pairs(mixins) do
+ target[v] = self[v]
+ end
+ self.embeds[target] = true
+ return target
+end
+
+-- Update embeds
+for target, v in pairs(AceSerializer.embeds) do
+ AceSerializer:Embed(target)
+end
diff --git a/MythicPlusDrop/Libs/AceSerializer-3.0/AceSerializer-3.0.xml b/MythicPlusDrop/Libs/AceSerializer-3.0/AceSerializer-3.0.xml
new file mode 100644
index 0000000..94924af
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceSerializer-3.0/AceSerializer-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/MythicPlusDrop/Libs/AceTab-3.0/AceTab-3.0.lua b/MythicPlusDrop/Libs/AceTab-3.0/AceTab-3.0.lua
new file mode 100644
index 0000000..6fe6c24
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceTab-3.0/AceTab-3.0.lua
@@ -0,0 +1,441 @@
+--- AceTab-3.0 provides support for tab-completion.
+-- Note: This library is not yet finalized.
+-- @class file
+-- @name AceTab-3.0
+-- @release $Id$
+
+local ACETAB_MAJOR, ACETAB_MINOR = 'AceTab-3.0', 9
+local AceTab, oldminor = LibStub:NewLibrary(ACETAB_MAJOR, ACETAB_MINOR)
+
+if not AceTab then return end -- No upgrade needed
+
+AceTab.registry = AceTab.registry or {}
+
+-- local upvalues
+local _G = _G
+local pairs = pairs
+local ipairs = ipairs
+local type = type
+local registry = AceTab.registry
+
+local strfind = string.find
+local strsub = string.sub
+local strlower = string.lower
+local strformat = string.format
+local strmatch = string.match
+
+local function printf(...)
+ DEFAULT_CHAT_FRAME:AddMessage(strformat(...))
+end
+
+local function getTextBeforeCursor(this, start)
+ return strsub(this:GetText(), start or 1, this:GetCursorPosition())
+end
+
+-- Hook OnTabPressed and OnTextChanged for the frame, give it an empty matches table, and set its curMatch to 0, if we haven't done so already.
+local function hookFrame(f)
+ if f.hookedByAceTab3 then return end
+ f.hookedByAceTab3 = true
+ if f == ChatEdit_GetActiveWindow() then
+ local origCTP = ChatEdit_CustomTabPressed
+ function ChatEdit_CustomTabPressed(...)
+ if AceTab:OnTabPressed(f) then
+ return origCTP(...)
+ else
+ return true
+ end
+ end
+ else
+ local origOTP = f:GetScript('OnTabPressed')
+ if type(origOTP) ~= 'function' then
+ origOTP = function() end
+ end
+ f:SetScript('OnTabPressed', function(...)
+ if AceTab:OnTabPressed(f) then
+ return origOTP(...)
+ end
+ end)
+ end
+ f.at3curMatch = 0
+ f.at3matches = {}
+end
+
+local fallbacks, notfallbacks = {}, {} -- classifies completions into those which have preconditions and those which do not. Those without preconditions are only considered if no other completions have matches.
+local pmolengths = {} -- holds the number of characters to overwrite according to pmoverwrite and the current prematch
+-- ------------------------------------------------------------------------------
+-- RegisterTabCompletion( descriptor, prematches, wordlist, usagefunc, listenframes, postfunc, pmoverwrite )
+-- See http://www.wowace.com/wiki/AceTab-2.0 for detailed API documentation
+--
+-- descriptor string Unique identifier for this tab completion set
+--
+-- prematches string|table|nil String match(es) AFTER which this tab completion will apply.
+-- AceTab will ignore tabs NOT preceded by the string(s).
+-- If no value is passed, will check all tabs pressed in the specified editframe(s) UNLESS a more-specific tab complete applies.
+--
+-- wordlist function|table Function that will be passed a table into which it will insert strings corresponding to all possible completions, or an equivalent table.
+-- The text in the editbox, the position of the start of the word to be completed, and the uncompleted partial word
+-- are passed as second, third, and fourth arguments, to facilitate pre-filtering or conditional formatting, if desired.
+--
+-- usagefunc function|boolean|nil Usage statement function. Defaults to the wordlist, one per line. A boolean true squelches usage output.
+--
+-- listenframes string|table|nil EditFrames to monitor. Defaults to ChatFrameEditBox.
+--
+-- postfunc function|nil Post-processing function. If supplied, matches will be passed through this function after they've been identified as a match.
+--
+-- pmoverwrite boolean|number|nil Offset the beginning of the completion string in the editbox when making a completion. Passing a boolean true indicates that we want to overwrite
+-- the entire prematch string, and passing a number will overwrite that many characters prior to the cursor.
+-- This is useful when you want to use the prematch as an indicator character, but ultimately do not want it as part of the text, itself.
+--
+-- no return
+-- ------------------------------------------------------------------------------
+function AceTab:RegisterTabCompletion(descriptor, prematches, wordlist, usagefunc, listenframes, postfunc, pmoverwrite)
+ -- Arg checks
+ if type(descriptor) ~= 'string' then error("Usage: RegisterTabCompletion(descriptor, prematches, wordlist, usagefunc, listenframes, postfunc, pmoverwrite): 'descriptor' - string expected.", 3) end
+ if prematches and type(prematches) ~= 'string' and type(prematches) ~= 'table' then error("Usage: RegisterTabCompletion(descriptor, prematches, wordlist, usagefunc, listenframes, postfunc, pmoverwrite): 'prematches' - string, table, or nil expected.", 3) end
+ if type(wordlist) ~= 'function' and type(wordlist) ~= 'table' then error("Usage: RegisterTabCompletion(descriptor, prematches, wordlist, usagefunc, listenframes, postfunc, pmoverwrite): 'wordlist' - function or table expected.", 3) end
+ if usagefunc and type(usagefunc) ~= 'function' and type(usagefunc) ~= 'boolean' then error("Usage: RegisterTabCompletion(descriptor, prematches, wordlist, usagefunc, listenframes, postfunc, pmoverwrite): 'usagefunc' - function or boolean expected.", 3) end
+ if listenframes and type(listenframes) ~= 'string' and type(listenframes) ~= 'table' then error("Usage: RegisterTabCompletion(descriptor, prematches, wordlist, usagefunc, listenframes, postfunc, pmoverwrite): 'listenframes' - string or table expected.", 3) end
+ if postfunc and type(postfunc) ~= 'function' then error("Usage: RegisterTabCompletion(descriptor, prematches, wordlist, usagefunc, listenframes, postfunc, pmoverwrite): 'postfunc' - function expected.", 3) end
+ if pmoverwrite and type(pmoverwrite) ~= 'boolean' and type(pmoverwrite) ~= 'number' then error("Usage: RegisterTabCompletion(descriptor, prematches, wordlist, usagefunc, listenframes, postfunc, pmoverwrite): 'pmoverwrite' - boolean or number expected.", 3) end
+
+ local pmtable
+
+ if type(prematches) == 'table' then
+ pmtable = prematches
+ notfallbacks[descriptor] = true
+ else
+ pmtable = {}
+ -- Mark this group as a fallback group if no value was passed.
+ if not prematches then
+ pmtable[1] = ""
+ fallbacks[descriptor] = true
+ -- Make prematches into a one-element table if it was passed as a string.
+ elseif type(prematches) == 'string' then
+ pmtable[1] = prematches
+ if prematches == "" then
+ fallbacks[descriptor] = true
+ else
+ notfallbacks[descriptor] = true
+ end
+ end
+ end
+
+ -- Make listenframes into a one-element table if it was not passed a table of frames.
+ if not listenframes then -- default
+ listenframes = {}
+ for i = 1, NUM_CHAT_WINDOWS do
+ listenframes[i] = _G["ChatFrame"..i.."EditBox"]
+ end
+ elseif type(listenframes) ~= 'table' or type(listenframes[0]) == 'userdata' and type(listenframes.IsObjectType) == 'function' then -- single frame or framename
+ listenframes = { listenframes }
+ end
+
+ -- Hook each registered listenframe and give it a matches table.
+ for _, f in pairs(listenframes) do
+ if type(f) == 'string' then
+ f = _G[f]
+ end
+ if type(f) ~= 'table' or type(f[0]) ~= 'userdata' or type(f.IsObjectType) ~= 'function' then
+ error(strformat(ACETAB_MAJOR..": Cannot register frame %q; it does not exist", f:GetName()))
+ end
+ if f then
+ if f:GetObjectType() ~= 'EditBox' then
+ error(strformat(ACETAB_MAJOR..": Cannot register frame %q; it is not an EditBox", f:GetName()))
+ else
+ hookFrame(f)
+ end
+ end
+ end
+
+ -- Everything checks out; register this completion.
+ if not registry[descriptor] then
+ registry[descriptor] = { prematches = pmtable, wordlist = wordlist, usagefunc = usagefunc, listenframes = listenframes, postfunc = postfunc, pmoverwrite = pmoverwrite }
+ end
+end
+
+function AceTab:IsTabCompletionRegistered(descriptor)
+ return registry and registry[descriptor]
+end
+
+function AceTab:UnregisterTabCompletion(descriptor)
+ registry[descriptor] = nil
+ pmolengths[descriptor] = nil
+ fallbacks[descriptor] = nil
+ notfallbacks[descriptor] = nil
+end
+
+-- ------------------------------------------------------------------------------
+-- gcbs( s1, s2 )
+--
+-- s1 string First string to be compared
+--
+-- s2 string Second string to be compared
+--
+-- returns the greatest common substring beginning s1 and s2
+-- ------------------------------------------------------------------------------
+local function gcbs(s1, s2)
+ if not s1 and not s2 then return end
+ if not s1 then s1 = s2 end
+ if not s2 then s2 = s1 end
+ if #s2 < #s1 then
+ s1, s2 = s2, s1
+ end
+ if strfind(strlower(s2), "^"..strlower(s1)) then
+ return s1
+ else
+ return gcbs(strsub(s1, 1, -2), s2)
+ end
+end
+
+local cursor -- Holds cursor position. Set in :OnTabPressed().
+-- ------------------------------------------------------------------------------
+-- cycleTab()
+-- For when a tab press has multiple possible completions, we need to allow the user to press tab repeatedly to cycle through them.
+-- If we have multiple possible completions, all tab presses after the first will call this function to cycle through and insert the different possible matches.
+-- This function will stop being called after OnTextChanged() is triggered by something other than AceTab (i.e. the user inputs a character).
+-- ------------------------------------------------------------------------------
+local previousLength, cMatch, matched, postmatch
+local function cycleTab(this)
+ cMatch = 0 -- Counter across all sets. The pseudo-index relevant to this value and corresponding to the current match is held in this.at3curMatch
+ matched = false
+
+ -- Check each completion group registered to this frame.
+ for desc, compgrp in pairs(this.at3matches) do
+
+ -- Loop through the valid completions for this set.
+ for m, pm in pairs(compgrp) do
+ cMatch = cMatch + 1
+ if cMatch == this.at3curMatch then -- we're back to where we left off last time through the combined list
+ this.at3lastMatch = m
+ this.at3lastWord = pm
+ this.at3curMatch = cMatch + 1 -- save the new cMatch index
+ matched = true
+ break
+ end
+ end
+ if matched then break end
+ end
+
+ -- If our index is beyond the end of the list, reset the original uncompleted substring and let the cycle start over next time tab is pressed.
+ if not matched then
+ this.at3lastMatch = this.at3origMatch
+ this.at3lastWord = this.at3origWord
+ this.at3curMatch = 1
+ end
+
+ -- Insert the completion.
+ this:HighlightText(this.at3matchStart-1, cursor)
+ this:Insert(this.at3lastWord or '')
+ this.at3_last_precursor = getTextBeforeCursor(this) or ''
+end
+
+local IsSecureCmd = IsSecureCmd
+
+local candUsage = {}
+local numMatches = 0
+local firstMatch, hasNonFallback, allGCBS, setGCBS, usage
+local text_precursor, text_all, text_pmendToCursor
+
+-- Fill the this.at3matches[descriptor] tables with matching completion pairs for each entry, based on
+-- the partial string preceding the cursor position and using the corresponding registered wordlist.
+--
+-- The entries of the matches tables are of the format raw_match = formatted_match, where raw_match is the plaintext completion and
+-- formatted_match is the match after being formatted/altered/processed by the registered postfunc.
+-- If no postfunc exists, then the formatted and raw matches are the same.
+local pms, pme, pmt, prematchStart, prematchEnd, text_prematch, entry
+local function fillMatches(this, desc, fallback)
+ entry = registry[desc]
+ -- See what frames are registered for this completion group. If the frame in which we pressed tab is one of them, then we start building matches.
+ for _, f in ipairs(entry.listenframes) do
+ if f == this then
+
+ -- Try each precondition string registered for this completion group.
+ for _, prematch in ipairs(entry.prematches) do
+
+ -- Test if our prematch string is satisfied.
+ -- If it is, then we find its last occurence prior to the cursor, calculate and store its pmoverwrite value (if applicable), and start considering completions.
+ if fallback then prematch = "%s" end
+
+ -- Find the last occurence of the prematch before the cursor.
+ pms, pme, pmt = nil, 1, ''
+ text_prematch, prematchEnd, prematchStart = nil, nil, nil
+ while true do
+ pms, pme, pmt = strfind(text_precursor, "("..prematch..")", pme)
+ if pms then
+ prematchStart, prematchEnd, text_prematch = pms, pme, pmt
+ pme = pme + 1
+ else
+ break
+ end
+ end
+
+ if not prematchStart and fallback then
+ prematchStart, prematchEnd, text_prematch = 0, 0, ''
+ end
+ if prematchStart then
+ -- text_pmendToCursor should be the sub-word/phrase to be completed.
+ text_pmendToCursor = strsub(text_precursor, prematchEnd + 1)
+
+ -- How many characters should we eliminate before the completion before writing it in.
+ pmolengths[desc] = entry.pmoverwrite == true and #text_prematch or entry.pmoverwrite or 0
+
+ -- This is where we will insert completions, taking the prematch overwrite into account.
+ this.at3matchStart = prematchEnd + 1 - (pmolengths[desc] or 0)
+
+ -- We're either a non-fallback set or all completions thus far have been fallback sets, and the precondition matches.
+ -- Create cands from the registered wordlist, filling it with all potential (unfiltered) completion strings.
+ local wordlist = entry.wordlist
+ local cands = type(wordlist) == 'table' and wordlist or {}
+ if type(wordlist) == 'function' then
+ wordlist(cands, text_all, prematchEnd + 1, text_pmendToCursor)
+ end
+ if cands ~= false then
+ local matches = this.at3matches[desc] or {}
+ for i in pairs(matches) do matches[i] = nil end
+
+ -- Check each of the entries in cands to see if it completes the word before the cursor.
+ -- Finally, increment our match count and set firstMatch, if appropriate.
+ for _, m in ipairs(cands) do
+ if strfind(strlower(m), strlower(text_pmendToCursor), 1, 1) == 1 then -- we have a matching completion!
+ hasNonFallback = hasNonFallback or (not fallback)
+ matches[m] = entry.postfunc and entry.postfunc(m, prematchEnd + 1, text_all) or m
+ numMatches = numMatches + 1
+ if numMatches == 1 then
+ firstMatch = matches[m]
+ end
+ end
+ end
+ this.at3matches[desc] = numMatches > 0 and matches or nil
+ end
+ end
+ end
+ end
+ end
+end
+
+function AceTab:OnTabPressed(this)
+ if this:GetText() == '' then return true end
+
+ -- allow Blizzard to handle slash commands, themselves
+ if this == ChatEdit_GetActiveWindow() then
+ local command = this:GetText()
+ if strfind(command, "^/[%a%d_]+$") then
+ return true
+ end
+ local cmd = strmatch(command, "^/[%a%d_]+")
+ if cmd and IsSecureCmd(cmd) then
+ return true
+ end
+ end
+
+ cursor = this:GetCursorPosition()
+
+ text_all = this:GetText()
+ text_precursor = getTextBeforeCursor(this) or ''
+
+ -- If we've already found some matches and haven't done anything since the last tab press, then (continue) cycling matches.
+ -- Otherwise, reset this frame's matches and proceed to creating our list of possible completions.
+ this.at3lastMatch = this.at3curMatch > 0 and (this.at3lastMatch or this.at3origWord)
+ -- Detects if we've made any edits since the last tab press. If not, continue cycling completions.
+ if text_precursor == this.at3_last_precursor then
+ return cycleTab(this)
+ else
+ for i in pairs(this.at3matches) do this.at3matches[i] = nil end
+ this.at3curMatch = 0
+ this.at3origWord = nil
+ this.at3origMatch = nil
+ this.at3lastWord = nil
+ this.at3lastMatch = nil
+ this.at3_last_precursor = text_precursor
+ end
+
+ numMatches = 0
+ firstMatch = nil
+ hasNonFallback = false
+ for i in pairs(pmolengths) do pmolengths[i] = nil end
+
+ for desc in pairs(notfallbacks) do
+ fillMatches(this, desc)
+ end
+ if not hasNonFallback then
+ for desc in pairs(fallbacks) do
+ fillMatches(this, desc, true)
+ end
+ end
+
+ if not firstMatch then
+ this.at3_last_precursor = "\0"
+ return true
+ end
+
+ -- We want to replace the entire word with our completion, so highlight it up to the cursor.
+ -- If only one match exists, then stick it in there and append a space.
+ if numMatches == 1 then
+ -- HighlightText takes the value AFTER which the highlighting starts, so we have to subtract 1 to have it start before the first character.
+ this:HighlightText(this.at3matchStart-1, cursor)
+
+ this:Insert(firstMatch)
+ this:Insert(" ")
+ else
+ -- Otherwise, we want to begin cycling through the valid completions.
+ -- Beginning a cycle also causes the usage statement to be printed, if one exists.
+
+ -- Print usage statements for each possible completion (and gather up the GCBS of all matches while we're walking the tables).
+ allGCBS = nil
+ for desc, matches in pairs(this.at3matches) do
+ -- Don't print usage statements for fallback completion groups if we have 'real' completion groups with matches.
+ if hasNonFallback and fallbacks[desc] then break end
+
+ -- Use the group's description as a heading for its usage statements.
+ DEFAULT_CHAT_FRAME:AddMessage(desc..":")
+
+ local usagefunc = registry[desc].usagefunc
+ if not usagefunc then
+ -- No special usage processing; just print a list of the (formatted) matches.
+ for m, fm in pairs(matches) do
+ DEFAULT_CHAT_FRAME:AddMessage(fm)
+ allGCBS = gcbs(allGCBS, m)
+ end
+ else
+ -- Print a usage statement based on the corresponding registered usagefunc.
+ -- candUsage is the table passed to usagefunc to be filled with candidate = usage_statement pairs.
+ if type(usagefunc) == 'function' then
+ for i in pairs(candUsage) do candUsage[i] = nil end
+
+ -- usagefunc takes the greatest common substring of valid matches as one of its args, so let's find that now.
+ -- TODO: Make the GCBS function accept a vararg or table, after which we can just pass in the list of matches.
+ setGCBS = nil
+ for m in pairs(matches) do
+ setGCBS = gcbs(setGCBS, m)
+ end
+ allGCBS = gcbs(allGCBS, setGCBS)
+ usage = usagefunc(candUsage, matches, setGCBS, strsub(text_precursor, 1, prematchEnd))
+
+ -- If the usagefunc returns a string, then the entire usage statement has been taken care of by usagefunc, and we need only to print it...
+ if type(usage) == 'string' then
+ DEFAULT_CHAT_FRAME:AddMessage(usage)
+
+ -- ...otherwise, it should have filled candUsage with candidate-usage statement pairs, and we need to print the matching ones.
+ elseif next(candUsage) and numMatches > 0 then
+ for m, fm in pairs(matches) do
+ if candUsage[m] then DEFAULT_CHAT_FRAME:AddMessage(strformat("%s - %s", fm, candUsage[m])) end
+ end
+ end
+ end
+ end
+
+ if next(matches) then
+ -- Replace the original string with the greatest common substring of all valid completions.
+ this.at3curMatch = 1
+ this.at3origWord = strsub(text_precursor, this.at3matchStart, this.at3matchStart + pmolengths[desc] - 1) .. allGCBS or ""
+ this.at3origMatch = allGCBS or ""
+ this.at3lastWord = this.at3origWord
+ this.at3lastMatch = this.at3origMatch
+
+ this:HighlightText(this.at3matchStart-1, cursor)
+ this:Insert(this.at3origWord)
+ this.at3_last_precursor = getTextBeforeCursor(this) or ''
+ end
+ end
+ end
+end
diff --git a/MythicPlusDrop/Libs/AceTab-3.0/AceTab-3.0.xml b/MythicPlusDrop/Libs/AceTab-3.0/AceTab-3.0.xml
new file mode 100644
index 0000000..2e50904
--- /dev/null
+++ b/MythicPlusDrop/Libs/AceTab-3.0/AceTab-3.0.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/MythicPlusDrop/Libs/AceTimer-3.0/AceTimer-3.0.lua b/MythicPlusDrop/Libs/AceTimer-3.0/AceTimer-3.0.lua
index 8ba6b3c..52939af 100644
--- a/MythicPlusDrop/Libs/AceTimer-3.0/AceTimer-3.0.lua
+++ b/MythicPlusDrop/Libs/AceTimer-3.0/AceTimer-3.0.lua
@@ -15,7 +15,7 @@
-- make into AceTimer.
-- @class file
-- @name AceTimer-3.0
--- @release $Id: AceTimer-3.0.lua 1119 2014-10-14 17:23:29Z nevcairiel $
+-- @release $Id$
local MAJOR, MINOR = "AceTimer-3.0", 17 -- Bump minor on changes
local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
@@ -34,18 +34,20 @@ local function new(self, loop, func, delay, ...)
delay = 0.01 -- Restrict to the lowest time that the C_Timer API allows us
end
- local timer = {...}
- timer.object = self
- timer.func = func
- timer.looping = loop
- timer.argsCount = select("#", ...)
- timer.delay = delay
- timer.ends = GetTime() + delay
+ local timer = {
+ object = self,
+ func = func,
+ looping = loop,
+ argsCount = select("#", ...),
+ delay = delay,
+ ends = GetTime() + delay,
+ ...
+ }
activeTimers[timer] = timer
-- Create new timer closure to wrap the "timer" object
- timer.callback = function()
+ timer.callback = function()
if not timer.cancelled then
if type(timer.func) == "string" then
-- We manually set the unpack count to prevent issues with an arg set that contains nil and ends with nil
@@ -59,11 +61,11 @@ local function new(self, loop, func, delay, ...)
-- Compensate delay to get a perfect average delay, even if individual times don't match up perfectly
-- due to fps differences
local time = GetTime()
- local delay = timer.delay - (time - timer.ends)
+ local ndelay = timer.delay - (time - timer.ends)
-- Ensure the delay doesn't go below the threshold
- if delay < 0.01 then delay = 0.01 end
- C_TimerAfter(delay, timer.callback)
- timer.ends = time + delay
+ if ndelay < 0.01 then ndelay = 0.01 end
+ C_TimerAfter(ndelay, timer.callback)
+ timer.ends = time + ndelay
else
activeTimers[timer.handle or timer] = nil
end
@@ -156,7 +158,7 @@ end
--- Cancels all timers registered to the current addon object ('self')
function AceTimer:CancelAllTimers()
- for k,v in pairs(activeTimers) do
+ for k,v in next, activeTimers do
if v.object == self then
AceTimer.CancelTimer(self, k)
end
@@ -187,8 +189,8 @@ if oldminor and oldminor < 10 then
AceTimer.frame:SetScript("OnEvent", nil)
AceTimer.frame:UnregisterAllEvents()
-- convert timers
- for object,timers in pairs(AceTimer.selfs) do
- for handle,timer in pairs(timers) do
+ for object,timers in next, AceTimer.selfs do
+ for handle,timer in next, timers do
if type(timer) == "table" and timer.callback then
local newTimer
if timer.delay then
@@ -214,7 +216,7 @@ elseif oldminor and oldminor < 17 then
-- Clear old timer table and update upvalue
AceTimer.activeTimers = {}
activeTimers = AceTimer.activeTimers
- for handle, timer in pairs(oldTimers) do
+ for handle, timer in next, oldTimers do
local newTimer
-- Stop the old timer animation
local duration, elapsed = timer:GetDuration(), timer:GetElapsed()
@@ -232,7 +234,7 @@ elseif oldminor and oldminor < 17 then
-- Migrate transitional handles
if oldminor < 13 and AceTimer.hashCompatTable then
- for handle, id in pairs(AceTimer.hashCompatTable) do
+ for handle, id in next, AceTimer.hashCompatTable do
local t = activeTimers[id]
if t then
activeTimers[id] = nil
@@ -257,7 +259,7 @@ local mixins = {
function AceTimer:Embed(target)
AceTimer.embeds[target] = true
- for _,v in pairs(mixins) do
+ for _,v in next, mixins do
target[v] = AceTimer[v]
end
return target
@@ -271,6 +273,6 @@ function AceTimer:OnEmbedDisable(target)
target:CancelAllTimers()
end
-for addon in pairs(AceTimer.embeds) do
+for addon in next, AceTimer.embeds do
AceTimer:Embed(addon)
end
diff --git a/MythicPlusDrop/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua b/MythicPlusDrop/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua
index a791159..05fb9d2 100644
--- a/MythicPlusDrop/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua
+++ b/MythicPlusDrop/Libs/CallbackHandler-1.0/CallbackHandler-1.0.lua
@@ -1,5 +1,5 @@
---[[ $Id: CallbackHandler-1.0.lua 1284 2022-09-25 09:15:30Z nevcairiel $ ]]
-local MAJOR, MINOR = "CallbackHandler-1.0", 7
+--[[ $Id: CallbackHandler-1.0.lua 25 2022-12-12 15:02:36Z nevcairiel $ ]]
+local MAJOR, MINOR = "CallbackHandler-1.0", 8
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
if not CallbackHandler then return end -- No upgrade needed
@@ -7,21 +7,16 @@ if not CallbackHandler then return end -- No upgrade needed
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
-- Lua APIs
-local error = error
+local securecallfunction, error = securecallfunction, error
local setmetatable, rawget = setmetatable, rawget
local next, select, pairs, type, tostring = next, select, pairs, type, tostring
-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, ...)
+ securecallfunction(method, ...)
index, method = next(handlers, index)
until not method
end
diff --git a/MythicPlusDrop/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml b/MythicPlusDrop/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml
index c107f88..876df83 100644
--- a/MythicPlusDrop/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml
+++ b/MythicPlusDrop/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/MythicPlusDrop/MythicPlusDrop.toc b/MythicPlusDrop/MythicPlusDrop.toc
index 8f9eb15..514742b 100644
--- a/MythicPlusDrop/MythicPlusDrop.toc
+++ b/MythicPlusDrop/MythicPlusDrop.toc
@@ -1,6 +1,6 @@
-## Interface: 100007
+## Interface: 100100
## Title: |cffd6266cMythicPlusDrop|r
-## Version: 6.0
+## Version: 6.1
## Author: BloodDragon2580
## Notes: Info for Mythic Dungeons