From f550ea0324f10e31e8ea48683328d6b3a793d714 Mon Sep 17 00:00:00 2001 From: papa-smurf <4224975+papa-smurf@users.noreply.github.com> Date: Fri, 12 May 2023 16:45:28 +0200 Subject: [PATCH] Improved add-on performance, especially when using GDKP queues --- Classes/Comm.lua | 50 ++++++++++++++++- Classes/CommMessage.lua | 2 +- Classes/GDKP/Auction.lua | 105 ++++++++++++++++++++++++++++++++---- Classes/GDKP/Auctioneer.lua | 2 +- Classes/Helpers.lua | 1 + _ide_helper.lua | 4 ++ 6 files changed, 149 insertions(+), 15 deletions(-) diff --git a/Classes/Comm.lua b/Classes/Comm.lua index 4527e867..0e7233aa 100644 --- a/Classes/Comm.lua +++ b/Classes/Comm.lua @@ -111,6 +111,10 @@ function Comm:_init() -- Register the Ace Comm channel listener GL.Ace:RegisterComm(self.channel, Comm.listen); + -- Store the default ChatThrottleLib burst and CPS values + self.defaultBurstValue = _G.ChatThrottleLib.BURST or 4000; + self.defaultCPSValue = _G.ChatThrottleLib.MAX_CPS or 800; + self._initialized = true; end @@ -125,6 +129,7 @@ function Comm:send(CommMessage, broadcastFinishedCallback, packageSentCallback) local distribution = CommMessage.channel; local recipient = CommMessage.recipient; + local action = CommMessage.action; if (distribution == "GROUP") then distribution = "PARTY"; @@ -156,23 +161,64 @@ function Comm:send(CommMessage, broadcastFinishedCallback, packageSentCallback) end -- We lower the burst value and cps on large payloads to make sure - -- our messages are not dropped by the server, which happens A LOT ffs + -- our messages are not dropped by the server. ChatThrottleLib is not accurate enough sadly local stringLength = string.len(compressedMessage); - GL:debug("Payload size: " .. stringLength); + local throttle = distribution ~= "WHISPER" and stringLength > 1900; + + local throttleResetTimer; + -- Stop throttling: reset the burst and max cps values + local stopThrottling = function() + GL:debug("Resetting burst value and cps"); + + _G.ChatThrottleLib.BURST = self.defaultBurstValue; + _G.ChatThrottleLib.MAX_CPS = self.defaultCPSValue; + end; + + if (throttle) then + GL:debug("Throttling burst value and cps"); + + _G.ChatThrottleLib.BURST = 2000; + _G.ChatThrottleLib.MAX_CPS = 400; + + -- Make sure we reset the values even if the message couldn't be sent + throttleResetTimer = GL.Ace:ScheduleTimer(function () + stopThrottling(); + end, 5); + end + + -- Make sure we can keep an eye on comm behavior + if (GL.User:isDev()) then + local actionTitle = GL:tableFlip(Actions)[action] or action; + DevTools_Dump(("Action: %s | Payload size: %s | Throttled: %s"):format(tostring(actionTitle), stringLength, throttle and "Y" or "N")); + end GL.Ace:SendCommMessage(self.channel, compressedMessage, distribution, recipient, "BULK", function (_, sent, textlen) GL:debug(string.format("Sent %s from %s characters", sent, textlen)); + -- Cancel the throttle reset timer if it exists + if (throttleResetTimer) then + GL.Ace:CancelTimer(throttleResetTimer); + end + -- Execute the package sent calback if (type(packageSentCallback) == "function") then packageSentCallback(sent, textlen); end if (sent >= textlen) then + if (throttle) then + stopThrottling(); + end + -- Execute the broadcast finished callback if (type(broadcastFinishedCallback) == "function") then broadcastFinishedCallback(sent, textlen); end + else + -- Make sure we reset the values even if the message couldn't be sent in full + throttleResetTimer = GL.Ace:ScheduleTimer(function () + stopThrottling(); + end, 5); end end); end diff --git a/Classes/CommMessage.lua b/Classes/CommMessage.lua index 55e25f91..19f1c817 100644 --- a/Classes/CommMessage.lua +++ b/Classes/CommMessage.lua @@ -162,7 +162,7 @@ function CommMessage:compress(Message) local success, encoded = pcall(function () local serialized = LibSerialize:Serialize(Payload); - local compressed = LibDeflate:CompressDeflate(serialized, {level = 8}); + local compressed = LibDeflate:CompressDeflate(serialized, {level = 5}); local encoded = LibDeflate:EncodeForWoWAddonChannel(compressed); return encoded; diff --git a/Classes/GDKP/Auction.lua b/Classes/GDKP/Auction.lua index 05780b9b..4dbe34b8 100644 --- a/Classes/GDKP/Auction.lua +++ b/Classes/GDKP/Auction.lua @@ -26,6 +26,7 @@ local Auctioneer; ---@class GDKPAuction GDKP.Auction = { + _broadcastingDisabled = false, _initialized = false, autoBiddingIsActive = nil, lastBidAt = nil, @@ -65,7 +66,7 @@ local GDKPSession = GDKP.Session; --[[ CONSTANTS ]] local AUTO_BID_THROTTLE_IN_SECONDS = .6; -local BROADCAST_QUEUE_DELAY_IN_SECONDS = 2; +local BROADCAST_QUEUE_DELAY_IN_SECONDS = 3; function Auction:_init() GL:debug("GDKP.Auction:_init"); @@ -130,6 +131,7 @@ function Auction:_initializeQueue() return; end + self._broadcastingDisabled = true; local SortedQueue = GL:tableValues(Auction.Queue); table.sort(SortedQueue, function (a, b) if (a.order and b.order) then @@ -151,13 +153,21 @@ function Auction:_initializeQueue() GL.Ace:CancelTimer(QueueAddTimer); SortedQueue = nil; + self._broadcastingDisabled = false; + GL.Events:fire("GL.GDKP_QUEUE_UPDATED"); + + -- Make sure to broadcast the queue when everything's said and done + if (i > 1) then + self:broadcastQueue(); + end + return; end i = i + 1; return Auctioneer:addToQueue(Queued.itemLink, Queued.identifier, false); - end, .2); + end, .1); end ---@return void @@ -830,10 +840,8 @@ function Auction:addToQueue(itemLink, identifier) return; end - local addedAt = GetTime(); local PerItemSettings = GDKP:settingsForItemID(GL:getItemIDFromLink(itemLink)); self.Queue[identifier] = { - addedAt = addedAt, identifier = identifier, increment = PerItemSettings.increment, itemID = itemID, @@ -918,8 +926,7 @@ end function Auction:removeFromQueue(checksum) GL:debug("Auction:removeFromQueue"); - checksum = tostring(checksum or 0); - if (not self.Queue[checksum]) then + if (not self.Queue[checksum or 0]) then return false; end @@ -978,10 +985,16 @@ function Auction:sanitizeQueue() end end +--- Broadcast the first 20 items to everyone in the raid ---@return void function Auction:broadcastQueue(immediately) GL:debug("Auction:broadcastQueue"); + -- Broadcasting is + if (self._broadcastingDisabled) then + return; + end + GL.Ace:CancelTimer(self.QueueBroadcastTimer); self:sanitizeQueue(); @@ -989,10 +1002,41 @@ function Auction:broadcastQueue(immediately) return; end + -- Make sure we only broadcast the first 15 items as to not overload the system + local SortedQueue = GL:tableValues(Auction.Queue); + table.sort(SortedQueue, function (a, b) + if (a.order and b.order) then + return a.order < b.order; + end + + return false; + end); + + local QueueSegment = {}; + local i = 0; + for _, Details in pairs(SortedQueue) do + + i = i + 1; + + -- Trim down the queue details in order to minimize the comm payload + tinsert(QueueSegment, { + Details.identifier, + Details.itemID, + Details.minimumBid, + Details.order, + Details.increment, + }); + + -- A queue of more than a 100 items makes no sense + if (i > 100) then + break; + end + end + local broadcast = function () GL.CommMessage.new( CommActions.broadcastGDKPAuctionQueue, - self.Queue or {}, + QueueSegment or {}, "GROUP" ):send(); end; @@ -1025,10 +1069,50 @@ function Auction:receiveQueue(CommMessage) return; end - self.Queue = CommMessage.content; - self:sanitizeQueue(); + local Queue = {}; + + -- Check if this is the old format including item links + local itemLinksArePresent = true; + for _, Details in pairs(CommMessage.content or {}) do + itemLinksArePresent = not not Details.itemLink; + end + + -- Old format, no need to continue + if (itemLinksArePresent) then + self.Queue = Queue; + self:sanitizeQueue(); + + Events:fire("GL.GDKP_QUEUE_UPDATED"); + return; + end - Events:fire("GL.GDKP_QUEUE_UPDATED"); + -- Enrich the received queue with required data + GL:onItemLoadDo(GL:tableColumn(CommMessage.content, 2), function (Details) + local ItemLinksByID = {}; + + for _, Entry in pairs(Details) do + ItemLinksByID[Entry.id] = Entry.link; + end + + for _, Queued in pairs(CommMessage.content or {}) do + local itemLink = ItemLinksByID[Queued[2]]; + if (itemLink) then + Queue[Queued[1]] = { + identifier = Queued[1], + itemID = Queued[2], + minimumBid = Queued[3], + order = Queued[4], + increment = Queued[5], + itemLink = itemLink, + }; + end + end + + self.Queue = Queue; + self:sanitizeQueue(); + + Events:fire("GL.GDKP_QUEUE_UPDATED"); + end); end --- Announce to everyone in the raid that an auction is starting @@ -1080,7 +1164,6 @@ function Auction:announceStart(itemLink, minimumBid, minimumIncrement, duration, self.inProgress = true; self:listenForBids(); - self:broadcastQueue(true); -- This is still the same item, use the previous highest bid as the starting point if (itemLink == self.Current.itemLink) then diff --git a/Classes/GDKP/Auctioneer.lua b/Classes/GDKP/Auctioneer.lua index 56b298ea..e3050eee 100644 --- a/Classes/GDKP/Auctioneer.lua +++ b/Classes/GDKP/Auctioneer.lua @@ -258,7 +258,7 @@ function Auctioneer:addToQueue(itemLink, identifier, open) AuctioneerUI = AuctioneerUI or GL.Interface.GDKP.Auctioneer; local Queue = AuctioneerUI:getQueueWindow(true); - identifier = identifier or GL:stringHash(GetTime() .. itemLink) .. math.random(1, 1000); + identifier = identifier or tonumber(GL:stringHash(GetTime() .. itemLink) .. math.random(1, 1000)); Auction:addToQueue(itemLink, identifier); Queue:addItemByLink(itemLink, identifier); diff --git a/Classes/Helpers.lua b/Classes/Helpers.lua index c3db6f8b..c1b294ec 100644 --- a/Classes/Helpers.lua +++ b/Classes/Helpers.lua @@ -417,6 +417,7 @@ end --- StringHash method, courtesy of Mikk38024 @ Wowpedia (https://wowpedia.fandom.com/wiki/StringHash) --- ---@param text string|table +---@return number function GL:stringHash(text) if (type(text) == "table") then text = GL:implode(text, "."); diff --git a/_ide_helper.lua b/_ide_helper.lua index c9b915fb..3c16a12b 100644 --- a/_ide_helper.lua +++ b/_ide_helper.lua @@ -35,6 +35,10 @@ AceGUIIcon = {}; ---@class AceGUIButton AceGUIButton = {}; +-- [[ GLOBAL ]] +---@param mixed any +function DevTools_Dump(mixed) end + -- [[ AceGUIFrame ]] ---@param value string function AceGUIFrame:SetStatusText(value) end