Files
agentmc/scaffold/MOD-BLOCKS.md
JianFeeeee bea69b2556 mod 方块渲染(零加载器):注册链路实测打通
关键洞察:方块**渲染**只需要「注册表里有名字」+「资源包有模型」,
与方块行为无关 ⇒ 不必等 Fabric 加载器。

实测(已跑通):
  frozen 置 false + unregisteredIntrusiveHolders 恢复非 null
  注册占位方块 → BLOCK 1003→1004
  BlockState 手动 add 进 BLOCK_STATE_REGISTRY → 24135→24136
  state id = 24135,parseForBlock 可解析(渲染路径通)

★ 两个必须都处理的字段:只解冻 frozen 会抛
  "This registry can't create intrusive holders"
★ BlockState 不会自动注册(state id 会是 0),需手动 IdMapper.add

边界已诚实标注(scaffold/MOD-BLOCKS.md):
  外观 ✅ / state id ✅ / 变体属性 ⚠️ / 行为 ❌(需加载器)
  渲染类型(半透明)⚠️ 未验证 / 方块实体 ⚠️ 未验证
  Iris 光影必须加载器,此路不覆盖
2026-09-25 19:33:42 +08:00

3.5 KiB
Raw Blame History

mod 方块渲染(零加载器方案)

问题

附录 D 已证明:1.20.1 不在网络上下发方块注册表, mod 方块的 state id 只在 mod 被加载时才注册进客户端。

⇒ 走 mod 加载器(Fabric/Forge)是一个方案,但成本高(加载器 + 重映射整个游戏)。

关键洞察

方块渲染只需要「注册表里有这个名字」+「资源包里有它的模型/贴图」, 与方块的行为无关(行为是游戏逻辑,渲染不看)。

所以零加载器也能让 mod 方块正确显示:

  1. 注册同名占位方块进客户端注册表(拿到 state id)
  2. mod jar 当资源包加载(拿到 blockstates/models/textures)

实测(2026-09-25,已跑通)

Registry.register 与 Block 构造是 public,但注册表在 BuiltInRegistries.bootStrap() 里被 freeze()。绕过需要两步:

// ★ 1. 解冻:frozen 是 MappedRegistry 的 private boolean
// ★ 2. 恢复 unregisteredIntrusiveHolders —— freeze() 会把它置 null,
//      而注册路径需要它(否则抛 "This registry can't create intrusive holders")
//      —— 这两个字段必须**都**处理,只解冻 frozen 不够(实测)
Field frozen = ...getDeclaredField("frozen"); frozen.setBoolean(BLOCK, false);
Field holders = ...getDeclaredField("unregisteredIntrusiveHolders");
if (holders.get(BLOCK) == null) holders.set(BLOCK, new IdentityHashMap<>());

// 3. 注册占位方块(外观由资源包提供,行为对渲染无关)
Block b = new Block(BlockBehaviour.Properties.copy(Blocks.STONE));
Registry.register(BuiltInRegistries.BLOCK,
        new ResourceLocation("createbigcannons", "cast_iron_autocannon_breech"), b);

// ★ 4. BlockState **不会**自动进 BLOCK_STATE_REGISTRY(实测 state id 会是 0)
//      需手动 add —— IdMapper.add(T) 是 public
Block.BLOCK_STATE_REGISTRY.add(b.defaultBlockState());

实测结果:

注册前  BLOCK = 1003, BLOCK_STATE = 24135
注册后  BLOCK = 1004, BLOCK_STATE = 24136
state id = 24135                              ← 正确分配
反查     = createbigcannons:cast_iron_autocannon_breech
parseForBlock("createbigcannons:...") 成功 → id 24135   ← 渲染路径可解析

外观怎么来

mod jar 里通常自带 pack.mcmeta(实测 createbigcannons 有), 可直接作为资源包加入 resourcePackRepository:

assets/<modid>/blockstates/<block>.json   → 变体 → 模型
assets/<modid>/models/block/*.json
assets/<modid>/models/item/*.json
assets/<modid>/textures/block/*.png

这条路的边界(诚实标注)

项 状态
方块外观(模型/贴图) ✅ 资源包机制可覆盖
state id 分配 ✅ 已实测
方块属性(朝向/开关等 blockstate 变体) ⚠️ 占位方块只有 defaultBlockState。要支持变体需按 blockstates json 的 variants 逐个注册 state(工作量与 mod 方块数成正比)
方块行为(红石/交互/掉落) ❌ 不适用(渲染不需要,但要 gameplay 就必须加载器)
方块实体(箱子/机器) ⚠️ 未验证
渲染类型(solid/cutout/translucent) ⚠️ 未验证 —— 占位方块都是 solid,可能半透明方块显示异常

与加载器方案的关系

零加载器方案适合渲染(我们的用途);一旦需要 gameplay (红石/交互/mod 逻辑),才必须上 Fabric/Forge。 Iris 光影必须加载器(它是 Fabric mod),这条路覆盖不了。