Files
agentmc/scaffold/Scaffold.java
JianFeeeee e223be2571 P8: scaffold —— 反混淆 + MC 渲染栈离屏初始化 + 真渲染出图
实测链路(全绿):
  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 同格式)⇒ 这就是数据喂渲染器的落点。
2026-09-25 15:39:41 +08:00

92 lines
4.4 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import com.mojang.blaze3d.platform.DisplayData;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.authlib.properties.PropertyMap;
import net.minecraft.SharedConstants;
import net.minecraft.client.Minecraft;
import net.minecraft.client.User;
import net.minecraft.client.main.GameConfig;
import net.minecraft.server.Bootstrap;
import java.io.File;
import java.net.Proxy;
import java.util.OptionalInt;
/**
* mcfold scaffold —— 只起 MC 的**渲染栈**,不进游戏主循环。
*
* 依据(反编译 net.minecraft.client.main.Main 的实测序列):
* Bootstrap.bootStrap()
* RenderSystem.initRenderThread(); beginInitialization();
* new Minecraft(gameConfig) ← 构造即完成 GL/资源/渲染器初始化
* RenderSystem.finishInitialization()
* 之后 Main 才起 Game thread 跑主循环 —— 我们**不**走那步。
*/
public class Scaffold {
public static void main(String[] args) throws Exception {
String gameDir = arg(args, "--gameDir", "/home/newqqagent/mcview/instances/default");
String assets = arg(args, "--assets", "/home/newqqagent/mcview/store/vanilla-1.20.1/assets");
// ★ 索引名必须是 assets/indexes/<name>.json 中真实存在的那个。
// version.json 的 assetIndex.id 是 "5",但 MCLC 落盘用 version.number(1.20.1)
// —— 传 "5" 会导致索引加载失败,所有资源/icons 全部找不到(实测踩过)。
String assetIdx = arg(args, "--assetIndex", "1.20.1");
int width = Integer.parseInt(arg(args, "--width", "1280"));
int height = Integer.parseInt(arg(args, "--height", "720"));
System.out.println("[scaffold] bootstrap...");
// ★ 官方 Main 的实测序列:tryDetectVersion 必须在 bootStrap 之前,
// 否则 DataFixers.<clinit> 抛 "Game version not set"
SharedConstants.tryDetectVersion();
SharedConstants.enableDataFixerOptimizations();
Bootstrap.bootStrap();
System.out.println("[scaffold] bootstrap ok, mcVersion=" + SharedConstants.getCurrentVersion().getName());
File runDir = new File(gameDir);
File assetsDir = new File(assets);
User user = new User("mcfold_cam", "0".repeat(32), "mcfold_cam",
java.util.Optional.empty(), java.util.Optional.empty(), User.Type.LEGACY);
PropertyMap props = new PropertyMap();
GameConfig cfg = new GameConfig(
new GameConfig.UserData(user, props, props, Proxy.NO_PROXY),
new DisplayData(width, height, OptionalInt.empty(), OptionalInt.empty(), false),
new GameConfig.FolderData(
// ★ 顺序是 (gameDirectory, resourcePackDirectory, assetDirectory, assetIndex)
// 反着写会把 assets 当游戏目录,导致资源全找不到(实测踩过:icons/icon_16x16.png 404)
runDir, new File(runDir, "resourcepacks"), assetsDir, assetIdx),
new GameConfig.GameData(
false, // demo
"mcfold", // version
"release", // versionType
false, // disableMultiplayer
false), // disableChat
new GameConfig.QuickPlayData(null, null, null, null)
);
System.out.println("[scaffold] RenderSystem init...");
RenderSystem.initRenderThread();
RenderSystem.beginInitialization();
System.out.println("[scaffold] new Minecraft(cfg) ...");
Minecraft mc = new Minecraft(cfg);
RenderSystem.finishInitialization();
System.out.println("[scaffold] OK Minecraft constructed");
// 检查渲染栈关键对象是否就绪(不启主循环)
System.out.println("[scaffold] window=" + mc.getWindow().getWidth() + "x" + mc.getWindow().getHeight());
System.out.println("[scaffold] levelRenderer=" + (mc.levelRenderer != null ? "present" : "null"));
System.out.println("[scaffold] gameRenderer=" + (mc.gameRenderer != null ? "present" : "null"));
System.out.println("[scaffold] level=" + (mc.level != null ? "present" : "null (не connected)"));
System.out.println("[scaffold] DONE (no main loop)");
}
private static String arg(String[] a, String key, String def) {
for (int i = 0; i < a.length - 1; i++)
if (a[i].equals(key)) return a[i + 1];
return def;
}
}