-------------------------------------------------------------------------------- -- OctoLatency for Vanilla WoW (1.12.1) - Author: Palladinpala -------------------------------------------------------------------------------- -- Throttle timer to reduce CPU/performance overhead local elapsedTimer = 0 local UPDATE_INTERVAL = 2.0 -- update every 2 seconds local MAX_ERROR_LOG = 20 local function OctoLatency_EnsureDB() if (not OctoLatencyDB) then OctoLatencyDB = {} end if (not OctoLatencyDB.errorLog) then OctoLatencyDB.errorLog = {} end return OctoLatencyDB end -- Records an error to SavedVariables (visible in-game via /octolat errors, -- and readable straight out of the WTF SavedVariables file after logout) -- and pings the chat frame so it isn't silently swallowed. function OctoLatency_LogError(context, err) local db = OctoLatency_EnsureDB() local entry = { time = date("%Y-%m-%d %H:%M:%S"), context = context, message = tostring(err), } table.insert(db.errorLog, entry) while (table.getn(db.errorLog) > MAX_ERROR_LOG) do table.remove(db.errorLog, 1) end DEFAULT_CHAT_FRAME:AddMessage("|cffff5555OctoLatency error|r in " .. context .. ": " .. tostring(err) .. " (type /octolat errors)") end -- Runs func in protected mode so one bad tick can't break the addon, -- and captures the error for later reporting instead of losing it. local function OctoLatency_SafeCall(context, func, ...) local ok, err = pcall(func, ...) if (not ok) then OctoLatency_LogError(context, err) end return ok end function OctoLatency_OnLoad(self) -- Tooltip on hover self:SetScript("OnEnter", function() OctoLatency_SafeCall("OnEnter", function() GameTooltip:SetOwner(this, "ANCHOR_TOP") GameTooltip:AddLine("OctoLatency", 0, 1, 1) local bandwidth, latency, homeLatency, worldLatency = GetNetStats() GameTooltip:AddLine("Home Latency: " .. homeLatency .. " ms", 1, 1, 1) GameTooltip:AddLine("World Latency: " .. worldLatency .. " ms", 1, 1, 1) GameTooltip:AddLine("Bandwidth: " .. string.format("%.2f", bandwidth) .. " KB/s", 1, 1, 1) GameTooltip:AddLine("Left-click and drag to move.", 0.7, 0.7, 0.7) GameTooltip:Show() end) end) self:SetScript("OnLeave", function() GameTooltip:Hide() end) end local function OctoLatency_UpdateText() -- GetNetStats returns: bandwidth, latency, homeLatency, worldLatency local _, _, homeLatency, worldLatency = GetNetStats() -- We'll display world latency (or max of home/world) local latency = worldLatency or homeLatency or 0 -- Color thresholds: Green < 150ms, Yellow 150-350ms, Red > 350ms local colorHex if (latency < 150) then colorHex = "|cff00ff00" -- Green elseif (latency <= 350) then colorHex = "|cffffff00" -- Yellow else colorHex = "|cffff0000" -- Red end OctoLatencyText:SetText(colorHex .. latency .. " ms|r") end function OctoLatency_OnUpdate(elapsed) elapsedTimer = elapsedTimer + elapsed if (elapsedTimer < UPDATE_INTERVAL) then return end elapsedTimer = 0 OctoLatency_SafeCall("OnUpdate", OctoLatency_UpdateText) end function OctoLatency_StopMoving(self) if (self.isMoving) then self:StopMovingOrSizing() self.isMoving = false OctoLatency_SavePosition() end end function OctoLatency_SavePosition() if (not OctoLatencyDB) then OctoLatencyDB = {} end local point, relativeTo, relativePoint, xOfs, yOfs = OctoLatencyFrame:GetPoint() OctoLatencyDB.point = point OctoLatencyDB.relativePoint = relativePoint OctoLatencyDB.xOfs = xOfs OctoLatencyDB.yOfs = yOfs end -- Load saved position if available on PLAYER_LOGIN or VARIABLES_LOADED local loadFrame = CreateFrame("Frame") loadFrame:RegisterEvent("PLAYER_LOGIN") loadFrame:SetScript("OnEvent", function() OctoLatency_SafeCall("PLAYER_LOGIN", function() if (OctoLatencyDB and OctoLatencyDB.point) then OctoLatencyFrame:ClearAllPoints() OctoLatencyFrame:SetPoint(OctoLatencyDB.point, UIParent, OctoLatencyDB.relativePoint, OctoLatencyDB.xOfs, OctoLatencyDB.yOfs) end end) end) -------------------------------------------------------------------------------- -- Slash command: /octolat errors | clearerrors -------------------------------------------------------------------------------- SLASH_OCTOLATENCY1 = "/octolat" SlashCmdList["OCTOLATENCY"] = function(msg) local db = OctoLatency_EnsureDB() msg = string.lower(msg or "") if (msg == "errors") then if (table.getn(db.errorLog) == 0) then DEFAULT_CHAT_FRAME:AddMessage("OctoLatency: no errors logged.") return end DEFAULT_CHAT_FRAME:AddMessage("OctoLatency: last " .. table.getn(db.errorLog) .. " error(s):") for i, entry in ipairs(db.errorLog) do DEFAULT_CHAT_FRAME:AddMessage("[" .. entry.time .. "] " .. entry.context .. ": " .. entry.message) end elseif (msg == "clearerrors") then db.errorLog = {} DEFAULT_CHAT_FRAME:AddMessage("OctoLatency: error log cleared.") else DEFAULT_CHAT_FRAME:AddMessage("OctoLatency commands: /octolat errors, /octolat clearerrors") end end