Squash of the classicapi_next branch (10 commits). ClassicAPI is now a hard requirement, and the Lua-side reimplementations it supersedes are gone: net -1087 lines across 12 files. Macro display: resolved macro actions are published through C_Macro.SetMacroDisplay, so the client draws macro buttons and the action-bar function overrides this addon used to install are removed. Ownership is per macro -- ClassicAPI keeps the macros we never claim. Auras and timing: ClassicAPI is the source of truth for non-player aura timing via the positional C_UnitAuras.UnitAura, replacing the write-only buff tracking tables and the overflow-slot fallback. Cleanup: the hasPfUI76 flag and the pfUI 7.6 branches it gated, two silently-shadowed code paths, and per-call allocations in the event and publish paths (SPELL_CAST_EVENT merged). Packaging moves to brues-code/packager@vCAPI. Macro syntax: a clause may carry a leading run of [group] blocks sharing one action, Blizzard-style -- groups are OR'd, first pass wins, and [] always passes. The ;-separated form is unchanged and mixes freely. @focus clauses with no focus set now fail quietly instead of printing "Invalid target" on the way past.
13 KiB
ClassicAPI Adoption Backlog
Opportunities to use ClassicAPI
(C:\Git\ClassicAPI, see docs/API.md) in SuperCleveRoidMacros. ClassicAPI is
a client mod (sibling to nampower/SuperWoW) that backports the modern C_* API
into the 1.12.1 client.
Policy: ClassicAPI is a hard requirement of this fork — no fallbacks. The
load-time requirement check warns when it's missing (Core.lua), the same as
nampower/UnitXP. ClassicAPI-backed code may assume the API is present (light
pcall/nil guards for runtime safety are fine, but do not maintain alternate
non-ClassicAPI implementations). Users who don't want ClassicAPI should run the
upstream addon instead.
API references are line numbers into C:\Git\ClassicAPI\docs\API.md.
Tier 1 — high impact (new capabilities, not just refactors)
1. C_UnitAuras — native aura data for any unit
-
API:
API.md:8670—GetAuraDataBySpellName(unit, name, filter),GetUnitAuraBySpellID(unit, spellID, filter),GetAuraDataByIndex. -
Returns
spellId,dispelName("Magic"/"Curse"/"Disease"/"Poison"),applications(stacks),duration. -
Unlocks:
[dispellable]/[curse]/[magic]target conditionals and spellID-based (rank/locale-proof) aura matching. -
Caveat:— NO LONGER TRUE. This note said target/focusexpirationTimeis player-onlyexpirationTimewas always0, so debuff timers had to stay on libdebuff. ClassicAPI has since added theAura::Sourcecache: for a non-player unitexpirationTimeis reconstructed from the observedSMSG_SPELL_GO, anddurationis the caster-modified value (talent extensions like Improved Shadow Word: Pain included). It also handles combo-point finisher scaling automatically (Rupture at 4 CP reads 14s, no registration) and ships Carnage's roll-gated Rip/Rake refresh in the DLL (src/turtle/Carnage.cpp, exposed asRegisterAuraDurationModifierByTrigger). -
Real remaining caveats (all best-effort, from
docs/API.md):- Only auras observed after login carry caster/timing; older ones report
expirationTime0 andsourceUnitnil. - Max-stack refresh is a blind spot: re-applying at max stacks (Shadow Weaving 5→5) emits no client-visible change, so the entry elapses and evicts.
- Out-of-range group members are spell-ID only, with
applicationsalways 1.
- Only auras observed after login carry caster/timing; older ones report
-
Consequence: most of libdebuff is now redundant — see "libdebuff retirement" below.
-
DONE (slice 1 — dispel-type conditionals): added
ClassicAPI.luadetection module (CleveRoids.ClassicAPI, mirrors NampowerAPI'sHasMinimumVersion) and the[magic]/[curse]/[disease]/[poison]/[dispellable]conditionals + negations, backed byC_UnitAuras.GetDebuffDataByIndex(...).dispelName. No-arg booleans, honor@unit, graceful fallback (positive→false, negated→true) when ClassicAPI is absent. Purely additive — the existingValidateAurapath is untouched. -
DONE (slice 2 — buff-side / offensive dispel):
UnitHasDispelTypenow takes ahelpfulflag (scansGetBuffDataByIndex), exposed as[magicbuff]/[dispellablebuff]+ negations — detect a dispellable buff to strip off an enemy (e.g.[harm,magicbuff] Dispel Magic). Magic-only is the practical set since 1.12 offensive dispel removes Magic buffs. -
Follow-ups (still TODO):
- spellID-based aura matching via
GetUnitAuraBySpellID(rank/locale-proof), optionally wired intoValidateAuraas a fast path with libdebuff fallback. - more reliable cross-unit stacks via
applications. - class-aware
[dispellable](only types this character can actually remove). - optional name filtering on the type keywords (e.g.
[magic:Polymorph]).
- spellID-based aura matching via
2. C_Item.GetWeaponEnchantInfo() — temp-enchant IDs — DONE
C_Item.GetWeaponEnchantInfo() — temp-enchant IDs- Shipped as
[mhenchant]/[ohenchant](+novariants). Matches the applied temp enchant by SpellItemEnchantment ID or localized name — the name path resolves viaC_Item.GetEnchantInfo(id).name(the ID→name table this doc assumed we lacked), so no tooltip scan. WrappersClassicAPI.GetWeaponEnchant/GetEnchantName;ValidateWeaponImbuenow reads through the former. - Bare = any temp enchant; OR-lists supported (
[mhenchant:2823/Deadly_Poison]). - Follow-up (optional): route
[mhimbue:Name]'s match throughGetEnchantNametoo, retiring the green-text tooltip scan inCheckWeaponImbueByName.
3. GetUnitSpeed(unit) + IsFalling() / IsSwimming()
-
API:
API.md:8312,API.md:7629. -
Replaces today: MonkeySpeed addon dependency (which needs SuperWoW
UnitPosition) for[moving]—Conditionals.lua:2981. -
DONE:
ClassicAPI.luaexposesHasUnitSpeed/GetUnitCurrentSpeed/GetPlayerSpeedPercent(100% = 7.0 yd/s) plusIsPlayerFalling(IsFalling).GetPlayerSpeedandIsPlayerMovingare ClassicAPI-only now; the boolean[moving]ORs inIsPlayerFallingso jumping/falling registers even thoughcurrentSpeedis horizontal-only. -
Fallbacks removed (ClassicAPI mandatory): deleted the MonkeySpeed integration (
HasMonkeySpeed,RequireMonkeySpeed), the NampowerPlayerIsMovingbranch, and the 100 Hz position-tracking buffer in Core.lua's OnUpdate (_positionHistory,POS_TRACK_INTERVAL,UnitPositionupvalue). MonkeySpeed dropped from README "Supported Addons". -
IsSwimmingdeliberately not used: swim state is true while treading water motionless, which would falsely report[moving].
Tier 2 — replace custom scanning / extra deps
GetActionInfo(slot) — action-slot → spell/macro/item mapping
- API:
API.md:489— returnsactionType, id, subType. - DONE:
ClassicAPI.GetActionInfowrapper added;GetActionButtonInfo(Extensions/Tooltip/Generic.lua) rewritten to use it and resolve names viaGetSpellRecField/GetItem/GetMacroInfo, replacing the per-slot GameTooltip scan + texture heuristic (which couldn't tell spell from item and never recognized macros). Powers reactive-ability slot detection (IndexActionSlot). Deleted the dead SuperWoW-GetActionTextcopy ofGetActionButtonInfoinConditionals.lua. - Known limitation: GetActionInfo returns
id = nilfor bag-instance items (items dragged from bags rather than placed by itemID), so those slots get no name. The consumers (actionSlotsfor/startattack·/shoot·auto-shot proxies, reactive spells) only need spells, so this is acceptable. - Follow-up (optional): migrate the remaining
GetActionTextmacro-slot detection inCore.lua/ComboPointTracker.luatoGetActionInfotoo.
4. C_Spell.* / GetSpellInfo(spellID)
- API:
API.md:6649+—GetSpellCooldown,IsUsableSpell,IsSpellKnown,SpellHasRange,GetSpellSchool,FindSpellBookSlotByID. - Replaces today: spellbook scanning via
GetSpellName(i, BOOKTYPE_SPELL)(Conditionals.lua:2500) and the Slam-slot hack. Simplifies[known],[usable], range checks.
5. C_Timer.After / NewTicker (+ coroutines)
- API:
API.md:8008+. - Replaces today: manual
OnUpdateframes (Core.lua:5082,:80,:460) and the UnitXP aura-cleanup timer (Conditionals.lua:1474).
6. UnitGUID / UnitTokenFromGUID
- API:
API.md:8206+. - Replaces today: SuperWoW GUIDs in ComboPointTracker (
ComboPointTracker.lua). - Verify first: confirm GUID string format matches SuperWoW's before swapping.
7. Native focus token + FocusUnit/ClearFocus + PLAYER_FOCUS_CHANGED
- API:
API.md:2624+. - Replaces today: custom/pfUI focus resolution (
Conditionals.lua:5799,:3148). Gives engine-backed@focusfor non-pfUI users.
Tier 3 — situational
C_NamePlate.GetNamePlates()/nameplateNtokens (API.md:5742+) — alternative to UnitXP enemy enumeration for AoE counting (Conditionals.lua:3099).GetShapeshiftFormID()+UPDATE_SHAPESHIFT_FORM(API.md:7792) — cleaner stance/form conditionals.CastSpellNoToggle/ numeric spellIDs in/cast(API.md:5336+) — rank-specific casting by ID, no-toggle behavior; could back a/cast <spellID>.- State helpers
IsStealthed/IsMounted/UnitStandState(API.md:7574+) — back simple[stealth]/[mounted]/[standing]conditionals.
Cross-cutting policy
ClassicAPI is a hard requirement (see policy at the top) — ClassicAPI-backed
code calls the API directly, no fallbacks. Light pcall/nil guards for
runtime safety are fine; do not maintain alternate non-ClassicAPI
implementations. The load-time requirement check (Core.lua) warns when it's
missing, the same as nampower/UnitXP.
Conditionals.lua audit — do NOT migrate (traps)
Findings from the full Conditionals.lua audit. These look like ClassicAPI candidates but are worse than the current implementation — recorded so we don't re-investigate.
Auras /— STALE, do not trust this entry. It was written before theValidateAura—C_UnitAuras.expirationTimeis player-onlyAura::Sourcecache landed. Non-playerexpirationTime/durationnow work (caster-modified, talent extensions included), so this is no longer a reason to keep libdebuff's remote-duration tracking. See Tier 1 §1 and "libdebuff retirement" for the current picture and the real caveats. The nampowerGetUnitFieldbatch read is a separate question and has not been re-examined.GetCurrentShapeshiftIndexform loop /[stance]·[form]—GetShapeshiftFormID()returns the DBC form id (Cat=1, Bear=5, Shadowform=28…), NOT the 1-based bar index these conditionals compare against. Swapping would silently break every[stance:N]/[form:N]macro. (Only the Rogue stealth branch was migrated, viaIsStealthed.)- Cast-time scans (Slam-clip,
GetSpellCastTime) — ClassicAPI/DBC cast time is base only (no haste/talents/buffs), which defeats the reason these scan the tooltip. - Range / distance / behind / facing — UnitXP_SP3 gives precise yards +
facing;
UnitInRangeis a binary 40yd and has no facing/behind. Keep UnitXP. FindItemLocation— nampowerFindPlayerItemSlotfinds an item by id/name across bags in one call; ClassicAPI has no equivalent (would need a manualC_Containerbag scan). Keep nampower.[known](name+rank+talent logic richer thanIsSpellKnown/IsPlayerSpell's current-rank/no-talent semantics) and[usable]/reactive (nampowerIsSpellUsable==IsUsableSpell). Keep.
Conditionals.lua audit — done
GetItemCooldownCached→ ClassicAPIGetItemCooldown(item)(slots 1-19 still inventory-based).[stealth]/[nostealth]/[stl]/[nostl]+ Rogue branch ofGetCurrentShapeshiftIndex→IsStealthed().CountEnemiesMatchingnameplate scan →C_NamePlate.GetNamePlateGUIDs().- Focus:
GetFocusUnitId/TryTargetFocususe the native"focus"token; added[focus]/[nofocus]./focusis provided by ClassicAPI's companion addon.
libdebuff retirement
libdebuff exists because vanilla cannot report debuff durations on units other
than the player. ClassicAPI's Aura::Source cache now does exactly that, so most
of the library is redundant. This is a staged replacement, not a delete: measure
first, then remove per group.
Current footprint: 28 public lib: methods, ~726 internal references in
Utility.lua, consumers in 8 files (Conditionals.lua 45, Compatibility/pfUI.lua
39, Core.lua 9). Note pfUI did not delete its own libdebuff — v9.0.25 still
ships ~1695 lines of it, re-based on C_UnitAuras.GetAuraDataByIndex /
GetAuraDataBySpellName. "Re-base on C_UnitAuras", not "remove", is the precedent.
Group A — replaceable by C_UnitAuras (do these first):
GetDuration, GetDebuffCaster, IsOurDebuff, UnitBuff/UnitDebuff,
FindPlayerDebuff/FindPlayerBuff, GetAllDebuffsOnTarget, GetCachedIcon,
ApplyCarnageRefresh, and the Dark Harvest trio (ApplyDarkHarvestStart/End,
GetDarkHarvestReduction, GetTimeRemainingWithDarkHarvest) — ClassicAPI ships
Carnage refresh and Dark Harvest tick compression in the DLL.
Group B — no C_UnitAuras equivalent, keep:
ShouldApplyDebuffRank, DidSpellFail, WasSpellReflected, DidTargetEvade,
ProcessMissReason, IsPersonalDebuff, GetSpellRank/GetSpellBaseName,
HasPendingCast. These are miss/rank/learning logic, not aura state.
Gate before removing Group A: confirm parity in-game on one spell where
ClassicAPI does the hard part — Rip under Carnage. Compare
CleveRoids.libdebuff:GetDuration(spellID) against
C_UnitAuras.GetUnitAuraBySpellID(unit, spellID).duration and the derived
remaining (expirationTime - GetTime()), on a target you have debuffed. If those
agree across a Carnage proc, Group A can go. Watch the documented best-effort
gaps: an aura cast before you logged in, and refresh-at-max-stacks.
Marginal / optional follow-ups
[swimming]→IsSwimming()would drop the nampower-2.36 version gate + warning (same semantics).[rooted]has no ClassicAPI equivalent — keep nampower.- Weapon-imbue name match (
[imbue:Mongoose]) →C_Item.GetWeaponEnchantInfogives enchant IDs, so it needs an enchantID→name table we don't ship.