工程(基线合一批·golden单基线跨平台+补锚14张+审核关卡立规): 分平台基线机制拆除(2026-11-08用户裁:跨平台渲染必须一致,禁加基线消化差异)——windows 6件基线提升到golden/根,删windows/mac两平台目录与根目录遗留(level_map.png+边车,零引用核实); 闸件去平台化(render_gate.sh GOLDEN直拼/golden_compare.py删_PLAT与plat_missing/golden_baseline_refresh.sh落点改根+--screens换代入口); 拆自愈采集(ci.yml步+tools/ci/golden_selfheal.sh——CI自动落基线=既当裁判又当选手,测量数据已采完退役); 补锚14张(用户裁:发现少了就补,备案清零)——shot_probe扩九态(营地五窗真点热点开窗/图例真点钮/战末结算与三选一直调喂真实形态文案/调试浮窗直调)+battle段呼吸相位冻结(motion_scale0.5+1.2s动画完结锚定,board_shot同款)+热点键→基线语义名映射(dummy→tree/board→codex); 渲染闸屏态浮层golden段(golden_compare 14面)+shot_checker 16屏清单; 基线审核关卡立规(test-conventions §8.2:逐张审核确认后才入库生效+审核记录落档+非卡片批基线操作同关卡;process-conventions五·实现行:未审核的基线禁合回;req-card/iter技能特殊标注——豁免面直改); 实测依据: mac真渲染vs windows基线四指标(棋盘0.025~0.033%/menu 0.674% changed,RGB零色偏,块平均≈0)全在容差带内——数据归档reports/基线合一批-反哺点-2026-11-08.md; 读数: shot_probe直跑16图问题=0+渲染闸直跑exit=0(20面全PASS,新候选changed=0.00%)+bash -n×3+py_compile+文档域闸绿; 基线审核记录: 20张全部DKChan 2026-11-08确认(README审核记录节)

This commit is contained in:
DKChan committed 2026-11-08 23:19:47 +08:00
1 parent 26a01c026f
commit 126e583fed
38 files changed
+263 -110

No files matched your search

-43
View File
@@ -1,43 +0,0 @@
#!/usr/bin/env bash
# 棋盘黄金图 CI 自愈补采(2026-11-08 用户裁:补采自动化——渲染能力在 runner 会话里,人手不做二进制搬运)。
# 背景:golden 基线按平台分目录(render_gate.sh:37 gate_platform_id),改版批只能重制本平台侧;
# 他平台基线缺失=渲染闸红(基准未建),而补采必须在他平台真实渲染——只有 runner 会话做得到。
# 本件挂 CI full 批(ci.yml 导入步之后、跑闸步之前):缺棋盘三件基线时跑 golden_baseline_refresh
# 棋盘模式,产物提交回 master 并推送,下一轮 full 批拉取后渲染闸绿。
# 护栏:
# - 只认 CI 跑批环境(GITHUB_WORKSPACE 必在)——本地误跑立即拒(防人手把本平台基线提交出去)。
# - 三件基线齐盘即零动作退出(幂等——不会每轮提交,无循环)。
# - 只 add 三件 PNG;刷新红/落盘缺/提交败/push 败一律置红不静默,下一轮 full 批自动重试。
set -u
: "${GITHUB_WORKSPACE:?本件只属 CI 跑批环境(GITHUB_WORKSPACE 必在)——人手补采走 tools/golden_baseline_refresh.sh}"
REPO="$(cd "$(dirname "$0")/../.." && pwd)"
cd "$REPO"
. "$REPO/tools/gate_platform.sh"
PLAT="$(gate_platform_id)"
GOLDEN_DIR="game/tests/golden/$PLAT"
BOARD_FILES="board_L1_dungeon.png board_L2_underdark.png board_L3_deep_underdark.png"
_miss=0
for b in $BOARD_FILES; do
[ -s "$GOLDEN_DIR/$b" ] || { _miss=1; echo "[selfheal] 缺基准: $GOLDEN_DIR/$b"; }
done
if [ "$_miss" -eq 0 ]; then
echo "[selfheal] $PLAT 棋盘三件基线在库——零动作(幂等护栏)"
exit 0
fi
GODOT_BIN="${GODOT_BIN:?GODOT_BIN 必注(runner 自举件安装位)}" \
bash "$REPO/tools/golden_baseline_refresh.sh" game || {
echo "[selfheal] FAIL — 补采刷新脚本红(探针自检/裁剪失败见上)"; exit 1
}
for b in $BOARD_FILES; do
[ -s "$GOLDEN_DIR/$b" ] || { echo "[selfheal] FAIL — 刷新后仍缺: $b"; exit 1; }
done
for b in $BOARD_FILES; do
git add "$GOLDEN_DIR/$b"
done
git -c user.name="gitea-actions" -c user.email="actions@noreply.git.kuaimeo.com" \
commit -m "黄金图自愈补采($PLAT·棋盘三件): 渲染闸缺基准——golden_baseline_refresh棋盘模式在runner会话渲染产出,本提交由CI采集步自动落库,下一轮full批拉取后渲染闸绿;触发源提交见父提交" \
|| { echo "[selfheal] FAIL — git commit 失败(无差异或工作区异常)"; exit 1; }
git push origin HEAD:master || { echo "[selfheal] FAIL — push 失败(令牌权限/分支保护;修复前每轮 full 批会重试)"; exit 1; }
echo "[selfheal] 完成 — 基线已落库,下一轮 CI 拉取生效"
+50 -12
View File
@@ -5,8 +5,12 @@
# 缺位时先拷主区素材+导入边车再跑)。
# 模式:
# --menu:shot_probe 启动态菜单整屏帧 → game/tests/golden/menu_boot.png。
# --screens:shot_probe 十六图(七屏+营地五窗+四浮层)全量采集 → 按基线名 cp 入库
# (camp_screen/settings_screen/battle_screen/career_screen/status_panel/camp_forge/
# camp_chest/camp_tree/camp_codex/camp_notebook/battle_end/curio_pick/legend/debug_overlay
# ——golden 补锚批 2026-11-08)。候选图仍须用户逐张审核确认后才算冻结(审核关卡)。
# --lmap:level_map_shot_probe 关卡视口两 Shot(入口停点+Boss 列锚定——2026-11-05 用户裁
# 两 Shot 面)→ game/tests/golden/<plat>/lmap_entry.png + lmap_boss.png。
# 两 Shot 面)→ game/tests/golden/lmap_entry.png + lmap_boss.png。
# 全屏基线可行性前置已验证:菜单连续帧差 0.0000%/max_diff=0(光柱为
# 程序生成静态贴片、零动画着色器,全屏基线不抖动);采集确定性=探针隔离档(无断点+出厂
# 设置 1280×800),与 render_gate 的 shot_menu 对比段同源同帧。
@@ -24,12 +28,13 @@ for a in "$@"; do
case "$a" in
--menu) MODE="menu" ;;
--lmap) MODE="lmap" ;;
--screens) MODE="screens" ;;
*) if [ -z "$GAME" ]; then GAME="$a"; fi ;;
esac
done
GAME="${GAME:-$REPO/game}"
GAME_WIN="$(gate_game_path "$GAME")" # Godot --path 接受形式(Windows 混合斜杠,其他平台原样)
PLAT="$(gate_platform_id)" # 基线落点=本平台子目录(game/tests/golden/<windows|mac|linux>/)
GOLDEN="$REPO/game/tests/golden" # 单基线跨平台落点(2026-11-08 用户裁,无平台子目录)
TMP="$(mktemp -d /tmp/goldenrefresh_XXXXXX)"
trap 'rm -rf "$TMP"' EXIT
@@ -50,9 +55,42 @@ if [ "$MODE" = "menu" ]; then
echo "[golden_refresh] FAIL — 菜单截图缺失或 shot_probe 自检红(st=$st,见上)"
exit 1
fi
mkdir -p "$REPO/game/tests/golden/$PLAT"
cp "$TMP/shots/shot_menu.png" "$REPO/game/tests/golden/$PLAT/menu_boot.png" || exit 1
echo "[golden_refresh] 完成 — 菜单全屏基线已代入 game/tests/golden/$PLAT/menu_boot.png(提交说明须写明触发原因)"
mkdir -p "$GOLDEN"
cp "$TMP/shots/shot_menu.png" "$GOLDEN/menu_boot.png" || exit 1
echo "[golden_refresh] 完成 — 菜单全屏基线已代入 game/tests/golden/menu_boot.png(提交说明须写明触发原因)"
exit 0
fi
if [ "$MODE" = "screens" ]; then
# 七屏+九态候选基线采集(golden 补锚批 2026-11-08):跑完整 shot_probe(十六图+meta),
# 全部按基线名 cp 入库——候选图仍须用户逐张审核确认后才算冻结(审核关卡=README「基线冻结与审核」)。
for a in assets/fonts/ui_font_fusion_pixel_zh_hans.ttf \
assets/art/ui/button_stone.png; do
if [ ! -f "$GAME/$a" ]; then
echo "[golden_refresh] 拒跑 — 素材缺位: ${a}(S3 停机点口径)"
exit 1
fi
done
gate_run_timeout 420 "$TMP/run.log" "$G" --path "$GAME_WIN" --quit-after 3000 res://probe/shot_probe.tscn -- "$TMP/shots"
st=$?
grep -E "\[shot_probe\]" "$TMP/run.log" | tail -3
if ! grep -q "问题=0" "$TMP/run.log"; then
echo "[golden_refresh] FAIL — shot_probe 自检红(st=$st,见上)"
exit 1
fi
mkdir -p "$GOLDEN"
for m in "shot_camp.png camp_screen.png" "shot_settings.png settings_screen.png" \
"shot_battle.png battle_screen.png" "shot_career.png career_screen.png" \
"shot_status.png status_panel.png" "shot_camp_forge.png camp_forge.png" \
"shot_camp_chest.png camp_chest.png" "shot_camp_tree.png camp_tree.png" \
"shot_camp_codex.png camp_codex.png" "shot_camp_notebook.png camp_notebook.png" \
"shot_battle_end.png battle_end.png" "shot_curio_pick.png curio_pick.png" \
"shot_legend.png legend.png" "shot_debug.png debug_overlay.png"; do
set -- $m
[ -s "$TMP/shots/$1" ] || { echo "[golden_refresh] FAIL — 候选缺失: $1"; exit 1; }
cp "$TMP/shots/$1" "$GOLDEN/$2" || exit 1
done
echo "[golden_refresh] 完成 — 14 张屏态/浮层候选基线已代入 game/tests/golden/(呈报用户逐张审核后随批提交)"
exit 0
fi
@@ -77,10 +115,10 @@ if [ "$MODE" = "lmap" ]; then
echo "[golden_refresh] FAIL — 关卡视口截图缺失或探针自检红(st=$st,见上)"
exit 1
fi
mkdir -p "$REPO/game/tests/golden/$PLAT"
cp "$TMP/shots/lmap_entry.png" "$REPO/game/tests/golden/$PLAT/lmap_entry.png" || exit 1
cp "$TMP/shots/lmap_boss.png" "$REPO/game/tests/golden/$PLAT/lmap_boss.png" || exit 1
echo "[golden_refresh] 完成 — 关卡视口两 Shot 基线已代入 game/tests/golden/$PLAT/(提交说明须写明触发原因)"
mkdir -p "$GOLDEN"
cp "$TMP/shots/lmap_entry.png" "$GOLDEN/lmap_entry.png" || exit 1
cp "$TMP/shots/lmap_boss.png" "$GOLDEN/lmap_boss.png" || exit 1
echo "[golden_refresh] 完成 — 关卡视口两 Shot 基线已代入 game/tests/golden/(提交说明须写明触发原因)"
exit 0
fi
@@ -105,8 +143,8 @@ if [ ! -s "$TMP/shots/board_meta.json" ] || ! grep -q "PASS — 三关双帧取
exit 1
fi
python3 tools/golden_board_crop.py "$TMP/shots/board_meta.json" "$TMP/shots" "$TMP/crop" || exit 1
mkdir -p "$REPO/game/tests/golden/$PLAT"
mkdir -p "$GOLDEN"
for b in board_L1_dungeon.png board_L2_underdark.png board_L3_deep_underdark.png; do
cp "$TMP/crop/$b" "$REPO/game/tests/golden/$PLAT/$b" || exit 1
cp "$TMP/crop/$b" "$GOLDEN/$b" || exit 1
done
echo "[golden_refresh] 完成 — 三张基线已换代入 game/tests/golden/$PLAT/(提交说明须写明触发原因)"
echo "[golden_refresh] 完成 — 三张基线已换代入 game/tests/golden/(提交说明须写明触发原因)"
+5 -10
View File
@@ -19,13 +19,9 @@ from PIL import Image, ImageChops
TOLERANCE = 16 # 灰度差容差(单通道)
FAIL_RATIO = 0.02 # changed 占比失败线
# 基线平台子目录:<黄金图根目录>/<windows|mac|linux>——渲染基线按平台各存(gate_platform_id 同口径),
# 平台内部照常逐像素严格比对;跨平台不互比(字形/抗锯齿机制差异,2026-11-03 用户裁)。
_PLAT = {"win32": "windows", "darwin": "mac"}.get(sys.platform, "linux")
def plat_missing(base: Path) -> bool:
return not (base / _PLAT).is_dir()
# 单基线跨平台(2026-11-08 用户裁:跨平台渲染必须一致)——全平台对拍同一份基线,
# 跨平台字形锯齿噪声由容差带吸收(实测:棋盘 ≤0.033% / menu ≤0.68% changed,预算 ≤2%);
# 超容差即红(视觉回归或跨平台失配,均须人工排查,禁加基线消化)。
def compare(base: Path, curr: Path, name: str, failures: list) -> None:
@@ -56,10 +52,9 @@ def main() -> int:
print("用法: python tools/golden_compare.py <黄金图目录> <新截图目录> [屏清单...]")
return 1
base, curr = Path(sys.argv[1]), Path(sys.argv[2])
base = base / _PLAT
if not base.is_dir():
print("[golden] FAIL — 本平台(%s)基线目录未建:%s" % (_PLAT, base))
print(" 处置:在该平台跑 tools/golden_baseline_refresh.sh 重制基线并提交(基线换代权限 Q6)")
print("[golden] FAIL — 基线目录未建:%s" % base)
print(" 处置:跑 tools/golden_baseline_refresh.sh 重制基线并提交(基线换代权限 Q6)")
return 1
shots = sys.argv[3:] or ["shot_menu.png", "shot_camp.png", "shot_level.png", "shot_battle.png"]
failures = []
+36 -8
View File
@@ -34,7 +34,7 @@ REPO="$(cd "$(dirname "$0")/.." && pwd)"
. "$REPO/tools/gate_platform.sh" # 跨平台件(平台探测/路径形式/带超时执行/孤儿清杀)
GAME="${1:-$REPO/game}"
GAME_WIN="$(gate_game_path "$GAME")" # Godot --path 接受形式(Windows 混合斜杠,其他平台原样)
GOLDEN="$REPO/game/tests/golden/$(gate_platform_id)" # 本平台基线目录(按平台各存,比较器同口径)
GOLDEN="$REPO/game/tests/golden" # 单基线跨平台(2026-11-08 用户裁:跨平台渲染必须一致,差异由容差带吸收)
TMP="$(mktemp -d /tmp/rendergate_XXXXXX)"
trap 'rm -rf "$TMP"' EXIT
_rc=0
@@ -75,7 +75,7 @@ if ! grep -q "问题=0" "$TMP/shot.log"; then
echo "[render_gate] FAIL — shot_probe 未干净完成(exit=${st},缺失屏/空文件/路径断裂见上)"; _rc=1
fi
if [ "$_rc" -eq 0 ]; then
python3 tools/shot_checker.py "$SHOT" shot_menu.png shot_settings.png shot_career.png shot_camp.png shot_level.png shot_battle.png shot_status.png | sed 's/^/[render_gate] /'
python3 tools/shot_checker.py "$SHOT" shot_menu.png shot_settings.png shot_career.png shot_camp.png shot_level.png shot_battle.png shot_status.png shot_camp_forge.png shot_camp_chest.png shot_camp_tree.png shot_camp_codex.png shot_camp_notebook.png shot_battle_end.png shot_curio_pick.png shot_legend.png shot_debug.png | sed 's/^/[render_gate] /'
_rc="${PIPESTATUS[0]}"
[ "$_rc" -ne 0 ] && echo "[render_gate] FAIL — shot_checker A-D 断言存在红(S1 停机点:首跑存量 FAIL 全量呈报登记待办清单)"
fi
@@ -118,7 +118,7 @@ done
echo "======== 棋盘 golden 逐像素(T2——裁剪→对比,容差 provisional) ========"
if [ ! -d "$GOLDEN" ]; then
echo "[render_gate] FAIL — 本平台($(gate_platform_id))基线目录缺失:${GOLDEN}(基线按平台各存、在库=验收断言②)"; _rc=1
echo "[render_gate] FAIL — 基线目录缺失:${GOLDEN}(基线入库=验收断言②)"; _rc=1
elif [ ! -s "$BD/board_meta.json" ]; then
echo "[render_gate] SKIP — board_meta.json 缺失(取证段已红),golden 对比不判"
else
@@ -150,7 +150,7 @@ fi
echo "======== 菜单 golden 逐像素(迭代 28 T4——启动态全屏基线)========"
if [ ! -s "$GOLDEN/menu_boot.png" ]; then
echo "[render_gate] FAIL — $GOLDEN/menu_boot.png 基线缺失(菜单 golden 未建——本平台跑 tools/golden_baseline_refresh.sh --menu)"; _rc=1
echo "[render_gate] FAIL — $GOLDEN/menu_boot.png 基线缺失(菜单 golden 未建——跑 tools/golden_baseline_refresh.sh --menu)"; _rc=1
elif [ ! -s "$SHOT/shot_menu.png" ]; then
echo "[render_gate] SKIP — shot_menu.png 缺失(shot_probe 段已红),菜单 golden 不判"
elif [ ! -f "$GAME/assets/fonts/ui_font_fusion_pixel_zh_hans.ttf" ] || [ ! -f "$GAME/assets/art/ui/button_stone.png" ]; then
@@ -159,12 +159,41 @@ else
MENUG="$TMP/menugolden"
mkdir -p "$MENUG"
cp "$SHOT/shot_menu.png" "$MENUG/menu_boot.png"
python3 tools/golden_compare.py "$REPO/game/tests/golden" "$MENUG" menu_boot.png | sed 's/^/[render_gate] /'
python3 tools/golden_compare.py "$REPO/game/tests/golden" "$MENUG" menu_boot.png | sed 's/^/[render_gate] /'
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
echo "[render_gate] FAIL — 菜单 golden 超容差(S2 停机点口径:核对热区——按钮换墨/布局变更属预期面=显式重制基线+呈报;超预期面=L3)"; _rc=1
fi
fi
echo "======== 屏态/浮层 golden 逐像素(golden 补锚批 2026-11-08——七屏锚+营地五窗+四浮层)========"
if [ ! -s "$SHOT/shot_camp.png" ]; then
echo "[render_gate] SKIP — shot_camp.png 缺失(shot_probe 段已红),屏态/浮层 golden 不判"
else
SG="$TMP/sgolden"
mkdir -p "$SG"
cp "$SHOT/shot_camp.png" "$SG/camp_screen.png"
cp "$SHOT/shot_settings.png" "$SG/settings_screen.png"
cp "$SHOT/shot_battle.png" "$SG/battle_screen.png"
cp "$SHOT/shot_career.png" "$SG/career_screen.png"
cp "$SHOT/shot_status.png" "$SG/status_panel.png"
cp "$SHOT/shot_camp_forge.png" "$SG/camp_forge.png"
cp "$SHOT/shot_camp_chest.png" "$SG/camp_chest.png"
cp "$SHOT/shot_camp_tree.png" "$SG/camp_tree.png"
cp "$SHOT/shot_camp_codex.png" "$SG/camp_codex.png"
cp "$SHOT/shot_camp_notebook.png" "$SG/camp_notebook.png"
cp "$SHOT/shot_battle_end.png" "$SG/battle_end.png"
cp "$SHOT/shot_curio_pick.png" "$SG/curio_pick.png"
cp "$SHOT/shot_legend.png" "$SG/legend.png"
cp "$SHOT/shot_debug.png" "$SG/debug_overlay.png"
python3 tools/golden_compare.py "$REPO/game/tests/golden" "$SG" \
camp_screen.png settings_screen.png battle_screen.png career_screen.png status_panel.png \
camp_forge.png camp_chest.png camp_tree.png camp_codex.png camp_notebook.png \
battle_end.png curio_pick.png legend.png debug_overlay.png | sed 's/^/[render_gate] /'
if [ "${PIPESTATUS[0]}" -ne 0 ]; then
echo "[render_gate] FAIL — 屏态/浮层 golden 超容差(S2 停机点口径:核对热区——预期面=显式重制基线+呈报审核;超预期面=L3)"; _rc=1
fi
fi
echo "======== 关卡视口 golden 逐像素(卷轴视口批——两 Shot 面:入口停点+Boss 列锚定)========"
LM="$TMP/lmapshots"
@@ -182,9 +211,8 @@ scan_log "level_map_shot_probe" "$TMP/lm.log"
if [ "$_rc" -eq 0 ]; then
for b in lmap_entry.png lmap_boss.png; do
if [ ! -s "$GOLDEN/$b" ]; then
# 两 Shot 面(2026-11-05 用户裁)各平台独立冻结——本平台缺基线=未冻结态记 SKIP 不判红
#(windows 先锚;他平台冻结义务归收尾呈报),已锚平台照常逐像素严判
echo "[render_gate] SKIP — $GOLDEN/$b 基线缺失(本平台未冻结——跑 tools/golden_baseline_refresh.sh --lmap)"
# 两 Shot 面(2026-11-05 用户裁)缺基线=未冻结态记 SKIP 不判红(先锚后盯),已锚照常逐像素严判
echo "[render_gate] SKIP — $GOLDEN/$b 基线缺失(未冻结——跑 tools/golden_baseline_refresh.sh --lmap)"
else
LMG="$TMP/lmgolden"
mkdir -p "$LMG"