Optional ClassicAPI support

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
This commit is contained in:
2026-11-02 19:36:30 +00:00
co-authored by Claude Opus 5.5
parent f7ba1c934f
commit 0f803aca4d
11 changed files with 779 additions and 93 deletions
+102 -5
View File
@@ -65,11 +65,8 @@ RegisterEventHandler({"UNIT_MANA", "UNIT_RAGE", "UNIT_ENERGY", "UNIT_FOCUS", "UN
raidFrameGroup:RequestRaidManaUpdate()
end
end)
RegisterEventHandler("UNIT_AURA", function()
local unit = arg1
if not IsRelevantUnit(unit) then
return
end
-- Rescans the unit's auras and rebuilds its aura icons
local function UpdateUnitAuras(unit)
if unit == "player" then
util.MarkSpellCostCacheDirty()
end
@@ -78,7 +75,107 @@ RegisterEventHandler("UNIT_AURA", function()
ui:UpdateAuras()
ui:UpdateHealth() -- Update health because there may be an aura that changes health bar color
end
end
-- True once UNIT_AURA_DELTA handles the real unit tokens (see RegisterClassicAPIEvents)
local auraDeltaActive = false
local AllRealUnitsSet = util.AllRealUnitsSet
RegisterEventHandler("UNIT_AURA", function()
local unit = arg1
if not IsRelevantUnit(unit) then
return
end
-- ClassicAPI reports the same changes for these tokens through UNIT_AURA_DELTA, with what changed.
-- Other arguments (SuperWoW GUIDs of custom units) still come only through UNIT_AURA, and so do
-- members out of view, whose auras arrive with the party stats rather than the unit's own fields.
if auraDeltaActive and AllRealUnitsSet[unit] and UnitIsVisible(unit) then
return
end
UpdateUnitAuras(unit)
end)
-- ClassicAPI events, registered once options are loaded and the unit frames exist
function RegisterClassicAPIEvents()
if util.IsClassicAPIActive("AuraDelta") then
auraDeltaActive = true
RegisterEventHandler("UNIT_AURA_DELTA", function()
local unit = arg1
if not IsRelevantUnit(unit) then
return
end
local info = arg2 -- Valid only during this handler
if info and not info.isFullUpdate and not info.addedAuraInstanceIDs and not info.removedAuraInstanceIDs then
-- Only refreshes and stack changes: update the timers and stacks in place
if PTUnit.Get(unit):RefreshClassicAuras() then
if unit == "player" then
util.MarkSpellCostCacheDirty()
end
for ui in UnitFrames(unit) do
ui:RefreshAuras()
end
return
end
end
UpdateUnitAuras(unit)
end)
end
if util.IsClassicAPIActive("Resurrection") then
RegisterEventHandler("INCOMING_RESURRECT_CHANGED", function()
local unit = arg1
if not IsRelevantUnit(unit) then
return
end
for ui in UnitFrames(unit) do
ui:UpdateHealth()
end
end)
end
if util.IsClassicAPIActive("ConnectionEvent") then
RegisterEventHandler("UNIT_CONNECTION", function()
local unit = arg1
if not IsRelevantUnit(unit) then
return
end
PTUnit.Get(unit):UpdateDistance()
for ui in UnitFrames(unit) do
ui:UpdateHealth()
ui:UpdatePower()
ui:UpdateRange()
end
end)
end
-- Visibility and the 40 yard check change state right away instead of at the next tracking scan
local function UpdateUnitRange()
local unit = arg1
if not IsRelevantUnit(unit) then
return
end
local cache = PTUnit.Get(unit)
local distanceChanged = cache:UpdateDistance()
local sightChanged = cache:UpdateSight()
if distanceChanged or sightChanged then
for ui in UnitFrames(unit) do
if distanceChanged then
ui:UpdateRange()
end
if sightChanged then
ui:UpdateSight()
end
end
end
end
if util.IsClassicAPIActive("VisibilityEvent") then
RegisterEventHandler("UNIT_DISTANCE_CHECK_UPDATE", UpdateUnitRange)
end
if util.IsClassicAPIActive("RangeEvent") then
-- RegisterEvent covers pet, party and raid members and their pets, which ClassicAPI checks every frame
RegisterEventHandler("UNIT_IN_RANGE_UPDATE", UpdateUnitRange)
end
end
RegisterEventHandler({"PARTY_MEMBERS_CHANGED", "RAID_ROSTER_UPDATE"}, function()
CheckGroupThrottled()
end)