Add files via upload
This commit is contained in:
+1249
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
## Interface: 20003
|
||||
## Author: Thrae
|
||||
## Title: VitalWatch |cff7fff7f -Ace2-|r
|
||||
## Notes: A powerfully customizable health, mana, and aggro alert system for solo, group, and raid.
|
||||
## SavedVariables: VitalWatchDB
|
||||
## SavedVariablesPerCharacter: VitalWatchCharDB
|
||||
libs\AceLibrary\AceLibrary.lua
|
||||
libs\AceOO-2.0\AceOO-2.0.lua
|
||||
libs\AceEvent-2.0\AceEvent-2.0.lua
|
||||
libs\AceDB-2.0\AceDB-2.0.lua
|
||||
libs\AceAddon-2.0\AceAddon-2.0.lua
|
||||
libs\Dewdrop-2.0\Dewdrop-2.0.lua
|
||||
libs\Tablet-2.0\Tablet-2.0.lua
|
||||
libs\FuBarPlugin-2.0\FuBarPlugin-2.0.lua
|
||||
libs\Roster-2.1\Roster-2.1.lua
|
||||
libs\Banzai-1.1\Banzai-1.1.lua
|
||||
|
||||
VitalWatchLocale_enEN.lua
|
||||
VitalWatch.lua
|
||||
@@ -0,0 +1,41 @@
|
||||
--[[ VitalWatch by Thrae
|
||||
--
|
||||
--
|
||||
-- English Localization (Default)
|
||||
--
|
||||
-- VitalWatchLocale should be defined in your FIRST localization
|
||||
-- code.
|
||||
--
|
||||
--]]
|
||||
|
||||
VitalWatchLocale = {}
|
||||
VitalWatchLocale.locale = getglobal("GetLocale")()
|
||||
|
||||
if VitalWatchLocale.locale then
|
||||
VitalWatchLocale.LogTitle = "VitalWatch Log"
|
||||
|
||||
VitalWatchLocale.Floating_Message_Self_LowHealth = "Your health is low!"
|
||||
VitalWatchLocale.Floating_Message_Self_CritHealth = "Your health is CRITICAL!"
|
||||
VitalWatchLocale.Floating_Message_Self_LowMana = "Your mana is low!"
|
||||
VitalWatchLocale.Floating_Message_Self_CritMana = "Your mana is CRITICAL!"
|
||||
|
||||
VitalWatchLocale.Floating_Message_LowHealth = "'s health is low!"
|
||||
VitalWatchLocale.Floating_Message_CritHealth = "'s health is CRITICAL!"
|
||||
VitalWatchLocale.Floating_Message_LowMana = "'s mana is low!"
|
||||
VitalWatchLocale.Floating_Message_CritMana = "'s mana is CRITICAL!"
|
||||
|
||||
VitalWatchLocale.Floating_Message_Aggro = "AGGRO: "
|
||||
VitalWatchLocale.Floating_Message_AggroLost = "Lost aggro."
|
||||
|
||||
VitalWatchLocale.MyPetTag = " (my pet)"
|
||||
VitalWatchLocale.PetTag = " (pet)"
|
||||
|
||||
VitalWatchLocale.DEFAULT_MsgCritHealth = "My health is CRITICAL!"
|
||||
|
||||
-- Below are voice emotes for your locale. On an English client, you
|
||||
-- would type in /oom to announce to everyone you're out of mana. To
|
||||
-- properly translate, you must find out the command for your locale.
|
||||
VitalWatchLocale.DEFAULT_EmoteCritMana = "/oom"
|
||||
|
||||
VitalWatchLocale.locale = nil -- we no longer need this
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,702 @@
|
||||
--[[
|
||||
Name: AceLibrary
|
||||
Revision: $Rev: 23383 $
|
||||
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: 23383 $
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/index.php/AceLibrary
|
||||
SVN: http://svn.wowace.com/root/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 = "$Revision: 23383 $"
|
||||
|
||||
local _G = getfenv(0)
|
||||
local previous = _G[ACELIBRARY_MAJOR]
|
||||
if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
|
||||
|
||||
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:find("\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 function assert(self, condition, message, ...)
|
||||
if not condition then
|
||||
if not message then
|
||||
local stack = debugstack()
|
||||
local _,_,second = stack:find("\n(.-)\n")
|
||||
message = "assertion failed! " .. second
|
||||
end
|
||||
return error(self, message, ...)
|
||||
end
|
||||
return condition
|
||||
end
|
||||
|
||||
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
|
||||
local errored = false
|
||||
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:find("`argCheck'.-([`<].-['>])")
|
||||
if not func then
|
||||
_,_,func = stack:find("([`<].-['>])")
|
||||
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)
|
||||
if type(text) == "string" then
|
||||
if text:find("^%$Revision: (%d+) %$$") then
|
||||
return tonumber((text:gsub("^%$Revision: (%d+) %$$", "%1")))
|
||||
elseif text:find("^%$Rev: (%d+) %$$") then
|
||||
return tonumber((text:gsub("^%$Rev: (%d+) %$$", "%1")))
|
||||
elseif text:find("^%$LastChangedRevision: (%d+) %$$") then
|
||||
return tonumber((text:gsub("^%$LastChangedRevision: (%d+) %$$", "%1")))
|
||||
end
|
||||
elseif type(text) == "number" then
|
||||
return text
|
||||
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)
|
||||
local to = {}
|
||||
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
|
||||
|
||||
-- @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, return values from the call to LoadAddOn are 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)
|
||||
if loadable then
|
||||
return LoadAddOn(name)
|
||||
end
|
||||
|
||||
for i=1,GetNumAddOns() do
|
||||
if GetAddOnMetadata(i, "X-AceLibrary-"..major) then
|
||||
local name, _, _, enabled, loadable = GetAddOnInfo(i)
|
||||
if loadable then
|
||||
return LoadAddOn(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
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 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")
|
||||
TryToLoadStandalone(major)
|
||||
|
||||
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 self.libs[major] then
|
||||
return
|
||||
end
|
||||
return self.libs[major].minor == minor
|
||||
end
|
||||
return self.libs[major] and true
|
||||
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")
|
||||
TryToLoadStandalone(major)
|
||||
|
||||
local data = self.libs[major]
|
||||
if not data then
|
||||
_G.error(("Cannot find a library instance of %s."):format(major), 2)
|
||||
return
|
||||
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 data.minor ~= minor then
|
||||
_G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2)
|
||||
end
|
||||
end
|
||||
return data.instance
|
||||
end
|
||||
|
||||
-- Syntax sugar. AceLibrary("FooBar-1.0")
|
||||
AceLibrary_mt.__call = AceLibrary.GetInstance
|
||||
|
||||
local donothing = function() end
|
||||
|
||||
local AceEvent
|
||||
|
||||
-- @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
|
||||
local instance = copyTable(newInstance)
|
||||
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, 'assert') then
|
||||
rawset(instance, 'assert', assert)
|
||||
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
|
||||
|
||||
--[[ if major ~= ACELIBRARY_MAJOR then
|
||||
for k,v in pairs(_G) do
|
||||
if v == instance 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]]
|
||||
end
|
||||
|
||||
if externalFunc then
|
||||
for k,data in pairs(self.libs) do
|
||||
if k ~= major then
|
||||
safecall(externalFunc, instance, k, data.instance)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k,data in pairs(self.libs) do
|
||||
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
|
||||
local instance = data.instance
|
||||
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
|
||||
-- This is an update
|
||||
local oldInstance = {}
|
||||
|
||||
addToPositions(newInstance, major)
|
||||
local isAceLibrary = (AceLibrary == newInstance)
|
||||
local old_error, old_assert, old_argCheck, old_pcall
|
||||
if isAceLibrary then
|
||||
self = instance
|
||||
AceLibrary = instance
|
||||
|
||||
old_error = instance.error
|
||||
old_assert = instance.assert
|
||||
old_argCheck = instance.argCheck
|
||||
old_pcall = instance.pcall
|
||||
|
||||
self.error = error
|
||||
self.assert = assert
|
||||
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(self)
|
||||
return major, minor
|
||||
end)
|
||||
if not rawget(instance, 'error') then
|
||||
rawset(instance, 'error', error)
|
||||
end
|
||||
if not rawget(instance, 'assert') then
|
||||
rawset(instance, 'assert', assert)
|
||||
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, 'assert') or i.assert == old_assert then
|
||||
rawset(i, 'assert', assert)
|
||||
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)
|
||||
|
||||
--[[ if major ~= ACELIBRARY_MAJOR then
|
||||
for k,v in pairs(_G) do
|
||||
if v == instance 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]]
|
||||
else
|
||||
safecall(oldDeactivateFunc, oldInstance)
|
||||
end
|
||||
oldInstance = nil
|
||||
|
||||
if externalFunc then
|
||||
for k,data in pairs(self.libs) do
|
||||
if k ~= major then
|
||||
safecall(externalFunc, instance, k, data.instance)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return instance
|
||||
end
|
||||
|
||||
local iter
|
||||
function AceLibrary:IterateLibraries()
|
||||
if not iter then
|
||||
local function iter(t, k)
|
||||
k = next(t, k)
|
||||
if not k then
|
||||
return nil
|
||||
else
|
||||
return k, t[k].instance
|
||||
end
|
||||
end
|
||||
end
|
||||
return iter, self.libs, nil
|
||||
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
|
||||
|
||||
-- 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)
|
||||
@@ -0,0 +1,986 @@
|
||||
--[[
|
||||
Name: AceOO-2.0
|
||||
Revision: $Rev: 23383 $
|
||||
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/root/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 = "$Revision: 23383 $"
|
||||
|
||||
-- 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 pad(cap)
|
||||
return ("0"):rep(8 - cap:len()) .. cap
|
||||
end
|
||||
local function getuid(t)
|
||||
local mt = getmetatable(t)
|
||||
setmetatable(t, nil)
|
||||
local str = tostring(t)
|
||||
setmetatable(t, mt)
|
||||
local cap = str:match("[^:]*: 0x(.*)$")
|
||||
if not cap then
|
||||
cap = str:match("[^:]*: (.*)$")
|
||||
end
|
||||
if cap then
|
||||
return pad(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,217 @@
|
||||
--[[
|
||||
Name: Banzai-1.1
|
||||
Revision: $Rev: 21576 $
|
||||
Author(s): Rabbit (rabbit.magtheridon@gmail.com), maia
|
||||
Documentation: http://www.wowace.com/index.php/Banzai-1.1_API_Documentation
|
||||
SVN: http://svn.wowace.com/wowace/trunk/BanzaiLib/Banzai-1.1
|
||||
Description: Aggro notification library.
|
||||
Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, Roster-2.1
|
||||
]]
|
||||
|
||||
--[[
|
||||
BanzaiLib is copyrighted 2006 by Rabbit.
|
||||
|
||||
This addon is distributed under the terms of the Creative Commons
|
||||
Attribution-NonCommercial-ShareAlike 2.0 license.
|
||||
|
||||
http://creativecommons.org/licenses/by-nc-sa/2.5/
|
||||
|
||||
You may distribute and use these libraries without making your mod adhere to the
|
||||
same license, as long as you preserve the license text embedded in the
|
||||
libraries.
|
||||
|
||||
Any and all questions regarding our stance and licensing should be
|
||||
directed to the #wowace IRC channel on irc.freenode.net.
|
||||
]]
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Locals
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local MAJOR_VERSION = "Banzai-1.1"
|
||||
local MINOR_VERSION = "$Revision: 21576 $"
|
||||
|
||||
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
|
||||
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
|
||||
|
||||
if AceLibrary:HasInstance("Banzai-1.0") then error(MAJOR_VERSION .. " can't run alongside Banzai-1.0.") end
|
||||
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end
|
||||
if not AceLibrary:HasInstance("AceEvent-2.0") then error(MAJOR_VERSION .. " requires AceEvent-2.0.") end
|
||||
if not AceLibrary:HasInstance("Roster-2.1") then error(MAJOR_VERSION .. " requires Roster-2.1.") end
|
||||
|
||||
local lib = {}
|
||||
AceLibrary("AceEvent-2.0"):embed(lib)
|
||||
|
||||
local RL = nil
|
||||
local roster = nil
|
||||
local playerName = nil
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Local heap
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local new, del
|
||||
do
|
||||
local cache = setmetatable({},{__mode='k'})
|
||||
function new()
|
||||
local t = next(cache)
|
||||
if t then
|
||||
cache[t] = nil
|
||||
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
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Initialization
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-- Activate a new instance of this library
|
||||
function activate(self, oldLib, oldDeactivate)
|
||||
if oldLib then
|
||||
self.vars = oldLib.vars
|
||||
if oldLib:IsEventScheduled("UpdateAggroList") then
|
||||
oldLib:CancelScheduledEvent("UpdateAggroList")
|
||||
self:StartOrStop()
|
||||
end
|
||||
else
|
||||
self.vars = {}
|
||||
end
|
||||
|
||||
RL = AceLibrary("Roster-2.1")
|
||||
roster = RL.roster
|
||||
playerName = UnitName("player")
|
||||
|
||||
if not self.vars then self.vars = {} end
|
||||
|
||||
self:RegisterEvent("AceEvent_EventRegistered", "StartOrStop")
|
||||
self:RegisterEvent("AceEvent_EventUnregistered", "StartOrStop")
|
||||
|
||||
if oldDeactivate then oldDeactivate(oldLib) end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Events
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function lib:StartOrStop()
|
||||
local aceEvent = AceLibrary("AceEvent-2.0")
|
||||
if aceEvent:IsEventRegistered("Banzai_UnitGainedAggro") or
|
||||
aceEvent:IsEventRegistered("Banzai_PlayerGainedAggro") or
|
||||
aceEvent:IsEventRegistered("Banzai_UnitLostAggro") or
|
||||
aceEvent:IsEventRegistered("Banzai_PlayerLostAggro") or
|
||||
aceEvent:IsEventRegistered("Banzai_Run") then
|
||||
if not self:IsEventScheduled("UpdateAggroList") then
|
||||
self:ScheduleRepeatingEvent("UpdateAggroList", self.UpdateAggroList, 0.2, self)
|
||||
self.vars.running = true
|
||||
self:TriggerEvent("Banzai_Enabled")
|
||||
end
|
||||
elseif self:IsEventRegistered("UpdateAggroList") then
|
||||
self:CancelScheduledEvent("UpdateAggroList")
|
||||
for i, unit in pairs(roster) do
|
||||
unit.banzai = nil
|
||||
unit.banzaiModifier = nil
|
||||
end
|
||||
self.vars.running = nil
|
||||
self:TriggerEvent("Banzai_Disabled")
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Library
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function lib:UpdateAggroList()
|
||||
local oldBanzai = nil
|
||||
|
||||
for name, unit in pairs(roster) do
|
||||
if not oldBanzai then oldBanzai = new() end
|
||||
oldBanzai[name] = unit.banzai
|
||||
|
||||
-- deduct aggro for all, increase it later for everyone with aggro
|
||||
if not unit.banzaiModifier then unit.banzaiModifier = 0 end
|
||||
unit.banzaiModifier = math.max(0, unit.banzaiModifier - 5)
|
||||
|
||||
-- check for aggro
|
||||
local targetId = unit.unitid .. "target"
|
||||
if UnitExists(targetId) and UnitExists(targetId .. "target") then
|
||||
local targetName = UnitName(targetId .. "target")
|
||||
if roster[targetName] and UnitCanAttack("player", targetId) and UnitCanAttack(targetId, "player") then
|
||||
if not roster[targetName].banzaiModifier then roster[targetName].banzaiModifier = 0 end
|
||||
roster[targetName].banzaiModifier = roster[targetName].banzaiModifier + 10
|
||||
if not roster[targetName].banzaiTarget then roster[targetName].banzaiTarget = new() end
|
||||
table.insert(roster[targetName].banzaiTarget, targetId)
|
||||
end
|
||||
end
|
||||
|
||||
-- cleanup
|
||||
unit.banzaiModifier = math.max(0, unit.banzaiModifier)
|
||||
unit.banzaiModifier = math.min(25, unit.banzaiModifier)
|
||||
|
||||
-- set aggro
|
||||
unit.banzai = (unit.banzaiModifier > 15)
|
||||
end
|
||||
|
||||
for name, unit in pairs(roster) do
|
||||
if oldBanzai[name] ~= nil and oldBanzai[name] ~= unit.banzai then
|
||||
-- Aggro status has changed.
|
||||
if unit.banzai == true and unit.banzaiTarget then
|
||||
-- Unit has aggro
|
||||
self:TriggerEvent("Banzai_UnitGainedAggro", unit.unitid, unit.banzaiTarget)
|
||||
if name == playerName then
|
||||
self:TriggerEvent("Banzai_PlayerGainedAggro", unit.banzaiTarget)
|
||||
end
|
||||
elseif unit.banzai == false then
|
||||
-- Unit lost aggro
|
||||
self:TriggerEvent("Banzai_UnitLostAggro", unit.unitid)
|
||||
if name == playerName then
|
||||
self:TriggerEvent("Banzai_PlayerLostAggro", unit.unitid)
|
||||
end
|
||||
end
|
||||
end
|
||||
if unit.banzaiTarget then
|
||||
unit.banzaiTarget = del(unit.banzaiTarget)
|
||||
end
|
||||
end
|
||||
|
||||
if oldBanzai then
|
||||
oldBanzai = del(oldBanzai)
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- API
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function lib:GetUnitAggroByUnitId( unitId )
|
||||
if not self.vars.running then error(MAJOR_VERSION.." is not running. You must register for one of the events.") end
|
||||
local rosterUnit = RL:GetUnitObjectFromUnit(unitId)
|
||||
if not rosterUnit then return nil end
|
||||
return rosterUnit.banzai
|
||||
end
|
||||
|
||||
function lib:GetUnitAggroByUnitName( unitName )
|
||||
if not self.vars.running then error(MAJOR_VERSION.." is not running. You must register for one of the events.") end
|
||||
local rosterUnit = RL:GetUnitObjectFromName(unitName)
|
||||
if not rosterUnit then return nil end
|
||||
return rosterUnit.banzai
|
||||
end
|
||||
|
||||
function lib:IsRunning()
|
||||
return self:IsEventScheduled("UpdateAggroList")
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Register
|
||||
-------------------------------------------------------------------------------
|
||||
AceLibrary:Register(lib, MAJOR_VERSION, MINOR_VERSION, activate)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,425 @@
|
||||
--[[
|
||||
Name: Roster-2.1
|
||||
Revision: $Revision: 21071 $
|
||||
X-ReleaseDate: $Date: 2006-12-17 13:56:50 -0500 (Sun, 17 Dec 2006) $
|
||||
Author: Maia (maia.proudmoore@gmail.com)
|
||||
Website: http://www.wowace.com/
|
||||
Documentation: http://www.wowace.com/wiki/Roster-2.1
|
||||
SVN: http://svn.wowace.com/wowace/trunk/RosterLib/
|
||||
Description: Party/raid roster management
|
||||
Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0
|
||||
]]
|
||||
|
||||
local MAJOR_VERSION = "Roster-2.1"
|
||||
local MINOR_VERSION = "$Revision: 21071 $"
|
||||
|
||||
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
|
||||
if not AceLibrary:HasInstance("AceEvent-2.0") then error(MAJOR_VERSION .. " requires AceEvent-2.0") end
|
||||
|
||||
local unknownUnits = {}
|
||||
local Lib = {}
|
||||
local roster
|
||||
local new, del
|
||||
do
|
||||
local cache = setmetatable({}, {__mode='k'})
|
||||
function new()
|
||||
local t = next(cache)
|
||||
if t then
|
||||
cache[t] = nil
|
||||
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
|
||||
|
||||
------------------------------------------------
|
||||
-- activate, enable, disable
|
||||
------------------------------------------------
|
||||
|
||||
local function activate(self, oldLib, oldDeactivate)
|
||||
if oldLib then
|
||||
if oldLib.roster then self.roster = oldLib.roster end
|
||||
oldLib:UnregisterAllEvents()
|
||||
oldLib:CancelAllScheduledEvents()
|
||||
end
|
||||
if not self.roster then self.roster = {} end
|
||||
if oldDeactivate then oldDeactivate(oldLib) end
|
||||
roster = self.roster
|
||||
end
|
||||
|
||||
|
||||
local function external(self, major, instance)
|
||||
if major == "AceEvent-2.0" then
|
||||
instance:embed(self)
|
||||
if instance:IsFullyInitialized() then
|
||||
self:AceEvent_FullyInitialized()
|
||||
else
|
||||
self:RegisterEvent("AceEvent_FullyInitialized")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------
|
||||
-- Internal functions
|
||||
------------------------------------------------
|
||||
|
||||
function Lib:AceEvent_FullyInitialized()
|
||||
self:TriggerEvent("RosterLib_Enabled")
|
||||
|
||||
self:RegisterBucketEvent({"RAID_ROSTER_UPDATE", "PARTY_MEMBERS_CHANGED"}, 0.2, "ScanFullRoster")
|
||||
self:RegisterBucketEvent("UNIT_PET", 0.2, "ScanPet")
|
||||
|
||||
self:ScanFullRoster()
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------
|
||||
-- Unit iterator
|
||||
------------------------------------------------
|
||||
|
||||
local UnitIterator
|
||||
do
|
||||
local rmem, pmem, step, count
|
||||
local function SelfIterator()
|
||||
while step do
|
||||
local unit
|
||||
if step == 1 then
|
||||
-- STEP 1: player
|
||||
unit = "player"
|
||||
step = 2
|
||||
elseif step == 2 then
|
||||
-- STEP 2: pet
|
||||
unit = "pet"
|
||||
step = nil
|
||||
end
|
||||
if unit and UnitExists(unit) then return unit end
|
||||
end
|
||||
end
|
||||
|
||||
local function SelfAndPartyIterator()
|
||||
while step do
|
||||
local unit
|
||||
if step <= 2 then
|
||||
unit = SelfIterator()
|
||||
if not step then step = 3 end
|
||||
elseif step == 3 then
|
||||
-- STEP 3: party units
|
||||
unit = string.format("party%d", count)
|
||||
step = 4
|
||||
elseif step == 4 then
|
||||
-- STEP 4: party pets
|
||||
unit = string.format("partypet%d", count)
|
||||
count = count + 1
|
||||
step = count <= pmem and 3 or nil
|
||||
end
|
||||
if unit and UnitExists(unit) then return unit end
|
||||
end
|
||||
end
|
||||
|
||||
local function RaidIterator()
|
||||
while step do
|
||||
local unit
|
||||
if step == 1 then
|
||||
-- STEP 1: raid units
|
||||
unit = string.format("raid%d", count)
|
||||
step = 2
|
||||
elseif step == 2 then
|
||||
-- STEP 2: raid pets
|
||||
unit = string.format("raidpet%d", count)
|
||||
count = count + 1
|
||||
step = count <= rmem and 1 or nil
|
||||
end
|
||||
if unit and UnitExists(unit) then return unit end
|
||||
end
|
||||
end
|
||||
|
||||
function UnitIterator()
|
||||
rmem = GetNumRaidMembers()
|
||||
step = 1
|
||||
if rmem == 0 then
|
||||
pmem = GetNumPartyMembers()
|
||||
if pmem == 0 then
|
||||
return SelfIterator, false
|
||||
else
|
||||
count = 1
|
||||
return SelfAndPartyIterator, false
|
||||
end
|
||||
else
|
||||
count = 1
|
||||
return RaidIterator, true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------
|
||||
-- Roster code
|
||||
------------------------------------------------
|
||||
|
||||
local rosterScanCache = {}
|
||||
function Lib:ScanFullRoster()
|
||||
local changed
|
||||
local it, isInRaid = UnitIterator()
|
||||
-- save all units we currently have, this way we can check who to remove from roster later.
|
||||
for name in pairs(roster) do
|
||||
rosterScanCache[name] = true
|
||||
end
|
||||
-- update data
|
||||
for unitid in it do
|
||||
local name = self:CreateOrUpdateUnit(unitid, isInRaid)
|
||||
-- we successfully added a unit, so we don't need to remove it next step
|
||||
if name then
|
||||
rosterScanCache[name] = nil
|
||||
changed = true
|
||||
end
|
||||
end
|
||||
-- clear units we had in roster that either left the raid or are unknown for some reason.
|
||||
for name in pairs(rosterScanCache) do
|
||||
self:RemoveUnit(name)
|
||||
rosterScanCache[name] = nil
|
||||
changed = true
|
||||
end
|
||||
self:ProcessRoster()
|
||||
if changed then
|
||||
self:TriggerEvent("RosterLib_RosterUpdated")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function Lib:ScanPet(owner_list)
|
||||
local changed
|
||||
for owner in pairs(owner_list) do
|
||||
local unitid = self:GetPetFromOwner(owner)
|
||||
if not unitid then return end
|
||||
|
||||
if not UnitExists(unitid) then
|
||||
unknownUnits[unitid] = nil
|
||||
-- find the pet in the roster we need to delete
|
||||
for _,u in pairs(roster) do
|
||||
if u.unitid == unitid then
|
||||
self:RemoveUnit(u.name)
|
||||
changed = true
|
||||
end
|
||||
end
|
||||
else
|
||||
_, changed = self:CreateOrUpdateUnit(unitid)
|
||||
end
|
||||
self:ProcessRoster()
|
||||
end
|
||||
if changed then
|
||||
self:TriggerEvent("RosterLib_RosterUpdated")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Lib:GetPetFromOwner(id)
|
||||
-- convert party3 crap to raid IDs when in raid.
|
||||
local owner = self:GetUnitIDFromUnit(id)
|
||||
if not owner then return end
|
||||
|
||||
-- get ID
|
||||
if owner:find("raid") then
|
||||
return owner:gsub("raid", "raidpet")
|
||||
elseif owner:find("party") then
|
||||
return owner:gsub("party", "partypet")
|
||||
elseif owner == "player" then
|
||||
return "pet"
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Lib:ScanUnknownUnits()
|
||||
local changed
|
||||
for unitid in pairs(unknownUnits) do
|
||||
local name, c
|
||||
if UnitExists(unitid) then
|
||||
name, c = self:CreateOrUpdateUnit(unitid)
|
||||
else
|
||||
unknownUnits[unitid] = nil
|
||||
end
|
||||
-- some pets never have a name. too bad for them, farewell!
|
||||
if not name and unitid:find("pet") then
|
||||
unknownUnits[unitid] = nil
|
||||
else
|
||||
changed = changed or c
|
||||
end
|
||||
end
|
||||
self:ProcessRoster()
|
||||
if changed then
|
||||
self:TriggerEvent("RosterLib_RosterUpdated")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Lib:ProcessRoster()
|
||||
if next(unknownUnits, nil) then
|
||||
self:CancelScheduledEvent("ScanUnknownUnits")
|
||||
self:ScheduleEvent("ScanUnknownUnits", self.ScanUnknownUnits, 1, self)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Lib:CreateOrUpdateUnit(unitid, isInRaid)
|
||||
-- check for name
|
||||
local name = UnitName(unitid)
|
||||
if name and name ~= UNKNOWNOBJECT and name ~= UKNOWNBEING and not UnitIsCharmed(unitid) then
|
||||
local unit = roster[name]
|
||||
local isPet = unitid:find("pet")
|
||||
|
||||
-- clear stuff
|
||||
unknownUnits[unitid] = nil
|
||||
-- return if a pet attempts to replace a player name
|
||||
-- this doesnt fix the problem with 2 pets overwriting each other FIXME
|
||||
if isPet and unit and unit.class ~= "PET" then
|
||||
return name
|
||||
end
|
||||
-- save old data if existing
|
||||
local old_name, old_unitid, old_class, old_rank, old_subgroup, old_online
|
||||
if unit then
|
||||
old_name = unit.name
|
||||
old_unitid = unit.unitid
|
||||
old_class = unit.class
|
||||
old_rank = unit.rank
|
||||
old_subgroup = unit.subgroup
|
||||
old_online = unit.online
|
||||
else
|
||||
-- object
|
||||
unit = new()
|
||||
roster[name] = unit
|
||||
end
|
||||
|
||||
local new_name, new_unitid, new_class, new_rank, new_subgroup, new_online
|
||||
|
||||
-- name
|
||||
new_name = name
|
||||
-- unitid
|
||||
new_unitid = unitid
|
||||
-- class
|
||||
if isPet then
|
||||
new_class = "PET"
|
||||
else
|
||||
_, new_class = UnitClass(unitid)
|
||||
end
|
||||
if isInRaid == nil and GetNumRaidMembers() > 0 then
|
||||
isInRaid = true
|
||||
end
|
||||
|
||||
-- subgroup and rank
|
||||
new_subgroup = 1
|
||||
new_rank = 0 -- XXX Support party leader?
|
||||
if isInRaid then
|
||||
local _,_,num = unitid:find("(%d+)")
|
||||
if num then
|
||||
_, new_rank, new_subgroup = GetRaidRosterInfo(num)
|
||||
end
|
||||
end
|
||||
-- online/offline status
|
||||
new_online = UnitIsConnected(unitid)
|
||||
|
||||
-- compare data
|
||||
if not old_name
|
||||
or new_name ~= old_name
|
||||
or new_unitid ~= old_unitid
|
||||
or new_class ~= old_class
|
||||
or new_subgroup ~= old_subgroup
|
||||
or new_rank ~= old_rank
|
||||
or new_online ~= old_online
|
||||
then
|
||||
unit.name = new_name
|
||||
unit.unitid = new_unitid
|
||||
unit.class = new_class
|
||||
unit.subgroup = new_subgroup
|
||||
unit.rank = new_rank
|
||||
unit.online = new_online
|
||||
self:TriggerEvent("RosterLib_UnitChanged",
|
||||
new_unitid, new_name, new_class, new_subgroup, new_rank,
|
||||
old_name, old_unitid, old_class, old_subgroup, old_rank)
|
||||
return name, true
|
||||
end
|
||||
return name
|
||||
else
|
||||
unknownUnits[unitid] = true
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Lib:RemoveUnit(name)
|
||||
local r = roster[name]
|
||||
roster[name] = nil
|
||||
self:TriggerEvent("RosterLib_UnitChanged",
|
||||
nil, nil, nil, nil, nil,
|
||||
r.name, r.unitid, r.class, r.subgroup, r.rank)
|
||||
r = del(r)
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------
|
||||
-- API
|
||||
------------------------------------------------
|
||||
|
||||
function Lib:GetUnitIDFromName(name)
|
||||
if roster[name] then
|
||||
return roster[name].unitid
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Lib:GetUnitIDFromUnit(unit)
|
||||
local name = UnitName(unit)
|
||||
if name and roster[name] then
|
||||
return roster[name].unitid
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function Lib:GetUnitObjectFromName(name)
|
||||
return roster[name]
|
||||
end
|
||||
|
||||
|
||||
function Lib:GetUnitObjectFromUnit(unit)
|
||||
local name = UnitName(unit)
|
||||
return roster[name]
|
||||
end
|
||||
|
||||
|
||||
local function iter(t)
|
||||
local key = t.key
|
||||
local pets = t.pets
|
||||
repeat
|
||||
key = next(roster, key)
|
||||
if not key then
|
||||
t = del(t)
|
||||
return nil
|
||||
end
|
||||
until (pets or roster[key].class ~= "PET")
|
||||
t.key = key
|
||||
return roster[key]
|
||||
end
|
||||
|
||||
function Lib:IterateRoster(pets)
|
||||
local t = new()
|
||||
t.pets = pets
|
||||
return iter, t
|
||||
end
|
||||
|
||||
AceLibrary:Register(Lib, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user