The jitter had two causes, and the larger one is embarrassing: boss_state() handed back the newest snapshot raw while players and enemies both went through the interpolator. The boss therefore stepped at the 20Hz snapshot rate instead of the frame rate. Invisible for as long as every boss stood still, and the first one that moved looked broken. It is interpolated now -- but not across an instance change, where the previous snapshot describes a different fight in a different room and lerping to it would fling the new boss across the map for a frame. The smaller cause was server-side: a CHASE boss corrects by the SIGN of its distance error, so at the standoff the sign flipped every tick and the boss vibrated a couple of pixels at 60Hz. It has a dead band now. The settings screen covers rebindable controls and volume, reachable from both the main menu and the in-game menu. Bindings are stored as physical keycodes -- following key position, the choice setup_input_map.gd already made -- and labelled back through the active layout so an AZERTY player reads the letter on the key their fingers are on. A rebind replaces every event on the action rather than the first, because an action that kept its alternates would still answer to the key you just moved away from. A key already in use is refused and the clash is named. Reset restores what the PROJECT shipped, captured once before anything overrides it -- captured later it would restore the last session's choice, which is the thing being undone. Effects play on an SFX bus created at runtime, so both sliders are real mixer settings rather than a number multiplied into every play() call. Worth recording: the test suite AND the smoke test both passed while a client logged twelve engine errors on every startup. ConfigFile.get_value(s, k, null) does not mean "no default" -- it means the key is absent and no default was given, and the engine logs an error per action. Nothing caught it because the smoke refutations matched SCRIPT ERROR and friends, and a plain ERROR: is none of those. It surfaced from running the client and reading the output. smoke.sh now asserts no plain engine errors either, excluding by name the one line Godot prints on every clean exit, and reintroducing the bug makes it fail. One mutation caught nothing and should not have: the early return in linear_to_db_clamped was dead code, since the clamp beneath it already prevents negative infinity. Removed rather than left looking tested. check.sh clean, 439 tests, SMOKE PASS (23 assertions), all four diagnostics green, and a real client boots with zero engine errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+9
-3
@@ -20,8 +20,8 @@ What "everything passes" currently means. Numbers move; the shape does not.
|
||||
| Gate | Covers | Runtime |
|
||||
| --- | --- | --- |
|
||||
| `tools/check.sh` | every script parses and type-checks | ~5s |
|
||||
| `tools/test.sh` | 414 GUT tests, no SceneTree | ~4s |
|
||||
| `tools/smoke.sh` | 22 assertions over a real ENet socket: handshake, auth, character creation and persistence, both dungeon kinds, escape, hard kill, polite disconnect | ~40s |
|
||||
| `tools/test.sh` | 439 GUT tests, no SceneTree | ~4s |
|
||||
| `tools/smoke.sh` | 23 assertions over a real ENet socket: handshake, auth, character creation and persistence, both dungeon kinds, escape, hard kill, polite disconnect | ~40s |
|
||||
| `diag_prediction.tscn` | client-prediction gap, with injected clock drift | ~10s |
|
||||
| `diag_progression.tscn` | kill → xp → level → health, death → retire → roster, swap guards | ~10s |
|
||||
| `diag_loot.tscn` | drop → snapshot → pick up → persist → use → drop, and both loot visibilities on the wire | ~10s |
|
||||
@@ -128,7 +128,8 @@ play off server events. Enough to prove the pipeline, not a finished look.
|
||||
| Rects validated without a display | done | `tests/unit/test_art.gd` |
|
||||
| Impact/death VFX animation | todo | `Art.IMPACT` is loaded and validated but nothing plays it yet |
|
||||
| Directional sprites, hit flashes, screen shake | todo | |
|
||||
| Audio buses and a volume setting | todo | Everything plays on Master at hardcoded dB |
|
||||
| Rebindable controls | done | [src/ui/settings_screen.gd](../src/ui/settings_screen.gd), [src/core/settings.gd](../src/core/settings.gd) |
|
||||
| Audio buses and a volume setting | done | `Settings`, an SFX bus created at runtime, sliders in the settings screen |
|
||||
| **In-game credits screen** | **todo** | Not cosmetic: the SFX are CC BY 4.0 and attribution is a licence *requirement*. [CREDITS.md](../CREDITS.md) is not reachable by a player. |
|
||||
| Replace the two non-redistributable packs | todo | Bullet and FX art is local-only and non-commercial. CC0 replacements would let them into the repo and unblock a commercial release. See [ASSETS.md](ASSETS.md). |
|
||||
|
||||
@@ -391,6 +392,11 @@ had already gone stale and silently stopped writing the second boss.
|
||||
|
||||
### Known gaps
|
||||
|
||||
- **Nothing tests how the fight *looks*.** The boss was drawn straight from the
|
||||
newest snapshot with no interpolation — a visible step at 20 Hz — and every
|
||||
test passed for as long as bosses stood still. There is still no automated
|
||||
check that a moving actor renders smoothly; the ones added cover the
|
||||
interpolation call, not the impression.
|
||||
- **No boss-specific music, intro or death sequence.** A boss dies like an
|
||||
enemy, only louder.
|
||||
- **Telegraph markers are one shape.** A circle is the only warning the client
|
||||
|
||||
Reference in New Issue
Block a user