Files
modbison/docs/checkpoints/PC3.md
T

4.7 KiB
Raw Blame History

Package Checkpoint 3 (PC3)

Status: partial. PC3's planned scope was M4-avatars + M5-multiplayer + Foundation Hardening + M6–M10 (see docs/build-plan-v1.md). As of 2026-09-05, M4, M5, and most of Foundation Hardening are done and checkpoint-verified; M6–M10 have not been started. This doc records what is real. Whether to call this "PC3" (redefined scope, M6–M10 → PC4) or keep PC3 open is a user decision.

Built by Claude directly (fleet offline), branch pc3 → main.

What's real and verified (scripts/run_checkpoint_tests.py, all green)

Check Result
Alembic migrations, fresh DB PASS
Backend pytest 77/77 PASS (hermetic — auto-starts an ephemeral Postgres)
Godot smoke tests (~16 files) ALL PASS
smoke_test_network_client (real dedicated server) 4/4 PASS
2-player multiplayer (run_multiplayer_2p_test.sh) PASS
Fresh-clone boot (verify_fresh_clone.sh) PASS
Linux + Windows exports Build as real ELF64 / PE32+ binaries

M4 — Avatars in the game

  • Placeholder avatar pack (14 GLBs, rigged 24-bone base body + attachments) generated by scripts/tools/gen_placeholder_avatars.gd. Real art is a content swap — catalog paths are stable.
  • The avatar loader was fixed — it had never run against a real skeleton (Skeleton3D.has_bone() isn't a Godot 4 method; the bone-copy dropped the skin binding; attachments were parsed then discarded).
  • avatar_visualizer.gd rewritten — the old one referenced a loader API that never existed and didn't compile.
  • Persistence: avatar_loadouts table + GET/PUT /api/avatar/loadout (loadout stored as one JSON doc; server validates the envelope only).
  • Wired into gameplay: the in-world player renders as the assembled avatar (not a capsule); the loadout is fetched at login; "Customize Avatar" from the main menu saves through to the backend.
  • Follow-up: camera is still first-person, so the local player doesn't see their own avatar much (third-person is a polish item); remote players' avatar appearance is not replicated yet (they show as labelled capsules).

M5 — Real multiplayer

  • server.gd actually runs a sim now — loads the world level, spawns a server player per peer, processes each peer's input queue in seq order at a fixed 30 Hz, broadcasts full snapshots with a per-peer last_seq. (The input queue was a no-op before.)
  • network_client.gd reconciliation replays in-flight inputs from the authoritative state (drops acked ones), snaps only on real drift.
  • Server orchestration (backend/app/services/game_servers.py): one headless Godot dedicated-server process per world, spawned on demand by POST /api/worlds/{id}/join, port-allocated, with a status-file idle reaper. Off by default; the playtest launcher (checkpoint_ops.py) enables it.
  • Client play path: world browser → /join → Session → game.tscn connects → local player predicts with collision, input forwarded, server position is a drift backstop, remote players render from snapshots, disconnect returns to the world list. Falls back to local single-player when the backend has no orchestration.
  • Verified: two real client processes each register → /join → play, hosted on an orchestrated server, see and move relative to each other (run_game_multiplayer_test.sh).

Foundation Hardening

  • Hermetic backend tests — cd backend && pytest works from a clean checkout (auto ephemeral Postgres + migrations, torn down after); skips cleanly with a message if there's no Docker.
  • Fresh-clone boot check — verify_fresh_clone.sh exports a pristine tree, imports from scratch, boots headless, fails on any script error. Also fixed the root cause: a stale .godot/global_script_class_cache.cfg was committed to the repo.
  • Real age verification — /register takes a date of birth (not a checkbox), server computes age, 403 under 18. Still self-attested; the limitation and the ID-check hook are documented (content_moderation.md 5.2).
  • Auth rate limiting — 10 attempts / min / IP on /register + /login.
  • CI workflow — .forgejo/workflows/checkpoint.yml written, not running yet: needs the operator to enable Forgejo Actions + register a host runner (one-time; see docs/ci.md). Interim gate is run_checkpoint_tests.py by hand / the dashboard.

Not in PC3 (planned but not started)

  • M2 server-side world persistence
  • M6 scripting sandbox
  • M7 in-game editor
  • M8 social / chat
  • M9 economy
  • M10 discovery

Playtest

Same as PC2 — grab the exe from the dashboard's /checkpoints, backend pointed at it. New: with multiple people in the same world you now actually see each other move.