From 2c1766968bc1807ff8c07a42d9222d7113a02774 Mon Sep 17 00:00:00 2001 From: ck Date: Sat, 13 Jan 2024 23:22:42 -0600 Subject: [PATCH] Init --- .vscode/settings.json | 6 + DiesalLibs/DiesalComm-1.0/ChatThrottleLib.lua | 524 +++++++++ DiesalLibs/DiesalComm-1.0/DiesalComm-1.0.lua | 274 +++++ DiesalLibs/DiesalComm-1.0/DiesalComm-1.0.xml | 5 + DiesalLibs/DiesalGUI-1.0/DiesalGUI-1.0.lua | 384 ++++++ DiesalLibs/DiesalGUI-1.0/DiesalGUI-1.0.xml | 23 + .../DiesalGUI-1.0/Objects/Accordian.lua | 62 + .../Objects/AccordianSection.lua | 217 ++++ DiesalLibs/DiesalGUI-1.0/Objects/Bar.lua | 177 +++ DiesalLibs/DiesalGUI-1.0/Objects/Branch.lua | 279 +++++ DiesalLibs/DiesalGUI-1.0/Objects/Button.lua | 109 ++ DiesalLibs/DiesalGUI-1.0/Objects/CheckBox.lua | 163 +++ DiesalLibs/DiesalGUI-1.0/Objects/ComboBox.lua | 282 +++++ .../DiesalGUI-1.0/Objects/ComboBoxItem.lua | 122 ++ DiesalLibs/DiesalGUI-1.0/Objects/DropDown.lua | 296 +++++ .../DiesalGUI-1.0/Objects/DropDownItem.lua | 137 +++ DiesalLibs/DiesalGUI-1.0/Objects/Input.lua | 124 ++ DiesalLibs/DiesalGUI-1.0/Objects/QuickDoc.lua | 163 +++ .../DiesalGUI-1.0/Objects/ScrollFrame.lua | 279 +++++ .../Objects/ScrollingEditBox.lua | 279 +++++ .../Objects/ScrollingMessageFrame.lua | 267 +++++ DiesalLibs/DiesalGUI-1.0/Objects/Spinner.lua | 294 +++++ DiesalLibs/DiesalGUI-1.0/Objects/Toggle.lua | 174 +++ DiesalLibs/DiesalGUI-1.0/Objects/Tree.lua | 93 ++ DiesalLibs/DiesalGUI-1.0/Objects/Window.lua | 387 ++++++ DiesalLibs/DiesalMenu-1.0/DiesalMenu-1.0.lua | 69 ++ DiesalLibs/DiesalMenu-1.0/DiesalMenu-1.0.xml | 6 + DiesalLibs/DiesalMenu-1.0/Objects/Menu.lua | 132 +++ .../DiesalMenu-1.0/Objects/MenuItem.lua | 157 +++ .../DiesalStyle-1.0/DiesalStyle-1.0.lua | 1048 +++++++++++++++++ .../Media/DejaVuSansMono-Bold.ttf | Bin 0 -> 331536 bytes .../DiesalStyle-1.0/Media/DejaVuSansMono.ttf | Bin 0 -> 340240 bytes .../Media/DiesalButtonIcons32x128x512.tga | Bin 0 -> 262188 bytes .../Media/DiesalGUIcons16x256x128.tga | Bin 0 -> 131116 bytes .../Media/DiesalGUIcons32x256x256.tga | Bin 0 -> 262188 bytes .../Media/DiesalGUIcons64x256x256.tga | Bin 0 -> 262188 bytes .../Media/FFF Intelligent Thin Condensed.ttf | Bin 0 -> 38348 bytes .../DiesalStyle-1.0/Media/FiraMono-Bold.ttf | Bin 0 -> 206548 bytes .../DiesalStyle-1.0/Media/FiraMono-Medium.ttf | Bin 0 -> 173516 bytes .../Media/FiraMono-Regular.ttf | Bin 0 -> 174632 bytes .../Media/FiraSans-Regular.ttf | Bin 0 -> 403924 bytes .../DiesalStyle-1.0/Media/Hack-Bold.ttf | Bin 0 -> 401928 bytes .../DiesalStyle-1.0/Media/Hack-Regular.ttf | Bin 0 -> 399724 bytes .../Media/Inconsolata-Bold.ttf | Bin 0 -> 67724 bytes .../Media/Inconsolata-Regular.ttf | Bin 0 -> 84868 bytes DiesalLibs/DiesalStyle-1.0/Media/LUCON.TTF | Bin 0 -> 115068 bytes .../Media/OfficeCodePro-Bold.ttf | Bin 0 -> 77268 bytes .../Media/OfficeCodePro-Medium.ttf | Bin 0 -> 77964 bytes .../Media/OfficeCodePro-Regular.ttf | Bin 0 -> 80476 bytes .../DiesalStyle-1.0/Media/RobotoMono-Bold.ttf | Bin 0 -> 114752 bytes .../Media/RobotoMono-Medium.ttf | Bin 0 -> 114696 bytes .../Media/RobotoMono-Regular.ttf | Bin 0 -> 114624 bytes .../Media/SourceCodePro-Black.ttf | Bin 0 -> 197024 bytes .../Media/SourceCodePro-Bold.ttf | Bin 0 -> 197004 bytes .../Media/SourceCodePro-Medium.ttf | Bin 0 -> 197064 bytes .../Media/SourceCodePro-Regular.ttf | Bin 0 -> 197644 bytes .../Media/SourceCodePro-Semibold.ttf | Bin 0 -> 196576 bytes .../DiesalStyle-1.0/Media/Standard0755.ttf | Bin 0 -> 21752 bytes .../DiesalStyle-1.0/Media/UbuntuMono-B.ttf | Bin 0 -> 191400 bytes .../DiesalStyle-1.0/Media/UbuntuMono-R.ttf | Bin 0 -> 205748 bytes DiesalLibs/DiesalStyle-1.0/Media/calibrib.ttf | Bin 0 -> 848720 bytes DiesalLibs/DiesalStyle-1.0/Media/monof55.ttf | Bin 0 -> 169452 bytes DiesalLibs/DiesalStyle-1.0/Media/monof56.ttf | Bin 0 -> 181628 bytes DiesalLibs/DiesalStyle-1.0/Media/shadow.tga | Bin 0 -> 32812 bytes .../DiesalStyle-1.0/Media/shadowNoDist.tga | Bin 0 -> 32812 bytes .../DiesalTools-1.0/DiesalTools-1.0.lua | 515 ++++++++ 66 files changed, 7047 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 DiesalLibs/DiesalComm-1.0/ChatThrottleLib.lua create mode 100644 DiesalLibs/DiesalComm-1.0/DiesalComm-1.0.lua create mode 100644 DiesalLibs/DiesalComm-1.0/DiesalComm-1.0.xml create mode 100644 DiesalLibs/DiesalGUI-1.0/DiesalGUI-1.0.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/DiesalGUI-1.0.xml create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/Accordian.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/AccordianSection.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/Bar.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/Branch.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/Button.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/CheckBox.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/ComboBox.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/ComboBoxItem.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/DropDown.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/DropDownItem.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/Input.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/QuickDoc.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/ScrollFrame.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/ScrollingEditBox.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/ScrollingMessageFrame.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/Spinner.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/Toggle.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/Tree.lua create mode 100644 DiesalLibs/DiesalGUI-1.0/Objects/Window.lua create mode 100644 DiesalLibs/DiesalMenu-1.0/DiesalMenu-1.0.lua create mode 100644 DiesalLibs/DiesalMenu-1.0/DiesalMenu-1.0.xml create mode 100644 DiesalLibs/DiesalMenu-1.0/Objects/Menu.lua create mode 100644 DiesalLibs/DiesalMenu-1.0/Objects/MenuItem.lua create mode 100644 DiesalLibs/DiesalStyle-1.0/DiesalStyle-1.0.lua create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/DejaVuSansMono-Bold.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/DejaVuSansMono.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/DiesalButtonIcons32x128x512.tga create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/DiesalGUIcons16x256x128.tga create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/DiesalGUIcons32x256x256.tga create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/DiesalGUIcons64x256x256.tga create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/FFF Intelligent Thin Condensed.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/FiraMono-Bold.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/FiraMono-Medium.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/FiraMono-Regular.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/FiraSans-Regular.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/Hack-Bold.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/Hack-Regular.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/Inconsolata-Bold.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/Inconsolata-Regular.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/LUCON.TTF create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/OfficeCodePro-Bold.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/OfficeCodePro-Medium.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/OfficeCodePro-Regular.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/RobotoMono-Bold.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/RobotoMono-Medium.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/RobotoMono-Regular.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/SourceCodePro-Black.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/SourceCodePro-Bold.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/SourceCodePro-Medium.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/SourceCodePro-Regular.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/SourceCodePro-Semibold.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/Standard0755.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/UbuntuMono-B.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/UbuntuMono-R.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/calibrib.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/monof55.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/monof56.ttf create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/shadow.tga create mode 100644 DiesalLibs/DiesalStyle-1.0/Media/shadowNoDist.tga create mode 100644 DiesalLibs/DiesalTools-1.0/DiesalTools-1.0.lua diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ea6d5da --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "Lua.diagnostics.globals": [ + "DEFAULT_CHAT_FRAME", + "ChatFrame1" + ] +} \ No newline at end of file diff --git a/DiesalLibs/DiesalComm-1.0/ChatThrottleLib.lua b/DiesalLibs/DiesalComm-1.0/ChatThrottleLib.lua new file mode 100644 index 0000000..05a0363 --- /dev/null +++ b/DiesalLibs/DiesalComm-1.0/ChatThrottleLib.lua @@ -0,0 +1,524 @@ +-- +-- ChatThrottleLib by Mikk +-- +-- Manages AddOn chat output to keep player from getting kicked off. +-- +-- ChatThrottleLib:SendChatMessage/:SendAddonMessage functions that accept +-- a Priority ("BULK", "NORMAL", "ALERT") as well as prefix for SendChatMessage. +-- +-- Priorities get an equal share of available bandwidth when fully loaded. +-- Communication channels are separated on extension+chattype+destination and +-- get round-robinned. (Destination only matters for whispers and channels, +-- obviously) +-- +-- Will install hooks for SendChatMessage and SendAddonMessage to measure +-- bandwidth bypassing the library and use less bandwidth itself. +-- +-- +-- Fully embeddable library. Just copy this file into your addon directory, +-- add it to the .toc, and it's done. +-- +-- Can run as a standalone addon also, but, really, just embed it! :-) +-- +-- LICENSE: ChatThrottleLib is released into the Public Domain +-- + +local CTL_VERSION = 23 + +local _G = _G + +if _G.ChatThrottleLib then + if _G.ChatThrottleLib.version >= CTL_VERSION then + -- There's already a newer (or same) version loaded. Buh-bye. + return + elseif not _G.ChatThrottleLib.securelyHooked then + print("ChatThrottleLib: Warning: There's an ANCIENT ChatThrottleLib.lua (pre-wow 2.0, =v16) in it!") + -- ATTEMPT to unhook; this'll behave badly if someone else has hooked... + -- ... and if someone has securehooked, they can kiss that goodbye too... >.< + _G.SendChatMessage = _G.ChatThrottleLib.ORIG_SendChatMessage + if _G.ChatThrottleLib.ORIG_SendAddonMessage then + _G.SendAddonMessage = _G.ChatThrottleLib.ORIG_SendAddonMessage + end + end + _G.ChatThrottleLib.ORIG_SendChatMessage = nil + _G.ChatThrottleLib.ORIG_SendAddonMessage = nil +end + +if not _G.ChatThrottleLib then + _G.ChatThrottleLib = {} +end + +ChatThrottleLib = _G.ChatThrottleLib -- in case some addon does "local ChatThrottleLib" above us and we're copypasted (AceComm-2, sigh) +local ChatThrottleLib = _G.ChatThrottleLib + +ChatThrottleLib.version = CTL_VERSION + + + +------------------ TWEAKABLES ----------------- + +ChatThrottleLib.MAX_CPS = 800 -- 2000 seems to be safe if NOTHING ELSE is happening. let's call it 800. +ChatThrottleLib.MSG_OVERHEAD = 40 -- Guesstimate overhead for sending a message; source+dest+chattype+protocolstuff + +ChatThrottleLib.BURST = 4000 -- WoW's server buffer seems to be about 32KB. 8KB should be safe, but seen disconnects on _some_ servers. Using 4KB now. + +ChatThrottleLib.MIN_FPS = 20 -- Reduce output CPS to half (and don't burst) if FPS drops below this value + + +local setmetatable = setmetatable +local table_remove = table.remove +local tostring = tostring +local GetTime = GetTime +local math_min = math.min +local math_max = math.max +local next = next +local strlen = string.len +local GetFramerate = GetFramerate +local strlower = string.lower +local unpack,type,pairs,wipe = unpack,type,pairs,wipe +local UnitInRaid,UnitInParty = UnitInRaid,UnitInParty + + +----------------------------------------------------------------------- +-- Double-linked ring implementation + +local Ring = {} +local RingMeta = { __index = Ring } + +function Ring:New() + local ret = {} + setmetatable(ret, RingMeta) + return ret +end + +function Ring:Add(obj) -- Append at the "far end" of the ring (aka just before the current position) + if self.pos then + obj.prev = self.pos.prev + obj.prev.next = obj + obj.next = self.pos + obj.next.prev = obj + else + obj.next = obj + obj.prev = obj + self.pos = obj + end +end + +function Ring:Remove(obj) + obj.next.prev = obj.prev + obj.prev.next = obj.next + if self.pos == obj then + self.pos = obj.next + if self.pos == obj then + self.pos = nil + end + end +end + + + +----------------------------------------------------------------------- +-- Recycling bin for pipes +-- A pipe is a plain integer-indexed queue of messages +-- Pipes normally live in Rings of pipes (3 rings total, one per priority) + +ChatThrottleLib.PipeBin = nil -- pre-v19, drastically different +local PipeBin = setmetatable({}, {__mode="k"}) + +local function DelPipe(pipe) + PipeBin[pipe] = true +end + +local function NewPipe() + local pipe = next(PipeBin) + if pipe then + wipe(pipe) + PipeBin[pipe] = nil + return pipe + end + return {} +end + + + + +----------------------------------------------------------------------- +-- Recycling bin for messages + +ChatThrottleLib.MsgBin = nil -- pre-v19, drastically different +local MsgBin = setmetatable({}, {__mode="k"}) + +local function DelMsg(msg) + msg[1] = nil + -- there's more parameters, but they're very repetetive so the string pool doesn't suffer really, and it's faster to just not delete them. + MsgBin[msg] = true +end + +local function NewMsg() + local msg = next(MsgBin) + if msg then + MsgBin[msg] = nil + return msg + end + return {} +end + + +----------------------------------------------------------------------- +-- ChatThrottleLib:Init +-- Initialize queues, set up frame for OnUpdate, etc + + +function ChatThrottleLib:Init() + + -- Set up queues + if not self.Prio then + self.Prio = {} + self.Prio["ALERT"] = { ByName = {}, Ring = Ring:New(), avail = 0 } + self.Prio["NORMAL"] = { ByName = {}, Ring = Ring:New(), avail = 0 } + self.Prio["BULK"] = { ByName = {}, Ring = Ring:New(), avail = 0 } + end + + -- v4: total send counters per priority + for _, Prio in pairs(self.Prio) do + Prio.nTotalSent = Prio.nTotalSent or 0 + end + + if not self.avail then + self.avail = 0 -- v5 + end + if not self.nTotalSent then + self.nTotalSent = 0 -- v5 + end + + + -- Set up a frame to get OnUpdate events + if not self.Frame then + self.Frame = CreateFrame("Frame") + self.Frame:Hide() + end + self.Frame:SetScript("OnUpdate", self.OnUpdate) + self.Frame:SetScript("OnEvent", self.OnEvent) -- v11: Monitor P_E_W so we can throttle hard for a few seconds + self.Frame:RegisterEvent("PLAYER_ENTERING_WORLD") + self.OnUpdateDelay = 0 + self.LastAvailUpdate = GetTime() + self.HardThrottlingBeginTime = GetTime() -- v11: Throttle hard for a few seconds after startup + + -- Hook SendChatMessage and SendAddonMessage so we can measure unpiped traffic and avoid overloads (v7) + if not self.securelyHooked then + -- Use secure hooks as of v16. Old regular hook support yanked out in v21. + self.securelyHooked = true + --SendChatMessage + hooksecurefunc("SendChatMessage", function(...) + return ChatThrottleLib.Hook_SendChatMessage(...) + end) + --SendAddonMessage + hooksecurefunc("SendAddonMessage", function(...) + return ChatThrottleLib.Hook_SendAddonMessage(...) + end) + end + self.nBypass = 0 +end + + +----------------------------------------------------------------------- +-- ChatThrottleLib.Hook_SendChatMessage / .Hook_SendAddonMessage + +local bMyTraffic = false + +function ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destination, ...) + if bMyTraffic then + return + end + local self = ChatThrottleLib + local size = strlen(tostring(text or "")) + strlen(tostring(destination or "")) + self.MSG_OVERHEAD + self.avail = self.avail - size + self.nBypass = self.nBypass + size -- just a statistic +end +function ChatThrottleLib.Hook_SendAddonMessage(prefix, text, chattype, destination, ...) + if bMyTraffic then + return + end + local self = ChatThrottleLib + local size = tostring(text or ""):len() + tostring(prefix or ""):len(); + size = size + tostring(destination or ""):len() + self.MSG_OVERHEAD + self.avail = self.avail - size + self.nBypass = self.nBypass + size -- just a statistic +end + + + +----------------------------------------------------------------------- +-- ChatThrottleLib:UpdateAvail +-- Update self.avail with how much bandwidth is currently available + +function ChatThrottleLib:UpdateAvail() + local now = GetTime() + local MAX_CPS = self.MAX_CPS; + local newavail = MAX_CPS * (now - self.LastAvailUpdate) + local avail = self.avail + + if now - self.HardThrottlingBeginTime < 5 then + -- First 5 seconds after startup/zoning: VERY hard clamping to avoid irritating the server rate limiter, it seems very cranky then + avail = math_min(avail + (newavail*0.1), MAX_CPS*0.5) + self.bChoking = true + elseif GetFramerate() < self.MIN_FPS then -- GetFrameRate call takes ~0.002 secs + avail = math_min(MAX_CPS, avail + newavail*0.5) + self.bChoking = true -- just a statistic + else + avail = math_min(self.BURST, avail + newavail) + self.bChoking = false + end + + avail = math_max(avail, 0-(MAX_CPS*2)) -- Can go negative when someone is eating bandwidth past the lib. but we refuse to stay silent for more than 2 seconds; if they can do it, we can. + + self.avail = avail + self.LastAvailUpdate = now + + return avail +end + + +----------------------------------------------------------------------- +-- Despooling logic +-- Reminder: +-- - We have 3 Priorities, each containing a "Ring" construct ... +-- - ... made up of N "Pipe"s (1 for each destination/pipename) +-- - and each pipe contains messages + +function ChatThrottleLib:Despool(Prio) + local ring = Prio.Ring + while ring.pos and Prio.avail > ring.pos[1].nSize do + local msg = table_remove(ring.pos, 1) + if not ring.pos[1] then -- did we remove last msg in this pipe? + local pipe = Prio.Ring.pos + Prio.Ring:Remove(pipe) + Prio.ByName[pipe.name] = nil + DelPipe(pipe) + else + Prio.Ring.pos = Prio.Ring.pos.next + end + local didSend=false + local lowerDest = strlower(msg[3] or "") + if lowerDest == "raid" and not UnitInRaid("player") then + -- do nothing + elseif lowerDest == "party" and not UnitInParty("player") then + -- do nothing + else + Prio.avail = Prio.avail - msg.nSize + bMyTraffic = true + msg.f(unpack(msg, 1, msg.n)) + bMyTraffic = false + Prio.nTotalSent = Prio.nTotalSent + msg.nSize + DelMsg(msg) + didSend = true + end + -- notify caller of delivery (even if we didn't send it) + if msg.callbackFn then + msg.callbackFn (msg.callbackArg, didSend) + end + -- USER CALLBACK MAY ERROR + end +end + + +function ChatThrottleLib.OnEvent(this,event) + -- v11: We know that the rate limiter is touchy after login. Assume that it's touchy after zoning, too. + local self = ChatThrottleLib + if event == "PLAYER_ENTERING_WORLD" then + self.HardThrottlingBeginTime = GetTime() -- Throttle hard for a few seconds after zoning + self.avail = 0 + end +end + + +function ChatThrottleLib.OnUpdate(this,delay) + local self = ChatThrottleLib + + self.OnUpdateDelay = self.OnUpdateDelay + delay + if self.OnUpdateDelay < 0.08 then + return + end + self.OnUpdateDelay = 0 + + self:UpdateAvail() + + if self.avail < 0 then + return -- argh. some bastard is spewing stuff past the lib. just bail early to save cpu. + end + + -- See how many of our priorities have queued messages (we only have 3, don't worry about the loop) + local n = 0 + for prioname,Prio in pairs(self.Prio) do + if Prio.Ring.pos or Prio.avail < 0 then + n = n + 1 + end + end + + -- Anything queued still? + if n<1 then + -- Nope. Move spillover bandwidth to global availability gauge and clear self.bQueueing + for prioname, Prio in pairs(self.Prio) do + self.avail = self.avail + Prio.avail + Prio.avail = 0 + end + self.bQueueing = false + self.Frame:Hide() + return + end + + -- There's stuff queued. Hand out available bandwidth to priorities as needed and despool their queues + local avail = self.avail/n + self.avail = 0 + + for prioname, Prio in pairs(self.Prio) do + if Prio.Ring.pos or Prio.avail < 0 then + Prio.avail = Prio.avail + avail + if Prio.Ring.pos and Prio.avail > Prio.Ring.pos[1].nSize then + self:Despool(Prio) + -- Note: We might not get here if the user-supplied callback function errors out! Take care! + end + end + end + +end + + + + +----------------------------------------------------------------------- +-- Spooling logic + +function ChatThrottleLib:Enqueue(prioname, pipename, msg) + local Prio = self.Prio[prioname] + local pipe = Prio.ByName[pipename] + if not pipe then + self.Frame:Show() + pipe = NewPipe() + pipe.name = pipename + Prio.ByName[pipename] = pipe + Prio.Ring:Add(pipe) + end + + pipe[#pipe + 1] = msg + + self.bQueueing = true +end + +function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, language, destination, queueName, callbackFn, callbackArg) + if not self or not prio or not prefix or not text or not self.Prio[prio] then + error('Usage: ChatThrottleLib:SendChatMessage("{BULK||NORMAL||ALERT}", "prefix", "text"[, "chattype"[, "language"[, "destination"]]]', 2) + end + if callbackFn and type(callbackFn)~="function" then + error('ChatThrottleLib:ChatMessage(): callbackFn: expected function, got '..type(callbackFn), 2) + end + + local nSize = text:len() + + if nSize>255 then + error("ChatThrottleLib:SendChatMessage(): message length cannot exceed 255 bytes", 2) + end + + nSize = nSize + self.MSG_OVERHEAD + + -- Check if there's room in the global available bandwidth gauge to send directly + if not self.bQueueing and nSize < self:UpdateAvail() then + self.avail = self.avail - nSize + bMyTraffic = true + _G.SendChatMessage(text, chattype, language, destination) + bMyTraffic = false + self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize + if callbackFn then + callbackFn (callbackArg, true) + end + -- USER CALLBACK MAY ERROR + return + end + + -- Message needs to be queued + local msg = NewMsg() + msg.f = _G.SendChatMessage + msg[1] = text + msg[2] = chattype or "SAY" + msg[3] = language + msg[4] = destination + msg.n = 4 + msg.nSize = nSize + msg.callbackFn = callbackFn + msg.callbackArg = callbackArg + + self:Enqueue(prio, queueName or (prefix..(chattype or "SAY")..(destination or "")), msg) +end + + +function ChatThrottleLib:SendAddonMessage(prio, prefix, text, chattype, target, queueName, callbackFn, callbackArg) + if not self or not prio or not prefix or not text or not chattype or not self.Prio[prio] then + error('Usage: ChatThrottleLib:SendAddonMessage("{BULK||NORMAL||ALERT}", "prefix", "text", "chattype"[, "target"])', 2) + end + if callbackFn and type(callbackFn)~="function" then + error('ChatThrottleLib:SendAddonMessage(): callbackFn: expected function, got '..type(callbackFn), 2) + end + + local nSize = text:len(); + + if RegisterAddonMessagePrefix then + if nSize>255 then + error("ChatThrottleLib:SendAddonMessage(): message length cannot exceed 255 bytes", 2) + end + else + nSize = nSize + prefix:len() + 1 + if nSize>255 then + error("ChatThrottleLib:SendAddonMessage(): prefix + message length cannot exceed 254 bytes", 2) + end + end + + nSize = nSize + self.MSG_OVERHEAD; + + -- Check if there's room in the global available bandwidth gauge to send directly + if not self.bQueueing and nSize < self:UpdateAvail() then + self.avail = self.avail - nSize + bMyTraffic = true + _G.SendAddonMessage(prefix, text, chattype, target) + bMyTraffic = false + self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize + if callbackFn then + callbackFn (callbackArg, true) + end + -- USER CALLBACK MAY ERROR + return + end + + -- Message needs to be queued + local msg = NewMsg() + msg.f = _G.SendAddonMessage + msg[1] = prefix + msg[2] = text + msg[3] = chattype + msg[4] = target + msg.n = (target~=nil) and 4 or 3; + msg.nSize = nSize + msg.callbackFn = callbackFn + msg.callbackArg = callbackArg + + self:Enqueue(prio, queueName or (prefix..chattype..(target or "")), msg) +end + + + + +----------------------------------------------------------------------- +-- Get the ball rolling! + +ChatThrottleLib:Init() + +--[[ WoWBench debugging snippet +if(WOWB_VER) then + local function SayTimer() + print("SAY: "..GetTime().." "..arg1) + end + ChatThrottleLib.Frame:SetScript("OnEvent", SayTimer) + ChatThrottleLib.Frame:RegisterEvent("CHAT_MSG_SAY") +end +]] + + diff --git a/DiesalLibs/DiesalComm-1.0/DiesalComm-1.0.lua b/DiesalLibs/DiesalComm-1.0/DiesalComm-1.0.lua new file mode 100644 index 0000000..8a006c3 --- /dev/null +++ b/DiesalLibs/DiesalComm-1.0/DiesalComm-1.0.lua @@ -0,0 +1,274 @@ +--- allows you to send messages of unlimited length over the addon comm channels. +-- It'll automatically split the messages into multiple parts and rebuild them on the receiving end.\\ +-- **ChatThrottleLib** is of course being used to avoid being disconnected by the server. + +-- **DiesalComm** can be embeded into your addon, either explicitly by calling DiesalComm:Embed(MyAddon) or by +-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object +-- and can be accessed directly, without having to explicitly call AceComm itself.\\ +-- It is recommended to embed AceComm, otherwise you'll have to specify a custom `self` on all calls you +-- make into DiesalComm. +-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded +-- List them here for Mikk's FindGlobals script +-- GLOBALS: LibStub, DEFAULT_CHAT_FRAME, geterrorhandler, RegisterAddonMessagePrefix + +-- $Id: AceComm-3.0.lua 1107 2014-02-19 16:40:32Z nevcairiel $ +-- ~~| Initialize library |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +local MAJOR, MINOR = "DiesalComm-1.0", 1 +local DiesalComm, oldminor = LibStub:NewLibrary(MAJOR, MINOR) +if not DiesalComm then return end + +local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0") +local CTL = assert(ChatThrottleLib, "DiesalComm-1.0 requires ChatThrottleLib") +-- ~~| Lua Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +local type, next, pairs, tostring = type, next, pairs, tostring +local strsub, strfind = string.sub, string.find +local match = string.match +local tinsert, tconcat = table.insert, table.concat +local error, assert = error, assert +-- ~~| WoW Upvalues |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +local Ambiguate = Ambiguate +-- ~~| DiesalComm Values |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +DiesalComm.embeds = DiesalComm.embeds or {} +DiesalComm.msg_spool = DiesalComm.msg_spool or {} + +local COMM_MODES = {'single','first','next','last'} +local HEADER_SIZE = 14 +local HEADER_FORMAT = '%[%x%x:%x%x%x%x:%x%x%x%x%]' + +local MAX_CHUNK_SIZE = 240 + + +--- Register for Addon Traffic on a specified prefix +-- @param prefix A printable character (\032-\255) classification of the message (typically AddonName or AddonNameEvent), max 16 characters +-- @param method Callback to call on message reception: Function reference, or method name (string) to call on self. Defaults to "OnCommReceived" +function DiesalComm:RegisterComm(prefix, method) + if method == nil then method = "OnCommReceived" end + if #prefix > 15 then error("AceComm:RegisterComm(prefix,method): prefix length is limited to 15 characters") end + RegisterAddonMessagePrefix(prefix) + + return DiesalComm.RegisterCallback(self, prefix, method) +end + + + +local function formatValue(num,len) + num = format('%X',num) + for i = 1, len - #num do + num = "0"..num + end + return num +end + + +local function encodeHeader(mode, chunk ,totalChunks ) + return '['..formatValue(mode,2)..':'..formatValue(chunk,4)..':'..formatValue(totalChunks,4)..']' +end +local function decodeHeader() + + +end + +--- Send a message over the Addon Channel +-- @param prefix A printable character (\032-\255) classification of the message (typically AddonName or AddonNameEvent) +-- @param text Data to send, nils (\000) not allowed. Any length. +-- @param channel Addon channel, e.g. "RAID", "GUILD", etc; see SendAddonMessage API +-- @param target Destination for some distributions; see SendAddonMessage API +-- @param callbackFn OPTIONAL: callback function to be called as each chunk is sent. receives 3 args: the user supplied arg (see next), the number of bytes sent so far, and the number of bytes total to send. +-- @param callbackArg: OPTIONAL: first arg to the callback function. nil will be passed if not specified. +-- @param prio OPTIONAL: ChatThrottleLib priority, "BULK", "NORMAL" or "ALERT". Defaults to "NORMAL". +function AceComm:SendCommMessage(prefix, text, channel, target, callbackFn, callbackArg, prio) + prio = prio or "NORMAL" + if type(prefix)~="string" and type(text)~="string" and type(channel)~="string" and (target==nil or type(target)~="string") and (prio~="BULK" or prio~="NORMAL" or prio~="ALERT") then + error('Usage: SendCommMessage(addon, "prefix", "text", "channel"[, "target"[, callbackFn, callbackarg[, "prio"]]])', 2) + end + + local textlen = #text + local ctlCallback = callbackFn and function(sent) return callbackFn(callbackArg, sent, textlen) end or nil + + + + if textlen <= MAX_CHUNK_SIZE then -- fits all in one message + text = '[0:0000:0000]'..text + CTL:SendAddonMessage(prio, prefix, text, channel, target, nil, ctlCallback, textlen) + else + -- first part + local chunk = strsub(text, 1, maxtextlen) + CTL:SendAddonMessage(prio, prefix, MSG_MULTI_FIRST..chunk, distribution, target, queueName, ctlCallback, maxtextlen) + + -- continuation + local pos = 1+maxtextlen + + while pos+maxtextlen <= textlen do + chunk = strsub(text, pos, pos+maxtextlen-1) + CTL:SendAddonMessage(prio, prefix, MSG_MULTI_NEXT..chunk, distribution, target, queueName, ctlCallback, pos+maxtextlen-1) + pos = pos + maxtextlen + end + + -- final part + chunk = strsub(text, pos) + CTL:SendAddonMessage(prio, prefix, MSG_MULTI_LAST..chunk, distribution, target, queueName, ctlCallback, textlen) + end +end + + +---------------------------------------- +-- Message receiving +---------------------------------------- + +do + local compost = setmetatable({}, {__mode = "k"}) + local function new() + local t = next(compost) + if t then + compost[t]=nil + for i=#t,3,-1 do -- faster than pairs loop. don't even nil out 1/2 since they'll be overwritten + t[i]=nil + end + return t + end + + return {} + end + + local function lostdatawarning(prefix,sender,where) + DEFAULT_CHAT_FRAME:AddMessage(MAJOR..": Warning: lost network data regarding '"..tostring(prefix).."' from '"..tostring(sender).."' (in "..where..")") + end + + function AceComm:OnReceiveMultipartFirst(prefix, message, distribution, sender) + local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender + local spool = AceComm.multipart_spool + + --[[ + if spool[key] then + lostdatawarning(prefix,sender,"First") + -- continue and overwrite + end + --]] + + spool[key] = message -- plain string for now + end + + function AceComm:OnReceiveMultipartNext(prefix, message, distribution, sender) + local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender + local spool = AceComm.multipart_spool + local olddata = spool[key] + + if not olddata then + --lostdatawarning(prefix,sender,"Next") + return + end + + if type(olddata)~="table" then + -- ... but what we have is not a table. So make it one. (Pull a composted one if available) + local t = new() + t[1] = olddata -- add old data as first string + t[2] = message -- and new message as second string + spool[key] = t -- and put the table in the spool instead of the old string + else + tinsert(olddata, message) + end + end + + function AceComm:OnReceiveMultipartLast(prefix, message, distribution, sender) + local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender + local spool = AceComm.multipart_spool + local olddata = spool[key] + + if not olddata then + --lostdatawarning(prefix,sender,"End") + return + end + + spool[key] = nil + + if type(olddata) == "table" then + -- if we've received a "next", the spooled data will be a table for rapid & garbage-free tconcat + tinsert(olddata, message) + AceComm.callbacks:Fire(prefix, tconcat(olddata, ""), distribution, sender) + compost[olddata] = true + else + -- if we've only received a "first", the spooled data will still only be a string + AceComm.callbacks:Fire(prefix, olddata..message, distribution, sender) + end + end +end + + + + + + +---------------------------------------- +-- Embed CallbackHandler +---------------------------------------- + +if not AceComm.callbacks then + AceComm.callbacks = CallbackHandler:New(AceComm, + "_RegisterComm", + "UnregisterComm", + "UnregisterAllComm") +end + +AceComm.callbacks.OnUsed = nil +AceComm.callbacks.OnUnused = nil + +local function OnEvent(self, event, prefix, message, distribution, sender) + if event == "CHAT_MSG_ADDON" then + sender = Ambiguate(sender, "none") + local control, rest = match(message, "^([\001-\009])(.*)") + if control then + if control==MSG_MULTI_FIRST then + AceComm:OnReceiveMultipartFirst(prefix, rest, distribution, sender) + elseif control==MSG_MULTI_NEXT then + AceComm:OnReceiveMultipartNext(prefix, rest, distribution, sender) + elseif control==MSG_MULTI_LAST then + AceComm:OnReceiveMultipartLast(prefix, rest, distribution, sender) + elseif control==MSG_ESCAPE then + AceComm.callbacks:Fire(prefix, rest, distribution, sender) + else + -- unknown control character, ignore SILENTLY (dont warn unnecessarily about future extensions!) + end + else + -- single part: fire it off immediately and let CallbackHandler decide if it's registered or not + AceComm.callbacks:Fire(prefix, message, distribution, sender) + end + else + assert(false, "Received "..tostring(event).." event?!") + end +end + +AceComm.frame = AceComm.frame or CreateFrame("Frame", "AceComm30Frame") +AceComm.frame:SetScript("OnEvent", OnEvent) +AceComm.frame:UnregisterAllEvents() +AceComm.frame:RegisterEvent("CHAT_MSG_ADDON") + + +---------------------------------------- +-- Base library stuff +---------------------------------------- + +local mixins = { + "RegisterComm", + "UnregisterComm", + "UnregisterAllComm", + "SendCommMessage", +} + +-- Embeds AceComm-3.0 into the target object making the functions from the mixins list available on target:.. +-- @param target target object to embed AceComm-3.0 in +function AceComm:Embed(target) + for k, v in pairs(mixins) do + target[v] = self[v] + end + self.embeds[target] = true + return target +end + +function AceComm:OnEmbedDisable(target) + target:UnregisterAllComm() +end + +-- Update embeds +for target, v in pairs(AceComm.embeds) do + AceComm:Embed(target) +end diff --git a/DiesalLibs/DiesalComm-1.0/DiesalComm-1.0.xml b/DiesalLibs/DiesalComm-1.0/DiesalComm-1.0.xml new file mode 100644 index 0000000..ea2cd96 --- /dev/null +++ b/DiesalLibs/DiesalComm-1.0/DiesalComm-1.0.xml @@ -0,0 +1,5 @@ + +