← Server architecture · all tasks

Stage 3 — Godot client with prediction and reconciliation; two clients

done priority 2 estimate L

server-architecture/007 · created 2026-08-02 · updated 2026-08-04 · blocked by server-architecture/006 · delivers #6

What to do

Add the client side: a Godot client that connects to stage 2’s world server, predicts its own movement locally for responsiveness, and reconciles against the server’s authoritative state as it arrives — the netcode decision overview.md calls out as “not deferred… retrofitting prediction onto a netcode layer that didn’t have it from the start is close to a rewrite.”

  1. A Godot client project using the EntityNode rendering half of the split stage 2’s server already established for Entity data — same codebase family, client-specific concerns only (rendering, local input, prediction).
  2. Client-side prediction: on local input, move immediately and locally, without waiting for the server round-trip.
  3. Server reconciliation: when the server’s authoritative position for this client’s own entity arrives (per stage 2’s protocol), reconcile — correct the local predicted position if it’s diverged, per the standard prediction/reconciliation pattern this decision is named after.
  4. Two clients, simultaneously connected to the same world instance, each seeing the other move — this is the concrete proof this stage exists to deliver, not just “one client works.”
  5. Portal routing: a player crosses a portal from world A to world B — membership enforced at the destination, the destination world spawned/hydrated on demand if not already running, and the player’s entity state transferred through the director with no loss or duplication. See overview.md’s “Not yet decided: the portal-transfer mechanism itself” note — the actual transfer mechanism (candidate: Postgres-as-transfer-medium, snapshotting out of world A and hydrating into world B) and its related snapshot-boundary question are open design questions, not settled ones; confirm an approach with Kris before locking in the implementation, don’t just build the candidate silently.
  6. Automated tests where feasible (reconciliation logic, message handling) plus a headless two-client test-client script that connects two instances of the test client (not two humans clicking) and asserts each sees the other’s position update correctly — consistent with every other stage’s “no listening port to click on” constraint. Extend this (or add a companion script) to cover the portal-routing case: a client crosses a portal and ends up correctly placed in, and only in, the destination world.
  7. Handoff note: land-of-lor/pocs/multiplayer-poc/handoff/stage-3.md, including explicitly what a human should look at when actually running two real Godot client windows on the droplet/locally (this is the one stage where an actual visual check by Kris is genuinely the most meaningful verification, even though the automated headless version has to exist too).
  8. Web export, deployed to the droplet — this stage’s close-out, and how Kris human-verifies it. Godot’s HTML5/web export target for the same client from step 1, built and served from lor-game-server-01 (deliverable #4/#5), connected to a live world. Verification is two browser tabs open to that URL, each seeing the other move — the same bar as the headless two-client test, just witnessed directly instead of read from a script’s assertions. This is deliverable #6 (deliverables/006-play-in-your-browser.md); it does not flip to delivered until this link is live and that two-tab check has actually been done. Known prerequisite, not yet resolved: there’s no deploy key set up for getting build output onto the droplet yet (see deliverable #5’s server notes) — sort that out as part of this step, don’t assume it exists. Known constraint, not a blocker: the droplet currently serves plain HTTP with no domain/TLS, so this ships as ws:// from an http:// page — that’s fine for the PoC, but flag in the handoff note that a later move to a real domain + TLS turns this into wss://, a client connection-code change, not just a hosting one.

Definition of done

Automated/headless-scripted verification passes and demonstrates two clients observing each other’s movement, plus a portal crossing between two world instances with membership enforced, on-demand destination hydration, and lossless entity-state transfer; the handoff note exists. Additionally, per the delivers: [6] gate (see epics/README.md’s “Promised deliverables” section): this task cannot move to done until deliverable #6 is delivered with its live link in place — the web export running on the droplet and the two-browser-tab check, not just the headless proof. The review→done gate this extends already required Kris’s sign-off; this makes explicit that his sign-off on deliverable #6 specifically is part of it. Set state: review, not done, once the automated/headless portion lands — done still waits on the web-export deploy and Kris’s check.

Where the work lands

land-of-lor/pocs/multiplayer-poc/.

Docs to read first

server-architecture/overview.md’s “Netcode” section (prediction/reconciliation, the reason it’s day-one not deferred). Stage 2’s handoff note for the protocol/movement contract this stage’s client talks to.

Status (2026-08-03)

State: review. All of steps 1-8 are built and automated-verified; deliverable #6 is delivered (live link in place, verified externally per the gate in “Definition of done” above) — so the delivers: [6] gate is satisfied. state: review (not done) regardless, per this epic’s build-plan gating: only Kris moves a stage to done, same rule every prior stage followed.

Built, across three sessions (server protocol, client, deploy):

Known gap, flagged plainly, not silently worked around: a GitHub deploy key for the droplet (deliverable #5’s outstanding follow-up) could not be registered via API this session — the container’s token lacks the required “Administration” repo permission (403). A read-only keypair was generated on the droplet (public key in deliverables/006-play-in-your-browser.md) and needs a human with GitHub admin access to add it. Code was still gotten onto the droplet, via the same git bundle transfer method deliverable #5 originally used — not blocking, just not the cleaner git pull workflow deliverable #5 described as the goal.

What’s still a human check, not provable from this container: actually opening http://209.38.29.22/play/index.html?director=ws://209.38.29.22/director/ in two browser tabs and watching the canvas render — no display/browser exists in this container. The live-verification script proves the underlying protocol traffic works end-to-end; the visual confirmation is Kris’s own remaining step, same as it would be for the desktop two-client check.

Full detail: land-of-lor/pocs/multiplayer-poc/handoff/stage-3.md (and handoff/stage-3-server-side.md for the protocol-only first half).

Verified and closed (2026-08-04)

Kris performed the human verification bar directly: the web client at https://lor-server.cocreations.com.au/play/index.html?director=wss://lor-server.cocreations.com.au/director/ — two browser tabs, each seeing the other’s player move in the live commons world. (His words on seeing it work are not printable on a family-friendly board, but they were an emphatic yes.) Getting the browser path to this point required the same-day HTTPS wiring and the public-commons-world work recorded in deliverable #6’s 2026-08-04 update. The delivers: [6] gate was already satisfied; with the visual check done, this stage is done.

View source in repository · also available as raw markdown.