Files
pz-client-to-dedicated-mult…/README.md
2026-08-08 11:57:50 +02:00

124 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Zomboid client-hosted → dedicated server
Convert a locally **hosted** Project Zomboid multiplayer world into a **dedicated** server layout, then run it with Docker.
The world save format is the same (B42 `Saves/Multiplayer/…`). Conversion is packaging + naming + `players.db` world rename + mod recovery — not a binary rewrite.
## Layout
Paths below are relative to the **repo root** (parent of this `converter/` folder):
| Path | Role |
|------|------|
| `original/` | Source saves / zips (**do not edit the zips**) |
| `converter/` | This crate — Rust CLI (`zomboid-converter`) |
| `server/` | Docker dedicated server (`docker-compose.yml`, `.env`) |
| `server/server-data/` | Zomboid userdir (Saves, Server, db, Logs) |
| `server/server-files/` | Game install (Steam download target) |
Typical source pair from a host:
- `Saves/Multiplayer/<WorldName>/` — authoritative world (**use this**)
- `Saves/Multiplayer/<WorldName>_player/` — client cache (**ignore**)
Server settings live separately under `Zomboid/Server/<WorldName>.*` on the host machine. They are **not** inside the world folder.
## Prerequisites
- Rust toolchain (for the converter)
- Docker + Docker Compose
- Optional: local Steam workshop cache for app `108600` (to resolve `WorkshopItems`)
## Converter
```bash
cd converter
cargo build --release
cargo run --release -- \
--input ../original/serverb42stable \
--output ../server/server-data \
--server-name pzserver \
--workshop-dir /path/to/steamapps/workshop/content/108600 \
--force
```
`--input` may be a world **directory** or a **`.zip`** (opened read-only; extracted to a temp dir). Paths ending in `_player` are rejected.
### Arguments
| Flag | Description |
|------|-------------|
| `-i`, `--input` | Hosted world dir or zip |
| `-o`, `--output` | Dedicated `server-data` root |
| `-n`, `--server-name` | World + config basename (default: `pzserver`) |
| `--workshop-dir` | `…/workshop/content/108600` — fills `WorkshopItems=` |
| `--server-config` | Optional host `Server/` dir to copy/rename configs |
| `--password` | Server join password (`Password=` in ini); overrides `.env` |
| `--env-file` | `.env` for password (default: `<output>/../.env`) |
| `--force` | Replace existing `Saves/Multiplayer/<server-name>/` |
### What it does
1. Copies the world into `output/Saves/Multiplayer/<server-name>/`
2. Skips syncthing conflict sidecars (`*-ZwS1g3qi*`), `*.db-journal`, and player-cache junk
3. Sets `networkPlayers.world` in `players.db` to `<server-name>`
4. Recovers mod IDs from `WorldDictionaryReadable.lua` into `Server/<name>.ini` (`Mods=`)
5. If `--workshop-dir` is set, resolves Steam workshop IDs (`WorkshopItems=`)
6. Optionally sets `Password=` from `--password` or `SERVER_PASSWORD` / `PASSWORD` in `.env`
It does **not** overwrite `db/<server-name>.db` (accounts / whitelist stay managed by the server).
### Characters / login
Characters bind to the **account username** in `players.db` (`networkPlayers.username`), not Steam display name. Players must log in with that exact username (or you rename the column before they join).
## Dedicated server (Docker)
```bash
cd ../server
cp .env.example .env # if needed; set passwords / SERVER_NAME
docker compose up -d
docker compose logs -f
```
Important `.env` keys:
- `SERVER_NAME` — must match converter `--server-name` (default `pzserver`)
- `ADMIN_USERNAME` / `ADMIN_PASSWORD` — admin account
- `RCON_PASSWORD` — RCON
- `SERVER_PASSWORD` — optional join password for the converter (`Password=` in ini)
Ports: `16261/udp`, `16262/udp`, `27015/tcp`.
Stop the container before re-running the converter with `--force`.
## Recommended migration flow
1. Stop the dedicated server.
2. Copy the host world into `original/` (keep zips untouched as backups).
3. Ideally also copy the hosts `Zomboid/Server/<WorldName>.ini` (+ `_SandboxVars.lua`, spawn files) and pass `--server-config`.
4. Run the converter with `--workshop-dir` and `--force`.
5. Start Docker; wait until workshop items finish installing (`Workshop: … Installed` in logs).
6. Join with the **same username** as in the hosted `players.db`.
## Known gaps / caveats
| Item | Notes |
|------|--------|
| Host `SandboxVars` / spawn / `Map=` | Not in the world save. Without `--server-config`, the dedicated defaults remain. |
| Mods with no WorldDictionary entries | Pure Lua/QoL mods may not appear in recovered `Mods=`. |
| Workshop **versions** | IDs are resolved from your local workshop cache; newer mod builds than the host used can cause chunk `LENGTH mismatch` / `blam` errors and odd world state (e.g. zombies in cleared bases). |
| `ZombieMigrate` | Dedicated sandbox may allow migration even when respawn is off; align sandbox with the host when possible. |
| Running without mods first | Can rewrite `WorldDictionary` and map chunks. Re-import from `original/` if that happened. |
## Example passwords
```bash
# ../server/.env (next to docker-compose)
SERVER_PASSWORD=hunter2
# or CLI override (from this directory)
cargo run --release -- … --password 'hunter2'
```