@ -25,36 +25,32 @@
local CTL_VERSION = 23
local _G = _G
if _G.ChatThrottleLib then
if _G.ChatThrottleLib . version >= CTL_VERSION then
if ChatThrottleLib then
if ChatThrottleLib.version >= CTL_VERSION then
-- There's already a newer (or same) version loaded. Buh-bye.
return
elseif not _G. ChatThrottleLib. securelyHooked then
elseif not ChatThrottleLib.securelyHooked then
print ( " ChatThrottleLib: Warning: There's an ANCIENT ChatThrottleLib.lua (pre-wow 2.0, <v16) in an addon somewhere. Get the addon updated or copy in a newer ChatThrottleLib.lua (>=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
SendChatMessage = ChatThrottleLib.ORIG_SendChatMessage
if ChatThrottleLib. ORIG_SendAddonMessage then
SendAddonMessage = ChatThrottleLib.ORIG_SendAddonMessage
end
end
_G.ChatThrottleLib . ORIG_SendChatMessage = nil
_G.ChatThrottleLib . ORIG_SendAddonMessage = nil
ChatThrottleLib. ORIG_SendChatMessage = nil
ChatThrottleLib. ORIG_SendAddonMessage = nil
end
if not _G. ChatThrottleLib then
_G. ChatThrottleLib = { }
if not ChatThrottleLib then
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 = ChatThrottleLib -- in case some addon does "local ChatThrottleLib" above us and we're copypasted (AceComm-2, sigh)
local ChatThrottleLib = 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.
@ -64,7 +60,6 @@ ChatThrottleLib.BURST = 4000 -- WoW's server buffer seems to be about 32KB. 8
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
@ -75,9 +70,8 @@ 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
local unpack , type , pairs , wipe = unpack , type , pairs , wipe
local UnitInRaid , UnitInParty = UnitInRaid , UnitInParty
-----------------------------------------------------------------------
-- Double-linked ring implementation
@ -115,15 +109,13 @@ function Ring:Remove(obj)
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 PipeBin = setmetatable ( { } , { __mode = " k " } )
local function DelPipe ( pipe )
PipeBin [ pipe ] = true
@ -139,14 +131,11 @@ local function NewPipe()
return { }
end
-----------------------------------------------------------------------
-- Recycling bin for messages
ChatThrottleLib.MsgBin = nil -- pre-v19, drastically different
local MsgBin = setmetatable ( { } , { __mode = " k " } )
local MsgBin = setmetatable ( { } , { __mode = " k " } )
local function DelMsg ( msg )
msg [ 1 ] = nil
@ -163,14 +152,11 @@ local function NewMsg()
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 = { }
@ -191,7 +177,6 @@ function ChatThrottleLib:Init()
self.nTotalSent = 0 -- v5
end
-- Set up a frame to get OnUpdate events
if not self.Frame then
self.Frame = CreateFrame ( " Frame " )
@ -220,7 +205,6 @@ function ChatThrottleLib:Init()
self.nBypass = 0
end
-----------------------------------------------------------------------
-- ChatThrottleLib.Hook_SendChatMessage / .Hook_SendAddonMessage
@ -240,37 +224,35 @@ function ChatThrottleLib.Hook_SendAddonMessage(prefix, text, chattype, destinati
return
end
local self = ChatThrottleLib
local size = tostring ( text or " " ) : len ( ) + tostring ( prefix or " " ) : len ( ) ;
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 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 )
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 )
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.
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
@ -278,7 +260,6 @@ function ChatThrottleLib:UpdateAvail()
return avail
end
-----------------------------------------------------------------------
-- Despooling logic
-- Reminder:
@ -298,7 +279,7 @@ function ChatThrottleLib:Despool(Prio)
else
Prio.Ring . pos = Prio.Ring . pos.next
end
local didSend = false
local didSend = false
local lowerDest = strlower ( msg [ 3 ] or " " )
if lowerDest == " raid " and not UnitInRaid ( " player " ) then
-- do nothing
@ -315,14 +296,13 @@ function ChatThrottleLib:Despool(Prio)
end
-- notify caller of delivery (even if we didn't send it)
if msg.callbackFn then
msg.callbackFn ( msg.callbackArg , didSend )
msg.callbackFn ( msg.callbackArg , didSend )
end
-- USER CALLBACK MAY ERROR
end
end
function ChatThrottleLib . OnEvent ( this , event )
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
@ -331,8 +311,7 @@ function ChatThrottleLib.OnEvent(this,event)
end
end
function ChatThrottleLib . OnUpdate ( this , delay )
function ChatThrottleLib . OnUpdate ( this , delay )
local self = ChatThrottleLib
self.OnUpdateDelay = self.OnUpdateDelay + delay
@ -349,14 +328,14 @@ function ChatThrottleLib.OnUpdate(this,delay)
-- 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
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
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
@ -368,7 +347,7 @@ function ChatThrottleLib.OnUpdate(this,delay)
end
-- There's stuff queued. Hand out available bandwidth to priorities as needed and despool their queues
local avail = self.avail / n
local avail = self.avail / n
self.avail = 0
for prioname , Prio in pairs ( self.Prio ) do
@ -380,12 +359,8 @@ function ChatThrottleLib.OnUpdate(this,delay)
end
end
end
end
-----------------------------------------------------------------------
-- Spooling logic
@ -409,13 +384,13 @@ function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, languag
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 )
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
if nSize > 255 then
error ( " ChatThrottleLib:SendChatMessage(): message length cannot exceed 255 bytes " , 2 )
end
@ -429,7 +404,7 @@ function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, languag
bMyTraffic = false
self.Prio [ prio ] . nTotalSent = self.Prio [ prio ] . nTotalSent + nSize
if callbackFn then
callbackFn ( callbackArg , true )
callbackFn ( callbackArg , true )
end
-- USER CALLBACK MAY ERROR
return
@ -447,32 +422,31 @@ function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, languag
msg.callbackFn = callbackFn
msg.callbackArg = callbackArg
self : Enqueue ( prio , queueName or ( prefix .. ( chattype or " SAY " ) .. ( destination or " " ) ) , msg )
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 )
if callbackFn and type ( callbackFn ) ~= " function " then
error ( " ChatThrottleLib:SendAddonMessage(): callbackFn: expected function, got " .. type ( callbackFn ) , 2 )
end
local nSize = text : len ( ) ;
local nSize = text : len ( )
if RegisterAddonMessagePrefix then
if nSize > 255 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
if nSize > 255 then
error ( " ChatThrottleLib:SendAddonMessage(): prefix + message length cannot exceed 254 bytes " , 2 )
end
end
nSize = nSize + self.MSG_OVERHEAD ;
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
@ -482,7 +456,7 @@ function ChatThrottleLib:SendAddonMessage(prio, prefix, text, chattype, target,
bMyTraffic = false
self.Prio [ prio ] . nTotalSent = self.Prio [ prio ] . nTotalSent + nSize
if callbackFn then
callbackFn ( callbackArg , true )
callbackFn ( callbackArg , true )
end
-- USER CALLBACK MAY ERROR
return
@ -495,17 +469,14 @@ function ChatThrottleLib:SendAddonMessage(prio, prefix, text, chattype, target,
msg [ 2 ] = text
msg [ 3 ] = chattype
msg [ 4 ] = target
msg.n = ( target ~= nil ) and 4 or 3 ;
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 )
self : Enqueue ( prio , queueName or ( prefix .. chattype .. ( target or " " ) ) , msg )
end
-----------------------------------------------------------------------
-- Get the ball rolling!
@ -520,5 +491,3 @@ if(WOWB_VER) then
ChatThrottleLib.Frame : RegisterEvent ( " CHAT_MSG_SAY " )
end
] ]