P8 完成:世界数据 → 官方渲染器 → 真实出图
不起完整客户端、不连服、不登录,只初始化 MC 渲染栈并喂入我们自己造的世界数据。
已验证(全绿):
countRenderedChunks=29 distinct colors=1450
画面:草地/原木/树叶/天空/HUD/英文文字(sample-world-render.png)
打通的关卡:
- 反混淆(client-named.jar)+ GL 离屏 + new Minecraft(cfg) 不进主循环
- 资源同步重载:22 listener(ModelManager/FontManager/Dispatcher)
★ 不能 join reloadResourcePacks(等主循环→死锁),直接调各 listener reload()
- 注册表从客户端自带 data/ 加载(dimension_type=4)
- 区块注入:LevelChunk + setBlockState → ClientChunkCache.Storage.chunks
+ LightEngine.queueSectionData(全亮)→ allChanged()
- 每帧 mc.tick() 推进网格重建队列(不跑则 countRenderedChunks=0)
踩坑记录(10 条,README 详列):
LoadingOverlay/ReceivingLevelScreen 遮挡、FolderData 参数序、
assetIndex 用落盘名、reloadShaders 包私有、读像素必须绑 FBO、
判据用 distinct colors 而非 non-black
更正附录 D:state_id=1003 → note_block 不是误映射(note_block 有 800 状态)
—— 真客户端给完整状态,是 1.20.1 上 mod 方块语义的唯一权威来源
This commit is contained in:
82
scaffold/RegistryProbe.java
Normal file
82
scaffold/RegistryProbe.java
Normal file
@ -0,0 +1,82 @@
|
||||
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.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.Proxy;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
/**
|
||||
* 证明:真客户端的注册表能给出 state id ↔ 方块名的权威映射。
|
||||
*
|
||||
* 这正是不起完整客户端、只用客户端注册表的价值所在:
|
||||
* 1.20.1 不从网络下发方块表(附录D),mod 方块的 state id 只有客户端注册表知道。
|
||||
*/
|
||||
public class RegistryProbe {
|
||||
|
||||
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");
|
||||
String assetIdx = arg(args, "--assetIndex", "1.20.1");
|
||||
|
||||
SharedConstants.tryDetectVersion();
|
||||
SharedConstants.enableDataFixerOptimizations();
|
||||
Bootstrap.bootStrap();
|
||||
|
||||
File runDir = new File(gameDir);
|
||||
User user = new User("mcfold_cam", "0".repeat(32), "mcfold_cam",
|
||||
Optional.empty(), Optional.empty(), User.Type.LEGACY);
|
||||
PropertyMap props = new PropertyMap();
|
||||
GameConfig cfg = new GameConfig(
|
||||
new GameConfig.UserData(user, props, props, Proxy.NO_PROXY),
|
||||
new DisplayData(854, 480, OptionalInt.empty(), OptionalInt.empty(), false),
|
||||
new GameConfig.FolderData(runDir, new File(runDir, "resourcepacks"), new File(assets), assetIdx),
|
||||
new GameConfig.GameData(false, "mcfold", "release", false, false),
|
||||
new GameConfig.QuickPlayData(null, null, null, null));
|
||||
|
||||
RenderSystem.initRenderThread();
|
||||
RenderSystem.beginInitialization();
|
||||
Minecraft mc = new Minecraft(cfg);
|
||||
RenderSystem.finishInitialization();
|
||||
System.out.println("[reg] Minecraft constructed");
|
||||
|
||||
// ★ 核心:客户端的方块注册表
|
||||
int blockCount = BuiltInRegistries.BLOCK.size();
|
||||
int stateCount = Block.BLOCK_STATE_REGISTRY.size();
|
||||
System.out.println("[reg] BLOCK registry size = " + blockCount);
|
||||
System.out.println("[reg] BLOCK_STATE registry size = " + stateCount);
|
||||
|
||||
// ★ 关键验证:mineflayer 会静默误映射的那些越界 id,客户端怎么答
|
||||
int[] probes = {0, 1, 1002, 1003, 1502, 30000, stateCount - 1};
|
||||
for (int id : probes) {
|
||||
BlockState st = Block.stateById(id);
|
||||
ResourceLocation key = BuiltInRegistries.BLOCK.getKey(st.getBlock());
|
||||
System.out.println("[reg] state_id=" + id + " -> " + key + " [" + st + "]");
|
||||
}
|
||||
|
||||
// ★ 列出几个方块名(证明可读)
|
||||
System.out.println("[reg] sample blocks:");
|
||||
for (int i = 0; i < 5; i++) {
|
||||
ResourceLocation k = BuiltInRegistries.BLOCK.getKey(BuiltInRegistries.BLOCK.byId(i));
|
||||
System.out.println(" id=" + i + " -> " + k);
|
||||
}
|
||||
|
||||
System.out.println("[reg] DONE");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user