diff --git a/README.md b/README.md new file mode 100644 index 0000000..dcf7cb6 --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +# Smack a Brother + +![1](/screenshots/1.png) + +![2](/screenshots/2.png) + +![3](/screenshots/3.png) + +![4](/screenshots/4.png) + +Online platform fighter. Lobbies of up to 16 players, games of up to 8. Play it in the browser [here](https://shweetz.net/smack-a-brother/). + +## Clarification +This application was developed with the assistance of a large language model. + +## Build + +After cloning and entering the repository's directory, make sure to initialize the submodules: + +```git submodule update --init --recursive``` + +Everything (SDL, libdatachannel, simdjson) is built statically from the submodules. The game's resources are in `resources/` and get linked next to the executable. + +### Linux + +Needs OpenSSL, plus the X11/Wayland and audio headers SDL builds against. + +``` +mkdir build +cd build +cmake .. +make +``` + +### Web + +Needs the [Emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html). + +``` +emcmake cmake -B build-web -DCMAKE_BUILD_TYPE=Release +cmake --build build-web +``` + +This makes `smack-a-brother.html`, `.js`, `.wasm` and `.data`. Rename the `.html` to `index.html` and serve all four. + +### Server + +The server builds on its own, without SDL. It needs OpenSSL (`libssl-dev` on Debian). + +``` +cmake -S server -B build-server -DCMAKE_BUILD_TYPE=Release +cmake --build build-server +``` + +Run it with: + +```smack-a-brother-server [port] [first UDP port] [last UDP port]``` + +Defaults are `47800`, `47810` and `47899`. It only listens on `127.0.0.1`, so put it behind a reverse proxy that handles TLS. For nginx: + +``` +location /smack-a-brother/ws { + proxy_pass http://127.0.0.1:47800; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_read_timeout 120s; +} +``` + +Open the UDP range in the firewall (e.g. `ufw allow 47810:47899/udp`). + +## Netcode + +- The server runs every lobby: a sandbox everyone in the lobby shares, plus the games queued in it. Each is its own simulation. All of them run on one thread, at 60 ticks a second. +- Clients send their inputs ahead of time. Each tick the server takes what has arrived (repeating a player's last inputs if they're late), steps the simulation, and sends everyone the inputs it used. Every 60 ticks it also sends a checksum. +- Clients run the same simulation about 3 ticks ahead of the server, guessing other players' inputs. When the server's inputs differ from the guess, the client rolls back and replays. +- The simulation is deterministic on every platform (strict floating point, own maths functions), so desktop and web play together. `tools/determinism_check.sh` checks this. +- Clients connect over a WebSocket first (lobbies, chat, WebRTC signaling). Then they open a WebRTC connection to the server with two data channels: a reliable one, and an unreliable one for inputs and frames. If WebRTC can't connect, everything stays on the WebSocket. +- STUN: `stun.l.google.com:19302`. +- The server address is set in Settings. Default: `wss://shweetz.net/smack-a-brother/ws`. + +### Joining a lobby directly +- Desktop: `smack-a-brother --join CODE` +- Web: `https://shweetz.net/smack-a-brother/?lobby=CODE` + +### Environment variables +- `SAB_SERVER_URL`: use a different server, e.g. `ws://127.0.0.1:47800` +- `SAB_NET_LAG`: add this many milliseconds of lag +- `SAB_NET_LOSS`: drop this percent of input packets +- `SAB_NET_STATS`: log how the client is keeping up with the server diff --git a/screenshots/1.png b/screenshots/1.png new file mode 100644 index 0000000..922eed4 Binary files /dev/null and b/screenshots/1.png differ diff --git a/screenshots/2.png b/screenshots/2.png new file mode 100644 index 0000000..2486f57 Binary files /dev/null and b/screenshots/2.png differ diff --git a/screenshots/3.png b/screenshots/3.png new file mode 100644 index 0000000..0b4ea0c Binary files /dev/null and b/screenshots/3.png differ diff --git a/screenshots/4.png b/screenshots/4.png new file mode 100644 index 0000000..37733bb Binary files /dev/null and b/screenshots/4.png differ