Files
mtgodot-poc/script/run_client_gate.sh
T

126 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Run one exported client process and seal its report after exit.
# This script owns exactly one child PID; it never pkills other clients.
set -euo pipefail
cd "$(dirname "$0")/.."
app_path="${MT_PLAYABLE_APP:-$PWD/build/export-native-trees-20260911/mtgodot-poc.app}"
mode="playable"
config_path=""
output_dir="${MT_PLAYABLE_OUTPUT:-$PWD/build/playable/run-$(date +%Y%m%d-%H%M%S)-$$}"
timeout_seconds="${MT_PLAYABLE_TIMEOUT_SECONDS:-180}"
allow_gameplay=0
usage() {
cat <<'EOF'
用法: script/run_client_gate.sh --app APP --config CONFIG [选项]
选项:
--output DIR 本次运行目录,必须不存在或为空
--mode MODE 默认 playable
--timeout-seconds N 墙钟超时,默认 180
--allow-gameplay 允许专用测试账号发送移动/战斗/拾取请求
EOF
}
while [ "$#" -gt 0 ]; do
case "$1" in
--app) app_path="$2"; shift 2 ;;
--config) config_path="$2"; shift 2 ;;
--output) output_dir="$2"; shift 2 ;;
--mode) mode="$2"; shift 2 ;;
--timeout-seconds) timeout_seconds="$2"; shift 2 ;;
--allow-gameplay) allow_gameplay=1; shift ;;
--help) usage; exit 0 ;;
*) echo "未知选项: $1" >&2; usage >&2; exit 2 ;;
esac
done
if [ -z "$config_path" ] || [ ! -f "$config_path" ]; then
echo "配置不存在;不会启动客户端:$config_path" >&2
exit 2
fi
if [ ! -x "$app_path/Contents/MacOS/mtgodot-poc" ]; then
echo "找不到可执行包:$app_path" >&2
exit 2
fi
if ! [[ "$timeout_seconds" =~ ^[1-9][0-9]*$ ]]; then
echo "timeout-seconds 必须是正整数" >&2
exit 2
fi
if [ -e "$output_dir" ] && [ "$(find "$output_dir" -mindepth 1 -maxdepth 1 -print -quit)" ]; then
echo "输出目录已有内容,拒绝复用历史报告:$output_dir" >&2
exit 2
fi
mkdir -p "$output_dir"
log="$output_dir/client.log"
client_report="$output_dir/client-report.json"
final_report="$output_dir/report.json"
events="$output_dir/events.jsonl"
if ! MT_PLAYABLE_VALIDATE_CONFIG="$config_path" godot --headless --path project --script playable_config_gate.gd >"$output_dir/config.log" 2>&1; then
echo "配置校验失败;不会启动客户端:$output_dir/config.log" >&2
exit 2
fi
char_slot="$(node -e 'const fs=require("node:fs"); const p=process.argv[1]; const d=JSON.parse(fs.readFileSync(p,"utf8")); process.stdout.write(String(d.character_slot));' "$config_path")"
sha256_of() {
if [ -f "$1" ]; then shasum -a 256 "$1" | awk '{print $1}'; else echo ""; fi
}
engine="$app_path/Contents/MacOS/mtgodot-poc"
pck="$app_path/Contents/Resources/mtgodot-poc.pck"
dylib="$(find "$app_path/Contents/Frameworks" -maxdepth 1 -type f -name '*.dylib' -print -quit)"
export MT_TEST_MODE="$mode"
export MT_PLAYABLE_CONFIG="$config_path"
export MT_TEST_REPORT="$client_report"
export MT_TEST_EVENTS="$events"
export MT_TEST_OUTPUT="$output_dir"
export MT_PROTOCOL="classic"
export MT_AUTOLOGIN=1
export MT_CHAR_SLOT="$char_slot"
export MT_PLAYABLE_RUN_ID="$(basename "$output_dir")"
export MT_BUILD_ENGINE_SHA256="$(sha256_of "$engine")"
export MT_BUILD_EXTENSION_SHA256="$(sha256_of "$dylib")"
export MT_BUILD_PCK_SHA256="$(sha256_of "$pck")"
file_description="$(file "$engine")"
case "$file_description" in
*arm64*) export MT_BUILD_ARCH="arm64" ;;
*x86_64*) export MT_BUILD_ARCH="x86_64" ;;
*) export MT_BUILD_ARCH="unknown" ;;
esac
if [ "$allow_gameplay" -eq 1 ]; then export MT_PLAYABLE_ALLOW_GAMEPLAY=1; else export MT_PLAYABLE_ALLOW_GAMEPLAY=0; fi
start_epoch="$(date +%s)"
set +e
env -u MT_ASSETS "$engine" >"$log" 2>&1 &
child_pid=$!
timed_out=0
while kill -0 "$child_pid" 2>/dev/null; do
now="$(date +%s)"
if [ $((now - start_epoch)) -ge "$timeout_seconds" ]; then
timed_out=1
kill -TERM "$child_pid" 2>/dev/null || true
for _ in 1 2 3 4 5 6 7 8 9 10; do
kill -0 "$child_pid" 2>/dev/null || break
sleep 1
done
kill -KILL "$child_pid" 2>/dev/null || true
break
fi
sleep 1
done
wait "$child_pid"
app_status=$?
set -e
if [ "$timed_out" -eq 1 ]; then app_status=124; fi
set +e
node script/validate_playable_report.mjs --report "$client_report" --output "$final_report" \
--log "$log" --process-code "$app_status" --require-pass
gate_status=$?
set -e
if [ "$app_status" -ne 0 ] || [ "$gate_status" -ne 0 ]; then
echo "PLAYABLE GATE: FAIL exit=$app_status report=$final_report log=$log" >&2
exit 1
fi
echo "PLAYABLE GATE: PASS report=$final_report log=$log"