Table of Contents

Loot Table Generation

Before reading this, make sure you've read Getting started with Data Generation, and have a class that implements DataGenerationEntrypoint

To begin, make a class (or a few, you need one for blocks, chests and entities) that extends SimpleFabricLootTableProvider and register it like so:

Setting Up

To get started with block loot, create a block loot table generator

private static class MyBlockLootTables extends FabricBlockLootTableProvider {
    public MyBlockLootTables(FabricDataOutput dataOutput) {
         super(dataOutput);
    }
 
    @Override
    public void generate() {
        // ...
    }
}
 
// ...
 
 
@Override
public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
    // ...
    FabricDataGenerator.Pack myPack = fabricDataGenerator.createPack();
    myPack.addProvider(MyBlockLootTables::new);
    // ...
}

If you're using versions pre-1.20, please replace myPack.addProvider(MyBlockLootTables::new); with fabricDataGenerator.addProvider(MyBlockLootTables::new);。You can also remove FabricDataGenerator.Pack myPack = fabricDataGenerator.createPack();

Let's just create a simple ore block and an item to drop from it for a block loot table. Add this to your block init or Tutorial class in this case.

public static final Block TEST_ORE = Registry.register(Registry.BLOCK, new Identifier("tutorial", "test_ore"), new Block(...));
 
public static final Item TEST_ITEM = Registry.register(Registry.ITEM, new Identifier("tutorial", "test_item", new Item(...));
// Let's just ignore the fact that there isn't a block item 😅

Adding Block Loot

private static class MyBlockLootTables extends FabricBlockLootTableProvider {
    public MyBlockLootTables(FabricDataOutput dataOutput) {
         super(dataOutput);
    }
 
    @Override
    public void generate() {
        addDrop(Tutorial.TEST_BLOCK, drops(Tutorial.TEST_ITEM));
    }
}

Now that we successfully adding a block. Now let's add chest loot.

Adding Chest Loot

Firstly, we need an identifier. This identifier points to a json file that contains your chest loot.

// In Tutorial class
public static final Identifier TEST_CHEST = new Identifier("tutorial", "chests/test_loot");

Let's create a chest loot table generator and register it like so.

private static class MyChestLootTables extends SimpleFabricLootTableProvider {
    public MyChestLootGenerator(FabricDataOutput dataGenerator) {
	super(dataGenerator, LootContextTypes.CHEST);
    }
 
    @Override
    public void accept(BiConsumer<Identifier, LootTable.Builder> biConsumer) {
        biConsumer.accept(Tutorial.TEST_CHEST, LootTable.builder()
                  .pool(LootPool.builder().rolls(ConstantLootNumberProvider.create(1.0F))
                  .with(ItemEntry.builder(Items.DIAMOND)
				.apply(SetCountLootFunction.builder(ConstantLootNumberProvider.create(1.0F))))
                  .with(ItemEntry.builder(Items.DIAMOND_SWORD)).apply(EnchantWithLevelsLootFunction.create(UniformLootNumberProvider.create(20.0F, 39.0F))))
        );
    }
}
 
// ...
 
@Override
public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) {
    FabricDataGenerator.Pack myPack = fabricDataGenerator.createPack();
    myPack.addProvider(MyChestLootTables::new);
}

If you're using versions pre-1.20, please replace myPack.addProvider(MyBlockLootTables::new); with fabricDataGenerator.addProvider(MyBlockLootTables::new);。You can also remove FabricDataGenerator.Pack myPack = fabricDataGenerator.createPack();