From 9bdeb73fa7e39ce01e04091d5d4f60d3defed5fb Mon Sep 17 00:00:00 2001 From: Josh Creek <8179928+jcreek@users.noreply.github.com> Date: Wed, 5 Aug 2026 09:18:08 +0100 Subject: [PATCH] docs: mark trained-bot compatibility items resolved in TODO.md Records the drag/aperture/collider-bake/beyond-1v1 items as done, with a short note on what actually shipped (scoped up to 5v5 mid-implementation) and the explicit non-goals (no 2v2+ curriculum, no team-size UI) so it's clear what's still open. --- TODO.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index c10eb588..2ac31eaa 100644 --- a/TODO.md +++ b/TODO.md @@ -14,13 +14,13 @@ The training pipeline is built — see `TRAINING.md` (self-play PPO via the vend Bugs found in an adversarial review. None are gameplay- or physics-affecting, so all are safe to land against the current `Game/bots/` checkpoints. -- [ ] Goal scoring volume (3.5 x 1.5, `objects/goal.tscn`) is smaller than the drawn mouth (3.7 x 1.65, `ArenaBoundary.GOAL_APERTURE_*`) — a ball crossing the visible edge doesn't score. Derive the aperture constants from the goal's collision shape, the way `goal.gd:53` already measures its own visuals. +- [x] ~~Goal scoring volume (3.5 x 1.5, `objects/goal.tscn`) is smaller than the drawn mouth (3.7 x 1.65, `ArenaBoundary.GOAL_APERTURE_*`) — a ball crossing the visible edge doesn't score.~~ Fixed: `GOAL_APERTURE_HALF_WIDTH`/`HEIGHT` now match the sensor exactly (1.75/1.5). - [ ] Delete the duplicate 1 MB texture — `assets/textures/planet_surface.png` and `assets/models/nebula_planet_planet_surface.png` are byte-identical. ## Performance - [ ] Measure `nebula_dust.gdshader`'s per-fragment depth-texture sample across 500 large soft billboards before adding more particle work. -- [ ] Bake `ArenaBoundary`'s ~160 runtime-generated `CollisionShape3D` nodes into the scene. Costs a load hitch on every arena entry and repeats in every parallel headless training env. **Blocked on the trained-bot decision below** — `arena_boundary.gd:235` notes this geometry is what the shipped policies were fitted against, so the bake must be verified byte-identical. +- [x] ~~Bake `ArenaBoundary`'s ~160 runtime-generated `CollisionShape3D` nodes into the scene.~~ Done: `ArenaBoundary.bake_colliders()` + `Game/tools/bake_arena_boundary.gd` (re-run after any future geometry change). `_ready()` self-heals — skips regenerating when a bake already matches the current `goal_mode`, regenerates at runtime otherwise (e.g. the `_elevated` arena variants, not yet baked). ## Presentation / AAA polish @@ -37,14 +37,14 @@ The largest gap between this and a AAA-feeling product is presentation, not code - [ ] Custom font + a real `Theme` resource for the HUD. The procedural instruments are well-engineered, but `ThemeDB.fallback_font` at 10-13 px reads as a debug overlay. - [ ] Post-processing beyond glow: DoF, motion blur, vignette, chromatic aberration on turbo. -## Open decision — trained-bot compatibility +## Resolved — trained-bot compatibility (2026-08-05 retrain-from-scratch reset) -Four items collide with the checkpoints in `Game/bots/`. Decide the policy before scheduling any of them; everything in Correctness and DRY above is safe either way. +The four items below all took their architecturally-correct form instead of their zero-risk form, since `Game/bots/promoted/*.json` are being retrained from scratch anyway (those two checkpoints are left in place and are expected to go stale, not migrated). Scoped up further mid-implementation to a genuine 5v5 ceiling with a proportionally resized arena, since the observation-space plumbing is the expensive part to redo twice. -- [ ] **Per-tick drag** (`ship.gd`): `state.linear_velocity *= drag_coefficient` and `angular_velocity *= 0.9` aren't delta-scaled, and `project.godot` never pins `physics/common/physics_ticks_per_second`. Correct at 60 Hz, silently different at any other rate. Zero-risk option: pin the tick rate to 60 and document the dependency. Correct-but-breaking option: delta-scale it and retrain. -- [ ] **Goal aperture** — cutting a real opening in the end walls so the ball visibly enters the net changes collision geometry the policies were fitted against. Today the walls are solid and the pocket/net are unreachable decoration. -- [ ] **Collider bake** (see Performance above) — safe only if byte-identical to the current generated output. -- [ ] **Beyond 1v1** — `ai_ship_controller.gd` takes the first non-self ship as "the opponent" and `ship_observations.gd` has room for exactly one. The observation space is the hardest thing to change later, so decide whether 2v2/3v3 is in scope before more training time is spent. +- [x] **Per-tick drag** (`ship.gd`) — delta-scaled via `_tick_scaled(k, state.step)`, invariant to `physics_ticks_per_second`. +- [x] **Goal aperture** — real navigable hole cut into each end wall's collision (`ArenaBoundary._build_end_wall_colliders`), sized to the actual scoring sensor and correct for both FLOOR and ELEVATED goal modes. +- [x] **Collider bake** — done alongside the geometry changes above (see Performance). +- [x] **Beyond 1v1** — `ShipObservations` now takes padded teammate/opponent arrays (`MAX_TEAMMATES=4`, `MAX_OPPONENTS=5`, `SIZE=83`), ordered by a new persistent `Ship.spawn_index` so slots never reorder mid-match. `training_mode.gd`/`match_mode.gd` gained a `team_size` export (default 1, so existing 1v1 behaviour is unchanged) and the arena was resized 1.5x to fit 5v5. This pass is plumbing only: no 2v2+ curriculum, no team-play reward design, and no match-mode UI to pick team size — those are still open work. ## Multiplayer (long term)