When ClassicAPI is installed and "Use ClassicAPI" is on (Mods tab, reload): - Detect ClassicAPI and each feature separately; show it in the Mods tab - Read auras with C_UnitAuras.GetAuraSlots (fill form) + UnitAuraBySlot, reusing entries, with ClassicAPI durations, expirations and casters - UNIT_AURA_DELTA: refresh-only events update stacks and timers in place without rebuilding the aura icons or the health bar - Aura timers without SuperWoW; native Cooldown frames with one shared text driver instead of a Model and OnUpdateModel per icon - UNIT_IN_RANGE_UPDATE, UNIT_DISTANCE_CHECK_UPDATE, UNIT_CONNECTION and INCOMING_RESURRECT_CHANGED; UnitHasIncomingResurrection in res checks - HealPredict learns heals from COMBAT_LOG_EVENT_UNFILTERED when the GUID formats match SuperWoW's - Distance and line of sight when UnitXP SP3 and SuperWoW are missing Without ClassicAPI, or with the option off, behaviour is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019W3rwwTK1hwTEWHqsan2mV
152 lines
4.8 KiB
Lua
152 lines
4.8 KiB
Lua
PTUtil.SetEnvironment(Puppeteer)
|
|
local _G = getfenv(0)
|
|
|
|
UnitTrackerFrame = CreateFrame("Frame", "PTUnitTrackerFrame", UIParent)
|
|
|
|
local util = PTUtil
|
|
local GetTime = GetTime
|
|
local compost = PTPool
|
|
|
|
local TRACKING_EVAL_INTERVAL = 1.25
|
|
local RANGE_MIN_DIST = 20
|
|
local RANGE_MAX_DIST = 60
|
|
local SIGHT_MAX_DIST = 80
|
|
local DISTANCE_UPDATE_INTERVAL = 0.1
|
|
local SIGHT_UPDATE_INTERVAL = 0.1
|
|
|
|
local AllUnits = util.AllUnits
|
|
|
|
local distanceTrackedUnits = {}
|
|
local sightTrackedUnits = {}
|
|
local prevSightTrackedUnits = {} -- Swapped with sightTrackedUnits on every evaluation, so no tables are created
|
|
local preciseDistance = util.CanClientGetPreciseDistance()
|
|
local sightTrackingEnabled = util.CanClientSightCheck()
|
|
local nextEval = GetTime() + 0.5
|
|
local nextRangeUpdate = GetTime() + 0.6
|
|
local nextSightUpdate = GetTime() + 0.6
|
|
if not preciseDistance then
|
|
nextRangeUpdate = nextRangeUpdate + 99999999 -- Effectively disable updates
|
|
end
|
|
if not sightTrackingEnabled then
|
|
nextSightUpdate = nextSightUpdate + 99999999
|
|
end
|
|
|
|
function LoadTrackingOptions()
|
|
local opts = PTOptions.Tracking
|
|
TRACKING_EVAL_INTERVAL = opts.EvaluateInterval
|
|
RANGE_MIN_DIST = opts.MinDistanceTracking
|
|
RANGE_MAX_DIST = opts.MaxDistanceTracking
|
|
SIGHT_MAX_DIST = opts.MaxSightTracking
|
|
DISTANCE_UPDATE_INTERVAL = opts.DistanceUpdateInterval
|
|
SIGHT_UPDATE_INTERVAL = opts.SightUpdateInterval
|
|
end
|
|
|
|
function RunTrackingScan()
|
|
local UnitFrames = UnitFrames
|
|
local time = GetTime()
|
|
if time > nextEval then
|
|
--StartTiming("TrackingEval")
|
|
nextEval = time + TRACKING_EVAL_INTERVAL
|
|
|
|
|
|
compost:Erase(distanceTrackedUnits)
|
|
local previous = sightTrackedUnits
|
|
sightTrackedUnits = compost:Erase(prevSightTrackedUnits)
|
|
prevSightTrackedUnits = previous
|
|
if PTGuidRoster then
|
|
for guid, cache in pairs(PTUnit.GetAllUnits()) do
|
|
EvaluateTracking(guid)
|
|
end
|
|
else
|
|
for _, unit in ipairs(AllUnits) do
|
|
EvaluateTracking(unit)
|
|
end
|
|
end
|
|
|
|
for _, unit in ipairs(prevSightTrackedUnits) do
|
|
for ui in UnitFrames(unit) do
|
|
ui:UpdateSight()
|
|
end
|
|
end
|
|
--EndTiming("TrackingEval")
|
|
end
|
|
|
|
if time > nextRangeUpdate then
|
|
nextRangeUpdate = time + DISTANCE_UPDATE_INTERVAL
|
|
for _, unit in ipairs(distanceTrackedUnits) do
|
|
local cache = PTUnit.Get(unit)
|
|
if cache and cache:UpdateDistance() then
|
|
for ui in UnitFrames(unit) do
|
|
ui:UpdateRange()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if time > nextSightUpdate then
|
|
nextSightUpdate = time + SIGHT_UPDATE_INTERVAL
|
|
for _, unit in ipairs(sightTrackedUnits) do
|
|
local cache = PTUnit.Get(unit)
|
|
--StartTiming("SightScan")
|
|
if cache and cache:UpdateSight() then
|
|
for ui in UnitFrames(unit) do
|
|
ui:UpdateSight()
|
|
end
|
|
end
|
|
--EndTiming("SightScan")
|
|
end
|
|
end
|
|
end
|
|
|
|
function EvaluateTracking(unit, update)
|
|
local UnitFrames = UnitFrames
|
|
local cache = PTUnit.Get(unit)
|
|
local distanceChanged = cache:UpdateDistance()
|
|
local sightChanged = cache:UpdateSight()
|
|
local new = cache:CheckNew()
|
|
local dist = cache:GetDistance()
|
|
if distanceChanged or sightChanged or new then
|
|
for ui in UnitFrames(unit) do
|
|
if distanceChanged or new then
|
|
ui:UpdateRange()
|
|
end
|
|
if sightChanged or new then
|
|
ui:UpdateSight()
|
|
end
|
|
end
|
|
end
|
|
if cache:UpdatePVP() then
|
|
for ui in UnitFrames(unit) do
|
|
ui:UpdatePVP()
|
|
end
|
|
end
|
|
local isTarget = UnitIsUnit(unit, "target")
|
|
if PTGuidRoster then
|
|
unit = PTGuidRoster.ResolveUnitGuid(unit)
|
|
end
|
|
-- Only closely track units that are close to the range threshold
|
|
if isTarget or (dist <= RANGE_MAX_DIST and dist >= RANGE_MIN_DIST) then
|
|
if not update or not util.ArrayContains(distanceTrackedUnits, unit) then
|
|
table.insert(distanceTrackedUnits, unit)
|
|
end
|
|
end
|
|
if sightTrackingEnabled and (isTarget or (dist > 0 and dist < SIGHT_MAX_DIST)) then
|
|
if not update or not util.ArrayContains(sightTrackedUnits, unit) then
|
|
table.insert(sightTrackedUnits, unit)
|
|
end
|
|
end
|
|
end
|
|
|
|
function StartUnitTracker()
|
|
LoadTrackingOptions()
|
|
-- Providers can change once options are loaded (ClassicAPI distance and sight)
|
|
if not preciseDistance and util.CanClientGetPreciseDistance() then
|
|
preciseDistance = true
|
|
nextRangeUpdate = GetTime() + 0.6
|
|
end
|
|
if not sightTrackingEnabled and util.CanClientSightCheck() then
|
|
sightTrackingEnabled = true
|
|
nextSightUpdate = GetTime() + 0.6
|
|
end
|
|
UnitTrackerFrame:SetScript("OnUpdate", RunTrackingScan)
|
|
end |