feat: add UnitEventListener for retail Midnight CLEU restrictions (#28)#29
Conversation
Retail patch 12.0 (Midnight, Interface 120000+) suppresses COMBAT_LOG_EVENT_UNFILTERED for addons - the event registers but never fires. Route interrupt and CC-on-player detection through UNIT_* events on affected clients while leaving Classic (MoP, TBC Anniversary) on the identical CLEU code path. Per ADR-0002: - New Core/Capabilities.lua exposes ns.capabilities.cleuRestricted, set at file scope from (C_RestrictedActions ~= nil) AND mainline build >= 120000. - New Listeners/UnitEventListener.lua: private unnamed CreateFrame (mirrors PR #26 anti-taint pattern), registers UNIT_SPELLCAST_INTERRUPTED and UNIT_AURA. Translates payloads into the CLEU-shaped positional tuple the existing handlers consume, plus a trailing 'extras' table for spell info (CombatLogGetCurrentEventInfo is not the source of truth on Midnight). - CombatLogListener.Initialize/Shutdown self-gate on cleuRestricted - no CLEU registration on retail Midnight. - InterruptListener.OnInterrupt and AuraListener.OnAuraApplied gain an optional trailing 'extras' parameter. When nil (Classic forwarding via CombatLogListener), behavior is unchanged. - Both dispatchers are always in LISTENER_MODULES; each self-gates on ns.capabilities inside its own Initialize. Dropped on retail Midnight (no clean attribution event): - dispels: DispelListener stays on disk but is never invoked. - ccApplied (CC the player lands on others): sourceUnit on AuraData is unreliable. Files added: Core/Capabilities.lua, Listeners/UnitEventListener.lua. Files modified: Core/Init.lua, DragonShout.toc, .luacheckrc, Listeners/{CombatLogListener,InterruptListener,AuraListener}.lua. Refs: #28, ADR-0002
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Organization UI (inherited) Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…) (#26) * fix: avoid AceEvent shared-frame taint for combat log registration (#22) Replace addon:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED", ...) with a private, unnamed CreateFrame("Frame") + OnEvent script. The shared AceEvent30Frame can be tainted by upstream addons via CallbackHandler's OnUsed lazy-registration path, which then blocks any first-time event registration from clean addons with ADDON_ACTION_FORBIDDEN. Using a private unnamed frame for CLEU isolates DragonShout from this class of cross-addon taint. The one-shot PLAYER_LOGIN registration in Core/Lifecycle.lua remains on AceEvent - it's rarely the first registrant and degrades gracefully. See .deliverables/tech-lead/ADR-0001-dragonshout-aceevent-taint.md * docs: remove stale UnitEventListener/capabilities prose (#22) Cleanup leftover design notes from abandoned PR #24 that documented a ns.capabilities.combatLog gate and UnitEventListener module which were never merged. PR #26 fixes #22 via a private CreateFrame frame to escape shared AceEvent30Frame taint; the prior Midnight/HasRestrictions diagnosis was incorrect. * feat: add UnitEventListener for retail Midnight CLEU restrictions (#28) (#29) Retail patch 12.0 (Midnight, Interface 120000+) suppresses COMBAT_LOG_EVENT_UNFILTERED for addons - the event registers but never fires. Route interrupt and CC-on-player detection through UNIT_* events on affected clients while leaving Classic (MoP, TBC Anniversary) on the identical CLEU code path. Per ADR-0002: - New Core/Capabilities.lua exposes ns.capabilities.cleuRestricted, set at file scope from (C_RestrictedActions ~= nil) AND mainline build >= 120000. - New Listeners/UnitEventListener.lua: private unnamed CreateFrame (mirrors PR #26 anti-taint pattern), registers UNIT_SPELLCAST_INTERRUPTED and UNIT_AURA. Translates payloads into the CLEU-shaped positional tuple the existing handlers consume, plus a trailing 'extras' table for spell info (CombatLogGetCurrentEventInfo is not the source of truth on Midnight). - CombatLogListener.Initialize/Shutdown self-gate on cleuRestricted - no CLEU registration on retail Midnight. - InterruptListener.OnInterrupt and AuraListener.OnAuraApplied gain an optional trailing 'extras' parameter. When nil (Classic forwarding via CombatLogListener), behavior is unchanged. - Both dispatchers are always in LISTENER_MODULES; each self-gates on ns.capabilities inside its own Initialize. Dropped on retail Midnight (no clean attribution event): - dispels: DispelListener stays on disk but is never invoked. - ccApplied (CC the player lands on others): sourceUnit on AuraData is unreliable. Files added: Core/Capabilities.lua, Listeners/UnitEventListener.lua. Files modified: Core/Init.lua, DragonShout.toc, .luacheckrc, Listeners/{CombatLogListener,InterruptListener,AuraListener}.lua. Refs: #28, ADR-0002
Closes #28. Implements the migration design specified in
.deliverables/tech-lead/ADR-0002-dragonshout-midnight-unit-events.md.Why
On retail Midnight (Interface 120000+),
COMBAT_LOG_EVENT_UNFILTEREDis no longer available to addons (per Blizzard's October 2025 announcement and Ion Hazzikostas's combat addon disarmament post). PR #26 silences the resultingADDON_ACTION_FORBIDDENerror on retail and remains fully functional on Classic flavors, but does not restore retail combat announcements. This PR adds the actual functional replacement.What
Core/Capabilities.luaexposesns.capabilities.cleuRestricted(anddispelAttribution). Set once at load time, gated onC_RestrictedActions ~= nil AND WOW_PROJECT_ID == WOW_PROJECT_MAINLINE AND build >= 120000.Listeners/UnitEventListener.luauses a private unnamedCreateFrame("Frame")(consistent with ADR-0001 / PR fix: avoid AceEvent shared-frame taint for combat log registration (#22) #26) to registerUNIT_SPELLCAST_INTERRUPTEDandUNIT_AURAon retail Midnight. Translates payloads into CLEU-shaped tuples plus an optional trailingextrastable.CombatLogListener.Initialize/Shutdownself-gate oncleuRestrictedso the two listeners are mutually exclusive withoutInit.luaknowing.InterruptListener.OnInterruptandAuraListener.OnAuraAppliedgain an optional trailingextrasparameter. When absent (Classic CLEU path), behavior is byte-for-byte identical to pre-PR.Behavior matrix
Retail Midnight degraded behaviors (intentional)
UNIT_SPELLCAST_INTERRUPTEDpayload contains only the interrupted spell, not the interrupter's spell. The announcement template now reads "Interrupted Boss's Fireball" rather than "Interrupted Boss's Fireball with Kick".UNIT_AURAsource attribution is unreliable in restriction windows. Onlyunit == "player"CC is announced on retail.RAID_PLAYER_DISPELLABLEfilter andGetAuraDispelTypeColorsignal intent toward display rather than attribution. One-shot DebugPrint at Initialize on retail explaining the gap.Stacked PR
This is stacked on top of #26. Once #26 merges, this branch will be rebased onto master.
Verification
luacheck .- 0 warnings, 0 errors in 32 files.39f5bffafter a BLOCKER fix (interrupter filter switched from incorrect GUID compare to correct unit-token compare).Out of scope