Skip to content

feat(leaderboard): remote score sync client (PHP score API)#680

Merged
PipFoweraker merged 1 commit into
mainfrom
feat/leaderboard-sync-client
Jul 17, 2026
Merged

feat(leaderboard): remote score sync client (PHP score API)#680
PipFoweraker merged 1 commit into
mainfrom
feat/leaderboard-sync-client

Conversation

@PipFoweraker

Copy link
Copy Markdown
Owner

What

Client side of the settled PHP score API (docs/strategy/BACKEND_AND_DATA_ARCHITECTURE.md, server/leaderboard/score_api.php). A downloaded build can now upload a run's score on game-over and view the global (online) board, keyed by (seed, game_version) per ADR-0002 #5.

Files

  • godot/autoload/leaderboard_sync.gd (new) -- LeaderboardSync autoload over Godot HTTPRequest:
    • submit_score(entry, seed, version) -> fire-and-forget POST, submit_completed signal.
    • fetch_board(seed, version, limit, callback) -> async GET, parsed into ScoreEntry objects.
    • Pure static helpers (build_post_body / build_endpoint / build_get_url / parse_submit_response / parse_board_entries) -- where the contract bugs hide; unit-tested.
  • godot/data/leaderboard_config.json (new) -- committed config: base_url, token, enabled. Default enabled=false + placeholder host so an unconfigured build never touches the network and never errors. Pip sets base_url + token here (then flip enabled to true) before building.
  • godot/project.godot -- registers the LeaderboardSync autoload.
  • godot/scripts/ui/game_over_screen.gd -- after the existing local save, submits remotely when enabled+configured+opted-in; tiny non-blocking status blip: submitting... -> submitted (rank N) / offline -- saved locally.
  • godot/scripts/ui/leaderboard_screen.gd -- Local/Global toggle (only shown when sync is configured); fetches the remote board for the current (seed, version); falls back to local silently on any failure.
  • godot/autoload/game_config.gd -- submit_scores_global opt-out (default ON), persisted under [leaderboard].
  • godot/scripts/ui/settings_menu.gd -- "Submit Scores to Global Leaderboard" toggle.
  • godot/tests/unit/test_leaderboard_sync.gd (new) -- POST-body build, GET-url encoding, response parsing (incl. malformed/error), and the enabled=false / opt-out no-op gating.

Where Pip configures it

godot/data/leaderboard_config.json: set base_url (host base; endpoint = <base>/score_api.php) + token (the X-PDoom-Token shared secret), then set enabled: true.

Determinism / replay is untouched (ADR-0006)

All network I/O is a pure view side-effect invoked ONLY from the game-over screen and the leaderboard screen (both UI). It never touches the simulation, the seeded RNG, turn logic, or replay, and is never called from any deterministic code path. Every HTTP call is async with an 8s timeout; unreachable/unconfigured/timeout/malformed -> the game plays normally, local leaderboard works, quiet status at most. Only the fields already in ScoreEntry (+ seed/version) go up; opt-out honored.

Verification

  • Fast gate: run_godot_tests.py --quick --ci-mode --min-tests 300 -> 431 tests, 0 failures (45/45 files, incl. the new test).
  • Simulation/determinism tier: --simulation -> 93 tests, 0 failures (proves determinism untouched).
  • godot --headless --path godot --import -> clean (no parse errors).

Do NOT merge -- Pip reviews first.

🤖 Generated with Claude Code

Client side of the settled PHP score API (docs/strategy/
BACKEND_AND_DATA_ARCHITECTURE.md). A downloaded build can upload a run's
score on game-over and view the global board, keyed by (seed, version).

- LeaderboardSync autoload (Godot HTTPRequest): submit_score() fire-and-forget
  POST with a result signal; fetch_board() async GET parsed into ScoreEntry.
  Pure request-build/response-parse helpers are static + unit-tested.
- godot/data/leaderboard_config.json: committed config (base_url, token,
  enabled). Default enabled=false + placeholder host so an unconfigured build
  never touches the network and never errors. Pip fills base_url+token here.
- Game-over: after the local save, submit remotely when enabled+configured+
  opted-in; tiny non-blocking status blip (submitting -> submitted (rank N) /
  offline -- saved locally).
- Leaderboard screen: Local/Global toggle (only shown when configured); fetches
  the remote board for the current (seed, version); falls back to local silently
  on any failure.
- Opt-out setting submit_scores_global (default ON) in GameConfig + a Settings
  toggle. Persisted under [leaderboard].

Determinism/replay (ADR-0006) untouched: all network I/O is a pure view
side-effect at game-over + the leaderboard screen only, async with an 8s
timeout, never on any deterministic/RNG/turn/replay path. Both test tiers green
(fast 431/0, simulation 93/0).

Co-Authored-By: Claude <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@PipFoweraker
PipFoweraker merged commit 85d4fea into main Jul 17, 2026
14 checks passed
@PipFoweraker
PipFoweraker deleted the feat/leaderboard-sync-client branch July 17, 2026 23:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant