上个会话把 `launcher="fabric"` 写进了后端,却**没有留下任何可重跑的验证** ——
「经加载器能起来」这件事只活在对话里。本次把它变成可复算的。
## 机制(路线 C,不是 LOADERS.md 原来写的 A/B)
A/B 都假设「游戏由 Loader 起」。但 `Knot.init()` 是 public 的:它做完
「发现 mod → 建 KnotClassLoader → 应用 mixin → invokeEntrypoints(preLaunch)」
后**返回**,不进入官方主循环(那在 GameProvider.launch())。
⇒ `knot.loadIntoTarget("McfoldRenderServer")` 把我们的服务端注入同一个
KnotClassLoader —— **mod 生态与我们的控制权同时拿到,不必把服务改写成 mod**。
## 主要改动
### ① `RenderBackend._fabric_classpath()` —— 组装从用户手里移到后端
两个变换是实测必需、且用户不该自己拼的机械操作:
- 剔除 1.20.1 自带的 asm(9.2 与 9.6 两版并存)—— 否则 Knot.<clinit> 抛
"duplicate ASM classes found on classpath"
- 追加 Fabric 的 8 个库(asm×5 / sponge-mixin / intermediary / fabric-loader)
库来源改为内容根 `.mcfold/fabric/`(原在 /tmp/fab,tmpfs 且违反版本隔离)。
实测 67 条 → 去 7 asm + 加 8 fabric = 68 条。
### ② `tests/test_loader_render.py`(新增,6 项)
✓ 启动架构与世代正交(动态子类,不写 N 个类)
✓ 两个架构可枚举
✓ classpath 组装(67→68:去 7 asm,加 8 fabric)
✓ 非 asm 库原样保留(去 asm 是外科手术,不是重写)
✓ **Fabric 加载器真启动并渲染**(KnotClassLoader / chunks=10..25 / colors=4391..4547)
✓ **Fabric 拒绝不兼容 mod** ← 反向对照:缺 fabric-api 的 Explorify 被拒
最后一条是**两条路线的可判差异**:零加载器是「无脑注册」,不知道 mod 要
fabric-api;Fabric 会。没有它,"加载器真的介入了"这句话就没有反面证据。
### ③ `run_tests.sh` —— 慢套件改为列表驱动 + 全跳过不再报绿
- SLOW 列表含 test_render_bridge / test_loader_render(默认不跑)
- ★ 全部跳过的套件**不算绿**:报"跳过 N 项"而非计入通过数 ——
否则"没测"会被读成"测过了"。
## 验证
./run_tests.sh → 62 项(2 个慢套件标 ⊘)
./run_tests.sh --with-render → **76 项全绿**
(62 单元 + test_render_bridge 8 + test_loader_render 6)
## 仍未做
Iris 光影真实加载(加载器已通,未验过一次 shader pack)
forge / neoforge 后端(gen_1_20 / gen_1_21 均待设计)
52 lines
1.9 KiB
Bash
Executable File
52 lines
1.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 统一测试入口。
|
||
#
|
||
# ./run_tests.sh 纯 Python 单元测试(秒级)
|
||
# ./run_tests.sh --with-render 额外跑渲染联测(需 Java + Xvfb,约 6 分钟)
|
||
#
|
||
# 渲染联测需要:
|
||
# MCFOLD_RENDER_CLASSPATH 含 client-named.jar 与 McfoldRenderServer.class
|
||
# MCFOLD_NATIVES_DIR lwjgl natives(**.so 必须平铺**,不能带包路径)
|
||
# DISPLAY 指向可用的 X(Xvfb 即可)
|
||
# (加载器联测另需 .mcfold/fabric/ 与已编译的 LoaderBoot.class)
|
||
# 缺任一项会**跳过而非失败**(不误报)。
|
||
cd "$(dirname "$0")"
|
||
WITH_RENDER=0
|
||
[ "${1:-}" = "--with-render" ] && WITH_RENDER=1
|
||
|
||
# 需要 JVM/Xvfb 的套件(默认不跑,跑一次约数分钟)
|
||
SLOW="test_render_bridge.py test_loader_render.py"
|
||
|
||
total=0; fail=0
|
||
for t in tests/test_*.py; do
|
||
name=$(basename "$t")
|
||
if [ $WITH_RENDER -eq 0 ] && [[ " $SLOW " == *" $name "* ]]; then
|
||
printf ' %-24s ⊘ 跳过(用 --with-render 启用)\n' "$name"
|
||
continue
|
||
fi
|
||
out=$(python3 "$t" 2>&1)
|
||
if echo "$out" | grep -qE "全部通过|通过$"; then
|
||
n=$(echo "$out" | grep -c "^ ✓")
|
||
skipped=$(echo "$out" | grep -c "^ - 跳过")
|
||
total=$((total+n))
|
||
# ★ 全跳过的套件不算绿:它对环境一无所知,报绿等于把"没测"说成"测过了"
|
||
if [ "$n" -eq 0 ] && [ "$skipped" -gt 0 ]; then
|
||
printf ' %-24s ⊘ 全部跳过(%d 项;环境未就绪)\n' "$name" "$skipped"
|
||
elif [ "$skipped" -gt 0 ]; then
|
||
printf ' %-24s ✓ %2d 项(%d 项跳过)\n' "$name" "$n" "$skipped"
|
||
else
|
||
printf ' %-24s ✓ %2d 项\n' "$name" "$n"
|
||
fi
|
||
else
|
||
fail=$((fail+1))
|
||
printf ' %-24s ✗ 失败\n' "$name"
|
||
echo "$out" | tail -6 | sed 's/^/ /'
|
||
fi
|
||
done
|
||
echo
|
||
if [ $fail -eq 0 ]; then
|
||
echo "全部通过:$total 项,0 失败"
|
||
else
|
||
echo "失败 $fail 个套件(共 $total 项通过)"; exit 1
|
||
fi
|