Fabric模组开发:程序化注册方块时遇「无法获取属性」错误
问题描述
开发Fabric模组时,为原版几乎所有方块添加「开裂」「苔藓化」等变体,采用循环批量注册的方式(变体名称格式为变体名+原方块名,比如Cracked Oak Planks),流程可正常生成模型文件,但在继承原方块硬度、材质等属性时遇到问题:针对原木、红石矿石等带子类特有属性的方块注册变体时抛出错误。
问题代码
public static void registerModBlocks() { for (Field block : Blocks.class.getFields()) { Block blockObject = (Block) block.get(null); TutorialMod.LOGGER.info(block.getName()); Block settings = new Block(FabricBlockSettings.copyOf(blockObject)); String blockName = "cracked_" + block.getName().toLowerCase(); gen_blocks.put(blockName, registerBlock(blockName, settings, ModItemGroup.ITEM_GROUP)); } } }
错误信息
- 原木报错:
Cannot get property EnumProperty{name=axis, clazz=class net.minecraft.util.math.Direction$Axis, values=[x, y, z]} as it does not exist in Block{minecraft:air}
- 红石矿石报错:
Cannot get property BooleanProperty{name=lit, clazz=class java.lang.Boolean, values=[true, false]} as it does not exist in Block{minecraft:air}
错误原因明确:原木的axis、红石矿石的lit属于Block子类的特有属性,统一用Block类创建变体无法继承这些属性。
解决方案
核心思路是通过类型判断生成对应子类的变体方块,而非统一使用基础Block类,同时过滤掉不需要生成变体的功能方块,无需额外维护JSON标签。
修改后的代码示例
public static void registerModBlocks() { for (Field blockField : Blocks.class.getFields()) { try { Block originalBlock = (Block) blockField.get(null); String originalBlockName = blockField.getName().toLowerCase(); TutorialMod.LOGGER.info("Processing block: {}", originalBlockName); // 跳过功能方块(可根据需求自行扩展排除列表) if (isFunctionBlock(originalBlock)) { continue; } Block variantBlock; String variantName = "cracked_" + originalBlockName; // 根据原方块的实际类型创建对应变体 if (originalBlock instanceof PillarBlock) { // 处理原木、石英柱等带axis属性的方块 variantBlock = new PillarBlock(FabricBlockSettings.copyOf(originalBlock)); } else if (originalBlock instanceof RedstoneOreBlock) { // 处理红石矿石(带lit属性) variantBlock = new RedstoneOreBlock(FabricBlockSettings.copyOf(originalBlock)); } else if (originalBlock instanceof OreBlock) { // 处理普通矿石方块 variantBlock = new OreBlock(FabricBlockSettings.copyOf(originalBlock)); } else if (originalBlock instanceof SlabBlock) { // 处理台阶方块 SlabBlock originalSlab = (SlabBlock) originalBlock; variantBlock = new SlabBlock(FabricBlockSettings.copyOf(originalBlock)); } else { // 默认处理普通方块 variantBlock = new Block(FabricBlockSettings.copyOf(originalBlock)); } // 注册变体方块 gen_blocks.put(variantName, registerBlock(variantName, variantBlock, ModItemGroup.ITEM_GROUP)); } catch (IllegalAccessException e) { TutorialMod.LOGGER.error("Failed to process block: {}", blockField.getName(), e); } } } // 辅助方法:判断是否为不需要生成变体的功能方块 private static boolean isFunctionBlock(Block block) { // 可自行添加更多需要排除的方块类型,比如门、按钮、压力板等 return block instanceof DoorBlock || block instanceof ButtonBlock || block instanceof PressurePlateBlock || block instanceof TrapdoorBlock || block instanceof LeverBlock || block instanceof RedstoneWireBlock; }
关键说明
- 类型匹配创建变体:通过
instanceof判断原方块的子类类型,创建对应类型的变体方块,确保继承子类特有的属性和行为(比如PillarBlock的axis方向、RedstoneOreBlock的发光逻辑)。 - 过滤功能方块:通过
isFunctionBlock方法跳过不需要生成变体的功能方块,避免无效注册和逻辑冲突。 - 异常捕获:添加
IllegalAccessException捕获,防止单个方块处理失败导致整个注册流程崩溃。
额外建议
- 可扩展更多方块类型的判断逻辑,比如楼梯(StairsBlock)、栅栏(FenceBlock)等,保证变体方块的行为与原方块一致。
- 测试时重点验证特殊方块变体的加载状态,比如原木的朝向切换、红石矿石的发光效果。
- 若需添加「苔藓化」等其他变体,可将变体类型(
cracked、mossy)抽离为参数,复用注册逻辑。
内容的提问来源于stack exchange,提问作者Ethan Parish
相关产品推荐
相关产品推荐

