tutorial:datagen_setup

Getting started with Data Generation

Data Generation is a module of Fabric API which allows you to programmatically generate Recipes, Language Files, Loot Tables, Advancements and pretty much anything with Custom Providers. Every time you modify the code that generates advancements (or anything else datagen can make like loot tables and such) you'll have to run the gradle task runDatagen which we will create shortly.

Enabling Data Generation

The recommended way to enable the data generation API is to have checked the Data Generation box when creating your project using the fabric template mod generator:

Doing so would've created the gradle task runDatagen for us, and would've made a configuration to run in our IDE so we wouldn't have to use the terminal. The good news is it doesn't take very long to do the same manually.

Manually Enabling Data Generation

First open up your build.gradle file in the root folder of your project, and add the following anywhere inside that file:

build.gradle
//
// ... (The rest of the file)
//
 
fabricApi {
    configureDataGeneration()
}

Next we'll define a new class in our project ExampleModDataGenerator which implements DataGeneratorEntrypoint.

  • The onInitializeDataGenerator function will be called whenever the gradle task we created earlier (runDatagen) is ran.
ExampleModDataGenerator.java
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
 
public class ExampleModDataGenerator implements DataGeneratorEntrypoint {
 
    @Override
    public void onInitializeDataGenerator(FabricDataGenerator generator) {
        FabricDataGenerator.Pack pack = generator.createPack();
 
        // Adding a provider example:
        // 
        // pack.addProvider(AdvancementsProvider::new);
    }
 
}

Now we need to tell fabric about this entry point in our fabric.mod.json file:

fabric.mod.json
{
 
  // ... (The rest of the file)
 
  "entrypoints": {
    "fabric-datagen": [
      "com.example.ExampleModDataGenerator"
    ],
    "main": [
      "com.example.ExampleMod"
    ],
    "client": [
      "com.example.ExampleModClient"
    ]
  },
 
  // ... (The rest of the file)
 
}

Before continuing further let's see if what we have so far is working, or if we have any errors. Run the runDatagen task. You can have your IDE do that for you, or just open the terminal in the root directory of your project and do:

Windows
gradlew runDatagen
Linux
./gradlew runDatagen

Read the output and make sure there are no errors.

  • You can safely ignore: com.mojang.authlib.exceptions.InvalidCredentialsException: Status: 401 if it comes up. That error happens because the debug version of Minecraft we're running doesn't try to authenticate our account.

If you do get an error, it's usually pretty explicit about what's missing or wrong, but if you can't seem to figure it out, you might want to head over to the discord, and get some help.

There should be a new folder in src/main called generated. For now it'll be empty, but once we start generating data (like advancements), that is where it'll be saved.

IDE Integration (Optional)

Because we don't want to be opening the terminal all the time, we can setup a configuration in IntelljJ IDEA that will run the command for us through a drop-down menu.

First open the Run/Debug Configurations menu. You can open it by opening the drop-down menu next to the run button and clicking Edit Configurations.. option or you can double click Shift and type Edit Configuration into the menu that pops up.

Next click the '+' button, search for gradle, and select it.

Inside the Run textbox write runDatagen. Click Okay and you should be able to simply run the configuration instead of having to open the terminal.

Adding Providers

This is a generic guide on how to add a provider, for more in depth information on each provider, see their respective pages:

In this example, we will be creating a tag provider, as it is the simplest to understand.

Firstly, inside your ExampleModDataGenerator class, create a new private static class that extends FabricTagProvider<T>:

If you want, you can place this class in a separate file, but we recommend it stays in your datagen entrypoint class.

import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint;
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.registry.tag.ItemTags;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
import java.util.concurrent.CompletableFuture;
 
public class ExampleModDataGenerator implements DataGeneratorEntrypoint {
 
    @Override
    public void onInitializeDataGenerator(FabricDataGenerator generator) {
        FabricDataGenerator.Pack pack = generator.createPack();
 
        pack.addProvider(MyTagGenerator::new);
    }
 
    private static class MyTagGenerator extends FabricTagProvider.ItemTagProvider {
        public MyTagGenerator(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> completableFuture) {
            super(output, completableFuture);
        }
 
        @Override
        protected void configure(RegistryWrapper.WrapperLookup arg) {
 
        }
    }
}

We will add some basic tags inside configure() for example's sake.

public class ExampleModDataGenerator implements DataGeneratorEntrypoint {
 
    // ... (The rest of the file)
 
    private static class MyTagGenerator extends FabricTagProvider.ItemTagProvider {
 
        // ... (The rest of the file)
 
        private static final TagKey<Item> SMELLY_ITEMS = TagKey.of(RegistryKeys.ITEM, new Identifier("mymod:smelly_items"));
 
        @Override
        protected void configure(WrapperLookup arg) {
          // This creates a tag builder, where we add slime balls, rotten flesh and everything in the minecraft:dirt item tag.
          // This will automatically generate "src/main/generated/data/tutorial/tags/items/smelly_items.json" in the "generated" folder.
          getOrCreateTagBuilder(SMELLY_ITEMS)
                  .add(Items.SLIME_BALL)
                  .add(Items.ROTTEN_FLESH)
                  .addOptionalTag(ItemTags.DIRT);
        }
    }
}

When we run gradlew runDatagen, we should see the generated in src/main/generated/data/tutorial/tags/items/smelly_items.json, and the item tag json should be present:

smelly_items.json
{
  "replace": false,
  "values": [
    "minecraft:slime_ball",
    "minecraft:rotten_flesh",
    {
      "id": "#minecraft:dirt",
      "required": false
    }
  ]
}
tutorial/datagen_setup.txt · Last modified: 2024/03/15 05:06 by shnupbups