Audited the whole set rather than appending to it, and the two files a fresh session reads first were both wrong. README claimed the emergency escape takes three seconds and is CANCELLED BY DAMAGE. It takes one, and damage explicitly does not interrupt it -- that is a settled decision with its own entry in DECISIONS.md, and the front page said the opposite. It also described one stationary boss, one hub portal, and none of characters, permadeath, levels, inventory, loot, upgrades, settings or credits. Rewritten, with the "not ready for the internet" warning made explicit. ROADMAP had no "what is next" at all: every stage reads *done*, which for a cold start is a dead end. It opens with where things stand and a table of candidates -- auth, a reason to play past level 15, an economy, hit feedback, replacing the non-redistributable packs, DTLS -- each with what blocks it, and says plainly that the user has chosen none of them. Open questions renumbered from the orphaned 8-11 they were left at, with the solved one dropped and three real ones added. ARCHITECTURE's file map listed two files twice, missed five subsystems (upgrades, stats, poison, settings, credits, the UI theme), and still said MapGen.build() is "the entry point both sides use" -- it is server-only, and the whole anti-map-hack story depends on that. Rebuilt by layer and audited against the tree: every path listed exists, and every one of the 64 source files is covered. CLAUDE.md's security paragraph said a client can send "exactly two things" plus two roster requests. There are five client -> server messages. That number is the security model, so it is now a table naming each one and what it carries. Also records that nothing automated can see the screen. Smaller: a stale 156/156 test count in ASSETS.md, and test counts refreshed to 468 where they are quoted. check.sh clean, 468 tests, SMOKE PASS, all four diagnostics green, no broken internal links. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+78
-16
@@ -62,15 +62,24 @@ travel less than one tile per tick or the point test steps over walls (pinned by
|
||||
|
||||
## Where the layers sit now
|
||||
|
||||
Stage 1 and 2 added two things worth knowing before reading any file:
|
||||
Four things are worth knowing before reading any file:
|
||||
|
||||
- **Geometry is per-world.** There is no global arena. `SimWorld.map` is a
|
||||
[MapGrid](../src/sim/map_grid.gd); the hub and every dungeon have their own,
|
||||
and the client holds a *partial* copy streamed to it in chunks.
|
||||
- **`src/meta/` is server-only.** Accounts, characters, levels and experience
|
||||
live there. The simulation reads a player's level and maximum health; it never
|
||||
writes progression. One writer means a level cannot disagree with the
|
||||
- **`src/meta/` is server-only.** Accounts, characters, levels, experience,
|
||||
inventories and upgrades live there. The simulation reads a player's level and
|
||||
maximum health and moves items between the ground and a bag; it never writes
|
||||
progression or touches the store. It announces what happened and
|
||||
`ServerRuntime` banks it. One writer means a level cannot disagree with the
|
||||
experience that earned it.
|
||||
- **Derived, never stored.** Level comes from lifetime experience; combat
|
||||
numbers come from the upgrade list ([PlayerStats](../src/sim/player_stats.gd));
|
||||
maximum health comes from the level and the upgrades. Nothing that can be
|
||||
recomputed is persisted, so nothing saved can disagree with what produced it.
|
||||
- **`src/core/settings.gd` is the exception to "shared".** Everything else in
|
||||
`src/core/` is agreed by both sides; settings are the player's own machine
|
||||
and never reach the server.
|
||||
|
||||
## Tick
|
||||
|
||||
@@ -96,6 +105,13 @@ BossDef = stats + ordered phases
|
||||
`SimWorld._run_emitters()` is shared by enemies and bosses, so any pattern can
|
||||
be dropped on either. A boss is four phases layering one idea at a time; a new
|
||||
boss is a new function in `src/content/content.gd` and zero simulation changes.
|
||||
`SimWorld._move_boss()` is the same idea for movement: the mode is a field on
|
||||
the phase, and adding a boss that walks needs no code.
|
||||
|
||||
Emitters are **stateless**. They are shared resources — two bosses of the same
|
||||
kind would otherwise stomp each other's timers — so anything an emitter needs to
|
||||
remember between two ticks has to be derived instead. `TelegraphedStrikeEmitter`
|
||||
computes its strike positions from the volley number for exactly this reason.
|
||||
|
||||
## Entry point
|
||||
|
||||
@@ -108,30 +124,76 @@ after `--`:
|
||||
|
||||
## File map
|
||||
|
||||
Grouped by layer. The rule the whole thing hangs on: **`src/sim/` imports
|
||||
nothing from `net`, `view` or `ui`, and never touches `Net`.**
|
||||
|
||||
### Shared constants and helpers
|
||||
|
||||
| File | Role |
|
||||
| --- | --- |
|
||||
| `src/core/sim_config.gd` | Every constant server and client must agree on. |
|
||||
| `src/core/movement.gd` | Pure movement + overlap helpers. Shared by prediction. |
|
||||
| `src/core/game_log.gd`, `game_opts.gd` | Static; usable from tools and tests. |
|
||||
| `src/sim/sim_world.gd` | The simulation. Authority flag decides what runs. |
|
||||
| `src/core/settings.gd` | Client-local preferences. Never reaches the server. |
|
||||
| `src/core/credits.gd` | Third-party assets and their licences. Two are CC BY, so this is a legal requirement. |
|
||||
|
||||
### The simulation
|
||||
|
||||
| File | Role |
|
||||
| --- | --- |
|
||||
| `src/sim/sim_world.gd` | The simulation. The authority flag decides what runs. |
|
||||
| `src/sim/bullet_pool.gd` | Struct-of-arrays bullet storage and integration. |
|
||||
| `src/sim/input_frame.gd` | The only thing a client may assert about itself. |
|
||||
| `src/net/net_codec.gd` | Snapshot / event / input binary codecs. |
|
||||
| `src/net/server_runtime.gd` | Instances, ticking, transfers, broadcast. |
|
||||
| `src/net/client_runtime.gd` | Prediction, reconciliation, interpolation, bot input. |
|
||||
| `src/instances/instance.gd` | Lobby hub and dungeon progression. |
|
||||
| `src/autoload/net.gd` | ENet lifecycle, RPCs, local loopback for listen servers. |
|
||||
| `src/sim/player_stats.gd` | Combat numbers derived from a character's upgrades. |
|
||||
| `src/sim/poison_track.gd` | Damage over time. O(1) per actor per tick however many doses. |
|
||||
| `src/sim/sim_loot.gd` | An item on the ground: world-shared, or owned by one peer. |
|
||||
| `src/sim/sim_portal.gd` | A dungeon entrance, and which dungeon it opens. |
|
||||
| `src/sim/map_grid.gd` | Tile grid: collision, line of sight, chunked streaming. |
|
||||
| `src/sim/map_gen.gd` | Dungeon generation. `build()` is the only entry point both sides use. |
|
||||
| `src/content/rooms.gd` | Hand-authored stamps: the hub and each boss arena, as text. |
|
||||
| `src/sim/map_gen.gd` | Dungeon generation. **Server-side only** — the client is never given the seed. |
|
||||
| `src/sim/patterns/` | Bullet emitters. Stateless; the authoring surface for every fight. |
|
||||
|
||||
### Content (data, in code)
|
||||
|
||||
| File | Role |
|
||||
| --- | --- |
|
||||
| `src/content/content.gd` | Every enemy and boss. `ALL_ENEMIES` / `ALL_BOSSES` are what the tools and tests iterate. |
|
||||
| `src/content/items.gd` | Every item. `Items.ORDER` doubles as the wire format. |
|
||||
| `src/sim/sim_loot.gd` | An item on the ground. World-shared, or owned by one peer. |
|
||||
| `src/content/upgrades.gd` | The seven upgrades and their draw weights. |
|
||||
| `src/content/dungeons.gd` | The kinds of run. `ORDER` is a wire format *and* the hub's portal order. |
|
||||
| `src/content/rooms.gd` | Hand-authored stamps: the hub and each boss arena, as text. |
|
||||
| `src/actors/` | The `Resource` definitions those tables build: enemy, boss, item, loot, upgrade, dungeon. |
|
||||
|
||||
### Server-owned state
|
||||
|
||||
| File | Role |
|
||||
| --- | --- |
|
||||
| `src/meta/progression.gd` | XP curve and what a level is worth. Pure functions. |
|
||||
| `src/meta/character.gd`, `character_store.gd` | Characters and their JSON persistence. Server-owned. |
|
||||
| `src/meta/character.gd`, `character_store.gd` | Characters and their JSON persistence. |
|
||||
| `src/meta/auth_provider.gd` | Identity, shaped like Steamworks so it swaps out. |
|
||||
| `src/net/net_codec.gd` | Snapshot / event / input / roster / character / map-chunk codecs. |
|
||||
| `src/net/server_runtime.gd` | Instances, ticking, transfers, interest, progression, map streaming. |
|
||||
| `src/instances/instance.gd` | The hub and one dungeon run: a world plus a peer list. |
|
||||
|
||||
### Network
|
||||
|
||||
| File | Role |
|
||||
| --- | --- |
|
||||
| `src/net/net_codec.gd` | Every binary codec: snapshot, events, input, roster, characters, map chunks, portals, upgrade state. |
|
||||
| `src/net/server_runtime.gd` | Instances, ticking, transfers, interest, progression, persistence, map streaming. |
|
||||
| `src/net/client_runtime.gd` | Prediction, reconciliation, interpolation, bot input. |
|
||||
| `src/net/protocol.gd` | Wire version and constants. Bump `VERSION` whenever a layout changes. |
|
||||
| `src/autoload/net.gd` | ENet lifecycle, RPCs, local loopback for listen servers. The only autoload. |
|
||||
|
||||
### View and UI (read-only; decides nothing)
|
||||
|
||||
| File | Role |
|
||||
| --- | --- |
|
||||
| `src/view/world_view.gd` | Everything that is not a bullet. Fog, actors, loot, telegraphs. |
|
||||
| `src/view/bullet_renderer.gd` | The bullet field: one MultiMesh per bullet kind. |
|
||||
| `src/view/art.gd` | Every atlas rect and sound path, in one table. |
|
||||
| `src/view/ui_theme.gd` | The control theme, built in code from the UI pack. |
|
||||
| `src/view/debug_draw.gd` | F1 overlay: what the simulation collides against. |
|
||||
| `src/view/game_scene.gd`, `sfx.gd` | Wiring the view to whatever client `Net` currently has. |
|
||||
| `src/ui/hud.gd` | Bars, inventory, prompts. Drawn, not built from controls. |
|
||||
| `src/ui/main_menu.gd`, `game_menu.gd` | Connect screen and the in-game menu. |
|
||||
| `src/ui/character_select.gd` | Roster screen: pick or create. |
|
||||
| `src/ui/upgrade_screen.gd` | The quartermaster's three choices, and what you hold. |
|
||||
| `src/ui/settings_screen.gd`, `credits_screen.gd` | Controls, volumes, attribution. |
|
||||
|
||||
Reference in New Issue
Block a user