Forge 1.16.4-35.1.28 recipe not working

I'm quite new to modding with forge, so this question may be dumb or silly.

First there's my file: (located at ~/forge-1.16.4-35.1.28-mdk/data/chemc/recipes/H2_O2__H2O.json)

{
    "type": "minecraft:crafting_shapeless",
    "ingredients":
    [
        {
            "item": "chemc:hydrogen"
        },
        {
            "item": "chemc:oxygen"
        }
    ],
    "result":
    {
        "item": "minecraft:water_bucket"
    }
}

The problem is, when I load the game and switch to survival more trying to combine hydrogen and oxygen to make a water bucket, but it seems that it can't be crafted.

Suppose the items are registered correctly, as I can get them in-game. Main Mod file so you can see the unlocalized named of the items.

package com.***.***.mcmods.chemc;

import com.***.***.mcmods.chemc.items.Hydrogen;
import com.***.***.mcmods.chemc.items.Oxygen;

import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.Item.Properties;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;

// The value here should match an entry in the META-INF/mods.toml file
@Mod(CheMC.modid)
public class CheMC {

    public static final String modid = "chemc";
    static Item i_h = new Hydrogen(new Properties()).setRegistryName("chemc", "hydrogen");
    static Item i_o = new Oxygen(new Properties()).setRegistryName("chemc", "oxygen");

    public CheMC() {
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
        MinecraftForge.EVENT_BUS.register(this);
    }

    private void setup(final FMLCommonSetupEvent event) {
    }

    // You can use EventBusSubscriber to automatically subscribe events on the
    // contained class (this is subscribing to the MOD
    // Event bus for receiving Registry Events)
    @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
    public static class RegistryEvents {
        @SubscribeEvent
        public static void onBlocksRegistry(final RegistryEvent.Register<Block> blockRegistryEvent) {
            // register a new block here
            // blockRegistryEvent.getRegistry().registerAll();
        }

        @SubscribeEvent
        public static void onItemsRegistry(final RegistryEvent.Register<Item> itemRegistryEvent) {
            // register a new item here
            itemRegistryEvent.getRegistry().registerAll(i_h,i_o);
        }
    }
}

The documentation I took a look at: ReadTheDocs Forge 1.16

Output of ./gradlew runClient --full-stacktrace --debug --info --parallel

Any answer would be appreciated!


Solution 1:

The preferred way to register items in new forge mods is with the deferred registry system (which takes care of the event handling for you). When you need to access the items within code you will need to use e.g. ModItems.HYDROGEN.get() instead of simply ModItems.HYDROGEN.

// The value here should match an entry in the META-INF/mods.toml file
@Mod(CheMC.MODID)
public class CheMC {

    public static final String MODID = "chemc";

    public CheMC() {
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
        MinecraftForge.EVENT_BUS.register(this);
        ModItems.init();
    }

    private void setup(final FMLCommonSetupEvent event) {
    }
}

public class ModItems {
    public static final DeferredRegister<Item> ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, CheMC.MODID);

    public static final ItemGroup ITEM_GROUP = new ItemGroup(CheMC.MODID) {
        @Override
        public ItemStack createIcon() {
            // pick any item here, it will be the icon for your creative tab
            return new ItemStack(HYDROGEN.get());
        }
    };

    public static void init() {
        ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus());
    }

    public static final RegistryObject<Hydrogen> HYDROGEN = ITEMS.register("hydrogen", () -> new Hydrogen(new Properties().group(ITEM_GROUP)));
    public static final RegistryObject<Oxygen> OXYGEN = ITEMS.register("oxygen", () -> new Oxygen(new Properties().group(ITEM_GROUP)));
}

I've also separated out the item registry into a separate class for you and changed some naming conventions to fit best practices. Note that you don't need to create a separate class for each Item unless you're overriding some methods in the class, you can just use new Item. But I don't know the rest of your code so I haven't changed that.

(Also, just a design note: your recipe gives the user a free bucket, which can be reused once emptied. You may want to add an empty bucket to the ingredients)

EDIT: ...I just realized I hadn't answered your question about the recipe issue (I misread the other part of your post as suggesting that they weren't registered correctly - if they work, it's fine, though you may still find the deferred registry-based system more scalable as you add more items.)

The data folder needs to be located under src/main/resources, not in the root of the project. Additionally, the name of the file needs to be all-lowercase.