feat(autoplay): add weston rendering support

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-04-15 19:55:24 -07:00
parent cbb8de7004
commit 8ed21325c7
3 changed files with 117 additions and 48 deletions

View file

@ -1,17 +1,26 @@
#!/bin/bash
# Godot headless autoplay runner. Uses Godot's --headless flag (no weston,
# no Wayland, no X). Screenshots will be blank but turn_stats.jsonl /
# events.jsonl / saves/ are produced.
# Godot autoplay runner with two headless modes.
#
# RENDER_MODE=headless (default) — Godot --headless, no display server.
# Fastest. Screenshots blank. For bulk simulation / data collection.
#
# RENDER_MODE=weston — weston --backend=headless provides a virtual Wayland
# display with software rendering (llvmpipe). Screenshots work.
# Requires weston installed on the host.
set -uo pipefail
pkill -f "flatpak run.*Godot" 2>/dev/null || true
pkill -f godot 2>/dev/null || true
sleep 1
: "${AUTO_PLAY:=true}"
: "${AUTO_PLAY_DIR:=$HOME/tmp/ap_default}"
: "${AUTO_PLAY_TURN_LIMIT:=500}"
: "${RENDER_MODE:=headless}"
mkdir -p "$AUTO_PLAY_DIR"
cd "$HOME/Code/@projects/@magic-civilization/src/game"
SAFETY=$((AUTO_PLAY_TURN_LIMIT * 2 + 300))
FLATPAK_ENVS=(
"--env=AUTO_PLAY=true"
"--env=AUTO_PLAY_DIR=$AUTO_PLAY_DIR"
@ -20,9 +29,40 @@ FLATPAK_ENVS=(
if [ -n "${AUTO_PLAY_SEED:-}" ]; then
FLATPAK_ENVS+=("--env=AUTO_PLAY_SEED=$AUTO_PLAY_SEED")
fi
GODOT_ARGS=("--path" "." "--rendering-method" "gl_compatibility")
WESTON_PID=""
_cleanup() {
if [ -n "$WESTON_PID" ]; then
kill "$WESTON_PID" 2>/dev/null || true
wait "$WESTON_PID" 2>/dev/null || true
fi
}
trap _cleanup EXIT
if [ "$RENDER_MODE" = "weston" ]; then
if ! command -v weston >/dev/null 2>&1; then
echo "ERROR: RENDER_MODE=weston but weston not found" >&2
exit 1
fi
WESTON_SOCKET="godot-headless-$$"
weston --backend=headless --socket="$WESTON_SOCKET" --width=1920 --height=1080 \
>"$AUTO_PLAY_DIR/weston.log" 2>&1 &
WESTON_PID=$!
sleep 1
FLATPAK_ENVS+=(
"--socket=wayland"
"--env=WAYLAND_DISPLAY=$WESTON_SOCKET"
)
FLATPAK_ENVS+=("--filesystem=xdg-run/${WESTON_SOCKET}")
else
GODOT_ARGS+=("--headless")
fi
timeout "$SAFETY" flatpak run --user \
--filesystem=home \
"${FLATPAK_ENVS[@]}" \
org.godotengine.Godot --path . --headless 2>&1
org.godotengine.Godot "${GODOT_ARGS[@]}" 2>&1
EXIT=$?
echo "EXIT_CODE=$EXIT"

View file

@ -1,25 +1,21 @@
#!/bin/bash
# Headless seeded autoplay runner. No weston/Wayland — uses Godot --headless.
# Seeded autoplay runner. Delegates to run_ap3.sh with seed and turn limit.
#
# Usage: run_seeded.sh [seed=1] [turn_limit=200]
# Set RENDER_MODE=weston for screenshot-capable runs (default: headless).
set -uo pipefail
SEED="${1:-1}"
TURN_LIMIT="${2:-200}"
pkill -f "flatpak run.*Godot" 2>/dev/null || true
pkill -f godot 2>/dev/null || true
sleep 1
DIR="$HOME/tmp/ap_seeded_${SEED}"
rm -rf "$DIR"
mkdir -p "$DIR"
cd "$HOME/Code/@projects/@magic-civilization/src/game"
SAFETY=$((TURN_LIMIT * 2 + 300))
FLATPAK_ENVS=(
"--env=AUTO_PLAY=true"
"--env=AUTO_PLAY_SEED=$SEED"
"--env=AUTO_PLAY_TURN_LIMIT=$TURN_LIMIT"
"--env=AUTO_PLAY_DIR=$DIR"
)
timeout "$SAFETY" flatpak run --user \
--filesystem=home \
"${FLATPAK_ENVS[@]}" \
org.godotengine.Godot --path . --headless 2>&1
EXIT=$?
echo "EXIT_CODE=$EXIT"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
AUTO_PLAY=true \
AUTO_PLAY_SEED="$SEED" \
AUTO_PLAY_TURN_LIMIT="$TURN_LIMIT" \
AUTO_PLAY_DIR="$DIR" \
RENDER_MODE="${RENDER_MODE:-headless}" \
bash "$SCRIPT_DIR/run_ap3.sh"

View file

@ -1,7 +1,7 @@
#!/usr/bin/env bash
# autoplay-batch.sh — Run auto_play N times with different seeds and collect per-game output dirs.
#
# Usage: tools/autoplay-batch.sh [count=3] [turn_limit=500] [results_dir=/tmp/autoplay_batch]
# Usage: tools/autoplay-batch.sh [--weston] [count=3] [turn_limit=500] [results_dir]
#
# Output layout:
# <results_dir>/game_<stamp>_seed<N>/
@ -9,24 +9,39 @@
# turn_stats.jsonl
# events.jsonl
# game.log
# weston.log (local only)
# weston.log (weston mode only)
# *.save (per-turn saves, if configured)
#
# Environment:
# AUTOPLAY_HOST — If set (e.g. "lilith@apricot.local"), run each game via SSH using
# /tmp/run_ap3.sh on the remote host and scp results back.
# AUTOPLAY_HOST — If set (e.g. "lilith@apricot.local"), run each game via SSH
# using run_ap3.sh on the remote host and scp results back.
# If unset, run locally via flatpak (Linux only).
# RENDER_MODE — "headless" (default) or "weston". --weston flag sets this.
# headless: Godot --headless, no display, no screenshots.
# weston: weston headless backend, software rendering, screenshots work.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
GAME_DIR="$PROJECT_DIR/src/game"
REPO_ROOT="$PROJECT_DIR"
RENDER_MODE="${RENDER_MODE:-headless}"
# Parse --weston flag before positional args
POSITIONAL=()
for arg in "$@"; do
case "$arg" in
--weston) RENDER_MODE="weston" ;;
--headless) RENDER_MODE="headless" ;;
*) POSITIONAL+=("$arg") ;;
esac
done
set -- "${POSITIONAL[@]+"${POSITIONAL[@]}"}"
COUNT="${1:-3}"
TURN_LIMIT="${2:-500}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
RESULTS_DIR="${3:-$REPO_ROOT/.local/batches/autoplay_batch}"
if ! [[ "$COUNT" =~ ^[0-9]+$ ]] || [ "$COUNT" -lt 1 ]; then
@ -62,6 +77,7 @@ if [ -n "$AUTOPLAY_HOST" ]; then
else
echo "Mode: local flatpak"
fi
echo "Render: $RENDER_MODE"
echo "Safety timeout: ${SAFETY_TIMEOUT}s per game"
echo "============================================================"
@ -82,34 +98,50 @@ _run_local() {
_kill_stale_procs
echo "[seed $seed] Starting weston (headless)..."
WESTON_SOCKET="godot-headless-$$"
weston --backend=headless --socket="$WESTON_SOCKET" --width=1920 --height=1080 \
>"$game_dir/weston.log" 2>&1 &
WESTON_PID=$!
sleep 1
local WESTON_PID=""
local FLATPAK_ENVS=(
"--env=AUTO_PLAY=true"
"--env=AUTO_PLAY_SEED=$seed"
"--env=AUTO_PLAY_TURN_LIMIT=$TURN_LIMIT"
"--env=AUTO_PLAY_DIR=$game_dir"
)
local GODOT_ARGS=("--path" "$GAME_DIR" "--rendering-method" "gl_compatibility")
echo "[seed $seed] Launching Godot (timeout ${SAFETY_TIMEOUT}s)..."
WAYLAND_DISPLAY="$WESTON_SOCKET" \
if [ "$RENDER_MODE" = "weston" ]; then
if ! command -v weston >/dev/null 2>&1; then
echo "ERROR: --weston mode but weston not installed" >&2
exit 1
fi
WESTON_SOCKET="godot-headless-$$"
echo "[seed $seed] Starting weston (headless)..."
weston --backend=headless --socket="$WESTON_SOCKET" --width=1920 --height=1080 \
>"$game_dir/weston.log" 2>&1 &
WESTON_PID=$!
sleep 1
FLATPAK_ENVS+=(
"--socket=wayland"
"--env=WAYLAND_DISPLAY=$WESTON_SOCKET"
"--filesystem=xdg-run/${WESTON_SOCKET}"
)
else
GODOT_ARGS+=("--headless")
fi
echo "[seed $seed] Launching Godot ($RENDER_MODE, timeout ${SAFETY_TIMEOUT}s)..."
XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" \
timeout "$SAFETY_TIMEOUT" flatpak run --user \
--socket=wayland \
--env=WAYLAND_DISPLAY="$WESTON_SOCKET" \
--env=AUTO_PLAY=true \
--env=AUTO_PLAY_SEED="$seed" \
--env=AUTO_PLAY_TURN_LIMIT="$TURN_LIMIT" \
--env=AUTO_PLAY_DIR="$game_dir" \
org.godotengine.Godot \
--path "$GAME_DIR" \
--rendering-method gl_compatibility \
--headless \
--filesystem=home \
"${FLATPAK_ENVS[@]}" \
org.godotengine.Godot "${GODOT_ARGS[@]}" \
>"$game_dir/game.log" 2>&1 || {
local exit_code=$?
echo "[seed $seed] Godot exited with code $exit_code" >&2
}
kill "$WESTON_PID" 2>/dev/null || true
wait "$WESTON_PID" 2>/dev/null || true
if [ -n "$WESTON_PID" ]; then
kill "$WESTON_PID" 2>/dev/null || true
wait "$WESTON_PID" 2>/dev/null || true
fi
}
_run_remote() {
@ -136,6 +168,7 @@ _run_remote() {
AUTO_PLAY_SEED='$seed' \
AUTO_PLAY_TURN_LIMIT='$TURN_LIMIT' \
AUTO_PLAY_DIR='$remote_game_dir' \
RENDER_MODE='$RENDER_MODE' \
bash '$remote_runner' >'$remote_game_dir/game.log' 2>&1
" || {
echo "[seed $seed] SSH run exited with error — see $game_dir/game.log after scp" >&2