126 lines
4.3 KiB
Bash
Executable File
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"
|