initial commit, update of grennon mail (postal), speedup for opening all mail and fixed the unread mail minimap icon issue

This commit is contained in:
Manuel Simon Hirsig
2015-09-24 18:31:40 +02:00
commit 607d79fb99
15 changed files with 6623 additions and 0 deletions
+961
View File
@@ -0,0 +1,961 @@
Postal = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceHook-2.0")
function Postal:OnInitialize()
tinsert(UISpecialFrames, "PostalInboxOpenAll")
-- Allows the mail frame to be pushed
if UIPanelWindows["MailFrame"] then
UIPanelWindows["MailFrame"].pushable = 1
else
UIPanelWindows["MailFrame"] = { area = "left", pushable = 1 }
end
-- Close FriendsFrame will close if you try to open a mail with mailframe+friendsframe open
if UIPanelWindows["FriendsFrame"] then
UIPanelWindows["FriendsFrame"].pushable = 2
else
UIPanelWindows["FriendsFrame"] = { area = "left", pushable = 2 }
end
MailItem1:SetPoint("TOPLEFT", "InboxFrame", "TOPLEFT", 48, -80)
for i = 1, 7 do
getglobal("MailItem" .. i .. "ExpireTime"):SetPoint("TOPRIGHT", "MailItem" .. i, "TOPRIGHT", 10, -4)
getglobal("MailItem" .. i):SetWidth(280)
end
POSTAL_NUMITEMBUTTONS = 21
Postal_BagLinks = {}
Postal_ScheduledStack = {}
Postal_SelectedItems = {}
Postal_PICKDELAY = 0.2
Postal_DELETEDELAY = 0.2
Postal_DELETEEVENTDELAY = 0.2
PostalFrame.num = 0
PanelTemplates_SetNumTabs(MailFrame, 3)
PostalForwardFrame.pickItem = {}
PostalForwardFrame.process = 0
PostalGlobalFrame.queue = {}
PostalGlobalFrame.update = 0
PostalGlobalFrame.total = 0
PostalGlobalFrame.sendmail = 0
PostalGlobalFrame.latency = 2.25
PostalTooltip:SetOwner(WorldFrame, "ANCHOR_NONE")
PostalInboxFrame.eventFunc = {}
end
function Postal:OnEnable()
self:RegisterEvent("MAIL_INBOX_UPDATE")
self:RegisterEvent("UI_ERROR_MESSAGE")
self:RegisterEvent("MAIL_SEND_SUCCESS")
self:RegisterEvent("MAIL_SEND_INFO_UPDATE")
self:RegisterEvent("MAIL_CLOSED")
self:RegisterEvent("BAG_UPDATE")
self:Hook("ContainerFrameItemButton_OnClick")
self:Hook("PickupContainerItem")
self:Hook("ContainerFrame_Update")
self:Hook("ClickSendMailItemButton")
self:HookScript(TradeFrame, "OnShow", "TF_Show")
self:Hook("InboxFrameItem_OnEnter")
self:Hook("MailFrameTab_OnClick")
self:Hook("InboxFrame_OnClick")
self:Hook("InboxFrame_Update")
self:Hook("CloseMail")
self:Hook("TakeInboxItem")
self:Hook("OpenMail_Reply")
oldTakeInboxMoney = OpenMailMoneyButton:GetScript("OnClick")
end
function Postal:MAIL_CLOSED()
Postal:ClearItems()
PostalGlobalFrame.total = 0
PostalGlobalFrame.queue = {}
-- Hides the minimap unread mail button if there are no unread mail on closing the mailbox.
-- Does not scan past the first 50 items since only the first 50 are viewable.
for i = 1, GetInboxNumItems() do
_, _, _, _, _, _, _, _, wasRead = GetInboxHeaderInfo(i)
if not wasRead then
return
end
end
MiniMapMailFrame:Hide()
end
function Postal:MAIL_SEND_SUCCESS()
POSTAL_CANSENDNEXT = 1
end
function Postal:ContainerFrameItemButton_OnClick(btn, ignore)
if self:GetItemFrame(this:GetParent():GetID(), this:GetID()) then
return
end
self.hooks["ContainerFrameItemButton_OnClick"].orig(btn, ignore)
self:UpdateItemButtons()
end
function Postal:PickupContainerItem(bag, item, special)
if (self:GetItemFrame(bag, item) or (Postal_addItem and Postal_addItem[1] == bag and Postal_addItem[2] == item)) and not special then
return
end
if not CursorHasItem() then
PostalFrame.bag = bag
PostalFrame.item = item
end
if IsAltKeyDown() and PostalFrame:IsVisible() and not CursorHasItem() then
local i
for i = 1, POSTAL_NUMITEMBUTTONS do
if not getglobal("PostalButton" .. i).item then
if self:ItemIsMailable(bag, item) then
Postal:Print("Postal: Cannot attach item.", 1, 0.5, 0)
return
end
self.hooks["PickupContainerItem"].orig(bag, item)
self:MailButton_OnClick(getglobal("PostalButton" .. i))
self:UpdateItemButtons()
return
end
end
elseif IsAltKeyDown() and SendMailFrame:IsVisible() and not CursorHasItem() then
self.hooks["PickupContainerItem"].orig(bag, item)
ClickSendMailItemButton()
return
elseif IsAltKeyDown() and TradeFrame:IsVisible() and not CursorHasItem() then
for i = 1, 6 do
if not GetTradePlayerItemLink(i) then
self.hooks["PickupContainerItem"].orig(bag, item)
ClickTradeButton(i)
return
end
end
elseif IsAltKeyDown() and not CursorHasItem() and (not TradeFrame or not TradeFrame:IsVisible()) and (not AuctionFrame or not AuctionFrame:IsVisible()) and UnitExists("target") and CheckInteractDistance("target", 2) and UnitIsFriend("player", "target") and UnitIsPlayer("target") then
InitiateTrade("target")
Postal_addItem = { bag, item, UnitName("target"), 2 }
for i = 1, NUM_CONTAINER_FRAMES do
if getglobal("ContainerFrame" .. i):IsVisible() then
ContainerFrame_Update(getglobal("ContainerFrame" .. i))
end
end
return
end
self.hooks["PickupContainerItem"].orig(bag, item)
self:UpdateItemButtons()
end
function Postal:MailFrameTab_OnClick(tab)
if not tab then
tab = this:GetID()
end
if tab == 3 then
PanelTemplates_SetTab(MailFrame, 3)
InboxFrame:Hide()
SendMailFrame:Hide()
PostalFrame:Show()
SendMailFrame.sendMode = "massmail"
MailFrameTopLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopLeft")
MailFrameTopRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopRight")
MailFrameBotLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-BotLeft")
MailFrameBotRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-BotRight")
MailFrameTopLeft:SetPoint("TOPLEFT", "MailFrame", "TOPLEFT", 2, -1)
return
else
PostalFrame:Hide()
end
self.hooks["MailFrameTab_OnClick"].orig(tab)
self:Forward_EnableForward()
end
function Postal:ClickSendMailItemButton()
if not GetSendMailItem() then
PostalFrame.mailbag = PostalFrame.bag
PostalFrame.mailitem = PostalFrame.item
end
self.hooks["ClickSendMailItemButton"].orig()
end
-- Handle the dragging of items
function Postal:MailButton_OnClick(button)
if not button then button = this end
if CursorHasItem() then
local bag = PostalFrame.bag
local item = PostalFrame.item
if not bag or not item then return end
if self:ItemIsMailable(bag, item) then
Postal:Print("Postal: Cannot attach item.", 1, 0.5, 0)
self.hooks["PickupContainerItem"].orig(bag, item)
return
end
self.hooks["PickupContainerItem"].orig(bag, item)
if this.bag and this.item then
-- There's already an item there
-- Pickup that item to replicate Send Mail's behaviour
self.hooks["PickupContainerItem"].orig(button.bag, button.item)
PostalFrame.bag = button.bag
PostalFrame.item = button.item
else
PostalFrame.bag = nil
PostalFrame.item = nil
end
local texture, count = GetContainerItemInfo(bag, item)
getglobal(button:GetName() .. "IconTexture"):Show()
getglobal(button:GetName() .. "IconTexture"):SetTexture(texture)
if count > 1 then
getglobal(button:GetName() .. "Count"):SetText(count)
getglobal(button:GetName() .. "Count"):Show()
else
getglobal(button:GetName() .. "Count"):Hide()
end
button.bag = bag
button.item = item
button.texture = texture
button.count = count
elseif button.item and button.bag then
self.hooks["PickupContainerItem"].orig(button.bag, button.item)
getglobal(button:GetName() .. "IconTexture"):Hide()
getglobal(button:GetName() .. "Count"):Hide()
PostalFrame.bag = button.bag
PostalFrame.item = button.item
button.item = nil
button.bag = nil
button.count = nil
button.texture = nil
end
local num = self:GetNumMails()
PostalFrame.num = num
self:CanSend(PostalNameEditBox)
if num == 0 then num = 1 end
MoneyFrame_Update("PostalCostMoneyFrame", GetSendMailPrice()*num)
for i = 1, NUM_CONTAINER_FRAMES do
if getglobal("ContainerFrame" .. i):IsVisible() then
ContainerFrame_Update(getglobal("ContainerFrame" .. i))
end
end
end
function Postal:ItemIsMailable(bag, item)
-- Make sure tooltip is cleared
for i = 1, 29 do
getglobal("PostalTooltipTextLeft" .. i):SetText("")
end
PostalTooltip:SetBagItem(bag, item)
for i = 1, PostalTooltip:NumLines() do
local text = getglobal("PostalTooltipTextLeft" .. i):GetText()
if text == ITEM_SOULBOUND or text == ITEM_BIND_QUEST or text == ITEM_CONJURED or text == ITEM_BIND_ON_PICKUP then
return 1
end
end
return nil
end
function Postal:UpdateItemButtons(frame)
local i
for i = 1, POSTAL_NUMITEMBUTTONS do
local btn = getglobal("PostalButton" .. i)
if not frame or btn ~= frame then
local texture, count
if btn.item and btn.bag then
texture, count = GetContainerItemInfo(btn.bag, btn.item)
end
if not texture then
getglobal(btn:GetName() .. "IconTexture"):Hide()
getglobal(btn:GetName() .. "Count"):Hide()
btn.item = nil
btn.bag = nil
btn.count = nil
btn.texture = nil
else
btn.count = count
btn.texture = texture
getglobal(btn:GetName() .. "IconTexture"):Show()
getglobal(btn:GetName() .. "IconTexture"):SetTexture(texture)
if count > 1 then
getglobal(btn:GetName() .. "Count"):Show()
getglobal(btn:GetName() .. "Count"):SetText(count)
else
getglobal(btn:GetName() .. "Count"):Hide()
end
end
end
end
end
function Postal:GetItemFrame(bag, item)
local i
for i = 1, POSTAL_NUMITEMBUTTONS do
local btn = getglobal("PostalButton" .. i)
if btn.item == item and btn.bag == bag then
return btn
end
end
return nil
end
function Postal:GetNumMails()
local i
local num = 0
for i = 1, POSTAL_NUMITEMBUTTONS do
local btn = getglobal("PostalButton" .. i)
if btn.item and btn.bag then
num = num + 1
end
end
return num
end
function Postal:ClearItems()
local i
local num = 0
for i = 1, POSTAL_NUMITEMBUTTONS do
local btn = getglobal("PostalButton" .. i)
btn.item = nil
btn.count = nil
btn.bag = nil
btn.texture = nil
end
self:UpdateItemButtons()
PostalMailButton:Disable()
PostalNameEditBox:SetText("")
PostalSubjectEditBox:SetText("")
PostalStatusText:SetText("")
PostalAbortButton:Hide()
PostalAcceptSendFrame:Hide()
end
function Postal:CanSend(eb)
if not eb then eb = this end
if strlen(eb:GetText()) > 0 and PostalFrame.num > 0 and GetSendMailPrice()*PostalFrame.num <= GetMoney() then
PostalMailButton:Enable()
else
PostalMailButton:Disable()
end
end
function Postal:SendMail()
for key, val in this.queue do
PostalStatusText:SetText(format(POSTAL_SENDING, key, this.total))
PostalAbortButton:Show()
if GetSendMailItem() and PostalFrame.mailbag and PostalFrame.mailitem then
-- There's already an item in the slot
ClickSendMailItemButton()
self.hooks["PickupContainerItem"].orig(PostalFrame.mailbag, PostalFrame.mailitem)
PostalFrame.mailbag = nil
PostalFrame.mailitem = nil
elseif CursorHasItem() and PostalFrame.bag and PostalFrame.item then
PickupContainerItem(PostalFrame.bag, PostalFrame.item)
PostalFrame.bag = nil
PostalFrame.item = nil
end
self.hooks["PickupContainerItem"].orig(val.bag, val.item)
ClickSendMailItemButton()
local name, useless, count = GetSendMailItem()
if not name then
Postal:Print("Postal: " .. POSTAL_ERROR, 1, 0, 0)
else
local subjectstr = PostalSubjectEditBox:GetText()
if strlen(subjectstr) > 0 then
subjectstr = subjectstr .. " "
end
if count > 1 then
subjectstr = subjectstr .. "[" .. name .. " x" .. count .. "]"
else
subjectstr = subjectstr .. "[" .. name .. "]"
end
SendMail(val.to, subjectstr, format(POSTAL_ITEMNUM, key, this.total))
end
PostalGlobalFrame.queue[key] = nil
return
end
PostalStatusText:SetText(format(POSTAL_DONESENDING, this.total))
PostalAbortButton:Hide()
PostalGlobalFrame:Hide()
PostalGlobalFrame.total = 0
PostalGlobalFrame.queue = {}
end
function Postal:FillItemTable()
local arr = {}
for i = 1, POSTAL_NUMITEMBUTTONS do
local btn = getglobal("PostalButton" .. i)
if btn.item and btn.bag then
tinsert(arr, { ["item"] = btn.item, ["bag"] = btn.bag, ["to"] = PostalNameEditBox:GetText() })
end
end
return arr
end
function Postal:ProcessQueue(elapsed)
if not POSTAL_CANSENDNEXT then
return
end
this.sendmail = this.sendmail + elapsed
if this.sendmail > 0.5 then
this.sendmail = 0
if this.total > 0 then
self:SendMail()
POSTAL_CANSENDNEXT = nil
end
end
end
function Postal:ContainerFrame_Update(frame)
self.hooks["ContainerFrame_Update"].orig(frame)
local id = frame:GetID()
if PostalFrame:IsVisible() then
local i
for i = 1, POSTAL_NUMITEMBUTTONS do
local btn = getglobal("PostalButton" .. i)
if btn.item and btn.bag then
if btn.bag == frame:GetID() then
SetItemButtonDesaturated(getglobal(frame:GetName() .. "Item" .. (frame.size-btn.item)+1), 1, 0.5, 0.5, 0.5)
end
end
end
end
if Postal_addItem and Postal_addItem[1] == frame:GetID() then
SetItemButtonDesaturated(getglobal(frame:GetName() .. "Item" .. (frame.size-Postal_addItem[2])+1), 1, 0.5, 0.5, 0.5)
end
end
function Postal:MAIL_SEND_INFO_UPDATE()
if not SendMailFrame:IsVisible() then return end
local name, useless, count = GetSendMailItem()
if name and strlen(SendMailSubjectEditBox:GetText()) == 0 then
if count > 1 then
name = name .. " x" .. count
end
SendMailSubjectEditBox:SetText(name)
end
end
function Postal:InboxFrameItem_OnEnter()
local didSetTooltip
if this.index then
if GetInboxItem(this.index) then
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetInboxItem(this.index)
didSetTooltip = 1
end
end
if not didSetTooltip then
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
end
if this.money then
GameTooltip:AddLine(ENCLOSED_MONEY, "", 1, 1, 1)
SetTooltipMoney(GameTooltip, this.money)
SetMoneyFrameColor("GameTooltipMoneyFrame", HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
elseif this.cod then
GameTooltip:AddLine(COD_AMOUNT, "", 1, 1, 1)
SetTooltipMoney(GameTooltip, this.cod)
if this.cod > GetMoney() then
SetMoneyFrameColor("GameTooltipMoneyFrame", RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b)
else
SetMoneyFrameColor("GameTooltipMoneyFrame", HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
end
end
if didSetTooltip and (this.money or this.cod) then
GameTooltip:SetHeight(GameTooltip:GetHeight()+getglobal("GameTooltipTextLeft" .. GameTooltip:NumLines()):GetHeight())
if GameTooltipMoneyFrame:IsVisible() then
GameTooltip:SetHeight(GameTooltip:GetHeight()+GameTooltipMoneyFrame:GetHeight())
end
end
GameTooltip:Show()
end
function Postal:TF_Show()
self.hooks[TradeFrame].OnShow.orig()
if Postal_addItem and not CursorHasItem() and UnitName("NPC") == Postal_addItem[3] then
self.hooks["PickupContainerItem"].orig(Postal_addItem[1], Postal_addItem[2])
ClickTradeButton(1)
end
Postal_addItem = nil
end
function Postal:Inbox_OnUpdate(elapsed)
if Postal_addItem then
Postal_addItem[4] = Postal_addItem[4] - elapsed
if Postal_addItem[4] <= 0 then
Postal_addItem = nil
for i = 1, NUM_CONTAINER_FRAMES do
if getglobal("ContainerFrame" .. i):IsVisible() then
ContainerFrame_Update(getglobal("ContainerFrame" .. i))
end
end
end
end
if this.num and this.timeout then
this.timeout = this.timeout - elapsed
if this.timeout <= 0 then
this.timeout = nil
if this.id[1] then
local val = this.id[1]
local success = Postal:PickMail(val, this.openSelected)
if success ~= 2 then
tremove(this.id, 1)
this.num = this.num - 1
end
if success == 1 then
for key, va in this.id do
if va > val then
this.id[key] = va - 1
end
end
this.lastVal = val
InboxFrame_Update()
else
this.timeout = Postal_PICKDELAY
this.lastVal = nil
end
if this.num == 0 then
this.num = nil
Postal:Inbox_DisableClicks(nil)
end
end
end
end
if this.delete then
this.delete[1] = this.delete[1] - elapsed
if this.delete[1] <= 0 then
local _, _, _, _, money, _, _, itemID, _, _, _ = GetInboxHeaderInfo(this.delete[2])
if money == 0 and not itemID then
GetInboxText(this.delete[2])
DeleteInboxItem(this.delete[2])
end
this.delete = nil
this.timeout = Postal_PICKDELAY
end
end
end
function Postal:MAIL_INBOX_UPDATE()
if PostalInboxFrame.eventDelete then
PostalInboxFrame.delete = { Postal_DELETEEVENTDELAY, PostalInboxFrame.eventDelete }
PostalInboxFrame.eventDelete = nil
end
end
function Postal:UI_ERROR_MESSAGE()
if event == "UI_ERROR_MESSAGE" and (arg1 == ERR_INV_FULL or arg1 == ERR_ITEM_MAX_COUNT) then
if this.num then
if arg1 == ERR_INV_FULL then
Postal:Inbox_Abort()
Postal:Print("Postal: Inventory full. Aborting.", 1, 0, 0)
elseif arg1 == ERR_ITEM_MAX_COUNT then
Postal:Print("Postal: You already have the maximum amount of that item. Skipping.", 1, 0, 0)
this.timeout = Postal_DELETEDELAY
if this.lastVal then
for key, va in this.id do
if va >= this.lastVal then
this.id[key] = va + 1
end
end
end
end
end
end
end
function Postal:Print(msg, r, g, b)
DEFAULT_CHAT_FRAME:AddMessage(msg, r, g, b)
end
function Postal:PickMail(id, openSelected)
if not id then
return 0
end
local _, _, sender, subject, money, CODAmount, _, hasItem = GetInboxHeaderInfo(id)
if CODAmount > 0 then
Postal:Print("Postal: Mail |c00FFFFFF" .. this.numMails - (this.num - 1) .. "|r/|c00FFFFFF" .. this.numMails .. "|r is Cash on Delivery, skipping.", 1, 0, 0)
return 0
elseif not hasItem and money == 0 and not openSelected then
Postal:Print("Postal: Mail |c00FFFFFF" .. this.numMails - (this.num - 1) .. "|r/|c00FFFFFF" .. this.numMails .. "|r has no money or items, skipping.", 1, 1, 0)
return 0
end
Postal:Print("Postal: Opening mail |c00FFFFFF" .. this.numMails - (this.num - 1) .. "|r/|c00FFFFFF" .. this.numMails .. "|r: \"|c00FFFFFF" .. ( subject or "<No Subject>" ) .. "|r\" from |c00FFFFFF" .. ( sender or "<Unknown Sender>" ) .. "|r.", 1, 1, 0)
local eventDelete
if hasItem then
self.hooks["TakeInboxItem"].orig(id)
eventDelete = 1
if money > 0 then
return 2
end
end
if money > 0 then
TakeInboxMoney(id)
eventDelete = 1
end
if eventDelete then
PostalInboxFrame.eventDelete = id
else
PostalInboxFrame.delete = { Postal_DELETEDELAY, id }
end
return 1
end
function Postal_Inbox_SetSelected()
local id = this:GetID() + (InboxFrame.pageNum - 1) * 7
if not this:GetChecked() then
for k, v in Postal_SelectedItems do
if v == id then
tremove(Postal_SelectedItems, k)
break
end
end
else
tinsert(Postal_SelectedItems, id)
end
end
function Postal_Inbox_OpenSelected(openAll)
Postal:Inbox_DisableClicks(1)
PostalInboxFrame.num = 0
PostalInboxFrame.timeout = Postal_PICKDELAY
PostalInboxFrame.id = {}
PostalInboxFrame.openSelected = not openAll
if openAll then
for i = 1, GetInboxNumItems() do
PostalInboxFrame.num = PostalInboxFrame.num + 1
tinsert(PostalInboxFrame.id, i)
end
else
for k, v in Postal_SelectedItems do
PostalInboxFrame.num = PostalInboxFrame.num + 1
tinsert(PostalInboxFrame.id, v)
end
end
PostalInboxFrame.numMails = PostalInboxFrame.num
Postal_SelectedItems = {}
end
function Postal:InboxFrame_Update()
self.hooks["InboxFrame_Update"].orig()
for i = 1, 7 do
local index = (i + (InboxFrame.pageNum - 1) * 7)
if index > GetInboxNumItems() then
getglobal("PostalBoxItem" .. i .. "CB"):Hide()
else
getglobal("PostalBoxItem" .. i .. "CB"):Show()
getglobal("PostalBoxItem" .. i .. "CB"):SetChecked(nil)
for k, v in Postal_SelectedItems do
if v == index then
getglobal("PostalBoxItem" .. i .. "CB"):SetChecked(1)
break
end
end
end
end
if PostalInboxFrame.num then
Postal:Inbox_DisableClicks(1, 1)
end
end
function Postal:Inbox_DisableClicks(disable, loopPrevention)
if disable then
for i = 1, 7 do
getglobal("MailItem" .. i .. "ButtonIcon"):SetDesaturated(1)
end
if not self:IsHooked("InboxFrame_OnClick") then self:Hook("InboxFrame_OnClick", "DummyFunction") end
else
for i = 1, 7 do
getglobal("MailItem" .. i .. "ButtonIcon"):SetDesaturated(nil)
end
if not loopPrevention then
InboxFrame_Update()
end
if self:IsHooked("InboxFrame_OnClick") then self:Unhook("InboxFrame_OnClick") end
end
end
function Postal:InboxFrame_OnClick()
this:SetChecked(nil)
end
function Postal:Inbox_Abort()
PostalInboxFrame.num = nil
PostalInboxFrame.timeout = nil
PostalInboxFrame.id = {}
Postal_SelectedItems = {}
Postal:Inbox_DisableClicks()
HideUIPanel(PostalInboxOpenAll)
end
function Postal:CloseMail()
self.hooks["CloseMail"].orig()
Postal:Inbox_Abort()
end
function Postal:TakeInboxItem(id)
self.hooks["TakeInboxItem"].orig(id)
local name = GetInboxItem(id)
tinsert(PostalForwardFrame.pickItem, name)
end
-- Mail Forwarding
function Postal:DisableAttachments(disable)
if disable then
OpenMailMoneyButtonIconTexture:SetDesaturated(1)
OpenMailPackageButtonIconTexture:SetDesaturated(1)
if not self:IsHooked(OpenMailMoneyButton, "OnClick") then self:HookScript(OpenMailMoneyButton, "OnClick", "DummyFunction") end
if not self:IsHooked(OpenMailPackageButton, "OnClick") then self:HookScript(OpenMailPackageButton, "OnClick", "DummyFunction") end
else
OpenMailMoneyButtonIconTexture:SetDesaturated(nil)
OpenMailPackageButtonIconTexture:SetDesaturated(nil)
if self:IsHooked(OpenMailMoneyButton, "OnClick") then self:Unhook(OpenMailMoneyButton, "OnClick") end
if self:IsHooked(OpenMailPackageButton, "OnClick") then self:Unhook(OpenMailPackageButton, "OnClick") end
end
end
function Postal:DummyFunction()
end
function Postal:OpenMail_Reply()
self.hooks["OpenMail_Reply"].orig()
SendMailMoneyCopper:SetText("")
SendMailMoneySilver:SetText("")
SendMailMoneyGold:SetText("")
end
function Postal:OpenReply()
OpenMail_Reply()
local _, _, _, subject, money = GetInboxHeaderInfo(InboxFrame.openMailID)
-- Money
local gold, silver, copper = "", "", ""
if money and money > 0 then
gold = floor(money / (COPPER_PER_SILVER * SILVER_PER_GOLD))
silver = floor((money - (gold * COPPER_PER_SILVER * SILVER_PER_GOLD)) / COPPER_PER_SILVER)
copper = mod(money, COPPER_PER_SILVER)
end
SendMailMoneyCopper:SetText(copper)
SendMailMoneySilver:SetText(silver)
SendMailMoneyGold:SetText(gold)
-- Items
local _, itemTexture, count = GetInboxItem(InboxFrame.openMailID)
SendMailPackageButton:SetNormalTexture(itemTexture)
if count > 1 then
SendMailPackageButtonCount:SetText(count)
else
SendMailPackageButtonCount:SetText("")
end
-- Text fields
SendMailNameEditBox:SetText("")
local subject = OpenMailSubject:GetText()
local prefix = "FW:".." "
if strsub(subject, 1, strlen(prefix)) ~= prefix then
subject = prefix..subject
end
SendMailSubjectEditBox:SetText(subject or "")
SendMailBodyEditBox:SetText(string.gsub(OpenMailBodyText:GetText() or "", "\n", "\n>"))
SendMailNameEditBox:SetFocus()
-- Set the send mode so the work flow can change accordingly
SendMailFrame.sendMode = "reply"
self:Forward_EnableForward(1)
end
function Postal:SendMailMailButton_OnClick()
local name = GetInboxItem(InboxFrame.openMailID)
local _, _, _, _, money = GetInboxHeaderInfo(InboxFrame.openMailID)
if name then
PostalForwardFrame.searchItem = name
PostalForwardFrame.forwardStep = 1
self.hooks["TakeInboxItem"].orig(InboxFrame.openMailID)
else
PostalForwardFrame.forwardStep = 2
if money and money > 0 then
SetSendMailMoney(money)
PostalForwardFrame.countDown = 2
oldTakeInboxMoney(InboxFrame.openMailID)
else
PostalForwardFrame.countDown = 0.5
end
end
SendMailMailButton:Disable()
end
function Postal:Forward_OnUpdate(elapsed)
if this.forwardStep and this.forwardStep > 1 then
if this.countDown then
this.countDown = this.countDown - elapsed
if this.countDown <= 0 then
if this.forwardStep == 2 then
this.countDown = 0.5
this.forwardStep = 3
-- Send the mail
SendMail(SendMailNameEditBox:GetText(), SendMailSubjectEditBox:GetText(), SendMailBodyEditBox:GetText())
SendMailMailButton:Disable()
elseif this.forwardStep == 3 then
-- Delete the old one
local _, _, _, _, money, _, _, itemID = GetInboxHeaderInfo(InboxFrame.openMailID)
if money == 0 and not itemID then
DeleteInboxItem(InboxFrame.openMailID)
end
self:MailFrameTab_OnClick(1)
HideUIPanel(OpenMailFrame)
this.countDown = nil
this.forwardStep = nil
end
end
end
end
this.process = this.process - elapsed
if this.process <= 0 then
this.process = 3
if getn(Postal_ScheduledStack) > 0 then
self:ProcessStack()
end
end
end
function Postal:InboxFrame_OnClick(id)
self.hooks["InboxFrame_OnClick"].orig(id)
local _, _, _, _, _, CODAmount = GetInboxHeaderInfo(id)
if CODAmount and CODAmount > 0 then
OpenMailForwardButton:Disable()
else
OpenMailForwardButton:Enable()
end
end
function Postal:Forward_EnableForward(enable)
if enable then
OpenMailForwardButton:Disable()
if not self:IsHooked(SendMailPackageButton, "OnEnter") then self:HookScript(SendMailPackageButton, "OnEnter", "SMPBOE") end
SendMailCODButton:Disable()
self:DisableAttachments(1)
if not self:IsHooked("SendMailMailButton_OnClick") then self:Hook("SendMailMailButton_OnClick") end
if not self:IsHooked("SendMailPackageButton_OnClick") then self:Hook("SendMailPackageButton_OnClick") end
else
OpenMailForwardButton:Enable()
if self:IsHooked(SendMailPackageButton, "OnEnter") then self:Unhook(SendMailPackageButton, "OnEnter") end
SendMailCODButton:Enable()
self:DisableAttachments(nil)
if self:IsHooked("SendMailMailButton_OnClick") then self:Unhook("SendMailMailButton_OnClick") end
if self:IsHooked("SendMailPackageButton_OnClick") then self:Unhook("SendMailPackageButton_OnClick") end
end
end
function Postal:SMPBOE()
GameTooltip:SetOwner(SendMailPackageButton, "ANCHOR_RIGHT")
GameTooltip:SetInboxItem(InboxFrame.openMailID)
end
function Postal:SendMailPackageButton_OnClick()
end
function Postal:Forward_AttachSlot(container, item)
PickupContainerItem(container, item)
ClickSendMailItemButton()
PostalForwardFrame.searchItem = nil
PostalForwardFrame.forwardStep = 2
PostalForwardFrame.countDown = 1.5
end
function Postal:BAG_UPDATE()
local old = {}
for k, v in Postal_BagLinks do
if type(v) == "table" then
old[k] = { }
for key, val in v do
old[k][key] = val
end
end
end
Postal_BagLinks = {}
for i = 0, 4 do
Postal_BagLinks[i] = {}
for y = 1, GetContainerNumSlots(i) do
local curr = GetContainerItemLink(i, y)
local _, _, name = string.find(( curr or "" ), "%[(.+)%]")
if name then
if PostalForwardFrame.searchItem then
if name and name == PostalForwardFrame.searchItem and not old[i][y] then
self:Forward_AttachSlot(i, y)
end
else
local _, _, name = string.find(( curr or "" ), "%[(.+)%]")
if name and name == PostalForwardFrame.pickItem[1] and not old[i][y] then
tremove(PostalForwardFrame.pickItem, 1)
for k, v in old do
local hasFound
for key, val in v do
if val == name and ( k ~= i or key ~= y ) then
local _,_, link = string.find((GetContainerItemLink(k, key) or ""), "(item:[%d:]+)")
if link then
local texture, itemCount = GetContainerItemInfo(k,key)
local tex, iC = GetContainerItemInfo(i, y)
local sName, sLink, iQuality, iLevel, sType, sSubType, iCount = GetItemInfo(link)
if sName and itemCount and iCount and iC then
if iCount >= (itemCount+iC) then
if getn(Postal_ScheduledStack) == 0 then
PostalForwardFrame.process = 2
end
tinsert(Postal_ScheduledStack, { i, y, k, key })
hasFound = 1
break
end
end
end
end
end
if hasFound then
break
end
end
end
end
Postal_BagLinks[i][y] = name
end
end
end
end
function Postal:ProcessStack()
local val = tremove(Postal_ScheduledStack, 1)
PickupContainerItem(val[1], val[2])
PickupContainerItem(val[3], val[4])
end
local oldSMMFfunc = SendMailMoneyFrame.onvalueChangedFunc
SendMailMoneyFrame.onvalueChangedFunc = function()
if oldSMMFfunc then
oldSMMFfunc()
end
local subject = SendMailSubjectEditBox:GetText()
if subject == "" or string.find(subject, "%[%d+G, %d+S, %d+C%]") then
local copper, silver, gold = SendMailMoneyFrameCopper:GetText(), SendMailMoneyFrameSilver:GetText(), SendMailMoneyFrameGold:GetText()
if not tonumber(copper) then
copper = 0
end
if not tonumber(silver) then
silver = 0
end
if not tonumber(gold) then
gold = 0
end
SendMailSubjectEditBox:SetText(format("[%sG, %sS, %sC]", gold, silver, copper))
end
end
+14
View File
@@ -0,0 +1,14 @@
## Interface: 11200
## Version: 1.0
## Title: Postal |cff7fff7f -Ace2-|r
## Notes: Postal
## Notes-zhCN: 批量邮件收取发送
## Author: Grennon
## X-Category: Interface
## OptionalDeps: Ace2
libs\AceLibrary\AceLibrary.lua
libs\AceOO\AceOO-2.0.lua
libs\AceEvent\AceEvent-2.0.lua
libs\AceAddon\AceAddon-2.0.lua
libs\AceHook\AceHook-2.0.lua
Postal.xml
+936
View File
@@ -0,0 +1,936 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
C:\Projects\WoW\Bin\Interface\FrameXML\UI.xsd">
<Script file="localization.lua"/>
<Script file="localization.ge.lua"/>
<Script file="localization.fr.lua"/>
<Script file="localization.cn.lua"/>
<Script file="Postal.lua"/>
<Button name="PostalButtonTemplate" virtual="true">
<Size>
<AbsDimension x="37" y="37"/>
</Size>
<Layers>
<Layer level="BACKGROUND">
<Texture file="Interface\Buttons\UI-Slot-Background">
<Size>
<AbsDimension x="39" y="39"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="-2" y="2"/>
</Offset>
</Anchor>
</Anchors>
<TexCoords left="0" right="0.640625" top="0" bottom="0.640625"/>
</Texture>
</Layer>
<Layer level="ARTWORK">
<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT">
<Anchors>
<Anchor point="BOTTOMRIGHT">
<Offset>
<AbsDimension x="-5" y="2"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
</Layer>
<Layer level="BORDER">
<Texture name="$parentIconTexture"/>
</Layer>
</Layers>
<Scripts>
<OnLoad>
this:RegisterForDrag("LeftButton")
</OnLoad>
<OnReceiveDrag>
Postal:MailButton_OnClick()
</OnReceiveDrag>
<OnDragStart>
Postal:MailButton_OnClick()
</OnDragStart>
<OnClick>
Postal:MailButton_OnClick()
</OnClick>
<OnEnter>
GameTooltip:SetOwner(this, "ANCHOR_RIGHT");
if ( this.item and this.bag ) then
GameTooltip:SetBagItem(this.bag,this.item);
else
GameTooltip:SetText(ATTACHMENT_TEXT, 1.0, 1.0, 1.0);
end
</OnEnter>
<OnLeave>
GameTooltip:Hide()
</OnLeave>
</Scripts>
<HighlightTexture alphaMode="ADD" file="Interface\Buttons\ButtonHilight-Square"/>
</Button>
<Frame name="PostalFrame" parent="MailFrame" hidden="true">
<Size>
<AbsDimension x="384" y="512"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT"/>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<FontString name="PostalTitleText" inherits="GameFontNormal" text="POSTAL_SEND">
<Size>
<AbsDimension x="224" y="14"/>
</Size>
<Anchors>
<Anchor point="CENTER">
<Offset>
<AbsDimension x="6" y="230"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
<FontString name="PostalStatusText" inherits="GameFontNormal">
<Size>
<AbsDimension x="224" y="14"/>
</Size>
<Anchors>
<Anchor point="BOTTOM" relativePoint="BOTTOM">
<Offset>
<AbsDimension x="0" y="125"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
<FontString justifyH="left" justifyV="top" name="PostalHelpText" inherits="GameFontNormal" text="POSTAL_HELP">
<Size>
<AbsDimension x="300" y="150"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="30" y="-105"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
<Texture name="PostalHorizontalBarLeft" file="Interface\ClassTrainerFrame\UI-ClassTrainer-HorizontalBar">
<Size>
<AbsDimension x="256" y="16"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="15" y="-350"/>
</Offset>
</Anchor>
</Anchors>
<TexCoords left="0" right="1.0" top="0" bottom="0.25"/>
</Texture>
<Texture file="Interface\ClassTrainerFrame\UI-ClassTrainer-HorizontalBar">
<Size>
<AbsDimension x="75" y="16"/>
</Size>
<Anchors>
<Anchor point="LEFT" relativeTo="PostalHorizontalBarLeft" relativePoint="RIGHT">
<Offset>
<AbsDimension x="0" y="0"/>
</Offset>
</Anchor>
</Anchors>
<TexCoords left="0" right="0.29296875" top="0.25" bottom="0.5"/>
</Texture>
</Layer>
</Layers>
<Frames>
<EditBox name="PostalNameEditBox" letters="12" historyLines="0" autoFocus="false">
<Size>
<AbsDimension x="122" y="20"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="105" y="-46"/>
</Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<FontString inherits="GameFontNormal" text="MAIL_TO_LABEL" justifyH="RIGHT">
<Anchors>
<Anchor point="RIGHT" relativePoint="LEFT">
<Offset>
<AbsDimension x="-12" y="0"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
<Texture name="$parentLeft" file="Interface\Common\Common-Input-Border">
<Size>
<AbsDimension x="8" y="20"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="-8" y="0"/>
</Offset>
</Anchor>
</Anchors>
<TexCoords left="0" right="0.0625" top="0" bottom="0.625"/>
</Texture>
<Texture name="$parentMiddle" file="Interface\Common\Common-Input-Border">
<Size>
<AbsDimension x="100" y="20"/>
</Size>
<Anchors>
<Anchor point="LEFT" relativeTo="$parentLeft" relativePoint="RIGHT"/>
</Anchors>
<TexCoords left="0.0625" right="0.9375" top="0" bottom="0.625"/>
</Texture>
<Texture name="$parentRight" file="Interface\Common\Common-Input-Border">
<Size>
<AbsDimension x="8" y="20"/>
</Size>
<Anchors>
<Anchor point="LEFT" relativeTo="$parentMiddle" relativePoint="RIGHT"/>
</Anchors>
<TexCoords left="0.9375" right="1.0" top="0" bottom="0.625"/>
</Texture>
</Layer>
</Layers>
<Scripts>
<OnTabPressed>
PostalSubjectEditBox:SetFocus()
</OnTabPressed>
<OnEditFocusLost>
this:HighlightText(0, 0)
</OnEditFocusLost>
<OnChar>
SendMailFrame_SendeeAutocomplete()
</OnChar>
<OnEnterPressed>
PostalSubjectEditBox:SetFocus()
</OnEnterPressed>
<OnEscapePressed>
PostalNameEditBox:ClearFocus()
</OnEscapePressed>
<OnTextChanged>
Postal:CanSend()
</OnTextChanged>
</Scripts>
<FontString inherits="ChatFontNormal"/>
</EditBox>
<Frame name="PostalCostMoneyFrame" inherits="SmallMoneyFrameTemplate">
<Anchors>
<Anchor point="TOPRIGHT">
<Offset>
<AbsDimension x="-46" y="-48"/>
</Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<FontString inherits="GameFontNormal" text="SEND_MAIL_COST">
<Anchors>
<Anchor point="RIGHT" relativePoint="LEFT">
<Offset>
<AbsDimension x="-3" y="0"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>
SmallMoneyFrame_OnLoad()
MoneyFrame_SetType("STATIC")
MoneyFrame_Update("PostalCostMoneyFrame", GetSendMailPrice())
</OnLoad>
</Scripts>
</Frame>
<EditBox name="PostalSubjectEditBox" letters="64" historyLines="0" autoFocus="false">
<Size>
<AbsDimension x="237" y="20"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT" relativeTo="PostalNameEditBox" relativePoint="BOTTOMLEFT">
<Offset>
<AbsDimension x="0" y="-3"/>
</Offset>
</Anchor>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<FontString inherits="GameFontNormal" text="MAIL_SUBJECT_LABEL" justifyH="RIGHT">
<Anchors>
<Anchor point="RIGHT" relativePoint="LEFT">
<Offset>
<AbsDimension x="-12" y="0"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
<Texture name="$parentLeft" file="Interface\Common\Common-Input-Border">
<Size>
<AbsDimension x="8" y="20"/>
</Size>
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="-8" y="0"/>
</Offset>
</Anchor>
</Anchors>
<TexCoords left="0" right="0.0625" top="0" bottom="0.625"/>
</Texture>
<Texture name="$parentMiddle" file="Interface\Common\Common-Input-Border">
<Size>
<AbsDimension x="221" y="20"/>
</Size>
<Anchors>
<Anchor point="LEFT" relativeTo="$parentLeft" relativePoint="RIGHT"/>
</Anchors>
<TexCoords left="0.0625" right="0.9375" top="0" bottom="0.625"/>
</Texture>
<Texture name="$parentRight" file="Interface\Common\Common-Input-Border">
<Size>
<AbsDimension x="8" y="20"/>
</Size>
<Anchors>
<Anchor point="LEFT" relativeTo="$parentMiddle" relativePoint="RIGHT"/>
</Anchors>
<TexCoords left="0.9375" right="1.0" top="0" bottom="0.625"/>
</Texture>
</Layer>
</Layers>
<Scripts>
<OnTabPressed>
PostalNameEditBox:SetFocus()
</OnTabPressed>
<OnEscapePressed>
PostalSubjectEditBox:ClearFocus()
</OnEscapePressed>
</Scripts>
<FontString inherits="ChatFontNormal"/>
</EditBox>
<Frame name="PostalMoneyFrame" inherits="SmallMoneyFrameTemplate">
<Anchors>
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMLEFT">
<Offset>
<AbsDimension x="183" y="84"/>
</Offset>
</Anchor>
</Anchors>
</Frame>
<Button name="PostalCancelButton" inherits="UIPanelButtonTemplate" text="CANCEL">
<Size>
<AbsDimension x="80" y="22"/>
</Size>
<Anchors>
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT">
<Offset>
<AbsDimension x="-39" y="80"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
HideUIPanel(MailFrame)
</OnClick>
</Scripts>
</Button>
<Button name="PostalMailButton" inherits="UIPanelButtonTemplate" text="SEND_LABEL">
<Size>
<AbsDimension x="80" y="22"/>
</Size>
<Anchors>
<Anchor point="RIGHT" relativeTo="SendMailCancelButton" relativePoint="LEFT">
<Offset>
<AbsDimension x="0" y="0"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
PostalAcceptSendFrame:Show()
</OnClick>
</Scripts>
</Button>
<Button name="PostalAbortButton" hidden="true" inherits="UIPanelButtonTemplate" text="POSTAL_ABORT">
<Size>
<AbsDimension x="80" y="22"/>
</Size>
<Anchors>
<Anchor point="BOTTOM" relativePoint="BOTTOM">
<Offset>
<AbsDimension x="0" y="105"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
PostalStatusText:SetText(format(POSTAL_ABORTED, PostalGlobalFrame.total-(getn(PostalGlobalFrame.queue)-1), PostalGlobalFrame.total));
PostalGlobalFrame.queue = { };
PostalGlobalFrame.total = 0;
PostalGlobalFrame:Hide();
</OnClick>
</Scripts>
</Button>
<Button name="PostalButton1" inherits="PostalButtonTemplate" id="1" hidden="false">
<Anchors>
<Anchor point="TOPLEFT">
<Offset>
<AbsDimension x="30" y="-222"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton2" inherits="PostalButtonTemplate" id="2" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton1">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton3" inherits="PostalButtonTemplate" id="3" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton2">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton4" inherits="PostalButtonTemplate" id="4" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton3">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton5" inherits="PostalButtonTemplate" id="5" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton4">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton6" inherits="PostalButtonTemplate" id="6" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton5">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton7" inherits="PostalButtonTemplate" id="7" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton6">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton8" inherits="PostalButtonTemplate" id="8" hidden="false">
<Anchors>
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="PostalButton1">
<Offset>
<AbsDimension x="0" y="-8"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton9" inherits="PostalButtonTemplate" id="9" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton8">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton10" inherits="PostalButtonTemplate" id="10" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton9">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton11" inherits="PostalButtonTemplate" id="11" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton10">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton12" inherits="PostalButtonTemplate" id="12" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton11">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton13" inherits="PostalButtonTemplate" id="13" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton12">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton14" inherits="PostalButtonTemplate" id="14" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton13">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton15" inherits="PostalButtonTemplate" id="15" hidden="false">
<Anchors>
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="PostalButton8">
<Offset>
<AbsDimension x="0" y="-8"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton16" inherits="PostalButtonTemplate" id="16" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton15">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton17" inherits="PostalButtonTemplate" id="17" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton16">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton18" inherits="PostalButtonTemplate" id="18" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton17">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton19" inherits="PostalButtonTemplate" id="19" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton18">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton20" inherits="PostalButtonTemplate" id="20" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton19">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
<Button name="PostalButton21" inherits="PostalButtonTemplate" id="21" hidden="false">
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="PostalButton20">
<Offset>
<AbsDimension x="8" y="0"/>
</Offset>
</Anchor>
</Anchors>
</Button>
</Frames>
<Scripts>
<OnShow>
PostalNameEditBox:SetFocus()
</OnShow>
</Scripts>
</Frame>
<Button name="MailFrameTab3" inherits="FriendsFrameTabTemplate" id="3" parent="MailFrame" text="Mass Mail">
<Anchors>
<Anchor point="LEFT" relativeTo="MailFrameTab2" relativePoint="RIGHT">
<Offset>
<AbsDimension x="-8" y="0"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
Postal:MailFrameTab_OnClick()
</OnClick>
</Scripts>
</Button>
<Frame name="PostalAcceptSendFrame" toplevel="true" frameStrata="DIALOG" movable="true" enableMouse="true" hidden="true" parent="PostalFrame">
<Size>
<AbsDimension x="400" y="150"/>
</Size>
<Anchors>
<Anchor point="CENTER" relativeTo="UIParent"/>
</Anchors>
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
<BackgroundInsets>
<AbsInset left="11" right="12" top="12" bottom="11"/>
</BackgroundInsets>
<TileSize>
<AbsValue val="32"/>
</TileSize>
<EdgeSize>
<AbsValue val="32"/>
</EdgeSize>
</Backdrop>
<Layers>
<Layer level="ARTWORK">
<Texture name="$parentHeaderTexture" file="Interface\DialogFrame\UI-DialogBox-Header">
<Size>
<AbsDimension x="256" y="64"/>
</Size>
<Anchors>
<Anchor point="TOP">
<Offset>
<AbsDimension x="0" y="12"/>
</Offset>
</Anchor>
</Anchors>
</Texture>
<FontString inherits="GameFontNormal" text="POSTAL_SEND">
<Anchors>
<Anchor point="TOP" relativeTo="$parentHeaderTexture">
<Offset>
<AbsDimension x="0" y="-14"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
<FontString name="$parentInfo" justifyV="top" inherits="GameFontNormal" text="POSTAL_SENDINFO">
<Size>
<AbsDimension x="350" y="32"/>
</Size>
<Anchors>
<Anchor point="TOP">
<Offset>
<AbsDimension x="0" y="-78"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
<FontString name="$parentInfoString" justifyV="top" inherits="GameFontNormal" text="POSTAL_SENDINFO2">
<Size>
<AbsDimension x="350" y="12"/>
</Size>
<Anchors>
<Anchor point="TOP">
<Offset>
<AbsDimension x="0" y="-30"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
<FontString name="$parentInfoItems" justifyV="top" inherits="GameFontNormal" text="">
<Size>
<AbsDimension x="350" y="12"/>
</Size>
<Anchors>
<Anchor point="TOP" relativeTo="$parentInfoString" relativePoint="BOTTOM">
<Offset>
<AbsDimension x="0" y="-2"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
</Layer>
</Layers>
<Frames>
<Frame name="$parentMoneyFrame" inherits="SmallMoneyFrameTemplate">
<Anchors>
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentInfo">
<Offset>
<AbsDimension x="0" y="5"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnLoad>
SmallMoneyFrame_OnLoad();
MoneyFrame_SetType("STATIC");
MoneyFrame_Update(this:GetName(), GetSendMailPrice())
</OnLoad>
</Scripts>
</Frame>
<Button name="$parentSendButton" hidden="false" inherits="GameMenuButtonTemplate" text="POSTAL_SENDBUTTON">
<Size>
<AbsDimension x="60" y="21"/>
</Size>
<Anchors>
<Anchor point="BOTTOM" relativePoint="BOTTOM">
<Offset>
<AbsDimension x="-32" y="8"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
PostalGlobalFrame.queue = Postal:FillItemTable();
PostalGlobalFrame.total = getn(PostalGlobalFrame.queue);
Postal:ClearItems();
PostalGlobalFrame:Show();
this:GetParent():Hide();
POSTAL_CANSENDNEXT = 1
</OnClick>
</Scripts>
</Button>
<Button name="$parentCancelButton" hidden="false" inherits="GameMenuButtonTemplate" text="POSTAL_CANCELBUTTON">
<Size>
<AbsDimension x="60" y="21"/>
</Size>
<Anchors>
<Anchor point="BOTTOM" relativePoint="BOTTOM">
<Offset>
<AbsDimension x="32" y="8"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
this:GetParent():Hide()
</OnClick>
</Scripts>
</Button>
</Frames>
<Scripts>
<OnShow>
getglobal(this:GetName() .. "InfoItems"):SetText(PostalFrame.num .. " " .. POSTAL_ITEMS);
MoneyFrame_Update(this:GetName() .. "MoneyFrame", PostalFrame.num*GetSendMailPrice())
</OnShow>
</Scripts>
</Frame>
<Frame name="PostalInboxFrame" parent="UIParent">
<Scripts>
<OnUpdate>
Postal:Inbox_OnUpdate(arg1)
</OnUpdate>
</Scripts>
</Frame>
<CheckButton name="PostalBoxItemCBTemplate" hidden="true" virtual="true" inherits="OptionsCheckButtonTemplate">
<HitRectInsets>
<AbsInset left="0" right="0" top="0" bottom="0"/>
</HitRectInsets>
<Size>
<AbsDimension x="24" y="24"/>
</Size>
<Anchors>
<Anchor point="RIGHT" relativePoint="LEFT">
<Offset>
<AbsDimension x="1" y="0"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
Postal_Inbox_SetSelected()
</OnClick>
</Scripts>
</CheckButton>
<CheckButton name="PostalBoxItem1CB" id="1" hidden="false" parent="MailItem1" inherits="PostalBoxItemCBTemplate"/>
<CheckButton name="PostalBoxItem2CB" id="2" hidden="false" parent="MailItem2" inherits="PostalBoxItemCBTemplate"/>
<CheckButton name="PostalBoxItem3CB" id="3" hidden="false" parent="MailItem3" inherits="PostalBoxItemCBTemplate"/>
<CheckButton name="PostalBoxItem4CB" id="4" hidden="false" parent="MailItem4" inherits="PostalBoxItemCBTemplate"/>
<CheckButton name="PostalBoxItem5CB" id="5" hidden="false" parent="MailItem5" inherits="PostalBoxItemCBTemplate"/>
<CheckButton name="PostalBoxItem6CB" id="6" hidden="false" parent="MailItem6" inherits="PostalBoxItemCBTemplate"/>
<CheckButton name="PostalBoxItem7CB" id="7" hidden="false" parent="MailItem7" inherits="PostalBoxItemCBTemplate"/>
<Button name="PostalInboxOpenSelected" parent="InboxFrame" inherits="UIPanelButtonTemplate" text="POSTAL_INBOX_OPENSELECTED">
<Size>
<AbsDimension x="120" y="25"/>
</Size>
<Anchors>
<Anchor relativePoint="TOP" point="RIGHT">
<Offset>
<AbsDimension x="5" y="-53"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
Postal_Inbox_OpenSelected()
</OnClick>
</Scripts>
</Button>
<Button name="PostalInboxOpenAllButton" parent="InboxFrame" inherits="UIPanelButtonTemplate" text="POSTAL_INBOX_OPENALL">
<Size>
<AbsDimension x="120" y="25"/>
</Size>
<Anchors>
<Anchor relativePoint="TOP" point="LEFT">
<Offset>
<AbsDimension x="10" y="-53"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
ShowUIPanel(PostalInboxOpenAll)
</OnClick>
</Scripts>
</Button>
<Frame name="PostalInboxOpenAll" toplevel="true" frameStrata="DIALOG" movable="true" enableMouse="true" hidden="true" parent="MailFrame">
<Size>
<AbsDimension x="400" y="100"/>
</Size>
<Anchors>
<Anchor point="CENTER" relativeTo="UIParent"/>
</Anchors>
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
<BackgroundInsets>
<AbsInset left="11" right="12" top="12" bottom="11"/>
</BackgroundInsets>
<TileSize>
<AbsValue val="32"/>
</TileSize>
<EdgeSize>
<AbsValue val="32"/>
</EdgeSize>
</Backdrop>
<Layers>
<Layer level="ARTWORK">
<Texture name="$parentHeaderTexture" file="Interface\DialogFrame\UI-DialogBox-Header">
<Size>
<AbsDimension x="256" y="64"/>
</Size>
<Anchors>
<Anchor point="TOP">
<Offset>
<AbsDimension x="0" y="12"/>
</Offset>
</Anchor>
</Anchors>
</Texture>
<FontString inherits="GameFontNormal" text="POSTAL_INBOX_OPENALLTITLE">
<Anchors>
<Anchor point="TOP" relativeTo="$parentHeaderTexture">
<Offset>
<AbsDimension x="0" y="-14"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
<FontString name="$parentInfo" justifyV="top" inherits="GameFontNormal" text="POSTAL_INBOX_OPENALLCONFIRMATION">
<Size>
<AbsDimension x="350" y="32"/>
</Size>
<Anchors>
<Anchor point="CENTER">
<Offset>
<AbsDimension x="0" y="4"/>
</Offset>
</Anchor>
</Anchors>
</FontString>
</Layer>
</Layers>
<Frames>
<Button name="$parentOpenButton" hidden="false" inherits="GameMenuButtonTemplate" text="POSTAL_INBOX_OPENALL">
<Size>
<AbsDimension x="125" y="32"/>
</Size>
<Anchors>
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOM">
<Offset>
<AbsDimension x="-8" y="16"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
Postal_Inbox_OpenSelected(1);
HideUIPanel(this:GetParent())
</OnClick>
</Scripts>
</Button>
<Button name="$parentCancelButton" hidden="false" inherits="GameMenuButtonTemplate" text="POSTAL_CANCELBUTTON">
<Size>
<AbsDimension x="125" y="32"/>
</Size>
<Anchors>
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOM">
<Offset>
<AbsDimension x="8" y="16"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
HideUIPanel(this:GetParent())
</OnClick>
</Scripts>
</Button>
</Frames>
</Frame>
<!-- Mail forwarding -->
<Button name="OpenMailForwardButton" parent="OpenMailFrame" inherits="UIPanelButtonTemplate" text="Forward">
<Size>
<AbsDimension x="82" y="22"/>
</Size>
<Anchors>
<Anchor point="RIGHT" relativeTo="OpenMailReplyButton" relativePoint="LEFT">
<Offset>
<AbsDimension x="0" y="0"/>
</Offset>
</Anchor>
</Anchors>
<Scripts>
<OnClick>
Postal:OpenReply()
</OnClick>
</Scripts>
</Button>
<Frame name="PostalForwardFrame" parent="UIParent">
<Scripts>
<OnUpdate>
Postal:Forward_OnUpdate(arg1)
</OnUpdate>
</Scripts>
</Frame>
<Frame name="PostalGlobalFrame" parent="UIParent" hidden="true">
<Scripts>
<OnUpdate>
Postal:ProcessQueue(arg1)
</OnUpdate>
</Scripts>
</Frame>
<GameTooltip name="PostalTooltip" inherits="GameTooltipTemplate"></GameTooltip>
</Ui>
+728
View File
@@ -0,0 +1,728 @@
--[[
Name: AceAddon-2.0
Revision: $Rev: 10447 $
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/AceAddon-2.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceAddon-2.0
Description: Base for all Ace addons to inherit from.
Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, (optional) AceConsole-2.0
]]
local MAJOR_VERSION = "AceAddon-2.0"
local MINOR_VERSION = "$Revision: 10447 $"
-- 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 not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end
-- Localization
local STANDBY, TITLE, NOTES, VERSION, AUTHOR, DATE, CATEGORY, EMAIL, WEBSITE, CATEGORIES, ABOUT, PRINT_ADDON_INFO
if false then -- GetLocale() == "deDE"
else -- enUS
STANDBY = "|cffff5050(standby)|r"
TITLE = "Title"
NOTES = "Notes"
VERSION = "Version"
AUTHOR = "Author"
DATE = "Date"
CATEGORY = "Category"
EMAIL = "E-mail"
WEBSITE = "Website"
ABOUT = "About"
PRINT_ADDON_INFO = "Print out addon info"
CATEGORIES = {
["Action Bars"] = "Action Bars",
["Auction"] = "Auction",
["Audio"] = "Audio",
["Battlegrounds/PvP"] = "Battlegrounds/PvP",
["Buffs"] = "Buffs",
["Chat/Communication"] = "Chat/Communication",
["Druid"] = "Druid",
["Hunter"] = "Hunter",
["Mage"] = "Mage",
["Paladin"] = "Paladin",
["Priest"] = "Priest",
["Rogue"] = "Rogue",
["Shaman"] = "Shaman",
["Warlock"] = "Warlock",
["Warrior"] = "Warrior",
["Healer"] = "Healer",
["Tank"] = "Tank",
["Caster"] = "Caster",
["Combat"] = "Combat",
["Compilations"] = "Compilations",
["Data Export"] = "Data Export",
["Development Tools "] = "Development Tools ",
["Guild"] = "Guild",
["Frame Modification"] = "Frame Modification",
["Interface Enhancements"] = "Interface Enhancements",
["Inventory"] = "Inventory",
["Library"] = "Library",
["Map"] = "Map",
["Mail"] = "Mail",
["Miscellaneous"] = "Miscellaneous",
["Quest"] = "Quest",
["Raid"] = "Raid",
["Tradeskill"] = "Tradeskill",
["UnitFrame"] = "UnitFrame",
}
end
setmetatable(CATEGORIES, { __index = function(self, key) -- case-insensitive
local lowerKey = string.lower(key)
for k,v in CATEGORIES do
if string.lower(k) == lowerKey then
return v
end
end
end })
-- Create the library object
local AceOO = AceLibrary("AceOO-2.0")
local AceAddon = AceOO.Class()
local AceEvent
local AceConsole
local AceModuleCore
function AceAddon:ToString()
return "AceAddon"
end
local function print(text)
DEFAULT_CHAT_FRAME:AddMessage(text)
end
function AceAddon:ADDON_LOADED(name)
while table.getn(self.nextAddon) > 0 do
local addon = table.remove(self.nextAddon, 1)
table.insert(self.addons, addon)
if not self.addons[name] then
self.addons[name] = addon
end
self:InitializeAddon(addon, name)
end
end
local function RegisterOnEnable(self)
if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage then -- HACK
AceAddon.playerLoginFired = true
end
if AceAddon.playerLoginFired then
AceAddon.addonsStarted[self] = true
if (type(self.IsActive) ~= "function" or self:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(self) or AceModuleCore:IsModuleActive(self)) then
local current = self.class
while true do
if current == AceOO.Class then
break
end
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedEnable) == "function" then
mixin:OnEmbedEnable(self)
end
end
end
current = current.super
end
if type(self.OnEnable) == "function" then
self:OnEnable()
end
end
else
if not AceAddon.addonsToOnEnable then
AceAddon.addonsToOnEnable = {}
end
table.insert(AceAddon.addonsToOnEnable, self)
end
end
local function stripSpaces(text)
if type(text) == "string" then
return (string.gsub(string.gsub(text, "^%s*(.-)%s*$", "%1"), "%s%s+", " "))
end
return text
end
function AceAddon:InitializeAddon(addon, name)
if addon.name == nil then
addon.name = name
end
if GetAddOnMetadata then
-- TOC checks
if addon.title == nil then
addon.title = GetAddOnMetadata(name, "Title")
if addon.title then
local num = string.find(addon.title, " |cff7fff7f %-Ace2%-|r$")
if num then
addon.title = string.sub(addon.title, 1, num - 1)
end
addon.title = stripSpaces(addon.title)
end
end
if addon.notes == nil then
addon.notes = GetAddOnMetadata(name, "Notes")
addon.notes = stripSpaces(addon.notes)
end
if addon.version == nil then
addon.version = GetAddOnMetadata(name, "Version")
if addon.version then
if string.find(addon.version, "%$Revision: (%d+) %$") then
addon.version = string.gsub(addon.version, "%$Revision: (%d+) %$", "%1")
elseif string.find(addon.version, "%$Rev: (%d+) %$") then
addon.version = string.gsub(addon.version, "%$Rev: (%d+) %$", "%1")
elseif string.find(addon.version, "%$LastChangedRevision: (%d+) %$") then
addon.version = string.gsub(addon.version, "%$LastChangedRevision: (%d+) %$", "%1")
end
end
addon.version = stripSpaces(addon.version)
end
if addon.author == nil then
addon.author = GetAddOnMetadata(name, "Author")
addon.author = stripSpaces(addon.author)
end
if addon.date == nil then
addon.date = GetAddOnMetadata(name, "X-Date") or GetAddOnMetadata(name, "X-ReleaseDate")
if addon.date then
if string.find(addon.date, "%$Date: (.-) %$") then
addon.date = string.gsub(addon.date, "%$Date: (.-) %$", "%1")
elseif string.find(addon.date, "%$LastChangedDate: (.-) %$") then
addon.date = string.gsub(addon.date, "%$LastChangedDate: (.-) %$", "%1")
end
end
addon.date = stripSpaces(addon.date)
end
if addon.category == nil then
addon.category = GetAddOnMetadata(name, "X-Category")
addon.category = stripSpaces(addon.category)
end
if addon.email == nil then
addon.email = GetAddOnMetadata(name, "X-eMail") or GetAddOnMetadata(name, "X-Email")
addon.email = stripSpaces(addon.email)
end
if addon.website == nil then
addon.website = GetAddOnMetadata(name, "X-Website")
addon.website = stripSpaces(addon.website)
end
end
local current = addon.class
while true do
if current == AceOO.Class then
break
end
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedInitialize) == "function" then
mixin:OnEmbedInitialize(addon, name)
end
end
end
current = current.super
end
if type(addon.OnInitialize) == "function" then
addon:OnInitialize(name)
end
RegisterOnEnable(addon)
end
function AceAddon.prototype:PrintAddonInfo()
local x
if self.title then
x = "|cffffff7f" .. tostring(self.title) .. "|r"
elseif self.name then
x = "|cffffff7f" .. tostring(self.name) .. "|r"
else
x = "|cffffff7f<" .. tostring(self.class) .. " instance>|r"
end
if type(self.IsActive) == "function" then
if not self:IsActive() then
x = x .. " " .. STANDBY
end
end
if self.version then
x = x .. " - |cffffff7f" .. tostring(self.version) .. "|r"
end
if self.notes then
x = x .. " - " .. tostring(self.notes)
end
print(x)
if self.author then
print(" - |cffffff7f" .. AUTHOR .. ":|r " .. tostring(self.author))
end
if self.date then
print(" - |cffffff7f" .. DATE .. ":|r " .. tostring(self.date))
end
if self.category then
local category = CATEGORIES[self.category]
if category then
print(" - |cffffff7f" .. CATEGORY .. ":|r " .. category)
end
end
if self.email then
print(" - |cffffff7f" .. EMAIL .. ":|r " .. tostring(self.email))
end
if self.website then
print(" - |cffffff7f" .. WEBSITE .. ":|r " .. tostring(self.website))
end
end
local options
function AceAddon:GetAceOptionsDataTable(target)
if not options then
options = {
about = {
name = ABOUT,
desc = PRINT_ADDON_INFO,
type = "execute",
func = "PrintAddonInfo",
order = -1,
}
}
end
return options
end
function AceAddon:PLAYER_LOGIN()
self.playerLoginFired = true
if self.addonsToOnEnable then
while table.getn(self.addonsToOnEnable) > 0 do
local addon = table.remove(self.addonsToOnEnable, 1)
self.addonsStarted[addon] = true
if (type(addon.IsActive) ~= "function" or addon:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(addon) or AceModuleCore:IsModuleActive(addon)) then
local current = addon.class
while true do
if current == AceOO.Class then
break
end
if current.mixins then
for mixin in pairs(current.mixins) do
if type(mixin.OnEmbedEnable) == "function" then
mixin:OnEmbedEnable(addon)
end
end
end
current = current.super
end
if type(addon.OnEnable) == "function" then
addon:OnEnable()
end
end
end
self.addonsToOnEnable = nil
end
end
function AceAddon.prototype:Inject(t)
AceAddon:argCheck(t, 2, "table")
for k,v in pairs(t) do
self[k] = v
end
end
function AceAddon.prototype:init()
if not AceEvent then
error(MAJOR_VERSION .. " requires AceEvent-2.0", 4)
end
AceAddon.super.prototype.init(self)
self.super = self.class.prototype
AceAddon:RegisterEvent("ADDON_LOADED", "ADDON_LOADED", true)
table.insert(AceAddon.nextAddon, self)
end
function AceAddon.prototype:ToString()
local x
if type(self.title) == "string" then
x = self.title
elseif type(self.name) == "string" then
x = self.name
else
x = "<" .. tostring(self.class) .. " instance>"
end
if (type(self.IsActive) == "function" and not self:IsActive()) or (AceModuleCore and AceModuleCore:IsModule(addon) and AceModuleCore:IsModuleActive(addon)) then
x = x .. " " .. STANDBY
end
return x
end
AceAddon.new = function(self, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20)
local class = AceAddon:pcall(AceOO.Classpool, self, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20)
return class:new()
end
local function external(self, major, instance)
if major == "AceEvent-2.0" then
AceEvent = instance
AceEvent:embed(self)
self:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true)
elseif major == "AceConsole-2.0" then
AceConsole = instance
local slashCommands = { "/ace2" }
local _,_,_,enabled,loadable = GetAddOnInfo("Ace")
if not enabled or not loadable then
table.insert(slashCommands, "/ace")
end
local function listAddon(addon, depth)
if not depth then
depth = 0
end
local s = string.rep(" ", depth) .. " - " .. tostring(addon)
if addon.version then
s = s .. " - |cffffff7f" .. tostring(addon.version) .. "|r"
end
if addon.slashCommand then
s = s .. " |cffffff7f(" .. tostring(addon.slashCommand) .. ")|r"
end
print(s)
if type(addon.modules) == "table" then
local i = 0
for k,v in pairs(addon.modules) do
i = i + 1
if i == 6 then
print(string.rep(" ", depth + 1) .. " - more...")
break
else
listAddon(v, depth + 1)
end
end
end
end
local function listNormalAddon(i)
local name,_,_,enabled,loadable = GetAddOnInfo(i)
if not loadable then
enabled = false
end
if self.addons[name] then
local addon = self.addons[name]
if not AceCoreAddon or not AceCoreAddon:IsModule(addon) then
listAddon(addon)
end
else
local s = " - " .. tostring(GetAddOnMetadata(i, "Title") or name)
local version = GetAddOnMetadata(i, "Version")
if version then
if string.find(version, "%$Revision: (%d+) %$") then
version = string.gsub(version, "%$Revision: (%d+) %$", "%1")
elseif string.find(version, "%$Rev: (%d+) %$") then
version = string.gsub(version, "%$Rev: (%d+) %$", "%1")
elseif string.find(version, "%$LastChangedRevision: (%d+) %$") then
version = string.gsub(version, "%$LastChangedRevision: (%d+) %$", "%1")
end
s = s .. " - |cffffff7f" .. version .. "|r"
end
if not enabled then
s = s .. " |cffff0000(disabled)|r"
end
if IsAddOnLoadOnDemand(i) then
s = s .. " |cff00ff00[LoD]|r"
end
print(s)
end
end
local function mySort(alpha, bravo)
return tostring(alpha) < tostring(bravo)
end
AceConsole.RegisterChatCommand(self, slashCommands, {
desc = "AddOn development framework",
name = "Ace2",
type = "group",
args = {
about = {
desc = "Get information about Ace2",
name = "About",
type = "execute",
func = function()
print("|cffffff7fAce2|r - |cffffff7f2.0." .. string.gsub(MINOR_VERSION, "%$Revision: (%d+) %$", "%1") .. "|r - AddOn development framework")
print(" - |cffffff7f" .. AUTHOR .. ":|r Ace Development Team")
print(" - |cffffff7f" .. WEBSITE .. ":|r http://www.wowace.com/")
end
},
list = {
desc = "List addons",
name = "List",
type = "group",
args = {
ace2 = {
desc = "List addons using Ace2",
name = "Ace2",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
table.sort(self.addons, mySort)
for _,v in ipairs(self.addons) do
if not AceCoreAddon or not AceCoreAddon:IsModule(v) then
listAddon(v)
end
end
end
},
all = {
desc = "List all addons",
name = "All",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
local count = GetNumAddOns()
for i = 1, count do
listNormalAddon(i)
end
end
},
enabled = {
desc = "List all enabled addons",
name = "Enabled",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
local count = GetNumAddOns()
for i = 1, count do
local _,_,_,enabled,loadable = GetAddOnInfo(i)
if enabled and loadable then
listNormalAddon(i)
end
end
end
},
disabled = {
desc = "List all disabled addons",
name = "Disabled",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
local count = GetNumAddOns()
for i = 1, count do
local _,_,_,enabled,loadable = GetAddOnInfo(i)
if not enabled or not loadable then
listNormalAddon(i)
end
end
end
},
lod = {
desc = "List all LoadOnDemand addons",
name = "LoadOnDemand",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0")
local count = GetNumAddOns()
for i = 1, count do
if IsAddOnLoadOnDemand(i) then
listNormalAddon(i)
end
end
end
},
ace1 = {
desc = "List all addons using Ace1",
name = "Ace 1.x",
type = "execute",
func = function()
print("|cffffff7fAddon list:|r")
local count = GetNumAddOns()
for i = 1, count do
local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i)
if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then
listNormalAddon(i)
end
end
end
},
libs = {
desc = "List all libraries using AceLibrary",
name = "Libraries",
type = "execute",
func = function()
if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then
print("|cffffff7fLibrary list:|r")
for name, data in pairs(AceLibrary.libs) do
local s
if data.minor then
s = " - " .. tostring(name) .. "." .. tostring(data.minor)
else
s = " - " .. tostring(name)
end
if AceLibrary(name).slashCommand then
s = s .. " |cffffff7f(" .. tostring(AceLibrary(name).slashCommand) .. "|cffffff7f)"
end
print(s)
end
end
end
},
search = {
desc = "Search by name",
name = "Search",
type = "text",
usage = "<keyword>",
input = true,
get = false,
set = function(...)
for i,v in ipairs(arg) do
arg[i] = string.lower(string.gsub(string.gsub(v, '%*', '.*'), '%%', '%%%%'))
end
local count = GetNumAddOns()
for i = 1, count do
local name = GetAddOnInfo(i)
local good = true
for _,v in ipairs(arg) do
if not string.find(string.lower(name), v) then
good = false
break
end
end
if good then
listNormalAddon(i)
end
end
end
}
},
},
enable = {
desc = "Enable addon",
name = "Enable",
type = "text",
usage = "<addon>",
get = false,
set = function(text)
local name,title,_,_,_,reason = GetAddOnInfo(text)
if reason == "MISSING" then
print(string.format("|cffffff7fAce2:|r AddOn %q does not exist", text))
else
EnableAddOn(text)
print(string.format("|cffffff7fAce2:|r %s is now enabled", title or name))
end
end,
},
disable = {
desc = "Disable addon",
name = "Disable",
type = "text",
usage = "<addon>",
get = false,
set = function(text)
local name,title,_,_,_,reason = GetAddOnInfo(text)
if reason == "MISSING" then
print(string.format("|cffffff7fAce2:|r AddOn %q does not exist", text))
else
DisableAddOn(text)
print(string.format("|cffffff7fAce2:|r %s is now disabled", title or name))
end
end,
},
load = {
desc = "Load addon",
name = "Load",
type = "text",
usage = "<addon>",
get = false,
set = function(text)
local name,title,_,_,loadable,reason = GetAddOnInfo(text)
if reason == "MISSING" then
print(string.format("|cffffff7fAce2:|r AddOn %q does not exist.", text))
elseif not loadable then
print(string.format("|cffffff7fAce2:|r AddOn %q is not loadable. Reason: %s", text, reason))
else
LoadAddOn(text)
print(string.format("|cffffff7fAce2:|r %s is now loaded", title or name))
end
end
},
info = {
desc = "Display information",
name = "Information",
type = "execute",
func = function()
local mem, threshold = gcinfo()
print(string.format(" - |cffffff7fMemory usage [|r%.3f MiB|cffffff7f]|r", mem / 1024))
print(string.format(" - |cffffff7fThreshold [|r%.3f MiB|cffffff7f]|r", threshold / 1024))
print(string.format(" - |cffffff7fFramerate [|r%.0f fps|cffffff7f]|r", GetFramerate()))
local bandwidthIn, bandwidthOut, latency = GetNetStats()
bandwidthIn, bandwidthOut = floor(bandwidthIn * 1024), floor(bandwidthOut * 1024)
print(string.format(" - |cffffff7fLatency [|r%.0f ms|cffffff7f]|r", latency))
print(string.format(" - |cffffff7fBandwidth in [|r%.0f B/s|cffffff7f]|r", bandwidthIn))
print(string.format(" - |cffffff7fBandwidth out [|r%.0f B/s|cffffff7f]|r", bandwidthOut))
print(string.format(" - |cffffff7fTotal addons [|r%d|cffffff7f]|r", GetNumAddOns()))
print(string.format(" - |cffffff7fAce2 addons [|r%d|cffffff7f]|r", table.getn(self.addons)))
local ace = 0
local enabled = 0
local disabled = 0
local lod = 0
for i = 1, GetNumAddOns() do
local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i)
if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then
ace = ace + 1
end
if IsAddOnLoadOnDemand(i) then
lod = lod + 1
end
local _,_,_,IsActive,loadable = GetAddOnInfo(i)
if not IsActive or not loadable then
disabled = disabled + 1
else
enabled = enabled + 1
end
end
print(string.format(" - |cffffff7fAce 1.x addons [|r%d|cffffff7f]|r", ace))
print(string.format(" - |cffffff7fLoadOnDemand addons [|r%d|cffffff7f]|r", lod))
print(string.format(" - |cffffff7fenabled addons [|r%d|cffffff7f]|r", enabled))
print(string.format(" - |cffffff7fdisabled addons [|r%d|cffffff7f]|r", disabled))
local libs = 0
if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then
for _ in pairs(AceLibrary.libs) do
libs = libs + 1
end
end
print(string.format(" - |cffffff7fAceLibrary instances [|r%d|cffffff7f]|r", libs))
end
}
}
})
elseif major == "AceModuleCore-2.0" then
AceModuleCore = instance
end
end
local function activate(self, oldLib, oldDeactivate)
AceAddon = self
if oldLib then
self.playerLoginFired = oldLib.playerLoginFired or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage
self.addonsToOnEnable = oldLib.addonsToOnEnable
self.addons = oldLib.addons
self.nextAddon = oldLib.nextAddon
self.addonsStarted = oldLib.addonsStarted
end
if not self.addons then
self.addons = {}
end
if not self.nextAddon then
self.nextAddon = {}
end
if not self.addonsStarted then
self.addonsStarted = {}
end
if oldDeactivate then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(AceAddon, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
AceAddon = AceLibrary(MAJOR_VERSION)
+956
View File
@@ -0,0 +1,956 @@
--[[
Name: AceEvent-2.0
Revision: $Rev: 11577 $
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: 11577 $"
if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
local AceOO = AceLibrary:GetInstance("AceOO-2.0")
local Mixin = AceOO.Mixin
local AceEvent = Mixin {
"RegisterEvent",
"RegisterAllEvents",
"UnregisterEvent",
"UnregisterAllEvents",
"TriggerEvent",
"ScheduleEvent",
"ScheduleRepeatingEvent",
"CancelScheduledEvent",
"CancelAllScheduledEvents",
"IsEventRegistered",
"IsEventScheduled",
"RegisterBucketEvent",
"UnregisterBucketEvent",
"UnregisterAllBucketEvents",
"IsBucketEventRegistered",
}
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 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
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 function OnUpdate()
local t = GetTime()
local k,v = next(delayRegistry)
local last = nil
while k do
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
if delayRegistry[k] then
last = k
end
k,v = next(delayRegistry, last)
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(bucket.func, event)
else
for _,v in ipairs(event) do
AceEvent.UnregisterEvent(bucket.func, 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()
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)
+572
View File
@@ -0,0 +1,572 @@
--[[
Name: AceHook-2.0
Revision: $Rev: 11577 $
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.0
SVN: http://svn.wowace.com/root/trunk/Ace2/AceHook-2.0
Description: Mixin to allow for safe hooking of functions, methods, and scripts.
Dependencies: AceLibrary, AceOO-2.0
]]
local MAJOR_VERSION = "AceHook-2.0"
local MINOR_VERSION = "$Revision: 11577 $"
-- 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 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",
"Unhook",
"UnhookAll",
"HookReport",
"IsHooked",
"HookScript",
}
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
--[[---------------------------------------------------------------------------------
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 _G = getfenv(0)
local handlers, funcs, scripts, actives
--[[---------------------------------------------------------------------------------
Private definitions (Not exposed)
----------------------------------------------------------------------------------]]
--[[----------------------------------------------------------------------
_debug - Internal Method
-------------------------------------------------------------------------]]
local function print(text)
DEFAULT_CHAT_FRAME:AddMessage(text)
end
local function _debug(self, msg)
local name = self.hooks.name
if name then
print(string.format("[%s]: %s", name, msg))
else
print(msg)
end
end
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)
table_setn(t, 0)
for k in pairs(t) do
t[k] = nil
end
list[t] = true
end
end
local origMetatable = {
__call = function(self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
return self.orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
}
--[[----------------------------------------------------------------------
AceHook:_getFunctionHook- internal method
-------------------------------------------------------------------------]]
local function _getFunctionHook(self, func, handler, orig)
if type(handler) == "string" then
-- The handler is a method, need to self it
return function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[orig] 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
else
-- The handler is a function, just call it
return function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[orig] 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
end
end
--[[----------------------------------------------------------------------
AceHook:_getMethodHook - Internal Method
-------------------------------------------------------------------------]]
local function _getMethodHook(self, object, method, handler, orig, script)
if type(handler) == "string" then
-- The handler is a method, need to self it
if script then
return function()
if actives[orig] then
return self[handler](self, object)
else
return orig()
end
end
else
return function(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[orig] then
return self[handler](self, obj, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(obj, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
end
else
-- The handler is a function, just call it
if script then
return function()
if actives[orig] then
return handler(object)
else
return orig()
end
end
else
return function(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
if actives[orig] then
return handler(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
else
return orig(obj, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
end
end
end
end
end
--[[----------------------------------------------------------------------
AceHook:HookFunc - internal method.
o You can only hook each function once from each source.
o If there is an inactive hook for this func/handler pair, we reactivate it
o If there is an inactive hook for another handler, we error out.
o Looks for handler as a method of the calling class, error if not available
o If handler is a function, it just uses it directly through the wrapper
-------------------------------------------------------------------------]]
local function _hookFunc(self, func, handler)
local orig = _G[func]
if not orig or type(orig) ~= "function" then
_debug(self, string.format("Attempt to hook a non-existant function %q", func),3)
return
end
if not handler then handler = func end
if self.hooks[func] then
local orig = self.hooks[func].orig
-- We have an active hook from this source. Don't multi-hook
if actives[orig] then
_debug(self, string.format("%q already has an active hook from this source.", func))
return
end
-- The hook is inactive, so reactivate it
if handlers[orig] == handler then
actives[orig] = 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 t = setmetatable(new(), origMetatable)
self.hooks[func] = t
t.orig = orig
actives[orig] = true
handlers[orig] = handler
local newFunc = _getFunctionHook(self, func, handler, orig)
funcs[orig] = newFunc
_G[func] = newFunc
end
--[[----------------------------------------------------------------------
AceHook:UnhookFunc - internal method
o If you attempt to unhook a function that has never been hooked, or to unhook in a
system that has never had a hook before, the system will error with a stack trace
o If we own the global function, then put the original back in its place and remove
all references to the Hooks[func] structure.
o If we don't own the global function (we've been hooked) we deactivate the hook,
forcing the handler to passthrough.
-------------------------------------------------------------------------]]
local function _unhookFunc(self, func)
if not self.hooks[func] or not funcs[self.hooks[func].orig] then
_debug(self, string.format("Tried to unhook %q which is not currently hooked.", func))
return
end
local orig = self.hooks[func].orig
if actives[orig] then
-- See if we own the global function
if _G[func] == funcs[orig] then
_G[func] = orig
self.hooks[func] = del(self.hooks[func])
handlers[orig] = nil
funcs[orig] = nil
scripts[orig] = nil
actives[orig] = nil
-- Magically all-done
else
actives[orig] = nil
end
end
end
--[[----------------------------------------------------------------------
AceHook:HookMeth - Takes an optional fourth argument
o script - Signifies whether this is a script hook or not
-------------------------------------------------------------------------]]
local function _hookMeth(self, obj, method, handler, script)
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
if self.hooks[obj] and self.hooks[obj][method] then
local orig = self.hooks[obj][method].orig
-- We have an active hook from this source. Don't multi-hook
if actives[orig] then
_debug(self, string.format("%q already has an active hook from this source.", method))
return
end
-- The hook is inactive, so reactivate it.
if handlers[orig] == handler then
actives[orig] = true
return
else
AceHook:error("There is a stale hook for %q can't hook or reactivate.", method)
end
end
-- We're clear to try the hook, let's make some checks first
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
-- Handler has been found, so now try to find the method we're trying to hook
local orig
-- Script
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
-- Sometimes there is not a original function for a script.
orig = obj:GetScript(method)
if not orig then
orig = function() end
end
-- Method
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 self.hooks[obj] then
self.hooks[obj] = new()
end
local t = setmetatable(new(), origMetatable)
self.hooks[obj][method] = t
t.orig = orig
actives[orig] = true
handlers[orig] = handler
scripts[orig] = script and true or nil
local newFunc = _getMethodHook(self, obj, method, handler, orig, script)
funcs[orig] = newFunc
if script then
obj:SetScript(method, newFunc)
else
obj[method] = newFunc
end
end
--[[----------------------------------------------------------------------
AceHook:UnhookMeth - Internal method
o If you attempt to unhook a method that has never been hooked, or to unhook in a
system that has never had a hook before, the system will error with a stack trace
o If we own the global method, then put the original back in its place and remove
all references to the Hooks[obj][method] structure.
o If we don't own the global method (we've been hooked) we deactivate the hook,
forcing the handler to passthrough.
-------------------------------------------------------------------------]]
local function _unhookMeth(self, obj, method)
if not self.hooks[obj] or not self.hooks[obj][method] or not funcs[self.hooks[obj][method].orig] then
_debug(self, string.format("Attempt to unhook a method %q that is not currently hooked.", method))
return
end
local orig = self.hooks[obj][method].orig
if actives[orig] then
-- If this is a script
if scripts[orig] then
if obj:GetScript(method) == funcs[orig] then
-- We own the script. Kill it.
obj:SetScript(method, orig)
self.hooks[obj][method] = del(self.hooks[obj][method])
handlers[orig] = nil
funcs[orig] = nil
scripts[orig] = nil
actives[orig] = nil
else
actives[orig] = nil
end
else
if obj[method] == funcs[orig] then
-- We own the method. Kill it.
obj[method] = orig
self.hooks[obj][method] = del(self.hooks[obj][method])
handlers[orig] = nil
funcs[orig] = nil
scripts[orig] = nil
actives[orig] = nil
else
actives[orig] = nil
end
end
end
if not next(self.hooks[obj]) then
-- Spank the table
self.hooks[obj] = del(self.hooks[obj])
end
end
function AceHook:OnInstanceInit(object)
if not object.hooks then
object.hooks = new()
end
local name
if type(rawget(object, 'GetLibraryVersion')) == "function" then
name = object:GetLibraryVersion()
end
if not name and type(object.GetName) == "function" then
name = object:GetName()
end
if not name and type(object.name) == "string" then
name = object.name
end
if not name then
for k,v in pairs(_G) do
if v == object then
name = tostring(k)
break
end
end
end
object.hooks.name = name
end
AceHook.OnManualEmbed = AceHook.OnInstanceInit
--[[----------------------------------------------------------------------
AceHook:Hook
self:Hook("functionName", ["handlerName" | handler])
self:Hook(ObjectName, "Method", ["Handler" | handler])
-------------------------------------------------------------------------]]
function AceHook:Hook(arg1, arg2, arg3)
if type(arg1)== "string" then
if protFuncs[arg1] then
if self.hooks.name then
AceHook:error("%s tried to hook %q, which is a Blizzard protected function.", self.hooks.name, arg1)
else
_debug(self, string.format("An Addon tried to hook %q, which is a Blizzard protected function.", arg1))
end
else
_hookFunc(self, arg1, arg2)
end
else
_hookMeth(self, arg1, arg2, arg3)
end
end
function AceHook:HookScript(arg1, arg2, arg3)
_hookMeth(self, arg1, arg2, arg3, true)
end
--[[----------------------------------------------------------------------
AceHook:IsHooked()
self:Hook("functionName")
self:Hook(ObjectName, "Method")
Returns whether or not the given function is hooked in the current
namespace. A hooked, but inactive function is considered NOT
hooked in this context.
-------------------------------------------------------------------------]]
function AceHook:IsHooked(obj, method)
if method and obj then
if self.hooks and self.hooks[obj] and self.hooks[obj][method] and actives[self.hooks[obj][method].orig] then
return true, handlers[self.hooks[obj][method].orig]
end
else
if self.hooks and self.hooks[obj] and actives[self.hooks[obj].orig] then
return true, handlers[self.hooks[obj].orig]
end
end
return false, nil
end
--[[----------------------------------------------------------------------
AceHook:Unhook
self:Unhook("functionName")
self:Unhook(ObjectName, "Method")
-------------------------------------------------------------------------]]
function AceHook:Unhook(arg1, arg2)
if type(arg1) == "string" then
_unhookFunc(self, arg1)
else
_unhookMeth(self, arg1, arg2)
end
end
--[[----------------------------------------------------------------------
AceHook:UnhookAll - Unhooks all active hooks from the calling source
-------------------------------------------------------------------------]]
function AceHook:UnhookAll()
for key, value in pairs(self.hooks) 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:OnEmbedDisable(target)
self.UnhookAll(target)
end
--[[----------------------------------------------------------------------
AceHook:HookReport - Lists registered hooks from this source
-------------------------------------------------------------------------]]
function AceHook:HookReport()
_debug(self, "This is a list of all active hooks for this object:")
if not self.hooks then _debug(self, "No registered hooks.") return end
for key, value in pairs(self.hooks) do
if type(value) == "table" then
for method in pairs(value) do
_debug(self, string.format("key: %s method: %q |cff%s|r", tostring(key), method, self.hooks[key][method].active and "00ff00Active" or "ffff00Inactive"))
end
else
_debug(self, string.format("key: %s value: %q |cff%s|r", tostring(key), tostring(value), self.hooks[key].active and "00ff00Active" or "ffff00Inactive"))
end
end
end
--[[---------------------------------------------------------------------------------
Stub and Library registration
----------------------------------------------------------------------------------]]
local function activate(self, oldLib, oldDeactivate)
AceHook = self
AceHook.super.activate(self, oldLib, oldDeactivate)
if oldLib then
self.handlers = oldLib.handlers
self.funcs = oldLib.funcs
self.scripts = oldLib.scripts
self.actives = oldLib.actives
end
if not self.handlers then
self.handlers = {}
end
if not self.funcs then
self.funcs = {}
end
if not self.scripts then
self.scripts = {}
end
if not self.actives then
self.actives = {}
end
handlers = self.handlers
funcs = self.funcs
scripts = self.scripts
actives = self.actives
if oldDeactivate then
oldDeactivate(oldLib)
end
end
AceLibrary:Register(AceHook, MAJOR_VERSION, MINOR_VERSION, activate)
+568
View File
@@ -0,0 +1,568 @@
--[[
Name: AceHook-2.1
Revision: $Rev: 15485 $
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: 15485 $"
-- 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 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][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 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(self.hooks) 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)
+723
View File
@@ -0,0 +1,723 @@
--[[
Name: AceLibrary
Revision: $Rev: 11612 $
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: 11612 $
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: 11612 $"
-- CHANGE DEBUG TO ``false`` ON RELEASE -------------------
local DEBUG = true
-- CHANGE DEBUG TO ``false`` ON RELEASE -------------------
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 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")
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")
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")
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
if DEBUG then
-- This one is already obsolete, raise an error.
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
return instance
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
end
if not self.libs then
self.libs = {}
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)
File diff suppressed because it is too large Load Diff
+26
View File
@@ -0,0 +1,26 @@
-- zhCN localization by hk2717
if GetLocale() == "zhCN" then
POSTAL_HELP = "将物品拖入下面的空格中。每个物品都将以单独的邮件发送给收件人。邮件标题为你输入的标题后加物品名称数量(例如: <标题> [金锭 x10])。合计邮资显示于顶部右侧。你可以按住Alt键单击你背包中的物品,直接将其添加到邮件列表中。";
POSTAL_SEND = "发送邮件";
POSTAL_SENDBUTTON = "发送";
POSTAL_CANCELBUTTON = "取消";
POSTAL_SENDINFO = "你确定要发送这些邮件吗?合计邮资:";
POSTAL_SENDINFO2 = "正在发送:";
POSTAL_ITEMS = "物品";
POSTAL_ABORT = "中止";
POSTAL_ITEMNUM = "已发送%d个物品,总计%d个物品。";
POSTAL_SENDING = "发送邮件 |c00FFFFFF%d|r/|c00FFFFFF%d|r…";
POSTAL_DONESENDING = "邮寄完毕,总计|c00FFFFFF%d|r封邮件";
POSTAL_ABORTED = "中止邮寄,已寄出|c00FFFFFF%d|r/|c00FFFFFF%d|r封邮件。";
POSTAL_ERROR = "POSTAL出现了一个错误。可能是由网络延迟导致的,请尝试用普通邮件窗口邮寄一个物品。也可能是试图邮寄不能邮寄的物品而导致。";
POSTAL_INBOX_OPENSELECTED = "打开选择";
POSTAL_INBOX_OPENALL = "打开全部";
POSTAL_INBOX_OPENALLTITLE = "打开全部?";
POSTAL_INBOX_OPENALLCONFIRMATION = "确定要打开全部邮件吗?";
POSTAL_INBOX_DISPLAYPROCESSMESSAGES = "显示进程信息";
end
+27
View File
@@ -0,0 +1,27 @@
-- Version : French ( by Sasmira )
-- Last Update : 03/29/2005
if GetLocale() == "frFR" then
POSTAL_HELP = "compl\195\169tez autant de cases que vous souhaitez. Chaque article sera envoy\195\169 s\195\169par\195\169ment dans un courrier au destinataire, avec le sujet que vous sp\195\169cifiez et qui sera attach\195\169 au nom de l\'objet plus un num\195\169ro, ( Pour exemple : <Sujet> [Barre d\'Or x10]). L\'affranchissement combin\195\169 est montr\195\169 dans le coin en haut \195\60 droite. Vous pouvez ALT-Clic Gauche sur les objets dans votre inventaire afin de les ajouter \195\60 la liste automatiquement.";
POSTAL_SEND = "Envoyer un Message";
POSTAL_SENDBUTTON = "Envoi";
POSTAL_CANCELBUTTON = "Annuler";
POSTAL_SENDINFO = "Etes vous sur de vouloir envoyer ce message ? La Somme Totale pour les messages post\195\169s sera de :";
POSTAL_SENDINFO2 = "Vous avez envoy\195\169 :";
POSTAL_ITEMS = "Objet(s)";
POSTAL_ABORT = "Abandonner";
POSTAL_ITEMNUM = "Objet %d hors de %d.";
POSTAL_SENDING = "Envoi de Messages |c00FFFFFF%d|r/|c00FFFFFF%d|r...";
POSTAL_DONESENDING = "Envoi de |c00FFFFFF%d|r message(s) termin\195\169(s) !";
POSTAL_ABORTED = "Abandonn\195\169. |c00FFFFFF%d|r/|c00FFFFFF%d|r de message(s) a \195\169t\195\169 envoy\195\169.";
POSTAL_ERROR = "Une Erreur c\'est produite dans Postal. Envoyez un rapport de bug \195\160 l\'url suivante : http://www.ctmod.net";
POSTAL_INBOX_OPENSELECTED = "Ouvrir la s\195\169lection";
POSTAL_INBOX_OPENALL = "Tous les Ouvrir";
POSTAL_INBOX_OPENALLTITLE = "Ouvrir les messages ?";
POSTAL_INBOX_OPENALLCONFIRMATION = "Etes vous sur de vouloir ouvrir tous les messages ?";
POSTAL_INBOX_DISPLAYPROCESSMESSAGES = "Afficher les processus";
end
+20
View File
@@ -0,0 +1,20 @@
if GetLocale() == "deDE" then
-- Credits to Hjörvarör for these
POSTAL_HELP = "Belege soviele Pl\195\164tze wie du m\195\182chtest. Jeder Gegenstand wird seperat an den Empf\195\164nger gesendet, und zwar mit dem Betreff den du bestimmst gefolgt vom Namen des Gegenstands und dessen Anzahl (z.B. <Betreff> [Goldbarren x10]). Die zusammengefassten Versandkosten werden oben rechts angezeigt. Du kannst Gegenst\195\164nde in deinen Taschen durch Alt-Klick automatisch zur Liste hinzuf\195\188gen.";
POSTAL_SEND = "Post verschicken";
POSTAL_SENDBUTTON = "Verschicken";
POSTAL_CANCELBUTTON = "Abbrechen";
POSTAL_SENDINFO = "Bist du sicher das du die Post verschicken willst? Die gesamten Versandkosten belaufen sich auf:";
POSTAL_SENDINFO2 = "Du verschickst:";
POSTAL_ITEMS = "Item(s)";
POSTAL_ABORT = "Abbrechen";
POSTAL_ITEMNUM = "Gegenstand %d von %d.";
POSTAL_SENDING = "Verschicke P\195\164ckchen |c00FFFFFF%d|r/|c00FFFFFF%d|r...";
POSTAL_DONESENDING = "Verschicken von |c00FFFFFF%d|r P\195\164ckchen erledigt!";
POSTAL_ABORTED = "Abgebrochen. |c00FFFFFF%d|r/|c00FFFFFF%d|r P\195\164ckchen wurde(n) verschickt.";
POSTAL_ERROR = "Ein Fehler in Postal ist aufgetreten. Bitte \195\188bermittle einen Fehlerbericht auf http://www.ctmod.net";
end
+22
View File
@@ -0,0 +1,22 @@
POSTAL_HELP = "Fill in as many slots as you want. Each item will be sent in a separate mail to the recipient, with the subject you specify, followed by the item's name and count (for example: <Subject> [Gold Bar x10]). The combined postage is shown in the top right. You can alt-click on items in your bags to add them to the list automatically.";
POSTAL_SEND = "Send Mail";
POSTAL_SENDBUTTON = "Send";
POSTAL_CANCELBUTTON = "Cancel";
POSTAL_SENDINFO = "Are you sure you want to send the mail? Total postage will be:";
POSTAL_SENDINFO2 = "You are sending:";
POSTAL_ITEMS = "Item(s)";
POSTAL_ABORT = "Abort";
POSTAL_ITEMNUM = "Item %d out of %d.";
POSTAL_SENDING = "Sending mail |c00FFFFFF%d|r/|c00FFFFFF%d|r...";
POSTAL_DONESENDING = "Done sending |c00FFFFFF%d|r mail(s)!";
POSTAL_ABORTED = "Aborted. |c00FFFFFF%d|r/|c00FFFFFF%d|r mail were sent.";
POSTAL_ERROR = "An error occured in POSTAL. This might be related to lag, trying to send items with an item placed in the normal send mail window, or trying to send items that cannot be sent.";
POSTAL_INBOX_OPENSELECTED = "Open Selected";
POSTAL_INBOX_OPENALL = "Open All";
POSTAL_INBOX_OPENALLTITLE = "Open All?";
POSTAL_INBOX_OPENALLCONFIRMATION = "Are you sure you want to open all mail?";
POSTAL_INBOX_DISPLAYPROCESSMESSAGES = "Display process messages";
+33
View File
@@ -0,0 +1,33 @@
if GetLocale() == "zhTW" then
POSTAL_HELP = "將物品拖入下面空格中。每件物品都將以單獨的信件寄給收件者。郵件標題為你輸入的標題+物品名稱+數量(例: <標題> [夢葉草 x10])。郵資計算顯示於右上方。你可以使用Alt點選背包中的物品直接加入寄件清單中。";
POSTAL_SEND = "發送郵件";
POSTAL_SENDBUTTON = "發送";
POSTAL_CANCELBUTTON = "取消";
POSTAL_SENDINFO = "你確定要發送這些郵件嗎?合計郵資:";
POSTAL_SENDINFO2 = "正在發送:";
POSTAL_ITEMS = "物品";
POSTAL_ABORT = "中止";
POSTAL_ITEMNUM = "已發送%d件物品,總計%d件物品。";
POSTAL_SENDING = "發送郵件 |c00FFFFFF%d|r/|c00FFFFFF%d|r...";
POSTAL_DONESENDING = "寄件完畢,總計|c00FFFFFF%d|r封郵件";
POSTAL_ABORTED = "中止發送,已寄出|c00FFFFFF%d|r/|c00FFFFFF%d|r封郵件";
POSTAL_ERROR = "Gmail出現了一個錯誤,可能是網路延遲所導致,請嘗試用普通郵件寄出一件物品,也有可能是點選了不能郵寄的物品所導致。";
POSTAL_INBOX_OPENSELECTED = "打開選擇郵件";
POSTAL_INBOX_OPENALL = "打開全部郵件";
POSTAL_INBOX_OPENALLTITLE = "打開全部?";
POSTAL_INBOX_OPENALLCONFIRMATION = "確定要打開全部郵件嗎?";
POSTAL_INBOX_DISPLAYPROCESSMESSAGES = "顯示處理過程";
POSTAL_MASS_MAIL="群發郵件";
POSTAL_FORWARD="轉寄";
POSTAL_NOSUBJECT="<無標題>"
POSTAL_UNKNOWNSENDER="<未知寄件者>"
POSTAL_OPEN_FORMAT1="Postal: 郵件 |c00FFFFFF%d|r/|c00FFFFFF%d|r 是C.O.D郵件,忽略。"
POSTAL_OPEN_FORMAT2="Postal: 郵件 |c00FFFFFF%d|r/|c00FFFFFF%d|r 沒有附帶金錢或物品,忽略。"
POSTAL_OPEN_FORMAT3="Postal: 正在打開郵件 |c00FFFFFF%d|r/|c00FFFFFF%d|r: \"|c00FFFFFF%s|r\" 來自 |c00FFFFFF%s|r。"
end
+34
View File
@@ -0,0 +1,34 @@
--[[ $Id: localization.zhcn.lua 13144 2006-10-06 01:35:52Z hshh $ ]]--
if GetLocale() == "zhCN" then
POSTAL_HELP = "将你要发送的物品放入下面的格子,每样物品将自动通过分开的邮件发送出去.邮件标题将使用填写的主题加上物品描述.总的邮资显示在右上角.你也可以通过按住ALT键点击你的背包中的物品添加到邮件里.";
POSTAL_SEND = "发送批量邮件";
POSTAL_SENDBUTTON = "发送";
POSTAL_CANCELBUTTON = "取消";
POSTAL_SENDINFO = "你真的确定要发送这个批量邮件么? 总的邮资是:";
POSTAL_SENDINFO2 = "你将要发送:";
POSTAL_ITEMS = "个物品";
POSTAL_ABORT = "终止发送";
POSTAL_ITEMNUM = "这是批量发送邮件的第%d个物品, 共%d个.";
POSTAL_SENDING = "正在发送邮件 |c00FFFFFF%d|r/|c00FFFFFF%d|r...";
POSTAL_DONESENDING = "已发送 |c00FFFFFF%d|r 封邮件!";
POSTAL_ABORTED = "已终止. |c00FFFFFF%d|r/|c00FFFFFF%d|r 封邮件已发送.";
POSTAL_ERROR = "POSTAL 出错. 造成这个原因有可能是网络或服务器延迟, 或者你发送的物品是不能被邮件传递的, 请尝试使用正常途径发送邮件.";
POSTAL_INBOX_OPENSELECTED = "打开已选";
POSTAL_INBOX_OPENALL = "打开所有";
POSTAL_INBOX_OPENALLTITLE = "确定打开所有?";
POSTAL_INBOX_OPENALLCONFIRMATION = "你确定要打开所有邮件么?";
POSTAL_INBOX_DISPLAYPROCESSMESSAGES = "显示处理信息";
POSTAL_MASS_MAIL="批量邮件";
POSTAL_FORWARD="转发";
POSTAL_NOSUBJECT="<无标题>"
POSTAL_UNKNOWNSENDER="<未知发信者>"
POSTAL_OPEN_FORMAT1="Postal: 邮件 |c00FFFFFF%d|r/|c00FFFFFF%d|r 是付费邮件, 忽略."
POSTAL_OPEN_FORMAT2="Postal: 邮件 |c00FFFFFF%d|r/|c00FFFFFF%d|r 没有附带金钱或物品, 忽略."
POSTAL_OPEN_FORMAT3="Postal: 正在打开邮件 |c00FFFFFF%d|r/|c00FFFFFF%d|r: \"|c00FFFFFF%s|r\" 来自 |c00FFFFFF%s|r."
end