6.5 KiB
6.5 KiB
Architecture
This is the big-picture design. It's deliberately written before heavy coding so the hard decisions (networking authority, addon sandbox) are made up front, not bolted on.
1. Guiding principles
- Server is authoritative. The client is a renderer + input device. It never decides game state (health, inventory, block placement, hits). This is the anti-cheat baseline — you cannot bolt it on later.
- Same binary, two modes. One Godot project runs as the client and as the
headless dedicated server (
--headless -- --server). No separate codebase. - Addons can never hurt the host. Mods run in a sandbox (Lua) with a capped API, CPU/memory quotas, and no filesystem/network/host access. Designed in from day one.
- Low-poly + lighting, not textures. Art pipeline stays cheap so a solo dev can actually finish.
2. Process topology
┌────────────────────────────────────────────┐
│ Dedicated Server (headless Godot) │
│ - owns ALL game state │
│ - runs the simulation tick (fixed timestep) │
│ - loads & sandboxes addons │
│ - persists the world (save system) │
└───────────────▲───────────────▲──────────────┘
│ ENet/UDP │
┌───────────┴───┐ ┌───────┴─────────┐
│ Client A │ │ Client B │
│ render+input │ │ render+input │
│ client-side │ │ client-side │
│ prediction │ │ prediction │
└────────────────┘ └──────────────────┘
Single-player = the client spawns an in-process server (loopback). So single-player and multiplayer share the exact same code path — no "SP special case" that rots.
3. Networking
- Transport: Godot's built-in high-level multiplayer over ENet (reliable UDP). Good for 2–16 players, which is the realistic self-hosted survival scale.
- Model: server-authoritative with client-side prediction + reconciliation for the local player's movement (so it feels responsive), and interpolation for remote entities (so they look smooth).
- RPC discipline: clients send intents ("I want to place a wall here", "I swung at this"), never results. The server validates, applies, and broadcasts the authoritative result.
- Scale target: 2–16 players per server. NOT Rust's 200. That's a deliberate scope cut — 200-player netcode is a multi-year problem on its own.
4. World
- Terrain: heightmap-based mesh, chunked. Each chunk is a mesh the server generates deterministically from a seed, so clients can regenerate geometry locally and the server only syncs edits (not the whole mesh).
- Generation: deterministic noise (seed → biome map → heightmap → object placement). Deterministic = client and server agree without syncing megabytes.
- Biomes: start with 2–3 (meadows, forest, maybe a harsher zone) à la Valheim.
- Streaming: load/unload chunks around each player. Server keeps a slightly larger radius than clients.
5. Entities & simulation
- Fixed-timestep simulation tick on the server (e.g. 20–30 Hz). Rendering runs at the client's framerate, decoupled.
- Entity types: player, resource node (tree/rock), dropped item, creature, building piece, projectile.
- Each entity has a network id; the server owns it and replicates state deltas.
6. Building system
- Snap-together prefabs: walls, floors, roofs, stairs — each with snap points.
- Structural rules (Valheim-style): pieces need support; stability falls off with distance from the ground, unsupported pieces collapse. Great emergent gameplay, and it's a clean server-authoritative calculation.
- Placement is a client intent; the server validates snap + support + resource cost, then commits.
7. Survival systems
- Health, stamina, hunger (and later temperature/comfort like Valheim).
- Crafting: recipes (inputs → output + required crafting station + skill level).
- Inventory: grid or slot-based, server-authoritative.
- Day/night cycle + weather driving lighting and creature behaviour.
8. Persistence
- World save = seed + chunk edits + entity states + player inventories.
- Server writes periodic snapshots + on clean shutdown. Format: Godot resources or a simple binary/JSON hybrid. Keep it moddable-inspectable where cheap.
9. Addon SDK — the differentiator (full spec in ADDON_SDK.md)
- Addons are Lua scripts run inside a sandboxed Lua VM embedded in the server.
- The host exposes a deliberately limited API surface — the only things an
addon can touch. No
os, noio, norequireof host files, no raw sockets. - Quotas: instruction-count / wall-time caps per callback (so an addon can't hang the tick), and a memory ceiling per addon VM.
- Event model: addons register handlers (
on_player_join,on_block_place,on_tick, …). The host calls them inside the sandbox with the quota enforced. - Content model: addons can also declare data (new items, recipes, prefabs) via manifest files the host validates before loading.
- Addons run server-side (authoritative). Clients receive the resulting state like any other. (A later client-side cosmetic addon lane is possible but separate and even more locked down.)
10. Why Godot 4 + GDScript here
- Free, open-source, no licensing worry, exports to all three desktop OSes.
- Godot 4's renderer (SDFGI / voxel GI, volumetric fog) is enough for the Valheim atmosphere without expensive assets.
- GDScript keeps iteration fast for a solo dev; drop to C++ GDExtension only for hotspots (terrain meshing, noise) if profiling demands it.
- The Lua addon VM is embedded via a GDExtension or a Lua-in-Godot addon
(e.g.
godot-luaAPI), keeping mods off GDScript (so a mod can't call engine internals).
11. Deliberate scope cuts (so this can actually ship)
- 2–16 players, not 200.
- Desktop only first (no console/mobile).
- A handful of biomes, items, creatures for the vertical slice — breadth comes later.
- No photoreal art. Low-poly + lighting only.