Files
HailMaryGuildTools/Modules/Tracker/GroupTrackerFrames.lua
Torsten Brendgen fc5a8aa361 initial commit
2026-04-10 21:30:31 +02:00

248 lines
10 KiB
Lua

local ADDON_NAME = "HailMaryGuildTools"
local HMGT = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME)
if not HMGT or not HMGT.TrackerManager then return end
local Manager = HMGT.TrackerManager
local S = Manager._shared or {}
function Manager:EnsurePlayerFrame(tracker, playerName)
local frameKey = S.GetTrackerFrameKey(tracker.id)
self.perPlayerFrames[frameKey] = self.perPlayerFrames[frameKey] or {}
local frame = self.perPlayerFrames[frameKey][playerName]
if not frame then
frame = HMGT.TrackerFrame:CreateTrackerFrame(S.GetTrackerPlayerFrameName(tracker.id, playerName), tracker)
frame._hmgtTrackerId = tonumber(tracker.id) or 0
frame._hmgtPlayerName = playerName
self.perPlayerFrames[frameKey][playerName] = frame
end
frame._settings = tracker
HMGT.TrackerFrame:SetTitle(frame, string.format("%s - %s", S.GetTrackerLabel(tracker), S.ShortName(playerName)))
HMGT.TrackerFrame:SetLocked(frame, tracker.locked)
return frame
end
function Manager:HidePlayerFrames(frameKey)
local frames = self.perPlayerFrames[frameKey]
if type(frames) ~= "table" then
self.activeOrders[frameKey] = nil
self.unitByPlayer[frameKey] = nil
self.anchorLayoutSignatures[frameKey] = nil
self.nextAnchorRetryAt[frameKey] = nil
self._displaySignatures[frameKey] = "0"
return
end
for _, frame in pairs(frames) do
frame:Hide()
end
self.activeOrders[frameKey] = nil
self.unitByPlayer[frameKey] = nil
self.anchorLayoutSignatures[frameKey] = nil
self.nextAnchorRetryAt[frameKey] = nil
self._displaySignatures[frameKey] = "0"
end
function Manager:BuildEntriesByPlayerForTracker(tracker)
local frameKey = S.GetTrackerFrameKey(tracker.id)
local ownName = HMGT:NormalizePlayerName(UnitName("player")) or "Player"
if tracker.testMode then
local entries = self:CollectTestEntries(tracker)
if S.IsGroupTracker(tracker) and tracker.attachToPartyFrame == true then
return S.BuildPartyPreviewEntries(entries)
end
local byPlayer, order, unitByPlayer = {}, {}, {}
if #entries > 0 then
byPlayer[ownName] = entries
order[1] = ownName
unitByPlayer[ownName] = "player"
end
return byPlayer, order, unitByPlayer, true
end
if tracker.demoMode then
local entries = HMGT:GetDemoEntries(frameKey, S.GetTrackerSpellPool(tracker.categories), tracker)
if S.IsGroupTracker(tracker) and tracker.attachToPartyFrame == true then
return S.BuildPartyPreviewEntries(entries)
end
for _, entry in ipairs(entries) do
entry.playerName = ownName
end
local byPlayer, order, unitByPlayer = {}, {}, {}
if #entries > 0 then
byPlayer[ownName] = entries
order[1] = ownName
unitByPlayer[ownName] = "player"
end
return byPlayer, order, unitByPlayer, true
end
if not tracker.enabled or not HMGT:IsVisibleForCurrentGroup(tracker) then
return {}, {}, {}, false
end
if IsInRaid() or not IsInGroup() then
return {}, {}, {}, false
end
local byPlayer, order, unitByPlayer = {}, {}, {}
for _, playerInfo in ipairs(S.GetGroupPlayers(tracker)) do
local entries = S.CollectEntriesForPlayer(tracker, playerInfo)
if #entries > 0 then
local playerName = playerInfo.name
byPlayer[playerName] = entries
order[#order + 1] = playerName
unitByPlayer[playerName] = playerInfo.unitId
end
end
return byPlayer, order, unitByPlayer, true
end
function Manager:RefreshPerGroupAnchors(tracker, force)
local frameKey = S.GetTrackerFrameKey(tracker.id)
local frames = self.perPlayerFrames[frameKey] or {}
local ordered = {}
for _, playerName in ipairs(self.activeOrders[frameKey] or {}) do
local frame = frames[playerName]
if frame and frame:IsShown() then
ordered[#ordered + 1] = playerName
end
end
if #ordered == 0 then
self.anchorLayoutSignatures[frameKey] = nil
self.nextAnchorRetryAt[frameKey] = nil
return
end
local now = GetTime()
local signature = S.BuildAnchorLayoutSignature(tracker, ordered, self.unitByPlayer[frameKey])
if not force and self.anchorLayoutSignatures[frameKey] == signature then
local retryAt = tonumber(self.nextAnchorRetryAt[frameKey]) or 0
if retryAt <= 0 or now < retryAt then
return
end
end
for _, playerName in ipairs(ordered) do
local frame = frames[playerName]
if frame and frame._hmgtDragging then
return
end
end
if tracker.attachToPartyFrame == true then
local side = tracker.partyAttachSide or "RIGHT"
local extraX = tonumber(tracker.partyAttachOffsetX) or 8
local extraY = tonumber(tracker.partyAttachOffsetY) or 0
local growsUp = tracker.showBar == true and tracker.growDirection == "UP"
local barHeight = tonumber(tracker.barHeight) or 20
local growUpAttachOffset = barHeight + 20
local prevPlaced = nil
local missingTargets = 0
for _, playerName in ipairs(ordered) do
local frame = frames[playerName]
local unitId = self.unitByPlayer[frameKey] and self.unitByPlayer[frameKey][playerName]
local target = S.ResolveUnitAnchorFrame(unitId)
local contentTopInset = HMGT.TrackerFrame.GetContentTopInset and HMGT.TrackerFrame:GetContentTopInset(frame) or 0
frame:ClearAllPoints()
if target then
if side == "LEFT" then
if growsUp then
frame:SetPoint("BOTTOMRIGHT", target, "TOPLEFT", -extraX, extraY - growUpAttachOffset)
else
frame:SetPoint("TOPRIGHT", target, "TOPLEFT", -extraX, extraY + contentTopInset)
end
else
if growsUp then
frame:SetPoint("BOTTOMLEFT", target, "TOPRIGHT", extraX, extraY - growUpAttachOffset)
else
frame:SetPoint("TOPLEFT", target, "TOPRIGHT", extraX, extraY + contentTopInset)
end
end
elseif prevPlaced then
missingTargets = missingTargets + 1
HMGT:DebugScoped("verbose", HMGT:GetTrackerDebugScope(tracker), "TrackerAttach fallback-stack tracker=%s player=%s unit=%s", tostring(tracker.id), tostring(playerName), tostring(unitId))
if growsUp then
frame:SetPoint("BOTTOMLEFT", prevPlaced, "TOPLEFT", 0, (tracker.barSpacing or 2) + 10)
else
frame:SetPoint("TOPLEFT", prevPlaced, "BOTTOMLEFT", 0, -((tracker.barSpacing or 2) + 10))
end
else
missingTargets = missingTargets + 1
HMGT:DebugScoped("info", HMGT:GetTrackerDebugScope(tracker), "TrackerAttach fallback-anchor tracker=%s player=%s unit=%s", tostring(tracker.id), tostring(playerName), tostring(unitId))
HMGT.TrackerFrame:ApplyAnchor(frame)
end
frame:EnableMouse(false)
prevPlaced = frame
end
if missingTargets > 0 then
self.anchorLayoutSignatures[frameKey] = nil
self.nextAnchorRetryAt[frameKey] = now + 1.0
else
self.anchorLayoutSignatures[frameKey] = signature
self.nextAnchorRetryAt[frameKey] = nil
end
return
end
local primary = frames[ordered[1]]
HMGT.TrackerFrame:ApplyAnchor(primary)
primary:EnableMouse(not tracker.locked)
local gap = (tracker.barSpacing or 2) + 10
local growsUp = tracker.showBar == true and tracker.growDirection == "UP"
for index = 2, #ordered do
local prev = frames[ordered[index - 1]]
local frame = frames[ordered[index]]
frame:ClearAllPoints()
if growsUp then
frame:SetPoint("BOTTOMLEFT", prev, "TOPLEFT", 0, gap)
else
frame:SetPoint("TOPLEFT", prev, "BOTTOMLEFT", 0, -gap)
end
frame:EnableMouse(false)
end
self.anchorLayoutSignatures[frameKey] = signature
self.nextAnchorRetryAt[frameKey] = nil
end
function Manager:UpdatePerGroupMemberTracker(tracker)
local frameKey = S.GetTrackerFrameKey(tracker.id)
local byPlayer, order, unitByPlayer, shouldShow = self:BuildEntriesByPlayerForTracker(tracker)
self.activeOrders[frameKey] = order
self.unitByPlayer[frameKey] = unitByPlayer
local active, shownOrder = {}, {}
local shownByPlayer = {}
local entryCount, shouldTick = 0, false
for _, playerName in ipairs(order) do
local frame = self:EnsurePlayerFrame(tracker, playerName)
local entries = byPlayer[playerName] or {}
if HMGT.FilterDisplayEntries then
entries = HMGT:FilterDisplayEntries(tracker, entries) or entries
end
if HMGT.SortDisplayEntries then
HMGT:SortDisplayEntries(entries)
end
if #entries > 0 then
HMGT.TrackerFrame:UpdateFrame(frame, entries, true)
frame:Show()
active[playerName] = true
shownOrder[#shownOrder + 1] = playerName
shownByPlayer[playerName] = entries
entryCount = entryCount + #entries
for _, entry in ipairs(entries) do
if S.EntryNeedsVisualTicker(entry) then
shouldTick = true
break
end
end
else
frame:Hide()
end
end
for playerName, frame in pairs(self.perPlayerFrames[frameKey] or {}) do
if not active[playerName] then
frame:Hide()
end
end
self.activeOrders[frameKey] = shownOrder
self.unitByPlayer[frameKey] = unitByPlayer
self._displaySignatures[frameKey] = S.BuildGroupDisplaySignature and S.BuildGroupDisplaySignature(shownOrder, shownByPlayer) or nil
if shouldShow and #shownOrder > 0 then
self:RefreshPerGroupAnchors(tracker, false)
return true, entryCount, shouldTick
end
self:HidePlayerFrames(frameKey)
self._displaySignatures[frameKey] = "0"
return false, 0, false
end