Table of Contents

Loot Table Generation

In this tutorial, you will learn how to generate loot tables for blocks and other contents. With data generation, you do not need to write JSONs for each block anymore. Before reading this, make sure you've read Getting started with Data Generation, and have a class that implements DataGenerationEntrypoint.

Block loot tables

To add a data generation for block loot tables, just create a class which extends FabricBlockLootTableProvider.

TutorialBlockLootTableProvider.java
public class TutorialBlockLootTableProvider extends FabricBlockLootTableProvider {
  protected TutorialBlockLootTableProvider(FabricDataOutput dataOutput, CompletableFuture<RegistryWrapper.WrapperLookup> registryLookup) {
    super(dataOutput, registryLookup);
  }
 
  @Override
  public void generate() {
    // ...
  }
}

And then, add this data generation in the entrypoint (we use ExampleModDataGenerator as an example):

ExampleModDataGenerator.java
public class ExampleModDataGenerator implements DataGeneratorEntrypoint {
  @Override
  public void onInitializeDataGenerator(FabricDataGenerator generator) {
    FabricDataGenerator.Pack pack = generator.createPack();
 
    pack.addProvider(TutorialBlockLootTableProvider::new);
  }
}
If you're using versions pre-1.20, please replace pack.addProvider(TutorialBlockLootTableProvider::new); with fabricDataGenerator.addProvider(TutorialBlockLootTableProvider::new); and remove FabricDataGenerator.Pack myPack = fabricDataGenerator.createPack();

In the previous blocks tutorial, we created an example block. Now let's use the data generator to generate its loot table. It's as simple as:

TutorialBlockLootTableProvider.java
  @Override
  public void generate() {
    addDrop(TutorialBlocks.EXAMPLE_BLOCK);
  }

This is the most common loot table for a block. When mined, drops one. When exploded in a explosion with decay (such as creeper and nether bed), it may be destroyed totally and drop nothing.

You can also make it drop a little more complex, for example (the code is just to show an exmaple; please do not add loot tables for one block multiple times):

    // drops nothing
    addDrop(TutorialBlocks.EXAMPLE_BLOCK, dropsNothing());
 
    // drops a dirt block
    addDrop(TutorialBlocks.EXAMPLE_BLOCK, Blocks.DIRT);
 
    // drops itself only when with tools with Silk Touch, otherwise drops nothing
    addDropWithSilkTouch(TutorialBlocks.EXAMPLE_BLOCK);
 
    // drops itself only when with tools with Silk Touch, otherwise drops a dirt block
    addDropWithSilkTouch(TutorialBlocks.EXAMPLE_BLOCK, Blocks.DIRT);
 
    // drops itself only when with shears or tools with Silk Touch, otherwise drops nothing
    addDrop(TutorialBlocks.EXAMPLE_BLOCK, dropsWithSilkTouchOrShears(TutorialBlocks.EXAMPLE_BLOCK));
 
    // drops five blocks
    addDrop(TutorialBlocks.EXAMPLE_BLOCK, drops(TutorialBlocks.EXAMPLE_BLOCK)
        .apply(SetCountLootFunction.builder(ConstantLootNumberProvider.create(5))));

You can also generate loot tables for the crops we introduced before:

    addDrop(TutorialBlocks.CUSTOM_CROP, cropDrops(TutorialBlocks.CUSTOM_CROP, TutorialItems.CUSTOM_ITEM, TutorialItems.CUSTOM_SEEDS, BlockStatePropertyLootCondition.builder(TutorialBlocks.CUSTOM_CROP).properties(StatePredicate.Builder.create().exactMatch(CropBlock.AGE, 7))));

Simple Loot Table

To add a simple loot table, which can also be used in many occasions, such as chests, we just extend SimpleFabricLootTableProvider.

TutorialChestLootTableProvider.java
public class TutorialChestLootTableProvider extends SimpleFabricLootTableProvider {
  public TutorialChestLootTableProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registryLookup) {
    super(output, registryLookup, LootContextTypes.CHEST);
  }
 
  public static final RegistryKey<LootTable> TEST_CHEST = RegistryKey.of(RegistryKeys.LOOT_TABLE, Identifier.of("tutorial", "test_chest"));
 
  @Override
  public void accept(BiConsumer<RegistryKey<LootTable>, LootTable.Builder> lootTableBiConsumer) {
    lootTableBiConsumer.accept(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)))
    );
  }
}

And then in your entry point:

ExampleModDataGenerator.java
public class ExampleModDataGenerator implements DataGeneratorEntrypoint {
  @Override
  public void onInitializeDataGenerator(FabricDataGenerator generator) {
    // ...
 
    pack.addProvider(TutorialChestLootTableProvider::new);
  }
}
If you're using versions pre-1.20, please replace pack.addProvider(TutorialChestLootTableProvider::new); with fabricDataGenerator.addProvider(TutorialChestLootTableProvider::new);, and remove FabricDataGenerator.Pack myPack = fabricDataGenerator.createPack();.

Now run the data generator, then start Minecraft and run the command /loot give @s loot tutorial:test_chest multiple times. See what happens! You can also try running the command /setblock ~ ~ ~ chest{LootTable:“tutorial:test_chest”} and open the chest.