The live GDScript turn emitted `unit_healed` inline; the headless healing phase recovered HP silently. The healing phase runs in the end-of-turn `fn(&mut GameState)` registry (no event sink), so follow the FloraSuccession buffer pattern: stash `(player, unit_id, applied_amount, col, row)` into a new transient `GameState.pending_heal_events`, drain it in `step()` into `TurnEvent::UnitHealed`. The buffered amount is the CLAMPED delta actually applied (not the nominal heal rate). No wire surface — dispatch drops it; the live UI consumes it via the kind-tagged `event_to_dict` dict. Verified headless: mc-replay 19/0 (unit_healed_serde), mc-turn 289/0 (healing_buffers_unit_heal_event_with_applied_amount + healing_buffers_clamped_amount_near_full_hp + event_collector_wiring). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
69 lines
3.4 KiB
Bash
Executable file
69 lines
3.4 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Golden-image provisioner. Runs as root on a fresh Ubuntu 24.04 box during
|
|
# `packer build`. Produces a build-ready image for the distributed test fleet:
|
|
# - a build user (flatpak runs --user as this account; root flatpak is unsupported)
|
|
# - the repo cloned at $HOME/Code/@projects/@magic-civilization (run_ap3.sh hard-codes this path)
|
|
# - the full toolchain via the repo's own scripts/dev-setup/linux.sh (DRY)
|
|
# - a prebuilt GDExtension .so (remote autoplay-batch skips the rebuild)
|
|
# - a warm Godot import cache + warm cargo registry
|
|
#
|
|
# Env (injected by Packer): GIT_REMOTE (required), GIT_REF, BUILD_USER.
|
|
set -euo pipefail
|
|
|
|
GIT_REMOTE="${GIT_REMOTE:?GIT_REMOTE must be set}"
|
|
GIT_REF="${GIT_REF:-main}"
|
|
BUILD_USER="${BUILD_USER:-mc}"
|
|
REPO_PATH="Code/@projects/@magic-civilization" # relative to the build user's HOME
|
|
|
|
echo "=== [1/7] base packages ==="
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
apt-get update -y
|
|
apt-get install -y --no-install-recommends \
|
|
git curl ca-certificates build-essential pkg-config libssl-dev \
|
|
unzip sudo python3-pip flatpak rsync
|
|
|
|
echo "=== [2/7] build user '$BUILD_USER' ==="
|
|
if ! id "$BUILD_USER" >/dev/null 2>&1; then
|
|
useradd --create-home --shell /bin/bash "$BUILD_USER"
|
|
fi
|
|
BUILD_UID="$(id -u "$BUILD_USER")"
|
|
# Enable lingering so /run/user/$UID (and the user D-Bus flatpak needs for
|
|
# headless --import) exists without an interactive login.
|
|
loginctl enable-linger "$BUILD_USER" || true
|
|
|
|
# Helper: run a command as the build user in a login shell with the user
|
|
# runtime dir wired up (matches autoplay-batch.sh's XDG_RUNTIME_DIR handling).
|
|
as_user() {
|
|
sudo -u "$BUILD_USER" -H \
|
|
env "XDG_RUNTIME_DIR=/run/user/${BUILD_UID}" \
|
|
bash -lc "$1"
|
|
}
|
|
|
|
echo "=== [3/7] clone repo @ \$HOME/$REPO_PATH (ref $GIT_REF) ==="
|
|
as_user "mkdir -p ~/$(dirname "$REPO_PATH")"
|
|
as_user "git clone '$GIT_REMOTE' ~/$REPO_PATH"
|
|
as_user "cd ~/$REPO_PATH && git checkout -f '$GIT_REF'"
|
|
|
|
echo "=== [4/7] toolchain via scripts/dev-setup/linux.sh ==="
|
|
# WITH_RUNNER must be defined: linux.sh references it unguarded under set -u and
|
|
# we use GitLab CI, not a forgejo runner, so keep it false.
|
|
as_user "cd ~/$REPO_PATH && WITH_RUNNER=false bash scripts/dev-setup/linux.sh"
|
|
|
|
echo "=== [5/7] python RL deps ==="
|
|
as_user "pip3 install --user --break-system-packages -r ~/$REPO_PATH/tooling/rl_self_play/requirements.txt || pip3 install --user -r ~/$REPO_PATH/tooling/rl_self_play/requirements.txt"
|
|
|
|
echo "=== [6/7] prebuild GDExtension + warm cargo registry ==="
|
|
# Remote autoplay-batch mode does NOT rebuild the .so (tools/autoplay-batch.sh:144),
|
|
# so the golden image must ship a fresh one.
|
|
as_user "cd ~/$REPO_PATH/src/simulator && source ~/.cargo/env && cargo fetch && bash build-gdext.sh"
|
|
|
|
echo "=== [7/7] place run_ap3.sh in ~/bin + warm Godot import cache ==="
|
|
# autoplay-batch.sh expects the runner at \$HOME/bin/run_ap3.sh (tools/autoplay-batch.sh:372).
|
|
as_user "mkdir -p ~/bin && cp ~/$REPO_PATH/scripts/autoplay/run_ap3.sh ~/bin/run_ap3.sh && chmod +x ~/bin/run_ap3.sh"
|
|
# First-import gotcha: a fresh checkout needs one --headless --import to build
|
|
# .godot/*.cfg or GDExtension classes resolve as 'not declared'. Non-fatal if it
|
|
# flakes here — the first real run rebuilds it — but baking it makes boots clean.
|
|
as_user "cd ~/$REPO_PATH && flatpak run --user org.godotengine.Godot --path src/game --headless --import" || \
|
|
echo "WARN: headless --import did not complete cleanly — validate in the live smoke"
|
|
|
|
echo "=== golden image provisioned OK ==="
|