Fix nil worldLatency tooltip error, add copy-errors UI, gradient title
- Fix OnEnter tooltip crash: attempt to concatenate local 'worldLatency' (a nil value) when GetNetStats() hasn't populated latency yet (e.g. right after login/loading screen); fall back to 0 like OctoLatency_UpdateText already does - Add /octolat copyerrors and a minimap button opening a copy-errors window (auto-highlighted EditBox), since vanilla WoW chat text can't be selected/copied directly - Minimap button also right-click toggles the latency frame and can be dragged to reposition - Color the addon's title in the AddOns list with a per-letter dark-to-light green gradient - Add CHANGELOG.md Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
e28b7781d4
commit
874cadc0f7
@@ -0,0 +1,26 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to OctoLatency are documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- `/octolat copyerrors` and a minimap button, both opening a copy-errors window: a multi-line `EditBox` pre-filled with the error log and auto-highlighted, so the text can be selected and copied with Ctrl+C (vanilla WoW's chat frame doesn't support text selection).
|
||||
- Minimap button also right-click toggles the latency frame, and can be dragged to reposition around the minimap (position saved to `OctoLatencyDB.minimapAngle`).
|
||||
- Colored addon title in the character-select AddOns list: `OctoLatency` now renders as a per-letter gradient from dark to light green (`## Title:` in `OctoLatency.toc`).
|
||||
|
||||
### Fixed
|
||||
- Tooltip (`OnEnter`) no longer errors with `attempt to concatenate local 'worldLatency' (a nil value)`. `GetNetStats()` can return `nil` for latency/bandwidth briefly after login or a loading screen; the tooltip now falls back to `0` for `bandwidth`, `homeLatency`, and `worldLatency`, matching the fallback already used by the status text update.
|
||||
|
||||
## [1.0]
|
||||
### Added
|
||||
- Core addon: draggable frame showing world latency (falling back to home latency) with color-coded text (green < 150ms, yellow 150–350ms, red > 350ms), updated every 2 seconds.
|
||||
- Tooltip on hover showing home latency, world latency, and bandwidth.
|
||||
- `/octolat errors` slash command to view the last 20 logged errors in-game.
|
||||
- `/octolat clearerrors` slash command to clear the error log.
|
||||
- Error logging: tooltip/update/login handlers run through `pcall`, with failures recorded to `OctoLatencyDB.errorLog` (persisted in SavedVariables) and echoed to the chat frame instead of raising a Lua error popup.
|
||||
|
||||
### Fixed
|
||||
- Stuck drag state when the mouse button is released off-frame: dragging now also stops on `OnHide`, not just `OnMouseUp`.
|
||||
|
||||
### Removed
|
||||
- Dead `VARIABLES_LOADED` event registration (no handler was ever attached to it).
|
||||
+157
-3
@@ -52,6 +52,9 @@ function OctoLatency_OnLoad(self)
|
||||
GameTooltip:SetOwner(this, "ANCHOR_TOP")
|
||||
GameTooltip:AddLine("OctoLatency", 0, 1, 1)
|
||||
local bandwidth, latency, homeLatency, worldLatency = GetNetStats()
|
||||
bandwidth = bandwidth or 0
|
||||
homeLatency = homeLatency or 0
|
||||
worldLatency = worldLatency or 0
|
||||
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)
|
||||
@@ -114,7 +117,155 @@ function OctoLatency_SavePosition()
|
||||
OctoLatencyDB.yOfs = yOfs
|
||||
end
|
||||
|
||||
-- Load saved position if available on PLAYER_LOGIN or VARIABLES_LOADED
|
||||
--------------------------------------------------------------------------------
|
||||
-- Copy Errors window: vanilla WoW chat text can't be selected or copied, so
|
||||
-- this shows the log in a multi-line EditBox that's auto-highlighted for Ctrl+C.
|
||||
--------------------------------------------------------------------------------
|
||||
local copyFrame, copyEditBox
|
||||
|
||||
local function OctoLatency_BuildErrorText()
|
||||
local db = OctoLatency_EnsureDB()
|
||||
if (table.getn(db.errorLog) == 0) then
|
||||
return "No errors logged."
|
||||
end
|
||||
local lines = {}
|
||||
for i, entry in ipairs(db.errorLog) do
|
||||
table.insert(lines, "[" .. entry.time .. "] " .. entry.context .. ": " .. entry.message)
|
||||
end
|
||||
return table.concat(lines, "\n")
|
||||
end
|
||||
|
||||
local function OctoLatency_CreateCopyFrame()
|
||||
local f = CreateFrame("Frame", "OctoLatencyCopyFrame", UIParent)
|
||||
f:SetFrameStrata("DIALOG")
|
||||
f:SetWidth(420)
|
||||
f:SetHeight(260)
|
||||
f:SetPoint("CENTER")
|
||||
f:SetBackdrop({
|
||||
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
|
||||
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
|
||||
tile = true, tileSize = 32, edgeSize = 32,
|
||||
insets = { left = 11, right = 12, top = 12, bottom = 11 },
|
||||
})
|
||||
f:EnableMouse(true)
|
||||
f:SetMovable(true)
|
||||
f:RegisterForDrag("LeftButton")
|
||||
f:SetScript("OnDragStart", function() this:StartMoving() end)
|
||||
f:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
|
||||
f:Hide()
|
||||
|
||||
local title = f:CreateFontString(nil, "ARTWORK", "GameFontNormal")
|
||||
title:SetPoint("TOP", f, "TOP", 0, -16)
|
||||
title:SetText("OctoLatency Errors (Ctrl+C to copy, Esc to close)")
|
||||
|
||||
local scroll = CreateFrame("ScrollFrame", "OctoLatencyCopyScroll", f, "UIPanelScrollFrameTemplate")
|
||||
scroll:SetPoint("TOPLEFT", f, "TOPLEFT", 16, -40)
|
||||
scroll:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -34, 44)
|
||||
|
||||
local editBox = CreateFrame("EditBox", "OctoLatencyCopyEditBox", scroll)
|
||||
editBox:SetMultiLine(true)
|
||||
editBox:SetFontObject(ChatFontNormal)
|
||||
editBox:SetWidth(360)
|
||||
editBox:SetAutoFocus(false)
|
||||
editBox:SetScript("OnEscapePressed", function() copyFrame:Hide() end)
|
||||
scroll:SetScrollChild(editBox)
|
||||
copyEditBox = editBox
|
||||
|
||||
local closeBtn = CreateFrame("Button", nil, f, "UIPanelCloseButton")
|
||||
closeBtn:SetPoint("TOPRIGHT", f, "TOPRIGHT", -4, -4)
|
||||
closeBtn:SetScript("OnClick", function() f:Hide() end)
|
||||
|
||||
copyFrame = f
|
||||
end
|
||||
|
||||
function OctoLatency_ShowCopyErrors()
|
||||
if (not copyFrame) then
|
||||
OctoLatency_CreateCopyFrame()
|
||||
end
|
||||
copyEditBox:SetText(OctoLatency_BuildErrorText())
|
||||
copyFrame:Show()
|
||||
copyEditBox:SetFocus()
|
||||
copyEditBox:HighlightText()
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Minimap button: left-click opens the copy-errors window, right-click toggles
|
||||
-- the latency frame, drag to reposition around the minimap.
|
||||
--------------------------------------------------------------------------------
|
||||
local function OctoLatency_UpdateMinimapButtonPosition(button)
|
||||
local db = OctoLatency_EnsureDB()
|
||||
local angle = db.minimapAngle or 220
|
||||
local rad = math.rad(angle)
|
||||
local radius = 80
|
||||
button:ClearAllPoints()
|
||||
button:SetPoint("CENTER", Minimap, "CENTER", radius * math.cos(rad), radius * math.sin(rad))
|
||||
end
|
||||
|
||||
local function OctoLatency_CreateMinimapButton()
|
||||
local button = CreateFrame("Button", "OctoLatencyMinimapButton", Minimap)
|
||||
button:SetWidth(31)
|
||||
button:SetHeight(31)
|
||||
button:SetFrameStrata("MEDIUM")
|
||||
button:SetFrameLevel(8)
|
||||
button:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||||
button:RegisterForDrag("LeftButton")
|
||||
|
||||
local icon = button:CreateTexture(nil, "BACKGROUND")
|
||||
icon:SetWidth(20)
|
||||
icon:SetHeight(20)
|
||||
icon:SetPoint("CENTER", 0, 0)
|
||||
icon:SetTexture("Interface\\Icons\\INV_Misc_PocketWatch_01")
|
||||
|
||||
local overlay = button:CreateTexture(nil, "OVERLAY")
|
||||
overlay:SetWidth(53)
|
||||
overlay:SetHeight(53)
|
||||
overlay:SetPoint("TOPLEFT", 0, 0)
|
||||
overlay:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
|
||||
|
||||
button:SetScript("OnClick", function()
|
||||
OctoLatency_SafeCall("MinimapButtonClick", function()
|
||||
if (arg1 == "RightButton") then
|
||||
if (OctoLatencyFrame:IsShown()) then
|
||||
OctoLatencyFrame:Hide()
|
||||
else
|
||||
OctoLatencyFrame:Show()
|
||||
end
|
||||
else
|
||||
OctoLatency_ShowCopyErrors()
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
button:SetScript("OnEnter", function()
|
||||
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
|
||||
GameTooltip:AddLine("OctoLatency", 0, 1, 1)
|
||||
GameTooltip:AddLine("Left-click: copy error log", 1, 1, 1)
|
||||
GameTooltip:AddLine("Right-click: toggle latency frame", 1, 1, 1)
|
||||
GameTooltip:AddLine("Drag: move this button", 0.7, 0.7, 0.7)
|
||||
GameTooltip:Show()
|
||||
end)
|
||||
button:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
||||
|
||||
button:SetScript("OnDragStart", function()
|
||||
this:SetScript("OnUpdate", function()
|
||||
local mx, my = GetCursorPosition()
|
||||
local scale = Minimap:GetEffectiveScale()
|
||||
mx, my = mx / scale, my / scale
|
||||
local cx, cy = Minimap:GetCenter()
|
||||
local db = OctoLatency_EnsureDB()
|
||||
db.minimapAngle = math.deg(math.atan2(my - cy, mx - cx))
|
||||
OctoLatency_UpdateMinimapButtonPosition(this)
|
||||
end)
|
||||
end)
|
||||
button:SetScript("OnDragStop", function()
|
||||
this:SetScript("OnUpdate", nil)
|
||||
end)
|
||||
|
||||
OctoLatency_UpdateMinimapButtonPosition(button)
|
||||
return button
|
||||
end
|
||||
|
||||
-- Load saved position and create the minimap button on PLAYER_LOGIN
|
||||
local loadFrame = CreateFrame("Frame")
|
||||
loadFrame:RegisterEvent("PLAYER_LOGIN")
|
||||
loadFrame:SetScript("OnEvent", function()
|
||||
@@ -123,11 +274,12 @@ loadFrame:SetScript("OnEvent", function()
|
||||
OctoLatencyFrame:ClearAllPoints()
|
||||
OctoLatencyFrame:SetPoint(OctoLatencyDB.point, UIParent, OctoLatencyDB.relativePoint, OctoLatencyDB.xOfs, OctoLatencyDB.yOfs)
|
||||
end
|
||||
OctoLatency_CreateMinimapButton()
|
||||
end)
|
||||
end)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- Slash command: /octolat errors | clearerrors
|
||||
-- Slash command: /octolat errors | copyerrors | clearerrors
|
||||
--------------------------------------------------------------------------------
|
||||
SLASH_OCTOLATENCY1 = "/octolat"
|
||||
SlashCmdList["OCTOLATENCY"] = function(msg)
|
||||
@@ -143,10 +295,12 @@ SlashCmdList["OCTOLATENCY"] = function(msg)
|
||||
for i, entry in ipairs(db.errorLog) do
|
||||
DEFAULT_CHAT_FRAME:AddMessage("[" .. entry.time .. "] " .. entry.context .. ": " .. entry.message)
|
||||
end
|
||||
elseif (msg == "copyerrors") then
|
||||
OctoLatency_ShowCopyErrors()
|
||||
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")
|
||||
DEFAULT_CHAT_FRAME:AddMessage("OctoLatency commands: /octolat errors, /octolat copyerrors, /octolat clearerrors")
|
||||
end
|
||||
end
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
## Interface: 11200
|
||||
## Title: OctoLatency
|
||||
## Title: |cff003c00O|cff005000c|cff006300t|cff007700o|cff008a00L|cff009e00a|cff00b100t|cff00c500e|cff00d800n|cff00ec00c|cff00ff00y|r
|
||||
## Notes: Lightweight latency monitor with color-coding for Vanilla WoW (1.12.1)
|
||||
## Author: Palladinpala
|
||||
## Version: 1.0
|
||||
|
||||
@@ -32,7 +32,16 @@ you to report:
|
||||
|
||||
- `/octolat errors` — print the last 20 logged errors (with timestamps) to
|
||||
chat.
|
||||
- `/octolat copyerrors` — open a copy-paste window with the same log, since
|
||||
vanilla WoW's chat frame doesn't let you select/copy its text. The window
|
||||
opens with the text already highlighted, so you can just press Ctrl+C.
|
||||
- `/octolat clearerrors` — clear the error log.
|
||||
|
||||
There's also a minimap button for the same purpose without typing a command:
|
||||
|
||||
- **Left-click** — open the copy-errors window.
|
||||
- **Right-click** — toggle the latency frame on/off.
|
||||
- **Drag** — reposition the button around the minimap.
|
||||
|
||||
The log is also saved to your `SavedVariables` file, so it survives
|
||||
logout/relog.
|
||||
|
||||
Reference in New Issue
Block a user