Public: anyone can read this; the crew can change it.

forked from trevato/cs

multiplayer. i need to run this with my friends. surprised it’s not there yet… #312

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

Multiplayer lands as a room you can make from the menu and read a code out for. The round is stepped **on this server**, not in anybody's browser: `src/rooms/room.ts` runs the shooter's own `createWorld` and `updateWith` at 64 Hz, each member holds one seat (a bot's, so a round is always 5v5, handed straight back with its money and guns when they leave), and everyone is sent the same 544-byte pack…

shipped production is serving it deploy ae07c2d

opened this

Multiplayer lands as a room you can make from the menu and read a code out for. The round is stepped on this server, not in anybody's browser: src/rooms/room.ts runs the shooter's own createWorld and updateWith at 64 Hz, each member holds one seat (a bot's, so a round is always 5v5, handed straight back with its money and guns when they leave), and everyone is sent the same 544-byte packed snapshot sixteen times a second — measured, 8.7 kB/s a member down and 14 bytes a tick up. Verified against the running server over a real socket: POST /api/room hands back a code, the upgrade delivers hello and then 15 snapshots in a second at 7.7 kB.

The load-bearing change is first and on its own commit: update no longer applies one Input to world.me but asks for each body's input (updateWith), with the single-player game passing its own — the replay digests do not move and bun test is green (1283 pass).

What to look at: src/rooms/wire.ts is the whole protocol and the only boundary a client's bytes cross — a weapon id cannot be named on it, a switch is one of four things the server resolves against your body, a buy is an index the economy still refuses if the money is not there, and a frame of the wrong size is dropped rather than parsed. src/rooms/hub.ts holds the numbers with reasons: twenty rooms a process, ten people a room, 64-byte frames, a flood or a silent connection closed, an empty room forgotten after ninety seconds. src/server.ts is the only file that knows what a WebSocket is; a plain GET of /ws is the app's own 404. In the preview: make a room from the menu, open the code in a second browser, and watch both bodies in one round.

What is not done and is stated on the page and in the README rather than faked: your own movement is not predicted, so it answers on the round trip (#305's remaining half, and the thing a CS player will notice first); a room has no hit marker or damage arrow, because both are effects recorded for one screen and a snapshot goes to everybody; a room's result is not posted to the leaderboard, so #168's trust half is untouched; and #302's bench with three candidate encodings was not written — the snapshot's size is asserted by a test in src/rooms/rooms.test.ts and the CPU argument leans on the ceiling src/budget.test.ts already holds. No new dependency. The app bundle's ceiling moves to 122,000 raw / 47,500 gzipped, copied from bun run scripts/build.ts, for the session and the codec. I did not open two real browsers against the preview — the socket was proved with a Bun client and the page's wiring is typechecked and booted by main.test.ts, but the first thing a reviewer should do is play it with somebody.

🤖 Generated with Claude Code

Budget reached at $10.25; this is where it stopped.

Closes #300

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs