Files
pz-client-to-dedicated-mult…/README.md
2026-08-08 12:31:55 +02:00

142 lines
6.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.
# AI Disclosure
yeah, vibed, 100%. I read the code, should be fine.
Zomboid savefiles are a mess IMHO, this was the quickest way to get to the goal.
If you don't like it, don't use it, idc.
----
# Zomboid Converter
## client-hosted → dedicated server
Rust CLI that converts a locally **hosted** Project Zomboid multiplayer world into a **dedicated** server layout.
The world save format is the same (B42 `Saves/Multiplayer/…`). Conversion is packaging + naming + `players.db` world rename + mod recovery — not a binary rewrite.
This repository is **only** the converter. Sibling folders next to a checkout (e.g. `original/`, `server/`) are optional local testing aids and are not part of the git tree.
## Build
```bash
cargo build --release
# binary: target/release/zomboid-converter
```
Copy the binary wherever you run the dedicated server (example below: `~/docker/zomboid/bin/`).
## Inputs / outputs
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. They are **not** inside the world folder. Pass the directory that contains those files with `--server-config`.
`--input` may be a world **directory** or a **`.zip`** (opened read-only; extracted to a temp dir). Paths ending in `_player` are rejected.
`--output` is the dedicated **server-data** root (writes `Saves/Multiplayer/<server-name>/` and patches `Server/<server-name>.ini`).
## Example (Hetzner / Docker layout)
Assumes:
| Path | Role |
|------|------|
| `~/docker/zomboid/` | Dedicated server (`docker-compose.yml`, `.env`) |
| `~/docker/zomboid/server-data/` | Zomboid userdir (Saves, Server, db, …) |
| `~/docker/zomboid/server-files/` | Game install (Steam download target) |
| `~/docker/zomboid/bin/zomboid-converter` | This binary |
| `~/docker/copyparty/data/zomboid/…` | Uploaded host world + configs |
```bash
# stop the server first if it is running
cd ~/docker/zomboid
docker compose stop
./bin/zomboid-converter \
--input ~/docker/copyparty/data/zomboid/alt/serverb42stable \
--output ~/docker/zomboid/server-data \
--server-name pzserver \
--server-config ~/docker/copyparty/data/zomboid/alt \
--force
docker compose up -d
docker compose logs -f
```
Or edit and run `~/docker/zomboid/convert-and-start.sh` (config block at the top).
`--server-name` (default `pzserver`) must match `SERVER_NAME` in the server `.env`. It is only a basename for the dedicated world and `Server/*.ini` files.
`--workshop-dir` defaults to `<output>/../server-files/steamapps/workshop/content/108600` when that directory exists (fills `WorkshopItems=`). Until Steam has downloaded mods once, re-run after the first install if needed.
## Arguments
| Flag | Description |
|------|-------------|
| `-i`, `--input` | Hosted world dir or zip |
| `-o`, `--output` | Dedicated `server-data` root |
| `-n`, `--server-name` | World + config basename (default: `pzserver`) |
| `--server-config` | Dir with host `<WorldName>.ini`, `_SandboxVars.lua`, spawn files |
| `--workshop-dir` | `…/workshop/content/108600` — fills `WorkshopItems=` (auto if present next to `server-data`) |
| `--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. Resolves Steam workshop IDs into `WorkshopItems=` when a workshop dir is available
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 notes
Use any Project Zomboid dedicated image/layout you like. With Docker next to `server-data`:
- `SERVER_NAME` must match converter `--server-name`
- Optional: `SERVER_PASSWORD` in `.env` for the converters `Password=` patch
- Also typical: `ADMIN_USERNAME` / `ADMIN_PASSWORD`, `RCON_PASSWORD`, memory, ports
- Ports: `16261/udp`, `16262/udp`, `27015/tcp` (RCON)
- Stop the container before re-running the converter with `--force`
- After first start, wait until workshop items finish installing (`Workshop: … Installed` in logs)
## Recommended migration flow
1. Stop the dedicated server.
2. Upload/copy the host world (not the `_player` folder) and ideally the host `Server/<WorldName>.*` configs.
3. Run the converter with `--server-config` pointing at the config directory.
4. Start the dedicated server; wait for workshop installs if needed.
5. 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`, dedicated defaults remain. |
| Mods with no WorldDictionary entries | Pure Lua/QoL mods may not appear in recovered `Mods=`. |
| Workshop **versions** | IDs come from the workshop cache on disk; newer mod builds than the host used can cause chunk `LENGTH mismatch` / `blam` errors. |
| `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 the original host world if that happened. |
## Example passwords
```bash
# next to docker-compose (.env)
SERVER_PASSWORD=hunter2
# or CLI override
zomboid-converter … --password 'hunter2'
```