M2.4: the server decides online (characters, inventory, stats, death, owned graves, per-player saves); death screen with Respawn after 3 s

This commit is contained in:
Paul Bailey
2026-11-04 19:18:31 +00:00
parent 8e8f10eb96
commit 35a656e996
16 changed files with 1124 additions and 477 deletions

View File

@@ -6,9 +6,9 @@ concrete decisions for this codebase, as it stands after M1.
## 1. Goals
- **Self-hosted**, 2-8 players (up to 16 possible). No central service, no
accounts: a world lives on whoever hosts it.
- **Three ways to play, one code path:**
- **Single-player**: the game runs a server inside itself and connects to
it (loopback). It plays exactly as now.
- **Three ways to play, the same rules (Actions):**
- **Single-player**: no server; your game decides, exactly as now
(decided in M2.4, §7).
- **Host & play**: "Host game" on the title screen, and friends join you.
- **Dedicated server**: a headless "server only" process with no local
player. It keeps the world running (or paused) for whoever connects.
@@ -204,12 +204,32 @@ it needs no syncing.
the server, never on top of a player.
- The world (fires, regrowth, the clock) pauses while nobody's on.
Until later phases, while online: your inventory, stats and crafting stay on
your own game and aren't saved by the server (M2.4), so the server trusts
what you say you're putting into the world (a wall, a chest deposit, a
grave's contents) but decides everything taken out. Animals are off (M2.5).
Sleeping is off (it needs the sleep rule, M2.5). Respawning ignores beds.
The HUD says so.
**Your character on the server** *(built in M2.4: `player_net.gd`,
`server_player.gd`, autoload PlayerNet)*. Online the server decides;
offline there's no server and your game decides, exactly as before.
- Each player has a character on the server with their inventory, hotbar
choice, cloak, inventory-screen cursor, bed and survival stats. The stats
run there: warmth from the server's fires and buildings, rain, hunger and
the diet. Sprinting and jumping cost stamina there too.
- Online, every `Actions.*` intent becomes a request (`PlayerNet.ask("eat",
[slot])`). The server runs the same Actions function on your character
and sends back your inventory (after every request, and whenever it
changes) and your stats (4 times a second). What your own game has in
its bag counts for nothing: a modified game that adds walls to its bag
can't build with them.
- Clicks in your own bag also happen on your screen at once, so dragging
items doesn't wait for the network. The server's copy replaces yours as
soon as it has handled every click you sent.
- Death happens on the server: a grave with your name on it (only you can
open it until the M2.6 rules), then you wake at your bed if it's still
standing, otherwise the island start.
- Characters are saved in `worlds/<world>/players/<player id>.json`, with
the world, so you come back where you left off.
Until later phases, while online: animals, hunting and fishing are off
(M2.5), and so is sleeping (it needs the sleep rule, M2.5). The HUD says so.
The server doesn't yet check that you're out of stamina when you sprint
(it charges you, but doesn't stop you).
**Interest.** On a 320 m worldlet with 8 players, the server sends every
entity to everyone at first. Distance-based interest is a later
@@ -243,10 +263,18 @@ net ids, no owners yet) are written next to `server.json` within 10 s of
any change, when a player leaves, and every `autosave_minutes`. (Ctrl+C
kills Godot without running any code, so there's no save on the way out.) An
existing world keeps the seed it was made with, even if `server.json`
changes. Player files, owners and backups come in M2.4 and M2.7.
- Single-player saves (today's `world.json` with a `"player"` block) are
migrated on first load. That block becomes the local player's file. The
test suite keeps an old-format save fixture to prove it.
changes. *As of M2.4:* `players/<player id>.json` too (position, facing,
inventory, hotbar choice, stats, diet, buffs, cloak, bed), saved with the
world, when the player leaves and when they die. Graves carry their
owner. Backups come in M2.7.
*Decision (M2.4):* single-player stays as it is, with no server inside it
("if it's single-player there is no server, so the game decides"). So
single-player saves need no migration: they keep working unchanged, and
`tests/test_save_load.gd` still proves it. The old idea of running
single-player as a loopback server is dropped.
- *(Originally: single-player saves migrated to a player file on first
load. Not needed since the M2.4 decision above.)*
- Per-player graves already work, since graves are pieces. With
`death_penalty: grave` they get an owner, and only the owner (and friends,
depending on locks) can loot them.
@@ -274,7 +302,7 @@ player" or "this player":
| **M2.1** *(done)* | network skeleton: `--server`, ENet on 24242, Join screen (address, name), handshake with identity and challenge, name rules, player list | two clients and a headless server on one Mac connect, see the player list, and disconnect cleanly |
| **M2.2** *(done)* | player bodies and name tags; predicted movement, interpolation for others | two players walk around together at 100 ms simulated latency without visible rubber-banding |
| **M2.3** *(done)* | world state replicated: resource nodes, pickups, pieces, chests, fires, doors, clock, weather | one chops a tree and the other sees it fall; one builds a wall and the other walks into it |
| **M2.4** | intents as RPCs; per-player inventory, stats, diet, death and graves; per-player saves and migration | two players craft, eat, die and loot their own graves; an old single-player save loads |
| **M2.4** *(done)* | intents as RPCs; per-player inventory, stats, diet, death and graves; per-player saves and migration | two players craft, eat, die and loot their own graves; an old single-player save loads |
| **M2.5** | wildlife and wolves server-side, projectiles, fishing, sleeping with the rule | a pack hunts two players at once; arrows hit on both screens |
| **M2.6** | server rules: PvP, raiding, locks and friends, death penalty, difficulty; admin console and chat | each preset (co-op, rivals, adversarial) behaves as described in §4 |
| **M2.7** | hosting polish: "Host game" button, systemd and launchd samples, backups, a Tailscale how-to in the docs | Paul runs it on the home server, and a friend joins over Tailscale and plays for an hour |
@@ -288,9 +316,8 @@ player" or "this player":
- **Rules tests:** one per server rule (PvP off means no damage between
players; raiding off means you can't dismantle a stranger's wall; locks
keep strangers out of your chest).
- **Save tests:** world and player file round trips, migration of old
saves, backups.
- The existing 9 suites keep running in single-player (loopback) mode.
- **Save tests:** world and player file round trips, backups.
- The single-player suites keep running as they are (no server).
- `tests/test_net_shared.gd` (M2.3) is the two-world version: this test is
one player and `tests/net_world_bot.gd` (a second process with its own
world, following commands the test writes as files) is the other. A

View File

@@ -47,12 +47,13 @@ Detailed plan in `docs/SURVIVAL_DESIGN.md` (phases M1a–M1d).
Detailed plan in `docs/MULTIPLAYER_PLAN.md` (hosting on UDP 24242 via Tailscale
or port forwarding, player identity and names, server rules for co-op/PvP, and
phases M2.0-M2.7).
- [ ] Refactor state to server-authoritative (single-player becomes loopback server)
- [x] Server-authoritative online (single-player stays as it is, with no server) *(M2.4)*
- [x] Headless dedicated server, joining, identity handshake, names, player list *(M2.1)*
- [x] ENet transport, player bodies and name tags, local movement checked by the server, interpolation for others *(M2.2)*
- [x] Replicate resource nodes, pickups, building, chests, fires, doors, clock *(M2.3)*
- [x] Persistence: world save/load on the server *(M2.3)*
- [ ] Per-player inventory, stats and saves on the server *(M2.4)*
- [x] Per-player inventory, stats, death, graves and saves on the server *(M2.4)*
- [ ] Animals, hunting, fishing and sleeping on the server *(M2.5)*
- **Done when:** a friend joins your self-hosted server and you build together.
## M3 — Addon SDK + sandbox · ~2–3 months