Patterns from brues-code/pfUI: - Event updates (health, power, auras, range, sight, connection, resurrection) skip frames whose container or group is hidden; Show and group Show already run UpdateAll to catch up - HealPredict's cleanup OnUpdate stops when nothing can expire and restarts when a cast, HoT, resurrection or cast icon is added - UNIT_IN_RANGE_UPDATE is only registered without UnitXP SP3 and SuperWoW, since ClassicAPI checks registered units every frame Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019W3rwwTK1hwTEWHqsan2mV
156 lines
5.0 KiB
Lua
156 lines
5.0 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
|
|
if ui:IsActive() then -- Hidden frames catch up in UpdateAll when shown
|
|
ui:UpdateRange()
|
|
end
|
|
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
|
|
if ui:IsActive() then
|
|
ui:UpdateSight()
|
|
end
|
|
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 |