delted old debug window, added new version notice window, added new features to tracker module, updated locales, and updated main addon files.
This commit is contained in:
@@ -1,486 +0,0 @@
|
|||||||
local ADDON_NAME = "HailMaryGuildTools"
|
|
||||||
local HMGT = _G[ADDON_NAME]
|
|
||||||
if not HMGT then return end
|
|
||||||
|
|
||||||
local L = HMGT.L or LibStub("AceLocale-3.0"):GetLocale(ADDON_NAME)
|
|
||||||
local AceGUI = LibStub("AceGUI-3.0", true)
|
|
||||||
|
|
||||||
local function GetOrderedDebugLevels()
|
|
||||||
return { "error", "info", "verbose" }
|
|
||||||
end
|
|
||||||
|
|
||||||
local function GetOrderedDebugScopes()
|
|
||||||
local values = HMGT:GetDebugScopeOptions() or {}
|
|
||||||
local names = { "ALL" }
|
|
||||||
for scope in pairs(values) do
|
|
||||||
if scope ~= "ALL" then
|
|
||||||
names[#names + 1] = scope
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.sort(names, function(a, b)
|
|
||||||
if a == "ALL" then return true end
|
|
||||||
if b == "ALL" then return false end
|
|
||||||
return tostring(values[a] or a) < tostring(values[b] or b)
|
|
||||||
end)
|
|
||||||
return names, values
|
|
||||||
end
|
|
||||||
|
|
||||||
local function SetFilterButtonText(buttonWidget, prefix, valueLabel)
|
|
||||||
if not buttonWidget then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
buttonWidget:SetText(string.format("%s: %s", tostring(prefix or ""), tostring(valueLabel or "")))
|
|
||||||
end
|
|
||||||
|
|
||||||
local function AdvanceDebugLevel(step)
|
|
||||||
local levels = GetOrderedDebugLevels()
|
|
||||||
local current = HMGT:GetConfiguredDebugLevel()
|
|
||||||
local nextIndex = 1
|
|
||||||
for index, value in ipairs(levels) do
|
|
||||||
if value == current then
|
|
||||||
nextIndex = index + (step or 1)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if nextIndex < 1 then
|
|
||||||
nextIndex = #levels
|
|
||||||
elseif nextIndex > #levels then
|
|
||||||
nextIndex = 1
|
|
||||||
end
|
|
||||||
HMGT.db.profile.debugLevel = levels[nextIndex]
|
|
||||||
HMGT:RefreshDebugWindow()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function AdvanceDebugScope(step)
|
|
||||||
local scopes, labels = GetOrderedDebugScopes()
|
|
||||||
local current = (HMGT.db and HMGT.db.profile and HMGT.db.profile.debugScope) or "ALL"
|
|
||||||
local nextIndex = 1
|
|
||||||
for index, value in ipairs(scopes) do
|
|
||||||
if value == current then
|
|
||||||
nextIndex = index + (step or 1)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if nextIndex < 1 then
|
|
||||||
nextIndex = #scopes
|
|
||||||
elseif nextIndex > #scopes then
|
|
||||||
nextIndex = 1
|
|
||||||
end
|
|
||||||
HMGT.db.profile.debugScope = scopes[nextIndex]
|
|
||||||
HMGT:RefreshDebugWindow()
|
|
||||||
end
|
|
||||||
|
|
||||||
function HMGT:SetDebugWindowMinimized(minimized)
|
|
||||||
local frame = self.debugWindow
|
|
||||||
if not frame then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
minimized = minimized and true or false
|
|
||||||
self.debugWindowStatus = self.debugWindowStatus or {
|
|
||||||
width = 860,
|
|
||||||
height = 340,
|
|
||||||
}
|
|
||||||
self.debugWindowStatus.minimized = minimized
|
|
||||||
|
|
||||||
local collapsedHeight = 64
|
|
||||||
if minimized then
|
|
||||||
self.debugWindowStatus.restoreHeight = self.debugWindowStatus.height or frame:GetHeight() or 340
|
|
||||||
end
|
|
||||||
|
|
||||||
local targetHeight = minimized
|
|
||||||
and collapsedHeight
|
|
||||||
or (self.debugWindowStatus.restoreHeight or self.debugWindowStatus.height or 340)
|
|
||||||
|
|
||||||
if frame.aceWidget then
|
|
||||||
frame.aceWidget:EnableResize(not minimized)
|
|
||||||
frame.aceWidget:SetHeight(targetHeight)
|
|
||||||
else
|
|
||||||
frame:SetHeight(targetHeight)
|
|
||||||
end
|
|
||||||
|
|
||||||
if frame.minimizeButton then
|
|
||||||
frame.minimizeButton:SetText(minimized and "+" or "-")
|
|
||||||
end
|
|
||||||
if frame.clearButton then
|
|
||||||
local buttonFrame = frame.clearButton.frame or frame.clearButton
|
|
||||||
buttonFrame:SetShown(not minimized)
|
|
||||||
end
|
|
||||||
if frame.selectButton then
|
|
||||||
local buttonFrame = frame.selectButton.frame or frame.selectButton
|
|
||||||
buttonFrame:SetShown(not minimized)
|
|
||||||
end
|
|
||||||
if frame.levelFilter then
|
|
||||||
local filterFrame = frame.levelFilter.frame or frame.levelFilter
|
|
||||||
filterFrame:SetShown(not minimized)
|
|
||||||
end
|
|
||||||
if frame.scopeFilter then
|
|
||||||
local filterFrame = frame.scopeFilter.frame or frame.scopeFilter
|
|
||||||
filterFrame:SetShown(not minimized)
|
|
||||||
end
|
|
||||||
if frame.logWidget then
|
|
||||||
frame.logWidget.frame:SetShown(not minimized)
|
|
||||||
end
|
|
||||||
if frame.scrollBG then
|
|
||||||
frame.scrollBG:SetShown(not minimized)
|
|
||||||
end
|
|
||||||
|
|
||||||
if not minimized then
|
|
||||||
self:RefreshDebugWindow()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function HMGT:ToggleDebugWindowMinimized()
|
|
||||||
self:SetDebugWindowMinimized(not (self.debugWindowStatus and self.debugWindowStatus.minimized))
|
|
||||||
end
|
|
||||||
|
|
||||||
function HMGT:EnsureDebugWindow()
|
|
||||||
if self.debugWindow then
|
|
||||||
return self.debugWindow
|
|
||||||
end
|
|
||||||
|
|
||||||
local frameWidget
|
|
||||||
if AceGUI then
|
|
||||||
frameWidget = AceGUI:Create("Frame")
|
|
||||||
self.debugWindowStatus = self.debugWindowStatus or {
|
|
||||||
width = 860,
|
|
||||||
height = 340,
|
|
||||||
}
|
|
||||||
frameWidget:SetTitle(L["DEBUG_WINDOW_TITLE"] or "HMGT Debug Console")
|
|
||||||
frameWidget:SetStatusText(L["DEBUG_WINDOW_HINT"] or "Mouse wheel scrolls, Ctrl+A selects all, Ctrl+C copies selected text")
|
|
||||||
frameWidget:SetStatusTable(self.debugWindowStatus)
|
|
||||||
frameWidget:SetWidth(self.debugWindowStatus.width or 860)
|
|
||||||
frameWidget:SetHeight(self.debugWindowStatus.height or 340)
|
|
||||||
frameWidget:EnableResize(true)
|
|
||||||
frameWidget.frame:SetClampedToScreen(true)
|
|
||||||
frameWidget.frame:SetToplevel(true)
|
|
||||||
frameWidget.frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
|
||||||
frameWidget:Hide()
|
|
||||||
end
|
|
||||||
|
|
||||||
local frame = frameWidget and frameWidget.frame or CreateFrame("Frame", "HMGT_DebugWindow", UIParent, "BackdropTemplate")
|
|
||||||
if not frameWidget then
|
|
||||||
frame:SetSize(860, 340)
|
|
||||||
frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
|
|
||||||
frame:SetFrameStrata("DIALOG")
|
|
||||||
frame:SetClampedToScreen(true)
|
|
||||||
frame:SetMovable(true)
|
|
||||||
frame:EnableMouse(true)
|
|
||||||
frame:RegisterForDrag("LeftButton")
|
|
||||||
frame:SetScript("OnDragStart", function(selfFrame) selfFrame:StartMoving() end)
|
|
||||||
frame:SetScript("OnDragStop", function(selfFrame) selfFrame:StopMovingOrSizing() end)
|
|
||||||
frame:SetBackdrop({
|
|
||||||
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background-Dark",
|
|
||||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
||||||
edgeSize = 12,
|
|
||||||
insets = { left = 3, right = 3, top = 3, bottom = 3 },
|
|
||||||
})
|
|
||||||
frame:SetBackdropColor(0.05, 0.05, 0.06, 0.95)
|
|
||||||
frame:SetBackdropBorderColor(0.35, 0.55, 0.85, 1)
|
|
||||||
frame:Hide()
|
|
||||||
|
|
||||||
local title = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
|
|
||||||
title:SetPoint("TOPLEFT", frame, "TOPLEFT", 14, -12)
|
|
||||||
title:SetText(L["DEBUG_WINDOW_TITLE"] or "HMGT Debug Console")
|
|
||||||
frame.title = title
|
|
||||||
|
|
||||||
local closeButton = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
|
|
||||||
closeButton:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -5, -5)
|
|
||||||
frame.closeButton = closeButton
|
|
||||||
|
|
||||||
local minimizeButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
|
||||||
minimizeButton:SetSize(22, 20)
|
|
||||||
minimizeButton:SetPoint("TOPRIGHT", closeButton, "TOPLEFT", -2, 0)
|
|
||||||
minimizeButton:SetText((self.debugWindowStatus and self.debugWindowStatus.minimized) and "+" or "-")
|
|
||||||
minimizeButton:SetScript("OnClick", function()
|
|
||||||
HMGT:ToggleDebugWindowMinimized()
|
|
||||||
end)
|
|
||||||
frame.minimizeButton = minimizeButton
|
|
||||||
end
|
|
||||||
|
|
||||||
frame.aceWidget = frameWidget
|
|
||||||
|
|
||||||
if frameWidget and AceGUI then
|
|
||||||
local content = frameWidget.content
|
|
||||||
|
|
||||||
local minimizeButton = AceGUI:Create("Button")
|
|
||||||
minimizeButton:SetText((self.debugWindowStatus and self.debugWindowStatus.minimized) and "+" or "-")
|
|
||||||
minimizeButton:SetWidth(24)
|
|
||||||
minimizeButton:SetCallback("OnClick", function()
|
|
||||||
HMGT:ToggleDebugWindowMinimized()
|
|
||||||
end)
|
|
||||||
minimizeButton.frame:SetParent(frame)
|
|
||||||
minimizeButton.frame:ClearAllPoints()
|
|
||||||
minimizeButton.frame:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -34, -4)
|
|
||||||
minimizeButton.frame:SetHeight(20)
|
|
||||||
minimizeButton.frame:Show()
|
|
||||||
frame.minimizeButton = minimizeButton
|
|
||||||
|
|
||||||
local clearButton = AceGUI:Create("Button")
|
|
||||||
clearButton:SetText(L["OPT_DEBUG_CLEAR"] or "Clear log")
|
|
||||||
clearButton:SetWidth(120)
|
|
||||||
clearButton:SetCallback("OnClick", function()
|
|
||||||
HMGT:ClearDebugLog()
|
|
||||||
end)
|
|
||||||
clearButton.frame:SetParent(content)
|
|
||||||
clearButton.frame:ClearAllPoints()
|
|
||||||
clearButton.frame:SetPoint("TOPRIGHT", content, "TOPRIGHT", 0, -2)
|
|
||||||
clearButton.frame:Show()
|
|
||||||
frame.clearButton = clearButton
|
|
||||||
|
|
||||||
local selectButton = AceGUI:Create("Button")
|
|
||||||
selectButton:SetText(L["OPT_DEBUG_SELECT_ALL"] or "Select all")
|
|
||||||
selectButton:SetWidth(120)
|
|
||||||
selectButton:SetCallback("OnClick", function()
|
|
||||||
if frame.editBox then
|
|
||||||
frame.editBox:SetFocus()
|
|
||||||
frame.editBox:HighlightText(0)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
selectButton.frame:SetParent(content)
|
|
||||||
selectButton.frame:ClearAllPoints()
|
|
||||||
selectButton.frame:SetPoint("TOPRIGHT", clearButton.frame, "TOPLEFT", -6, 0)
|
|
||||||
selectButton.frame:Show()
|
|
||||||
frame.selectButton = selectButton
|
|
||||||
|
|
||||||
local levelFilter = AceGUI:Create("Button")
|
|
||||||
levelFilter:SetWidth(150)
|
|
||||||
levelFilter:SetCallback("OnClick", function()
|
|
||||||
AdvanceDebugLevel(1)
|
|
||||||
end)
|
|
||||||
levelFilter.frame:SetParent(content)
|
|
||||||
levelFilter.frame:ClearAllPoints()
|
|
||||||
levelFilter.frame:SetPoint("TOPLEFT", content, "TOPLEFT", 0, 0)
|
|
||||||
levelFilter.frame:Show()
|
|
||||||
frame.levelFilter = levelFilter
|
|
||||||
|
|
||||||
local scopeFilter = AceGUI:Create("Button")
|
|
||||||
scopeFilter:SetWidth(180)
|
|
||||||
scopeFilter:SetCallback("OnClick", function()
|
|
||||||
AdvanceDebugScope(1)
|
|
||||||
end)
|
|
||||||
scopeFilter.frame:SetParent(content)
|
|
||||||
scopeFilter.frame:ClearAllPoints()
|
|
||||||
scopeFilter.frame:SetPoint("TOPLEFT", levelFilter.frame, "TOPRIGHT", 8, 0)
|
|
||||||
scopeFilter.frame:Show()
|
|
||||||
frame.scopeFilter = scopeFilter
|
|
||||||
|
|
||||||
local logWidget = AceGUI:Create("MultiLineEditBox")
|
|
||||||
logWidget:SetLabel("")
|
|
||||||
logWidget:DisableButton(true)
|
|
||||||
logWidget:SetNumLines(18)
|
|
||||||
logWidget:SetText("")
|
|
||||||
logWidget.frame:SetParent(content)
|
|
||||||
logWidget.frame:ClearAllPoints()
|
|
||||||
logWidget.frame:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -54)
|
|
||||||
logWidget.frame:SetPoint("BOTTOMRIGHT", content, "BOTTOMRIGHT", 0, 0)
|
|
||||||
logWidget.frame:Show()
|
|
||||||
logWidget:SetCallback("OnTextChanged", function()
|
|
||||||
HMGT:RefreshDebugWindow()
|
|
||||||
end)
|
|
||||||
logWidget.editBox:SetScript("OnKeyDown", function(selfBox, key)
|
|
||||||
if IsControlKeyDown() and (key == "A" or key == "a") then
|
|
||||||
selfBox:HighlightText(0)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
frame.logWidget = logWidget
|
|
||||||
frame.editBox = logWidget.editBox
|
|
||||||
frame.scrollFrame = logWidget.scrollFrame
|
|
||||||
|
|
||||||
self.debugWindow = frame
|
|
||||||
self:SetDebugWindowMinimized(self.debugWindowStatus and self.debugWindowStatus.minimized)
|
|
||||||
return frame
|
|
||||||
end
|
|
||||||
|
|
||||||
local clearButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
|
||||||
clearButton:SetSize(90, 22)
|
|
||||||
clearButton:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -30, -6)
|
|
||||||
clearButton:SetText(L["OPT_DEBUG_CLEAR"] or "Clear log")
|
|
||||||
clearButton:SetScript("OnClick", function()
|
|
||||||
HMGT:ClearDebugLog()
|
|
||||||
end)
|
|
||||||
frame.clearButton = clearButton
|
|
||||||
|
|
||||||
local selectButton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
|
||||||
selectButton:SetSize(90, 22)
|
|
||||||
selectButton:SetPoint("TOPRIGHT", clearButton, "TOPLEFT", -6, 0)
|
|
||||||
selectButton:SetText(L["OPT_DEBUG_SELECT_ALL"] or "Select all")
|
|
||||||
selectButton:SetScript("OnClick", function()
|
|
||||||
if frame.editBox then
|
|
||||||
frame.editBox:SetFocus()
|
|
||||||
frame.editBox:HighlightText(0)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
frame.selectButton = selectButton
|
|
||||||
|
|
||||||
local scopeFilter = CreateFrame("Frame", nil, frame)
|
|
||||||
scopeFilter:SetSize(170, 22)
|
|
||||||
scopeFilter:SetPoint("TOPLEFT", frame, "TOPLEFT", 16, -8)
|
|
||||||
frame.scopeFilter = scopeFilter
|
|
||||||
|
|
||||||
local scrollBG = CreateFrame("Frame", nil, frame, "BackdropTemplate")
|
|
||||||
scrollBG:SetBackdrop({
|
|
||||||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
|
||||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
|
||||||
edgeSize = 16,
|
|
||||||
insets = { left = 4, right = 3, top = 4, bottom = 3 },
|
|
||||||
})
|
|
||||||
scrollBG:SetBackdropColor(0, 0, 0, 0.95)
|
|
||||||
scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4, 1)
|
|
||||||
scrollBG:SetPoint("TOPLEFT", frame, "TOPLEFT", 14, -36)
|
|
||||||
scrollBG:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -30, 14)
|
|
||||||
frame.scrollBG = scrollBG
|
|
||||||
|
|
||||||
local scrollFrame = CreateFrame("ScrollFrame", nil, scrollBG, "UIPanelScrollFrameTemplate")
|
|
||||||
scrollFrame:SetPoint("TOPLEFT", scrollBG, "TOPLEFT", 6, -6)
|
|
||||||
scrollFrame:SetPoint("BOTTOMRIGHT", scrollBG, "BOTTOMRIGHT", -27, 4)
|
|
||||||
scrollFrame:EnableMouseWheel(true)
|
|
||||||
scrollFrame:SetScript("OnMouseWheel", function(selfMsg, delta)
|
|
||||||
if delta > 0 then
|
|
||||||
selfMsg:SetVerticalScroll(math.max(0, selfMsg:GetVerticalScroll() - 42))
|
|
||||||
else
|
|
||||||
selfMsg:SetVerticalScroll(selfMsg:GetVerticalScroll() + 42)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
frame.scrollFrame = scrollFrame
|
|
||||||
|
|
||||||
local editBox = CreateFrame("EditBox", nil, scrollFrame)
|
|
||||||
editBox:SetMultiLine(true)
|
|
||||||
editBox:SetAutoFocus(false)
|
|
||||||
editBox:SetFontObject(ChatFontNormal)
|
|
||||||
editBox:SetWidth(780)
|
|
||||||
editBox:SetTextInsets(6, 6, 6, 6)
|
|
||||||
editBox:EnableMouse(true)
|
|
||||||
editBox:SetScript("OnEscapePressed", function(selfBox)
|
|
||||||
selfBox:ClearFocus()
|
|
||||||
end)
|
|
||||||
editBox:SetScript("OnKeyDown", function(selfBox, key)
|
|
||||||
if IsControlKeyDown() and (key == "A" or key == "a") then
|
|
||||||
selfBox:HighlightText(0)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
editBox:SetScript("OnTextChanged", function(selfBox, userInput)
|
|
||||||
if userInput then
|
|
||||||
HMGT:RefreshDebugWindow()
|
|
||||||
else
|
|
||||||
selfBox:SetCursorPosition(selfBox:GetNumLetters())
|
|
||||||
selfBox:SetHeight(math.max(scrollFrame:GetHeight(), HMGT:GetDebugWindowTextHeight(frame, selfBox:GetText()) + 16))
|
|
||||||
scrollFrame:UpdateScrollChildRect()
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
editBox:SetScript("OnMouseUp", function(selfBox)
|
|
||||||
selfBox:SetFocus()
|
|
||||||
end)
|
|
||||||
scrollFrame:SetScrollChild(editBox)
|
|
||||||
frame.editBox = editBox
|
|
||||||
|
|
||||||
local measureText = frame:CreateFontString(nil, "ARTWORK", "ChatFontNormal")
|
|
||||||
measureText:SetJustifyH("LEFT")
|
|
||||||
measureText:SetJustifyV("TOP")
|
|
||||||
if measureText.SetSpacing then
|
|
||||||
measureText:SetSpacing(2)
|
|
||||||
end
|
|
||||||
measureText:SetWidth(768)
|
|
||||||
frame.measureText = measureText
|
|
||||||
|
|
||||||
self.debugWindow = frame
|
|
||||||
self:SetDebugWindowMinimized(self.debugWindowStatus and self.debugWindowStatus.minimized)
|
|
||||||
return frame
|
|
||||||
end
|
|
||||||
|
|
||||||
function HMGT:GetDebugWindowTextHeight(frame, text)
|
|
||||||
if not frame or not frame.measureText then
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
local width = 768
|
|
||||||
if frame.editBox then
|
|
||||||
width = math.max(1, (frame.editBox:GetWidth() or width) - 12)
|
|
||||||
end
|
|
||||||
frame.measureText:SetWidth(width)
|
|
||||||
frame.measureText:SetText(text or "")
|
|
||||||
return frame.measureText:GetStringHeight()
|
|
||||||
end
|
|
||||||
|
|
||||||
function HMGT:RefreshDebugWindow()
|
|
||||||
local frame = self:EnsureDebugWindow()
|
|
||||||
if not frame then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local filtered = self:GetFilteredDebugBuffer() or self.debugBuffer or {}
|
|
||||||
local text = table.concat(filtered, "\n")
|
|
||||||
if frame.logWidget and frame.editBox then
|
|
||||||
if frame.levelFilter then
|
|
||||||
local levelOptions = self:GetDebugLevelOptions()
|
|
||||||
SetFilterButtonText(frame.levelFilter, L["OPT_DEBUG_LEVEL"] or "Level", levelOptions[self:GetConfiguredDebugLevel()])
|
|
||||||
end
|
|
||||||
if frame.scopeFilter then
|
|
||||||
local scopeOptions = self:GetDebugScopeOptions()
|
|
||||||
local currentScope = (self.db and self.db.profile and self.db.profile.debugScope) or "ALL"
|
|
||||||
SetFilterButtonText(frame.scopeFilter, L["OPT_DEBUG_SCOPE"] or "Module", scopeOptions[currentScope] or currentScope)
|
|
||||||
end
|
|
||||||
frame.logWidget:SetText(text)
|
|
||||||
frame.editBox:SetCursorPosition(frame.editBox:GetNumLetters())
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if not frame.editBox then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
frame.editBox:SetText(text)
|
|
||||||
frame.editBox:SetCursorPosition(#text)
|
|
||||||
frame.editBox:SetHeight(math.max(frame.scrollFrame:GetHeight(), self:GetDebugWindowTextHeight(frame, text) + 16))
|
|
||||||
frame.scrollFrame:SetVerticalScroll(math.max(0, frame.editBox:GetHeight() - frame.scrollFrame:GetHeight()))
|
|
||||||
end
|
|
||||||
|
|
||||||
function HMGT:UpdateDebugWindowVisibility()
|
|
||||||
if self.db and self.db.profile then
|
|
||||||
self.db.profile.debug = false
|
|
||||||
end
|
|
||||||
local frame = self.debugWindow
|
|
||||||
if not frame then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local widget = frame.aceWidget
|
|
||||||
if widget then
|
|
||||||
widget:Hide()
|
|
||||||
else
|
|
||||||
frame:Hide()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function HMGT:ClearDebugLog()
|
|
||||||
wipe(self.debugBuffer)
|
|
||||||
if self.debugWindow and self.debugWindow.logWidget then
|
|
||||||
self.debugWindow.logWidget:SetText("")
|
|
||||||
self.debugWindow.editBox:SetCursorPosition(0)
|
|
||||||
self.debugWindow.scrollFrame:SetVerticalScroll(0)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if self.debugWindow and self.debugWindow.editBox then
|
|
||||||
self.debugWindow.editBox:SetText("")
|
|
||||||
self.debugWindow.scrollFrame:SetVerticalScroll(0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function HMGT:ToggleDebugWindowShortcut()
|
|
||||||
if self.db and self.db.profile then
|
|
||||||
self.db.profile.debug = false
|
|
||||||
end
|
|
||||||
local frame = self.debugWindow
|
|
||||||
if not frame then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local widget = frame.aceWidget
|
|
||||||
if widget then
|
|
||||||
widget:Hide()
|
|
||||||
else
|
|
||||||
frame:Hide()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function HMGT:DumpDebugLog(maxLines)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
@@ -68,12 +68,14 @@ local function GetPlayerVersionText(name)
|
|||||||
return tostring(HMGT.ADDON_VERSION or "dev"), tonumber(HMGT.PROTOCOL_VERSION) or 0, true
|
return tostring(HMGT.ADDON_VERSION or "dev"), tonumber(HMGT.PROTOCOL_VERSION) or 0, true
|
||||||
end
|
end
|
||||||
|
|
||||||
local version = HMGT.peerVersions and HMGT.peerVersions[normalized] or nil
|
local addonStatus = HMGT.GetPlayerAddonStatus and HMGT:GetPlayerAddonStatus(normalized) or nil
|
||||||
local protocol = HMGT.GetPeerProtocolVersion and HMGT:GetPeerProtocolVersion(normalized) or 0
|
if addonStatus and addonStatus.mode == "hmgt" and addonStatus.version and addonStatus.version ~= "" then
|
||||||
if version and version ~= "" then
|
return tostring(addonStatus.version), tonumber(addonStatus.protocol) or 0, true
|
||||||
return tostring(version), tonumber(protocol) or 0, true
|
|
||||||
end
|
end
|
||||||
return nil, tonumber(protocol) or 0, false
|
if addonStatus and addonStatus.mode == "bridge" then
|
||||||
|
return L["VERSION_WINDOW_BRIDGE_MODE"] or "Bridge Mode", 0, true
|
||||||
|
end
|
||||||
|
return nil, tonumber(addonStatus and addonStatus.protocol) or 0, false
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ApplyClassIcon(texture, classTag)
|
local function ApplyClassIcon(texture, classTag)
|
||||||
@@ -167,7 +169,11 @@ function HMGT:RefreshVersionNoticeWindow()
|
|||||||
local versionText, protocol, hasAddon = GetPlayerVersionText(info.name)
|
local versionText, protocol, hasAddon = GetPlayerVersionText(info.name)
|
||||||
if hasAddon then
|
if hasAddon then
|
||||||
row.versionText:SetText(versionText or "?")
|
row.versionText:SetText(versionText or "?")
|
||||||
row.versionText:SetTextColor(0.9, 0.9, 0.9, 1)
|
if versionText == (L["VERSION_WINDOW_BRIDGE_MODE"] or "Bridge Mode") then
|
||||||
|
row.versionText:SetTextColor(0.55, 0.82, 1, 1)
|
||||||
|
else
|
||||||
|
row.versionText:SetTextColor(0.9, 0.9, 0.9, 1)
|
||||||
|
end
|
||||||
row.protocolText:SetText(protocol > 0 and tostring(protocol) or "-")
|
row.protocolText:SetText(protocol > 0 and tostring(protocol) or "-")
|
||||||
row.protocolText:SetTextColor(0.75, 0.75, 0.75, 1)
|
row.protocolText:SetTextColor(0.75, 0.75, 0.75, 1)
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -288,16 +288,20 @@ HMGT.powerTracking = {
|
|||||||
}
|
}
|
||||||
HMGT.pendingSpellPowerCosts = {}
|
HMGT.pendingSpellPowerCosts = {}
|
||||||
HMGT.demoModeData = {}
|
HMGT.demoModeData = {}
|
||||||
HMGT.peerVersions = {}
|
|
||||||
HMGT.versionWarnings = {}
|
HMGT.versionWarnings = {}
|
||||||
HMGT.versionWhisperWarnings = {}
|
HMGT.versionWhisperWarnings = {}
|
||||||
|
HMGT.playerStatus = {}
|
||||||
HMGT.debugBuffer = {}
|
HMGT.debugBuffer = {}
|
||||||
HMGT.debugBufferMax = 500
|
HMGT.debugBufferMax = 500
|
||||||
HMGT.enabledDebugScopes = {
|
HMGT.enabledDebugScopes = {
|
||||||
General = true,
|
General = true,
|
||||||
Debug = true,
|
Debug = true,
|
||||||
Comm = true,
|
Comm = true,
|
||||||
TrackedSpells = true,
|
TrackerCore = true,
|
||||||
|
TrackerSync = true,
|
||||||
|
TrackerUI = true,
|
||||||
|
TrackerBridge = true,
|
||||||
|
TrackerState = true,
|
||||||
PowerSpend = true,
|
PowerSpend = true,
|
||||||
}
|
}
|
||||||
HMGT.pendingReliableMessages = HMGT.pendingReliableMessages or {}
|
HMGT.pendingReliableMessages = HMGT.pendingReliableMessages or {}
|
||||||
@@ -311,7 +315,11 @@ local DEBUG_SCOPE_LABELS = {
|
|||||||
General = "General",
|
General = "General",
|
||||||
Debug = "Debug",
|
Debug = "Debug",
|
||||||
Comm = "Communication",
|
Comm = "Communication",
|
||||||
TrackedSpells = "Tracked Spells",
|
TrackerCore = "Tracker Core",
|
||||||
|
TrackerSync = "Tracker Sync",
|
||||||
|
TrackerUI = "Tracker UI",
|
||||||
|
TrackerBridge = "Tracker Bridge",
|
||||||
|
TrackerState = "Tracker State",
|
||||||
PowerSpend = "Power Spend",
|
PowerSpend = "Power Spend",
|
||||||
RaidTimeline = "Raid Timeline",
|
RaidTimeline = "Raid Timeline",
|
||||||
Notes = "Notes",
|
Notes = "Notes",
|
||||||
@@ -340,8 +348,12 @@ end
|
|||||||
|
|
||||||
function HMGT:GetTrackerDebugScope(tracker)
|
function HMGT:GetTrackerDebugScope(tracker)
|
||||||
local trackerName = nil
|
local trackerName = nil
|
||||||
|
local trackerId = nil
|
||||||
|
local trackerType = nil
|
||||||
if type(tracker) == "table" then
|
if type(tracker) == "table" then
|
||||||
trackerName = tracker.name
|
trackerName = tracker.name
|
||||||
|
trackerId = tonumber(tracker.id)
|
||||||
|
trackerType = tracker.trackerType
|
||||||
if (not trackerName or trackerName == "") and tracker.id then
|
if (not trackerName or trackerName == "") and tracker.id then
|
||||||
trackerName = string.format("Tracker %s", tostring(tracker.id))
|
trackerName = string.format("Tracker %s", tostring(tracker.id))
|
||||||
end
|
end
|
||||||
@@ -353,7 +365,106 @@ function HMGT:GetTrackerDebugScope(tracker)
|
|||||||
if trackerName == "" then
|
if trackerName == "" then
|
||||||
trackerName = "Tracker"
|
trackerName = "Tracker"
|
||||||
end
|
end
|
||||||
return "Tracker: " .. trackerName
|
local prefix = "Tracker"
|
||||||
|
if trackerType == "group" then
|
||||||
|
prefix = "Tracker Group"
|
||||||
|
elseif trackerType == "normal" then
|
||||||
|
prefix = "Tracker Normal"
|
||||||
|
end
|
||||||
|
if trackerId then
|
||||||
|
return string.format("%s #%d: %s", prefix, trackerId, trackerName)
|
||||||
|
end
|
||||||
|
return prefix .. ": " .. trackerName
|
||||||
|
end
|
||||||
|
|
||||||
|
function HMGT:GetPlayerStatus(playerName, create)
|
||||||
|
local normalizedName = self:NormalizePlayerName(playerName)
|
||||||
|
if not normalizedName or normalizedName == "" then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
self.playerStatus = self.playerStatus or {}
|
||||||
|
if create then
|
||||||
|
self.playerStatus[normalizedName] = self.playerStatus[normalizedName] or {}
|
||||||
|
end
|
||||||
|
return self.playerStatus[normalizedName]
|
||||||
|
end
|
||||||
|
|
||||||
|
function HMGT:SetPlayerVersionStatus(playerName, version, protocol, sourceTag)
|
||||||
|
local status = self:GetPlayerStatus(playerName, true)
|
||||||
|
if not status then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if version and version ~= "" then
|
||||||
|
status.version = tostring(version)
|
||||||
|
end
|
||||||
|
if tonumber(protocol) then
|
||||||
|
status.protocol = tonumber(protocol)
|
||||||
|
end
|
||||||
|
if sourceTag and sourceTag ~= "" then
|
||||||
|
status.versionSource = tostring(sourceTag)
|
||||||
|
end
|
||||||
|
status.mode = "hmgt"
|
||||||
|
return status
|
||||||
|
end
|
||||||
|
|
||||||
|
function HMGT:SetPlayerBridgeStatus(playerName, sourceName)
|
||||||
|
local source = tostring(sourceName or "")
|
||||||
|
if source == "" then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
local status = self:GetPlayerStatus(playerName, true)
|
||||||
|
if not status then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
status.bridgeSource = source
|
||||||
|
if not status.version or status.version == "" then
|
||||||
|
status.mode = "bridge"
|
||||||
|
end
|
||||||
|
return status
|
||||||
|
end
|
||||||
|
|
||||||
|
function HMGT:GetPlayerAddonStatus(playerName)
|
||||||
|
local status = self:GetPlayerStatus(playerName, false)
|
||||||
|
if not status then
|
||||||
|
return {
|
||||||
|
mode = "missing",
|
||||||
|
version = nil,
|
||||||
|
protocol = 0,
|
||||||
|
bridgeSource = nil,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local version = status.version
|
||||||
|
local protocol = tonumber(status.protocol) or 0
|
||||||
|
local bridgeSource = status.bridgeSource
|
||||||
|
local mode = status.mode
|
||||||
|
|
||||||
|
if version and version ~= "" then
|
||||||
|
mode = "hmgt"
|
||||||
|
elseif bridgeSource and bridgeSource ~= "" then
|
||||||
|
mode = "bridge"
|
||||||
|
else
|
||||||
|
mode = "missing"
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
mode = mode,
|
||||||
|
version = version,
|
||||||
|
protocol = protocol,
|
||||||
|
bridgeSource = bridgeSource,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function HMGT:ClearPlayerStatus(playerName)
|
||||||
|
local normalizedName = self:NormalizePlayerName(playerName)
|
||||||
|
if not normalizedName or not self.playerStatus then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if self.playerStatus[normalizedName] then
|
||||||
|
self.playerStatus[normalizedName] = nil
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function HMGT:GetStaticDebugScopeOptions()
|
function HMGT:GetStaticDebugScopeOptions()
|
||||||
@@ -456,6 +567,10 @@ function HMGT:IsReliableCommType(msgType)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function HMGT:GetPeerProtocolVersion(playerName)
|
function HMGT:GetPeerProtocolVersion(playerName)
|
||||||
|
local status = self:GetPlayerStatus(playerName, false)
|
||||||
|
if status and tonumber(status.protocol) then
|
||||||
|
return tonumber(status.protocol) or 0
|
||||||
|
end
|
||||||
local normalizedName = self:NormalizePlayerName(playerName)
|
local normalizedName = self:NormalizePlayerName(playerName)
|
||||||
local peerProtocols = self.peerProtocols or {}
|
local peerProtocols = self.peerProtocols or {}
|
||||||
return tonumber(normalizedName and peerProtocols[normalizedName]) or 0
|
return tonumber(normalizedName and peerProtocols[normalizedName]) or 0
|
||||||
@@ -469,6 +584,7 @@ function HMGT:RememberPeerProtocolVersion(playerName, protocol)
|
|||||||
end
|
end
|
||||||
self.peerProtocols = self.peerProtocols or {}
|
self.peerProtocols = self.peerProtocols or {}
|
||||||
self.peerProtocols[normalizedName] = numeric
|
self.peerProtocols[normalizedName] = numeric
|
||||||
|
self:SetPlayerVersionStatus(normalizedName, nil, numeric, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ParseVersionTokens(version)
|
local function ParseVersionTokens(version)
|
||||||
@@ -747,7 +863,32 @@ function HMGT:SendDirectMessage(payload, target, prio)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function HMGT:DebugScoped(level, scope, fmt, ...)
|
function HMGT:DebugScoped(level, scope, fmt, ...)
|
||||||
return
|
local normalizedLevel = tostring(level or "info"):lower()
|
||||||
|
if not DEBUG_LEVELS[normalizedLevel] then
|
||||||
|
normalizedLevel = "info"
|
||||||
|
end
|
||||||
|
|
||||||
|
local normalizedScope = tostring(scope or "General"):match("^%s*(.-)%s*$")
|
||||||
|
if normalizedScope == "" then
|
||||||
|
normalizedScope = "General"
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, message = pcall(string.format, tostring(fmt or ""), ...)
|
||||||
|
if not ok then
|
||||||
|
message = tostring(fmt or "")
|
||||||
|
end
|
||||||
|
local line = string.format("%s [%s][%s] %s", date("%H:%M:%S"), string.upper(normalizedLevel), normalizedScope, tostring(message or ""))
|
||||||
|
|
||||||
|
self.debugBuffer = self.debugBuffer or {}
|
||||||
|
self.debugBuffer[#self.debugBuffer + 1] = line
|
||||||
|
local maxLines = tonumber(self.debugBufferMax) or 500
|
||||||
|
while #self.debugBuffer > maxLines do
|
||||||
|
table.remove(self.debugBuffer, 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.debugWindow and self.debugWindow.IsShown and self.debugWindow:IsShown() and self.RefreshDebugWindow then
|
||||||
|
self:RefreshDebugWindow()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function HMGT:Debug(fmt, ...)
|
function HMGT:Debug(fmt, ...)
|
||||||
@@ -764,7 +905,7 @@ end
|
|||||||
|
|
||||||
function HMGT:RegisterPeerVersion(playerName, version, protocol, sourceTag)
|
function HMGT:RegisterPeerVersion(playerName, version, protocol, sourceTag)
|
||||||
if not playerName then return end
|
if not playerName then return end
|
||||||
self.peerVersions[playerName] = version
|
self:SetPlayerVersionStatus(playerName, version, protocol, sourceTag)
|
||||||
self:RememberPeerProtocolVersion(playerName, protocol)
|
self:RememberPeerProtocolVersion(playerName, protocol)
|
||||||
if self.versionNoticeWindow and self.versionNoticeWindow.IsShown and self.versionNoticeWindow:IsShown() and self.RefreshVersionNoticeWindow then
|
if self.versionNoticeWindow and self.versionNoticeWindow.IsShown and self.versionNoticeWindow:IsShown() and self.RefreshVersionNoticeWindow then
|
||||||
self:RefreshVersionNoticeWindow()
|
self:RefreshVersionNoticeWindow()
|
||||||
@@ -798,7 +939,7 @@ function HMGT:RegisterPeerVersion(playerName, version, protocol, sourceTag)
|
|||||||
tostring(playerName), table.concat(details, " | "))
|
tostring(playerName), table.concat(details, " | "))
|
||||||
self:Print("|cffff5555HMGT|r " .. text)
|
self:Print("|cffff5555HMGT|r " .. text)
|
||||||
self:ShowVersionMismatchPopup(playerName, table.concat(details, " | "), sourceTag)
|
self:ShowVersionMismatchPopup(playerName, table.concat(details, " | "), sourceTag)
|
||||||
self:Debug("info", "Version mismatch %s via=%s %s", tostring(playerName), tostring(sourceTag or "?"), table.concat(details, " | "))
|
self:DebugScoped("info", "TrackerCore", "Version mismatch %s via=%s %s", tostring(playerName), tostring(sourceTag or "?"), table.concat(details, " | "))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1091,7 +1232,7 @@ function HMGT:LogTrackedSpellCast(playerName, spellEntry, details)
|
|||||||
|
|
||||||
self:DebugScoped(
|
self:DebugScoped(
|
||||||
"verbose",
|
"verbose",
|
||||||
"TrackedSpells",
|
"TrackerCore",
|
||||||
"%s -> %s von %s, %s",
|
"%s -> %s von %s, %s",
|
||||||
GetTrackedSpellCategoryLabel(spellEntry),
|
GetTrackedSpellCategoryLabel(spellEntry),
|
||||||
GetSpellDebugLabel(spellEntry.spellId),
|
GetSpellDebugLabel(spellEntry.spellId),
|
||||||
@@ -1699,22 +1840,9 @@ function HMGT:MigrateProfileSettings()
|
|||||||
|
|
||||||
if #p.trackers == 0 and p.trackerModelVersion ~= TRACKER_MODEL_VERSION then
|
if #p.trackers == 0 and p.trackerModelVersion ~= TRACKER_MODEL_VERSION then
|
||||||
p.trackers = {
|
p.trackers = {
|
||||||
self:CreateTrackerConfig(1, CopyTrackerFields({
|
self:BuildTrackerConfigFromPreset("interruptTracker", 1, CopyTrackerFields({}, p.interruptTracker or {})),
|
||||||
name = L["IT_NAME"] or "Interrupts",
|
self:BuildTrackerConfigFromPreset("raidCooldownTracker", 2, CopyTrackerFields({}, p.raidCooldownTracker or {})),
|
||||||
trackerType = "normal",
|
self:BuildTrackerConfigFromPreset("groupCooldownTracker", 3, CopyTrackerFields({}, p.groupCooldownTracker or {})),
|
||||||
categories = { "interrupt" },
|
|
||||||
}, p.interruptTracker or {})),
|
|
||||||
self:CreateTrackerConfig(2, CopyTrackerFields({
|
|
||||||
name = L["RCD_NAME"] or "Raid Cooldowns",
|
|
||||||
trackerType = "normal",
|
|
||||||
categories = { "raid" },
|
|
||||||
}, p.raidCooldownTracker or {})),
|
|
||||||
self:CreateTrackerConfig(3, CopyTrackerFields({
|
|
||||||
name = L["GCD_NAME"] or "Cooldowns",
|
|
||||||
trackerType = "group",
|
|
||||||
categories = { "defensive", "offensive", "tank", "healing", "utility", "cc", "lust" },
|
|
||||||
showChargesOnIcon = true,
|
|
||||||
}, p.groupCooldownTracker or {})),
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1732,11 +1860,7 @@ function HMGT:MigrateProfileSettings()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if #normalizedTrackers == 0 then
|
if #normalizedTrackers == 0 then
|
||||||
normalizedTrackers[1] = self:CreateTrackerConfig(1, {
|
normalizedTrackers[1] = self:BuildTrackerConfigFromPreset("interruptTracker", 1)
|
||||||
name = L["IT_NAME"] or "Interrupts",
|
|
||||||
trackerType = "normal",
|
|
||||||
categories = { "interrupt" },
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
p.trackers = normalizedTrackers
|
p.trackers = normalizedTrackers
|
||||||
p.trackerModelVersion = TRACKER_MODEL_VERSION
|
p.trackerModelVersion = TRACKER_MODEL_VERSION
|
||||||
@@ -2648,7 +2772,7 @@ function HMGT:OnGroupRosterUpdate()
|
|||||||
if not validPlayers[name] then
|
if not validPlayers[name] then
|
||||||
self.playerData[name] = nil
|
self.playerData[name] = nil
|
||||||
self:ClearTrackerStateForPlayer(name)
|
self:ClearTrackerStateForPlayer(name)
|
||||||
self.peerVersions[name] = nil
|
self:ClearPlayerStatus(name)
|
||||||
self.versionWarnings[name] = nil
|
self.versionWarnings[name] = nil
|
||||||
if self.peerProtocols then
|
if self.peerProtocols then
|
||||||
self.peerProtocols[name] = nil
|
self.peerProtocols[name] = nil
|
||||||
@@ -3040,127 +3164,6 @@ function HMGT:TestMode()
|
|||||||
self:Print(L["TEST_MODE_ACTIVE"])
|
self:Print(L["TEST_MODE_ACTIVE"])
|
||||||
end
|
end
|
||||||
|
|
||||||
function HMGT:GetDemoEntries(trackerKey, database, settings)
|
|
||||||
local pool = {}
|
|
||||||
local poolByClass = {}
|
|
||||||
for _, entry in ipairs(database) do
|
|
||||||
if settings.enabledSpells[entry.spellId] ~= false then
|
|
||||||
pool[#pool + 1] = entry
|
|
||||||
for _, cls in ipairs(entry.classes or {}) do
|
|
||||||
poolByClass[cls] = poolByClass[cls] or {}
|
|
||||||
poolByClass[cls][#poolByClass[cls] + 1] = entry
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #pool == 0 then return {} end
|
|
||||||
|
|
||||||
local classKeys = {}
|
|
||||||
for cls in pairs(poolByClass) do
|
|
||||||
classKeys[#classKeys + 1] = cls
|
|
||||||
end
|
|
||||||
if #classKeys == 0 then classKeys[1] = "WARRIOR" end
|
|
||||||
|
|
||||||
local count = settings.showBar and math.min(8, #pool) or math.min(12, #pool)
|
|
||||||
local names = { "Alice", "Bob", "Clara", "Duke", "Elli", "Fynn", "Gina", "Hektor", "Ivo", "Jana", "Kira", "Lio" }
|
|
||||||
|
|
||||||
local spellIds = {}
|
|
||||||
for _, e in ipairs(pool) do spellIds[#spellIds + 1] = tostring(e.spellId) end
|
|
||||||
table.sort(spellIds)
|
|
||||||
local signature = table.concat(spellIds, ",") .. "|" .. tostring(settings.showBar and 1 or 0) .. "|" .. tostring(count)
|
|
||||||
|
|
||||||
local now = GetTime()
|
|
||||||
local cache = self.demoModeData[trackerKey]
|
|
||||||
if (not cache) or (cache.signature ~= signature) or (not cache.entries) or (#cache.entries ~= count) then
|
|
||||||
local entries = {}
|
|
||||||
for i = 1, count do
|
|
||||||
local cls = classKeys[math.random(1, #classKeys)]
|
|
||||||
local classPool = poolByClass[cls]
|
|
||||||
local spell = (classPool and classPool[math.random(1, #classPool)]) or pool[math.random(1, #pool)]
|
|
||||||
local duration = math.max(
|
|
||||||
1,
|
|
||||||
tonumber(HMGT_SpellData.GetBaseCooldown and HMGT_SpellData.GetBaseCooldown(spell)) or tonumber(spell.cooldown) or 60
|
|
||||||
)
|
|
||||||
local playerName = names[((i - 1) % #names) + 1]
|
|
||||||
-- start offset so demo entries do not all tick in sync
|
|
||||||
local offset = math.random() * math.min(duration * 0.85, duration - 0.1)
|
|
||||||
entries[#entries + 1] = {
|
|
||||||
playerName = playerName,
|
|
||||||
class = cls or ((spell.classes and spell.classes[1]) or "WARRIOR"),
|
|
||||||
spellEntry = spell,
|
|
||||||
total = duration,
|
|
||||||
cycleStart = now - offset,
|
|
||||||
currentCharges = nil,
|
|
||||||
maxCharges = nil,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
cache = { signature = signature, entries = entries }
|
|
||||||
self.demoModeData[trackerKey] = cache
|
|
||||||
end
|
|
||||||
|
|
||||||
local out = {}
|
|
||||||
for _, e in ipairs(cache.entries) do
|
|
||||||
local total = math.max(1, tonumber(e.total) or 1)
|
|
||||||
local elapsed = math.max(0, now - (e.cycleStart or now))
|
|
||||||
local phase = math.fmod(elapsed, total)
|
|
||||||
local rem = total - phase
|
|
||||||
-- show zero briefly at cycle boundary, then restart immediately
|
|
||||||
if elapsed > 0 and phase < 0.05 then rem = 0 end
|
|
||||||
out[#out + 1] = {
|
|
||||||
playerName = e.playerName,
|
|
||||||
class = e.class,
|
|
||||||
spellEntry = e.spellEntry,
|
|
||||||
remaining = rem,
|
|
||||||
total = total,
|
|
||||||
currentCharges = e.currentCharges,
|
|
||||||
maxCharges = e.maxCharges,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
|
|
||||||
function HMGT:GetOwnTestEntries(database, settings, cooldownInfoOpts)
|
|
||||||
local entries = {}
|
|
||||||
local enabledSpells = settings and settings.enabledSpells or {}
|
|
||||||
local playerName = self:NormalizePlayerName(UnitName("player")) or "Player"
|
|
||||||
local classToken = select(2, UnitClass("player"))
|
|
||||||
if not classToken then
|
|
||||||
return entries, playerName
|
|
||||||
end
|
|
||||||
|
|
||||||
local specIdx = GetSpecialization()
|
|
||||||
local lookupSpec = (specIdx and specIdx > 0) and specIdx or 0
|
|
||||||
local talents = (self.playerData[playerName] and self.playerData[playerName].talents) or {}
|
|
||||||
local spells = HMGT_SpellData.GetSpellsForSpec(classToken, lookupSpec, database or {})
|
|
||||||
|
|
||||||
for _, spellEntry in ipairs(spells) do
|
|
||||||
if enabledSpells[spellEntry.spellId] ~= false then
|
|
||||||
local remaining, total, curCharges, maxCharges = self:GetCooldownInfo(playerName, spellEntry.spellId, cooldownInfoOpts)
|
|
||||||
local effectiveCd = HMGT_SpellData.GetEffectiveCooldown(spellEntry, talents)
|
|
||||||
local isAvailabilitySpell = self:IsAvailabilitySpell(spellEntry)
|
|
||||||
local spellKnown = self:IsTrackedSpellKnownForPlayer(playerName, spellEntry.spellId)
|
|
||||||
local hasPartialCharges = (tonumber(maxCharges) or 0) > 0
|
|
||||||
and (tonumber(curCharges) or tonumber(maxCharges) or 0) < (tonumber(maxCharges) or 0)
|
|
||||||
local hasActiveCd = ((remaining or 0) > 0) or hasPartialCharges
|
|
||||||
local hasAvailabilityState = isAvailabilitySpell and self:HasAvailabilityState(playerName, spellEntry.spellId)
|
|
||||||
|
|
||||||
if spellKnown or hasActiveCd or hasAvailabilityState then
|
|
||||||
entries[#entries + 1] = {
|
|
||||||
playerName = playerName,
|
|
||||||
class = classToken,
|
|
||||||
spellEntry = spellEntry,
|
|
||||||
remaining = remaining,
|
|
||||||
total = total > 0 and total or effectiveCd,
|
|
||||||
currentCharges = curCharges,
|
|
||||||
maxCharges = maxCharges,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return entries, playerName
|
|
||||||
end
|
|
||||||
|
|
||||||
-- ═══════════════════════════════════════════════════════════════
|
-- ═══════════════════════════════════════════════════════════════
|
||||||
-- HILFSFUNKTIONEN
|
-- HILFSFUNKTIONEN
|
||||||
-- ═══════════════════════════════════════════════════════════════
|
-- ═══════════════════════════════════════════════════════════════
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ Modules\Tracker\RaidCooldownTracker\RaidCooldownTracker.lua
|
|||||||
Modules\Tracker\GroupCooldownTracker\GroupCooldownTracker.lua
|
Modules\Tracker\GroupCooldownTracker\GroupCooldownTracker.lua
|
||||||
|
|
||||||
Modules\Tracker\InterruptTracker\InterruptSpellDatabase.lua
|
Modules\Tracker\InterruptTracker\InterruptSpellDatabase.lua
|
||||||
Modules\Tracker\RaidcooldownTracker\RaidCooldownSpellDatabase.lua
|
Modules\Tracker\RaidCooldownTracker\RaidCooldownSpellDatabase.lua
|
||||||
Modules\Tracker\GroupCooldownTracker\GroupCooldownSpellDatabase.lua
|
Modules\Tracker\GroupCooldownTracker\GroupCooldownSpellDatabase.lua
|
||||||
Modules\Tracker\TrackerManager.lua
|
Modules\Tracker\TrackerManager.lua
|
||||||
Modules\Tracker\NormalTrackerFrames.lua
|
Modules\Tracker\NormalTrackerFrames.lua
|
||||||
@@ -65,5 +65,4 @@ Modules\MapOverlay\MapOverlay.xml
|
|||||||
Modules\RaidTimeline\RaidTimelineBossAbilityData.lua
|
Modules\RaidTimeline\RaidTimelineBossAbilityData.lua
|
||||||
Modules\RaidTimeline\RaidTimeline.lua
|
Modules\RaidTimeline\RaidTimeline.lua
|
||||||
Modules\RaidTimeline\RaidTimelineBigWigs.lua
|
Modules\RaidTimeline\RaidTimelineBigWigs.lua
|
||||||
Modules\RaidTimeline\RaidTimelineDBM.lua
|
|
||||||
Modules\RaidTimeline\RaidTimelineOptions.lua
|
Modules\RaidTimeline\RaidTimelineOptions.lua
|
||||||
|
|||||||
@@ -22,11 +22,12 @@ L["VERSION_WINDOW_MESSAGE"] = "Hail Mary Guild Tools Versionen in deiner aktuell
|
|||||||
L["VERSION_WINDOW_DETAIL"] = "Erkannt ueber %s von %s.\n%s"
|
L["VERSION_WINDOW_DETAIL"] = "Erkannt ueber %s von %s.\n%s"
|
||||||
L["VERSION_WINDOW_NO_MISMATCH"] = "In deiner aktuellen Gruppe wurde keine neuere HMGT-Version erkannt."
|
L["VERSION_WINDOW_NO_MISMATCH"] = "In deiner aktuellen Gruppe wurde keine neuere HMGT-Version erkannt."
|
||||||
L["VERSION_WINDOW_CURRENT"] = "Aktuelle Version: %s | Protokoll: %s"
|
L["VERSION_WINDOW_CURRENT"] = "Aktuelle Version: %s | Protokoll: %s"
|
||||||
L["VERSION_WINDOW_STATUS"] = "HMGT bei %d/%d Spielern erkannt"
|
L["VERSION_WINDOW_STATUS"] = "Addon oder Bridge bei %d/%d Spielern erkannt"
|
||||||
L["VERSION_WINDOW_REFRESH"] = "Aktualisieren"
|
L["VERSION_WINDOW_REFRESH"] = "Aktualisieren"
|
||||||
L["VERSION_WINDOW_COLUMN_PLAYER"] = "Spieler"
|
L["VERSION_WINDOW_COLUMN_PLAYER"] = "Spieler"
|
||||||
L["VERSION_WINDOW_COLUMN_VERSION"] = "Version"
|
L["VERSION_WINDOW_COLUMN_VERSION"] = "Version"
|
||||||
L["VERSION_WINDOW_COLUMN_PROTOCOL"] = "Protokoll"
|
L["VERSION_WINDOW_COLUMN_PROTOCOL"] = "Protokoll"
|
||||||
|
L["VERSION_WINDOW_BRIDGE_MODE"] = "Bridge Mode"
|
||||||
L["VERSION_WINDOW_MISSING_ADDON"] = "Addon nicht vorhanden"
|
L["VERSION_WINDOW_MISSING_ADDON"] = "Addon nicht vorhanden"
|
||||||
L["VERSION_WINDOW_LEADER_TAG"] = "(Leiter)"
|
L["VERSION_WINDOW_LEADER_TAG"] = "(Leiter)"
|
||||||
L["VERSION_WINDOW_ASSISTANT_TAG"] = "(Assist)"
|
L["VERSION_WINDOW_ASSISTANT_TAG"] = "(Assist)"
|
||||||
|
|||||||
@@ -22,11 +22,12 @@ L["VERSION_WINDOW_MESSAGE"] = "Hail Mary Guild Tools versions in your current gr
|
|||||||
L["VERSION_WINDOW_DETAIL"] = "Detected via %s from %s.\n%s"
|
L["VERSION_WINDOW_DETAIL"] = "Detected via %s from %s.\n%s"
|
||||||
L["VERSION_WINDOW_NO_MISMATCH"] = "No newer HMGT version has been detected in your current group."
|
L["VERSION_WINDOW_NO_MISMATCH"] = "No newer HMGT version has been detected in your current group."
|
||||||
L["VERSION_WINDOW_CURRENT"] = "Current version: %s | Protocol: %s"
|
L["VERSION_WINDOW_CURRENT"] = "Current version: %s | Protocol: %s"
|
||||||
L["VERSION_WINDOW_STATUS"] = "Detected HMGT on %d/%d players"
|
L["VERSION_WINDOW_STATUS"] = "Detected addon or bridge on %d/%d players"
|
||||||
L["VERSION_WINDOW_REFRESH"] = "Refresh"
|
L["VERSION_WINDOW_REFRESH"] = "Refresh"
|
||||||
L["VERSION_WINDOW_COLUMN_PLAYER"] = "Player"
|
L["VERSION_WINDOW_COLUMN_PLAYER"] = "Player"
|
||||||
L["VERSION_WINDOW_COLUMN_VERSION"] = "Version"
|
L["VERSION_WINDOW_COLUMN_VERSION"] = "Version"
|
||||||
L["VERSION_WINDOW_COLUMN_PROTOCOL"] = "Protocol"
|
L["VERSION_WINDOW_COLUMN_PROTOCOL"] = "Protocol"
|
||||||
|
L["VERSION_WINDOW_BRIDGE_MODE"] = "Bridge Mode"
|
||||||
L["VERSION_WINDOW_MISSING_ADDON"] = "Addon not installed"
|
L["VERSION_WINDOW_MISSING_ADDON"] = "Addon not installed"
|
||||||
L["VERSION_WINDOW_LEADER_TAG"] = "(Leader)"
|
L["VERSION_WINDOW_LEADER_TAG"] = "(Leader)"
|
||||||
L["VERSION_WINDOW_ASSISTANT_TAG"] = "(Assist)"
|
L["VERSION_WINDOW_ASSISTANT_TAG"] = "(Assist)"
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
local ADDON_NAME = "HailMaryGuildTools"
|
|
||||||
local HMGT = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME)
|
|
||||||
if not HMGT then return end
|
|
||||||
|
|
||||||
local RT = HMGT.RaidTimeline
|
|
||||||
if not RT then return end
|
|
||||||
|
|
||||||
-- Placeholder for later DBM-specific raid timeline integration.
|
|
||||||
@@ -80,6 +80,8 @@ function HMGT:ApplyExternalKnownSpell(sourceName, playerName, spellId, class, co
|
|||||||
knownSpells = knownSpells,
|
knownSpells = knownSpells,
|
||||||
externalSource = source,
|
externalSource = source,
|
||||||
}
|
}
|
||||||
|
self:SetPlayerBridgeStatus(normalizedName, source)
|
||||||
|
self:DebugScoped("verbose", "TrackerBridge", "Bridge known spell source=%s player=%s spellId=%s", tostring(source), tostring(normalizedName), tostring(sid))
|
||||||
|
|
||||||
if tonumber(cooldown) and tonumber(cooldown) > 0 then
|
if tonumber(cooldown) and tonumber(cooldown) > 0 then
|
||||||
spellEntry._hmgtExternalBaseCd = tonumber(cooldown)
|
spellEntry._hmgtExternalBaseCd = tonumber(cooldown)
|
||||||
@@ -128,6 +130,8 @@ function HMGT:ApplyExternalSpecInfo(sourceName, playerName, class, specId, talen
|
|||||||
knownSpells = knownSpells,
|
knownSpells = knownSpells,
|
||||||
externalSource = source,
|
externalSource = source,
|
||||||
}
|
}
|
||||||
|
self:SetPlayerBridgeStatus(normalizedName, source)
|
||||||
|
self:DebugScoped("info", "TrackerBridge", "Bridge spec sync source=%s player=%s class=%s spec=%s", tostring(source), tostring(normalizedName), tostring(classToken), tostring(spec))
|
||||||
|
|
||||||
self:PruneAvailabilityStates(normalizedName, knownSpells)
|
self:PruneAvailabilityStates(normalizedName, knownSpells)
|
||||||
self:TriggerTrackerUpdate("trackers")
|
self:TriggerTrackerUpdate("trackers")
|
||||||
@@ -154,6 +158,7 @@ function HMGT:ApplyExternalCooldown(sourceName, playerName, spellId, cooldown)
|
|||||||
|
|
||||||
self:RegisterExternalAddonSource(source)
|
self:RegisterExternalAddonSource(source)
|
||||||
self:ApplyExternalKnownSpell(source, normalizedName, sid, nil, cd)
|
self:ApplyExternalKnownSpell(source, normalizedName, sid, nil, cd)
|
||||||
|
self:DebugScoped("info", "TrackerBridge", "Bridge cooldown source=%s player=%s spellId=%s cooldown=%.1f", tostring(source), tostring(normalizedName), tostring(sid), cd)
|
||||||
self:HandleRemoteSpellCast(normalizedName, sid, GetServerTime(), nil, nil, nil, cd)
|
self:HandleRemoteSpellCast(normalizedName, sid, GetServerTime(), nil, nil, nil, cd)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,6 +4,91 @@ if not HMGT then return end
|
|||||||
|
|
||||||
HMGT.TrackerCore = HMGT.TrackerCore or {}
|
HMGT.TrackerCore = HMGT.TrackerCore or {}
|
||||||
|
|
||||||
|
HMGT.TRACKER_PRESET_DEFINITIONS = HMGT.TRACKER_PRESET_DEFINITIONS or {
|
||||||
|
interruptTracker = {
|
||||||
|
moduleName = "InterruptTracker",
|
||||||
|
dbKey = "interruptTracker",
|
||||||
|
trackerType = "normal",
|
||||||
|
trackerKey = "interruptTracker",
|
||||||
|
categories = { "interrupt" },
|
||||||
|
defaultName = function(L)
|
||||||
|
return (L and L["IT_NAME"]) or "Interrupts"
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
raidCooldownTracker = {
|
||||||
|
moduleName = "RaidCooldownTracker",
|
||||||
|
dbKey = "raidCooldownTracker",
|
||||||
|
trackerType = "normal",
|
||||||
|
trackerKey = "raidCooldownTracker",
|
||||||
|
categories = { "lust", "defensive", "healing", "tank", "utility", "offensive", "cc", "interrupt" },
|
||||||
|
defaultName = function(L)
|
||||||
|
return (L and L["RCD_NAME"]) or "Raid Cooldowns"
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
groupCooldownTracker = {
|
||||||
|
moduleName = "GroupCooldownTracker",
|
||||||
|
dbKey = "groupCooldownTracker",
|
||||||
|
trackerType = "group",
|
||||||
|
trackerKey = "groupCooldownTracker",
|
||||||
|
categories = { "tank", "defensive", "healing", "cc", "utility", "offensive", "lust", "interrupt" },
|
||||||
|
includeSelfFrame = false,
|
||||||
|
showChargesOnIcon = true,
|
||||||
|
defaultName = function(L)
|
||||||
|
return (L and L["GCD_NAME"]) or "Cooldowns"
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function HMGT:GetTrackerPresetDefinitions()
|
||||||
|
return self.TRACKER_PRESET_DEFINITIONS or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
function HMGT:GetTrackerPresetDefinition(key)
|
||||||
|
local definitions = self:GetTrackerPresetDefinitions()
|
||||||
|
return definitions and definitions[tostring(key or "")]
|
||||||
|
end
|
||||||
|
|
||||||
|
function HMGT:GetTrackerPresetDefinitionByModule(moduleName)
|
||||||
|
local target = tostring(moduleName or "")
|
||||||
|
for _, definition in pairs(self:GetTrackerPresetDefinitions()) do
|
||||||
|
if tostring(definition.moduleName or "") == target then
|
||||||
|
return definition
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function HMGT:GetTrackerTypeOptions()
|
||||||
|
local L = self.L
|
||||||
|
return {
|
||||||
|
normal = (L and L["OPT_TRACKER_TYPE_NORMAL"]) or "Normal tracker",
|
||||||
|
group = (L and L["OPT_TRACKER_TYPE_GROUP"]) or "Group-based tracker",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function HMGT:BuildTrackerConfigFromPreset(presetKey, trackerId, overrides)
|
||||||
|
local definition = self:GetTrackerPresetDefinition(presetKey)
|
||||||
|
local config = overrides or {}
|
||||||
|
if not definition then
|
||||||
|
return self:CreateTrackerConfig(trackerId, config)
|
||||||
|
end
|
||||||
|
|
||||||
|
local base = {
|
||||||
|
name = type(definition.defaultName) == "function" and definition.defaultName(self.L) or tostring(definition.defaultName or ""),
|
||||||
|
trackerType = definition.trackerType,
|
||||||
|
trackerKey = definition.trackerKey,
|
||||||
|
categories = definition.categories,
|
||||||
|
includeSelfFrame = definition.includeSelfFrame,
|
||||||
|
showChargesOnIcon = definition.showChargesOnIcon,
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value in pairs(config) do
|
||||||
|
base[key] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
return self:CreateTrackerConfig(trackerId, base)
|
||||||
|
end
|
||||||
|
|
||||||
local function EntryNeedsVisualTicker(entry)
|
local function EntryNeedsVisualTicker(entry)
|
||||||
if type(entry) ~= "table" then
|
if type(entry) ~= "table" then
|
||||||
return false
|
return false
|
||||||
@@ -204,6 +289,93 @@ function HMGT:CollectTrackerEntries(tracker)
|
|||||||
return entries
|
return entries
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function HMGT:GetDemoEntries(trackerKey, database, settings)
|
||||||
|
local pool = {}
|
||||||
|
local poolByClass = {}
|
||||||
|
for _, entry in ipairs(database or {}) do
|
||||||
|
if settings.enabledSpells[entry.spellId] ~= false then
|
||||||
|
pool[#pool + 1] = entry
|
||||||
|
for _, classToken in ipairs(entry.classes or {}) do
|
||||||
|
poolByClass[classToken] = poolByClass[classToken] or {}
|
||||||
|
poolByClass[classToken][#poolByClass[classToken] + 1] = entry
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #pool == 0 then
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local classKeys = {}
|
||||||
|
for classToken in pairs(poolByClass) do
|
||||||
|
classKeys[#classKeys + 1] = classToken
|
||||||
|
end
|
||||||
|
if #classKeys == 0 then
|
||||||
|
classKeys[1] = "WARRIOR"
|
||||||
|
end
|
||||||
|
|
||||||
|
local count = settings.showBar and math.min(8, #pool) or math.min(12, #pool)
|
||||||
|
local names = { "Alice", "Bob", "Clara", "Duke", "Elli", "Fynn", "Gina", "Hektor", "Ivo", "Jana", "Kira", "Lio" }
|
||||||
|
|
||||||
|
local spellIds = {}
|
||||||
|
for _, entry in ipairs(pool) do
|
||||||
|
spellIds[#spellIds + 1] = tostring(entry.spellId)
|
||||||
|
end
|
||||||
|
table.sort(spellIds)
|
||||||
|
local signature = table.concat(spellIds, ",") .. "|" .. tostring(settings.showBar and 1 or 0) .. "|" .. tostring(count)
|
||||||
|
|
||||||
|
local now = GetTime()
|
||||||
|
local cache = self.demoModeData[trackerKey]
|
||||||
|
if (not cache) or cache.signature ~= signature or (not cache.entries) or #cache.entries ~= count then
|
||||||
|
local cachedEntries = {}
|
||||||
|
for index = 1, count do
|
||||||
|
local classToken = classKeys[math.random(1, #classKeys)]
|
||||||
|
local classPool = poolByClass[classToken]
|
||||||
|
local spellEntry = (classPool and classPool[math.random(1, #classPool)]) or pool[math.random(1, #pool)]
|
||||||
|
local duration = math.max(
|
||||||
|
1,
|
||||||
|
tonumber(HMGT_SpellData.GetBaseCooldown and HMGT_SpellData.GetBaseCooldown(spellEntry)) or tonumber(spellEntry.cooldown) or 60
|
||||||
|
)
|
||||||
|
local offset = math.random() * math.min(duration * 0.85, duration - 0.1)
|
||||||
|
cachedEntries[#cachedEntries + 1] = {
|
||||||
|
playerName = names[((index - 1) % #names) + 1],
|
||||||
|
class = classToken or ((spellEntry.classes and spellEntry.classes[1]) or "WARRIOR"),
|
||||||
|
spellEntry = spellEntry,
|
||||||
|
total = duration,
|
||||||
|
cycleStart = now - offset,
|
||||||
|
currentCharges = nil,
|
||||||
|
maxCharges = nil,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
cache = {
|
||||||
|
signature = signature,
|
||||||
|
entries = cachedEntries,
|
||||||
|
}
|
||||||
|
self.demoModeData[trackerKey] = cache
|
||||||
|
end
|
||||||
|
|
||||||
|
local entries = {}
|
||||||
|
for _, entry in ipairs(cache.entries) do
|
||||||
|
local total = math.max(1, tonumber(entry.total) or 1)
|
||||||
|
local elapsed = math.max(0, now - (entry.cycleStart or now))
|
||||||
|
local phase = math.fmod(elapsed, total)
|
||||||
|
local remaining = total - phase
|
||||||
|
if elapsed > 0 and phase < 0.05 then
|
||||||
|
remaining = 0
|
||||||
|
end
|
||||||
|
entries[#entries + 1] = {
|
||||||
|
playerName = entry.playerName,
|
||||||
|
class = entry.class,
|
||||||
|
spellEntry = entry.spellEntry,
|
||||||
|
remaining = remaining,
|
||||||
|
total = total,
|
||||||
|
currentCharges = entry.currentCharges,
|
||||||
|
maxCharges = entry.maxCharges,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return entries
|
||||||
|
end
|
||||||
|
|
||||||
function HMGT:CollectTrackerTestEntries(tracker)
|
function HMGT:CollectTrackerTestEntries(tracker)
|
||||||
local playerName = self:NormalizePlayerName(UnitName("player")) or "Player"
|
local playerName = self:NormalizePlayerName(UnitName("player")) or "Player"
|
||||||
local classToken = select(2, UnitClass("player"))
|
local classToken = select(2, UnitClass("player"))
|
||||||
@@ -385,7 +557,7 @@ function HMGT:TriggerTrackerUpdate(reason)
|
|||||||
if t0 and t1 then
|
if t0 and t1 then
|
||||||
local mod = HMGT[name]
|
local mod = HMGT[name]
|
||||||
local count = mod and mod.lastEntryCount or 0
|
local count = mod and mod.lastEntryCount or 0
|
||||||
self:Debug("verbose", "UIUpdate %s took %.2fms entries=%s", tostring(name), t1 - t0, tostring(count))
|
self:DebugScoped("verbose", "TrackerUI", "UIUpdate %s took %.2fms entries=%s", tostring(name), t1 - t0, tostring(count))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ function HMGT:RefreshOwnCooldownStateFromGame(spellId)
|
|||||||
if isLikelyGlobalCooldown or isSuspiciousShortRefresh then
|
if isLikelyGlobalCooldown or isSuspiciousShortRefresh then
|
||||||
self:DebugScoped(
|
self:DebugScoped(
|
||||||
"verbose",
|
"verbose",
|
||||||
"TrackedSpells",
|
"TrackerState",
|
||||||
"Ignore suspicious refresh for %s: spellCD=%.3f gcd=%.3f existing=%.3f remaining=%.3f effective=%.3f",
|
"Ignore suspicious refresh for %s: spellCD=%.3f gcd=%.3f existing=%.3f remaining=%.3f effective=%.3f",
|
||||||
GetSpellDebugLabel and GetSpellDebugLabel(sid) or tostring(sid),
|
GetSpellDebugLabel and GetSpellDebugLabel(sid) or tostring(sid),
|
||||||
cooldownDuration,
|
cooldownDuration,
|
||||||
|
|||||||
@@ -142,13 +142,26 @@ local function IsPartyAttachMode(tracker)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function IsGroupTracker(tracker)
|
local function IsGroupTracker(tracker)
|
||||||
return type(tracker) == "table" and tracker.trackerType == "group"
|
return HMGT.IsGroupTrackerConfig and HMGT:IsGroupTrackerConfig(tracker) or (type(tracker) == "table" and tracker.trackerType == "group")
|
||||||
end
|
end
|
||||||
|
|
||||||
local TRACKER_TYPE_VALUES = {
|
local function GetTrackerTypeValues()
|
||||||
normal = L["OPT_TRACKER_TYPE_NORMAL"] or "Normal tracker",
|
return HMGT.GetTrackerTypeOptions and HMGT:GetTrackerTypeOptions() or {
|
||||||
group = L["OPT_TRACKER_TYPE_GROUP"] or "Group-based tracker",
|
normal = L["OPT_TRACKER_TYPE_NORMAL"] or "Normal tracker",
|
||||||
}
|
group = L["OPT_TRACKER_TYPE_GROUP"] or "Group-based tracker",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function GetPresetLabel(presetKey)
|
||||||
|
local definition = HMGT.GetTrackerPresetDefinition and HMGT:GetTrackerPresetDefinition(presetKey) or nil
|
||||||
|
if not definition then
|
||||||
|
return tostring(presetKey or (L["OPT_TRACKER"] or "Tracker"))
|
||||||
|
end
|
||||||
|
if type(definition.defaultName) == "function" then
|
||||||
|
return tostring(definition.defaultName(L))
|
||||||
|
end
|
||||||
|
return tostring(definition.defaultName or definition.moduleName or presetKey)
|
||||||
|
end
|
||||||
|
|
||||||
local function GetTrackerVisibilitySummary(tracker)
|
local function GetTrackerVisibilitySummary(tracker)
|
||||||
local parts = {}
|
local parts = {}
|
||||||
@@ -180,7 +193,7 @@ local function GetTrackerSummaryText(tracker)
|
|||||||
local display = tracker.showBar and (L["OPT_DISPLAY_BAR"] or "Progress bars") or (L["OPT_DISPLAY_ICON"] or "Icons")
|
local display = tracker.showBar and (L["OPT_DISPLAY_BAR"] or "Progress bars") or (L["OPT_DISPLAY_ICON"] or "Icons")
|
||||||
|
|
||||||
return table.concat({
|
return table.concat({
|
||||||
string.format("|cffffd100%s|r: %s", L["OPT_TRACKER_TYPE"] or "Tracker type", TRACKER_TYPE_VALUES[tracker.trackerType or "normal"] or (L["OPT_TRACKER_TYPE_NORMAL"] or "Normal tracker")),
|
string.format("|cffffd100%s|r: %s", L["OPT_TRACKER_TYPE"] or "Tracker type", GetTrackerTypeValues()[tracker.trackerType or "normal"] or (L["OPT_TRACKER_TYPE_NORMAL"] or "Normal tracker")),
|
||||||
string.format("|cffffd100%s|r: %s", L["OPT_TRACKER_CATEGORIES"] or "Categories", GetTrackerCategoriesSummary(tracker)),
|
string.format("|cffffd100%s|r: %s", L["OPT_TRACKER_CATEGORIES"] or "Categories", GetTrackerCategoriesSummary(tracker)),
|
||||||
string.format("|cffffd100%s|r: %s", L["OPT_STATUS_MODE"] or "Mode", modeLabel),
|
string.format("|cffffd100%s|r: %s", L["OPT_STATUS_MODE"] or "Mode", modeLabel),
|
||||||
string.format("|cffffd100%s|r: %s", L["OPT_STATUS_DISPLAY"] or "Display", display),
|
string.format("|cffffd100%s|r: %s", L["OPT_STATUS_DISPLAY"] or "Display", display),
|
||||||
@@ -814,7 +827,7 @@ local function BuildGlobalSpellBrowserArgs()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function BuildTrackerOverviewArgs()
|
local function BuildTrackerOverviewArgs()
|
||||||
return {
|
local args = {
|
||||||
description = {
|
description = {
|
||||||
type = "description",
|
type = "description",
|
||||||
order = 1,
|
order = 1,
|
||||||
@@ -833,22 +846,36 @@ local function BuildTrackerOverviewArgs()
|
|||||||
return string.format("%s\n\n%s (%d): %s", body, L["OPT_TRACKERS"] or "Tracker Bars", #trackers, table.concat(names, ", "))
|
return string.format("%s\n\n%s (%d): %s", body, L["OPT_TRACKERS"] or "Tracker Bars", #trackers, table.concat(names, ", "))
|
||||||
end,
|
end,
|
||||||
},
|
},
|
||||||
addTracker = {
|
}
|
||||||
|
|
||||||
|
local definitions = HMGT.GetTrackerPresetDefinitions and HMGT:GetTrackerPresetDefinitions() or {}
|
||||||
|
local presetKeys = {}
|
||||||
|
for presetKey in pairs(definitions) do
|
||||||
|
presetKeys[#presetKeys + 1] = presetKey
|
||||||
|
end
|
||||||
|
table.sort(presetKeys, function(a, b)
|
||||||
|
return GetPresetLabel(a) < GetPresetLabel(b)
|
||||||
|
end)
|
||||||
|
|
||||||
|
for index, presetKey in ipairs(presetKeys) do
|
||||||
|
args["addPreset_" .. presetKey] = {
|
||||||
type = "execute",
|
type = "execute",
|
||||||
order = 2,
|
order = 2 + index,
|
||||||
width = "full",
|
width = "full",
|
||||||
name = L["OPT_ADD_TRACKER"] or "Add tracker",
|
name = function()
|
||||||
|
return string.format("%s: %s", L["OPT_ADD_TRACKER"] or "Add tracker", GetPresetLabel(presetKey))
|
||||||
|
end,
|
||||||
func = function()
|
func = function()
|
||||||
local nextId = HMGT:GetNextTrackerId()
|
local nextId = HMGT:GetNextTrackerId()
|
||||||
local tracker = HMGT:CreateTrackerConfig(nextId, {
|
local tracker = HMGT:BuildTrackerConfigFromPreset(presetKey, nextId)
|
||||||
name = string.format("%s %d", L["OPT_TRACKER"] or "Tracker", nextId),
|
|
||||||
})
|
|
||||||
HMGT.db.profile.trackers = HMGT.db.profile.trackers or {}
|
HMGT.db.profile.trackers = HMGT.db.profile.trackers or {}
|
||||||
HMGT.db.profile.trackers[#HMGT.db.profile.trackers + 1] = tracker
|
HMGT.db.profile.trackers[#HMGT.db.profile.trackers + 1] = tracker
|
||||||
TriggerTrackerUpdate(true)
|
TriggerTrackerUpdate(true)
|
||||||
end,
|
end,
|
||||||
},
|
}
|
||||||
}
|
end
|
||||||
|
|
||||||
|
return args
|
||||||
end
|
end
|
||||||
|
|
||||||
local function BuildTrackerGroup(trackerId, order)
|
local function BuildTrackerGroup(trackerId, order)
|
||||||
@@ -1008,7 +1035,7 @@ local function BuildTrackerGroup(trackerId, order)
|
|||||||
width = "full",
|
width = "full",
|
||||||
name = L["OPT_TRACKER_TYPE"] or "Tracker type",
|
name = L["OPT_TRACKER_TYPE"] or "Tracker type",
|
||||||
desc = L["OPT_TRACKER_TYPE_DESC"] or "Choose whether this tracker uses one shared frame or separate frames per group member.",
|
desc = L["OPT_TRACKER_TYPE_DESC"] or "Choose whether this tracker uses one shared frame or separate frames per group member.",
|
||||||
values = TRACKER_TYPE_VALUES,
|
values = GetTrackerTypeValues,
|
||||||
get = function()
|
get = function()
|
||||||
local tracker = s()
|
local tracker = s()
|
||||||
return (tracker and tracker.trackerType) or "normal"
|
return (tracker and tracker.trackerType) or "normal"
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ function HMGT:SendSpellStateSnapshot(snapshot, target, revision)
|
|||||||
|
|
||||||
self:DebugScoped(
|
self:DebugScoped(
|
||||||
"verbose",
|
"verbose",
|
||||||
"TrackedSpells",
|
"TrackerSync",
|
||||||
"SendSpellStateSnapshot target=%s spell=%s kind=%s rev=%d a=%.3f b=%.3f c=%.3f d=%.3f",
|
"SendSpellStateSnapshot target=%s spell=%s kind=%s rev=%d a=%.3f b=%.3f c=%.3f d=%.3f",
|
||||||
tostring(target and target ~= "" and target or "GROUP"),
|
tostring(target and target ~= "" and target or "GROUP"),
|
||||||
GetSpellDebugLabel and GetSpellDebugLabel(sid) or tostring(sid),
|
GetSpellDebugLabel and GetSpellDebugLabel(sid) or tostring(sid),
|
||||||
@@ -307,7 +307,7 @@ function HMGT:BroadcastRepairSpellStates()
|
|||||||
if not self:IsEnabled() then return end
|
if not self:IsEnabled() then return end
|
||||||
local sent = self:SendOwnTrackedSpellStates()
|
local sent = self:SendOwnTrackedSpellStates()
|
||||||
if sent > 0 then
|
if sent > 0 then
|
||||||
self:DebugScoped("verbose", "TrackedSpells", "RepairSpellStates sent=%d", sent)
|
self:DebugScoped("verbose", "TrackerSync", "RepairSpellStates sent=%d", sent)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -407,7 +407,7 @@ function HMGT:BroadcastSpellCast(spellId, snapshot)
|
|||||||
chargeRemaining = math.max(0, tonumber(remaining) or 0)
|
chargeRemaining = math.max(0, tonumber(remaining) or 0)
|
||||||
chargeDuration = math.max(0, tonumber(total) or 0)
|
chargeDuration = math.max(0, tonumber(total) or 0)
|
||||||
end
|
end
|
||||||
self:DebugScoped("verbose", "TrackedSpells", "BroadcastSpellCast spell=%s serverTime=%s charges=%d/%d",
|
self:DebugScoped("verbose", "TrackerSync", "BroadcastSpellCast spell=%s serverTime=%s charges=%d/%d",
|
||||||
GetSpellDebugLabel and GetSpellDebugLabel(spellId) or tostring(spellId),
|
GetSpellDebugLabel and GetSpellDebugLabel(spellId) or tostring(spellId),
|
||||||
tostring(GetServerTime()),
|
tostring(GetServerTime()),
|
||||||
cur,
|
cur,
|
||||||
@@ -563,7 +563,7 @@ function HMGT:StoreRemotePlayerInfo(playerName, class, specIndex, talentHash, kn
|
|||||||
end
|
end
|
||||||
self:DebugScoped(
|
self:DebugScoped(
|
||||||
"info",
|
"info",
|
||||||
"TrackedSpells",
|
"TrackerSync",
|
||||||
"Spielerinfo von %s: class=%s spec=%s bekannteSpells=%d",
|
"Spielerinfo von %s: class=%s spec=%s bekannteSpells=%d",
|
||||||
tostring(playerName),
|
tostring(playerName),
|
||||||
tostring(class),
|
tostring(class),
|
||||||
@@ -753,7 +753,7 @@ function HMGT:ApplyRemoteSpellState(playerName, spellId, kind, revision, a, b, c
|
|||||||
if changed then
|
if changed then
|
||||||
self:DebugScoped(
|
self:DebugScoped(
|
||||||
"info",
|
"info",
|
||||||
"TrackedSpells",
|
"TrackerSync",
|
||||||
"Sync von %s: %s -> %s (rev=%d)",
|
"Sync von %s: %s -> %s (rev=%d)",
|
||||||
tostring(normalizedName),
|
tostring(normalizedName),
|
||||||
GetSpellDebugLabel and GetSpellDebugLabel(sid) or tostring(sid),
|
GetSpellDebugLabel and GetSpellDebugLabel(sid) or tostring(sid),
|
||||||
@@ -814,7 +814,7 @@ function HMGT:OnCommReceived(prefix, message, distribution, sender)
|
|||||||
if (tonumber(protocol) or 0) >= 5 then
|
if (tonumber(protocol) or 0) >= 5 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self:DebugScoped("verbose", "TrackedSpells", "Legacy cast von %s: %s ts=%s",
|
self:DebugScoped("verbose", "TrackerSync", "Legacy cast von %s: %s ts=%s",
|
||||||
tostring(senderName),
|
tostring(senderName),
|
||||||
GetSpellDebugLabel and GetSpellDebugLabel(spellId) or tostring(spellId),
|
GetSpellDebugLabel and GetSpellDebugLabel(spellId) or tostring(spellId),
|
||||||
tostring(timestamp))
|
tostring(timestamp))
|
||||||
@@ -892,7 +892,7 @@ function HMGT:OnCommReceived(prefix, message, distribution, sender)
|
|||||||
self:RememberPeerProtocolVersion(senderName, protocol)
|
self:RememberPeerProtocolVersion(senderName, protocol)
|
||||||
self:ClearRemoteSpellStateRevisions(senderName)
|
self:ClearRemoteSpellStateRevisions(senderName)
|
||||||
self:StoreRemotePlayerInfo(senderName, class, specIndex, talentHash, knownSpellList)
|
self:StoreRemotePlayerInfo(senderName, class, specIndex, talentHash, knownSpellList)
|
||||||
self:DebugScoped("info", "TrackedSpells", "Hello von %s: class=%s spec=%s spells=%s",
|
self:DebugScoped("info", "TrackerSync", "Hello von %s: class=%s spec=%s spells=%s",
|
||||||
tostring(senderName), tostring(class), tostring(specIndex), tostring(knownSpellList or ""))
|
tostring(senderName), tostring(class), tostring(specIndex), tostring(knownSpellList or ""))
|
||||||
self:SendSyncResponse(sender)
|
self:SendSyncResponse(sender)
|
||||||
self:TriggerTrackerUpdate()
|
self:TriggerTrackerUpdate()
|
||||||
@@ -1003,7 +1003,7 @@ function HMGT:OnCommReceived(prefix, message, distribution, sender)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:DebugScoped("info", "TrackedSpells", "SyncResponse von %s: cdsApplied=%d", tostring(senderName), applied)
|
self:DebugScoped("info", "TrackerSync", "SyncResponse von %s: cdsApplied=%d", tostring(senderName), applied)
|
||||||
end
|
end
|
||||||
self:TriggerTrackerUpdate()
|
self:TriggerTrackerUpdate()
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user