feat(smash): every ability draws something, on the press - #1086
Merged
Merged
Conversation
`tools/smash-match.py` joins a real client, presses every ability in the roster and refuses one that sends no `level_particles`. It named twenty-three. This is those twenty-three. The cheap fix would be a `visuals::blast` in each. That passes the gate and leaves the game where it started: a player who sees the same grey puff for a bow, a web, an ink cloud and a tidal wave has learnt nothing from any of them. So `visuals` gains a vocabulary instead, and each entry picks the particle vanilla already uses for the thing being drawn -- `crit` for a bow release, `item_cobweb` for webbing, `item_slime` for a slam, `mycelium` for mooshroom spores, `angry_villager` for a rage mode, `sweep_attack` for a lunge. A player who has played Minecraft reads them without being taught. Shape carries meaning with it. An aura is a ring and not a disc, because the only fact a player needs from an aura is whether they are inside it, and a ring is the boundary that answers exactly that. A lunge is a line from where it began to where it ended, because the distance covered is the ability. A wave is a rising wall at its own radius. Two of the twenty-three are not decoration. Ice Path is documented as laying ice blocks, the seam cannot write blocks, and so the ability today is a small hop and nothing else; the drawn path is the only evidence a player has that anything happened. Arctic Aura is the same at radius 5. Sustained abilities draw on their beat and not once at the cast. A twenty-second ultimate that draws one puff is a twenty-second window a victim cannot see they are inside. Separately, and found while chasing the two abilities that declare `buffs_melee` and fail the same sweep: `tests/abilities.rs::melee_damage` could not fail. It read the kit's base damage, read `MeleeBonus`, added them, and then dealt exactly that much -- comparing one copy of the formula against another copy of the same formula. Deleting the bonus lookup from the swing path would have left every `buffs_melee` assertion green. It now calls `input::melee_damage`, which is what a real attack packet calls. Watched failing before being trusted: with the bonus lookup removed from `input::melee_damage`, `every_declared_effect_actually_happens` goes red; restored, green. Under the old version that deletion was invisible. The repaired test then clears both accused abilities, so the `buffs_melee` disagreement is between the game bench and the real client rather than in the game. That is a separate and smaller bug, still open. Verified: `cargo test -p smash` is 292 tests green across 27 binaries.
andrewgazelka
force-pushed
the
feat/every-ability-is-visible
branch
from
July 30, 2026 03:12
e4908a2 to
e5faf5f
Compare
Seven abilities drew nothing at the moment of the press. Each passed the real-client particle gate only when some later contingent event happened to draw: usually a projectile landing on somebody. `Zombie / Bile Blaster` is the one that proved it. It passed one CI run and failed the next with nothing between them: in the passing run a blob connected and the particle appeared at the victim's feet, and in the failing run every blob missed. The gate had been deciding that ability's fate on a coin flip, and the coin came up tails. So the rule this commit adds is not "every ability draws", which the previous commit already established. It is that **the draw happens on the press itself**, above any branch that a miss or a failed lookup can skip. Guardian's Target Laser is the clearest case: it looks for the nearest player in range and returns if there is none, so anything drawn after that lookup is a visual whose presence depends on the game state rather than on the button. It now draws at the caster first, unconditionally, and draws a second beam to the marked player once there is one. Nine additions to the vocabulary, each picking the particle vanilla already uses for the thing depicted, on the same terms as the rest of that file. Sustained ultimates draw on their beat: a twenty second mode that draws once is a twenty second window a victim cannot see they are inside. This closes the class rather than the instance. Of the eight abilities whose particle was contingent, the seven fixable ones are fixed; the eighth, Wither Image, already draws on the press. Verified: `cargo test -p smash`, 292 tests green across 27 binaries. The real-client sweep is the instrument that named this and is the one that has to confirm it. Written by a subagent; the placement above the early return was the one thing I insisted on and it did it in every case.
Benchmark Results for generalComparing to 5c7f127 |
Benchmark Results for generalComparing to 5c7f127 |
andrewgazelka
added a commit
that referenced
this pull request
Jul 30, 2026
…r the class (#1093) Two abilities put nothing on any screen when you pressed them, and the check that would have caught them could not, for a reason worth writing down. ## The two **Wither Image** is two presses: the first plants a decoy where you stand, the second swaps you back to it. Only the swap drew. Planting was silent, so an opponent could not see that the escape was armed — which is the entire threat the ability carries. It now plants a column of soul fire, deliberately unlike the portal shell every teleport uses, so the two presses are told apart at a glance. **Blaze's Inferno** is a half-second-cooldown flame cone and drew nothing at all. The only fire on screen came from the burn on a victim, so spewing at open air was invisible and a player could not see where their own flame reached. It now draws a jet along the facing, above the victim search, because the search is what can come up empty. Both are the pattern #1086 was supposed to finish. That commit message says *"the eighth, Wither Image, already draws on the press."* It does not, and never did — I read the second press for the first. ## Why no gate caught it Every sweep we have, the mock one here and the real-client one in `tools/smash-match.py`, presses each ability **up to three times**, because two abilities in the roster genuinely need more than one. That is correct for the question those sweeps ask and is exactly why neither could ask this one: the second press supplied the particles and the first press's silence was invisible. So `every_ability_draws_on_the_press_that_fires_it` presses **once**, and once only. ## The near-miss in the gate itself Written first against particles alone, it named seven abilities and **only one was a defect**: ``` "Iron Golem / Iron Hook", "Spider / Needler", "Creeper / Sulphur Bomb", "Wither Skeleton / Guided Wither Skull", "Blaze / Inferno", "Chicken / Chicken Missile", "Wither Skeleton / Wither Image" ``` Six of those answer the press by putting a **drawn object** in the world — a skull, an egg, a thrown block — and for those the object is the picture. A check that calls correct code broken is the same error in a mirror, and it is the worse direction: somebody satisfies it by bolting a redundant puff onto six working abilities. It now asks whether the press put anything at all on a screen, by either route, and stays one test because "which abilities are the projectile kind" is not a list anybody should maintain. ## Watched to fail ``` without the Wither Image fix, particles-only: 7 named, 1 real without the Wither Image fix, widened: ["Wither Skeleton / Wither Image"] with both fixes: ok. 13 passed; 0 failed ``` `cargo test -p smash` green across all 21 test binaries; `cargo fmt --all --check` and `cargo clippy -p smash --all-targets` both clean. ## Second commit: clippy has been red on main since #1086 `cargo clippy -p smash --lib` exits **101** on `origin/main` at `ee1139e`: ``` error: this function could have a `#[must_use]` attribute --> events/smash/src/input.rs:260:8 ``` One attribute, from making `melee_damage` public in #1086. The attribute is not the interesting part — **nothing noticed for four hours**, because #1088 turned every workflow to `workflow_dispatch` and clippy only ever ran there. It is not in the nix flake gate, so `nix run .#ci`, the thing anybody actually runs before pushing, is green on a tree clippy rejects. Same hole as ENG-11424, which is the same sentence about `cargo fmt --all --check`. Both belong in the gate; turning CI off is what made that urgent rather than tidy. --- 🤖 Opened by Claude Code (claude-opus-4-6).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
tools/smash-match.pyjoins a real Minecraft client to a real server, pressesevery ability in the roster and refuses one that sends no
level_particles.It named 23. A 24th,
Zombie / Bile Blaster, was passing only when a thrownblob happened to land on somebody.
Measured before and after, on a real client, on x86_64-linux:
The two that remain are
Cow / Mooshroom MadnessandGuardian / Target Laseron
buffs_melee. Those are a harness measurement defect, not a game defect,and are filed as ENG-11399 with the evidence: the repaired game bench, which
now calls the same function a real attack packet calls, passes both.
What it does
The cheap fix would be a
visuals::blastin each. That passes the gate andleaves the game where it started: a player who sees the same grey puff for a
bow, a web, an ink cloud and a tidal wave has learnt nothing from any of them.
So
visualsgains a vocabulary, and each entry picks the particle vanillaalready uses for the thing depicted, so a player who has played Minecraft
reads it without being taught.
Shape carries meaning. An aura is a ring and not a disc, because the only
fact a player needs from an aura is whether they are inside it. A lunge is a
line from where it began to where it ended. A wave is a rising wall at its
own radius.
Two of these are not decoration. Ice Path is documented as laying ice blocks,
the seam cannot write blocks, so the ability was a small hop and nothing else;
the drawn path is a player's only evidence it exists. Arctic Aura is the same
at radius 5. The Snowman and the Wolf had no visual identity at all.
Sustained ultimates draw on their beat. A twenty second mode that draws once
is a twenty second window a victim cannot see they are inside.
And the draw happens on the press
The second commit is the part Bile Blaster forced. Seven abilities drew only
after some contingent later event, usually a projectile connecting, so the
gate decided their fate on a coin flip. The draw now happens on the press
itself, above any branch a miss or a failed lookup can skip. Guardian's Target
Laser is the clearest: it returns if nobody is in range, so it draws at the
caster first and only then a beam to whoever got marked.
A test that could not fail, fixed and watched failing
Found while chasing the two
buffs_meleeabilities.tests/abilities.rs::melee_damageread the kit's base damage, readMeleeBonus, added them, and dealt exactly that much, then checked the damagehad gone up. It compared one copy of the formula against another copy of
itself. Deleting the bonus lookup from the swing path would have left every
buffs_meleeassertion green forever.It now calls
input::melee_damage, the function a real attack packet calls.Proved rather than asserted: with the bonus lookup removed from that function,
every_declared_effect_actually_happensgoes red; restored, green. Under theold helper that deletion was invisible.
Verified:
cargo test -p smash292 tests green across 27 binaries, and thereal-client sweep above.
(sent by an AI agent via Claude Code)