gen_1_21 实测启动成功 + provision 工具
决定性验证:gen_1_21 后端在 1.21.1 上收到 {"event":"ready"}
⇒ 世代分派架构成立:同一套 Python 层,两个独立编译的 Java 后端
运行时发现第 12 处世代差异(编译期看不出):
1.20.x registryAccess 是可变 LayeredRegistryAccess → 事后反射替换
1.21.x registryAccess 是 final RegistryAccess$Frozen → 反射抛
"Can not set final field"
处理:gen_1_21 改为先载注册表 → 经 CommonListenerCookie.receivedRegistries
传入 → 再构造 listener。比 1.20 的反射做法更干净。
新增 mcfold/provision.py(从官方 manifest 装任意版本,版本无关):
- 跳过音频资源:1.21.1 实测 3911 条里跳过 3744 条
- natives 两种形态都认(1.21 起是独立库条目,非 classifiers)
- 实测 1.21.1:274 文件 / 200MB / 32s / 0 失败
This commit is contained in:
@ -524,35 +524,13 @@ public class McfoldRenderServer {
|
||||
reloadResources(mc);
|
||||
System.err.println("[mcfold] resources reloaded");
|
||||
|
||||
Connection conn = new Connection(PacketFlow.CLIENTBOUND);
|
||||
GameProfile profile = new GameProfile(UUID.randomUUID(), "mcfold_cam");
|
||||
// 初始注册表:官方静态层(1.21 的 cookie 需要它,随后会被真实注册表替换)
|
||||
net.minecraft.core.RegistryAccess.Frozen listenerRegistryAccess =
|
||||
net.minecraft.client.multiplayer.ClientRegistryLayer.createRegistryAccess()
|
||||
.compositeAccess();
|
||||
WorldSessionTelemetryManager telemetry = new WorldSessionTelemetryManager(
|
||||
TelemetryEventSender.DISABLED, false, Duration.ZERO, "");
|
||||
// ★ 世代差异(1.21+):ClientPacketListener(Minecraft, Connection, CommonListenerCookie)
|
||||
// 1.20.x 是 (Minecraft, Screen, Connection, ServerData, GameProfile, TelemetryManager)。
|
||||
// ★★ 这是本世代最大的一处变化 —— 参数个数与语义都不同。
|
||||
var cookie = new net.minecraft.client.multiplayer.CommonListenerCookie(
|
||||
profile,
|
||||
telemetry,
|
||||
listenerRegistryAccess, // 后面注册表加载后会被替换
|
||||
net.minecraft.world.flag.FeatureFlags.DEFAULT_FLAGS,
|
||||
null, // serverBrand
|
||||
null, // serverData
|
||||
null, // postDisconnectScreen
|
||||
java.util.Map.of(), // serverCookies
|
||||
null, // chatState
|
||||
false, // strictErrorHandling
|
||||
java.util.Map.of(), // customReportDetails
|
||||
net.minecraft.server.ServerLinks.EMPTY);
|
||||
ClientPacketListener listener = new ClientPacketListener(mc, conn, cookie);
|
||||
|
||||
// ★ 世代差异(1.21+):createPackRepository(Path, DirectoryValidator)
|
||||
// DirectoryValidator 没有 NONE 常量,构造要 PathMatcher;
|
||||
// 传一个「全部拒绝」的 matcher 最安全(我们不加载外来符号链接数据包)
|
||||
// ★★ 世代差异(1.21+):注册表经 CommonListenerCookie.receivedRegistries 传入,
|
||||
// 并在 ClientPacketListener 构造时赋给 **final** 字段
|
||||
// (实测:1.20.x 是可变 LayeredRegistryAccess,可事后反射替换;
|
||||
// 1.21 是 final RegistryAccess$Frozen,反射会抛
|
||||
// "Can not set final ... field")。
|
||||
// ⇒ 本世代的正确顺序:**先加载注册表,再构造 cookie + listener**。
|
||||
// 这比 1.20 的反射注入更干净。
|
||||
var packs = net.minecraft.server.packs.repository.ServerPacksSource.createPackRepository(
|
||||
new File(runDir, "datapacks").toPath(),
|
||||
new net.minecraft.world.level.validation.DirectoryValidator(p -> false));
|
||||
@ -563,13 +541,27 @@ public class McfoldRenderServer {
|
||||
var all = new java.util.ArrayList<RegistryDataLoader.RegistryData<?>>();
|
||||
all.addAll(RegistryDataLoader.WORLDGEN_REGISTRIES);
|
||||
all.addAll(RegistryDataLoader.DIMENSION_REGISTRIES);
|
||||
RegistryAccess.Frozen loaded = RegistryDataLoader.load(dataRm, listener.registryAccess(), all);
|
||||
var layered = net.minecraft.client.multiplayer.ClientRegistryLayer.createRegistryAccess()
|
||||
.replaceFrom(net.minecraft.client.multiplayer.ClientRegistryLayer.REMOTE,
|
||||
new RegistryAccess.Frozen[]{loaded});
|
||||
var rf = ClientPacketListener.class.getDeclaredField("registryAccess");
|
||||
rf.setAccessible(true);
|
||||
rf.set(listener, layered);
|
||||
RegistryAccess.Frozen base = net.minecraft.client.multiplayer.ClientRegistryLayer
|
||||
.createRegistryAccess().compositeAccess();
|
||||
RegistryAccess.Frozen loaded = RegistryDataLoader.load(dataRm, base, all);
|
||||
System.err.println("[mcfold] registries loaded: dimension_type="
|
||||
+ loaded.registryOrThrow(Registries.DIMENSION_TYPE).size());
|
||||
|
||||
Connection conn = new Connection(PacketFlow.CLIENTBOUND);
|
||||
GameProfile profile = new GameProfile(UUID.randomUUID(), "mcfold_cam");
|
||||
WorldSessionTelemetryManager telemetry = new WorldSessionTelemetryManager(
|
||||
TelemetryEventSender.DISABLED, false, Duration.ZERO, "");
|
||||
var cookie = new net.minecraft.client.multiplayer.CommonListenerCookie(
|
||||
profile,
|
||||
telemetry,
|
||||
loaded, // ← 注册表从这里进
|
||||
net.minecraft.world.flag.FeatureFlags.DEFAULT_FLAGS,
|
||||
null, null, null,
|
||||
java.util.Map.of(), null, false, java.util.Map.of(),
|
||||
net.minecraft.server.ServerLinks.EMPTY);
|
||||
ClientPacketListener listener = new ClientPacketListener(mc, conn, cookie);
|
||||
System.err.println("[mcfold] listener ok, registryAccess dims="
|
||||
+ listener.registryAccess().registryOrThrow(Registries.DIMENSION_TYPE).size());
|
||||
|
||||
Holder<DimensionType> dimHolder = loaded.registryOrThrow(Registries.DIMENSION_TYPE)
|
||||
.getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, ResourceLocation.parse("minecraft:overworld")));
|
||||
|
||||
Reference in New Issue
Block a user