Add aggro border and high damage flash

Finally added the ace library bloat
This commit is contained in:
OldManAlpha 2024-12-15 15:34:31 -08:00
parent 29ba027d88
commit d4eee5cfd4
18 changed files with 8518 additions and 9 deletions

View File

@ -140,6 +140,11 @@ function StartsWith(str, starts)
return string.sub(str, 1, string.len(starts)) == starts
end
function RoundNumber(number, decimalPlaces)
decimalPlaces = decimalPlaces or 0
return math.floor(number * 10^decimalPlaces + 0.5) / 10^decimalPlaces
end
-- Courtesy of ChatGPT
function InterpolateColors(colors, t)
local numColors = table.getn(colors)

View File

@ -23,6 +23,12 @@ HealUI.scrollingHealFrame = nil -- Unimplemented
HealUI.auraIconPool = {} -- map: {"frame", "icon", "stackText"}
HealUI.auraIcons = {} -- map: {"frame", "icon", "stackText"}
HealUI.aggroBorder = nil
HealUI.flashTexture = nil -- {"frame", "texture"}
HealUI.flashTime = 0
HealUI.lastHealthPercent = 0
HealUI.incomingHealing = 0
HealUI.hovered = false
@ -217,6 +223,36 @@ function HealUI:UpdateOpacity()
self.container:SetAlpha(alpha)
end
function HealUI:SetAggroBorderEnabled(enabled)
if enabled then
self.aggroBorder:Show()
else
self.aggroBorder:Hide()
end
end
function HealUI:Flash()
local FLASH_TIME = 0.15
local START_OPACITY = self:GetProfile().FlashOpacity / 100
self.flashTime = FLASH_TIME
local frame = self.flashTexture.frame
frame:Show()
frame:SetAlpha(START_OPACITY)
if not frame:GetScript("OnUpdate") then
frame:SetScript("OnUpdate", function()
self.flashTime = self.flashTime - arg1
frame:SetAlpha(START_OPACITY - (((FLASH_TIME - self.flashTime) / FLASH_TIME) * START_OPACITY))
if self.flashTime <= 0 then
frame:Hide()
frame:SetScript("OnUpdate", nil)
end
end)
end
end
function HealUI:GetCurrentHealth()
if self:IsFake() then
if not self.fakeStats.online then
@ -256,7 +292,8 @@ function HealUI:ShouldShowMissingHealth()
end
local missingHealth = self:GetMaxHealth() - currentHealth
return (missingHealth > 0 or profile.AlwaysShowMissingHealth) and profile.MissingHealthDisplay ~= "Hidden"
and (profile.ShowEnemyMissingHealth or not self:IsEnemy()) and not UnitIsGhost(self.unit)
and (profile.ShowEnemyMissingHealth or not self:IsEnemy())
and not UnitIsGhost(self.unit) and (UnitIsConnected(self.unit) or self:IsFake())
end
function HealUI.GetColorizedText(color, class, theText)
@ -327,7 +364,8 @@ function HealUI:UpdateHealth()
local text = util.Colorize("DEAD", 1, 0.3, 0.3)
-- Check for Feign Death so the healer doesn't get alarmed
if util.IsFeigning(unit) then
local feign = util.IsFeigning(unit)
if feign then
text = "Feign"
end
@ -335,6 +373,12 @@ function HealUI:UpdateHealth()
missingHealthText:SetText("")
self.healthBar:SetValue(0)
self.powerBar:SetValue(0)
if self.lastHealthPercent > 0 and not self:IsEnemy() then
if not feign then
self:Flash()
end
self.lastHealthPercent = 0
end
elseif UnitIsGhost(unit) then
healthText:SetText(util.Colorize("Ghost", 1, 0.3, 0.3))
missingHealthText:SetText("")
@ -378,6 +422,12 @@ function HealUI:UpdateHealth()
missingHealthText:SetText(missingText)
self.healthBar:SetValue(currentHealth / maxHealth)
local healthPercent = (currentHealth / maxHealth) * 100
if healthPercent < self.lastHealthPercent - profile.FlashThreshold and not self:IsEnemy() then
self:Flash()
end
self.lastHealthPercent = healthPercent
end
self:UpdateOpacity()
@ -858,6 +908,20 @@ function HealUI:Initialize()
self.auraPanel = buffPanel
buffPanel:SetFrameLevel(container:GetFrameLevel() + 2)
local aggroBorder = CreateFrame("Frame", "$parentAggroBorder", container)
self.aggroBorder = aggroBorder
aggroBorder:SetBackdrop({edgeFile = "Interface\\Buttons\\WHITE8X8", edgeSize = profile.AggroBorder.Thickness})
aggroBorder:SetBackdropBorderColor(1, 0, 0, 0.75)
aggroBorder:SetFrameLevel(container:GetFrameLevel() + 10)
aggroBorder:Hide()
local flashFrame = CreateFrame("Frame", "$parentFlash", container)
flashFrame:SetFrameLevel(container:GetFrameLevel() + 9)
local flashTexture = flashFrame:CreateTexture(nil, "OVERLAY")
self.flashTexture = {frame = flashFrame, texture = flashTexture}
flashTexture:SetTexture(1, 1, 1)
flashFrame:Hide()
--[[
local scrollingDamageFrame = CreateFrame("Frame", unit.."ScrollingDamageFrame", container)
self.scrollingDamageFrame = scrollingDamageFrame
@ -947,6 +1011,11 @@ function HealUI:SizeElements()
local auraPanel = self.auraPanel
self:UpdateComponent(auraPanel, profile.AuraTracker)
self:UpdateComponent(self.aggroBorder, profile.AggroBorder)
self:UpdateComponent(self.flashTexture.frame, profile.Flash)
self.flashTexture.texture:SetAllPoints(self.flashTexture.frame)
rootContainer:SetHeight(self:GetHeight())
overlayContainer:SetHeight(self:GetHeight())
container:SetHeight(self:GetHeight())
@ -1002,8 +1071,8 @@ function HealUI:UpdateComponent(component, props, xOffset, yOffset)
component:SetJustifyH(props.AlignmentH)
component:SetJustifyV(props.AlignmentV)
else
component:SetWidth(props.Width == "Anchor" and anchor:GetWidth() or props.Width)
component:SetHeight(props.Height == "Anchor" and anchor:GetHeight() or props.Height)
component:SetWidth(props:GetWidth(self))
component:SetHeight(props:GetHeight(self))
end
local alignment = alignmentAnchorMap[props.AlignmentH][props.AlignmentV]
component:SetPoint(alignment, anchor, alignment, props:GetOffsetX() + xOffset, props:GetOffsetY() + yOffset)

View File

@ -77,6 +77,8 @@ SlashCmdList["HEALERSMATE"] = function(args)
end
end
HealersMateLib = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0")
Banzai = AceLibrary("Banzai-1.0")
HealersMate = {}
local _G = getfenv(0)
setmetatable(HealersMate, {__index = getfenv(1)})
@ -624,6 +626,12 @@ function UpdateAllIncomingHealing()
end
end
function UpdateAllAggro()
for unit, ui in pairs(HealUIs) do
ui:SetAggroBorderEnabled(Banzai:GetUnitAggroByUnitId(unit))
end
end
local function createUIGroup(groupName, environment, units, petGroup, profile)
local uiGroup = HealUIGroup:New(groupName, environment, units, petGroup, profile)
for _, unit in ipairs(units) do
@ -708,6 +716,17 @@ function EventAddonLoaded()
initUIs()
HealersMateLib:RegisterEvent("Banzai_UnitGainedAggro", function(unit)
if HealUIs[unit] then
HealUIs[unit]:SetAggroBorderEnabled(true)
end
end)
HealersMateLib:RegisterEvent("Banzai_UnitLostAggro", function(unit)
if HealUIs[unit] then
HealUIs[unit]:SetAggroBorderEnabled(false)
end
end)
if HMOnLoadInfoDisabled == nil then
HMOnLoadInfoDisabled = false
end
@ -1134,6 +1153,7 @@ function CheckGroup()
if superwow then
HMHealPredict.SetRelevantGUIDs(util.ToArray(GUIDUnitMap))
end
UpdateAllAggro()
end
@ -1208,9 +1228,12 @@ function EventHandler()
HealUIGroups["Target"]:Hide()
local friendly = not UnitCanAttack("player", "target")
if (friendly and HMOptions.ShowTargets.Friendly) or (not friendly and HMOptions.ShowTargets.Hostile) then
local ui = HealUIs["target"]
ui.lastHealthPercent = (ui:GetCurrentHealth() / ui:GetMaxHealth()) * 100
ui:CheckRange()
ui:CheckSight()
ui:UpdateRole()
HealUIGroups["Target"]:Show()
HealUIs["target"]:CheckRange()
HealUIs["target"]:CheckSight()
if guid then -- If the guid isn't nil, then SuperWoW is present
for guidInMap, units in pairs(GUIDUnitMap) do
@ -1228,9 +1251,8 @@ function EventHandler()
end
table.insert(GUIDUnitMap[guid], "target")
HMHealPredict.SetRelevantGUIDs(util.ToArray(GUIDUnitMap))
HealUIs["target"].incomingHealing = HMHealPredict.GetIncomingHealing(guid)
HealUIs["target"]:UpdateHealth()
HealUIs["target"]:UpdateRole()
ui.incomingHealing = HMHealPredict.GetIncomingHealing(guid)
ui:UpdateHealth()
end
end
else

View File

@ -6,6 +6,20 @@
## SavedVariables: HMOnLoadInfoDisabled, HMHealCache, HMPlayerHealCache, HMRoleCache
## SavedVariablesPerCharacter: HMSpells, HMOptions
libs\ace\AceLibrary\AceLibrary.lua
libs\ace\AceLocale-2.2\AceLocale-2.2.lua
libs\ace\AceOO-2.0\AceOO-2.0.lua
libs\ace\AceDebug-2.0\AceDebug-2.0.lua
libs\ace\AceAddon-2.0\AceAddon-2.0.lua
libs\ace\AceConsole-2.0\AceConsole-2.0.lua
libs\ace\AceEvent-2.0\AceEvent-2.0.lua
libs\ace\AceHook-2.1\AceHook-2.1.lua
libs\ace\Compost-2.0\Compost-2.0.lua
libs\ace\Gratuity-2.0\Gratuity-2.0.lua
libs\ace\RosterLib-2.0\RosterLib-2.0.lua
libs\ace\Deformat-2.0\Deformat-2.0.lua
libs\ace\Banzai-1.0\Banzai-1.0.lua
HMUtil.lua
HealUI.lua
HealUIGroup.lua

View File

@ -25,6 +25,12 @@ function HMUIProfile.CreatePositionedObject()
obj.OffsetY = 0
obj.Anchor = "Health Bar" -- Health Bar, Power Bar, Button, Container
obj.Opacity = 100
obj.GetWidth = function(self, ui)
return (self.Width ~= "Anchor" and self.Width or self:GetAnchorComponent(ui):GetWidth()) + (self.Width2 or 0)
end
obj.GetHeight = function(self, ui)
return (self.Height ~= "Anchor" and self.Height or self:GetAnchorComponent(ui):GetHeight()) + (self.Height2 or 0)
end
obj.GetOffsetX = function(self)
if self.AlignmentH == "LEFT" then
return self.PaddingH + self.OffsetX
@ -202,6 +208,23 @@ function HMUIProfile.SetDefaults()
profile.TrackedAurasSpacing = 2
profile.TrackedAurasAlignment = "TOP"
profile.AggroBorder = createSizedObject({
["Height"] = "Anchor",
["Width"] = "Anchor",
["Height2"] = 2,
["Width2"] = 2,
["Anchor"] = "Button",
["Thickness"] = 2
})
profile.Flash = createSizedObject({
["Height"] = "Anchor",
["Width"] = "Anchor",
["Anchor"] = "Health Bar"
})
profile.FlashThreshold = 25
profile.FlashOpacity = 70
profile.MaxUnitsInAxis = 5
profile.Orientation = "Vertical" --"Vertical", "Horizontal"
profile.HorizontalSpacing = 1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,242 @@
--[[
Name: AceDebug-2.0
Revision: $Rev: 99999 $
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/AceDebug-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceDebug-2.0
Description: Mixin to allow for simple debugging capabilities.
Dependencies: AceLibrary, AceOO-2.0
]]
local MAJOR_VERSION = "AceDebug-2.0"
local MINOR_VERSION = "$Revision: 99999 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
local DEBUGGING, TOGGLE_DEBUGGING
if GetLocale() == "frFR" then
DEBUGGING = "D\195\169boguage"
TOGGLE_DEBUGGING = "Activer/d\195\169sactiver le d\195\169boguage"
elseif GetLocale() == "deDE" then
DEBUGGING = "Debuggen"
TOGGLE_DEBUGGING = "Aktiviert/Deaktiviert Debugging"
elseif GetLocale() == "koKR" then
DEBUGGING = "디버깅"
TOGGLE_DEBUGGING = "디버깅 기능 사용함/사용안함"
elseif GetLocale() == "zhTW" then
DEBUGGING = "除錯"
TOGGLE_DEBUGGING = "啟用/停用除錯功能"
elseif GetLocale() == "zhCN" then
DEBUGGING = "\232\176\131\232\175\149"
TOGGLE_DEBUGGING = "\229\144\175\231\148\168/\231\166\129\231\148\168 \232\176\131\232\175\149"
elseif GetLocale() == "ruRU" then
DEBUGGING = "Отладка"
TOGGLE_DEBUGGING = "Вкл./Выкл. отладку для этого аддона."
else -- enUS
DEBUGGING = "Debugging"
TOGGLE_DEBUGGING = "Enable/disable debugging"
end
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
local math_mod = math.mod or math.fmod
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local AceDebug = AceOO.Mixin {"Debug", "CustomDebug", "IsDebugging", "SetDebugging", "SetDebugLevel", "LevelDebug", "CustomLevelDebug", "GetDebugLevel"}
local function print(text, r, g, b, frame, delay)
(frame or DEFAULT_CHAT_FRAME):AddMessage(text, r, g, b, 1, delay or 5)
end
local tmp
function AceDebug:CustomDebug(r, g, b, frame, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not self.debugging then return end
local output = string.format("|cff7fff7f(DEBUG) %s:[%s%3d]|r", tostring(self), date("%H:%M:%S"), math_mod(GetTime(), 1) * 1000)
if string.find(tostring(a1), "%%") then
output = output .. " " .. string.format(tostring(a1), tostring(a2), tostring(a3), tostring(a4), tostring(a5), tostring(a6), tostring(a7), tostring(a8), tostring(a9), tostring(a10), tostring(a11), tostring(a12), tostring(a13), tostring(a14), tostring(a15), tostring(a16), tostring(a17), tostring(a18), tostring(a19), tostring(a20))
else
if not tmp then
tmp = {}
end
-- This block dynamically rebuilds the tmp array stopping on the first nil.
table.insert(tmp, output)
table.insert(tmp, tostring(a1))
table.insert(tmp, a2)
table.insert(tmp, a3)
table.insert(tmp, a4)
table.insert(tmp, a5)
table.insert(tmp, a6)
table.insert(tmp, a7)
table.insert(tmp, a8)
table.insert(tmp, a9)
table.insert(tmp, a10)
table.insert(tmp, a11)
table.insert(tmp, a12)
table.insert(tmp, a13)
table.insert(tmp, a14)
table.insert(tmp, a15)
table.insert(tmp, a16)
table.insert(tmp, a17)
table.insert(tmp, a18)
table.insert(tmp, a19)
table.insert(tmp, a20)
while tmp[table.getn(tmp)] == nil do
table.remove(tmp)
end
for k = 1, table.getn(tmp) do
tmp[k] = tostring(tmp[k])
end
output = table.concat(tmp, " ")
for k,v in pairs(tmp) do
tmp[k] = nil
end
table_setn(tmp, 0)
end
print(output, r, g, b, frame or self.debugFrame, delay)
end
function AceDebug:Debug(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
AceDebug.CustomDebug(self, nil, nil, nil, nil, nil, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
function AceDebug:IsDebugging()
return self.debugging
end
function AceDebug:SetDebugging(debugging)
self.debugging = debugging
end
-- Takes a number 1-3
-- Level 1: Critical messages that every user should receive
-- Level 2: Should be used for local debugging (function calls, etc)
-- Level 3: Very verbose debugging, will dump everything and anything
-- If set to nil, you will receive no debug information
function AceDebug:SetDebugLevel(level)
AceDebug:argCheck(level, 1, "number", "nil")
if not level then
self.debuglevel = nil
return
end
if level < 1 or level > 3 then
AceDebug:error("Bad argument #1 to `SetDebugLevel`, must be a number 1-3")
end
self.debuglevel = level
end
function AceDebug:GetDebugLevel()
return self.debuglevel
end
function AceDebug:CustomLevelDebug(level, r, g, b, frame, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not self.debugging or not self.debuglevel then return end
AceDebug:argCheck(level, 1, "number")
if level < 1 or level > 3 then
AceDebug:error("Bad argument #1 to `LevelDebug`, must be a number 1-3")
end
if level > self.debuglevel then return end
local output = string.format("|cff7fff7f(DEBUG) %s:[%s.%3d]|r", tostring(self), date("%H:%M:%S"), math_mod(GetTime(), 1) * 1000)
if string.find(tostring(a1), "%%") then
output = output .. " " .. string.format(tostring(a1), tostring(a2), tostring(a3), tostring(a4), tostring(a5), tostring(a6), tostring(a7), tostring(a8), tostring(a9), tostring(a10), tostring(a11), tostring(a12), tostring(a13), tostring(a14), tostring(a15), tostring(a16), tostring(a17), tostring(a18), tostring(a19), tostring(a20))
else
if not tmp then
tmp = {}
end
-- This block dynamically rebuilds the tmp array stopping on the first nil.
table.insert(tmp, output)
table.insert(tmp, tostring(a1))
table.insert(tmp, a2)
table.insert(tmp, a3)
table.insert(tmp, a4)
table.insert(tmp, a5)
table.insert(tmp, a6)
table.insert(tmp, a7)
table.insert(tmp, a8)
table.insert(tmp, a9)
table.insert(tmp, a10)
table.insert(tmp, a11)
table.insert(tmp, a12)
table.insert(tmp, a13)
table.insert(tmp, a14)
table.insert(tmp, a15)
table.insert(tmp, a16)
table.insert(tmp, a17)
table.insert(tmp, a18)
table.insert(tmp, a19)
table.insert(tmp, a20)
while tmp[table.getn(tmp)] == nil do
table.remove(tmp)
end
for k = 1, table.getn(tmp) do
tmp[k] = tostring(tmp[k])
end
output = table.concat(tmp, " ")
for k,v in pairs(tmp) do
tmp[k] = nil
end
table_setn(tmp, 0)
end
print(output, r, g, b, frame or self.debugFrame, delay)
end
function AceDebug:LevelDebug(level, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not self.debugging or not self.debuglevel then return end
AceDebug:argCheck(level, 1, "number")
if level < 1 or level > 3 then
AceDebug:error("Bad argument #1 to `LevelDebug`, must be a number 1-3")
end
if level > self.debuglevel then return end
AceDebug.CustomLevelDebug(self, level, nil, nil, nil, nil, nil, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
local options
function AceDebug:GetAceOptionsDataTable(target)
if not options then
options = {
debug = {
name = DEBUGGING,
desc = TOGGLE_DEBUGGING,
type = "toggle",
get = "IsDebugging",
set = "SetDebugging",
order = -2,
}
}
end
return options
end
AceLibrary:Register(AceDebug, MAJOR_VERSION, MINOR_VERSION, AceDebug.activate)
AceDebug = AceLibrary(MAJOR_VERSION)

View File

@ -0,0 +1,970 @@
--[[
Name: AceEvent-2.0
Revision: $Rev: 17638 $
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/root/trunk/Ace2/AceEvent-2.0
Description: Mixin to allow for event handling, scheduling, and inter-addon
communication.
Dependencies: AceLibrary, AceOO-2.0
]]
local MAJOR_VERSION = "AceEvent-2.0"
local MINOR_VERSION = "$Revision: 17638 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
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",
}
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
local weakKey = {__mode="k"}
local new, del
do
local list = setmetatable({}, weakKey)
function new()
local t = next(list)
if t then
list[t] = nil
return t
else
return {}
end
end
function del(t)
setmetatable(t, nil)
for k in pairs(t) do
t[k] = nil
end
list[t] = true
end
end
local FAKE_NIL
local RATE
local eventsWhichHappenOnce = {
PLAYER_LOGIN = true,
AceEvent_FullyInitialized = true,
VARIABLES_LOADED = true,
PLAYER_LOGOUT = true,
}
local registeringFromAceEvent
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 = new()
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 = new()
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] = del(AceEvent_throttleRegistry[event][self])
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] = del(AceEvent_throttleRegistry[event][self])
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
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
AceEvent_registry[ALL_EVENTS][self] = method
end
local _G = getfenv(0)
local memstack, timestack = {}, {}
local memdiff, timediff
function AceEvent:TriggerEvent(event, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
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 _G_event = _G.event
_G.event = event
local lastEvent = AceEvent.currentEvent
AceEvent.currentEvent = event
local AceEvent_onceRegistry = AceEvent.onceRegistry
local AceEvent_debugTable = AceEvent.debugTable
if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
local tmp = new()
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 mem, time
if AceEvent_debugTable then
if not AceEvent_debugTable[event] then
AceEvent_debugTable[event] = new()
end
if not AceEvent_debugTable[event][obj] then
AceEvent_debugTable[event][obj] = new()
AceEvent_debugTable[event][obj].mem = 0
AceEvent_debugTable[event][obj].time = 0
AceEvent_debugTable[event][obj].count = 0
end
if memdiff then
table.insert(memstack, memdiff)
table.insert(timestack, timediff)
end
memdiff, timediff = 0, 0
mem, time = gcinfo(), GetTime()
end
local method = tmp[obj]
AceEvent.UnregisterEvent(obj, event)
if type(method) == "string" then
local obj_method = obj[method]
if obj_method then
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
elseif method then -- function
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
if AceEvent_debugTable then
local dmem, dtime = memdiff, timediff
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
memdiff, timediff = table.remove(memstack), table.remove(timestack)
if memdiff then
memdiff = memdiff + mem + dmem
timediff = timediff + time + dtime
end
end
tmp[obj] = nil
obj = next(tmp)
end
del(tmp)
end
local AceEvent_throttleRegistry = AceEvent.throttleRegistry
local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
if AceEvent_registry[event] then
local tmp = new()
for obj, method in pairs(AceEvent_registry[event]) do
tmp[obj] = method
end
local obj = next(tmp)
while obj do
local method = tmp[obj]
local continue = false
if throttleTable and throttleTable[obj] then
local a1 = 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
continue = true
end
end
if not continue then
local mem, time
if AceEvent_debugTable then
if not AceEvent_debugTable[event] then
AceEvent_debugTable[event] = new()
end
if not AceEvent_debugTable[event][obj] then
AceEvent_debugTable[event][obj] = new()
AceEvent_debugTable[event][obj].mem = 0
AceEvent_debugTable[event][obj].time = 0
AceEvent_debugTable[event][obj].count = 0
end
if memdiff then
table.insert(memstack, memdiff)
table.insert(timestack, timediff)
end
memdiff, timediff = 0, 0
mem, time = gcinfo(), GetTime()
end
if type(method) == "string" then
local obj_method = obj[method]
if obj_method then
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
elseif method then -- function
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
if AceEvent_debugTable then
local dmem, dtime = memdiff, timediff
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
memdiff, timediff = table.remove(memstack), table.remove(timestack)
if memdiff then
memdiff = memdiff + mem + dmem
timediff = timediff + time + dtime
end
end
end
tmp[obj] = nil
obj = next(tmp)
end
del(tmp)
end
if AceEvent_registry[ALL_EVENTS] then
local tmp = new()
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 mem, time
if AceEvent_debugTable then
if not AceEvent_debugTable[event] then
AceEvent_debugTable[event] = new()
end
if not AceEvent_debugTable[event][obj] then
AceEvent_debugTable[event][obj] = new()
AceEvent_debugTable[event][obj].mem = 0
AceEvent_debugTable[event][obj].time = 0
AceEvent_debugTable[event][obj].count = 0
end
if memdiff then
table.insert(memstack, memdiff)
table.insert(timestack, timediff)
end
memdiff, timediff = 0, 0
mem, time = gcinfo(), GetTime()
end
if type(method) == "string" then
local obj_method = obj[method]
if obj_method then
obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
elseif method then -- function
method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
if AceEvent_debugTable then
local dmem, dtime = memdiff, timediff
mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
memdiff, timediff = table.remove(memstack), table.remove(timestack)
if memdiff then
memdiff = memdiff + mem + dmem
timediff = timediff + time + dtime
end
end
tmp[obj] = nil
obj = next(tmp)
end
del(tmp)
end
_G.event = _G_event
AceEvent.currentEvent = lastEvent
end
-- local accessors
local getn = table.getn
local tinsert = table.insert
local tremove = table.remove
local floor = math.floor
local GetTime = GetTime
local next = next
local pairs = pairs
local unpack = unpack
local delayRegistry
local tmp = {}
local function OnUpdate()
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] = del(v)
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 mem, time
if AceEvent_debugTable then
mem, time = gcinfo(), GetTime()
end
if type(event) == "function" then
event(unpack(v))
else
AceEvent:TriggerEvent(event, unpack(v))
end
if AceEvent_debugTable then
mem, time = gcinfo() - mem, GetTime() - time
v.mem = v.mem + mem
v.timeSpent = v.timeSpent + time
v.count = v.count + 1
end
if not v_repeatDelay then
local x = delayRegistry[k]
if x and x.time == v_time then -- check if it was manually reset
delayRegistry[k] = del(v)
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
local function ScheduleEvent(self, repeating, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
local id
if type(event) == "string" or type(event) == "table" then
if type(event) == "table" then
if not delayRegistry or not delayRegistry[event] then
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
end
end
if type(delay) ~= "number" then
id, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
AceEvent:argCheck(delay, 4, "number")
self:CancelScheduledEvent(id)
end
else
AceEvent:argCheck(event, 2, "string", "function")
AceEvent:argCheck(delay, 3, "number")
end
if not delayRegistry then
AceEvent.delayRegistry = new()
delayRegistry = AceEvent.delayRegistry
AceEvent.frame:SetScript("OnUpdate", OnUpdate)
end
local t
if type(id) == "table" then
for k in pairs(id) do
id[k] = nil
end
t = id
else
t = new()
end
t[1] = a1
t[2] = a2
t[3] = a3
t[4] = a4
t[5] = a5
t[6] = a6
t[7] = a7
t[8] = a8
t[9] = a9
t[10] = a10
t[11] = a11
t[12] = a12
t[13] = a13
t[14] = a14
t[15] = a15
t[16] = a16
t[17] = a17
t[18] = a18
t[19] = a19
t[20] = a20
table_setn(t, 20)
t.event = event
t.time = GetTime() + delay
t.self = self
t.id = id or t
t.repeatDelay = repeating and delay
if AceEvent_debugTable then
t.mem = 0
t.count = 0
t.timeSpent = 0
end
delayRegistry[t.id] = t
AceEvent.frame:Show()
return t.id
end
function AceEvent:ScheduleEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if type(event) == "string" or type(event) == "table" then
if type(event) == "table" then
if not delayRegistry or not delayRegistry[event] then
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
end
end
if type(delay) ~= "number" then
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
AceEvent:argCheck(a1, 4, "number")
end
else
AceEvent:argCheck(event, 2, "string", "function")
AceEvent:argCheck(delay, 3, "number")
end
return ScheduleEvent(self, false, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
function AceEvent:ScheduleRepeatingEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if type(event) == "string" or type(event) == "table" then
if type(event) == "table" then
if not delayRegistry or not delayRegistry[event] then
AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
end
end
if type(delay) ~= "number" then
AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
AceEvent:argCheck(a1, 4, "number")
end
else
AceEvent:argCheck(event, 2, "string", "function")
AceEvent:argCheck(delay, 3, "number")
end
return ScheduleEvent(self, true, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
end
function AceEvent:CancelScheduledEvent(t)
AceEvent:argCheck(t, 2, "string", "table")
if delayRegistry then
local v = delayRegistry[t]
if v then
delayRegistry[t] = del(v)
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", "table")
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] = del(AceEvent_throttleRegistry[event][self])
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(string.format("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0.", 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
del(AceEvent_registry[ALL_EVENTS])
AceEvent.frame:UnregisterAllEvents()
for k,v in pairs(AceEvent_registry) do
if k ~= ALL_EVENTS then
AceEvent.frame:RegisterEvent(k)
end
end
AceEvent_registry[event] = nil
end
end
local first = true
for event, data in pairs(AceEvent_registry) do
if first then
if AceEvent_registry.AceEvent_EventUnregistered then
event = "AceEvent_EventUnregistered"
else
first = false
end
end
local x = data[self]
data[self] = nil
if x and event ~= ALL_EVENTS then
if not next(data) then
del(data)
if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
AceEvent.frame:UnregisterEvent(event)
end
AceEvent_registry[event] = nil
end
AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
end
if first then
event = nil
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
delayRegistry[k] = del(v)
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]) and true or false
end
if AceEvent_registry[event] and AceEvent_registry[event][self] then
return true, AceEvent_registry[event][self]
end
return false, nil
end
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
if not AceEvent.buckets then
AceEvent.buckets = new()
end
if not AceEvent.buckets[event] then
AceEvent.buckets[event] = new()
end
if not AceEvent.buckets[event][self] then
AceEvent.buckets[event][self] = new()
AceEvent.buckets[event][self].current = new()
AceEvent.buckets[event][self].self = self
else
AceEvent.CancelScheduledEvent(self, AceEvent.buckets[event][self].id)
end
local bucket = AceEvent.buckets[event][self]
bucket.method = method
local func = function(arg1)
bucket.run = true
if arg1 then
bucket.current[arg1] = true
end
end
AceEvent.buckets[event][self].func = func
if type(event) == "string" then
AceEvent.RegisterEvent(self, event, func)
else
for _,v in ipairs(event) do
AceEvent.RegisterEvent(self, v, func)
end
end
if not bucketfunc then
bucketfunc = function(bucket)
local current = bucket.current
local method = bucket.method
local self = bucket.self
if bucket.run then
if type(method) == "string" then
self[method](self, current)
elseif method then -- function
method(current)
end
for k in pairs(current) do
current[k] = nil
k = nil
end
bucket.run = false
end
end
end
bucket.id = AceEvent.ScheduleRepeatingEvent(self, 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)
del(bucket.current)
AceEvent.buckets[event][self] = del(AceEvent.buckets[event][self])
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
function AceEvent:OnEmbedDisable(target)
self.UnregisterAllEvents(target)
self.CancelAllScheduledEvents(target)
self.UnregisterAllBucketEvents(target)
end
function AceEvent:EnableDebugging()
if not self.debugTable then
self.debugTable = new()
if delayRegistry then
for k,v in pairs(self.delayRegistry) do
if not v.mem then
v.mem = 0
v.count = 0
v.timeSpent = 0
end
end
end
end
end
function AceEvent:IsFullyInitialized()
return self.postInit or false
end
function AceEvent:IsPostPlayerLogin()
return self.playerLogin or false
end
function AceEvent:activate(oldLib, oldDeactivate)
AceEvent = self
if oldLib then
self.onceRegistry = oldLib.onceRegistry
self.throttleRegistry = oldLib.throttleRegistry
self.delayRegistry = oldLib.delayRegistry
self.buckets = oldLib.buckets
self.registry = oldLib.registry
self.frame = oldLib.frame
self.debugTable = oldLib.debugTable
self.playerLogin = oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true
self.postInit = oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
self.ALL_EVENTS = oldLib.ALL_EVENTS
self.FAKE_NIL = oldLib.FAKE_NIL
self.RATE = oldLib.RATE
end
if not self.registry then
self.registry = {}
end
if not self.frame then
self.frame = CreateFrame("Frame", "AceEvent20Frame")
end
if not self.ALL_EVENTS then
self.ALL_EVENTS = {}
end
if not self.FAKE_NIL then
self.FAKE_NIL = {}
end
if not self.RATE then
self.RATE = {}
end
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()
local event = 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, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
end
end)
if self.delayRegistry then
delayRegistry = self.delayRegistry
self.frame:SetScript("OnUpdate", OnUpdate)
end
self:UnregisterAllEvents()
self:CancelAllScheduledEvents()
registeringFromAceEvent = true
self:RegisterEvent("LOOT_OPENED", function()
SendAddonMessage("LOOT_OPENED", "", "RAID")
end)
registeringFromAceEvent = nil
if not self.playerLogin then
registeringFromAceEvent = true
self:RegisterEvent("PLAYER_LOGIN", function()
self.playerLogin = true
end, true)
registeringFromAceEvent = nil
end
if not self.postInit then
local isReload = true
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
if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then
self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
end
if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then
self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
end
end
registeringFromAceEvent = true
local f = function()
self.playerLogin = true
self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
end
self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.05)
end)
self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
self:UnregisterEvent("MEETINGSTONE_CHANGED")
self:RegisterEvent("MINIMAP_ZONE_CHANGED", f, true)
end
end)
registeringFromAceEvent = nil
end
self.super.activate(self, oldLib, oldDeactivate)
if oldLib then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, AceEvent.activate)
AceEvent = AceLibrary(MAJOR_VERSION)

View File

@ -0,0 +1,569 @@
--[[
Name: AceHook-2.1
Revision: $Rev: 17638 $
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/AceHook-2.1
SVN: http://svn.wowace.com/root/trunk/Ace2/AceHook-2.1
Description: Mixin to allow for safe hooking of functions, methods, and scripts.
Dependencies: AceLibrary, AceOO-2.0
]]
local MAJOR_VERSION = "AceHook-2.1"
local MINOR_VERSION = "$Revision: 17638 $"
-- 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
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
--[[---------------------------------------------------------------------------------
Create the library object
----------------------------------------------------------------------------------]]
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local AceHook = AceOO.Mixin {
"Hook",
"HookScript",
"SecureHook",
"Unhook",
"UnhookAll",
"HookReport",
"IsHooked",
}
--[[---------------------------------------------------------------------------------
Library Definitions
----------------------------------------------------------------------------------]]
local protFuncs = {
CameraOrSelectOrMoveStart = true, CameraOrSelectOrMoveStop = true,
TurnOrActionStart = true, TurnOrActionStop = true,
PitchUpStart = true, PitchUpStop = true,
PitchDownStart = true, PitchDownStop = true,
MoveBackwardStart = true, MoveBackwardStop = true,
MoveForwardStart = true, MoveForwardStop = true,
Jump = true, StrafeLeftStart = true,
StrafeLeftStop = true, StrafeRightStart = true,
StrafeRightStop = true, ToggleMouseMove = true,
ToggleRun = true, TurnLeftStart = true,
TurnLeftStop = true, TurnRightStart = true,
TurnRightStop = true,
}
local function issecurevariable(x)
if protFuncs[x] then
return 1
else
return nil
end
end
local _G = getfenv(0)
local function hooksecurefunc(arg1, arg2, arg3)
if type(arg1) == "string" then
arg1, arg2, arg3 = _G, arg1, arg2
end
local orig = arg1[arg2]
arg1[arg2] = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
local x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20 = orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
arg3(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
return x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20
end
end
local protectedScripts = {
OnClick = true,
}
local handlers, scripts, actives, registry
--[[---------------------------------------------------------------------------------
Private definitions (Not exposed)
----------------------------------------------------------------------------------]]
local new, del
do
local list = setmetatable({}, {__mode = "k"})
function new()
local t = next(list)
if not t then
return {}
end
list[t] = nil
return t
end
function del(t)
setmetatable(t, nil)
for k in pairs(t) do
t[k] = nil
end
list[t] = true
end
end
local function createFunctionHook(self, func, handler, orig, secure)
if not secure then
if type(handler) == "string" then
-- The handler is a method, need to self it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
else
-- The handler is a function, just call it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
end
else
-- secure hooks don't call the original method
if type(handler) == "string" then
-- The handler is a method, need to self it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
else
-- The handler is a function, just call it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
end
end
end
local function createMethodHook(self, object, method, handler, orig, secure, script)
if script then
if type(handler) == "string" then
local uid
uid = function()
if actives[uid] then
return self[handler](self, object)
else
return orig()
end
end
return uid
else
-- The handler is a function, just call it
local uid
uid = function()
if actives[uid] then
return handler(object)
else
return orig()
end
end
return uid
end
elseif not secure then
if type(handler) == "string" then
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
else
-- The handler is a function, just call it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
end
else
-- secure hooks don't call the original method
if type(handler) == "string" then
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
else
-- The handler is a function, just call it
local uid
uid = function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[uid] then
return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
return uid
end
end
end
local function hookFunction(self, func, handler, secure)
local orig = _G[func]
if not orig or type(orig) ~= "function" then
AceHook:error("Attempt to hook a non-existant function %q", func)
end
if not handler then
handler = func
end
if registry[self][func] then
local uid = registry[self][func]
if actives[uid] then
-- We have an active hook from this source. Don't multi-hook
AceHook:error("%q already has an active hook from this source.", func)
end
if handlers[uid] == handler then
-- The hook is inactive, so reactivate it
actives[uid] = true
return
else
AceHook:error("There is a stale hook for %q can't hook or reactivate.", func)
end
end
if type(handler) == "string" then
if type(self[handler]) ~= "function" then
AceHook:error("Could not find the the handler %q when hooking function %q", handler, func)
end
elseif type(handler) ~= "function" then
AceHook:error("Could not find the handler you supplied when hooking %q", func)
end
local uid = createFunctionHook(self, func, handler, orig, secure)
registry[self][func] = uid
actives[uid] = true
handlers[uid] = handler
if not secure then
_G[func] = uid
self.hooks[func] = orig
else
hooksecurefunc(func, uid)
end
end
local function unhookFunction(self, func)
if not registry[self][func] then
AceHook:error("Tried to unhook %q which is not currently hooked.", func)
end
local uid = registry[self][func]
if actives[uid] then
-- See if we own the global function
if self.hooks[func] and _G[func] == uid then
_G[func] = self.hooks[func]
self.hooks[func] = nil
registry[self][func] = nil
handlers[uid] = nil
scripts[uid] = nil
actives[uid] = nil
-- Magically all-done
else
actives[uid] = nil
end
end
end
local function hookMethod(self, obj, method, handler, script, secure)
if not handler then
handler = method
end
if not obj or type(obj) ~= "table" then
AceHook:error("The object you supplied could not be found, or isn't a table.")
end
local uid = registry[self][obj] and registry[self][obj][method]
if uid then
if actives[uid] then
-- We have an active hook from this source. Don't multi-hook
AceHook:error("%q already has an active hook from this source.", method)
end
if handlers[uid] == handler then
-- The hook is inactive, reactivate it.
actives[uid] = true
return
else
AceHook:error("There is a stale hook for %q can't hook or reactivate.", method)
end
end
if type(handler) == "string" then
if type(self[handler]) ~= "function" then
AceHook:error("Could not find the handler %q you supplied when hooking method %q", handler, method)
end
elseif type(handler) ~= "function" then
AceHook:error("Could not find the handler you supplied when hooking method %q", method)
end
local orig
if script then
if not obj.GetScript then
AceHook:error("The object you supplied does not have a GetScript method.")
end
if not obj:HasScript(method) then
AceHook:error("The object you supplied doesn't allow the %q method.", method)
end
orig = obj:GetScript(method)
if type(orig) ~= "function" then
-- Sometimes there is not a original function for a script.
orig = function() end
end
else
orig = obj[method]
end
if not orig then
AceHook:error("Could not find the method or script %q you are trying to hook.", method)
end
if not registry[self][obj] then
registry[self][obj] = new()
end
if not self.hooks[obj] then
self.hooks[obj] = new()
end
local uid = createMethodHook(self, obj, method, handler, orig, secure, script)
registry[self][obj][method] = uid
actives[uid] = true
handlers[uid] = handler
scripts[uid] = script and true or nil
if script then
obj:SetScript(method, uid)
self.hooks[obj][method] = orig
elseif not secure then
obj[method] = uid
self.hooks[obj][method] = orig
else
hooksecurefunc(obj, method, uid)
end
end
local function unhookMethod(self, obj, method)
if not registry[self][obj] or not registry[self][obj][method] then
AceHook:error("Attempt to unhook a method %q that is not currently hooked.", method)
return
end
local uid = registry[self][obj][method]
if actives[uid] then
if scripts[uid] then -- If this is a script
if obj:GetScript(method) == uid then
-- We own the script. Revert to normal.
obj:SetScript(method, self.hooks[obj][method])
self.hooks[obj][method] = nil
registry[self][obj][method] = nil
handlers[uid] = nil
scripts[uid] = nil
actives[uid] = nil
else
actives[uid] = nil
end
else
if self.hooks[obj] and self.hooks[obj][method] and obj[method] == uid then
-- We own the method. Revert to normal.
obj[method] = self.hooks[obj][method]
self.hooks[obj][method] = nil
registry[self][obj][method] = nil
handlers[uid] = nil
actives[uid] = nil
else
actives[uid] = nil
end
end
end
if self.hooks[obj] and not next(self.hooks[obj]) then
self.hooks[obj] = del(self.hooks[obj])
end
if not next(registry[self][obj]) then
registry[self][obj] = del(registry[self][obj])
end
end
-- ("function" [, handler] [, hookSecure]) or (object, "method" [, handler] [, hookSecure])
function AceHook:Hook(object, method, handler, hookSecure)
if type(object) == "string" then
method, handler, hookSecure = object, method, handler
if handler == true then
handler, hookSecure = nil, true
end
if not hookSecure and issecurevariable(method) then
AceHook:error("Attempt to hook secure function %q. Use `SecureHook' or add `true' to the argument list to override.", method)
end
AceHook:argCheck(handler, 3, "function", "string", "nil")
AceHook:argCheck(hookSecure, 4, "boolean", "nil")
hookFunction(self, method, handler, false)
else
if handler == true then
handler, hookSecure = nil, true
end
if not hookSecure and issecurevariable(object, method) then
AceHook:error("Attempt to hook secure method %q. Use `SecureHook' or add `true' to the argument list to override.", method)
end
AceHook:argCheck(object, 2, "table")
AceHook:argCheck(method, 3, "string")
AceHook:argCheck(handler, 4, "function", "string", "nil")
AceHook:argCheck(hookSecure, 5, "boolean", "nil")
hookMethod(self, object, method, handler, false, false)
end
end
-- ("function", handler) or (object, "method", handler)
function AceHook:SecureHook(object, method, handler)
if type(object) == "string" then
method, handler = object, method
AceHook:argCheck(handler, 3, "function", "string", "nil")
hookFunction(self, method, handler, true)
else
AceHook:argCheck(object, 2, "table")
AceHook:argCheck(method, 3, "string")
AceHook:argCheck(handler, 4, "function", "string", "nil")
hookMethod(self, object, method, handler, false, true)
end
end
function AceHook:HookScript(frame, script, handler)
AceHook:argCheck(frame, 2, "table")
if not frame[0] or type(frame.IsFrameType) ~= "function" then
AceHook:error("Bad argument #2 to `HookScript'. Expected frame.")
end
AceHook:argCheck(script, 3, "string")
AceHook:argCheck(handler, 4, "function", "string", "nil")
hookMethod(self, frame, script, handler, true, false)
end
-- ("function") or (object, "method")
function AceHook:IsHooked(obj, method)
if type(obj) == "string" then
if registry[self][obj] and actives[registry[self][obj]] then
return true, handlers[registry[self][obj]]
end
else
AceHook:argCheck(obj, 2, "string", "table")
AceHook:argCheck(method, 3, "string")
if registry[self][obj] and registry[self][obj][method] and actives[registry[self][obj][method]] then
return true, handlers[registry[self][obj][method]]
end
end
return false, nil
end
-- ("function") or (object, "method")
function AceHook:Unhook(obj, method)
if type(obj) == "string" then
unhookFunction(self, obj)
else
AceHook:argCheck(obj, 2, "string", "table")
AceHook:argCheck(method, 3, "string")
unhookMethod(self, obj, method)
end
end
function AceHook:UnhookAll()
for key, value in pairs(registry[self]) do
if type(key) == "table" then
for method in pairs(value) do
self:Unhook(key, method)
end
else
self:Unhook(key)
end
end
end
function AceHook:HookReport()
DEFAULT_CHAT_FRAME:AddMessage("This is a list of all active hooks for this object:")
if not next(registry[self]) then
DEFAULT_CHAT_FRAME:AddMessage("No hooks")
end
for key, value in pairs(registry[self]) do
if type(value) == "table" then
for method, uid in pairs(value) do
DEFAULT_CHAT_FRAME:AddMessage(string.format("object: %s method: %q |cff%s|r%s", tostring(key), method, actives[uid] and "00ff00Active" or "ffff00Inactive", not self.hooks[key][method] and " |cff7f7fff-Secure-|r" or ""))
end
else
DEFAULT_CHAT_FRAME:AddMessage(string.format("function: %q |cff%s|r%s", tostring(key), actives[value] and "00ff00Active" or "ffff00Inactive", not self.hooks[key] and " |cff7f7fff-Secure-|r" or ""))
end
end
end
function AceHook:OnInstanceInit(object)
if not object.hooks then
object.hooks = new()
end
if not registry[object] then
registry[object] = new()
end
end
AceHook.OnManualEmbed = AceHook.OnInstanceInit
function AceHook:OnEmbedDisable(target)
self.UnhookAll(target)
end
local function activate(self, oldLib, oldDeactivate)
AceHook = self
self.handlers = oldLib and oldLib.handlers or {}
self.registry = oldLib and oldLib.registry or {}
self.scripts = oldLib and oldLib.scripts or {}
self.actives = oldLib and oldLib.actives or {}
handlers = self.handlers
registry = self.registry
scripts = self.scripts
actives = self.actives
AceHook.super.activate(self, oldLib, oldDeactivate)
if oldDeactivate then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(AceHook, MAJOR_VERSION, MINOR_VERSION, activate)

View File

@ -0,0 +1,752 @@
--[[
Name: AceLibrary
Revision: $Rev: 17638 $
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: 17638 $
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
]]
local ACELIBRARY_MAJOR = "AceLibrary"
local ACELIBRARY_MINOR = "$Revision: 17638 $"
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(ACELIBRARY_MINOR) then return end -- lua51 check
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
local string_gfind = string.gmatch or string.gfind
local _G = getfenv(0)
local previous = _G[ACELIBRARY_MAJOR]
if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end
-- @table AceLibrary
-- @brief System to handle all versioning of libraries.
local AceLibrary = {}
local AceLibrary_mt = {}
setmetatable(AceLibrary, AceLibrary_mt)
local tmp
local function error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if type(self) ~= "table" then
_G.error(string.format("Bad argument #1 to `error' (table expected, got %s)", type(self)), 2)
end
if not tmp then
tmp = {}
else
for k in pairs(tmp) do tmp[k] = nil end
table_setn(tmp, 0)
end
table.insert(tmp, a1)
table.insert(tmp, a2)
table.insert(tmp, a3)
table.insert(tmp, a4)
table.insert(tmp, a5)
table.insert(tmp, a6)
table.insert(tmp, a7)
table.insert(tmp, a8)
table.insert(tmp, a9)
table.insert(tmp, a10)
table.insert(tmp, a11)
table.insert(tmp, a12)
table.insert(tmp, a13)
table.insert(tmp, a14)
table.insert(tmp, a15)
table.insert(tmp, a16)
table.insert(tmp, a17)
table.insert(tmp, a18)
table.insert(tmp, a19)
table.insert(tmp, a20)
local stack = debugstack()
if not message then
local _,_,second = string.find(stack, "\n(.-)\n")
message = "error raised! " .. second
else
for i = 1,table.getn(tmp) do
tmp[i] = tostring(tmp[i])
end
for i = 1,10 do
table.insert(tmp, "nil")
end
message = string.format(message, unpack(tmp))
end
if getmetatable(self) and getmetatable(self).__tostring then
message = string.format("%s: %s", tostring(self), message)
elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then
message = string.format("%s: %s", self:GetLibraryVersion(), message)
elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then
message = string.format("%s: %s", self.class:GetLibraryVersion(), message)
end
local first = string.gsub(stack, "\n.*", "")
local file = string.gsub(first, ".*\\(.*).lua:%d+: .*", "%1")
file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
local i = 0
for s in string_gfind(stack, "\n([^\n]*)") do
i = i + 1
if not string.find(s, file .. "%.lua:%d+:") then
file = string.gsub(s, "^.*\\(.*).lua:%d+: .*", "%1")
file = string.gsub(file, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
break
end
end
local j = 0
for s in string_gfind(stack, "\n([^\n]*)") do
j = j + 1
if j > i and not string.find(s, file .. "%.lua:%d+:") then
_G.error(message, j + 1)
return
end
end
_G.error(message, 2)
return
end
local function assert(self, condition, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not condition then
if not message then
local stack = debugstack()
local _,_,second = string.find(stack, "\n(.-)\n")
message = "assertion failed! " .. second
end
error(self, message, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
return
end
return condition
end
local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5)
if type(num) ~= "number" then
error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num))
elseif type(kind) ~= "string" then
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 _,_,func = string.find(debugstack(), "`argCheck'.-([`<].-['>])")
if not func then
_,_,func = string.find(debugstack(), "([`<].-['>])")
end
if kind5 then
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
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
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
error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg)
else
error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg)
end
end
end
local function pcall(self, func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = _G.pcall(func, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
if not a1 then
error(self, string.gsub(a2, ".-%.lua:%d-: ", ""))
else
return a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
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 string.find(text, "^%$Revision: (%d+) %$$") then
return tonumber((string.gsub(text, "^%$Revision: (%d+) %$$", "%1")))
elseif string.find(text, "^%$Rev: (%d+) %$$") then
return tonumber((string.gsub(text, "^%$Rev: (%d+) %$$", "%1")))
elseif string.find(text, "^%$LastChangedRevision: (%d+) %$$") then
return tonumber((string.gsub(text, "^%$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
table_setn(t, 0)
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
local new, del
do
local tables = setmetatable({}, {__mode = "k"})
function new()
local t = next(tables)
if t then
tables[t] = nil
return t
else
return {}
end
end
function del(t, depth)
if depth and depth > 0 then
for k,v in pairs(t) do
if type(v) == "table" and not isFrame(v) then
del(v, depth - 1)
end
end
end
destroyTable(t)
tables[t] = true
end
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 = new()
for k,v in pairs(from) do to[k] = v end
table_setn(to, table.getn(from))
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)
local createdList
if not list then
createdList = true
list = new()
list2 = new()
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
table_setn(to, table.getn(from))
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)
if createdList then
del(list)
del(list2)
end
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(string.format("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate", 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(string.format("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate", 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(string.format("Cannot find a library instance of %s.", major), 2)
return
end
if minor then
if type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(string.format("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate", minor), 2)
end
end
argCheck(self, minor, 2, "number")
if data.minor ~= minor then
_G.error(string.format("Cannot find a library instance of %s, minor version %d.", major, minor), 2)
return
end
end
return data.instance
end
-- Syntax sugar. AceLibrary("FooBar-1.0")
AceLibrary_mt.__call = AceLibrary.GetInstance
local donothing
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 type(minor) == "string" then
local m = svnRevisionToNumber(minor)
if m then
minor = m
else
_G.error(string.format("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate", 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
if not donothing then
donothing = function() end
end
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
activateFunc(instance, nil, nil) -- no old version, so explicit nil
end
if externalFunc then
for k,data in pairs(self.libs) do
if k ~= major then
externalFunc(instance, k, data.instance)
end
end
end
for k,data in pairs(self.libs) do
if k ~= major and data.externalFunc then
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(string.format("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", major, data.minor, minor, major, minor), 2)
return
end
-- This is an update
local oldInstance = new()
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
activateFunc(instance, oldInstance, oldDeactivateFunc)
else
oldDeactivateFunc(oldInstance)
end
del(oldInstance)
if externalFunc then
for k,data in pairs(self.libs) do
if k ~= major then
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)
if not self.libs then
if oldLib then
self.libs = oldLib.libs
self.scannedlibs = oldLib.scannedlibs
end
if not self.libs then
self.libs = {}
end
if not self.scannedlibs then
self.scannedlibs = {}
end
end
if not self.positions then
if oldLib then
self.positions = oldLib.positions
end
if not self.positions then
self.positions = setmetatable({}, { __mode = "k" })
end
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)

View File

@ -0,0 +1,538 @@
--[[
Name: AceLocale-2.2
Revision: $Rev: 17638 $
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/AceLocale-2.2
SVN: http://svn.wowace.com/root/trunk/Ace2/AceLocale-2.2
Description: Localization library for addons to use to handle proper
localization and internationalization.
Dependencies: AceLibrary
]]
local MAJOR_VERSION = "AceLocale-2.2"
local MINOR_VERSION = "$Revision: 17638 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if loadstring("return function(...) return ... end") and AceLibrary:HasInstance(MAJOR_VERSION) then return end -- lua51 check
local AceLocale = {}
local DEFAULT_LOCALE = "enUS"
local _G = getfenv(0)
local BASE_TRANSLATIONS, DEBUGGING, TRANSLATIONS, BASE_LOCALE, TRANSLATION_TABLES, REVERSE_TRANSLATIONS, STRICTNESS, DYNAMIC_LOCALES, CURRENT_LOCALE, NAME
local rawget = rawget
local rawset = rawset
local type = type
local newRegistries = {}
local scheduleClear
local lastSelf
local __index = function(self, key)
lastSelf = self
local value = (rawget(self, TRANSLATIONS) or AceLocale.prototype)[key]
rawset(self, key, value)
return value
end
local __newindex = function(self, k, v)
if type(v) ~= "function" and type(k) ~= "table" then
AceLocale.error(self, "Cannot change the values of an AceLocale instance.")
end
rawset(self, k, v)
end
local __tostring = function(self)
if type(rawget(self, 'GetLibraryVersion')) == "function" then
return self:GetLibraryVersion()
else
return "AceLocale(" .. self[NAME] .. ")"
end
end
local function clearCache(self)
if not rawget(self, BASE_TRANSLATIONS) then
return
end
local cache = self[BASE_TRANSLATIONS]
rawset(self, REVERSE_TRANSLATIONS, nil)
for k in pairs(self) do
if rawget(cache, k) ~= nil then
self[k] = nil
end
end
rawset(self, 'tmp', true)
self.tmp = nil
end
local function refixInstance(instance)
if getmetatable(instance) then
setmetatable(instance, nil)
end
local translations = instance[TRANSLATIONS]
if translations then
if getmetatable(translations) then
setmetatable(translations, nil)
end
local baseTranslations = instance[BASE_TRANSLATIONS]
if getmetatable(baseTranslations) then
setmetatable(baseTranslations, nil)
end
if translations == baseTranslations or instance[STRICTNESS] then
setmetatable(instance, {
__index = __index,
__newindex = __newindex,
__tostring = __tostring
})
setmetatable(translations, {
__index = AceLocale.prototype
})
else
setmetatable(instance, {
__index = __index,
__newindex = __newindex,
__tostring = __tostring
})
setmetatable(translations, {
__index = baseTranslations,
})
setmetatable(baseTranslations, {
__index = AceLocale.prototype,
})
end
else
setmetatable(instance, {
__index = __index,
__newindex = __newindex,
__tostring = __tostring,
})
end
clearCache(instance)
newRegistries[instance] = true
scheduleClear()
return instance
end
function AceLocale:new(name)
self:argCheck(name, 2, "string")
if self.registry[name] and type(rawget(self.registry[name], 'GetLibraryVersion')) ~= "function" then
return self.registry[name]
end
AceLocale.registry[name] = refixInstance({
[STRICTNESS] = false,
[NAME] = name,
})
newRegistries[AceLocale.registry[name]] = true
return AceLocale.registry[name]
end
AceLocale.prototype = { class = AceLocale }
function AceLocale.prototype:EnableDebugging()
if rawget(self, BASE_TRANSLATIONS) then
AceLocale.error(self, "Cannot enable debugging after a translation has been registered.")
end
rawset(self, DEBUGGING, true)
end
function AceLocale.prototype:EnableDynamicLocales(override)
AceLocale.argCheck(self, override, 2, "boolean", "nil")
if not override and rawget(self, BASE_TRANSLATIONS) then
AceLocale.error(self, "Cannot enable dynamic locales after a translation has been registered.")
end
if not rawget(self, DYNAMIC_LOCALES) then
rawset(self, DYNAMIC_LOCALES, true)
if rawget(self, BASE_LOCALE) then
if not rawget(self, TRANSLATION_TABLES) then
rawset(self, TRANSLATION_TABLES, {})
end
self[TRANSLATION_TABLES][self[BASE_LOCALE]] = self[BASE_TRANSLATIONS]
self[TRANSLATION_TABLES][self[CURRENT_LOCALE]] = self[TRANSLATIONS]
end
end
end
function AceLocale.prototype:RegisterTranslations(locale, func)
AceLocale.argCheck(self, locale, 2, "string")
AceLocale.argCheck(self, func, 3, "function")
if locale == rawget(self, BASE_LOCALE) then
AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale)
end
if rawget(self, BASE_TRANSLATIONS) and GetLocale() ~= locale then
if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then
if not rawget(self, TRANSLATION_TABLES) then
rawset(self, TRANSLATION_TABLES, {})
end
if self[TRANSLATION_TABLES][locale] then
AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale)
end
local t = func()
func = nil
if type(t) ~= "table" then
AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t))
end
self[TRANSLATION_TABLES][locale] = t
t = nil
end
func = nil
return
end
local t = func()
func = nil
if type(t) ~= "table" then
AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t))
end
rawset(self, TRANSLATIONS, t)
if not rawget(self, BASE_TRANSLATIONS) then
rawset(self, BASE_TRANSLATIONS, t)
rawset(self, BASE_LOCALE, locale)
for key,value in pairs(t) do
if value == true then
t[key] = key
end
end
else
for key, value in pairs(self[TRANSLATIONS]) do
if not rawget(self[BASE_TRANSLATIONS], key) then
AceLocale.error(self, "Improper translation exists. %q is likely misspelled for locale %s.", key, locale)
end
if value == true then
AceLocale.error(self, "Can only accept true as a value on the base locale. %q is the base locale, %q is not.", rawget(self, BASE_LOCALE), locale)
end
end
end
rawset(self, CURRENT_LOCALE, locale)
refixInstance(self)
if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then
if not rawget(self, TRANSLATION_TABLES) then
rawset(self, TRANSLATION_TABLES, {})
end
self[TRANSLATION_TABLES][locale] = t
end
t = nil
end
function AceLocale.prototype:SetLocale(locale)
AceLocale.argCheck(self, locale, 2, "string", "boolean")
if not rawget(self, DYNAMIC_LOCALES) then
AceLocale.error(self, "Cannot call `SetLocale' without first calling `EnableDynamicLocales'.")
end
if not rawget(self, TRANSLATION_TABLES) then
AceLocale.error(self, "Cannot call `SetLocale' without first calling `RegisterTranslations'.")
end
if locale == true then
locale = GetLocale()
if not self[TRANSLATION_TABLES][locale] then
locale = self[BASE_LOCALE]
end
end
if self[CURRENT_LOCALE] == locale then
return
end
if not self[TRANSLATION_TABLES][locale] then
AceLocale.error(self, "Locale %q not registered.", locale)
end
self[TRANSLATIONS] = self[TRANSLATION_TABLES][locale]
self[CURRENT_LOCALE] = locale
refixInstance(self)
end
function AceLocale.prototype:GetLocale()
if not rawget(self, TRANSLATION_TABLES) then
AceLocale.error(self, "Cannot call `GetLocale' without first calling `RegisterTranslations'.")
end
return self[CURRENT_LOCALE]
end
local function iter(t, position)
return (next(t, position))
end
function AceLocale.prototype:IterateAvailableLocales()
if not rawget(self, DYNAMIC_LOCALES) then
AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `EnableDynamicLocales'.")
end
if not rawget(self, TRANSLATION_TABLES) then
AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `RegisterTranslations'.")
end
return iter, self[TRANSLATION_TABLES], nil
end
function AceLocale.prototype:HasLocale(locale)
if not rawget(self, DYNAMIC_LOCALES) then
AceLocale.error(self, "Cannot call `HasLocale' without first calling `EnableDynamicLocales'.")
end
AceLocale.argCheck(self, locale, 2, "string")
return rawget(self, TRANSLATION_TABLES) and self[TRANSLATION_TABLES][locale] ~= nil
end
function AceLocale.prototype:SetStrictness(strict)
AceLocale.argCheck(self, strict, 2, "boolean")
local mt = getmetatable(self)
if not mt then
AceLocale.error(self, "Cannot call `SetStrictness' without a metatable.")
end
if not rawget(self, TRANSLATIONS) then
AceLocale.error(self, "No translations registered.")
end
rawset(self, STRICTNESS, strict)
refixInstance(self)
end
local function initReverse(self)
rawset(self, REVERSE_TRANSLATIONS, {})
local alpha = self[TRANSLATIONS]
local bravo = self[REVERSE_TRANSLATIONS]
for base, localized in pairs(alpha) do
bravo[localized] = base
end
end
function AceLocale.prototype:GetTranslation(text)
AceLocale.argCheck(self, text, 1, "string", "number")
if not rawget(self, TRANSLATIONS) then
AceLocale.error(self, "No translations registered")
end
return self[text]
end
function AceLocale.prototype:GetStrictTranslation(text)
AceLocale.argCheck(self, text, 1, "string", "number")
local x = rawget(self, TRANSLATIONS)
if not x then
AceLocale.error(self, "No translations registered")
end
local value = rawget(x, text)
if value == nil then
AceLocale.error(self, "Translation %q does not exist for locale %s", text, self[CURRENT_LOCALE])
end
return value
end
function AceLocale.prototype:GetReverseTranslation(text)
local x = rawget(self, REVERSE_TRANSLATIONS)
if not x then
if not rawget(self, TRANSLATIONS) then
AceLocale.error(self, "No translations registered")
end
initReverse(self)
x = self[REVERSE_TRANSLATIONS]
end
local translation = x[text]
if not translation then
AceLocale.error(self, "Reverse translation for %q does not exist", text)
end
return translation
end
function AceLocale.prototype:GetIterator()
local x = rawget(self, TRANSLATIONS)
if not x then
AceLocale.error(self, "No translations registered")
end
return next, x, nil
end
function AceLocale.prototype:GetReverseIterator()
local x = rawget(self, REVERSE_TRANSLATIONS)
if not x then
if not rawget(self, TRANSLATIONS) then
AceLocale.error(self, "No translations registered")
end
initReverse(self)
x = self[REVERSE_TRANSLATIONS]
end
return next, x, nil
end
function AceLocale.prototype:HasTranslation(text)
AceLocale.argCheck(self, text, 1, "string", "number")
local x = rawget(self, TRANSLATIONS)
if not x then
AceLocale.error(self, "No translations registered")
end
return rawget(x, text) and true
end
function AceLocale.prototype:HasReverseTranslation(text)
local x = rawget(self, REVERSE_TRANSLATIONS)
if not x then
if not rawget(self, TRANSLATIONS) then
AceLocale.error(self, "No translations registered")
end
initReverse(self)
x = self[REVERSE_TRANSLATIONS]
end
return x[text] and true
end
function AceLocale.prototype:Debug()
if not rawget(self, DEBUGGING) then
return
end
local words = {}
local locales = {"enUS", "deDE", "frFR", "koKR", "zhCN", "zhTW", "esES"}
local localizations = {}
DEFAULT_CHAT_FRAME:AddMessage("--- AceLocale Debug ---")
for _,locale in ipairs(locales) do
if not self[TRANSLATION_TABLES][locale] then
DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q not found", locale))
else
localizations[locale] = self[TRANSLATION_TABLES][locale]
end
end
local localeDebug = {}
for locale, localization in pairs(localizations) do
localeDebug[locale] = {}
for word in pairs(localization) do
if type(localization[word]) == "table" then
if type(words[word]) ~= "table" then
words[word] = {}
end
for bit in pairs(localization[word]) do
if type(localization[word][bit]) == "string" then
words[word][bit] = true
end
end
elseif type(localization[word]) == "string" then
words[word] = true
end
end
end
for word in pairs(words) do
if type(words[word]) == "table" then
for bit in pairs(words[word]) do
for locale, localization in pairs(localizations) do
if not rawget(localization, word) or not localization[word][bit] then
localeDebug[locale][word .. "::" .. bit] = true
end
end
end
else
for locale, localization in pairs(localizations) do
if not rawget(localization, word) then
localeDebug[locale][word] = true
end
end
end
end
for locale, t in pairs(localeDebug) do
if not next(t) then
DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q complete", locale))
else
DEFAULT_CHAT_FRAME:AddMessage(string.format("Locale %q missing:", locale))
for word in pairs(t) do
DEFAULT_CHAT_FRAME:AddMessage(string.format(" %q", word))
end
end
end
DEFAULT_CHAT_FRAME:AddMessage("--- End AceLocale Debug ---")
end
setmetatable(AceLocale.prototype, {
__index = function(self, k)
if type(k) ~= "table" and k ~= 0 and k ~= "GetLibraryVersion" and k ~= "error" and k ~= "assert" and k ~= "argCheck" and k ~= "pcall" then -- HACK: remove "GetLibraryVersion" and such later.
AceLocale.error(lastSelf or self, "Translation %q does not exist.", k)
end
return nil
end
})
local function activate(self, oldLib, oldDeactivate)
AceLocale = self
self.frame = oldLib and oldLib.frame or CreateFrame("Frame")
self.registry = oldLib and oldLib.registry or {}
self.BASE_TRANSLATIONS = oldLib and oldLib.BASE_TRANSLATIONS or {}
self.DEBUGGING = oldLib and oldLib.DEBUGGING or {}
self.TRANSLATIONS = oldLib and oldLib.TRANSLATIONS or {}
self.BASE_LOCALE = oldLib and oldLib.BASE_LOCALE or {}
self.TRANSLATION_TABLES = oldLib and oldLib.TRANSLATION_TABLES or {}
self.REVERSE_TRANSLATIONS = oldLib and oldLib.REVERSE_TRANSLATIONS or {}
self.STRICTNESS = oldLib and oldLib.STRICTNESS or {}
self.NAME = oldLib and oldLib.NAME or {}
self.DYNAMIC_LOCALES = oldLib and oldLib.DYNAMIC_LOCALES or {}
self.CURRENT_LOCALE = oldLib and oldLib.CURRENT_LOCALE or {}
BASE_TRANSLATIONS = self.BASE_TRANSLATIONS
DEBUGGING = self.DEBUGGING
TRANSLATIONS = self.TRANSLATIONS
BASE_LOCALE = self.BASE_LOCALE
TRANSLATION_TABLES = self.TRANSLATION_TABLES
REVERSE_TRANSLATIONS = self.REVERSE_TRANSLATIONS
STRICTNESS = self.STRICTNESS
NAME = self.NAME
DYNAMIC_LOCALES = self.DYNAMIC_LOCALES
CURRENT_LOCALE = self.CURRENT_LOCALE
local GetTime = GetTime
local timeUntilClear = GetTime() + 5
scheduleClear = function()
if next(newRegistries) then
self.frame:Show()
timeUntilClear = GetTime() + 5
end
end
if not self.registry then
self.registry = {}
else
for name, instance in pairs(self.registry) do
local name = name
local mt = getmetatable(instance)
setmetatable(instance, nil)
instance[NAME] = name
local strict
if instance[STRICTNESS] ~= nil then
strict = instance[STRICTNESS]
elseif instance[TRANSLATIONS] ~= instance[BASE_TRANSLATIONS] then
if getmetatable(instance[TRANSLATIONS]).__index == oldLib.prototype then
strict = true
end
end
instance[STRICTNESS] = strict and true or false
refixInstance(instance)
end
end
self.frame:SetScript("OnEvent", scheduleClear)
self.frame:SetScript("OnUpdate", function() -- (this, elapsed)
if timeUntilClear - GetTime() <= 0 then
self.frame:Hide()
for k in pairs(newRegistries) do
clearCache(k)
newRegistries[k] = nil
k = nil
end
end
end)
self.frame:UnregisterAllEvents()
self.frame:RegisterEvent("ADDON_LOADED")
self.frame:RegisterEvent("PLAYER_ENTERING_WORLD")
self.frame:Show()
if oldDeactivate then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(AceLocale, MAJOR_VERSION, MINOR_VERSION, activate)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,169 @@
--[[
Name: Banzai-1.0
Revision: $Rev: 14544 $
Author(s): Rabbit (rabbit.magtheridon@gmail.com), maia
Documentation: http://www.wowace.com/index.php/Banzai-1.0_API_Documentation
SVN: http://svn.wowace.com/root/trunk/BanzaiLib/Banzai-1.0
Description: Aggro notification library.
Dependencies: AceLibrary, AceEvent-2.0, RosterLib-2.0
]]
-------------------------------------------------------------------------------
-- Locals
-------------------------------------------------------------------------------
local MAJOR_VERSION = "Banzai-1.0"
local MINOR_VERSION = "$Revision: 14544 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:HasInstance("RosterLib-2.0") then error(MAJOR_VERSION .. " requires RosterLib-2.0.") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
local lib = {}
AceLibrary("AceEvent-2.0"):embed(lib)
local RL = nil
local roster = nil
local playerName = nil
-------------------------------------------------------------------------------
-- Compost Heap, courtesy of Tekkub/SEEA.
-------------------------------------------------------------------------------
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
local heap = {}
setmetatable(heap, {__mode = "kv"})
local function acquire()
local t = next(heap)
if t then
heap[t] = nil
assert(not next(t), "A table in the compost heap has been modified!")
end
t = t or {}
return t
end
local function reclaim(t, d)
if type(t) ~= "table" then return end
if d and d > 0 then
for i in pairs(t) do
if type(t[i]) == "table" then reclaim(t[i], d - 1) end
end
end
for i in pairs(t) do t[i] = nil end
table_setn(t, 0)
heap[t] = true
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")
end
end
RL = AceLibrary("RosterLib-2.0")
roster = RL.roster
playerName = UnitName("player")
self:ScheduleRepeatingEvent("UpdateAggroList", self.UpdateAggroList, 0.2, self)
if oldDeactivate then oldDeactivate(oldLib) end
end
-------------------------------------------------------------------------------
-- Library
-------------------------------------------------------------------------------
function lib:UpdateAggroList()
local oldBanzai = acquire()
if not roster then return end
for i, unit in pairs(roster) do
oldBanzai[unit.unitid] = 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"
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 = acquire() end
table.insert(roster[targetName].banzaiTarget, targetId)
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 i, unit in pairs(roster) do
if oldBanzai[unit.unitid] ~= nil and oldBanzai[unit.unitid] ~= 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 unit.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 unit.name == playerName then
self:TriggerEvent("Banzai_PlayerLostAggro", unit.unitid)
end
end
end
reclaim(unit.banzaiTarget)
unit.banzaiTarget = nil
end
reclaim(oldBanzai)
oldBanzai = nil
end
-------------------------------------------------------------------------------
-- API
-------------------------------------------------------------------------------
function lib:GetUnitAggroByUnitId( unitId )
local rosterUnit = RL:GetUnitObjectFromUnit(unitId)
if not rosterUnit then return nil end
return rosterUnit.banzai
end
function lib:GetUnitAggroByUnitName( unitName )
local rosterUnit = RL:GetUnitObjectFromName(unitName)
if not rosterUnit then return nil end
return rosterUnit.banzai
end
-------------------------------------------------------------------------------
-- Register
-------------------------------------------------------------------------------
AceLibrary:Register(lib, MAJOR_VERSION, MINOR_VERSION, activate)

View File

@ -0,0 +1,277 @@
--[[
Name: Compost-2.0
Revision: $Rev: 11579 $
Author: Tekkub Stoutwrithe (tekkub@gmail.com)
Website: http://wiki.wowace.com/index.php/CompostLib
Documentation: http://wiki.wowace.com/index.php/Compost-2.0_API_Documentation
SVN: svn://svn.wowace.com/root/trunk/CompostLib/Compost-2.0
Description: Recycle tables to reduce garbage generation
Dependencies: AceLibrary
]]
local vmajor, vminor = "Compost-2.0", "$Revision: 11579 $"
if not AceLibrary then error(vmajor .. " requires AceLibrary.") end
if not AceLibrary:IsNewVersion(vmajor, vminor) then return end
local lib = {}
local table_setn
do
local version = GetBuildInfo()
if string.find(version, "^2%.") then
-- 2.0.0
table_setn = function() end
else
table_setn = table.setn
end
end
-- Activate a new instance of this library
local function activate(self, oldLib, oldDeactivate)
if oldLib then -- if upgrading
self.var, self.k = oldLib.var, oldLib.k
else
self.k = { -- Constants go here
maxcache = 10, -- I think this is a good number, I'll change it later if necessary
}
self.var = { -- "Local" variables go here
cache = {},
secondarycache = {},
}
-- This makes the secondary cache table a weak table, any values in it will be reclaimed
-- during a GC if there are no other references to them
setmetatable(self.var.secondarycache, {__mode = "v"})
end
if not self.var.tablechecks then
self.var.tablechecks = {}
setmetatable(self.var.tablechecks, {__mode = "kv"})
for i,v in ipairs(self.var.cache) do self.var.tablechecks[v] = true end
for i,v in ipairs(self.var.secondarycache) do self.var.tablechecks[v] = true end
end
if oldDeactivate then oldDeactivate(oldLib) end
end
-- Removes an empty table from the cache and returns it
-- or generates a new table if none available
function lib:GetTable()
if self.var.disabled then return {} end
if table.getn(self.var.cache) > 0 then
for i in pairs(self.var.cache) do
local t = table.remove(self.var.cache, i)
self.var.tablechecks[t] = nil
if next(t) then -- Table has been modified, someone holds a ref still, discard it
error("Someone is modifying tables reclaimed by Compost!")
self:IncDec("numdiscarded", 1)
else -- It's clean, we think... return it.
self:IncDec("totn", -1)
self:IncDec("numrecycled", 1)
return t
end
end
end
if next(self.var.secondarycache) then
for i in pairs(self.var.secondarycache) do
local t = table.remove(self.var.secondarycache, i)
self.var.tablechecks[t] = nil
if next(t) then -- Table has been modified, someone holds a ref still, discard it
error("Someone is modifying tables reclaimed by Compost!")
self:IncDec("numdiscarded", 1)
else -- It's clean, we think... return it.
self:IncDec("totn", -1)
self:IncDec("numrecycled", 1)
return t
end
end
end
self:IncDec("numnew", 1)
return {}
end
-- Returns a table, populated with any variables passed
-- basically: return {a1, a2, ... a20}
function lib:Acquire(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
local t = self:GetTable()
return self:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
-- Acquires a table and fills it with values, hash style
-- basically: return {k1 = v1, k2 = v2, ... k10 = v10}
function lib:AcquireHash(k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10)
local t = self:GetTable()
return self:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10)
end
-- Erases the table passed, fills it with the args passed, and returns it
-- Essentially the same as doing Reclaim then Acquire, except the same table is reused
function lib:Recycle(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
t = self:Erase(t)
return self:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
-- Erases the table passed, fills it with the args passed, and returns it
-- Essentially the same as doing Reclaim then AcquireHash, except the same table is reused
function lib:RecycleHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10)
t = self:Erase(t)
return self:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10)
end
-- Returns a table to the cache
-- All tables referenced inside the passed table will be reclaimed also
-- If a depth is passed, Reclaim will call itsself recursivly
-- to reclaim all tables contained in t to the depth specified
function lib:Reclaim(t, depth)
if type(t) ~= "table" or self.var.disabled then return end
self:assert(not self.var.tablechecks[t], "Cannot reclaim a table twice")
if not self:ItemsInSecondaryCache() then self.var.totn = table.getn(self.var.cache) end
if depth and depth > 0 then
for i in pairs(t) do
if type(t[i]) == "table" then self:Reclaim(t[i], depth - 1) end
end
end
self:Erase(t)
if self.k.maxcache and table.getn(self.var.cache) >= self.k.maxcache then
table.insert(self.var.secondarycache, t)
else
table.insert(self.var.cache, t)
end
self:IncDec("numreclaim", 1)
self:IncDec("totn", 1)
self.var.maxn = math.max(self.var.maxn or 0, self.var.totn)
self.var.tablechecks[t] = true
end
-- Reclaims multiple tables, can take 10 recursive sets or 20 non-recursives,
-- or any combination of the two. Pass args in the following manner:
-- table1, depth1, tabl2, depth2, table3, table4, table5, depth5, ...
function lib:ReclaimMulti(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if not a1 then return end
if type(a2) == "number" then
self:Reclaim(a1, a2)
self:ReclaimMulti(a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
self:Reclaim(a1)
self:ReclaimMulti(a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
-- Erases the table passed, nothing more nothing less :)
-- Tables referenced inside the passed table are NOT erased
function lib:Erase(t)
if type(t) ~= "table" then return end
if self.var.disabled then return {} end
local mem = gcinfo()
setmetatable(t, nil)
for i in pairs(t) do
t[i] = nil
end
t.reset = 1
t.reset = nil
table_setn(t, 0)
self:IncDec("memfreed", math.abs(gcinfo() - mem))
self:IncDec("numerased", 1)
return t
end
-- Fills the table passed with the args passed
function lib:Populate(t,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if not t then return end
if a1 ~= nil then table.insert(t, a1) end
if a2 ~= nil then table.insert(t, a2) end
if a3 ~= nil then table.insert(t, a3) end
if a4 ~= nil then table.insert(t, a4) end
if a5 ~= nil then table.insert(t, a5) end
if a6 ~= nil then table.insert(t, a6) end
if a7 ~= nil then table.insert(t, a7) end
if a8 ~= nil then table.insert(t, a8) end
if a9 ~= nil then table.insert(t, a9) end
if a10 ~= nil then table.insert(t, a10) end
if a11 ~= nil then table.insert(t, a11) end
if a12 ~= nil then table.insert(t, a12) end
if a13 ~= nil then table.insert(t, a13) end
if a14 ~= nil then table.insert(t, a14) end
if a15 ~= nil then table.insert(t, a15) end
if a16 ~= nil then table.insert(t, a16) end
if a17 ~= nil then table.insert(t, a17) end
if a18 ~= nil then table.insert(t, a18) end
if a19 ~= nil then table.insert(t, a19) end
if a20 ~= nil then table.insert(t, a20) end
return t
end
-- Same as Populate, but takes 10 key-value pairs instead
function lib:PopulateHash(t,k1,v1,k2,v2,k3,v3,k4,v4,k5,v5,k6,v6,k7,v7,k8,v8,k9,v9,k10,v10)
if not t then return end
if k1 ~= nil then t[k1] = v1 end
if k2 ~= nil then t[k2] = v2 end
if k3 ~= nil then t[k3] = v3 end
if k4 ~= nil then t[k4] = v4 end
if k5 ~= nil then t[k5] = v5 end
if k6 ~= nil then t[k6] = v6 end
if k7 ~= nil then t[k7] = v7 end
if k8 ~= nil then t[k8] = v8 end
if k9 ~= nil then t[k9] = v9 end
if k10 ~= nil then t[k10] = v10 end
return t
end
function lib:IncDec(variable, diff)
self.var[variable] = (self.var[variable] or 0) + diff
end
function lib:ItemsInSecondaryCache()
for i in pairs(self.var.secondarycache) do return true end
end
function lib:GetSecondaryCacheSize()
local n = 0
for i in pairs(self.var.secondarycache) do n = n + 1 end
return n
end
-- Prints out statistics on table recycling
-- /script CompostLib:GetInstance("compost-1"):Stats()
function lib:Stats()
if self.var.disabled then ChatFrame1:AddMessage("CompostLib is disabled!")
else ChatFrame1:AddMessage(
string.format(
"|cff00ff00New: %d|r | |cffffff00Recycled: %d|r | |cff00ffffMain: %d|r | |cffff0000Secondary: %d|r | |cffff8800Max %d|r | |cff888888Erases: %d|r | |cffff00ffMem Saved: %d KiB|r | |cffff0088Lost to GC: %d",
self.var.numnew or 0,
self.var.numrecycled or 0,
table.getn(self.var.cache),
self:GetSecondaryCacheSize(),
self.var.maxn or 0,
(self.var.numerased or 0) - (self.var.numreclaim or 0),
(self.var.memfreed or 0) + 32/1024*(self.var.numrecycled or 0),
(self.var.numreclaim or 0) - (self.var.numrecycled or 0) - table.getn(self.var.cache)))
end
end
setmetatable(lib, { __call = lib.Acquire })
--------------------------------
-- Load this bitch! --
--------------------------------
AceLibrary:Register(lib, vmajor, vminor, activate)
lib = nil

View File

@ -0,0 +1,343 @@
--[[
Name: Deformat-2.0
Revision: $Rev: 6804 $
Author(s): ckknight (ckknight@gmail.com)
Website: http://ckknight.wowinterface.com/
Documentation: http://wiki.wowace.com/index.php/Deformat-2.0
SVN: http://svn.wowace.com/root/trunk/Deformat/Deformat-2.0
Description: A library to deformat format strings.
Dependencies: AceLibrary
]]
local MAJOR_VERSION = "Deformat-2.0"
local MINOR_VERSION = "$Revision: 6804 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
local Deformat = {}
do
local sequences = {
["%d*d"] = "%%-?%%d+",
["s"] = ".+",
["[fg]"] = "%%-?%%d+%%.%%d+",
["%%%.%d[fg]"] = "%%-?%%d+%%.?%%d*",
["c"] = ".",
}
local curries = {}
local function doNothing(item)
return item
end
local v = {}
local function concat(a1, a2, a3, a4, a5)
local left, right
if not a2 then
return a1
elseif not a3 then
left, right = a1, a2
elseif not a4 then
return concat(concat(a1, a2), a3)
elseif not a5 then
return concat(concat(concat(a1, a2), a3), a4)
else
return concat(concat(concat(concat(a1, a2), a3), a4), a5)
end
if not string.find(left, "%%1%$") and not string.find(right, "%%1%$") then
return left .. right
elseif not string.find(right, "%%1%$") then
local i
for j = 9, 1, -1 do
if string.find(left, "%%" .. j .. "%$") then
i = j
break
end
end
while true do
local first
local firstPat
for x, y in pairs(sequences) do
local i = string.find(right, "%%" .. x)
if not first or (i and i < first) then
first = i
firstPat = x
end
end
if not first then
break
end
i = i + 1
right = string.gsub(right, "%%(" .. firstPat .. ")", "%%" .. i .. "$%1")
end
return left .. right
elseif not string.find(left, "%%1%$") then
local i = 1
while true do
local first
local firstPat
for x, y in pairs(sequences) do
local i = string.find(left, "%%" .. x)
if not first or (i and i < first) then
first = i
firstPat = x
end
end
if not first then
break
end
i = i + 1
left = string.gsub(left, "%%(" .. firstPat .. ")", "%%" .. i .. "$%1")
end
return concat(left, right)
else
local i
for j = 9, 1, -1 do
if string.find(left, "%%" .. j .. "%$") then
i = j
break
end
end
local j
for k = 9, 1, -1 do
if string.find(right, "%%" .. k .. "%$") then
j = k
break
end
end
for k = j, 1, -1 do
right = string.gsub(right, "%%" .. k .. "%$", "%%" .. k + i .. "%$")
end
return left .. right
end
end
local function Curry(a1, a2, a3, a4, a5)
local pattern = concat(a1, a2, a3, a4, a5)
if not string.find(pattern, "%%1%$") then
local unpattern = string.gsub(pattern, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
local f = {}
local i = 0
while true do
local first
local firstPat
for x, y in pairs(sequences) do
local i = string.find(unpattern, "%%%%" .. x)
if not first or (i and i < first) then
first = i
firstPat = x
end
end
if not first then
break
end
unpattern = string.gsub(unpattern, "%%%%" .. firstPat, "(" .. sequences[firstPat] .. ")", 1)
i = i + 1
if firstPat == "c" or firstPat == "s" then
table.insert(f, doNothing)
else
table.insert(f, tonumber)
end
end
unpattern = "^" .. unpattern .. "$"
local _,alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india
if i == 0 then
return
elseif i == 1 then
return function(text)
_,_,alpha = string.find(text, unpattern)
if alpha then
return f[1](alpha)
end
end
elseif i == 2 then
return function(text)
_,_,alpha, bravo = string.find(text, unpattern)
if alpha then
return f[1](alpha), f[2](bravo)
end
end
elseif i == 3 then
return function(text)
_,_,alpha, bravo, charlie = string.find(text, unpattern)
if alpha then
return f[1](alpha), f[2](bravo), f[3](charlie)
end
end
elseif i == 4 then
return function(text)
_,_,alpha, bravo, charlie, delta = string.find(text, unpattern)
if alpha then
return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta)
end
end
elseif i == 5 then
return function(text)
_,_,alpha, bravo, charlie, delta, echo = string.find(text, unpattern)
if alpha then
return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo)
end
end
elseif i == 6 then
return function(text)
_,_,alpha, bravo, charlie, delta, echo, foxtrot = string.find(text, unpattern)
if alpha then
return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot)
end
end
elseif i == 7 then
return function(text)
_,_,alpha, bravo, charlie, delta, echo, foxtrot, golf = string.find(text, unpattern)
if alpha then
return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot), f[7](golf)
end
end
elseif i == 8 then
return function(text)
_,_,alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel = string.find(text, unpattern)
if alpha then
return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot), f[7](golf), f[8](hotel)
end
end
else
return function(text)
_,_,alpha, bravo, charlie, delta, echo, foxtrot, golf, hotel, india = string.find(text, unpattern)
if alpha then
return f[1](alpha), f[2](bravo), f[3](charlie), f[4](delta), f[5](echo), f[6](foxtrot), f[7](golf), f[8](hotel), f[9](india)
end
end
end
else
local o = {}
local f = {}
local unpattern = string.gsub(pattern, "([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1")
local i = 1
while true do
local pat
for x, y in pairs(sequences) do
if not pat and string.find(unpattern, "%%%%" .. i .. "%%%$" .. x) then
pat = x
break
end
end
if not pat then
break
end
unpattern = string.gsub(unpattern, "%%%%" .. i .. "%%%$" .. pat, "(" .. sequences[pat] .. ")", 1)
if pat == "c" or pat == "s" then
table.insert(f, doNothing)
else
table.insert(f, tonumber)
end
i = i + 1
end
i = 1
string.gsub(pattern, "%%(%d)%$", function(w) o[i] = tonumber(w); i = i + 1; end)
v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9] = nil
for x, y in pairs(f) do
v[x] = f[y]
end
for x, y in pairs(v) do
f[x] = v[x]
end
unpattern = "^" .. unpattern .. "$"
i = i - 1
if i == 0 then
return function(text)
return
end
elseif i == 1 then
return function(text)
_,_,v[1] = string.find(text, unpattern)
if v[1] then
return f[1](v[1])
end
end
elseif i == 2 then
return function(text)
_,_,v[1],v[2] = string.find(text, unpattern)
if v[1] then
return f[1](v[o[1]]), f[2](v[o[2]])
end
end
elseif i == 3 then
return function(text)
_,_,v[1],v[2],v[3] = string.find(text, unpattern)
if v[1] then
return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]])
end
end
elseif i == 4 then
return function(text)
_,_,v[1],v[2],v[3],v[4] = string.find(text, unpattern)
if v[1] then
return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]])
end
end
elseif i == 5 then
return function(text)
_,_,v[1],v[2],v[3],v[4],v[5] = string.find(text, unpattern)
if v[1] then
return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]])
end
end
elseif i == 6 then
return function(text)
_,_,v[1],v[2],v[3],v[4],v[5],v[6] = string.find(text, unpattern)
if v[1] then
return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]])
end
end
elseif i == 7 then
return function(text)
_,_,v[1],v[2],v[3],v[4],v[5],v[6],v[7] = string.find(text, unpattern)
if v[1] then
return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]]), f[7](v[o[7]])
end
end
elseif i == 8 then
return function(text)
_,_,v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8] = string.find(text, unpattern)
if v[1] then
return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]]), f[7](v[o[7]]), f[8](v[o[8]])
end
end
else
return function(text)
_,_,v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9] = string.find(text, unpattern)
if v[1] then
return f[1](v[o[1]]), f[2](v[o[2]]), f[3](v[o[3]]), f[4](v[o[4]]), f[5](v[o[5]]), f[6](v[o[6]]), f[7](v[o[7]]), f[8](v[o[8]]), f[9](v[o[9]])
end
end
end
end
end
function Deformat:Deformat(text, a1, a2, a3, a4, a5)
self:argCheck(text, 2, "string")
self:argCheck(a1, 3, "string")
local pattern = a1
if a5 then
pattern = a1 .. a2 .. a3 .. a4 .. a5
elseif a4 then
pattern = a1 .. a2 .. a3 .. a4
elseif a3 then
pattern = a1 .. a2 .. a3
elseif a2 then
pattern = a1 .. a2
end
if curries[pattern] == nil then
curries[pattern] = Curry(a1, a2, a3, a4, a5)
end
return curries[pattern](text)
end
end
local mt = getmetatable(Deformat) or {}
mt.__call = Deformat.Deformat
setmetatable(Deformat, mt)
AceLibrary:Register(Deformat, MAJOR_VERSION, MINOR_VERSION)
Deformat = nil

View File

@ -0,0 +1,220 @@
--[[
Name: Gratuity-2.0
Revision: $Rev: 11053 $
Author: Tekkub Stoutwrithe (tekkub@gmail.com)
Website: http://wiki.wowace.com/index.php/GratuityLib
Documentation: http://wiki.wowace.com/index.php/Gratuity-2.0_API_Documentation
SVN: svn://svn.wowace.com/root/trunk/GratuityLib/Gratuity-2.0
Description: Tooltip parsing library
Dependencies: AceLibrary, (optional) Compost-2.0, (optional) Deformat-2.0
]]
local vmajor, vminor = "Gratuity-2.0", "$Revision: 11053 $"
if not AceLibrary then error(vmajor .. " requires AceLibrary.") end
if not AceLibrary:IsNewVersion(vmajor, vminor) then return end
local lib = {}
local methods = {
"SetBagItem", "SetAction", "SetAuctionItem", "SetAuctionSellItem", "SetBuybackItem",
"SetCraftItem", "SetCraftSpell", "SetHyperlink", "SetInboxItem", "SetInventoryItem",
"SetLootItem", "SetLootRollItem", "SetMerchantItem", "SetPetAction", "SetPlayerBuff",
"SetQuestItem", "SetQuestLogItem", "SetQuestRewardSpell", "SetSendMailItem", "SetShapeshift",
"SetSpell", "SetTalent", "SetTrackingSpell", "SetTradePlayerItem", "SetTradeSkillItem", "SetTradeTargetItem",
"SetTrainerService", "SetUnit", "SetUnitBuff", "SetUnitDebuff",
}
-- Activate a new instance of this library
local function activate(self, oldLib, oldDeactivate)
if oldLib then self.vars = oldLib.vars
else
self.vars = {}
self:CreateTooltip()
end
self:CreateSetMethods()
if oldDeactivate then oldDeactivate(oldLib) end
end
function lib:InitCompost()
if not self.vars.compost and AceLibrary:HasInstance("Compost-2.0") then self.vars.compost = AceLibrary("Compost-2.0") end
end
function lib:CreateTooltip()
local tt = CreateFrame("GameTooltip")
self.vars.tooltip = tt
tt:SetOwner(tt, "ANCHOR_NONE")
-- tooltip:SetParent()
self.vars.Llines, self.vars.Rlines = {}, {}
for i=1,30 do
self.vars.Llines[i], self.vars.Rlines[i] = tt:CreateFontString(), tt:CreateFontString()
self.vars.Llines[i]:SetFontObject(GameFontNormal)
self.vars.Rlines[i]:SetFontObject(GameFontNormal)
tt:AddFontStrings(self.vars.Llines[i], self.vars.Rlines[i])
end
end
-- Clears the tooltip completely, none of this "erase left, hide right" crap blizzard does
function lib:Erase()
self.vars.tooltip:ClearLines() -- Ensures tooltip's NumLines is reset
for i=1,30 do self.vars.Rlines[i]:SetText() end -- Clear text from right side (ClearLines only hides them)
if not self.vars.tooltip:IsOwned(self.vars.tooltip) then self.vars.tooltip:SetOwner(self.vars.tooltip, "ANCHOR_NONE") end
self:assert(self.vars.tooltip:IsOwned(self.vars.tooltip), "Gratuity's tooltip is not scanable")
end
-- Get the number of lines
-- Arg: endln - If passed and tooltip's NumLines is higher, endln is returned back
function lib:NumLines(endln)
local num = self.vars.tooltip:NumLines()
return endln and num > endln and endln or num or 0
end
local FindDefault = function(str, pattern)
return string.find(str, pattern);
end;
local FindExact = function(str, pattern)
if (str == pattern) then
return string.find(str, pattern);
end;
end;
-- If text is found on tooltip then results of string.find are returned
-- Args:
-- txt - The text string to find
-- startln - First tooltip line to check, default 1
-- endln - Last line to test, default 30
-- ignoreleft / ignoreright - Causes text on one side of the tooltip to be ignored
-- exact - the compare will be an exact match vs the default behaviour of
function lib:Find(txt, startln, endln, ignoreleft, ignoreright, exact)
local searchFunction = FindDefault;
if (exact == true) then
searchFunction = FindExact;
end;
self:argCheck(txt, 2, "string", "number")
local t1, t2 = type(startln or 1), type(self:NumLines(endln))
if (t1 ~= "number" or t2 ~= "number") then print(t1, t2, (startln or 1),self:NumLines(endln)) end
for i=(startln or 1),self:NumLines(endln) do
if not ignoreleft then
local txtl = self.vars.Llines[i]:GetText()
if (txtl and searchFunction(txtl, txt)) then return string.find(txtl, txt) end
end
if not ignoreright then
local txtr = self.vars.Rlines[i]:GetText()
if (txtr and searchFunction(txtr, txt)) then return string.find(txtr, txt) end
end
end
end
-- Calls Find many times.
-- Args are passed directly to Find, t1-t10 replace the txt arg
-- Returns Find results for the first match found, if any
function lib:MultiFind(startln, endln, ignoreleft, ignoreright, t1,t2,t3,t4,t5,t6,t7,t8,t9,t10)
self:argCheck(t1, 6, "string", "number")
if t1 and self:Find(t1, startln, endln, ignoreleft, ignoreright) then return self:Find(t1, startln, endln, ignoreleft, ignoreright)
elseif t2 then return self:MultiFind(startln, endln, ignoreleft, ignoreright, t2,t3,t4,t5,t6,t7,t8,t9,t10) end
end
local deformat
-- If text is found on tooltip then results of deformat:Deformat are returned
-- Args:
-- txt - The text string to deformat and serach for
-- startln - First tooltip line to check, default 1
-- endln - Last line to test, default 30
-- ignoreleft / ignoreright - Causes text on one side of the tooltip to be ignored
function lib:FindDeformat(txt, startln, endln, ignoreleft, ignoreright)
self:argCheck(txt, 2, "string", "number")
if not deformat then
self:assert(AceLibrary:HasInstance("Deformat-2.0"), "FindDeformat requires Deformat-2.0 to be available")
deformat = AceLibrary("Deformat-2.0")
end
for i=(startln or 1),self:NumLines(endln) do
if not ignoreleft then
local txtl = self.vars.Llines[i]:GetText()
if (txtl and deformat(txtl, txt)) then return deformat(txtl, txt) end
end
if not ignoreright then
local txtr = self.vars.Rlines[i]:GetText()
if (txtr and deformat(txtr, txt)) then return deformat(txtr, txt) end
end
end
end
-- Returns a table of strings pulled from the tooltip, or nil if no strings in tooltip
-- Args:
-- startln - First tooltip line to check, default 1
-- endln - Last line to test, default 30
-- ignoreleft / ignoreright - Causes text on one side of the tooltip to be ignored
function lib:GetText(startln, endln, ignoreleft, ignoreright)
self:InitCompost()
local retval
for i=(startln or 1),(endln or 30) do
local txtl, txtr
if not ignoreleft then txtl = self.vars.Llines[i]:GetText() end
if not ignoreright then txtr = self.vars.Rlines[i]:GetText() end
if txtl or txtr then
if not retval then retval = self.vars.compost and self.vars.compost:Acquire() or {} end
local t = self.vars.compost and self.vars.compost:Acquire(txtl, txtr) or {txtl, txtr}
table.insert(retval, t)
end
end
return retval
end
-- Returns the text from a specific line (both left and right unless second arg is true)
-- Args:
-- line - the line number you wish to retrieve
-- getright - if passed the right line will be returned, if not the left will be returned
function lib:GetLine(line, getright)
self:argCheck(line, 2, "number")
if self.vars.tooltip:NumLines() < line then return end
if getright then return self.vars.Rlines[line] and self.vars.Rlines[line]:GetText()
elseif self.vars.Llines[line] then
return self.vars.Llines[line]:GetText(), self.vars.Rlines[line]:GetText()
end
end
-----------------------------------
-- Set tooltip methods --
-----------------------------------
-- These methods are designed to immitate the GameTooltip API
local testmethods = {
SetAction = function(id) return HasAction(id) end,
}
local gettrue = function() return true end
function lib:CreateSetMethods()
for _,m in pairs(methods) do
local meth = m
local func = testmethods[meth] or gettrue
self[meth] = function(self,a1,a2,a3,a4)
self:Erase()
if not func(a1,a2,a3,a4) then return end
return self:pcall(self.vars.tooltip[meth], self.vars.tooltip,a1,a2,a3,a4) end
end
end
--------------------------------
-- Load this bitch! --
--------------------------------
AceLibrary:Register(lib, vmajor, vminor, activate)
lib = nil

View File

@ -0,0 +1,393 @@
--[[
Name: RosterLib-2.0
Revision: $Revision: 16213 $
X-ReleaseDate: $Date: 2006-08-10 08:55:29 +0200 (Thu, 10 Aug 2006) $
Author: Maia (maia.proudmoore@gmail.com)
Website: http://wiki.wowace.com/index.php/RosterLib-2.0
Documentation: http://wiki.wowace.com/index.php/RosterLib-2.0_API_Documentation
SVN: http://svn.wowace.com/root/trunk/RosterLib-2.0/
Description: party/raid roster management
Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0
]]
local MAJOR_VERSION = "RosterLib-2.0"
local MINOR_VERSION = "$Revision: 16213 $"
if not AceLibrary then error(vmajor .. " 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 updatedUnits = {}
local unknownUnits = {}
local RosterLib = {}
local roster
------------------------------------------------
-- activate, enable, disable
------------------------------------------------
local function print(text)
ChatFrame3:AddMessage(text)
end
local function activate(self, oldLib, oldDeactivate)
RosterLib = self
if oldLib then
self.roster = oldLib.roster
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
AceEvent = instance
AceEvent:embed(self)
self:UnregisterAllEvents()
self:CancelAllScheduledEvents()
if AceEvent:IsFullyInitialized() then
self:AceEvent_FullyInitialized()
else
self:RegisterEvent("AceEvent_FullyInitialized", "AceEvent_FullyInitialized", true)
end
elseif major == "Compost-2.0" then
Compost = instance
end
end
function RosterLib:Enable()
-- not used anymore, but as addons still might be calling this method, we're keeping it.
end
function RosterLib:Disable()
-- not used anymore, but as addons still might be calling this method, we're keeping it.
end
------------------------------------------------
-- Internal functions
------------------------------------------------
function RosterLib:AceEvent_FullyInitialized()
self:TriggerEvent("RosterLib_Enabled")
self:RegisterEvent("RAID_ROSTER_UPDATE","ScanFullRoster")
self:RegisterEvent("PARTY_MEMBERS_CHANGED","ScanFullRoster")
self:RegisterEvent("UNIT_PET","ScanPet")
self:ScanFullRoster()
end
------------------------------------------------
-- Unit iterator
------------------------------------------------
local playersent, petsent, unitcount, petcount, pmem, rmem, unit
local function NextUnit()
-- STEP 1: pet
if not petsent then
petsent = true
if rmem == 0 then
unit = "pet"
if UnitExists(unit) then return unit end
end
end
-- STEP 2: player
if not playersent then
playersent = true
if rmem == 0 then
unit = "player"
if UnitExists(unit) then return unit end
end
end
-- STEP 3: raid units
if rmem > 0 then
-- STEP 3a: pet units
for i = petcount, rmem do
unit = string.format("raidpet%d", i)
petcount = petcount + 1
if UnitExists(unit) then return unit end
end
-- STEP 3b: player units
for i = unitcount, rmem do
unit = string.format("raid%d", i)
unitcount = unitcount + 1
if UnitExists(unit) then return unit end
end
-- STEP 4: party units
elseif pmem > 0 then
-- STEP 3a: pet units
for i = petcount, pmem do
unit = string.format("partypet%d", i)
petcount = petcount + 1
if UnitExists(unit) then return unit end
end
-- STEP 3b: player units
for i = unitcount, pmem do
unit = string.format("party%d", i)
unitcount = unitcount + 1
if UnitExists(unit) then return unit end
end
end
end
local function UnitIterator()
playersent, petsent, unitcount, petcount, pmem, rmem = false, false, 1, 1, GetNumPartyMembers(), GetNumRaidMembers()
return NextUnit
end
------------------------------------------------
-- Roster code
------------------------------------------------
function RosterLib:ScanFullRoster()
-- save all units we currently have, this way we can check who to remove from roster later.
local temp = Compost and Compost:Acquire() or {}
for name in pairs(roster) do
temp[name] = true
end
-- update data
for unitid in UnitIterator() do
local name = self:CreateOrUpdateUnit(unitid)
-- we successfully added a unit, so we don't need to remove it next step
if name then temp[name] = nil end
end
-- clear units we had in roster that either left the raid or are unknown for some reason.
for name in pairs(temp) do
self:RemoveUnit(name)
end
if Compost then Compost:Reclaim(temp) end
self:ProcessRoster()
end
function RosterLib:ScanPet(owner)
local unitid = self:GetPetFromOwner(owner)
if not unitid then
return
elseif 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)
end
end
else
self:CreateOrUpdateUnit(unitid)
end
self:ProcessRoster()
end
function RosterLib: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 string.find(owner,"raid") then
return string.gsub(owner, "raid", "raidpet")
elseif string.find(owner,"party") then
return string.gsub(owner, "party", "partypet")
elseif owner == "player" then
return "pet"
else
return nil
end
end
function RosterLib:ScanUnknownUnits()
local name
for unitid in pairs(unknownUnits) do
if UnitExists(unitid) then
name = self:CreateOrUpdateUnit(unitid)
else
unknownUnits[unitid] = nil
end
-- some pets never have a name. too bad for them, farewell!
if not name and string.find(unitid,"pet") then
unknownUnits[unitid] = nil
end
end
self:ProcessRoster()
end
function RosterLib:ProcessRoster()
if next(updatedUnits, nil) then
self:TriggerEvent("RosterLib_RosterChanged", updatedUnits)
for name in pairs(updatedUnits) do
local u = updatedUnits[name]
self:TriggerEvent("RosterLib_UnitChanged", u.unitid, u.name, u.class, u.subgroup, u.rank, u.oldname, u.oldunitid, u.oldclass, u.oldsubgroup, u.oldrank)
if Compost then Compost:Reclaim(updatedUnits[name]) end
updatedUnits[name] = nil
end
end
if next(unknownUnits, nil) then
self:CancelScheduledEvent("ScanUnknownUnits")
self:ScheduleEvent("ScanUnknownUnits",self.ScanUnknownUnits, 1, self)
end
end
function RosterLib:CreateOrUpdateUnit(unitid)
local old = nil
-- check for name
local name = UnitName(unitid)
if name and name ~= UNKNOWNOBJECT and name ~= UKNOWNBEING and not UnitIsCharmed(unitid) then
-- 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 string.find(unitid,"pet") then
if roster[name] and roster[name].class ~= "pet" then
return name
end
end
-- save old data if existing
if roster[name] then
old = Compost and Compost:Acquire() or {}
old.name = roster[name].name
old.unitid = roster[name].unitid
old.class = roster[name].class
old.rank = roster[name].rank
old.subgroup = roster[name].subgroup
old.online = roster[name].online
end
-- object
if not roster[name] then
roster[name] = Compost and Compost:Acquire() or {}
end
-- name
roster[name].name = name
-- unitid
roster[name].unitid = unitid
-- class
if string.find(unitid,"pet") then
roster[name].class = "PET"
else
_,roster[name].class = UnitClass(unitid)
end
-- subgroup and rank
if GetNumRaidMembers() > 0 then
local _,_,num = string.find(unitid, "(%d+)")
_,roster[name].rank,roster[name].subgroup = GetRaidRosterInfo(num)
else
roster[name].subgroup = 1
roster[name].rank = 0
end
-- online/offline status
roster[name].online = UnitIsConnected(unitid)
-- compare data
if not old
or roster[name].name ~= old.name
or roster[name].unitid ~= old.unitid
or roster[name].class ~= old.class
or roster[name].subgroup ~= old.subgroup
or roster[name].rank ~= old.rank
or roster[name].online ~= old.online
then
updatedUnits[name] = Compost and Compost:Acquire() or {}
updatedUnits[name].oldname = (old and old.name) or nil
updatedUnits[name].oldunitid = (old and old.unitid) or nil
updatedUnits[name].oldclass = (old and old.class) or nil
updatedUnits[name].oldsubgroup = (old and old.subgroup) or nil
updatedUnits[name].oldrank = (old and old.rank) or nil
updatedUnits[name].oldonline = (old and old.online) or nil
updatedUnits[name].name = roster[name].name
updatedUnits[name].unitid = roster[name].unitid
updatedUnits[name].class = roster[name].class
updatedUnits[name].subgroup = roster[name].subgroup
updatedUnits[name].rank = roster[name].rank
updatedUnits[name].online = roster[name].online
end
-- compost our table
if old and Compost then
Compost:Reclaim(old)
end
return name
else
unknownUnits[unitid] = true
return false
end
end
function RosterLib:RemoveUnit(name)
updatedUnits[name] = Compost and Compost:Acquire() or {}
updatedUnits[name].oldname = roster[name].name
updatedUnits[name].oldunitid = roster[name].unitid
updatedUnits[name].oldclass = roster[name].class
updatedUnits[name].oldsubgroup = roster[name].subgroup
updatedUnits[name].oldrank = roster[name].rank
if Compost then Compost:Reclaim(roster[name]) end
roster[name] = nil
end
------------------------------------------------
-- API
------------------------------------------------
function RosterLib:GetUnitIDFromName(name)
if roster[name] then
return roster[name].unitid
else
return nil
end
end
function RosterLib:GetUnitIDFromUnit(unit)
local name = UnitName(unit)
if name and roster[name] then
return roster[name].unitid
else
return nil
end
end
function RosterLib:GetUnitObjectFromName(name)
if roster[name] then
return roster[name]
else
return nil
end
end
function RosterLib:GetUnitObjectFromUnit(unit)
local name = UnitName(unit)
if roster[name] then
return roster[name]
else
return nil
end
end
function RosterLib:IterateRoster(pets)
local key
return function()
repeat
key = next(roster, key)
until (roster[key] == nil or pets or roster[key].class ~= "PET")
return roster[key]
end
end
AceLibrary:Register(RosterLib, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)