mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-08 12:35:01 +00:00
239 lines
8.0 KiB
Bash
Executable File
239 lines
8.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Run a flyby benchmark under tracy-capture and/or an in-process JFR profile
|
|
#
|
|
# * Launches the game with the flyby properties set and tracy-capture
|
|
# * Game waits for the tracy connection, runs the route, returns to the original coordinates and exits.
|
|
# * tracy-capture finalizes
|
|
#
|
|
# Usage: scripts/flyby-capture.sh <output.tracy|output.jfr> [route] [length] [extra gradle args...]
|
|
# route - straight | pan | circuit | static
|
|
# length - Units: blocks (straight), blocks per leg (circuit), degrees (pan), ticks (static).
|
|
# extra - passed through to gradle; -Dangelica.* reaches the client (e.g. -Dangelica.flyby.timeOfDay=1500).
|
|
# -Dangelica.flyby.camera=FIRST_PERSON|THIRD_PERSON_BACK|THIRD_PERSON_FRONT (default FIRST_PERSON).
|
|
# -Dangelica.flyby.dimension=<id> moves the player there first (1 = End), after world saving is off.
|
|
# -PclientJvmVendor=adoptium (macOS) picks the JVM vendor for runClient17/21/25.
|
|
#
|
|
# FLYBY_SPEED - blocks per tick. (0.5 ~= creative flight).
|
|
# FLYBY_PACING - UNCAPPED | CONFIGURED. Passed through when set.
|
|
# FLYBY_ORIGIN - x,z[,yaw] flight start. Unset or empty starts where the player is.
|
|
# QUICKPLAY_WORLD - save to auto-load (default: latest).
|
|
# FLYBY_SCENE - server command file run at flyby start.
|
|
# SDLGPU=0|1 - force OpenGL (0) or SDL-GPU (1); unset uses the build default.
|
|
# ALSO_JFR=1 - with a .tracy output, also record a JFR alongside it (timings inflated, correlation only).
|
|
# ASPROF_OPTS - comma separated async-profiler agent opts, passed through when a JFR is recorded.
|
|
#
|
|
# FLYBY_FULLSCREEN=0 - keep options.txt's window mode. Default: fullscreen:true for the run (avoids vsync pacing), restored on exit.
|
|
#
|
|
# The output extension selects the profiler: .tracy for Tracy, .jfr for an in-process async-profiler
|
|
# JFR that starts near the end of warmup and stops when the measured run ends.
|
|
#
|
|
# Requires tracy-capture on PATH (TRACY_CAPTURE=/path/to/tracy-capture) for .tracy output.
|
|
# QuickPlay loads QUICKPLAY_WORLD on launch; the run starts once the world is up.
|
|
#
|
|
# Ensure the chunks in the route have been generated before capturing
|
|
|
|
set -euo pipefail
|
|
|
|
# shellcheck source=flyby-lib.sh
|
|
. "$(dirname "$0")/flyby-lib.sh"
|
|
|
|
OUT="${1:?usage: flyby-capture.sh <output.tracy|output.jfr> [route] [length] [extra gradle args...]}"
|
|
ROUTE="${2:-straight}"
|
|
LENGTH="${3:-0}"
|
|
if [ $# -ge 3 ]; then
|
|
shift 3
|
|
else
|
|
shift $#
|
|
fi
|
|
WARMUP="${FLYBY_WARMUP:-400}"
|
|
TRACY_CAPTURE="${TRACY_CAPTURE:-tracy-capture}"
|
|
|
|
case "$OUT" in
|
|
*.tracy) MODE="tracy" ;;
|
|
*.jfr) MODE="jfr" ;;
|
|
*)
|
|
echo "usage: flyby-capture.sh <output.tracy|output.jfr> [route] [length] [extra gradle args...]" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
BACKEND_ARGS=()
|
|
if [ "${SDLGPU:-}" = "1" ]; then
|
|
BACKEND_ARGS+=(-Dangelica.sdlgpu.enable=true)
|
|
elif [ "${SDLGPU:-}" = "0" ]; then
|
|
BACKEND_ARGS+=(-Dangelica.sdlgpu.enable=false)
|
|
fi
|
|
if [ -n "${FLYBY_PACING:-}" ]; then
|
|
BACKEND_ARGS+=(-Dangelica.flyby.pacing="$FLYBY_PACING")
|
|
fi
|
|
if [ -n "${FLYBY_ORIGIN:-}" ]; then
|
|
BACKEND_ARGS+=(-Dangelica.flyby.origin="$FLYBY_ORIGIN")
|
|
fi
|
|
|
|
SCENE_ABS=""
|
|
SCENE_ARGS=()
|
|
if [ -n "${FLYBY_SCENE:-}" ]; then
|
|
case "$FLYBY_SCENE" in
|
|
/*) SCENE_ABS="$FLYBY_SCENE" ;;
|
|
*) SCENE_ABS="$PWD/$FLYBY_SCENE" ;;
|
|
esac
|
|
if [ ! -f "$SCENE_ABS" ]; then
|
|
echo "error: FLYBY_SCENE file not found: $SCENE_ABS" >&2
|
|
exit 1
|
|
fi
|
|
SCENE_ARGS+=(-Dangelica.flyby.commands="$SCENE_ABS")
|
|
fi
|
|
|
|
# JFR_OUT is set when a JFR is being recorded this run: always for MODE=jfr,
|
|
# additionally for MODE=tracy when ALSO_JFR=1 (both profilers active).
|
|
JFR_OUT=""
|
|
DISABLE_TRACY=0
|
|
if [ "$MODE" = "jfr" ]; then
|
|
JFR_OUT="$OUT"
|
|
DISABLE_TRACY=1
|
|
elif [ "${ALSO_JFR:-}" = "1" ]; then
|
|
JFR_OUT="${OUT%.tracy}.jfr"
|
|
fi
|
|
|
|
PROFILE_ARGS=()
|
|
JFR_ABS=""
|
|
if [ -n "$JFR_OUT" ]; then
|
|
JFR_DIR="$(dirname "$JFR_OUT")"
|
|
if [ ! -d "$JFR_DIR" ]; then
|
|
echo "error: directory for $JFR_OUT does not exist" >&2
|
|
exit 1
|
|
fi
|
|
JFR_ABS="$(cd "$JFR_DIR" && pwd)/$(basename "$JFR_OUT")"
|
|
if [ "$DISABLE_TRACY" = "1" ]; then
|
|
PROFILE_ARGS+=(-Dangelica.tracy=false)
|
|
fi
|
|
PROFILE_ARGS+=(-Dangelica.flyby.jfr=true -Dangelica.profile.output="$JFR_ABS")
|
|
if [ -n "${ASPROF_OPTS:-}" ]; then
|
|
PROFILE_ARGS+=(-Dangelica.profile.opts="$ASPROF_OPTS")
|
|
fi
|
|
fi
|
|
if [ "$MODE" = "tracy" ]; then
|
|
PROFILE_ARGS+=(-Dangelica.tracy=true)
|
|
fi
|
|
|
|
if [ "$MODE" = "tracy" ]; then
|
|
if ! command -v "$TRACY_CAPTURE" >/dev/null 2>&1 && [ ! -x "$TRACY_CAPTURE" ]; then
|
|
cat >&2 <<'EOF'
|
|
error: tracy-capture not found.
|
|
|
|
Build and launch with: TRACY_CAPTURE=/path/to/tracy/capture/build/tracy-capture scripts/flyby-capture.sh ...
|
|
EOF
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ -e "$OUT" ]; then
|
|
echo "error: $OUT already exists; refusing to overwrite a capture" >&2
|
|
exit 1
|
|
fi
|
|
if [ -n "$JFR_OUT" ] && [ "$JFR_OUT" != "$OUT" ] && [ -e "$JFR_OUT" ]; then
|
|
echo "error: $JFR_OUT already exists; refusing to overwrite a capture" >&2
|
|
exit 1
|
|
fi
|
|
|
|
WAIT_ARGS=()
|
|
CAPTURE_PID=""
|
|
if [ "$MODE" = "tracy" ]; then
|
|
WAIT_ARGS+=(-Dangelica.flyby.waitForTracy=true)
|
|
|
|
echo "==> starting capture -> $OUT"
|
|
if [ -n "${CAPTURE_SECONDS:-}" ]; then
|
|
"$TRACY_CAPTURE" -o "$OUT" -s "$CAPTURE_SECONDS" &
|
|
else
|
|
"$TRACY_CAPTURE" -o "$OUT" &
|
|
fi
|
|
CAPTURE_PID=$!
|
|
|
|
cleanup() {
|
|
if kill -0 "$CAPTURE_PID" 2>/dev/null; then
|
|
echo "==> stopping capture"
|
|
kill -INT "$CAPTURE_PID" 2>/dev/null || true
|
|
local waited=0
|
|
while kill -0 "$CAPTURE_PID" 2>/dev/null && { { [ -e "$OUT" ] && [ "$waited" -lt 600 ]; } || [ "$waited" -lt 120 ]; }; do
|
|
sleep 1
|
|
waited=$((waited + 1))
|
|
done
|
|
if kill -0 "$CAPTURE_PID" 2>/dev/null; then
|
|
echo "==> capture did not stop after ${waited}s (limit 120s before output exists, 600s after), killing it" >&2
|
|
kill -9 "$CAPTURE_PID" 2>/dev/null || true
|
|
fi
|
|
wait "$CAPTURE_PID" 2>/dev/null || true
|
|
fi
|
|
}
|
|
trap cleanup EXIT
|
|
fi
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
OPTIONS_TXT="$ROOT/run/client/options.txt"
|
|
FS_DIR="$(mktemp -d)"
|
|
|
|
on_exit() {
|
|
if [ -n "$CAPTURE_PID" ]; then
|
|
cleanup
|
|
fi
|
|
if [ "$FULLSCREEN" != 0 ]; then
|
|
flyby_fullscreen_restore "$OPTIONS_TXT" "$FS_DIR/options.txt.bak" || true
|
|
fi
|
|
rm -rf "$FS_DIR"
|
|
}
|
|
FULLSCREEN="${FLYBY_FULLSCREEN:-1}"
|
|
if [ "$FULLSCREEN" != 0 ]; then
|
|
flyby_fullscreen_on "$OPTIONS_TXT" "$FS_DIR/options.txt.bak"
|
|
fi
|
|
trap on_exit EXIT
|
|
|
|
echo "==> launching game (route=$ROUTE warmup=$WARMUP length=${LENGTH:-default} scene=${SCENE_ABS:-none})"
|
|
if [ -n "$JFR_OUT" ]; then
|
|
echo "==> recording JFR -> $JFR_ABS"
|
|
fi
|
|
if [ "$MODE" = "tracy" ] && [ -n "$JFR_OUT" ]; then
|
|
echo "==> both profilers active: timings inflated, use for correlation only"
|
|
fi
|
|
|
|
./gradlew runClient25 --console=plain \
|
|
-Dangelica.flyby.route="$ROUTE" \
|
|
-Dangelica.flyby.length="$LENGTH" \
|
|
-Dangelica.flyby.speed="${FLYBY_SPEED:-0}" \
|
|
-Dangelica.flyby.warmupTicks="$WARMUP" \
|
|
${WAIT_ARGS[@]+"${WAIT_ARGS[@]}"} \
|
|
-Dangelica.flyby.exitWhenDone=true \
|
|
-DquickPlaySingleplayer="${QUICKPLAY_WORLD:-latest}" \
|
|
${BACKEND_ARGS[@]+"${BACKEND_ARGS[@]}"} \
|
|
${SCENE_ARGS[@]+"${SCENE_ARGS[@]}"} \
|
|
${PROFILE_ARGS[@]+"${PROFILE_ARGS[@]}"} \
|
|
"$@"
|
|
|
|
echo "==> game exited, finalising capture"
|
|
if [ "$MODE" = "tracy" ]; then
|
|
cleanup
|
|
fi
|
|
|
|
if [ "$MODE" = "jfr" ]; then
|
|
if [ -s "$OUT" ]; then
|
|
echo "==> wrote $OUT ($(du -h "$OUT" | cut -f1))"
|
|
else
|
|
echo "error: $OUT is empty - did the run reach warmup?" >&2
|
|
exit 1
|
|
fi
|
|
else
|
|
if [ -s "$OUT" ]; then
|
|
echo "==> wrote $OUT ($(du -h "$OUT" | cut -f1))"
|
|
else
|
|
echo "error: $OUT is empty - did the game connect to Tracy?" >&2
|
|
exit 1
|
|
fi
|
|
if [ -n "$JFR_OUT" ]; then
|
|
if [ -s "$JFR_OUT" ]; then
|
|
echo "==> wrote $JFR_OUT ($(du -h "$JFR_OUT" | cut -f1))"
|
|
else
|
|
echo "error: $JFR_OUT is empty - did the run reach warmup?" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
fi
|