docs+cvars: four status rows the last two rounds made stale
The event bucket table still listed `SPELL_QUEUE_EVENT` as deliberately absent; it has been fired from `ui_spellbook.rs` since the queue landed. Three nampower rows and two code comments carried counts from before the cast-event and queue rounds: one of five `NP_Enable*` switches live (now three), twenty-two queue CVars stored only (now twenty), and the cast and buff/debuff event families listed as fired by nothing here. Rows are marked superseded rather than rewritten, per the doc's own convention — the earlier reason is why the later one is a decision. The two names still genuinely unfired from that row, `AUTO_ATTACK_*` and `SPELL_HEAL_*`, are named as combat-log producers, which is the block they actually belong with. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -1254,8 +1254,8 @@ pub(crate) const REGISTERED: &[Registered] = &[
|
||||
//
|
||||
// Unregistered, these were the six `unknown CVar '…' (not host-registered) — ignored` warnings
|
||||
// in the session log; registering them is only half the story, because **what an addon is
|
||||
// asking for here is an event stream, not a stored number**. So exactly one of the five is
|
||||
// live, and it is the one whose events this client can actually back:
|
||||
// asking for here is an event stream, not a stored number**. So a row goes live only when
|
||||
// this client can actually back its events — three of the five now can:
|
||||
ours(
|
||||
"NP_EnableAuraCastEvents",
|
||||
"0",
|
||||
@@ -1271,7 +1271,7 @@ pub(crate) const REGISTERED: &[Registered] = &[
|
||||
//
|
||||
// The remaining two name event classes nothing here emits. They are stored so the write
|
||||
// round-trips and `GetCVar` answers, and consumed by nothing — the same deliberate,
|
||||
// documented shape as the 22 stored-only queue rows above, and for the same reason: the
|
||||
// documented shape as the 20 stored-only queue rows above, and for the same reason: the
|
||||
// alternative is not "they work", it is the engine warning this task started from.
|
||||
//
|
||||
// What each would need, stated so the gap is a gap and not a mystery:
|
||||
|
||||
@@ -72,16 +72,16 @@ in this file on the strength of the namreeb research. pepo's v2 has its own
|
||||
| Cast-ready timing rule (namreeb's, and pepo's simplest case) | done | no Lua surface; `PendingCast::arm` in `crates/benilla-app/src/spell/inflight.rs` opens the guard from the spell's own known cast time at send, not a round trip through `SMSG_SPELL_START`; `SMSG_SPELL_DELAYED` pushback still extends it. This is the always-on version of what pepo's v2 makes configurable — see the stored-only row below for why that configurability is not wired |
|
||||
| `GetNampowerVersion()` | done | `script/compat/nampower.rs`, reporting `2.8.6`. The number is a claim about *surface*, not about benilla's code (same reasoning as `CLASSIC_API_VERSION`). `NampowerSettings` has exactly one version gate, `HasMinimumVersion(2, 8, 6)`, guarding exactly one setting: `NP_NameplateDistance` — which is also the one nampower CVar wired to real behaviour here. So 2.8.6 is the lowest version that still shows the only knob that genuinely works, and no higher: claiming more would assert the queue/buffer machinery of later releases (upstream documents through 4.5.0) that this client does not implement. The addon prints its own "update available" notice below its latest, which is accurate |
|
||||
| `NP_NameplateDistance` | **done, live** | the only `NP_*` row with a real engine reader. Drives both nameplate consumers — `nameplates.rs`'s `NameConfig::range_sq` (overhead names) and `vplates.rs`'s `VPlateMode::range_sq` (V-key plates) — i.e. the same knob SuperWoW's `NameplateRange` drives. **Two mods, one knob: last writer wins**, which is what a player moving either slider expects; neither is silently ignored. Each is clamped to the range its own mod documents: nampower 5..200 (the addon's own slider bounds in `settings.lua`), SuperWoW 10..80. Default `80` — upstream publishes *no* fixed default for this one ("Defaults to whatever was set by the game or vanilla tweaks"), so it keeps benilla's existing reach rather than inventing a number |
|
||||
| The other 22 `NP_*` CVars | **stored only, deliberately** | registered in `cvars.rs` with the mod's own documented defaults so the settings panel reads, writes and persists correctly — and consumed by nothing. benilla implements no spell-queueing system for them to tune: we carry namreeb's simpler always-on cast rule, not pepo's queue windows, dynamic latency buffer, retry and quickcast machinery. Storing them keeps the addon's UI truthful about what the player chose; claiming they change casting would be a lie the player would feel at the keyboard. They are listed in `cvars.rs`'s `LUA_ONLY` test table (whose rule is "a registered row needs a reader, or a named reason its reader is Lua") with that reason. The rows: the six `NP_Queue*` toggles, the four `*QueueWindowMs`, the four buffer knobs (`NP_MinBufferTimeMs`, `NP_MaxBufferIncreaseMs`, `NP_NonGcdBufferTimeMs`, `NP_OnSwingBufferCooldownMs`), `NP_ChannelLatencyReductionPercentage`, and the seven behaviour toggles (`NP_DoubleCastToEndChannelEarly`, `NP_InterruptChannelsOutsideQueueWindow`, `NP_OptimizeBufferUsingPacketTimings`, `NP_PreventRightClickTargetChange`, `NP_QuickcastTargetingSpells`, `NP_ReplaceMatchingNonGcdCategory`, `NP_RetryServerRejectedSpells`) |
|
||||
| The other 22 `NP_*` CVars | **superseded: 20 stored only, 2 live** | registered in `cvars.rs` with the mod's own documented defaults so the settings panel reads, writes and persists correctly — and consumed by nothing. benilla implements no spell-queueing system for them to tune: we carry namreeb's simpler always-on cast rule, not pepo's queue windows, dynamic latency buffer, retry and quickcast machinery. Storing them keeps the addon's UI truthful about what the player chose; claiming they change casting would be a lie the player would feel at the keyboard. They are listed in `cvars.rs`'s `LUA_ONLY` test table (whose rule is "a registered row needs a reader, or a named reason its reader is Lua") with that reason. The rows: the six `NP_Queue*` toggles, the four `*QueueWindowMs`, the four buffer knobs (`NP_MinBufferTimeMs`, `NP_MaxBufferIncreaseMs`, `NP_NonGcdBufferTimeMs`, `NP_OnSwingBufferCooldownMs`), `NP_ChannelLatencyReductionPercentage`, and the seven behaviour toggles (`NP_DoubleCastToEndChannelEarly`, `NP_InterruptChannelsOutsideQueueWindow`, `NP_OptimizeBufferUsingPacketTimings`, `NP_PreventRightClickTargetChange`, `NP_QuickcastTargetingSpells`, `NP_ReplaceMatchingNonGcdCategory`, `NP_RetryServerRejectedSpells`). **Superseded:** `NP_SpellQueueWindowMs` and `NP_QueueSpellsOnCooldown` are now LIVE — they are the explicit queue's own two knobs; see "The queue, and the one verb that needs it" |
|
||||
| pepo v2's wider surface beyond this addon | todo | upstream's README documents much more than `NampowerSettings` drives — later releases add `NP_SpamProtectionEnabled`, `NP_PreventMountingWhenBuffCapped`, the greater-demon autocast pair, `NP_PreventRightClickPvPAttack`, `NP_QuickcastOnDoubleCast`, and a family of events (`SPELL_START_SELF`/`_OTHER`, `AUTO_ATTACK_SELF`/`_OTHER`, `SPELL_HEAL_BY_SELF`, `AURA_CAST_ON_SELF`…). None is registered, because nothing installed asks for them; add them when an addon does, and raise `GetNampowerVersion` to match only then |
|
||||
| `GetNampowerVersion()` now reports **4.0.0** — and what the gate that opens actually reaches | **supersedes the `2.8.6` row above, which is now stale as a statement of the code** | `script/compat/nampower.rs`'s `NAMPOWER_VERSION` is `(4, 0, 0)`, set at the maintainer's explicit request; that file carries the full trade. The consequence this row exists to record: the number is not only read by `NampowerSettings`. **pfUI's `libs/libdebuff.lua:38-99` gates its entire debuff pipeline on `>= 3.0.0`** — below it the library prints "Debuff tracking disabled! Please update Nampower to v3.0.0 or higher" and raises `StaticPopup_Show("LIBDEBUFF_NAMPOWER_UPDATE")`, i.e. fails **loudly**. At `4.0.0` the gate passes, so the library enables five `NP_Enable*` CVars and registers `AURA_CAST_ON_SELF`/`_OTHER` and `DEBUFF_ADDED_OTHER`/`DEBUFF_REMOVED_OTHER` — which, before the rows below, were CVars that did not exist and events nothing fired. The version claim converted a loud failure into a silent one. The rows below are the other half of that claim being made good; `GetPlayerGuid`/`IsPlayerGuid` in the ClassicAPI section are the third half |
|
||||
| The five `NP_Enable*` event switches | **registered: one live, four stored only** | `cvars.rs`, all five at upstream's own documented `default 0` (`brues-code/nampower`'s `EVENTS.md` states it per row); names taken off the shipped `nampower.dll` (`strings` lists each beside its own "Set <name> to " line). pfUI's `libs/libdebuff.lua:56-88` writes all five at `PLAYER_LOGIN`. **`NP_EnableAuraCastEvents` is LIVE**: a `CvarChanged` observer moves `ui_cast_events.rs`'s `AuraCastFeed::enabled`, and off, the packet path queues nothing at all. `NP_EnableSpellStartEvents`, `NP_EnableSpellGoEvents`, `NP_EnableAutoAttackEvents` and `NP_EnableSpellHealEvents` are **stored only**, in `cvars.rs`'s `LUA_ONLY` table with that reason: benilla emits none of those event classes (see the `todo` row below for what each would need). Registering them is what stops the engine warning; it is *not* a claim that the stream arrived, and the chat line libdebuff prints ("Enabled 5 Nampower CVars") therefore over-reports by four. `NP_EnableSpellEnergizeEvents` and the `NP_EnableUnitEvents*` family exist upstream and are not registered — nothing installed writes them |
|
||||
| The five `NP_Enable*` event switches | **superseded: three live, two stored only** | `cvars.rs`, all five at upstream's own documented `default 0` (`brues-code/nampower`'s `EVENTS.md` states it per row); names taken off the shipped `nampower.dll` (`strings` lists each beside its own "Set <name> to " line). pfUI's `libs/libdebuff.lua:56-88` writes all five at `PLAYER_LOGIN`. **`NP_EnableAuraCastEvents` is LIVE**: a `CvarChanged` observer moves `ui_cast_events.rs`'s `AuraCastFeed::enabled`, and off, the packet path queues nothing at all. `NP_EnableSpellStartEvents`, `NP_EnableSpellGoEvents`, `NP_EnableAutoAttackEvents` and `NP_EnableSpellHealEvents` are **stored only**, in `cvars.rs`'s `LUA_ONLY` table with that reason: benilla emits none of those event classes (see the `todo` row below for what each would need). Registering them is what stops the engine warning; it is *not* a claim that the stream arrived, and the chat line libdebuff prints ("Enabled 5 Nampower CVars") therefore over-reports by four. `NP_EnableSpellEnergizeEvents` and the `NP_EnableUnitEvents*` family exist upstream and are not registered — nothing installed writes them . **Superseded by the rows below and by "The event table, accounted for":** `NP_EnableAuraCastEvents`, `NP_EnableSpellStartEvents` and `NP_EnableSpellGoEvents` are now LIVE, read by `NpCastGates` in `ui_cast_events.rs`; the two unit-event switches stay stored only because nothing produces those events yet |
|
||||
| `AURA_CAST_ON_SELF` / `AURA_CAST_ON_OTHER` | done, gated on `NP_EnableAuraCastEvents` | `crates/benilla-app/src/ui_cast_events.rs`'s `AuraCastFeed`: a second queue beside the `UNIT_CASTEVENT` one, pushed by `spell/net.rs`'s `on_spell_go` (where `Spell.dbc` is already in hand) and drained by the same VM-holding `drain_cast_edges`, behind the two cast families. Folded out of `SMSG_SPELL_GO`'s caster and **hit list** plus the spell's aura-applying effects: **one event per hit target per effect whose `EffectApplyAuraName` is nonzero**, which is upstream's own rule and the reason libdebuff dedupes inside 100 ms. The nine arguments are upstream's (`int spellId, string casterGuid, string targetGuid, int effect, int effectAuraName, int effectAmplitude, int effectMiscValue, int durationMs, int auraCapStatus`, matching the `%d%s%s%d%d%d%d%d%d` signal format in `nampower.dll`), and the shape was taken from the two live consumers' own destructures — `libs/libdebuff.lua:1105-1113` and `modules/innervatecall.lua:58-67`. **The SELF/OTHER split is by target, not caster.** GUIDs use benilla's own bare 16-hex spelling, as every other `compat/` GUID does. A ground-targeted AoE's GO carries no hit list and raises nothing: inventing the caster as the target would report Blizzard's area aura as landing on the player. `arg9` is computed from the target's `UNIT_FIELD_AURA` occupancy (bit 0 buff half full, bit 1 debuff half) |
|
||||
| `DEBUFF_ADDED_OTHER` / `DEBUFF_REMOVED_OTHER` | done, ungated (upstream gates neither) | `crates/benilla-app/src/ui_aura.rs`, inside the existing VM-holding `feed_auras` and after it has pushed the aura lists, so a handler that asks `C_UnitAuras` about the unit it was just told about cannot get a contradicting answer. A **delta on the `UNIT_FIELD_AURA` spell-id dwords**, driven off `net::FieldChanged` edges inside that 48-dword span — the same trigger `creature_anim::spell_visual`'s `arm_aura_state_fx` already uses — so a frame with no aura change does no work at all. First sight of a unit **seeds** the memory and fires nothing: an aura that was already on a mob we had never seen was not newly added, the descriptor keeps no caster for it, and a crowd would otherwise cost a burst of Lua dispatch on streaming in. Seven arguments, upstream's and identical across all eight buff/debuff events: `string guid, int luaSlot, int spellId, int stackCount, int auraLevel, int auraSlot, int state` — every column a field of the descriptor benilla already parses, `auraSlot` **0-based** as upstream reports it (pfUI adds 1 at `libdebuff.lua:1350`), `luaSlot` the `UnitDebuff` index through the same hidden-aura filter the aura lists use and `0` for a hidden aura, `state` 0 added / 1 removed. **Removals fire before adds** within one delta, because pfUI keys slot ownership on the raw slot and clears that key on removal (`libdebuff.lua:1507-1512`) — the other order would wipe the entry the add just wrote |
|
||||
| `durationMs` (`arg8`) for a combo-point or level-scaled `SpellDuration.dbc` row | todo | `ui_cast_events.rs`'s `aura_duration_ms` answers the row's `Duration[0]` when `Duration[1]` is 0, and **`0` otherwise** — including the permanent sentinel and a missing row. `0` is the consumer's own documented "absent" path. Reporting `Duration[0]` for a scaling row would quote 8 s for an 18 s five-point Rupture, and a debuff bar counting down to the wrong moment is worse than one that does not count down. What it would take: settling *which* input the row scales on (caster level vs combo points) per row, and reading the combo points as they stood at the cast rather than after the finisher consumed them. Upstream also promises "includes client modifiers if you are the caster": `spell/mods.rs` stores the server's `SPELLMOD_*` cells but has no duration reader, so this is the unmodified DBC length |
|
||||
| A stack-count change as a buff/debuff edge (`state` 2) | todo, deliberately | Upstream's legend has `2 = modified (stack change)` and its prose says the events fire "whenever a buff/buff **stack** … is added or removed", which reads as: a stack increase is an ADDED and a decrease a REMOVED, both with `state` 2. Not emitted here. Nothing in the corpus reads `arg7` at all; the watch span is the spell-id dwords alone, so a stack move inside a slot that keeps its spell is not an edge this sees; and under that reading a stack *decrease* would make pfUI clear a live debuff's slot ownership and its timer (`libdebuff.lua:1521-1540`), which is the wrong-timer failure this whole family exists to avoid. Costs nothing for the timers: a refresh's duration comes from `AURA_CAST`, which fires on every `SMSG_SPELL_GO`, and pfUI knows DEBUFF_ADDED does not fire on a refresh (`libdebuff.lua:1427`) |
|
||||
| `DEBUFF_ADDED_SELF` / `DEBUFF_REMOVED_SELF`, `BUFF_ADDED_*` / `BUFF_REMOVED_*` | todo | The other six of upstream's eight buff/debuff events, same seven arguments. The `*_SELF` pair is the player's own half of the delta `ui_aura.rs` already computes, and the `BUFF_*` pair the positive half of the slot range it already walks past, so all six are small additions to the same loop. Not built because nothing installed registers one: pfUI's libdebuff takes only the two `*_OTHER` names |
|
||||
| `SPELL_START_SELF`/`_OTHER`, `SPELL_GO_SELF`/`_OTHER`, `AUTO_ATTACK_*`, `SPELL_HEAL_*`, `SPELL_CAST_EVENT`, `SPELL_FAILED_OTHER` | todo — **registered by pfUI and fired by nothing here** | `libs/libdebuff.lua:863-869` registers all six families, and its `libdebuff_*_hooks` broadcast surface is what feeds `libs/libpredict.lua` (HoT send tracking), `modules/swingtimer.lua` and `modules/actionbar.lua`'s prowl hook. The start/go pair's packets are already folded into `ui_cast_events.rs`'s `CastEdge::Start`/`Cast`, so most of the data is in hand — but upstream's shapes want `itemId`, `castFlags`, `spellType` and `corpseOwnerGuid` columns this client does not carry, and those consumers key on arguments it would have to guess. `AUTO_ATTACK_*` needs a melee swing edge no path here raises at all (`CastEdge`'s own note). `SPELL_HEAL_*` needs `SMSG_SPELLHEALLOG`'s amount, which nothing reads. Guessing a column here is the same silent-failure shape the four rows above were written to avoid |
|
||||
| `DEBUFF_ADDED_SELF` / `DEBUFF_REMOVED_SELF`, `BUFF_ADDED_*` / `BUFF_REMOVED_*` | **superseded: six of eight built** | The other six of upstream's eight buff/debuff events, same seven arguments. The `*_SELF` pair is the player's own half of the delta `ui_aura.rs` already computes, and the `BUFF_*` pair the positive half of the slot range it already walks past, so all six are small additions to the same loop. Not built because nothing installed registers one: pfUI's libdebuff takes only the two `*_OTHER` names . **Superseded:** all six `*_SELF` names and the two `DEBUFF_*_OTHER` names fire from `ui_aura.rs`; only `BUFF_ADDED_OTHER`/`BUFF_REMOVED_OTHER` are left, and those stay out deliberately — see "The event table, accounted for" |
|
||||
| `SPELL_START_SELF`/`_OTHER`, `SPELL_GO_SELF`/`_OTHER`, `AUTO_ATTACK_*`, `SPELL_HEAL_*`, `SPELL_CAST_EVENT`, `SPELL_FAILED_OTHER` | **superseded: fired** | `libs/libdebuff.lua:863-869` registers all six families, and its `libdebuff_*_hooks` broadcast surface is what feeds `libs/libpredict.lua` (HoT send tracking), `modules/swingtimer.lua` and `modules/actionbar.lua`'s prowl hook. The start/go pair's packets are already folded into `ui_cast_events.rs`'s `CastEdge::Start`/`Cast`, so most of the data is in hand — but upstream's shapes want `itemId`, `castFlags`, `spellType` and `corpseOwnerGuid` columns this client does not carry, and those consumers key on arguments it would have to guess. `AUTO_ATTACK_*` needs a melee swing edge no path here raises at all (`CastEdge`'s own note). `SPELL_HEAL_*` needs `SMSG_SPELLHEALLOG`'s amount, which nothing reads. Guessing a column here is the same silent-failure shape the four rows above were written to avoid . **Superseded:** `SPELL_START_*`, `SPELL_GO_*`, `SPELL_FAILED_*`, `SPELL_DELAYED_SELF`, `SPELL_CHANNEL_START`/`_UPDATE` fire from `ui_cast_events.rs` and `SPELL_CAST_EVENT` from `ui_self_cast.rs`. Still unfired of this row: `AUTO_ATTACK_*` and `SPELL_HEAL_*`, which are combat-log producers, not cast-queue ones — they belong with the block in "The event table, accounted for" |
|
||||
|
||||
## UnitXP_SP3 — confirmed (open source, multiple mirrors)
|
||||
|
||||
@@ -955,8 +955,8 @@ from the consumer side — it destructures `arg2`=spellId, `arg3`=casterGuid, `a
|
||||
|
||||
| Bucket | Names |
|
||||
|---|---|
|
||||
| **Fired** | the aura eight — `BUFF_ADDED_SELF`, `BUFF_REMOVED_SELF`, `DEBUFF_ADDED_SELF`, `DEBUFF_REMOVED_SELF`, `DEBUFF_ADDED_OTHER`, `DEBUFF_REMOVED_OTHER`, `AURA_CAST_ON_SELF`, `AURA_CAST_ON_OTHER` (`ui_aura.rs`, `ui_cast_events.rs`) — the cast ten: `SPELL_START_SELF`/`_OTHER`, `SPELL_GO_SELF`/`_OTHER`, `SPELL_FAILED_SELF`/`_OTHER`, `SPELL_DELAYED_SELF`, `SPELL_CHANNEL_START`, `SPELL_CHANNEL_UPDATE` (`ui_cast_events.rs`), and `SPELL_CAST_EVENT` (`ui_self_cast.rs`) |
|
||||
| **Deliberately absent** | `BUFF_ADDED_OTHER`/`BUFF_REMOVED_OTHER` — diffing the helpful half of every streamed unit, which nothing registers (the `AuraEdge` doc says so at the enum); `SPELL_QUEUE_EVENT` — the queue; `SPELL_DELAYED_OTHER` — upstream's own note is that the server only sends the packet to the affected player, so it never fires there either |
|
||||
| **Fired** | the aura eight — `BUFF_ADDED_SELF`, `BUFF_REMOVED_SELF`, `DEBUFF_ADDED_SELF`, `DEBUFF_REMOVED_SELF`, `DEBUFF_ADDED_OTHER`, `DEBUFF_REMOVED_OTHER`, `AURA_CAST_ON_SELF`, `AURA_CAST_ON_OTHER` (`ui_aura.rs`, `ui_cast_events.rs`) — the cast ten: `SPELL_START_SELF`/`_OTHER`, `SPELL_GO_SELF`/`_OTHER`, `SPELL_FAILED_SELF`/`_OTHER`, `SPELL_DELAYED_SELF`, `SPELL_CHANNEL_START`, `SPELL_CHANNEL_UPDATE` (`ui_cast_events.rs`), `SPELL_CAST_EVENT` (`ui_self_cast.rs`), and `SPELL_QUEUE_EVENT` (`ui_spellbook.rs`, off `spell/queue.rs`'s own rows — every mutation of the queue goes through `queue`/`pop`, so a code cannot be dropped by a caller that forgets to emit one) |
|
||||
| **Deliberately absent** | `BUFF_ADDED_OTHER`/`BUFF_REMOVED_OTHER` — diffing the helpful half of every streamed unit, which nothing registers (the `AuraEdge` doc says so at the enum); `SPELL_DELAYED_OTHER` — upstream's own note is that the server only sends the packet to the affected player, so it never fires there either |
|
||||
|
||||
| **To fire, needs its own producer** | `UNIT_DIED`, the thirteen `UNIT_*_GUID`/`PLAYER_GUILD_UPDATE_GUID` rows (one shape: `guid, isPlayer, isTarget, isMouseover, isPet, partyIndex, raidIndex`, gated by the `NP_EnableUnitEvents*` CVars already registered), `UNIT_COMBAT_GUID`, `SPELL_DAMAGE_EVENT_SELF`/`_OTHER`, `SPELL_HEAL_BY_SELF`/`_BY_OTHER`/`_ON_SELF`, `SPELL_ENERGIZE_*`, `SPELL_MISS_SELF`/`_OTHER`, `SPELL_DISPEL_BY_*`, `DAMAGE_SHIELD_*`, `ENVIRONMENTAL_DMG_*`, `AUTO_ATTACK_SELF`/`_OTHER`, `BUFF_UPDATE_DURATION_SELF`, `DEBUFF_UPDATE_DURATION_SELF`, `KEY_DOWN`/`KEY_UP` |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user