使用DeferredRegistry的模组物品在Class Map中无法找到的问题求助
问题原因与解决方案
核心问题
你调用ModItems.SILVER_INGOT.get()时触发NPE,是因为RegistryObject的get()方法只有在物品完成注册后才能调用,而你大概率是在方块初始化(比如静态代码块、方块构造函数)阶段就调用了这个方法——此时DeferredRegistry还没完成模组物品的注册流程,RegistryObject里还没有实际的Item实例。
解决方案
1. 延迟配方Map的初始化
不要在静态代码块或方块构造阶段填充配方Map,而是在游戏注册流程完成后的事件中初始化,比如FMLCommonSetupEvent:
// 假设你的配方Map是类成员变量 private static final Map<Item, Item> RECIPE_MAP = new HashMap<>(); // 在模组主类或专门的事件处理类中注册监听 @SubscribeEvent public static void onCommonSetup(FMLCommonSetupEvent event) { // 使用enqueueWork确保在主线程执行 event.enqueueWork(() -> { // 此时所有物品已完成注册,可安全调用get() RECIPE_MAP.put(ModItems.SILVER_INGOT.get(), ModItems.SILVER_BRICK.get()); // 原版物品可直接添加 RECIPE_MAP.put(Items.STONE, Items.STONE_BRICKS); }); }
2. 直接用RegistryObject作为Map的键(可选)
如果不想延迟初始化,可以把配方Map的键类型换成RegistryObject<Item>,这样不需要提前调用get(),在onStep方法里再获取实例:
private static final Map<RegistryObject<Item>, RegistryObject<Item>> RECIPE_MAP = Map.of( ModItems.SILVER_INGOT, ModItems.SILVER_BRICK, RegistryObject.of(Items.STONE.getRegistryName(), Item.REGISTRY), Items.STONE_BRICKS ); // 在onStep方法中处理时: ItemEntity entity = ...; Item inputItem = entity.getItem().getItem(); // 遍历Map找到匹配的RegistryObject for (Map.Entry<RegistryObject<Item>, RegistryObject<Item>> entry : RECIPE_MAP.entrySet()) { if (entry.getKey().get() == inputItem) { Item outputItem = entry.getValue().get(); // 执行合成逻辑 break; } }
这种方式全程依赖RegistryObject,避免了提前获取实例的风险。
3. 排查代码执行时机
检查你调用get()的代码是否在静态初始化阶段执行——比如方块类的静态代码块、静态成员变量的初始化表达式,这些都会在模组加载早期执行,此时DeferredRegistry的注册还未完成,必然会触发NPE。
内容的提问来源于stack exchange,提问作者Gbotdays
相关产品推荐
相关产品推荐

