diff --git a/ansible/roles/podman/tasks/containers/home/zomboid.yml b/ansible/roles/podman/tasks/containers/home/zomboid.yml index 9d50a72..34ff90a 100644 --- a/ansible/roles/podman/tasks/containers/home/zomboid.yml +++ b/ansible/roles/podman/tasks/containers/home/zomboid.yml @@ -23,14 +23,17 @@ # than the container's subuid. Getting this wrong silently broke world resets: # the script's first log line failed with EACCES and set -e killed it before it # stopped the server, so `@bot` resets did nothing at all. -- name: create zomboid canonical config directory +- name: create zomboid host-side config directories become: true ansible.builtin.file: - path: "{{ zomboid_path }}/config-template" + path: "{{ zomboid_path }}/{{ item }}" state: directory owner: "{{ podman_user }}" group: "{{ podman_user }}" mode: 0755 + loop: + - config-template + - config-backup - name: create zomboid host-side log directory become: true @@ -228,18 +231,17 @@ state: started daemon_reload: true -# The intended world settings, kept somewhere the server cannot reach. +# A pristine copy of the Sophie preset, kept where the server cannot overwrite it. # -# PZ reads Server/_SandboxVars.lua only when it creates a world, and then -# writes the *running world's* settings back over that same file. So the file in -# Server/ is an output, not an input: once any world is created with defaults, -# the server stamps those defaults into it and every later wipe regenerates from -# them. That is how a Sophie world quietly became an Apocalypse one -- 139 values -# reverted, loot rates from 0.35 back to 0.9, CharacterFreePoints from 0 to 60. +# Reference only -- nothing applies this automatically. A wipe deliberately leaves +# the live settings alone so hand tuning survives it. # -# This copy is what a wipe restores from, so settings survive it. Seeded once and -# then left alone, so it is the file to hand-edit when changing the world: -# edit here, then wipe, and the new world comes up with the edits. +# It exists because the live files cannot be trusted as a record of intent: PZ +# reads Server/_SandboxVars.lua only when it creates a world, then writes +# the running world's settings back over it. The file in Server/ is an output as +# much as an input, and that is how a Sophie world quietly became an Apocalypse +# one -- 139 values reverted, loot from 0.35 back to 0.9, CharacterFreePoints +# from 0 to 60. When that happens again, this is what to copy back from. - name: seed canonical zomboid world settings become: true ansible.builtin.copy: diff --git a/ansible/roles/podman/templates/zomboid/world-reset.sh.j2 b/ansible/roles/podman/templates/zomboid/world-reset.sh.j2 index f0a6d1a..6ccdc34 100644 --- a/ansible/roles/podman/templates/zomboid/world-reset.sh.j2 +++ b/ansible/roles/podman/templates/zomboid/world-reset.sh.j2 @@ -32,6 +32,28 @@ if podman unshare test -f "$TRIGGER_FILE"; then podman unshare rm -f "$TRIGGER_FILE" fi +# Snapshot the current settings before touching anything. They are not modified +# by the wipe, but they are the one thing here with no other copy: Greg's edits +# were lost once already because the only record of them was a file the server +# had since overwritten. +# Every step here is best-effort: a wipe must never fail because a backup could +# not be written. An unwritable log aborted this whole script once already. +SNAP_DIR="{{ podman_home }}/.local/share/volumes/zomboid/config-backup/$(date '+%Y-%m-%d_%H-%M-%S')" +if ! mkdir -p "$SNAP_DIR" 2>/dev/null; then + log "WARNING: could not create $SNAP_DIR; skipping settings snapshot" + SNAP_DIR="" +fi +if [[ -n "$SNAP_DIR" ]]; then + for f in SandboxVars spawnregions spawnpoints; do + src="{{ podman_home }}/.local/share/volumes/zomboid/data/Server/${SERVER_NAME}_${f}.lua" + podman unshare cp "$src" "$SNAP_DIR/${f}.lua" 2>/dev/null || true + done + log "Settings snapshotted to ${SNAP_DIR##*/}" + # Keep the last 10 snapshots. + ls -1dt "{{ podman_home }}/.local/share/volumes/zomboid/config-backup"/*/ 2>/dev/null \ + | tail -n +11 | xargs -r rm -rf || true +fi + # Stop server log "Stopping zomboid service..." systemctl --user stop zomboid.service || true @@ -55,23 +77,16 @@ else log "No database found at $DB_PATH" fi -# Restore the intended world settings before the server regenerates. +# Settings are deliberately NOT touched here. A wipe resets the world and the +# players; Server/_{SandboxVars,spawnregions,spawnpoints}.lua carry over +# as-is, so hand-tuned settings survive it. # -# Without this the wipe silently changes the game. PZ writes the running world's -# settings back over Server/_SandboxVars.lua, so by the time we delete the -# save that file already describes the world we are throwing away -- and if that -# world had defaults, the replacement inherits them. Restoring from the canonical -# copy is what makes a wipe reset the world and keep the settings. -CONFIG_TEMPLATE="{{ podman_home }}/.local/share/volumes/zomboid/config-template" -SERVER_DIR="{{ podman_home }}/.local/share/volumes/zomboid/data/Server" -for f in SandboxVars spawnregions spawnpoints; do - if [[ -f "${CONFIG_TEMPLATE}/${f}.lua" ]]; then - podman unshare cp "${CONFIG_TEMPLATE}/${f}.lua" "${SERVER_DIR}/${SERVER_NAME}_${f}.lua" - log "Restored ${SERVER_NAME}_${f}.lua from canonical config" - else - log "WARNING: no canonical ${f}.lua; the new world will inherit whatever the server last wrote" - fi -done +# The risk that buys: PZ writes the running world's settings back over those +# files, so if a world is ever created with defaults the file inherits them and +# every later wipe regenerates from them -- which is how a Sophie world became an +# Apocalypse one. Nothing here corrects that automatically any more, so the +# snapshot above is the way back: config-backup/ holds the settings as they were +# before each wipe, and config-template/ holds the pristine Sophie preset. # Start server log "Starting zomboid service..."