Files
HailMaryGuildTools/Modules/Tracker/TrackerDataProvider.lua
2026-04-24 23:43:55 +02:00

269 lines
10 KiB
Lua

local ADDON_NAME = "HailMaryGuildTools"
local HMGT = LibStub("AceAddon-3.0"):GetAddon(ADDON_NAME)
if not HMGT then return end
HMGT.TrackerDataProvider = HMGT.TrackerDataProvider or {}
local internals = HMGT.TrackerInternals or {}
local SafeApiNumber = internals.SafeApiNumber
local GetSpellChargesInfo = internals.GetSpellChargesInfo
local GetSpellCooldownInfo = internals.GetSpellCooldownInfo
function HMGT:GetCooldownInfo(playerName, spellId, opts)
opts = opts or {}
local deferUntilEmpty = opts.deferChargeCooldownUntilEmpty and true or false
local spellEntry = HMGT_SpellData.InterruptLookup[spellId]
or HMGT_SpellData.CooldownLookup[spellId]
local ownName = self:NormalizePlayerName(UnitName("player"))
local isOwnPlayer = playerName == ownName
local pData = isOwnPlayer and self.playerData[ownName] or nil
local talents = pData and pData.talents or {}
local effectiveCd = spellEntry and HMGT_SpellData.GetEffectiveCooldown(spellEntry, talents) or 0
local knownMaxCharges, knownChargeDuration = 0, 0
if spellEntry and isOwnPlayer then
knownMaxCharges, knownChargeDuration = self:GetKnownChargeInfo(spellEntry, talents, spellId, effectiveCd)
end
if self:IsAvailabilitySpell(spellEntry) then
local normalizedName = self:NormalizePlayerName(playerName)
if normalizedName == ownName then
local current, max = self:GetOwnAvailabilityProgress(spellEntry)
if (tonumber(max) or 0) > 0 then
self:StoreAvailabilityState(ownName, spellId, current, max, spellEntry)
return 0, 0, current, max
end
else
local current, max = self:GetAvailabilityState(normalizedName, spellId)
if (tonumber(max) or 0) > 0 then
return 0, 0, current, max
end
end
return 0, 0, nil, nil
end
local cdData = self:GetActiveCooldown(playerName, spellId)
if isOwnPlayer and not (InCombatLockdown and InCombatLockdown()) then
local charges, maxCharges, chargeStart, chargeDuration = nil, nil, nil, nil
if GetSpellChargesInfo then
charges, maxCharges, chargeStart, chargeDuration = GetSpellChargesInfo(spellId)
end
charges = SafeApiNumber and SafeApiNumber(charges, 0) or tonumber(charges) or 0
maxCharges = SafeApiNumber and SafeApiNumber(maxCharges, 0) or tonumber(maxCharges) or 0
chargeStart = SafeApiNumber and SafeApiNumber(chargeStart) or tonumber(chargeStart)
chargeDuration = SafeApiNumber and SafeApiNumber(chargeDuration, 0) or tonumber(chargeDuration) or 0
if maxCharges > 0 then
local tempChargeState = {
currentCharges = charges,
maxCharges = maxCharges,
chargeStart = chargeStart,
chargeDuration = chargeDuration,
duration = chargeDuration,
}
local remaining, total, curCharges, maxChargeCount = self:ResolveChargeState(tempChargeState)
self:StoreKnownChargeInfo(spellId, maxChargeCount, total > 0 and total or chargeDuration)
if (curCharges or 0) < maxChargeCount and remaining <= 0 and GetSpellCooldownInfo then
local cdStart, cdDuration = GetSpellCooldownInfo(spellId)
if cdDuration > 0 then
remaining = math.max(0, cdDuration - (GetTime() - cdStart))
total = math.max(total or 0, cdDuration)
end
end
if deferUntilEmpty and (curCharges or 0) > 0 then
remaining = 0
end
return remaining, total, curCharges, maxChargeCount
end
if GetSpellCooldownInfo then
local cdStart, cdDuration = GetSpellCooldownInfo(spellId)
cdStart = tonumber(cdStart) or 0
cdDuration = tonumber(cdDuration) or 0
if cdDuration > 0 then
local remaining = math.max(0, cdDuration - (GetTime() - cdStart))
remaining = math.max(0, math.min(cdDuration, remaining))
if cdData and (tonumber(cdData.maxCharges) or 0) <= 0 then
local cachedRemaining = (tonumber(cdData.duration) or 0) - (GetTime() - (tonumber(cdData.startTime) or GetTime()))
cachedRemaining = math.max(0, math.min(tonumber(cdData.duration) or cachedRemaining, cachedRemaining))
local cachedDuration = math.max(0, tonumber(cdData.duration) or 0)
if cachedDuration > 2.0 and cachedRemaining > 2.0 and cdDuration < math.max(2.0, cachedDuration * 0.35) then
return cachedRemaining, cachedDuration, nil, nil
end
end
return remaining, cdDuration, nil, nil
end
end
end
if not cdData then
if isOwnPlayer and knownMaxCharges > 1 then
return 0, math.max(0, knownChargeDuration or effectiveCd or 0), knownMaxCharges, knownMaxCharges
end
return 0, 0, nil, nil
end
if (tonumber(cdData.maxCharges) or 0) > 0 then
local remaining, chargeDur, charges, maxCharges = self:ResolveChargeState(cdData)
self:StoreKnownChargeInfo(spellId, maxCharges, chargeDur)
if deferUntilEmpty and charges > 0 then
remaining = 0
end
return remaining, chargeDur, charges, maxCharges
end
if isOwnPlayer and knownMaxCharges > 1 then
local remaining = (tonumber(cdData.duration) or 0) - (GetTime() - (tonumber(cdData.startTime) or GetTime()))
remaining = math.max(0, math.min(tonumber(cdData.duration) or remaining, remaining))
local currentCharges = knownMaxCharges
if remaining > 0 then
currentCharges = math.max(0, knownMaxCharges - 1)
end
if deferUntilEmpty and currentCharges > 0 then
remaining = 0
end
return remaining, math.max(0, knownChargeDuration or effectiveCd or 0), currentCharges, knownMaxCharges
end
local remaining = cdData.duration - (GetTime() - cdData.startTime)
remaining = math.max(0, math.min(cdData.duration, remaining))
return remaining, cdData.duration, nil, nil
end
function HMGT:ShouldDisplayEntry(settings, remaining, currentCharges, maxCharges, spellEntry)
local rem = tonumber(remaining) or 0
local cur = tonumber(currentCharges) or 0
local max = tonumber(maxCharges) or 0
local soon = tonumber(settings.readySoonSec) or 0
local isAvailabilitySpell = spellEntry and self:IsAvailabilitySpell(spellEntry) or false
local isReady
if isAvailabilitySpell then
isReady = max > 0 and cur >= max
else
isReady = rem <= 0 or (max > 0 and cur > 0)
end
if settings.showOnlyReady then
return isReady
end
if soon > 0 then
if isAvailabilitySpell then
return isReady
end
return isReady or rem <= soon
end
return true
end
local DEFAULT_CATEGORY_PRIORITY = {
interrupt = 1,
lust = 2,
defensive = 3,
tank = 4,
healing = 5,
offensive = 6,
utility = 7,
cc = 8,
}
local TRACKER_CATEGORY_PRIORITY = {
interruptTracker = {
interrupt = 1,
defensive = 2,
utility = 3,
cc = 4,
healing = 5,
tank = 6,
offensive = 7,
lust = 8,
},
raidCooldownTracker = {
lust = 1,
defensive = 2,
healing = 3,
tank = 4,
utility = 5,
offensive = 6,
cc = 7,
interrupt = 8,
},
groupCooldownTracker = {
tank = 1,
defensive = 2,
healing = 3,
cc = 4,
utility = 5,
offensive = 6,
lust = 7,
interrupt = 8,
},
}
local function GetCategoryPriority(category, trackerKey)
local cat = tostring(category or "utility")
local trackerOrder = trackerKey and TRACKER_CATEGORY_PRIORITY[trackerKey]
if trackerOrder and trackerOrder[cat] then
return trackerOrder[cat]
end
local order = HMGT_SpellData and HMGT_SpellData.CategoryOrder
if type(order) == "table" then
for idx, key in ipairs(order) do
if key == cat then
return idx
end
end
return #order + 10
end
return DEFAULT_CATEGORY_PRIORITY[cat] or 99
end
function HMGT:SortDisplayEntries(entries, trackerKey)
if type(entries) ~= "table" then return end
table.sort(entries, function(a, b)
local aRemaining = tonumber(a and a.remaining) or 0
local bRemaining = tonumber(b and b.remaining) or 0
local aActive = aRemaining > 0
local bActive = bRemaining > 0
if aActive ~= bActive then
return aActive
end
local aEntry = a and a.spellEntry
local bEntry = b and b.spellEntry
local aPriority = tonumber(aEntry and aEntry.priority) or GetCategoryPriority(aEntry and aEntry.category, trackerKey)
local bPriority = tonumber(bEntry and bEntry.priority) or GetCategoryPriority(bEntry and bEntry.category, trackerKey)
if aPriority ~= bPriority then
return aPriority < bPriority
end
if aActive and aRemaining ~= bRemaining then
return aRemaining < bRemaining
end
local aTotal = tonumber(a and a.total)
or tonumber(aEntry and HMGT_SpellData.GetBaseCooldown and HMGT_SpellData.GetBaseCooldown(aEntry))
or tonumber(aEntry and aEntry.cooldown)
or 0
local bTotal = tonumber(b and b.total)
or tonumber(bEntry and HMGT_SpellData.GetBaseCooldown and HMGT_SpellData.GetBaseCooldown(bEntry))
or tonumber(bEntry and bEntry.cooldown)
or 0
if (not aActive) and aTotal ~= bTotal then
return aTotal > bTotal
end
if aRemaining ~= bRemaining then
return aRemaining < bRemaining
end
local aName = tostring(a and a.playerName or "")
local bName = tostring(b and b.playerName or "")
if aName ~= bName then
return aName < bName
end
local aSpell = tonumber(aEntry and aEntry.spellId) or 0
local bSpell = tonumber(bEntry and bEntry.spellId) or 0
return aSpell < bSpell
end)
end