实测链路(全绿): 1. 官方 ProGuard 映射 → SRG → SpecialSource 重映射 → client-named.jar 2. 反编译确认 MC 渲染器挂在 Minecraft 单例上,不能独立 new 3. 权威序列:tryDetectVersion → Bootstrap → RenderSystem → new Minecraft(cfg) 4. 渲 3 帧 + glReadPixels → PNG,画面是 Mojang 加载屏(真渲染,非清屏) 三个坑(实测证据): - 漏 tryDetectVersion → Game version not set - FolderData 参数顺序错 → icons/ 404 - assetIndex 用 id(5) 而非落盘名(1.20.1) → 资源全找不到 下一步:ClientLevel 构造只需 listener.registryAccess(), ClientChunkCache.replaceWithPacketData 接收 map_chunk 原始字节 (与 chunk.py 同格式)⇒ 这就是数据喂渲染器的落点。
77 lines
3.6 KiB
Bash
Executable File
77 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# mcfold scaffold 构建脚本 —— 把「官方客户端 jar」变成「可直接调用的渲染库」
|
||
#
|
||
# 实测链路(2026-09-25 全绿):
|
||
# 1. 下官方 ProGuard 映射(client_mappings.txt)
|
||
# 2. 转成 SRG(SpecialSource 只吃 SRG)
|
||
# 3. 重映射 client.jar → client-named.jar(类名可读,javap/javac 可用)
|
||
# 4. 编译脚手架
|
||
#
|
||
# 用法: ./build.sh [实例store目录] [MC版本]
|
||
set -euo pipefail
|
||
|
||
STORE="${1:-/home/newqqagent/mcview/store/vanilla-1.20.1}"
|
||
MCVER="${2:-1.20.1}"
|
||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||
WORK="${MCFOLD_SCAFFOLD_WORK:-/tmp/mcfold-scaffold}"
|
||
|
||
mkdir -p "$WORK"
|
||
cd "$WORK"
|
||
|
||
CLIENT_JAR="$STORE/versions/$MCVER/$MCVER.jar"
|
||
[ -f "$CLIENT_JAR" ] || { echo "找不到客户端 jar: $CLIENT_JAR"; exit 1; }
|
||
|
||
# ── 1. 映射文件 ────────────────────────────────────────────────
|
||
MAPPINGS_URL=$(python3 - "$STORE/versions/$MCVER/$MCVER.json" <<'PY'
|
||
import json,sys
|
||
d=json.load(open(sys.argv[1]))
|
||
print(d['downloads']['client_mappings']['url'])
|
||
PY
|
||
)
|
||
if [ ! -s client_mappings.txt ]; then
|
||
echo "[1/4] 下载官方映射..."
|
||
curl -sL -o client_mappings.txt "$MAPPINGS_URL"
|
||
fi
|
||
echo "[1/4] 映射: $(wc -l < client_mappings.txt) 行"
|
||
|
||
# ── 2. ProGuard → SRG ─────────────────────────────────────────
|
||
echo "[2/4] 转换映射格式..."
|
||
python3 "$HERE/pg2srg.py" client_mappings.txt mappings.srg
|
||
|
||
# ── 3. 重映射 jar ─────────────────────────────────────────────
|
||
if [ ! -f client-named.jar ] || [ "$CLIENT_JAR" -nt client-named.jar ]; then
|
||
echo "[3/4] 重映射客户端 jar(约 1-2 分钟)..."
|
||
SS=$(find /home/minecraft/libraries -name "SpecialSource-*.jar" 2>/dev/null | head -1)
|
||
[ -n "$SS" ] || { echo "找不到 SpecialSource"; exit 1; }
|
||
GUAVA=$(find /home/minecraft/libraries -name "guava-*.jar" ! -name "*sources*" 2>/dev/null | head -1)
|
||
for a in asm asm-commons asm-tree; do
|
||
[ -f "$a.jar" ] || curl -sL -o "$a.jar" "https://repo1.maven.org/maven2/org/ow2/asm/$a/9.7/$a-9.7.jar"
|
||
done
|
||
[ -f joptsimple.jar ] || curl -sL -o joptsimple.jar \
|
||
"https://repo1.maven.org/maven2/net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4.jar"
|
||
java -Xmx3G -cp "$SS:joptsimple.jar:asm.jar:asm-commons.jar:asm-tree.jar:$GUAVA" \
|
||
net.md_5.specialsource.SpecialSource \
|
||
-i "$CLIENT_JAR" -o client-named.jar -m mappings.srg
|
||
else
|
||
echo "[3/4] client-named.jar 已是最新"
|
||
fi
|
||
ls -la client-named.jar
|
||
|
||
# ── classpath ─────────────────────────────────────────────────
|
||
find "$STORE/libraries" -name "*.jar" ! -name "*-sources.jar" ! -name "*natives*" 2>/dev/null \
|
||
| grep -vE "minecraftforge|neoforge" > cp.txt
|
||
CP="$(paste -sd: cp.txt):$WORK/client-named.jar"
|
||
|
||
# ── 4. 编译脚手架 ─────────────────────────────────────────────
|
||
echo "[4/4] 编译脚手架..."
|
||
mkdir -p classes
|
||
javac -nowarn -proc:none -cp "$CP" -d classes "$HERE"/*.java
|
||
echo
|
||
echo "✅ 构建完成"
|
||
echo " named jar : $WORK/client-named.jar"
|
||
echo " classes : $WORK/classes"
|
||
echo
|
||
echo "运行(无头,需 Xvfb):"
|
||
echo " find $STORE/libraries -name '*natives-linux*.jar' | while read j; do unzip -o -q \$j -d $WORK/nativ; done"
|
||
echo " DISPLAY=:98 java -cp \"$CP:$WORK/classes\" -Djava.library.path=$WORK/nativ RenderProbe"
|