Add files via upload
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
--[[
|
||||
Name : AtlasLootFu
|
||||
Version : 1.1
|
||||
Author : Daviesh (oma_daviesh@hotmail.com)
|
||||
Website : http://www.atlasloot.net
|
||||
Description : Adds AtlasLoot to FuBar.
|
||||
]]
|
||||
|
||||
--Invoke libraries
|
||||
local tablet = AceLibrary("Tablet-2.0");
|
||||
|
||||
--Define the plugin
|
||||
AtlasLootFu = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceDB-2.0", "FuBarPlugin-2.0");
|
||||
AtlasLootFu.title = "AtlasLootFu";
|
||||
AtlasLootFu.hasIcon = "Interface\\Icons\\INV_Box_01";
|
||||
AtlasLootFu.defaultPosition = "LEFT";
|
||||
AtlasLootFu.defaultMinimapPosition = 180;
|
||||
AtlasLootFu.cannotDetachTooltip = true;
|
||||
|
||||
-- Activate menu options to hide icon/text (no point in having the colour option)
|
||||
AtlasLootFu.hasNoColor = true;
|
||||
AtlasLootFu:RegisterDB("AtlasLootFuDB");
|
||||
|
||||
--Make sure the plugin is the rightt format when activated
|
||||
function AtlasLootFu:OnEnable()
|
||||
self:Update();
|
||||
end
|
||||
|
||||
--Define text to display when the cursor mouses over the plugin
|
||||
function AtlasLootFu:OnTooltipUpdate()
|
||||
local cat = tablet:AddCategory()
|
||||
cat:AddLine(
|
||||
"text", ATLASLOOTFU_LEFTCLICK
|
||||
)
|
||||
cat:AddLine(
|
||||
"text", ATLASLOOTFU_SHIFTCLICK
|
||||
)
|
||||
cat:AddLine(
|
||||
"text", ATLASLOOTFU_LEFTDRAG
|
||||
)
|
||||
end
|
||||
|
||||
--Define what to do when the plugin is clicked
|
||||
function AtlasLootFu:OnClick(button)
|
||||
--Left click -> open loot browser
|
||||
--Shift Left Click -> show options menu
|
||||
--Right click -> standard FuBar options
|
||||
if IsShiftKeyDown() then
|
||||
AtlasLootOptions_Toggle();
|
||||
else
|
||||
if AtlasLootDefaultFrame:IsVisible() then
|
||||
AtlasLootDefaultFrame:Hide();
|
||||
else
|
||||
AtlasLootDefaultFrame:Show();
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
## Interface: 30300
|
||||
## Title: AtlasLootFu
|
||||
## Notes: Minimap button for AtlasLoot
|
||||
## Title-zhTW: |r|cFF0099FF[地圖]|rAL 小地圖按鍵
|
||||
## Notes-zhTW: AtlasLoot 小地圖按鍵
|
||||
## Author: Hegarol
|
||||
## Version: v5.11.04
|
||||
## X-eMail: manager@atlasloot.net
|
||||
## X-Category: Map
|
||||
## X-License: GPL v2
|
||||
## X-Website: http://www.atlasloot.net
|
||||
## X-Embeds: Ace2, FuBarPlugin-2.0, TabletLib
|
||||
## SavedVariables: AtlasLootFuDB
|
||||
## Dependencies: AtlasLoot
|
||||
## OptionalDeps: Ace2, FuBarPlugin-2.0, TabletLib, FuBar
|
||||
## X-Curse-Packaged-Version: v5.11.04
|
||||
## X-Curse-Project-Name: Atlasloot Enhanced
|
||||
## X-Curse-Project-ID: atlasloot-enhanced
|
||||
## X-Curse-Repository-ID: wow/atlasloot-enhanced/mainline
|
||||
|
||||
embeds.xml
|
||||
|
||||
Locales.lua
|
||||
AtlasLootFu.lua
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
## Interface: 30300
|
||||
## X-Curse-Packaged-Version: r1101
|
||||
## X-Curse-Project-Name: Ace2
|
||||
## X-Curse-Project-ID: ace2
|
||||
## X-Curse-Repository-ID: wow/ace2/mainline
|
||||
|
||||
## Title: Lib: AceAddon-2.0
|
||||
## Notes: AddOn development framework
|
||||
## Author: Ace Development Team
|
||||
## LoadOnDemand: 1
|
||||
## X-Website: http://www.wowace.com
|
||||
## X-Category: Library
|
||||
## X-License: LGPL v2.1 + MIT for AceOO-2.0
|
||||
## Dependencies: AceLibrary, AceOO-2.0
|
||||
|
||||
AceAddon-2.0.lua
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
## Interface: 30300
|
||||
## X-Curse-Packaged-Version: r1101
|
||||
## X-Curse-Project-Name: Ace2
|
||||
## X-Curse-Project-ID: ace2
|
||||
## X-Curse-Repository-ID: wow/ace2/mainline
|
||||
|
||||
## Title: Lib: AceDB-2.0
|
||||
## Notes: AddOn development framework
|
||||
## Author: Ace Development Team
|
||||
## LoadOnDemand: 1
|
||||
## X-Website: http://www.wowace.com
|
||||
## X-Category: Library
|
||||
## X-License: LGPL v2.1 + MIT for AceOO-2.0
|
||||
## Dependencies: AceLibrary, AceEvent-2.0, AceOO-2.0
|
||||
|
||||
AceDB-2.0.lua
|
||||
|
||||
@@ -0,0 +1,998 @@
|
||||
--[[
|
||||
Name: AceEvent-2.0
|
||||
Revision: $Rev: 1097 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceEvent-2.0
|
||||
SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceEvent-2.0
|
||||
Description: Mixin to allow for event handling, scheduling, and inter-addon
|
||||
communication.
|
||||
Dependencies: AceLibrary, AceOO-2.0
|
||||
License: LGPL v2.1
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "AceEvent-2.0"
|
||||
local MINOR_VERSION = 90000 + tonumber(("$Revision: 1097 $"):match("(%d+)"))
|
||||
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
|
||||
|
||||
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
|
||||
local Mixin = AceOO.Mixin
|
||||
local AceEvent = Mixin {
|
||||
"RegisterEvent",
|
||||
"RegisterAllEvents",
|
||||
"UnregisterEvent",
|
||||
"UnregisterAllEvents",
|
||||
"TriggerEvent",
|
||||
"ScheduleEvent",
|
||||
"ScheduleRepeatingEvent",
|
||||
"CancelScheduledEvent",
|
||||
"CancelAllScheduledEvents",
|
||||
"IsEventRegistered",
|
||||
"IsEventScheduled",
|
||||
"RegisterBucketEvent",
|
||||
"UnregisterBucketEvent",
|
||||
"UnregisterAllBucketEvents",
|
||||
"IsBucketEventRegistered",
|
||||
"ScheduleLeaveCombatAction",
|
||||
"CancelAllCombatSchedules",
|
||||
}
|
||||
|
||||
local weakKey = {__mode="k"}
|
||||
|
||||
local FAKE_NIL
|
||||
local RATE
|
||||
|
||||
local eventsWhichHappenOnce = {
|
||||
PLAYER_LOGIN = true,
|
||||
AceEvent_FullyInitialized = true,
|
||||
VARIABLES_LOADED = true,
|
||||
PLAYER_LOGOUT = true,
|
||||
}
|
||||
local next = next
|
||||
local pairs = pairs
|
||||
local pcall = pcall
|
||||
local type = type
|
||||
local GetTime = GetTime
|
||||
local gcinfo = gcinfo
|
||||
local unpack = unpack
|
||||
local geterrorhandler = geterrorhandler
|
||||
|
||||
local new, del
|
||||
do
|
||||
local cache = setmetatable({}, {__mode='k'})
|
||||
function new(...)
|
||||
local t = next(cache)
|
||||
if t then
|
||||
cache[t] = nil
|
||||
for i = 1, select('#', ...) do
|
||||
t[i] = select(i, ...)
|
||||
end
|
||||
return t
|
||||
else
|
||||
return { ... }
|
||||
end
|
||||
end
|
||||
function del(t)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
cache[t] = true
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local registeringFromAceEvent
|
||||
--[[----------------------------------------------------------------------------------
|
||||
Notes:
|
||||
* Registers the addon with a Blizzard event or a custom AceEvent, which will cause the given method to be called when that is triggered.
|
||||
Arguments:
|
||||
string - name of the event to register
|
||||
[optional] string or function - name of the method or function to call. Default: same name as "event".
|
||||
[optional] boolean - whether to have method called only once. Default: false
|
||||
------------------------------------------------------------------------------------]]
|
||||
function AceEvent:RegisterEvent(event, method, once)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
if self == AceEvent and not registeringFromAceEvent then
|
||||
AceEvent:argCheck(method, 3, "function")
|
||||
self = method
|
||||
else
|
||||
AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
|
||||
if type(method) == "boolean" or type(method) == "number" then
|
||||
AceEvent:argCheck(once, 4, "nil")
|
||||
once, method = method, event
|
||||
end
|
||||
end
|
||||
AceEvent:argCheck(once, 4, "number", "boolean", "nil")
|
||||
if eventsWhichHappenOnce[event] then
|
||||
once = true
|
||||
end
|
||||
local throttleRate
|
||||
if type(once) == "number" then
|
||||
throttleRate, once = once
|
||||
end
|
||||
if not method then
|
||||
method = event
|
||||
end
|
||||
if type(method) == "string" and type(self[method]) ~= "function" then
|
||||
AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
|
||||
else
|
||||
assert(type(method) == "function" or type(method) == "string")
|
||||
end
|
||||
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if not AceEvent_registry[event] then
|
||||
AceEvent_registry[event] = new()
|
||||
AceEvent.frame:RegisterEvent(event)
|
||||
end
|
||||
|
||||
local remember = true
|
||||
if AceEvent_registry[event][self] then
|
||||
remember = false
|
||||
end
|
||||
AceEvent_registry[event][self] = method
|
||||
|
||||
local AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
if once then
|
||||
if not AceEvent_onceRegistry then
|
||||
AceEvent.onceRegistry = {}
|
||||
AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
end
|
||||
if not AceEvent_onceRegistry[event] then
|
||||
AceEvent_onceRegistry[event] = new()
|
||||
end
|
||||
AceEvent_onceRegistry[event][self] = true
|
||||
else
|
||||
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
|
||||
AceEvent_onceRegistry[event][self] = nil
|
||||
if not next(AceEvent_onceRegistry[event]) then
|
||||
AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
if throttleRate then
|
||||
if not AceEvent_throttleRegistry then
|
||||
AceEvent.throttleRegistry = {}
|
||||
AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
end
|
||||
if not AceEvent_throttleRegistry[event] then
|
||||
AceEvent_throttleRegistry[event] = new()
|
||||
end
|
||||
if AceEvent_throttleRegistry[event][self] then
|
||||
AceEvent_throttleRegistry[event][self] = nil
|
||||
end
|
||||
AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey)
|
||||
local t = AceEvent_throttleRegistry[event][self]
|
||||
t[RATE] = throttleRate
|
||||
else
|
||||
if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then
|
||||
if AceEvent_throttleRegistry[event][self] then
|
||||
AceEvent_throttleRegistry[event][self] = nil
|
||||
end
|
||||
if not next(AceEvent_throttleRegistry[event]) then
|
||||
AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if remember then
|
||||
AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
|
||||
end
|
||||
end
|
||||
|
||||
local ALL_EVENTS
|
||||
|
||||
--[[----------------------------------------------------------------------------------
|
||||
Notes:
|
||||
* Registers all events to the given method
|
||||
* To access the current event, check AceEvent.currentEvent
|
||||
* To access the current event's unique identifier, check AceEvent.currentEventUID
|
||||
* This is only for debugging purposes.
|
||||
Arguments:
|
||||
[optional] string or function - name of the method or function to call. Default: same name as "event".
|
||||
------------------------------------------------------------------------------------]]
|
||||
function AceEvent:RegisterAllEvents(method)
|
||||
if self == AceEvent then
|
||||
AceEvent:argCheck(method, 1, "function")
|
||||
self = method
|
||||
else
|
||||
AceEvent:argCheck(method, 1, "string", "function")
|
||||
if type(method) == "string" and type(self[method]) ~= "function" then
|
||||
AceEvent:error("Cannot register all events to method %q, it does not exist", method)
|
||||
end
|
||||
end
|
||||
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if not AceEvent_registry[ALL_EVENTS] then
|
||||
AceEvent_registry[ALL_EVENTS] = new()
|
||||
AceEvent.frame:RegisterAllEvents()
|
||||
end
|
||||
|
||||
local remember = not AceEvent_registry[ALL_EVENTS][self]
|
||||
AceEvent_registry[ALL_EVENTS][self] = method
|
||||
if remember then
|
||||
AceEvent:TriggerEvent("AceEvent_EventRegistered", self, "all")
|
||||
end
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------------------
|
||||
Notes:
|
||||
* Trigger a custom AceEvent.
|
||||
* This should never be called to simulate fake Blizzard events.
|
||||
* Custom events should be in the form of AddonName_SpecificEvent
|
||||
Arguments:
|
||||
string - name of the event
|
||||
tuple - list of arguments to pass along
|
||||
------------------------------------------------------------------------------------]]
|
||||
function AceEvent:TriggerEvent(event, ...)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then
|
||||
return
|
||||
end
|
||||
local lastEvent = AceEvent.currentEvent
|
||||
AceEvent.currentEvent = event
|
||||
local lastEventUID = AceEvent.currentEventUID
|
||||
local uid = AceEvent.UID_NUM + 1
|
||||
AceEvent.UID_NUM = uid
|
||||
AceEvent.currentEventUID = uid
|
||||
|
||||
local tmp = new()
|
||||
|
||||
local AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
|
||||
for obj, method in pairs(AceEvent_onceRegistry[event]) do
|
||||
tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil
|
||||
end
|
||||
local obj = next(tmp)
|
||||
while obj do
|
||||
local method = tmp[obj]
|
||||
AceEvent.UnregisterEvent(obj, event)
|
||||
if type(method) == "string" then
|
||||
local obj_method = obj[method]
|
||||
if obj_method then
|
||||
local success, err = pcall(obj_method, obj, ...)
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
|
||||
end
|
||||
elseif method then -- function
|
||||
local success, err = pcall(method, ...)
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
|
||||
end
|
||||
tmp[obj] = nil
|
||||
obj = next(tmp)
|
||||
end
|
||||
end
|
||||
|
||||
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
|
||||
if AceEvent_registry[event] then
|
||||
for obj, method in pairs(AceEvent_registry[event]) do
|
||||
tmp[obj] = method
|
||||
end
|
||||
local obj = next(tmp)
|
||||
while obj do
|
||||
local cont = nil
|
||||
if throttleTable and throttleTable[obj] then
|
||||
local a1 = ...
|
||||
if a1 == nil then
|
||||
a1 = FAKE_NIL
|
||||
end
|
||||
if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
|
||||
throttleTable[obj][a1] = GetTime()
|
||||
else
|
||||
cont = true
|
||||
end
|
||||
end
|
||||
if not cont then
|
||||
local method = tmp[obj]
|
||||
local t = type(method)
|
||||
if t == "string" then
|
||||
local obj_method = obj[method]
|
||||
if obj_method then
|
||||
local success, err = pcall(obj_method, obj, ...)
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
|
||||
end
|
||||
elseif t == "function" then -- function
|
||||
local success, err = pcall(method, ...)
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
|
||||
else
|
||||
AceEvent:error("Cannot trigger event %q. %q's handler, %q, is not a method or function (%s).", event, obj, method, t)
|
||||
end
|
||||
end
|
||||
tmp[obj] = nil
|
||||
obj = next(tmp)
|
||||
end
|
||||
end
|
||||
if AceEvent_registry[ALL_EVENTS] then
|
||||
for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do
|
||||
tmp[obj] = method
|
||||
end
|
||||
local obj = next(tmp)
|
||||
while obj do
|
||||
local method = tmp[obj]
|
||||
local t = type(method)
|
||||
if t == "string" then
|
||||
local obj_method = obj[method]
|
||||
if obj_method then
|
||||
local success, err = pcall(obj_method, obj, ...)
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
|
||||
end
|
||||
elseif t == "function" then
|
||||
local success, err = pcall(method, ...)
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
|
||||
else
|
||||
AceEvent:error("Cannot trigger event %q. %q's handler, %q, is not a method or function (%s).", event, obj, method, t)
|
||||
end
|
||||
tmp[obj] = nil
|
||||
obj = next(tmp)
|
||||
end
|
||||
end
|
||||
tmp = del(tmp)
|
||||
AceEvent.currentEvent = lastEvent
|
||||
AceEvent.currentEventUID = lastEventUID
|
||||
end
|
||||
|
||||
local delayRegistry
|
||||
local OnUpdate
|
||||
do
|
||||
local tmp = {}
|
||||
OnUpdate = function()
|
||||
local t = GetTime()
|
||||
for k,v in pairs(delayRegistry) do
|
||||
tmp[k] = true
|
||||
end
|
||||
for k in pairs(tmp) do
|
||||
local v = delayRegistry[k]
|
||||
if v then
|
||||
local v_time = v.time
|
||||
if not v_time then
|
||||
delayRegistry[k] = nil
|
||||
elseif v_time <= t then
|
||||
local v_repeatDelay = v.repeatDelay
|
||||
if v_repeatDelay then
|
||||
-- use the event time, not the current time, else timing inaccuracies add up over time
|
||||
v.time = v_time + v_repeatDelay
|
||||
end
|
||||
local event = v.event
|
||||
local t = type(event)
|
||||
if t == "function" then
|
||||
local uid = AceEvent.UID_NUM + 1
|
||||
AceEvent.UID_NUM = uid
|
||||
AceEvent.currentEventUID = uid
|
||||
local success, err = pcall(event, unpack(v, 1, v.n))
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
|
||||
AceEvent.currentEventUID = nil
|
||||
elseif t == "string" then
|
||||
AceEvent:TriggerEvent(event, unpack(v, 1, v.n))
|
||||
else
|
||||
AceEvent:error("Cannot trigger event %q, it's not a method or function (%s).", event, t)
|
||||
end
|
||||
if not v_repeatDelay then
|
||||
local x = delayRegistry[k]
|
||||
if x and x.time == v_time then -- check if it was manually reset
|
||||
if type(k) == "string" then
|
||||
del(delayRegistry[k])
|
||||
end
|
||||
delayRegistry[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for k in pairs(tmp) do
|
||||
tmp[k] = nil
|
||||
end
|
||||
if not next(delayRegistry) then
|
||||
AceEvent.frame:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ScheduleEvent(self, repeating, event, delay, ...)
|
||||
local id
|
||||
if type(event) == "string" and type(delay) ~= "number" then
|
||||
id, event, delay = event, delay, ...
|
||||
AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
|
||||
AceEvent:argCheck(delay, 4, "number")
|
||||
self:CancelScheduledEvent(id)
|
||||
else
|
||||
AceEvent:argCheck(event, 2, "string", "function")
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
end
|
||||
|
||||
if not delayRegistry then
|
||||
AceEvent.delayRegistry = {}
|
||||
delayRegistry = AceEvent.delayRegistry
|
||||
AceEvent.frame:SetScript("OnUpdate", OnUpdate)
|
||||
end
|
||||
local t
|
||||
if id then
|
||||
t = new(select(2, ...))
|
||||
t.n = select('#', ...) - 1
|
||||
else
|
||||
t = new(...)
|
||||
t.n = select('#', ...)
|
||||
end
|
||||
t.event = event
|
||||
t.time = GetTime() + delay
|
||||
t.self = self
|
||||
t.id = id or t
|
||||
t.repeatDelay = repeating and delay
|
||||
delayRegistry[t.id] = t
|
||||
AceEvent.frame:Show()
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------------------
|
||||
Notes:
|
||||
* Schedule an event to fire.
|
||||
* To fire on the next frame, specify a delay of 0.
|
||||
Arguments:
|
||||
string or function - name of the event to fire, or a function to call.
|
||||
number - the amount of time to wait until calling.
|
||||
tuple - a list of arguments to pass along.
|
||||
------------------------------------------------------------------------------------]]
|
||||
function AceEvent:ScheduleEvent(event, delay, ...)
|
||||
if type(event) == "string" and type(delay) ~= "number" then
|
||||
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
|
||||
AceEvent:argCheck(..., 4, "number")
|
||||
else
|
||||
AceEvent:argCheck(event, 2, "string", "function")
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
end
|
||||
|
||||
return ScheduleEvent(self, false, event, delay, ...)
|
||||
end
|
||||
|
||||
function AceEvent:ScheduleRepeatingEvent(event, delay, ...)
|
||||
if type(event) == "string" and type(delay) ~= "number" then
|
||||
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
|
||||
AceEvent:argCheck(..., 4, "number")
|
||||
else
|
||||
AceEvent:argCheck(event, 2, "string", "function")
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
end
|
||||
|
||||
return ScheduleEvent(self, true, event, delay, ...)
|
||||
end
|
||||
|
||||
function AceEvent:CancelScheduledEvent(t)
|
||||
AceEvent:argCheck(t, 2, "string")
|
||||
if delayRegistry then
|
||||
local v = delayRegistry[t]
|
||||
if v then
|
||||
if type(t) == "string" then
|
||||
del(delayRegistry[t])
|
||||
end
|
||||
delayRegistry[t] = nil
|
||||
if not next(delayRegistry) then
|
||||
AceEvent.frame:Hide()
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function AceEvent:IsEventScheduled(t)
|
||||
AceEvent:argCheck(t, 2, "string")
|
||||
if delayRegistry then
|
||||
local v = delayRegistry[t]
|
||||
if v then
|
||||
return true, v.time - GetTime()
|
||||
end
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterEvent(event)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if AceEvent_registry[event] and AceEvent_registry[event][self] then
|
||||
AceEvent_registry[event][self] = nil
|
||||
local AceEvent_onceRegistry = AceEvent.onceRegistry
|
||||
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then
|
||||
AceEvent_onceRegistry[event][self] = nil
|
||||
if not next(AceEvent_onceRegistry[event]) then
|
||||
AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
|
||||
end
|
||||
end
|
||||
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
|
||||
if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then
|
||||
AceEvent_throttleRegistry[event][self] = nil
|
||||
if not next(AceEvent_throttleRegistry[event]) then
|
||||
AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
|
||||
end
|
||||
end
|
||||
if not next(AceEvent_registry[event]) then
|
||||
AceEvent_registry[event] = del(AceEvent_registry[event])
|
||||
if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
|
||||
AceEvent.frame:UnregisterEvent(event)
|
||||
end
|
||||
end
|
||||
else
|
||||
if self == AceEvent then
|
||||
error(("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0."):format(event), 2)
|
||||
else
|
||||
AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
|
||||
end
|
||||
end
|
||||
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterAllEvents()
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
|
||||
AceEvent_registry[ALL_EVENTS][self] = nil
|
||||
if not next(AceEvent_registry[ALL_EVENTS]) then
|
||||
AceEvent_registry[ALL_EVENTS] = del(AceEvent_registry[ALL_EVENTS])
|
||||
AceEvent.frame:UnregisterAllEvents()
|
||||
for k,v in pairs(AceEvent_registry) do
|
||||
AceEvent.frame:RegisterEvent(k)
|
||||
end
|
||||
end
|
||||
end
|
||||
if AceEvent_registry.AceEvent_EventUnregistered then
|
||||
local event, data = "AceEvent_EventUnregistered", AceEvent_registry.AceEvent_EventUnregistered
|
||||
local x = data[self]
|
||||
data[self] = nil
|
||||
if x then
|
||||
if not next(data) then
|
||||
if not AceEvent_registry[ALL_EVENTS] then
|
||||
AceEvent.frame:UnregisterEvent(event)
|
||||
end
|
||||
AceEvent_registry[event] = del(AceEvent_registry[event])
|
||||
end
|
||||
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
|
||||
end
|
||||
end
|
||||
for event, data in pairs(AceEvent_registry) do
|
||||
local x = data[self]
|
||||
data[self] = nil
|
||||
if x and event ~= ALL_EVENTS then
|
||||
if not next(data) then
|
||||
if not AceEvent_registry[ALL_EVENTS] then
|
||||
AceEvent.frame:UnregisterEvent(event)
|
||||
end
|
||||
AceEvent_registry[event] = del(AceEvent_registry[event])
|
||||
end
|
||||
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
|
||||
end
|
||||
end
|
||||
if AceEvent.onceRegistry then
|
||||
for event, data in pairs(AceEvent.onceRegistry) do
|
||||
data[self] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:CancelAllScheduledEvents()
|
||||
if delayRegistry then
|
||||
for k,v in pairs(delayRegistry) do
|
||||
if v.self == self then
|
||||
if type(k) == "string" then
|
||||
del(delayRegistry[k])
|
||||
end
|
||||
delayRegistry[k] = nil
|
||||
end
|
||||
end
|
||||
if not next(delayRegistry) then
|
||||
AceEvent.frame:Hide()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:IsEventRegistered(event)
|
||||
AceEvent:argCheck(event, 2, "string")
|
||||
local AceEvent_registry = AceEvent.registry
|
||||
if self == AceEvent then
|
||||
return AceEvent_registry[event] and next(AceEvent_registry[event]) or AceEvent_registry[ALL_EVENTS] and next(AceEvent_registry[ALL_EVENTS]) and true or false
|
||||
end
|
||||
if AceEvent_registry[event] and AceEvent_registry[event][self] then
|
||||
return true, AceEvent_registry[event][self]
|
||||
end
|
||||
if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
|
||||
return true, AceEvent_registry[ALL_EVENTS][self]
|
||||
end
|
||||
return false, nil
|
||||
end
|
||||
|
||||
local UnitExists = UnitExists
|
||||
local bucketfunc
|
||||
function AceEvent:RegisterBucketEvent(event, delay, method, ...)
|
||||
AceEvent:argCheck(event, 2, "string", "table")
|
||||
if type(event) == "table" then
|
||||
for k,v in pairs(event) do
|
||||
if type(k) ~= "number" then
|
||||
AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
|
||||
elseif type(v) ~= "string" then
|
||||
AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
|
||||
end
|
||||
end
|
||||
end
|
||||
AceEvent:argCheck(delay, 3, "number")
|
||||
if AceEvent == self then
|
||||
AceEvent:argCheck(method, 4, "function")
|
||||
self = method
|
||||
else
|
||||
if type(event) == "string" then
|
||||
AceEvent:argCheck(method, 4, "string", "function", "nil")
|
||||
if not method then
|
||||
method = event
|
||||
end
|
||||
else
|
||||
AceEvent:argCheck(method, 4, "string", "function")
|
||||
end
|
||||
|
||||
if type(method) == "string" and type(self[method]) ~= "function" then
|
||||
AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
|
||||
end
|
||||
end
|
||||
local buckets = AceEvent.buckets
|
||||
if not buckets[event] then
|
||||
buckets[event] = new()
|
||||
end
|
||||
if not buckets[event][self] then
|
||||
local t = {}
|
||||
t.current = {}
|
||||
t.self = self
|
||||
buckets[event][self] = t
|
||||
else
|
||||
AceEvent.CancelScheduledEvent(self, buckets[event][self].id)
|
||||
end
|
||||
local bucket = buckets[event][self]
|
||||
bucket.method = method
|
||||
|
||||
local n = select('#', ...)
|
||||
if n > 0 then
|
||||
for i = 1, n do
|
||||
bucket[i] = select(i, ...)
|
||||
end
|
||||
end
|
||||
bucket.n = n
|
||||
|
||||
local func = function(arg1)
|
||||
bucket.run = true
|
||||
if arg1 then
|
||||
bucket.current[arg1] = true
|
||||
end
|
||||
end
|
||||
buckets[event][self].func = func
|
||||
local isUnitBucket = true
|
||||
if type(event) == "string" then
|
||||
AceEvent.RegisterEvent(self, event, func)
|
||||
if not event:find("^UNIT_") then
|
||||
isUnitBucket = nil
|
||||
end
|
||||
else
|
||||
for _,v in ipairs(event) do
|
||||
AceEvent.RegisterEvent(self, v, func)
|
||||
if isUnitBucket and not v:find("^UNIT_") then
|
||||
isUnitBucket = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
bucket.unit = isUnitBucket
|
||||
if not bucketfunc then
|
||||
bucketfunc = function(bucket)
|
||||
if bucket.run then
|
||||
local current = bucket.current
|
||||
local method = bucket.method
|
||||
local self = bucket.self
|
||||
if bucket.unit then
|
||||
for unit in pairs(current) do
|
||||
if not UnitExists(unit) then
|
||||
current[unit] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
if type(method) == "string" then
|
||||
self[method](self, current, unpack(bucket, 1, bucket.n))
|
||||
elseif method then -- function
|
||||
method(current, unpack(bucket, 1, bucket.n))
|
||||
end
|
||||
for k in pairs(current) do
|
||||
current[k] = nil
|
||||
k = nil
|
||||
end
|
||||
bucket.run = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
bucket.id = "AceEvent-Bucket-" .. tostring(bucket)
|
||||
AceEvent.ScheduleRepeatingEvent(self, bucket.id, bucketfunc, delay, bucket)
|
||||
end
|
||||
|
||||
function AceEvent:IsBucketEventRegistered(event)
|
||||
AceEvent:argCheck(event, 2, "string", "table")
|
||||
return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self]
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterBucketEvent(event)
|
||||
AceEvent:argCheck(event, 2, "string", "table")
|
||||
if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then
|
||||
AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
|
||||
end
|
||||
|
||||
local bucket = AceEvent.buckets[event][self]
|
||||
|
||||
if type(event) == "string" then
|
||||
AceEvent.UnregisterEvent(self, event)
|
||||
else
|
||||
for _,v in ipairs(event) do
|
||||
AceEvent.UnregisterEvent(self, v)
|
||||
end
|
||||
end
|
||||
AceEvent:CancelScheduledEvent(bucket.id)
|
||||
|
||||
bucket.current = nil
|
||||
AceEvent.buckets[event][self] = nil
|
||||
if not next(AceEvent.buckets[event]) then
|
||||
AceEvent.buckets[event] = del(AceEvent.buckets[event])
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:UnregisterAllBucketEvents()
|
||||
if not AceEvent.buckets or not next(AceEvent.buckets) then
|
||||
return
|
||||
end
|
||||
for k,v in pairs(AceEvent.buckets) do
|
||||
if v == self then
|
||||
AceEvent.UnregisterBucketEvent(self, k)
|
||||
k = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local combatSchedules
|
||||
function AceEvent:CancelAllCombatSchedules()
|
||||
local i = 0
|
||||
while true do
|
||||
i = i + 1
|
||||
if not combatSchedules[i] then
|
||||
break
|
||||
end
|
||||
local v = combatSchedules[i]
|
||||
if v.self == self then
|
||||
v = del(v)
|
||||
table.remove(combatSchedules, i)
|
||||
i = i - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local inCombat = false
|
||||
|
||||
function AceEvent:PLAYER_REGEN_DISABLED()
|
||||
inCombat = true
|
||||
end
|
||||
|
||||
do
|
||||
local tmp = {}
|
||||
function AceEvent:PLAYER_REGEN_ENABLED()
|
||||
inCombat = false
|
||||
for i, v in ipairs(combatSchedules) do
|
||||
tmp[i] = v
|
||||
combatSchedules[i] = nil
|
||||
end
|
||||
for i, v in ipairs(tmp) do
|
||||
local func = v.func
|
||||
if func then
|
||||
local success, err = pcall(func, unpack(v, 1, v.n))
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
|
||||
else
|
||||
local obj = v.obj or v.self
|
||||
local method = v.method
|
||||
local obj_method = obj[method]
|
||||
if obj_method then
|
||||
local success, err = pcall(obj_method, obj, unpack(v, 1, v.n))
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
|
||||
end
|
||||
end
|
||||
tmp[i] = del(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceEvent:ScheduleLeaveCombatAction(method, ...)
|
||||
local style = type(method)
|
||||
if self == AceEvent then
|
||||
if style == "table" then
|
||||
local func = (...)
|
||||
AceEvent:argCheck(func, 3, "string")
|
||||
if type(method[func]) ~= "function" then
|
||||
AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
|
||||
end
|
||||
else
|
||||
AceEvent:argCheck(method, 2, "function", --[[so message is right]] "table")
|
||||
end
|
||||
self = method
|
||||
else
|
||||
AceEvent:argCheck(method, 2, "function", "string", "table")
|
||||
if style == "string" and type(self[method]) ~= "function" then
|
||||
AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", method)
|
||||
elseif style == "table" then
|
||||
local func = (...)
|
||||
AceEvent:argCheck(func, 3, "string")
|
||||
if type(method[func]) ~= "function" then
|
||||
AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not inCombat then
|
||||
local success, err
|
||||
if type(method) == "function" then
|
||||
success, err = pcall(method, ...)
|
||||
elseif type(method) == "table" then
|
||||
local func = (...)
|
||||
success, err = pcall(method[func], method, select(2, ...))
|
||||
else
|
||||
success, err = pcall(self[method], self, ...)
|
||||
end
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
|
||||
return
|
||||
end
|
||||
local t
|
||||
local n = select('#', ...)
|
||||
if style == "table" then
|
||||
t = new(select(2, ...))
|
||||
t.obj = method
|
||||
t.method = (...)
|
||||
t.n = n-1
|
||||
else
|
||||
t = new(...)
|
||||
t.n = n
|
||||
if style == "function" then
|
||||
t.func = method
|
||||
else
|
||||
t.method = method
|
||||
end
|
||||
end
|
||||
t.self = self
|
||||
table.insert(combatSchedules, t)
|
||||
end
|
||||
|
||||
function AceEvent:OnEmbedDisable(target)
|
||||
self.UnregisterAllEvents(target)
|
||||
|
||||
self.CancelAllScheduledEvents(target)
|
||||
|
||||
self.UnregisterAllBucketEvents(target)
|
||||
|
||||
self.CancelAllCombatSchedules(target)
|
||||
end
|
||||
|
||||
function AceEvent:IsFullyInitialized()
|
||||
return self.postInit or false
|
||||
end
|
||||
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
AceEvent = self
|
||||
|
||||
self.onceRegistry = oldLib and oldLib.onceRegistry or {}
|
||||
self.throttleRegistry = oldLib and oldLib.throttleRegistry or {}
|
||||
self.delayRegistry = oldLib and oldLib.delayRegistry or {}
|
||||
self.buckets = oldLib and oldLib.buckets or {}
|
||||
self.registry = oldLib and oldLib.registry or {}
|
||||
self.frame = oldLib and oldLib.frame or CreateFrame("Frame", "AceEvent20Frame")
|
||||
self.playerLogin = IsLoggedIn() and true
|
||||
self.postInit = oldLib and oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
|
||||
self.ALL_EVENTS = oldLib and oldLib.ALL_EVENTS or _G.newproxy()
|
||||
self.FAKE_NIL = oldLib and oldLib.FAKE_NIL or _G.newproxy()
|
||||
self.RATE = oldLib and oldLib.RATE or _G.newproxy()
|
||||
self.combatSchedules = oldLib and oldLib.combatSchedules or {}
|
||||
self.UID_NUM = oldLib and oldLib.UID_NUM or 0
|
||||
|
||||
combatSchedules = self.combatSchedules
|
||||
ALL_EVENTS = self.ALL_EVENTS
|
||||
FAKE_NIL = self.FAKE_NIL
|
||||
RATE = self.RATE
|
||||
local inPlw = false
|
||||
local blacklist = {
|
||||
UNIT_INVENTORY_CHANGED = true,
|
||||
BAG_UPDATE = true,
|
||||
ITEM_LOCK_CHANGED = true,
|
||||
ACTIONBAR_SLOT_CHANGED = true,
|
||||
}
|
||||
self.frame:SetScript("OnEvent", function(_, event, ...)
|
||||
if event == "PLAYER_ENTERING_WORLD" then
|
||||
inPlw = false
|
||||
elseif event == "PLAYER_LEAVING_WORLD" then
|
||||
inPlw = true
|
||||
end
|
||||
if event and (not inPlw or not blacklist[event]) then
|
||||
self:TriggerEvent(event, ...)
|
||||
end
|
||||
end)
|
||||
if self.delayRegistry then
|
||||
delayRegistry = self.delayRegistry
|
||||
self.frame:SetScript("OnUpdate", OnUpdate)
|
||||
end
|
||||
|
||||
self:UnregisterAllEvents()
|
||||
self:CancelAllScheduledEvents()
|
||||
|
||||
local function handleFullInit()
|
||||
if not self.postInit then
|
||||
local function func()
|
||||
self.postInit = true
|
||||
self:TriggerEvent("AceEvent_FullyInitialized")
|
||||
if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
|
||||
self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
|
||||
end
|
||||
if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
|
||||
self:UnregisterEvent("MEETINGSTONE_CHANGED")
|
||||
end
|
||||
end
|
||||
registeringFromAceEvent = true
|
||||
self:RegisterEvent("MEETINGSTONE_CHANGED", func, true)
|
||||
self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", func, true)
|
||||
|
||||
self:ScheduleEvent("AceEvent_FullyInitialized", func, 10)
|
||||
registeringFromAceEvent = nil
|
||||
end
|
||||
end
|
||||
|
||||
if not self.playerLogin then
|
||||
registeringFromAceEvent = true
|
||||
self:RegisterEvent("PLAYER_LOGIN", function()
|
||||
self.playerLogin = true
|
||||
handleFullInit()
|
||||
handleFullInit = nil
|
||||
end, true)
|
||||
registeringFromAceEvent = nil
|
||||
else
|
||||
handleFullInit()
|
||||
handleFullInit = nil
|
||||
end
|
||||
|
||||
if not AceEvent20EditBox then
|
||||
CreateFrame("Editbox", "AceEvent20EditBox")
|
||||
end
|
||||
local editbox = AceEvent20EditBox
|
||||
function editbox:Execute(line)
|
||||
local defaulteditbox = DEFAULT_CHAT_FRAME.editBox
|
||||
self:SetAttribute("chatType", defaulteditbox:GetAttribute("chatType"))
|
||||
self:SetAttribute("tellTarget", defaulteditbox:GetAttribute("tellTarget"))
|
||||
self:SetAttribute("channelTarget", defaulteditbox:GetAttribute("channelTarget"))
|
||||
self:SetText(line)
|
||||
ChatEdit_SendText(self)
|
||||
end
|
||||
editbox:Hide()
|
||||
_G["SLASH_IN1"] = "/in"
|
||||
SlashCmdList["IN"] = function(msg)
|
||||
local seconds, command, rest = msg:match("^([^%s]+)%s+(/[^%s]+)(.*)$")
|
||||
seconds = tonumber(seconds)
|
||||
if not seconds then
|
||||
DEFAULT_CHAT_FRAME:AddMessage("Error, bad arguments to /in. Must be in the form of `/in 5 /say hi'")
|
||||
return
|
||||
end
|
||||
if IsSecureCmd(command) then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(("Error, /in cannot call secure command: %s"):format(command))
|
||||
return
|
||||
end
|
||||
self:ScheduleEvent("AceEventSlashIn-" .. math.random(1, 1000000000), editbox.Execute, seconds, editbox, command .. rest)
|
||||
end
|
||||
|
||||
registeringFromAceEvent = true
|
||||
self:RegisterEvent("PLAYER_REGEN_ENABLED")
|
||||
self:RegisterEvent("PLAYER_REGEN_DISABLED")
|
||||
self:RegisterEvent("LOOT_OPENED", function()
|
||||
if GetRealNumRaidMembers() > 0 or GetRealNumPartyMembers() > 0 then SendAddonMessage("LOOT_OPENED", "", "RAID") end
|
||||
end)
|
||||
inCombat = InCombatLockdown()
|
||||
registeringFromAceEvent = nil
|
||||
|
||||
self:activate(oldLib, oldDeactivate)
|
||||
if oldLib then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, activate)
|
||||
@@ -0,0 +1,17 @@
|
||||
## Interface: 30300
|
||||
## X-Curse-Packaged-Version: r1101
|
||||
## X-Curse-Project-Name: Ace2
|
||||
## X-Curse-Project-ID: ace2
|
||||
## X-Curse-Repository-ID: wow/ace2/mainline
|
||||
|
||||
## Title: Lib: AceEvent-2.0
|
||||
## Notes: AddOn development framework
|
||||
## Author: Ace Development Team
|
||||
## LoadOnDemand: 1
|
||||
## X-Website: http://www.wowace.com
|
||||
## X-Category: Library
|
||||
## X-License: LGPL v2.1 + MIT for AceOO-2.0
|
||||
## Dependencies: AceLibrary, AceOO-2.0
|
||||
|
||||
AceEvent-2.0.lua
|
||||
|
||||
@@ -0,0 +1,799 @@
|
||||
--[[
|
||||
Name: AceLibrary
|
||||
Revision: $Rev: 1091 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Iriel (iriel@vigilance-committee.org)
|
||||
Tekkub (tekkub@gmail.com)
|
||||
Revision: $Rev: 1091 $
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceLibrary
|
||||
SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceLibrary
|
||||
Description: Versioning library to handle other library instances, upgrading,
|
||||
and proper access.
|
||||
It also provides a base for libraries to work off of, providing
|
||||
proper error tools. It is handy because all the errors occur in the
|
||||
file that called it, not in the library file itself.
|
||||
Dependencies: None
|
||||
License: LGPL v2.1
|
||||
]]
|
||||
|
||||
local ACELIBRARY_MAJOR = "AceLibrary"
|
||||
local ACELIBRARY_MINOR = 90000 + tonumber(("$Revision: 1091 $"):match("(%d+)"))
|
||||
|
||||
local _G = getfenv(0)
|
||||
local previous = _G[ACELIBRARY_MAJOR]
|
||||
if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
|
||||
|
||||
do
|
||||
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
|
||||
-- LibStub is hereby placed in the Public Domain -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
|
||||
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
|
||||
local LibStub = _G[LIBSTUB_MAJOR]
|
||||
|
||||
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
|
||||
LibStub = LibStub or {libs = {}, minors = {} }
|
||||
_G[LIBSTUB_MAJOR] = LibStub
|
||||
LibStub.minor = LIBSTUB_MINOR
|
||||
|
||||
function LibStub:NewLibrary(major, minor)
|
||||
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
|
||||
minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
|
||||
local oldminor = self.minors[major]
|
||||
if oldminor and oldminor >= minor then return nil end
|
||||
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
|
||||
return self.libs[major], oldminor
|
||||
end
|
||||
|
||||
function LibStub:GetLibrary(major, silent)
|
||||
if not self.libs[major] and not silent then
|
||||
error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
|
||||
end
|
||||
return self.libs[major], self.minors[major]
|
||||
end
|
||||
|
||||
function LibStub:IterateLibraries() return pairs(self.libs) end
|
||||
setmetatable(LibStub, { __call = LibStub.GetLibrary })
|
||||
end
|
||||
end
|
||||
local LibStub = _G.LibStub
|
||||
|
||||
-- If you don't want AceLibrary to enable libraries that are LoadOnDemand but
|
||||
-- disabled in the addon screen, set this to true.
|
||||
local DONT_ENABLE_LIBRARIES = nil
|
||||
|
||||
local function safecall(func,...)
|
||||
local success, err = pcall(func,...)
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end
|
||||
end
|
||||
|
||||
-- @table AceLibrary
|
||||
-- @brief System to handle all versioning of libraries.
|
||||
local AceLibrary = {}
|
||||
local AceLibrary_mt = {}
|
||||
setmetatable(AceLibrary, AceLibrary_mt)
|
||||
|
||||
local function error(self, message, ...)
|
||||
if type(self) ~= "table" then
|
||||
return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2)
|
||||
end
|
||||
|
||||
local stack = debugstack()
|
||||
if not message then
|
||||
local second = stack:match("\n(.-)\n")
|
||||
message = "error raised! " .. second
|
||||
else
|
||||
local arg = { ... } -- not worried about table creation, as errors don't happen often
|
||||
|
||||
for i = 1, #arg do
|
||||
arg[i] = tostring(arg[i])
|
||||
end
|
||||
for i = 1, 10 do
|
||||
table.insert(arg, "nil")
|
||||
end
|
||||
message = message:format(unpack(arg))
|
||||
end
|
||||
|
||||
if getmetatable(self) and getmetatable(self).__tostring then
|
||||
message = ("%s: %s"):format(tostring(self), message)
|
||||
elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
|
||||
message = ("%s: %s"):format(self:GetLibraryVersion(), message)
|
||||
elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
|
||||
message = ("%s: %s"):format(self.class:GetLibraryVersion(), message)
|
||||
end
|
||||
|
||||
local first = stack:gsub("\n.*", "")
|
||||
local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1")
|
||||
file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
|
||||
|
||||
|
||||
local i = 0
|
||||
for s in stack:gmatch("\n([^\n]*)") do
|
||||
i = i + 1
|
||||
if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
|
||||
file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1")
|
||||
file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
|
||||
break
|
||||
end
|
||||
end
|
||||
local j = 0
|
||||
for s in stack:gmatch("\n([^\n]*)") do
|
||||
j = j + 1
|
||||
if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
|
||||
return _G.error(message, j+1)
|
||||
end
|
||||
end
|
||||
return _G.error(message, 2)
|
||||
end
|
||||
|
||||
local type = type
|
||||
local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
|
||||
if type(num) ~= "number" then
|
||||
return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
|
||||
elseif type(kind) ~= "string" then
|
||||
return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
|
||||
end
|
||||
arg = type(arg)
|
||||
if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
|
||||
local stack = debugstack()
|
||||
local func = stack:match("`argCheck'.-([`<].-['>])")
|
||||
if not func then
|
||||
func = stack:match("([`<].-['>])")
|
||||
end
|
||||
if kind5 then
|
||||
return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
|
||||
elseif kind4 then
|
||||
return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
|
||||
elseif kind3 then
|
||||
return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
|
||||
elseif kind2 then
|
||||
return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
|
||||
else
|
||||
return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local pcall
|
||||
do
|
||||
local function check(self, ret, ...)
|
||||
if not ret then
|
||||
local s = ...
|
||||
return error(self, (s:gsub(".-%.lua:%d-: ", "")))
|
||||
else
|
||||
return ...
|
||||
end
|
||||
end
|
||||
|
||||
function pcall(self, func, ...)
|
||||
return check(self, _G.pcall(func, ...))
|
||||
end
|
||||
end
|
||||
|
||||
local recurse = {}
|
||||
local function addToPositions(t, major)
|
||||
if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
|
||||
rawset(t, recurse, true)
|
||||
AceLibrary.positions[t] = major
|
||||
for k,v in pairs(t) do
|
||||
if type(v) == "table" and not rawget(v, recurse) then
|
||||
addToPositions(v, major)
|
||||
end
|
||||
if type(k) == "table" and not rawget(k, recurse) then
|
||||
addToPositions(k, major)
|
||||
end
|
||||
end
|
||||
local mt = getmetatable(t)
|
||||
if mt and not rawget(mt, recurse) then
|
||||
addToPositions(mt, major)
|
||||
end
|
||||
rawset(t, recurse, nil)
|
||||
end
|
||||
end
|
||||
|
||||
local function svnRevisionToNumber(text)
|
||||
local kind = type(text)
|
||||
if kind == "number" or tonumber(text) then
|
||||
return tonumber(text)
|
||||
elseif kind == "string" then
|
||||
if text:find("^%$Revision: (%d+) %$$") then
|
||||
return tonumber((text:match("^%$Revision: (%d+) %$$")))
|
||||
elseif text:find("^%$Rev: (%d+) %$$") then
|
||||
return tonumber((text:match("^%$Rev: (%d+) %$$")))
|
||||
elseif text:find("^%$LastChangedRevision: (%d+) %$$") then
|
||||
return tonumber((text:match("^%$LastChangedRevision: (%d+) %$$")))
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local crawlReplace
|
||||
do
|
||||
local recurse = {}
|
||||
local function func(t, to, from)
|
||||
if recurse[t] then
|
||||
return
|
||||
end
|
||||
recurse[t] = true
|
||||
local mt = getmetatable(t)
|
||||
setmetatable(t, nil)
|
||||
rawset(t, to, rawget(t, from))
|
||||
rawset(t, from, nil)
|
||||
for k,v in pairs(t) do
|
||||
if v == from then
|
||||
t[k] = to
|
||||
elseif type(v) == "table" then
|
||||
if not recurse[v] then
|
||||
func(v, to, from)
|
||||
end
|
||||
end
|
||||
|
||||
if type(k) == "table" then
|
||||
if not recurse[k] then
|
||||
func(k, to, from)
|
||||
end
|
||||
end
|
||||
end
|
||||
setmetatable(t, mt)
|
||||
if mt then
|
||||
if mt == from then
|
||||
setmetatable(t, to)
|
||||
elseif not recurse[mt] then
|
||||
func(mt, to, from)
|
||||
end
|
||||
end
|
||||
end
|
||||
function crawlReplace(t, to, from)
|
||||
func(t, to, from)
|
||||
for k in pairs(recurse) do
|
||||
recurse[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @function destroyTable
|
||||
-- @brief remove all the contents of a table
|
||||
-- @param t table to destroy
|
||||
local function destroyTable(t)
|
||||
setmetatable(t, nil)
|
||||
for k,v in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function isFrame(frame)
|
||||
return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
|
||||
end
|
||||
|
||||
-- @function copyTable
|
||||
-- @brief Create a shallow copy of a table and return it.
|
||||
-- @param from The table to copy from
|
||||
-- @return A shallow copy of the table
|
||||
local function copyTable(from, to)
|
||||
if not to then
|
||||
to = {}
|
||||
end
|
||||
for k,v in pairs(from) do
|
||||
to[k] = v
|
||||
end
|
||||
setmetatable(to, getmetatable(from))
|
||||
return to
|
||||
end
|
||||
|
||||
-- @function deepTransfer
|
||||
-- @brief Fully transfer all data, keeping proper previous table
|
||||
-- backreferences stable.
|
||||
-- @param to The table with which data is to be injected into
|
||||
-- @param from The table whose data will be injected into the first
|
||||
-- @param saveFields If available, a shallow copy of the basic data is saved
|
||||
-- in here.
|
||||
-- @param list The account of table references
|
||||
-- @param list2 The current status on which tables have been traversed.
|
||||
local deepTransfer
|
||||
do
|
||||
-- @function examine
|
||||
-- @brief Take account of all the table references to be shared
|
||||
-- between the to and from tables.
|
||||
-- @param to The table with which data is to be injected into
|
||||
-- @param from The table whose data will be injected into the first
|
||||
-- @param list An account of the table references
|
||||
local function examine(to, from, list, major)
|
||||
list[from] = to
|
||||
for k,v in pairs(from) do
|
||||
if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
|
||||
if from[k] == to[k] then
|
||||
list[from[k]] = to[k]
|
||||
elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
|
||||
list[from[k]] = from[k]
|
||||
elseif not list[from[k]] then
|
||||
examine(to[k], from[k], list, major)
|
||||
end
|
||||
end
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
function deepTransfer(to, from, saveFields, major, list, list2)
|
||||
setmetatable(to, nil)
|
||||
if not list then
|
||||
list = {}
|
||||
list2 = {}
|
||||
examine(to, from, list, major)
|
||||
end
|
||||
list2[to] = to
|
||||
for k,v in pairs(to) do
|
||||
if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
|
||||
if saveFields then
|
||||
saveFields[k] = v
|
||||
end
|
||||
to[k] = nil
|
||||
elseif v ~= _G then
|
||||
if saveFields then
|
||||
saveFields[k] = copyTable(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
for k in pairs(from) do
|
||||
if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
|
||||
if not list2[to[k]] then
|
||||
deepTransfer(to[k], from[k], nil, major, list, list2)
|
||||
end
|
||||
to[k] = list[to[k]] or list2[to[k]]
|
||||
else
|
||||
rawset(to, k, from[k])
|
||||
end
|
||||
end
|
||||
setmetatable(to, getmetatable(from))
|
||||
local mt = getmetatable(to)
|
||||
if mt then
|
||||
if list[mt] then
|
||||
setmetatable(to, list[mt])
|
||||
elseif mt.__index and list[mt.__index] then
|
||||
mt.__index = list[mt.__index]
|
||||
end
|
||||
end
|
||||
destroyTable(from)
|
||||
end
|
||||
end
|
||||
|
||||
local function TryToEnable(addon)
|
||||
if DONT_ENABLE_LIBRARIES then return end
|
||||
local isondemand = IsAddOnLoadOnDemand(addon)
|
||||
if isondemand then
|
||||
local _, _, _, enabled = GetAddOnInfo(addon)
|
||||
EnableAddOn(addon)
|
||||
local _, _, _, _, loadable = GetAddOnInfo(addon)
|
||||
if not loadable and not enabled then
|
||||
DisableAddOn(addon)
|
||||
end
|
||||
|
||||
return loadable
|
||||
end
|
||||
end
|
||||
|
||||
-- @method TryToLoadStandalone
|
||||
-- @brief Attempt to find and load a standalone version of the requested library
|
||||
-- @param major A string representing the major version
|
||||
-- @return If library is found and loaded, true is return. If not loadable, false is returned.
|
||||
-- If the library has been requested previously, nil is returned.
|
||||
local function TryToLoadStandalone(major)
|
||||
if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end
|
||||
if AceLibrary.scannedlibs[major] then return end
|
||||
|
||||
AceLibrary.scannedlibs[major] = true
|
||||
|
||||
local name, _, _, enabled, loadable = GetAddOnInfo(major)
|
||||
|
||||
loadable = (enabled and loadable) or TryToEnable(name)
|
||||
|
||||
local loaded = false
|
||||
if loadable then
|
||||
loaded = true
|
||||
LoadAddOn(name)
|
||||
end
|
||||
|
||||
local field = "X-AceLibrary-" .. major
|
||||
for i = 1, GetNumAddOns() do
|
||||
if GetAddOnMetadata(i, field) then
|
||||
name, _, _, enabled, loadable = GetAddOnInfo(i)
|
||||
|
||||
loadable = (enabled and loadable) or TryToEnable(name)
|
||||
if loadable then
|
||||
loaded = true
|
||||
LoadAddOn(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
return loaded
|
||||
end
|
||||
|
||||
-- @method IsNewVersion
|
||||
-- @brief Obtain whether the supplied version would be an upgrade to the
|
||||
-- current version. This allows for bypass code in library
|
||||
-- declaration.
|
||||
-- @param major A string representing the major version
|
||||
-- @param minor An integer or an svn revision string representing the minor version
|
||||
-- @return whether the supplied version would be newer than what is
|
||||
-- currently available.
|
||||
function AceLibrary:IsNewVersion(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
TryToLoadStandalone(major)
|
||||
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 3, "number")
|
||||
local lib, oldMinor = LibStub:GetLibrary(major, true)
|
||||
if lib then
|
||||
return oldMinor < minor
|
||||
end
|
||||
local data = self.libs[major]
|
||||
if not data then
|
||||
return true
|
||||
end
|
||||
return data.minor < minor
|
||||
end
|
||||
|
||||
-- @method HasInstance
|
||||
-- @brief Returns whether an instance exists. This allows for optional support of a library.
|
||||
-- @param major A string representing the major version.
|
||||
-- @param minor (optional) An integer or an svn revision string representing the minor version.
|
||||
-- @return Whether an instance exists.
|
||||
function AceLibrary:HasInstance(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
if minor ~= false then
|
||||
TryToLoadStandalone(major)
|
||||
end
|
||||
|
||||
local lib, ver = LibStub:GetLibrary(major, true)
|
||||
if not lib and self.libs[major] then
|
||||
lib, ver = self.libs[major].instance, self.libs[major].minor
|
||||
end
|
||||
if minor then
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 3, "number")
|
||||
if not lib then
|
||||
return false
|
||||
end
|
||||
return ver == minor
|
||||
end
|
||||
return not not lib
|
||||
end
|
||||
|
||||
-- @method GetInstance
|
||||
-- @brief Returns the library with the given major/minor version.
|
||||
-- @param major A string representing the major version.
|
||||
-- @param minor (optional) An integer or an svn revision string representing the minor version.
|
||||
-- @return The library with the given major/minor version.
|
||||
function AceLibrary:GetInstance(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
if minor ~= false then
|
||||
TryToLoadStandalone(major)
|
||||
end
|
||||
|
||||
local data, ver = LibStub:GetLibrary(major, true)
|
||||
if not data then
|
||||
if self.libs[major] then
|
||||
data, ver = self.libs[major].instance, self.libs[major].minor
|
||||
else
|
||||
_G.error(("Cannot find a library instance of %s."):format(major), 2)
|
||||
return
|
||||
end
|
||||
end
|
||||
if minor then
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 2, "number")
|
||||
if ver ~= minor then
|
||||
_G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2)
|
||||
end
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
-- Syntax sugar. AceLibrary("FooBar-1.0")
|
||||
AceLibrary_mt.__call = AceLibrary.GetInstance
|
||||
|
||||
local donothing = function() end
|
||||
|
||||
local AceEvent
|
||||
|
||||
local tmp = {}
|
||||
|
||||
-- @method Register
|
||||
-- @brief Registers a new version of a given library.
|
||||
-- @param newInstance the library to register
|
||||
-- @param major the major version of the library
|
||||
-- @param minor the minor version of the library
|
||||
-- @param activateFunc (optional) A function to be called when the library is
|
||||
-- fully activated. Takes the arguments
|
||||
-- (newInstance [, oldInstance, oldDeactivateFunc]). If
|
||||
-- oldInstance is given, you should probably call
|
||||
-- oldDeactivateFunc(oldInstance).
|
||||
-- @param deactivateFunc (optional) A function to be called by a newer library's
|
||||
-- activateFunc.
|
||||
-- @param externalFunc (optional) A function to be called whenever a new
|
||||
-- library is registered.
|
||||
function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
|
||||
argCheck(self, newInstance, 2, "table")
|
||||
argCheck(self, major, 3, "string")
|
||||
if major ~= ACELIBRARY_MAJOR then
|
||||
for k,v in pairs(_G) do
|
||||
if v == newInstance then
|
||||
geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
|
||||
end
|
||||
end
|
||||
end
|
||||
if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then
|
||||
_G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2)
|
||||
end
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 4, "number")
|
||||
if math.floor(minor) ~= minor or minor < 0 then
|
||||
error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
|
||||
end
|
||||
argCheck(self, activateFunc, 5, "function", "nil")
|
||||
argCheck(self, deactivateFunc, 6, "function", "nil")
|
||||
argCheck(self, externalFunc, 7, "function", "nil")
|
||||
if not deactivateFunc then
|
||||
deactivateFunc = donothing
|
||||
end
|
||||
local data = self.libs[major]
|
||||
if not data then
|
||||
-- This is new
|
||||
if LibStub:GetLibrary(major, true) then
|
||||
error(self, "Cannot register library %q. It is already registered with LibStub.", major)
|
||||
end
|
||||
local instance = LibStub:NewLibrary(major, minor)
|
||||
copyTable(newInstance, instance)
|
||||
crawlReplace(instance, instance, newInstance)
|
||||
destroyTable(newInstance)
|
||||
if AceLibrary == newInstance then
|
||||
self = instance
|
||||
AceLibrary = instance
|
||||
end
|
||||
self.libs[major] = {
|
||||
instance = instance,
|
||||
minor = minor,
|
||||
deactivateFunc = deactivateFunc,
|
||||
externalFunc = externalFunc,
|
||||
}
|
||||
rawset(instance, 'GetLibraryVersion', function(self)
|
||||
return major, minor
|
||||
end)
|
||||
if not rawget(instance, 'error') then
|
||||
rawset(instance, 'error', error)
|
||||
end
|
||||
if not rawget(instance, 'argCheck') then
|
||||
rawset(instance, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(instance, 'pcall') then
|
||||
rawset(instance, 'pcall', pcall)
|
||||
end
|
||||
addToPositions(instance, major)
|
||||
if activateFunc then
|
||||
safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil
|
||||
end
|
||||
|
||||
if externalFunc then
|
||||
for k, data_instance in LibStub:IterateLibraries() do -- all libraries
|
||||
tmp[k] = data_instance
|
||||
end
|
||||
for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
|
||||
tmp[k] = data.instance
|
||||
end
|
||||
for k, data_instance in pairs(tmp) do
|
||||
if k ~= major then
|
||||
safecall(externalFunc, instance, k, data_instance)
|
||||
end
|
||||
tmp[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
for k,data in pairs(self.libs) do -- only Ace libraries
|
||||
if k ~= major and data.externalFunc then
|
||||
safecall(data.externalFunc, data.instance, major, instance)
|
||||
end
|
||||
end
|
||||
if major == "AceEvent-2.0" then
|
||||
AceEvent = instance
|
||||
end
|
||||
if AceEvent then
|
||||
AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
if minor <= data.minor then
|
||||
-- This one is already obsolete, raise an error.
|
||||
_G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2)
|
||||
return
|
||||
end
|
||||
local instance = data.instance
|
||||
-- This is an update
|
||||
local oldInstance = {}
|
||||
|
||||
local libStubInstance = LibStub:GetLibrary(major, true)
|
||||
if not libStubInstance then -- non-LibStub AceLibrary registered the library
|
||||
-- pass
|
||||
elseif libStubInstance ~= instance then
|
||||
error(self, "Cannot register library %q. It is already registered with LibStub.", major)
|
||||
else
|
||||
LibStub:NewLibrary(major, minor) -- upgrade the minor version
|
||||
end
|
||||
|
||||
addToPositions(newInstance, major)
|
||||
local isAceLibrary = (AceLibrary == newInstance)
|
||||
local old_error, old_argCheck, old_pcall
|
||||
if isAceLibrary then
|
||||
self = instance
|
||||
AceLibrary = instance
|
||||
|
||||
old_error = instance.error
|
||||
old_argCheck = instance.argCheck
|
||||
old_pcall = instance.pcall
|
||||
|
||||
self.error = error
|
||||
self.argCheck = argCheck
|
||||
self.pcall = pcall
|
||||
end
|
||||
deepTransfer(instance, newInstance, oldInstance, major)
|
||||
crawlReplace(instance, instance, newInstance)
|
||||
local oldDeactivateFunc = data.deactivateFunc
|
||||
data.minor = minor
|
||||
data.deactivateFunc = deactivateFunc
|
||||
data.externalFunc = externalFunc
|
||||
rawset(instance, 'GetLibraryVersion', function()
|
||||
return major, minor
|
||||
end)
|
||||
if not rawget(instance, 'error') then
|
||||
rawset(instance, 'error', error)
|
||||
end
|
||||
if not rawget(instance, 'argCheck') then
|
||||
rawset(instance, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(instance, 'pcall') then
|
||||
rawset(instance, 'pcall', pcall)
|
||||
end
|
||||
if isAceLibrary then
|
||||
for _,v in pairs(self.libs) do
|
||||
local i = type(v) == "table" and v.instance
|
||||
if type(i) == "table" then
|
||||
if not rawget(i, 'error') or i.error == old_error then
|
||||
rawset(i, 'error', error)
|
||||
end
|
||||
if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
|
||||
rawset(i, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(i, 'pcall') or i.pcall == old_pcall then
|
||||
rawset(i, 'pcall', pcall)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if activateFunc then
|
||||
safecall(activateFunc, instance, oldInstance, oldDeactivateFunc)
|
||||
else
|
||||
safecall(oldDeactivateFunc, oldInstance)
|
||||
end
|
||||
oldInstance = nil
|
||||
|
||||
if externalFunc then
|
||||
for k, data_instance in LibStub:IterateLibraries() do -- all libraries
|
||||
tmp[k] = data_instance
|
||||
end
|
||||
for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
|
||||
tmp[k] = data.instance
|
||||
end
|
||||
for k, data_instance in pairs(tmp) do
|
||||
if k ~= major then
|
||||
safecall(externalFunc, instance, k, data_instance)
|
||||
end
|
||||
tmp[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
|
||||
function AceLibrary:IterateLibraries()
|
||||
local t = {}
|
||||
for major, instance in LibStub:IterateLibraries() do
|
||||
t[major] = instance
|
||||
end
|
||||
for major, data in pairs(self.libs) do
|
||||
t[major] = data.instance
|
||||
end
|
||||
return pairs(t)
|
||||
end
|
||||
|
||||
local function manuallyFinalize(major, instance)
|
||||
if AceLibrary.libs[major] then
|
||||
-- don't work on Ace libraries
|
||||
return
|
||||
end
|
||||
local finalizedExternalLibs = AceLibrary.finalizedExternalLibs
|
||||
if finalizedExternalLibs[major] then
|
||||
return
|
||||
end
|
||||
finalizedExternalLibs[major] = true
|
||||
|
||||
for k,data in pairs(AceLibrary.libs) do -- only Ace libraries
|
||||
if k ~= major and data.externalFunc then
|
||||
safecall(data.externalFunc, data.instance, major, instance)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @function Activate
|
||||
-- @brief The activateFunc for AceLibrary itself. Called when
|
||||
-- AceLibrary properly registers.
|
||||
-- @param self Reference to AceLibrary
|
||||
-- @param oldLib (optional) Reference to an old version of AceLibrary
|
||||
-- @param oldDeactivate (optional) Function to deactivate the old lib
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
AceLibrary = self
|
||||
if not self.libs then
|
||||
self.libs = oldLib and oldLib.libs or {}
|
||||
self.scannedlibs = oldLib and oldLib.scannedlibs or {}
|
||||
end
|
||||
if not self.positions then
|
||||
self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" })
|
||||
end
|
||||
self.finalizedExternalLibs = oldLib and oldLib.finalizedExternalLibs or {}
|
||||
self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
|
||||
self.frame:UnregisterAllEvents()
|
||||
self.frame:RegisterEvent("ADDON_LOADED")
|
||||
self.frame:SetScript("OnEvent", function()
|
||||
for major, instance in LibStub:IterateLibraries() do
|
||||
manuallyFinalize(major, instance)
|
||||
end
|
||||
end)
|
||||
for major, instance in LibStub:IterateLibraries() do
|
||||
manuallyFinalize(major, instance)
|
||||
end
|
||||
|
||||
-- Expose the library in the global environment
|
||||
_G[ACELIBRARY_MAJOR] = self
|
||||
|
||||
if oldDeactivate then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
if not previous then
|
||||
previous = AceLibrary
|
||||
end
|
||||
if not previous.libs then
|
||||
previous.libs = {}
|
||||
end
|
||||
AceLibrary.libs = previous.libs
|
||||
if not previous.positions then
|
||||
previous.positions = setmetatable({}, { __mode = "k" })
|
||||
end
|
||||
AceLibrary.positions = previous.positions
|
||||
AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate, nil)
|
||||
@@ -0,0 +1,15 @@
|
||||
## Interface: 30300
|
||||
## X-Curse-Packaged-Version: r1101
|
||||
## X-Curse-Project-Name: Ace2
|
||||
## X-Curse-Project-ID: ace2
|
||||
## X-Curse-Repository-ID: wow/ace2/mainline
|
||||
|
||||
## Title: Lib: AceLibrary
|
||||
## Notes: AddOn development framework
|
||||
## Author: Ace Development Team
|
||||
## X-Website: http://www.wowace.com
|
||||
## X-Category: Library
|
||||
## X-License: LGPL v2.1 + MIT for AceOO-2.0
|
||||
|
||||
AceLibrary.lua
|
||||
|
||||
@@ -0,0 +1,980 @@
|
||||
--[[
|
||||
Name: AceOO-2.0
|
||||
Revision: $Rev: 1091 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Ace 1.x by Turan (turan@gryphon.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceOO-2.0
|
||||
SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceOO-2.0
|
||||
Description: Library to provide an object-orientation framework.
|
||||
Dependencies: AceLibrary
|
||||
License: MIT
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "AceOO-2.0"
|
||||
local MINOR_VERSION = 90000 + tonumber(("$Revision: 1091 $"):match("(%d+)"))
|
||||
|
||||
-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
local AceOO = {
|
||||
error = AceLibrary.error,
|
||||
argCheck = AceLibrary.argCheck
|
||||
}
|
||||
|
||||
-- @function getuid
|
||||
-- @brief Obtain a unique string identifier for the object in question.
|
||||
-- @param t The object to obtain the uid for.
|
||||
-- @return The uid string.
|
||||
local function getuid(t)
|
||||
local mt = getmetatable(t)
|
||||
setmetatable(t, nil)
|
||||
local str = tostring(t)
|
||||
setmetatable(t, mt)
|
||||
local cap = str:match("[^:]*: 0x(.*)$") or str:match("[^:]*: (.*)$")
|
||||
if cap then
|
||||
return ("0"):rep(8 - #cap) .. cap
|
||||
end
|
||||
end
|
||||
|
||||
local function getlibrary(o)
|
||||
if type(o) == "table" then
|
||||
return o
|
||||
elseif type(o) == "string" then
|
||||
if not AceLibrary:HasInstance(o) then
|
||||
AceOO:error("Library %q does not exist.", o)
|
||||
end
|
||||
return AceLibrary(o)
|
||||
end
|
||||
end
|
||||
|
||||
local function deeprawget(self, k)
|
||||
while true do
|
||||
local v = rawget(self, k)
|
||||
if v ~= nil then
|
||||
return v
|
||||
end
|
||||
local mt = getmetatable(self)
|
||||
if not mt or type(mt.__index) ~= "table" then
|
||||
return nil
|
||||
end
|
||||
self = mt.__index
|
||||
end
|
||||
end
|
||||
|
||||
-- @function Factory
|
||||
-- @brief Construct a factory for the creation of objects.
|
||||
-- @param obj The object whose init method will be called on the new factory
|
||||
-- object.
|
||||
-- @param newobj The object whose init method will be called on the new
|
||||
-- objects that the Factory creates, to initialize them.
|
||||
-- @param (...) Arguments which will be passed to obj.init() in addition
|
||||
-- to the Factory object.
|
||||
-- @return The new factory which creates a newobj when its new method is called,
|
||||
-- or when it is called directly (__call metamethod).
|
||||
local Factory
|
||||
do
|
||||
local function getlibraries(...)
|
||||
if select('#', ...) == 0 then
|
||||
return
|
||||
end
|
||||
return getlibrary((select(1, ...))), getlibraries(select(2, ...))
|
||||
end
|
||||
local arg = {}
|
||||
local function new(obj, ...)
|
||||
local t = {}
|
||||
local uid = getuid(t)
|
||||
obj:init(t, getlibraries(...))
|
||||
t.uid = uid
|
||||
return t
|
||||
end
|
||||
|
||||
local function createnew(self, ...)
|
||||
local o = self.prototype
|
||||
local x = new(o, getlibraries(...))
|
||||
return x
|
||||
end
|
||||
|
||||
function Factory(obj, newobj, ...)
|
||||
local t = new(obj, ...)
|
||||
t.prototype = newobj
|
||||
t.new = createnew
|
||||
getmetatable(t).__call = t.new
|
||||
return t
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function objtostring(self)
|
||||
if self.ToString then
|
||||
return self:ToString()
|
||||
elseif self.GetLibraryVersion then
|
||||
return (self:GetLibraryVersion())
|
||||
elseif self.super then
|
||||
local s = "Sub-" .. tostring(self.super)
|
||||
local first = true
|
||||
if self.interfaces then
|
||||
for interface in pairs(self.interfaces) do
|
||||
if first then
|
||||
s = s .. "(" .. tostring(interface)
|
||||
first = false
|
||||
else
|
||||
s = s .. ", " .. tostring(interface)
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.mixins then
|
||||
for mixin in pairs(self.mixins) do
|
||||
if first then
|
||||
s = s .. tostring(mixin)
|
||||
first = false
|
||||
else
|
||||
s = s .. ", " .. tostring(mixin)
|
||||
end
|
||||
end
|
||||
end
|
||||
if first then
|
||||
if self.uid then
|
||||
return s .. ":" .. self.uid
|
||||
else
|
||||
return s
|
||||
end
|
||||
else
|
||||
return s .. ")"
|
||||
end
|
||||
else
|
||||
return self.uid and 'Subclass:' .. self.uid or 'Subclass'
|
||||
end
|
||||
end
|
||||
|
||||
-- @table Object
|
||||
-- @brief Base of all objects, including Class.
|
||||
--
|
||||
-- @method init
|
||||
-- @brief Initialize a new object.
|
||||
-- @param newobject The object to initialize
|
||||
-- @param class The class to make newobject inherit from
|
||||
local Object
|
||||
do
|
||||
Object = {}
|
||||
function Object:init(newobject, class)
|
||||
local parent = class or self
|
||||
if not rawget(newobject, 'uid') then
|
||||
newobject.uid = getuid(newobject)
|
||||
end
|
||||
local mt = {
|
||||
__index = parent,
|
||||
__tostring = objtostring,
|
||||
}
|
||||
setmetatable(newobject, mt)
|
||||
end
|
||||
Object.uid = getuid(Object)
|
||||
setmetatable(Object, { __tostring = function() return 'Object' end })
|
||||
end
|
||||
|
||||
local Interface
|
||||
|
||||
local function validateInterface(object, interface)
|
||||
if not object.class and object.prototype then
|
||||
object = object.prototype
|
||||
end
|
||||
for k,v in pairs(interface.interface) do
|
||||
if tostring(type(object[k])) ~= v then
|
||||
return false
|
||||
end
|
||||
end
|
||||
if interface.superinterfaces then
|
||||
for superinterface in pairs(interface.superinterfaces) do
|
||||
if not validateInterface(object, superinterface) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
if type(object.class) == "table" and rawequal(object.class.prototype, object) then
|
||||
if not object.class.interfaces then
|
||||
rawset(object.class, 'interfaces', {})
|
||||
end
|
||||
object.class.interfaces[interface] = true
|
||||
elseif type(object.class) == "table" and type(object.class.prototype) == "table" then
|
||||
validateInterface(object.class.prototype, interface)
|
||||
-- check if class is proper, thus preventing future checks.
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- @function inherits
|
||||
-- @brief Return whether an Object or Class inherits from a given
|
||||
-- parent.
|
||||
-- @param object Object or Class to check
|
||||
-- @param parent Parent to test inheritance from
|
||||
-- @return whether an Object or Class inherits from a given
|
||||
-- parent.
|
||||
local function inherits(object, parent)
|
||||
object = getlibrary(object)
|
||||
if type(parent) == "string" then
|
||||
if not AceLibrary:HasInstance(parent) then
|
||||
return false
|
||||
else
|
||||
parent = AceLibrary(parent)
|
||||
end
|
||||
end
|
||||
AceOO:argCheck(parent, 2, "table")
|
||||
if type(object) ~= "table" then
|
||||
return false
|
||||
end
|
||||
local current
|
||||
local class = deeprawget(object, 'class')
|
||||
if class then
|
||||
current = class
|
||||
else
|
||||
current = object
|
||||
end
|
||||
if type(current) ~= "table" then
|
||||
return false
|
||||
end
|
||||
if rawequal(current, parent) then
|
||||
return true
|
||||
end
|
||||
if parent.class then
|
||||
while true do
|
||||
if rawequal(current, Object) then
|
||||
break
|
||||
end
|
||||
if current.mixins then
|
||||
for mixin in pairs(current.mixins) do
|
||||
if rawequal(mixin, parent) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
if current.interfaces then
|
||||
for interface in pairs(current.interfaces) do
|
||||
if rawequal(interface, parent) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
current = deeprawget(current, 'super')
|
||||
if type(current) ~= "table" then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local isInterface = false
|
||||
local curr = parent.class
|
||||
while true do
|
||||
if rawequal(curr, Object) then
|
||||
break
|
||||
elseif rawequal(curr, Interface) then
|
||||
isInterface = true
|
||||
break
|
||||
end
|
||||
curr = deeprawget(curr, 'super')
|
||||
if type(curr) ~= "table" then
|
||||
break
|
||||
end
|
||||
end
|
||||
return isInterface and validateInterface(object, parent)
|
||||
else
|
||||
while true do
|
||||
if rawequal(current, parent) then
|
||||
return true
|
||||
elseif rawequal(current, Object) then
|
||||
return false
|
||||
end
|
||||
current = deeprawget(current, 'super')
|
||||
if type(current) ~= "table" then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @table Class
|
||||
-- @brief An object factory which sets up inheritence and supports
|
||||
-- 'mixins'.
|
||||
--
|
||||
-- @metamethod Class call
|
||||
-- @brief Call ClassFactory:new() to create a new class.
|
||||
--
|
||||
-- @method Class new
|
||||
-- @brief Construct a new object.
|
||||
-- @param (...) Arguments to pass to the object init function.
|
||||
-- @return The new object.
|
||||
--
|
||||
-- @method Class init
|
||||
-- @brief Initialize a new class.
|
||||
-- @param parent Superclass.
|
||||
-- @param (...) Mixins.
|
||||
--
|
||||
-- @method Class ToString
|
||||
-- @return A string representing the object, in this case 'Class'.
|
||||
local initStatus
|
||||
local Class
|
||||
local Mixin
|
||||
local autoEmbed = false
|
||||
local function traverseInterfaces(bit, total)
|
||||
if bit.superinterfaces then
|
||||
for interface in pairs(bit.superinterfaces) do
|
||||
if not total[interface] then
|
||||
total[interface] = true
|
||||
traverseInterfaces(interface, total)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local class_new
|
||||
do
|
||||
Class = Factory(Object, setmetatable({}, {__index = Object}), Object)
|
||||
Class.super = Object
|
||||
|
||||
local function protostring(t)
|
||||
return '<' .. tostring(t.class) .. ' prototype>'
|
||||
end
|
||||
local function classobjectstring(t)
|
||||
if t.ToString then
|
||||
return t:ToString()
|
||||
elseif t.GetLibraryVersion then
|
||||
return (t:GetLibraryVersion())
|
||||
else
|
||||
return '<' .. tostring(t.class) .. ' instance>'
|
||||
end
|
||||
end
|
||||
local function classobjectequal(self, other)
|
||||
if type(self) == "table" and self.Equals then
|
||||
return self:Equals(other)
|
||||
elseif type(other) == "table" and other.Equals then
|
||||
return other:Equals(self)
|
||||
elseif type(self) == "table" and self.CompareTo then
|
||||
return self:CompareTo(other) == 0
|
||||
elseif type(other) == "table" and other.CompareTo then
|
||||
return other:CompareTo(self) == 0
|
||||
else
|
||||
return rawequal(self, other)
|
||||
end
|
||||
end
|
||||
local function classobjectlessthan(self, other)
|
||||
if type(self) == "table" and self.IsLessThan then
|
||||
return self:IsLessThan(other)
|
||||
elseif type(other) == "table" and other.IsLessThanOrEqualTo then
|
||||
return not other:IsLessThanOrEqualTo(self)
|
||||
elseif type(self) == "table" and self.CompareTo then
|
||||
return self:CompareTo(other) < 0
|
||||
elseif type(other) == "table" and other.CompareTo then
|
||||
return other:CompareTo(self) > 0
|
||||
elseif type(other) == "table" and other.IsLessThan and other.Equals then
|
||||
return other:Equals(self) or other:IsLessThan(self)
|
||||
else
|
||||
AceOO:error("cannot compare two objects")
|
||||
end
|
||||
end
|
||||
local function classobjectlessthanequal(self, other)
|
||||
if type(self) == "table" and self.IsLessThanOrEqualTo then
|
||||
return self:IsLessThanOrEqualTo(other)
|
||||
elseif type(other) == "table" and other.IsLessThan then
|
||||
return not other:IsLessThan(self)
|
||||
elseif type(self) == "table" and self.CompareTo then
|
||||
return self:CompareTo(other) <= 0
|
||||
elseif type(other) == "table" and other.CompareTo then
|
||||
return other:CompareTo(self) >= 0
|
||||
elseif type(self) == "table" and self.IsLessThan and self.Equals then
|
||||
return self:Equals(other) or self:IsLessThan(other)
|
||||
else
|
||||
AceOO:error("cannot compare two incompatible objects")
|
||||
end
|
||||
end
|
||||
local function classobjectadd(self, other)
|
||||
if type(self) == "table" and self.Add then
|
||||
return self:Add(other)
|
||||
else
|
||||
AceOO:error("cannot add two incompatible objects")
|
||||
end
|
||||
end
|
||||
local function classobjectsub(self, other)
|
||||
if type(self) == "table" and self.Subtract then
|
||||
return self:Subtract(other)
|
||||
else
|
||||
AceOO:error("cannot subtract two incompatible objects")
|
||||
end
|
||||
end
|
||||
local function classobjectunm(self, other)
|
||||
if type(self) == "table" and self.UnaryNegation then
|
||||
return self:UnaryNegation(other)
|
||||
else
|
||||
AceOO:error("attempt to negate an incompatible object")
|
||||
end
|
||||
end
|
||||
local function classobjectmul(self, other)
|
||||
if type(self) == "table" and self.Multiply then
|
||||
return self:Multiply(other)
|
||||
else
|
||||
AceOO:error("cannot multiply two incompatible objects")
|
||||
end
|
||||
end
|
||||
local function classobjectdiv(self, other)
|
||||
if type(self) == "table" and self.Divide then
|
||||
return self:Divide(other)
|
||||
else
|
||||
AceOO:error("cannot divide two incompatible objects")
|
||||
end
|
||||
end
|
||||
local function classobjectpow(self, other)
|
||||
if type(self) == "table" and self.Exponent then
|
||||
return self:Exponent(other)
|
||||
else
|
||||
AceOO:error("cannot exponentiate two incompatible objects")
|
||||
end
|
||||
end
|
||||
local function classobjectconcat(self, other)
|
||||
if type(self) == "table" and self.Concatenate then
|
||||
return self:Concatenate(other)
|
||||
else
|
||||
AceOO:error("cannot concatenate two incompatible objects")
|
||||
end
|
||||
end
|
||||
function class_new(self, ...)
|
||||
if self.virtual then
|
||||
AceOO:error("Cannot instantiate a virtual class.")
|
||||
end
|
||||
|
||||
local o = self.prototype
|
||||
local newobj = {}
|
||||
if o.class and o.class.instancemeta then
|
||||
setmetatable(newobj, o.class.instancemeta)
|
||||
else
|
||||
Object:init(newobj, o)
|
||||
end
|
||||
|
||||
if self.interfaces and not self.interfacesVerified then
|
||||
-- Verify the interfaces
|
||||
|
||||
for interface in pairs(self.interfaces) do
|
||||
for field,kind in pairs(interface.interface) do
|
||||
if tostring(type(newobj[field])) ~= kind then
|
||||
AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field])))
|
||||
end
|
||||
end
|
||||
end
|
||||
self.interfacesVerified = true
|
||||
end
|
||||
local tmp = initStatus
|
||||
initStatus = newobj
|
||||
newobj:init(...)
|
||||
if initStatus then
|
||||
initStatus = tmp
|
||||
AceOO:error("Initialization not completed, be sure to call the superclass's init method.")
|
||||
return
|
||||
end
|
||||
initStatus = tmp
|
||||
return newobj
|
||||
end
|
||||
local classmeta = {
|
||||
__tostring = objtostring,
|
||||
__call = function(self, ...)
|
||||
return self:new(...)
|
||||
end,
|
||||
}
|
||||
function Class:init(newclass, parent, ...)
|
||||
parent = parent or self
|
||||
|
||||
local total
|
||||
|
||||
if parent.class then
|
||||
total = { parent, ... }
|
||||
parent = self
|
||||
else
|
||||
total = { ... }
|
||||
end
|
||||
if not inherits(parent, Class) then
|
||||
AceOO:error("Classes must inherit from a proper class")
|
||||
end
|
||||
if parent.sealed then
|
||||
AceOO:error("Cannot inherit from a sealed class")
|
||||
end
|
||||
for i,v in ipairs(total) do
|
||||
if inherits(v, Mixin) and v.class then
|
||||
if v.__deprecated then
|
||||
AceOO:error(v.__deprecated)
|
||||
end
|
||||
if not newclass.mixins then
|
||||
newclass.mixins = {}
|
||||
end
|
||||
if newclass.mixins[v] then
|
||||
AceOO:error("Cannot explicitly inherit from the same mixin twice")
|
||||
end
|
||||
newclass.mixins[v] = true
|
||||
elseif inherits(v, Interface) and v.class then
|
||||
if not newclass.interfaces then
|
||||
newclass.interfaces = {}
|
||||
end
|
||||
if newclass.interfaces[v] then
|
||||
AceOO:error("Cannot explicitly inherit from the same interface twice")
|
||||
end
|
||||
newclass.interfaces[v] = true
|
||||
else
|
||||
AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces")
|
||||
end
|
||||
end
|
||||
if parent.interfaces then
|
||||
if not newclass.interfaces then
|
||||
newclass.interfaces = {}
|
||||
end
|
||||
for interface in pairs(parent.interfaces) do
|
||||
newclass.interfaces[interface] = true
|
||||
end
|
||||
end
|
||||
for k in pairs(total) do
|
||||
total[k] = nil
|
||||
end
|
||||
|
||||
newclass.super = parent
|
||||
|
||||
newclass.prototype = setmetatable(total, {
|
||||
__index = parent.prototype,
|
||||
__tostring = protostring,
|
||||
})
|
||||
total = nil
|
||||
|
||||
newclass.instancemeta = {
|
||||
__index = newclass.prototype,
|
||||
__tostring = classobjectstring,
|
||||
__eq = classobjectequal,
|
||||
__lt = classobjectlessthan,
|
||||
__le = classobjectlessthanequal,
|
||||
__add = classobjectadd,
|
||||
__sub = classobjectsub,
|
||||
__unm = classobjectunm,
|
||||
__mul = classobjectmul,
|
||||
__div = classobjectdiv,
|
||||
__pow = classobjectpow,
|
||||
__concat = classobjectconcat,
|
||||
}
|
||||
|
||||
setmetatable(newclass, classmeta)
|
||||
|
||||
newclass.new = class_new
|
||||
|
||||
if newclass.mixins then
|
||||
-- Fold in the mixins
|
||||
local err, msg
|
||||
for mixin in pairs(newclass.mixins) do
|
||||
local ret
|
||||
autoEmbed = true
|
||||
ret, msg = pcall(mixin.embed, mixin, newclass.prototype)
|
||||
autoEmbed = false
|
||||
if not ret then
|
||||
err = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if err then
|
||||
local pt = newclass.prototype
|
||||
for k,v in pairs(pt) do
|
||||
pt[k] = nil
|
||||
end
|
||||
|
||||
-- method conflict
|
||||
AceOO:error(msg)
|
||||
end
|
||||
end
|
||||
|
||||
newclass.prototype.class = newclass
|
||||
|
||||
if newclass.interfaces then
|
||||
for interface in pairs(newclass.interfaces) do
|
||||
traverseInterfaces(interface, newclass.interfaces)
|
||||
end
|
||||
end
|
||||
if newclass.mixins then
|
||||
for mixin in pairs(newclass.mixins) do
|
||||
if mixin.interfaces then
|
||||
if not newclass.interfaces then
|
||||
newclass.interfaces = {}
|
||||
end
|
||||
for interface in pairs(mixin.interfaces) do
|
||||
newclass.interfaces[interface] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
function Class:ToString()
|
||||
if type(self.GetLibraryVersion) == "function" then
|
||||
return (self:GetLibraryVersion())
|
||||
else
|
||||
return "Class"
|
||||
end
|
||||
end
|
||||
|
||||
local tmp
|
||||
function Class.prototype:init()
|
||||
if rawequal(self, initStatus) then
|
||||
initStatus = nil
|
||||
else
|
||||
AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2)
|
||||
end
|
||||
self.uid = getuid(self)
|
||||
local current = self.class
|
||||
while true do
|
||||
if current == Class then
|
||||
break
|
||||
end
|
||||
if current.mixins then
|
||||
for mixin in pairs(current.mixins) do
|
||||
if type(mixin.OnInstanceInit) == "function" then
|
||||
mixin:OnInstanceInit(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
current = current.super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- @object ClassFactory
|
||||
-- @brief A factory for creating classes. Rarely used directly.
|
||||
local ClassFactory = Factory(Object, Class, Object)
|
||||
|
||||
function Class:new(...)
|
||||
local x = ClassFactory:new(...)
|
||||
if AceOO.classes then
|
||||
AceOO.classes[x] = true
|
||||
end
|
||||
return x
|
||||
end
|
||||
getmetatable(Class).__call = Class.new
|
||||
|
||||
-- @class Mixin
|
||||
-- @brief A class to create mixin objects, which contain methods that get
|
||||
-- "mixed in" to class prototypes.
|
||||
--
|
||||
-- @object Mixin prototype
|
||||
-- @brief The prototype that mixin objects inherit their methods from.
|
||||
--
|
||||
-- @method Mixin prototype embed
|
||||
-- @brief Mix in the methods of our object which are listed in our interface
|
||||
-- to the supplied target table.
|
||||
--
|
||||
-- @method Mixin prototype init
|
||||
-- @brief Initialize the mixin object.
|
||||
-- @param newobj The new object we're initializing.
|
||||
-- @param interface The interface we implement (the list of methods our
|
||||
-- prototype provides which should be mixed into the target
|
||||
-- table by embed).
|
||||
do
|
||||
Mixin = Class()
|
||||
function Mixin:ToString()
|
||||
if self.GetLibraryVersion then
|
||||
return (self:GetLibraryVersion())
|
||||
else
|
||||
return 'Mixin'
|
||||
end
|
||||
end
|
||||
local function _Embed(state, field, target)
|
||||
field = next(state.export, field)
|
||||
if field == nil then
|
||||
return
|
||||
end
|
||||
|
||||
if rawget(target, field) or (target[field] and target[field] ~= state[field]) then
|
||||
AceOO:error("Method conflict in attempt to mixin. Field %q", field)
|
||||
end
|
||||
|
||||
target[field] = state[field]
|
||||
|
||||
local ret,msg = pcall(_Embed, state, field, target)
|
||||
if not ret then
|
||||
-- Mix in the next method according to the defined interface. If that
|
||||
-- fails due to a conflict, re-raise to back out the previous mixed
|
||||
-- methods.
|
||||
|
||||
target[field] = nil
|
||||
AceOO:error(msg)
|
||||
end
|
||||
end
|
||||
function Mixin.prototype:embed(target)
|
||||
if self.__deprecated then
|
||||
AceOO:error(self.__deprecated)
|
||||
end
|
||||
local mt = getmetatable(target)
|
||||
setmetatable(target, nil)
|
||||
local err, msg = pcall(_Embed, self, nil, target)
|
||||
if not err then
|
||||
setmetatable(target, mt)
|
||||
AceOO:error(msg)
|
||||
return
|
||||
end
|
||||
if type(self.embedList) == "table" then
|
||||
self.embedList[target] = true
|
||||
end
|
||||
if type(target.class) ~= "table" then
|
||||
target[self] = true
|
||||
end
|
||||
if not autoEmbed and type(self.OnManualEmbed) == "function" then
|
||||
self:OnManualEmbed(target)
|
||||
end
|
||||
setmetatable(target, mt)
|
||||
end
|
||||
|
||||
function Mixin.prototype:activate(oldLib, oldDeactivate)
|
||||
if oldLib and oldLib.embedList then
|
||||
for target in pairs(oldLib.embedList) do
|
||||
local mt = getmetatable(target)
|
||||
setmetatable(target, nil)
|
||||
for field in pairs(oldLib.export) do
|
||||
target[field] = nil
|
||||
end
|
||||
setmetatable(target, mt)
|
||||
end
|
||||
self.embedList = oldLib.embedList
|
||||
for target in pairs(self.embedList) do
|
||||
self:embed(target)
|
||||
end
|
||||
else
|
||||
self.embedList = setmetatable({}, {__mode="k"})
|
||||
end
|
||||
end
|
||||
|
||||
function Mixin.prototype:init(export, ...)
|
||||
AceOO:argCheck(export, 2, "table")
|
||||
for k,v in pairs(export) do
|
||||
if type(k) ~= "number" then
|
||||
AceOO:error("All keys to argument #2 must be numbers.")
|
||||
elseif type(v) ~= "string" then
|
||||
AceOO:error("All values to argument #2 must be strings.")
|
||||
end
|
||||
end
|
||||
local num = #export
|
||||
for i = 1, num do
|
||||
local v = export[i]
|
||||
export[i] = nil
|
||||
export[v] = true
|
||||
end
|
||||
|
||||
local interfaces
|
||||
if select('#', ...) >= 1 then
|
||||
interfaces = { ... }
|
||||
for i,v in ipairs(interfaces) do
|
||||
v = getlibrary(v)
|
||||
interfaces[i] = v
|
||||
if not v.class or not inherits(v, Interface) then
|
||||
AceOO:error("Mixins can inherit only from interfaces")
|
||||
end
|
||||
end
|
||||
local num = #interfaces
|
||||
for i = 1, num do
|
||||
local v = interfaces[i]
|
||||
interfaces[i] = nil
|
||||
interfaces[v] = true
|
||||
end
|
||||
for interface in pairs(interfaces) do
|
||||
traverseInterfaces(interface, interfaces)
|
||||
end
|
||||
for interface in pairs(interfaces) do
|
||||
for field,kind in pairs(interface.interface) do
|
||||
if kind ~= "nil" then
|
||||
local good = false
|
||||
for bit in pairs(export) do
|
||||
if bit == field then
|
||||
good = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not good then
|
||||
AceOO:error("Mixin does not fully accommodate field %q", field)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self.super = Mixin.prototype
|
||||
Mixin.super.prototype.init(self)
|
||||
self.export = export
|
||||
self.interfaces = interfaces
|
||||
end
|
||||
end
|
||||
|
||||
-- @class Interface
|
||||
-- @brief A class to create interfaces, which contain contracts that classes
|
||||
-- which inherit from this must comply with.
|
||||
--
|
||||
-- @object Interface prototype
|
||||
-- @brief The prototype that interface objects must adhere to.
|
||||
--
|
||||
-- @method Interface prototype init
|
||||
-- @brief Initialize the mixin object.
|
||||
-- @param interface The interface we contract (the hash of fields forced).
|
||||
-- @param (...) Superinterfaces
|
||||
do
|
||||
Interface = Class()
|
||||
function Interface:ToString()
|
||||
if self.GetLibraryVersion then
|
||||
return (self:GetLibraryVersion())
|
||||
else
|
||||
return 'Instance'
|
||||
end
|
||||
end
|
||||
function Interface.prototype:init(interface, ...)
|
||||
Interface.super.prototype.init(self)
|
||||
AceOO:argCheck(interface, 2, "table")
|
||||
for k,v in pairs(interface) do
|
||||
if type(k) ~= "string" then
|
||||
AceOO:error("All keys to argument #2 must be numbers.")
|
||||
elseif type(v) ~= "string" then
|
||||
AceOO:error("All values to argument #2 must be strings.")
|
||||
elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then
|
||||
AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".')
|
||||
end
|
||||
end
|
||||
if select('#', ...) >= 1 then
|
||||
self.superinterfaces = { ... }
|
||||
for i,v in ipairs(self.superinterfaces) do
|
||||
v = getlibrary(v)
|
||||
self.superinterfaces[i] = v
|
||||
if not inherits(v, Interface) or not v.class then
|
||||
AceOO:error('Cannot provide a non-Interface to inherit from')
|
||||
end
|
||||
end
|
||||
local num = #self.superinterfaces
|
||||
for i = 1, num do
|
||||
local v = self.superinterfaces[i]
|
||||
self.superinterfaces[i] = nil
|
||||
self.superinterfaces[v] = true
|
||||
end
|
||||
end
|
||||
self.interface = interface
|
||||
end
|
||||
end
|
||||
|
||||
-- @function Classpool
|
||||
-- @brief Obtain a read only class from our pool of classes, indexed by the
|
||||
-- superclass and mixins.
|
||||
-- @param sc The superclass of the class we want.
|
||||
-- @param (m1..m20) Mixins of the class we want's objects.
|
||||
-- @return A read only class from the class pool.
|
||||
local Classpool
|
||||
do
|
||||
local pool = setmetatable({}, {__mode = 'v'})
|
||||
local function newindex(k, v)
|
||||
AceOO:error('Attempt to modify a read-only class.')
|
||||
end
|
||||
local function protonewindex(k, v)
|
||||
AceOO:error('Attempt to modify a read-only class prototype.')
|
||||
end
|
||||
local function ts(bit)
|
||||
if type(bit) ~= "table" then
|
||||
return tostring(bit)
|
||||
elseif getmetatable(bit) and bit.__tostring then
|
||||
return tostring(bit)
|
||||
elseif type(bit.GetLibraryVersion) == "function" then
|
||||
return bit:GetLibraryVersion()
|
||||
else
|
||||
return tostring(bit)
|
||||
end
|
||||
end
|
||||
local t = {}
|
||||
local function getcomplexuid(sc, ...)
|
||||
if sc then
|
||||
if sc.uid then
|
||||
table.insert(t, sc.uid)
|
||||
else
|
||||
AceOO:error("%s is not an appropriate class/mixin", ts(sc))
|
||||
end
|
||||
end
|
||||
for i = 1, select('#', ...) do
|
||||
local m = select(i, ...)
|
||||
if m.uid then
|
||||
table.insert(t, m.uid)
|
||||
else
|
||||
AceOO:error("%s is not an appropriate mixin", ts(m))
|
||||
end
|
||||
end
|
||||
table.sort(t)
|
||||
local uid = table.concat(t, '')
|
||||
local num = #t
|
||||
for i = 1, num do
|
||||
t[i] = nil
|
||||
end
|
||||
return uid
|
||||
end
|
||||
local classmeta
|
||||
local arg = {}
|
||||
function Classpool(superclass, ...)
|
||||
local l = getlibrary
|
||||
superclass = getlibrary(superclass)
|
||||
arg = { ... }
|
||||
for i, v in ipairs(arg) do
|
||||
arg[i] = getlibrary(v)
|
||||
end
|
||||
if superclass then
|
||||
if superclass.class then -- mixin
|
||||
table.insert(arg, 1, superclass)
|
||||
superclass = Class
|
||||
end
|
||||
else
|
||||
superclass = Class
|
||||
end
|
||||
local key = getcomplexuid(superclass, unpack(arg))
|
||||
if not pool[key] then
|
||||
local class = Class(superclass, unpack(arg))
|
||||
if not classmeta then
|
||||
classmeta = {}
|
||||
local mt = getmetatable(class)
|
||||
for k,v in pairs(mt) do
|
||||
classmeta[k] = v
|
||||
end
|
||||
classmeta.__newindex = newindex
|
||||
end
|
||||
-- Prevent the user from adding methods to this class.
|
||||
-- NOTE: I'm not preventing modifications of existing class members,
|
||||
-- but it's likely that only a truly malicious user will be doing so.
|
||||
class.sealed = true
|
||||
setmetatable(class, classmeta)
|
||||
getmetatable(class.prototype).__newindex = protonewindex
|
||||
pool[key] = class
|
||||
end
|
||||
return pool[key]
|
||||
end
|
||||
end
|
||||
|
||||
AceOO.Factory = Factory
|
||||
AceOO.Object = Object
|
||||
AceOO.Class = Class
|
||||
AceOO.Mixin = Mixin
|
||||
AceOO.Interface = Interface
|
||||
AceOO.Classpool = Classpool
|
||||
AceOO.inherits = inherits
|
||||
|
||||
-- Library handling bits
|
||||
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
AceOO = self
|
||||
Factory = self.Factory
|
||||
Object = self.Object
|
||||
Class = self.Class
|
||||
ClassFactory.prototype = Class
|
||||
Mixin = self.Mixin
|
||||
Interface = self.Interface
|
||||
Classpool = self.Classpool
|
||||
|
||||
if oldLib then
|
||||
self.classes = oldLib.classes
|
||||
end
|
||||
if not self.classes then
|
||||
self.classes = setmetatable({}, {__mode="k"})
|
||||
else
|
||||
for class in pairs(self.classes) do
|
||||
class.new = class_new
|
||||
end
|
||||
end
|
||||
|
||||
if oldDeactivate then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate)
|
||||
AceOO = AceLibrary(MAJOR_VERSION)
|
||||
@@ -0,0 +1,16 @@
|
||||
## Interface: 30300
|
||||
## X-Curse-Packaged-Version: r1101
|
||||
## X-Curse-Project-Name: Ace2
|
||||
## X-Curse-Project-ID: ace2
|
||||
## X-Curse-Repository-ID: wow/ace2/mainline
|
||||
|
||||
## Title: Lib: AceOO-2.0
|
||||
## Notes: AddOn development framework
|
||||
## Author: Ace Development Team
|
||||
## LoadOnDemand: 1
|
||||
## X-Website: http://www.wowace.com
|
||||
## X-Category: Library
|
||||
## X-License: LGPL v2.1 + MIT for AceOO-2.0
|
||||
## Dependencies: AceLibrary
|
||||
|
||||
AceOO-2.0.lua
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,799 @@
|
||||
--[[
|
||||
Name: AceLibrary
|
||||
Revision: $Rev: 1091 $
|
||||
Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
|
||||
Inspired By: Iriel (iriel@vigilance-committee.org)
|
||||
Tekkub (tekkub@gmail.com)
|
||||
Revision: $Rev: 1091 $
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceLibrary
|
||||
SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceLibrary
|
||||
Description: Versioning library to handle other library instances, upgrading,
|
||||
and proper access.
|
||||
It also provides a base for libraries to work off of, providing
|
||||
proper error tools. It is handy because all the errors occur in the
|
||||
file that called it, not in the library file itself.
|
||||
Dependencies: None
|
||||
License: LGPL v2.1
|
||||
]]
|
||||
|
||||
local ACELIBRARY_MAJOR = "AceLibrary"
|
||||
local ACELIBRARY_MINOR = 90000 + tonumber(("$Revision: 1091 $"):match("(%d+)"))
|
||||
|
||||
local _G = getfenv(0)
|
||||
local previous = _G[ACELIBRARY_MAJOR]
|
||||
if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
|
||||
|
||||
do
|
||||
-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
|
||||
-- LibStub is hereby placed in the Public Domain -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
|
||||
local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
|
||||
local LibStub = _G[LIBSTUB_MAJOR]
|
||||
|
||||
if not LibStub or LibStub.minor < LIBSTUB_MINOR then
|
||||
LibStub = LibStub or {libs = {}, minors = {} }
|
||||
_G[LIBSTUB_MAJOR] = LibStub
|
||||
LibStub.minor = LIBSTUB_MINOR
|
||||
|
||||
function LibStub:NewLibrary(major, minor)
|
||||
assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
|
||||
minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
|
||||
local oldminor = self.minors[major]
|
||||
if oldminor and oldminor >= minor then return nil end
|
||||
self.minors[major], self.libs[major] = minor, self.libs[major] or {}
|
||||
return self.libs[major], oldminor
|
||||
end
|
||||
|
||||
function LibStub:GetLibrary(major, silent)
|
||||
if not self.libs[major] and not silent then
|
||||
error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
|
||||
end
|
||||
return self.libs[major], self.minors[major]
|
||||
end
|
||||
|
||||
function LibStub:IterateLibraries() return pairs(self.libs) end
|
||||
setmetatable(LibStub, { __call = LibStub.GetLibrary })
|
||||
end
|
||||
end
|
||||
local LibStub = _G.LibStub
|
||||
|
||||
-- If you don't want AceLibrary to enable libraries that are LoadOnDemand but
|
||||
-- disabled in the addon screen, set this to true.
|
||||
local DONT_ENABLE_LIBRARIES = nil
|
||||
|
||||
local function safecall(func,...)
|
||||
local success, err = pcall(func,...)
|
||||
if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end
|
||||
end
|
||||
|
||||
-- @table AceLibrary
|
||||
-- @brief System to handle all versioning of libraries.
|
||||
local AceLibrary = {}
|
||||
local AceLibrary_mt = {}
|
||||
setmetatable(AceLibrary, AceLibrary_mt)
|
||||
|
||||
local function error(self, message, ...)
|
||||
if type(self) ~= "table" then
|
||||
return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2)
|
||||
end
|
||||
|
||||
local stack = debugstack()
|
||||
if not message then
|
||||
local second = stack:match("\n(.-)\n")
|
||||
message = "error raised! " .. second
|
||||
else
|
||||
local arg = { ... } -- not worried about table creation, as errors don't happen often
|
||||
|
||||
for i = 1, #arg do
|
||||
arg[i] = tostring(arg[i])
|
||||
end
|
||||
for i = 1, 10 do
|
||||
table.insert(arg, "nil")
|
||||
end
|
||||
message = message:format(unpack(arg))
|
||||
end
|
||||
|
||||
if getmetatable(self) and getmetatable(self).__tostring then
|
||||
message = ("%s: %s"):format(tostring(self), message)
|
||||
elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
|
||||
message = ("%s: %s"):format(self:GetLibraryVersion(), message)
|
||||
elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
|
||||
message = ("%s: %s"):format(self.class:GetLibraryVersion(), message)
|
||||
end
|
||||
|
||||
local first = stack:gsub("\n.*", "")
|
||||
local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1")
|
||||
file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
|
||||
|
||||
|
||||
local i = 0
|
||||
for s in stack:gmatch("\n([^\n]*)") do
|
||||
i = i + 1
|
||||
if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
|
||||
file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1")
|
||||
file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
|
||||
break
|
||||
end
|
||||
end
|
||||
local j = 0
|
||||
for s in stack:gmatch("\n([^\n]*)") do
|
||||
j = j + 1
|
||||
if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then
|
||||
return _G.error(message, j+1)
|
||||
end
|
||||
end
|
||||
return _G.error(message, 2)
|
||||
end
|
||||
|
||||
local type = type
|
||||
local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
|
||||
if type(num) ~= "number" then
|
||||
return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
|
||||
elseif type(kind) ~= "string" then
|
||||
return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind))
|
||||
end
|
||||
arg = type(arg)
|
||||
if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then
|
||||
local stack = debugstack()
|
||||
local func = stack:match("`argCheck'.-([`<].-['>])")
|
||||
if not func then
|
||||
func = stack:match("([`<].-['>])")
|
||||
end
|
||||
if kind5 then
|
||||
return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg)
|
||||
elseif kind4 then
|
||||
return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg)
|
||||
elseif kind3 then
|
||||
return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg)
|
||||
elseif kind2 then
|
||||
return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
|
||||
else
|
||||
return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local pcall
|
||||
do
|
||||
local function check(self, ret, ...)
|
||||
if not ret then
|
||||
local s = ...
|
||||
return error(self, (s:gsub(".-%.lua:%d-: ", "")))
|
||||
else
|
||||
return ...
|
||||
end
|
||||
end
|
||||
|
||||
function pcall(self, func, ...)
|
||||
return check(self, _G.pcall(func, ...))
|
||||
end
|
||||
end
|
||||
|
||||
local recurse = {}
|
||||
local function addToPositions(t, major)
|
||||
if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then
|
||||
rawset(t, recurse, true)
|
||||
AceLibrary.positions[t] = major
|
||||
for k,v in pairs(t) do
|
||||
if type(v) == "table" and not rawget(v, recurse) then
|
||||
addToPositions(v, major)
|
||||
end
|
||||
if type(k) == "table" and not rawget(k, recurse) then
|
||||
addToPositions(k, major)
|
||||
end
|
||||
end
|
||||
local mt = getmetatable(t)
|
||||
if mt and not rawget(mt, recurse) then
|
||||
addToPositions(mt, major)
|
||||
end
|
||||
rawset(t, recurse, nil)
|
||||
end
|
||||
end
|
||||
|
||||
local function svnRevisionToNumber(text)
|
||||
local kind = type(text)
|
||||
if kind == "number" or tonumber(text) then
|
||||
return tonumber(text)
|
||||
elseif kind == "string" then
|
||||
if text:find("^%$Revision: (%d+) %$$") then
|
||||
return tonumber((text:match("^%$Revision: (%d+) %$$")))
|
||||
elseif text:find("^%$Rev: (%d+) %$$") then
|
||||
return tonumber((text:match("^%$Rev: (%d+) %$$")))
|
||||
elseif text:find("^%$LastChangedRevision: (%d+) %$$") then
|
||||
return tonumber((text:match("^%$LastChangedRevision: (%d+) %$$")))
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local crawlReplace
|
||||
do
|
||||
local recurse = {}
|
||||
local function func(t, to, from)
|
||||
if recurse[t] then
|
||||
return
|
||||
end
|
||||
recurse[t] = true
|
||||
local mt = getmetatable(t)
|
||||
setmetatable(t, nil)
|
||||
rawset(t, to, rawget(t, from))
|
||||
rawset(t, from, nil)
|
||||
for k,v in pairs(t) do
|
||||
if v == from then
|
||||
t[k] = to
|
||||
elseif type(v) == "table" then
|
||||
if not recurse[v] then
|
||||
func(v, to, from)
|
||||
end
|
||||
end
|
||||
|
||||
if type(k) == "table" then
|
||||
if not recurse[k] then
|
||||
func(k, to, from)
|
||||
end
|
||||
end
|
||||
end
|
||||
setmetatable(t, mt)
|
||||
if mt then
|
||||
if mt == from then
|
||||
setmetatable(t, to)
|
||||
elseif not recurse[mt] then
|
||||
func(mt, to, from)
|
||||
end
|
||||
end
|
||||
end
|
||||
function crawlReplace(t, to, from)
|
||||
func(t, to, from)
|
||||
for k in pairs(recurse) do
|
||||
recurse[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @function destroyTable
|
||||
-- @brief remove all the contents of a table
|
||||
-- @param t table to destroy
|
||||
local function destroyTable(t)
|
||||
setmetatable(t, nil)
|
||||
for k,v in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function isFrame(frame)
|
||||
return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function"
|
||||
end
|
||||
|
||||
-- @function copyTable
|
||||
-- @brief Create a shallow copy of a table and return it.
|
||||
-- @param from The table to copy from
|
||||
-- @return A shallow copy of the table
|
||||
local function copyTable(from, to)
|
||||
if not to then
|
||||
to = {}
|
||||
end
|
||||
for k,v in pairs(from) do
|
||||
to[k] = v
|
||||
end
|
||||
setmetatable(to, getmetatable(from))
|
||||
return to
|
||||
end
|
||||
|
||||
-- @function deepTransfer
|
||||
-- @brief Fully transfer all data, keeping proper previous table
|
||||
-- backreferences stable.
|
||||
-- @param to The table with which data is to be injected into
|
||||
-- @param from The table whose data will be injected into the first
|
||||
-- @param saveFields If available, a shallow copy of the basic data is saved
|
||||
-- in here.
|
||||
-- @param list The account of table references
|
||||
-- @param list2 The current status on which tables have been traversed.
|
||||
local deepTransfer
|
||||
do
|
||||
-- @function examine
|
||||
-- @brief Take account of all the table references to be shared
|
||||
-- between the to and from tables.
|
||||
-- @param to The table with which data is to be injected into
|
||||
-- @param from The table whose data will be injected into the first
|
||||
-- @param list An account of the table references
|
||||
local function examine(to, from, list, major)
|
||||
list[from] = to
|
||||
for k,v in pairs(from) do
|
||||
if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then
|
||||
if from[k] == to[k] then
|
||||
list[from[k]] = to[k]
|
||||
elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then
|
||||
list[from[k]] = from[k]
|
||||
elseif not list[from[k]] then
|
||||
examine(to[k], from[k], list, major)
|
||||
end
|
||||
end
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
function deepTransfer(to, from, saveFields, major, list, list2)
|
||||
setmetatable(to, nil)
|
||||
if not list then
|
||||
list = {}
|
||||
list2 = {}
|
||||
examine(to, from, list, major)
|
||||
end
|
||||
list2[to] = to
|
||||
for k,v in pairs(to) do
|
||||
if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then
|
||||
if saveFields then
|
||||
saveFields[k] = v
|
||||
end
|
||||
to[k] = nil
|
||||
elseif v ~= _G then
|
||||
if saveFields then
|
||||
saveFields[k] = copyTable(v)
|
||||
end
|
||||
end
|
||||
end
|
||||
for k in pairs(from) do
|
||||
if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then
|
||||
if not list2[to[k]] then
|
||||
deepTransfer(to[k], from[k], nil, major, list, list2)
|
||||
end
|
||||
to[k] = list[to[k]] or list2[to[k]]
|
||||
else
|
||||
rawset(to, k, from[k])
|
||||
end
|
||||
end
|
||||
setmetatable(to, getmetatable(from))
|
||||
local mt = getmetatable(to)
|
||||
if mt then
|
||||
if list[mt] then
|
||||
setmetatable(to, list[mt])
|
||||
elseif mt.__index and list[mt.__index] then
|
||||
mt.__index = list[mt.__index]
|
||||
end
|
||||
end
|
||||
destroyTable(from)
|
||||
end
|
||||
end
|
||||
|
||||
local function TryToEnable(addon)
|
||||
if DONT_ENABLE_LIBRARIES then return end
|
||||
local isondemand = IsAddOnLoadOnDemand(addon)
|
||||
if isondemand then
|
||||
local _, _, _, enabled = GetAddOnInfo(addon)
|
||||
EnableAddOn(addon)
|
||||
local _, _, _, _, loadable = GetAddOnInfo(addon)
|
||||
if not loadable and not enabled then
|
||||
DisableAddOn(addon)
|
||||
end
|
||||
|
||||
return loadable
|
||||
end
|
||||
end
|
||||
|
||||
-- @method TryToLoadStandalone
|
||||
-- @brief Attempt to find and load a standalone version of the requested library
|
||||
-- @param major A string representing the major version
|
||||
-- @return If library is found and loaded, true is return. If not loadable, false is returned.
|
||||
-- If the library has been requested previously, nil is returned.
|
||||
local function TryToLoadStandalone(major)
|
||||
if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end
|
||||
if AceLibrary.scannedlibs[major] then return end
|
||||
|
||||
AceLibrary.scannedlibs[major] = true
|
||||
|
||||
local name, _, _, enabled, loadable = GetAddOnInfo(major)
|
||||
|
||||
loadable = (enabled and loadable) or TryToEnable(name)
|
||||
|
||||
local loaded = false
|
||||
if loadable then
|
||||
loaded = true
|
||||
LoadAddOn(name)
|
||||
end
|
||||
|
||||
local field = "X-AceLibrary-" .. major
|
||||
for i = 1, GetNumAddOns() do
|
||||
if GetAddOnMetadata(i, field) then
|
||||
name, _, _, enabled, loadable = GetAddOnInfo(i)
|
||||
|
||||
loadable = (enabled and loadable) or TryToEnable(name)
|
||||
if loadable then
|
||||
loaded = true
|
||||
LoadAddOn(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
return loaded
|
||||
end
|
||||
|
||||
-- @method IsNewVersion
|
||||
-- @brief Obtain whether the supplied version would be an upgrade to the
|
||||
-- current version. This allows for bypass code in library
|
||||
-- declaration.
|
||||
-- @param major A string representing the major version
|
||||
-- @param minor An integer or an svn revision string representing the minor version
|
||||
-- @return whether the supplied version would be newer than what is
|
||||
-- currently available.
|
||||
function AceLibrary:IsNewVersion(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
TryToLoadStandalone(major)
|
||||
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 3, "number")
|
||||
local lib, oldMinor = LibStub:GetLibrary(major, true)
|
||||
if lib then
|
||||
return oldMinor < minor
|
||||
end
|
||||
local data = self.libs[major]
|
||||
if not data then
|
||||
return true
|
||||
end
|
||||
return data.minor < minor
|
||||
end
|
||||
|
||||
-- @method HasInstance
|
||||
-- @brief Returns whether an instance exists. This allows for optional support of a library.
|
||||
-- @param major A string representing the major version.
|
||||
-- @param minor (optional) An integer or an svn revision string representing the minor version.
|
||||
-- @return Whether an instance exists.
|
||||
function AceLibrary:HasInstance(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
if minor ~= false then
|
||||
TryToLoadStandalone(major)
|
||||
end
|
||||
|
||||
local lib, ver = LibStub:GetLibrary(major, true)
|
||||
if not lib and self.libs[major] then
|
||||
lib, ver = self.libs[major].instance, self.libs[major].minor
|
||||
end
|
||||
if minor then
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 3, "number")
|
||||
if not lib then
|
||||
return false
|
||||
end
|
||||
return ver == minor
|
||||
end
|
||||
return not not lib
|
||||
end
|
||||
|
||||
-- @method GetInstance
|
||||
-- @brief Returns the library with the given major/minor version.
|
||||
-- @param major A string representing the major version.
|
||||
-- @param minor (optional) An integer or an svn revision string representing the minor version.
|
||||
-- @return The library with the given major/minor version.
|
||||
function AceLibrary:GetInstance(major, minor)
|
||||
argCheck(self, major, 2, "string")
|
||||
if minor ~= false then
|
||||
TryToLoadStandalone(major)
|
||||
end
|
||||
|
||||
local data, ver = LibStub:GetLibrary(major, true)
|
||||
if not data then
|
||||
if self.libs[major] then
|
||||
data, ver = self.libs[major].instance, self.libs[major].minor
|
||||
else
|
||||
_G.error(("Cannot find a library instance of %s."):format(major), 2)
|
||||
return
|
||||
end
|
||||
end
|
||||
if minor then
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 2, "number")
|
||||
if ver ~= minor then
|
||||
_G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2)
|
||||
end
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
-- Syntax sugar. AceLibrary("FooBar-1.0")
|
||||
AceLibrary_mt.__call = AceLibrary.GetInstance
|
||||
|
||||
local donothing = function() end
|
||||
|
||||
local AceEvent
|
||||
|
||||
local tmp = {}
|
||||
|
||||
-- @method Register
|
||||
-- @brief Registers a new version of a given library.
|
||||
-- @param newInstance the library to register
|
||||
-- @param major the major version of the library
|
||||
-- @param minor the minor version of the library
|
||||
-- @param activateFunc (optional) A function to be called when the library is
|
||||
-- fully activated. Takes the arguments
|
||||
-- (newInstance [, oldInstance, oldDeactivateFunc]). If
|
||||
-- oldInstance is given, you should probably call
|
||||
-- oldDeactivateFunc(oldInstance).
|
||||
-- @param deactivateFunc (optional) A function to be called by a newer library's
|
||||
-- activateFunc.
|
||||
-- @param externalFunc (optional) A function to be called whenever a new
|
||||
-- library is registered.
|
||||
function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc)
|
||||
argCheck(self, newInstance, 2, "table")
|
||||
argCheck(self, major, 3, "string")
|
||||
if major ~= ACELIBRARY_MAJOR then
|
||||
for k,v in pairs(_G) do
|
||||
if v == newInstance then
|
||||
geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k))
|
||||
end
|
||||
end
|
||||
end
|
||||
if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then
|
||||
_G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2)
|
||||
end
|
||||
if type(minor) == "string" then
|
||||
local m = svnRevisionToNumber(minor)
|
||||
if m then
|
||||
minor = m
|
||||
else
|
||||
_G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2)
|
||||
end
|
||||
end
|
||||
argCheck(self, minor, 4, "number")
|
||||
if math.floor(minor) ~= minor or minor < 0 then
|
||||
error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor)
|
||||
end
|
||||
argCheck(self, activateFunc, 5, "function", "nil")
|
||||
argCheck(self, deactivateFunc, 6, "function", "nil")
|
||||
argCheck(self, externalFunc, 7, "function", "nil")
|
||||
if not deactivateFunc then
|
||||
deactivateFunc = donothing
|
||||
end
|
||||
local data = self.libs[major]
|
||||
if not data then
|
||||
-- This is new
|
||||
if LibStub:GetLibrary(major, true) then
|
||||
error(self, "Cannot register library %q. It is already registered with LibStub.", major)
|
||||
end
|
||||
local instance = LibStub:NewLibrary(major, minor)
|
||||
copyTable(newInstance, instance)
|
||||
crawlReplace(instance, instance, newInstance)
|
||||
destroyTable(newInstance)
|
||||
if AceLibrary == newInstance then
|
||||
self = instance
|
||||
AceLibrary = instance
|
||||
end
|
||||
self.libs[major] = {
|
||||
instance = instance,
|
||||
minor = minor,
|
||||
deactivateFunc = deactivateFunc,
|
||||
externalFunc = externalFunc,
|
||||
}
|
||||
rawset(instance, 'GetLibraryVersion', function(self)
|
||||
return major, minor
|
||||
end)
|
||||
if not rawget(instance, 'error') then
|
||||
rawset(instance, 'error', error)
|
||||
end
|
||||
if not rawget(instance, 'argCheck') then
|
||||
rawset(instance, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(instance, 'pcall') then
|
||||
rawset(instance, 'pcall', pcall)
|
||||
end
|
||||
addToPositions(instance, major)
|
||||
if activateFunc then
|
||||
safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil
|
||||
end
|
||||
|
||||
if externalFunc then
|
||||
for k, data_instance in LibStub:IterateLibraries() do -- all libraries
|
||||
tmp[k] = data_instance
|
||||
end
|
||||
for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
|
||||
tmp[k] = data.instance
|
||||
end
|
||||
for k, data_instance in pairs(tmp) do
|
||||
if k ~= major then
|
||||
safecall(externalFunc, instance, k, data_instance)
|
||||
end
|
||||
tmp[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
for k,data in pairs(self.libs) do -- only Ace libraries
|
||||
if k ~= major and data.externalFunc then
|
||||
safecall(data.externalFunc, data.instance, major, instance)
|
||||
end
|
||||
end
|
||||
if major == "AceEvent-2.0" then
|
||||
AceEvent = instance
|
||||
end
|
||||
if AceEvent then
|
||||
AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance)
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
if minor <= data.minor then
|
||||
-- This one is already obsolete, raise an error.
|
||||
_G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2)
|
||||
return
|
||||
end
|
||||
local instance = data.instance
|
||||
-- This is an update
|
||||
local oldInstance = {}
|
||||
|
||||
local libStubInstance = LibStub:GetLibrary(major, true)
|
||||
if not libStubInstance then -- non-LibStub AceLibrary registered the library
|
||||
-- pass
|
||||
elseif libStubInstance ~= instance then
|
||||
error(self, "Cannot register library %q. It is already registered with LibStub.", major)
|
||||
else
|
||||
LibStub:NewLibrary(major, minor) -- upgrade the minor version
|
||||
end
|
||||
|
||||
addToPositions(newInstance, major)
|
||||
local isAceLibrary = (AceLibrary == newInstance)
|
||||
local old_error, old_argCheck, old_pcall
|
||||
if isAceLibrary then
|
||||
self = instance
|
||||
AceLibrary = instance
|
||||
|
||||
old_error = instance.error
|
||||
old_argCheck = instance.argCheck
|
||||
old_pcall = instance.pcall
|
||||
|
||||
self.error = error
|
||||
self.argCheck = argCheck
|
||||
self.pcall = pcall
|
||||
end
|
||||
deepTransfer(instance, newInstance, oldInstance, major)
|
||||
crawlReplace(instance, instance, newInstance)
|
||||
local oldDeactivateFunc = data.deactivateFunc
|
||||
data.minor = minor
|
||||
data.deactivateFunc = deactivateFunc
|
||||
data.externalFunc = externalFunc
|
||||
rawset(instance, 'GetLibraryVersion', function()
|
||||
return major, minor
|
||||
end)
|
||||
if not rawget(instance, 'error') then
|
||||
rawset(instance, 'error', error)
|
||||
end
|
||||
if not rawget(instance, 'argCheck') then
|
||||
rawset(instance, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(instance, 'pcall') then
|
||||
rawset(instance, 'pcall', pcall)
|
||||
end
|
||||
if isAceLibrary then
|
||||
for _,v in pairs(self.libs) do
|
||||
local i = type(v) == "table" and v.instance
|
||||
if type(i) == "table" then
|
||||
if not rawget(i, 'error') or i.error == old_error then
|
||||
rawset(i, 'error', error)
|
||||
end
|
||||
if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then
|
||||
rawset(i, 'argCheck', argCheck)
|
||||
end
|
||||
if not rawget(i, 'pcall') or i.pcall == old_pcall then
|
||||
rawset(i, 'pcall', pcall)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if activateFunc then
|
||||
safecall(activateFunc, instance, oldInstance, oldDeactivateFunc)
|
||||
else
|
||||
safecall(oldDeactivateFunc, oldInstance)
|
||||
end
|
||||
oldInstance = nil
|
||||
|
||||
if externalFunc then
|
||||
for k, data_instance in LibStub:IterateLibraries() do -- all libraries
|
||||
tmp[k] = data_instance
|
||||
end
|
||||
for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub
|
||||
tmp[k] = data.instance
|
||||
end
|
||||
for k, data_instance in pairs(tmp) do
|
||||
if k ~= major then
|
||||
safecall(externalFunc, instance, k, data_instance)
|
||||
end
|
||||
tmp[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
|
||||
function AceLibrary:IterateLibraries()
|
||||
local t = {}
|
||||
for major, instance in LibStub:IterateLibraries() do
|
||||
t[major] = instance
|
||||
end
|
||||
for major, data in pairs(self.libs) do
|
||||
t[major] = data.instance
|
||||
end
|
||||
return pairs(t)
|
||||
end
|
||||
|
||||
local function manuallyFinalize(major, instance)
|
||||
if AceLibrary.libs[major] then
|
||||
-- don't work on Ace libraries
|
||||
return
|
||||
end
|
||||
local finalizedExternalLibs = AceLibrary.finalizedExternalLibs
|
||||
if finalizedExternalLibs[major] then
|
||||
return
|
||||
end
|
||||
finalizedExternalLibs[major] = true
|
||||
|
||||
for k,data in pairs(AceLibrary.libs) do -- only Ace libraries
|
||||
if k ~= major and data.externalFunc then
|
||||
safecall(data.externalFunc, data.instance, major, instance)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- @function Activate
|
||||
-- @brief The activateFunc for AceLibrary itself. Called when
|
||||
-- AceLibrary properly registers.
|
||||
-- @param self Reference to AceLibrary
|
||||
-- @param oldLib (optional) Reference to an old version of AceLibrary
|
||||
-- @param oldDeactivate (optional) Function to deactivate the old lib
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
AceLibrary = self
|
||||
if not self.libs then
|
||||
self.libs = oldLib and oldLib.libs or {}
|
||||
self.scannedlibs = oldLib and oldLib.scannedlibs or {}
|
||||
end
|
||||
if not self.positions then
|
||||
self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" })
|
||||
end
|
||||
self.finalizedExternalLibs = oldLib and oldLib.finalizedExternalLibs or {}
|
||||
self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
|
||||
self.frame:UnregisterAllEvents()
|
||||
self.frame:RegisterEvent("ADDON_LOADED")
|
||||
self.frame:SetScript("OnEvent", function()
|
||||
for major, instance in LibStub:IterateLibraries() do
|
||||
manuallyFinalize(major, instance)
|
||||
end
|
||||
end)
|
||||
for major, instance in LibStub:IterateLibraries() do
|
||||
manuallyFinalize(major, instance)
|
||||
end
|
||||
|
||||
-- Expose the library in the global environment
|
||||
_G[ACELIBRARY_MAJOR] = self
|
||||
|
||||
if oldDeactivate then
|
||||
oldDeactivate(oldLib)
|
||||
end
|
||||
end
|
||||
|
||||
if not previous then
|
||||
previous = AceLibrary
|
||||
end
|
||||
if not previous.libs then
|
||||
previous.libs = {}
|
||||
end
|
||||
AceLibrary.libs = previous.libs
|
||||
if not previous.positions then
|
||||
previous.positions = setmetatable({}, { __mode = "k" })
|
||||
end
|
||||
AceLibrary.positions = previous.positions
|
||||
AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate, nil)
|
||||
@@ -0,0 +1,15 @@
|
||||
## Interface: 30300
|
||||
## X-Curse-Packaged-Version: r1101
|
||||
## X-Curse-Project-Name: Ace2
|
||||
## X-Curse-Project-ID: ace2
|
||||
## X-Curse-Repository-ID: wow/ace2/mainline
|
||||
|
||||
## Title: Lib: AceLibrary
|
||||
## Notes: AddOn development framework
|
||||
## Author: Ace Development Team
|
||||
## X-Website: http://www.wowace.com
|
||||
## X-Category: Library
|
||||
## X-License: LGPL v2.1 + MIT for AceOO-2.0
|
||||
|
||||
AceLibrary.lua
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
||||
ATLASLOOTFU_LEFTCLICK = "|cff1eff00Left-Click|r Browse Loot Tables";
|
||||
ATLASLOOTFU_SHIFTCLICK = "|cffff0000Shift-Click|r View Options";
|
||||
ATLASLOOTFU_LEFTDRAG = "|cffccccccLeft-Click + Drag|r Move Minimap Button";
|
||||
|
||||
if (GetLocale() == "deDE") then
|
||||
ATLASLOOTFU_LEFTCLICK = "|cff1eff00Linksklick|r Loot-Tabellen durchsuchen";
|
||||
ATLASLOOTFU_SHIFTCLICK = "|cffff0000Shift-Klick|r Optionen anzeigen";
|
||||
ATLASLOOTFU_LEFTDRAG = "|cffccccccLinksklick + Ziehen|r Minimap-Button bewegen";
|
||||
end
|
||||
|
||||
if (GetLocale() == "frFR") then
|
||||
ATLASLOOTFU_LEFTCLICK = "|cff1eff00Clic-Gauche|r Parcourir les tables de butin";
|
||||
ATLASLOOTFU_SHIFTCLICK = "|cffff0000Shift-Clic|r Affiche les Options";
|
||||
ATLASLOOTFU_LEFTDRAG = "|cffccccccClic-Gauche + Maintenir|r Déplacer l'icone de la minimap";
|
||||
end
|
||||
|
||||
if (GetLocale() == "ruRU") then
|
||||
ATLASLOOTFU_LEFTCLICK = "|cff1eff00Левый-Клик|r обзор таблици добычи";
|
||||
ATLASLOOTFU_SHIFTCLICK = "|cffff0000Shift-Клик|r настройки";
|
||||
ATLASLOOTFU_LEFTDRAG = "|cffccccccЛевый-Клик + тащить|r перемещение кнопки";
|
||||
end
|
||||
|
||||
if (GetLocale() == "zhTW") then
|
||||
ATLASLOOTFU_LEFTCLICK = "|cff1eff00左鍵|r 瀏覽物品掉落表格";
|
||||
ATLASLOOTFU_SHIFTCLICK = "|cffff0000Shift-點擊|r 查看選項";
|
||||
ATLASLOOTFU_LEFTDRAG = "|cffcccccc右鍵 + 拖曳|r 移動小地圖按鈕";
|
||||
end
|
||||
|
||||
if (GetLocale() == "zhCN") then
|
||||
ATLASLOOTFU_LEFTCLICK = "|cff1eff00左键|r 浏览物品掉落表格";
|
||||
ATLASLOOTFU_SHIFTCLICK = "|cffff0000Shift-点击|r 查看选项";
|
||||
ATLASLOOTFU_LEFTDRAG = "|cffcccccc右键 + 拖曳|r 移动小地图按钮";
|
||||
end
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
|
||||
..\FrameXML\UI.xsd">
|
||||
|
||||
<Script file="Libs\AceLibrary\AceLibrary.lua"/>
|
||||
<Script file="Libs\AceOO-2.0\AceOO-2.0.lua"/>
|
||||
<Script file="Libs\AceAddon-2.0\AceAddon-2.0.lua"/>
|
||||
<Script file="Libs\AceEvent-2.0\AceEvent-2.0.lua"/>
|
||||
<Script file="Libs\AceDB-2.0\AceDB-2.0.lua"/>
|
||||
|
||||
<Script file="Libs\FuBarPlugin-2.0\FuBarPlugin-2.0.lua"/>
|
||||
|
||||
<Script file="Libs\Tablet-2.0\Tablet-2.0.lua"/>
|
||||
|
||||
</Ui>
|
||||
Reference in New Issue
Block a user