142 lines
6.0 KiB
Markdown
142 lines
6.0 KiB
Markdown
# 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 converter’s `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'
|
||
```
|