192 lines
6.7 KiB
Bash
Executable file
192 lines
6.7 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# ss — One-shot proof-scene screenshot capture.
|
|
#
|
|
# Usage:
|
|
# ./ss <name> # run scene locally (flatpak Godot on this host)
|
|
# ./ss --remote <host> <name> # rsync → ssh → weston+Godot → scp PNG back
|
|
# ./ss --remote <host> <name> [scene_path_override]
|
|
#
|
|
# `<name>` resolves a scene under `src/game/engine/scenes/tests/`:
|
|
# 1. `proof_<name>.tscn` (preferred — matches the project's proof-scene convention)
|
|
# 2. `<name>.tscn` (fallback)
|
|
#
|
|
# The chosen scene is launched as the main scene; it must self-capture
|
|
# its viewport into `user://screenshots/<name>.png`. (See proof scenes
|
|
# under `src/game/engine/scenes/tests/` for the pattern — they read
|
|
# `OS.get_environment("SCREENSHOT_NAME")` and call `Image.save_png`.)
|
|
#
|
|
# Output (local, after success): `screenshots/<name>.png` at repo root.
|
|
# `--remote` mode pulls the PNG back over scp.
|
|
#
|
|
# Why this wrapper exists:
|
|
# `tools/screenshot.sh` only knows two scenes (main_menu, game_setup) via
|
|
# the `capture_screenshot.gd` autoload. Proof scenes self-capture, so we
|
|
# bypass the autoload and launch the scene directly. `./ss --remote` is
|
|
# the path for mac-edit / apricot-run developers — the host check below
|
|
# prevents accidentally trying to flatpak-launch on macOS.
|
|
|
|
set -uo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
GODOT_PROJECT_NAME="Magic Civilization"
|
|
SCENES_REL_DIR="src/game/engine/scenes/tests"
|
|
|
|
REMOTE=""
|
|
NAME=""
|
|
SCENE_OVERRIDE=""
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--remote)
|
|
REMOTE="${2:-}"
|
|
if [[ -z "$REMOTE" ]]; then
|
|
echo "ss: --remote needs a host argument" >&2
|
|
exit 2
|
|
fi
|
|
shift 2
|
|
;;
|
|
-h|--help)
|
|
awk '/^# / { sub(/^# ?/, ""); print; next } NR>1 { exit }' "${BASH_SOURCE[0]}"
|
|
exit 0
|
|
;;
|
|
*)
|
|
if [[ -z "$NAME" ]]; then
|
|
NAME="$1"
|
|
elif [[ -z "$SCENE_OVERRIDE" ]]; then
|
|
SCENE_OVERRIDE="$1"
|
|
else
|
|
echo "ss: unexpected positional argument: $1" >&2
|
|
exit 2
|
|
fi
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "$NAME" ]]; then
|
|
echo "Usage: ./ss [--remote <host>] <name> [scene_path_override]" >&2
|
|
exit 2
|
|
fi
|
|
|
|
# Resolve scene path (relative to repo root).
|
|
if [[ -n "$SCENE_OVERRIDE" ]]; then
|
|
SCENE_REL="$SCENE_OVERRIDE"
|
|
elif [[ -f "$REPO_ROOT/$SCENES_REL_DIR/proof_$NAME.tscn" ]]; then
|
|
SCENE_REL="$SCENES_REL_DIR/proof_$NAME.tscn"
|
|
elif [[ -f "$REPO_ROOT/$SCENES_REL_DIR/$NAME.tscn" ]]; then
|
|
SCENE_REL="$SCENES_REL_DIR/$NAME.tscn"
|
|
else
|
|
echo "ss: scene not found — tried:" >&2
|
|
echo " $SCENES_REL_DIR/proof_$NAME.tscn" >&2
|
|
echo " $SCENES_REL_DIR/$NAME.tscn" >&2
|
|
echo "Pass a path explicitly: ./ss [--remote <host>] $NAME <scene_path>" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "$REPO_ROOT/$SCENE_REL" ]]; then
|
|
echo "ss: scene file does not exist: $SCENE_REL" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# `res://` paths are relative to `src/game/`, not the repo root.
|
|
SCENE_RES="res://${SCENE_REL#src/game/}"
|
|
LOCAL_OUT_DIR="$REPO_ROOT/screenshots"
|
|
LOCAL_OUT="$LOCAL_OUT_DIR/$NAME.png"
|
|
mkdir -p "$LOCAL_OUT_DIR"
|
|
|
|
run_remote() {
|
|
local host="$1"
|
|
local remote_repo
|
|
remote_repo="$(ssh -o ConnectTimeout=10 "$host" 'echo $HOME/Code/@projects/@magic-civilization')" || {
|
|
echo "ss: cannot reach $host" >&2
|
|
return 1
|
|
}
|
|
|
|
echo "ss: rsync → $host:$remote_repo"
|
|
rsync -az \
|
|
--exclude='target/' --exclude='pkg/' --exclude='.local/' \
|
|
--exclude='addons/*/*.so' --exclude='addons/*/*.dylib' --exclude='addons/*/*.dll' \
|
|
--exclude='node_modules/' --exclude='.git/' --exclude='screenshots/' \
|
|
"$REPO_ROOT/" "$host:$remote_repo/" >/dev/null
|
|
|
|
# Run scene under weston (virtual wayland → software-rendering Godot →
|
|
# viewport.get_texture().get_image() works under llvmpipe).
|
|
# The proof scene self-captures to user://screenshots/<NAME>.png and quits.
|
|
local remote_script
|
|
remote_script=$(cat <<REMOTE_EOF
|
|
set -uo pipefail
|
|
cd "$remote_repo/src/game"
|
|
SOCKET="ss-\$\$"
|
|
weston --backend=headless --socket="\$SOCKET" --width=1280 --height=720 \
|
|
>/tmp/ss-weston.log 2>&1 &
|
|
WESTON_PID=\$!
|
|
trap 'kill \$WESTON_PID 2>/dev/null || true' EXIT
|
|
sleep 1
|
|
timeout 90 flatpak run --user \
|
|
--filesystem=home \
|
|
--socket=wayland \
|
|
--env=WAYLAND_DISPLAY="\$SOCKET" \
|
|
--env=SCREENSHOT_NAME="$NAME" \
|
|
--filesystem="xdg-run/\$SOCKET" \
|
|
org.godotengine.Godot \
|
|
--path . \
|
|
--rendering-method gl_compatibility \
|
|
--quit-after 200 \
|
|
"$SCENE_RES" 2>&1 | tail -40
|
|
echo "ss: scene exit code \$?"
|
|
REMOTE_EOF
|
|
)
|
|
ssh "$host" bash -s <<< "$remote_script"
|
|
|
|
# The proof scene self-captures to user://screenshots/<NAME>.png AND the
|
|
# capture_screenshot.gd autoload also fires (it triggers on SCREENSHOT_NAME),
|
|
# writing user://screenshots/<NAME>_<timestamp>.png. Both end up under
|
|
# the flatpak userdata dir; we resolve the newest match by globbing both
|
|
# patterns on the remote and copying the most recent.
|
|
# Quote the project name on the remote side so the embedded space in
|
|
# "Magic Civilization" survives `ssh "$host" "<command>"`.
|
|
local remote_glob_cmd
|
|
printf -v remote_glob_cmd 'ls -t "$HOME/.var/app/org.godotengine.Godot/data/godot/app_userdata/%s/screenshots/"%s*.png 2>/dev/null | head -1' \
|
|
"$GODOT_PROJECT_NAME" "$NAME"
|
|
local remote_png
|
|
remote_png="$(ssh "$host" "$remote_glob_cmd")"
|
|
if [[ -z "$remote_png" ]]; then
|
|
echo "ss: no PNG matching ${NAME}*.png on $host. Check /tmp/ss-weston.log on $host and the Godot output above." >&2
|
|
return 1
|
|
fi
|
|
if scp "$host:$remote_png" "$LOCAL_OUT" 2>/dev/null; then
|
|
echo "ss: captured → $LOCAL_OUT (from $remote_png)"
|
|
return 0
|
|
fi
|
|
echo "ss: scp failed for $remote_png" >&2
|
|
return 1
|
|
}
|
|
|
|
run_local() {
|
|
if ! command -v flatpak >/dev/null 2>&1; then
|
|
echo "ss: local mode requires flatpak Godot. On macOS, use: ./ss --remote apricot $NAME" >&2
|
|
return 2
|
|
fi
|
|
cd "$REPO_ROOT/src/game"
|
|
timeout 90 flatpak run --user \
|
|
--env=SCREENSHOT_NAME="$NAME" \
|
|
org.godotengine.Godot \
|
|
--path . \
|
|
--rendering-method gl_compatibility \
|
|
--quit-after 200 \
|
|
"$SCENE_RES" 2>&1 | tail -40
|
|
local userdata_png="$HOME/.var/app/org.godotengine.Godot/data/godot/app_userdata/$GODOT_PROJECT_NAME/screenshots/$NAME.png"
|
|
if [[ -f "$userdata_png" ]]; then
|
|
cp "$userdata_png" "$LOCAL_OUT"
|
|
echo "ss: captured → $LOCAL_OUT"
|
|
return 0
|
|
fi
|
|
echo "ss: screenshot not written at $userdata_png" >&2
|
|
return 1
|
|
}
|
|
|
|
if [[ -n "$REMOTE" ]]; then
|
|
run_remote "$REMOTE"
|
|
else
|
|
run_local
|
|
fi
|