tutorial:datagen_advancements
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionLast revisionBoth sides next revision | ||
tutorial:datagen_advancements [2022/12/22 11:52] – [One More Simple Example] jmanc3 | tutorial:datagen_advancements [2023/09/29 18:08] – Updated pre-custom criterion section for fabric 1.20.2 jmanc3 | ||
---|---|---|---|
Line 5: | Line 5: | ||
==== Before continuing ==== | ==== Before continuing ==== | ||
- | Make sure you've to read the first section of the [[datagen_setup|Getting started with Data Generation]] page, have a class that implements '' | + | Make sure you've to read the first section of the [[datagen_setup|Getting started with Data Generation]] page, have a class that implements '' |
===== Hooking Up the Provider ===== | ===== Hooking Up the Provider ===== | ||
- | To begin making custom advancements, | + | To begin making custom advancements, |
- | Unfortunately there' | + | <code java> |
- | + | ||
- | <code java [highlight_lines_extra=" | + | |
import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; | import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; | ||
import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; | import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; | ||
+ | import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; | ||
+ | import net.fabricmc.fabric.api.datagen.v1.provider.FabricAdvancementProvider; | ||
+ | import net.minecraft.advancement.*; | ||
+ | import java.util.function.Consumer; | ||
- | public class DataGeneration | + | public class ExampleModDataGenerator |
@Override | @Override | ||
public void onInitializeDataGenerator(FabricDataGenerator generator) { | public void onInitializeDataGenerator(FabricDataGenerator generator) { | ||
- | | + | |
- | /* Add our advancements generator | + | |
- | **/ | + | |
- | | + | |
- | | + | |
} | } | ||
- | } | ||
- | </ | ||
- | * It should be noted that the '' | + | static |
+ | protected AdvancementsProvider(FabricDataOutput dataGenerator) { | ||
+ | super(dataGenerator); | ||
+ | } | ||
- | We passed the '' | + | |
- | + | public void generateAdvancement(Consumer< | |
- | <code java [highlight_lines_extra=" | + | // |
- | import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; | + | // We will create our custom advancements here... |
- | import net.fabricmc.fabric.api.datagen.v1.provider.FabricAdvancementProvider; | + | // |
- | import net.minecraft.advancement.Advancement; | + | |
- | + | ||
- | import java.util.function.Consumer; | + | |
- | + | ||
- | public class AdvancementsProvider extends FabricAdvancementProvider { | + | |
- | protected AdvancementsProvider(FabricDataOutput dataGenerator) { | + | |
- | super(dataGenerator); | + | |
- | } | + | |
- | + | ||
- | | + | |
- | public void generateAdvancement(Consumer< | + | |
- | | + | |
} | } | ||
} | } | ||
</ | </ | ||
- | You'll once again notice on the highlighted line that we have another class we haven' | + | * It should be noted that the '' |
- | + | ||
- | Here's how the '' | + | |
- | + | ||
- | <code java> | + | |
- | import net.minecraft.advancement.Advancement; | + | |
- | + | ||
- | import java.util.function.Consumer; | + | |
- | + | ||
- | public class Advancements implements Consumer< | + | |
- | + | ||
- | @Override | + | |
- | public void accept(Consumer< | + | |
- | // | + | |
- | // We will create our custom advancements here... | + | |
- | // | + | |
- | } | + | |
- | } | + | |
- | </ | + | |
===== Simple Advancement ===== | ===== Simple Advancement ===== | ||
- | Let's start simple and work our way up to custom criterions. We'll start with an advancement that activates after you pick up your first dirt block, and we're going to add it to our '' | + | Let's start simple and work our way up to custom criterions. We'll start with an advancement that activates after you pick up your first dirt block, and we're going to add it to the function |
<code java> | <code java> | ||
- | import net.minecraft.advancement.Advancement; | + | // ... (Previous imports) |
- | import net.minecraft.advancement.AdvancementFrame; | + | |
import net.minecraft.advancement.criterion.InventoryChangedCriterion; | import net.minecraft.advancement.criterion.InventoryChangedCriterion; | ||
import net.minecraft.item.Items; | import net.minecraft.item.Items; | ||
Line 86: | Line 56: | ||
import net.minecraft.util.Identifier; | import net.minecraft.util.Identifier; | ||
- | import java.util.function.Consumer; | + | public class ExampleModDataGenerator implements DataGeneratorEntrypoint { |
- | public class Advancements implements Consumer< | + | // ... (Rest of the code) |
- | @Override | + | |
- | public void accept(Consumer< | + | |
- | | + | // ... (Rest of the code) |
- | .display( | + | |
- | Items.DIRT, // The display icon | + | |
- | Text.literal(" | + | public void generateAdvancement(Consumer< |
- | Text.literal(" | + | |
- | new Identifier(" | + | .display( |
- | AdvancementFrame.TASK, | + | Items.DIRT, // The display icon |
- | true, // Show toast top right | + | Text.literal(" |
- | true, // Announce to chat | + | Text.literal(" |
- | false // Hidden in the advancement tab | + | new Identifier(" |
- | ) | + | AdvancementFrame.TASK, |
- | // The first string used in criterion is the name referenced by other advancements when they want to have ' | + | true, // Show toast top right |
- | .criterion(" | + | true, // Announce to chat |
- | .build(consumer, | + | false // Hidden in the advancement tab |
+ | ) | ||
+ | // The first string used in criterion is the name referenced by other advancements when they want to have ' | ||
+ | .criterion(" | ||
+ | .build(consumer, | ||
+ | } | ||
} | } | ||
} | } | ||
</ | </ | ||
- | * Make sure you change the '' | + | * Make sure you change the '' |
- | I'll explain in more detail what everything means, but if you compile your program now, and jump into a world in minecraft, you'll notice nothing happens. That's because we haven' | + | I'll explain in more detail what everything means, but if you compile your program now, and jump into a world in minecraft, you'll notice nothing happens. That's because we haven' |
- | So open up your projects root directory | + | If you have a configuration on '' |
+ | or you can open your projects root folder | ||
- | <code bash> | + | <code bash Windows> |
- | ./ | + | gradlew runDatagen |
+ | </ | ||
+ | |||
+ | <code bash Linux> | ||
+ | ./ | ||
</ | </ | ||
- | In the '' | + | In the '' |
<code javascript> | <code javascript> | ||
Line 162: | Line 142: | ||
</ | </ | ||
| | ||
- | Go ahead and run the game now and see if the advancement works by collecting a dirt block. You should even be able to leave the world, come back, collect another dirt block and notice that there is no re-trigger. If you press '' | + | Go ahead and run the game now and see if the advancement works by collecting a dirt block. You should even be able to leave the world, come back, collect another dirt block and notice that there is no re-trigger. If you press '' |
* **NOTE:** You have to complete one advancement in the tab group to open it up, otherwise the tab wont show (just in case you were wondering were the vanilla advancements were). | * **NOTE:** You have to complete one advancement in the tab group to open it up, otherwise the tab wont show (just in case you were wondering were the vanilla advancements were). | ||
Line 168: | Line 148: | ||
===== Advancements Explained ===== | ===== Advancements Explained ===== | ||
- | All advancements in minecraft look like that '' | + | All advancements in minecraft look like that '' |
- | Let's go through the advancement we created step by step and see the options we have. We start by calling the '' | + | Let's go through the advancement we created step by step and see the options we have. We start by calling the '' |
<code java> | <code java> | ||
- | Advancement | + | AdvancementEntry |
</ | </ | ||
Line 204: | Line 184: | ||
</ | </ | ||
- | Then we tell Minecraft when this advancement should be triggered (like after eating an item, or in our case, after a block enters our inventory) calling the '' | + | Then we tell Minecraft when this advancement should be triggered (like after eating an item, or in our case, after a block enters our inventory) calling the '' |
<code java> | <code java> | ||
Line 210: | Line 190: | ||
</ | </ | ||
- | The first argument is a name of type '' | + | The first argument is a name of type '' |
- | * This name is only ever used by '' | + | * This name is only ever used by '' |
- | The second argument is the criterion. In our example we use the '' | + | The second argument is the criterion. In our example we use the '' |
| PlayerHurtEntityCriterion.class | ImpossibleCriterion.class | Criterion.class | AbstractCriterion.class | VillagerTradeCriterion.class | | PlayerHurtEntityCriterion.class | ImpossibleCriterion.class | Criterion.class | AbstractCriterion.class | VillagerTradeCriterion.class | ||
Line 234: | Line 214: | ||
</ | </ | ||
- | We pass it the '' | + | We pass it the '' |
- | * Make sure you change the '' | + | * Make sure you change the '' |
===== One More Example ===== | ===== One More Example ===== | ||
Line 244: | Line 224: | ||
<code java> | <code java> | ||
- | import net.minecraft.advancement.Advancement; | + | package com.example; |
- | import net.minecraft.advancement.AdvancementFrame; | + | |
+ | 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.FabricAdvancementProvider; | ||
+ | import net.minecraft.advancement.*; | ||
+ | import java.util.function.Consumer; | ||
+ | import net.minecraft.advancement.criterion.ConsumeItemCriterion; | ||
import net.minecraft.advancement.criterion.InventoryChangedCriterion; | import net.minecraft.advancement.criterion.InventoryChangedCriterion; | ||
import net.minecraft.item.Items; | import net.minecraft.item.Items; | ||
Line 251: | Line 238: | ||
import net.minecraft.util.Identifier; | import net.minecraft.util.Identifier; | ||
- | import java.util.function.Consumer; | + | public class ExampleModDataGenerator implements DataGeneratorEntrypoint { |
- | public class Advancements implements Consumer< | + | // ... (Rest of the code) |
- | | + | |
- | public void accept(Consumer< | + | |
- | Advancement rootAdvancement = Advancement.Builder.create() | + | |
- | .display( | + | |
- | Items.DIRT, // The display icon | + | |
- | Text.literal(" | + | |
- | Text.literal(" | + | |
- | new Identifier(" | + | |
- | AdvancementFrame.TASK, | + | |
- | true, // Show toast top right | + | |
- | true, // Announce to chat | + | |
- | false // Hidden in the advancement tab | + | |
- | ) | + | |
- | // The first string used in criterion is the name referenced by other advancements when they want to have ' | + | |
- | .criterion(" | + | |
- | .build(consumer, | + | |
- | | + | // ... (Rest of the code) |
- | .display( | + | |
- | Items.OAK_LOG, | + | |
- | Text.literal(" | + | |
- | Text.literal(" | + | |
- | null, // children to parent advancements don't need a background set | + | |
- | AdvancementFrame.TASK, | + | |
- | true, | + | |
- | true, | + | |
- | false | + | |
- | ) | + | |
- | | + | |
- | .criterion(" | + | |
- | .build(consumer, | + | |
- | Advancement eatAppleAdvancement = Advancement.Builder.create().parent(rootAdvancement) | + | |
- | .display( | + | public void generateAdvancement(Consumer< |
- | Items.APPLE, | + | AdvancementEntry rootAdvancement = Advancement.Builder.create() |
- | Text.literal(" | + | .display( |
- | Text.literal(" | + | Items.DIRT, // The display icon |
- | null, // children to parent advancements don't need a background set | + | Text.literal(" |
- | AdvancementFrame.CHALLENGE, | + | Text.literal(" |
- | true, | + | new Identifier(" |
- | true, | + | AdvancementFrame.TASK, |
- | false | + | true, // Show toast top right |
- | ) | + | true, // Announce to chat |
- | .criterion(" | + | false // Hidden in the advancement tab |
- | .criterion(" | + | ) |
- | .build(consumer, | + | // The first string used in criterion is the name referenced by other advancements when they want to have ' |
+ | .criterion(" | ||
+ | .build(consumer, | ||
+ | |||
+ | AdvancementEntry gotOakAdvancement = Advancement.Builder.create().parent(rootAdvancement) | ||
+ | .display( | ||
+ | Items.OAK_LOG, | ||
+ | Text.literal(" | ||
+ | Text.literal(" | ||
+ | null, // children to parent advancements don't need a background set | ||
+ | AdvancementFrame.TASK, | ||
+ | true, | ||
+ | true, | ||
+ | false | ||
+ | ) | ||
+ | .rewards(AdvancementRewards.Builder.experience(1000)) | ||
+ | .criterion(" | ||
+ | .build(consumer, | ||
+ | |||
+ | AdvancementEntry | ||
+ | .display( | ||
+ | Items.APPLE, | ||
+ | Text.literal(" | ||
+ | Text.literal(" | ||
+ | null, // children to parent advancements don't need a background set | ||
+ | AdvancementFrame.CHALLENGE, | ||
+ | true, | ||
+ | true, | ||
+ | false | ||
+ | ) | ||
+ | .criterion(" | ||
+ | .criterion(" | ||
+ | .build(consumer, | ||
+ | } | ||
} | } | ||
} | } | ||
</ | </ | ||
- | Don't forget to generate the data. | + | Don't forget to generate the data (Run the gradle task). |
- | <code bash> | + | <code bash Windows> |
- | ./ | + | gradlew runDatagen |
+ | </ | ||
+ | |||
+ | <code bash Linux> | ||
+ | ./ | ||
</ | </ | ||
- | We added another | + | We added an advancement that activates when you get an oak log, and which awards one-thousand experience when completed. And we added another |
<code java> | <code java> | ||
Line 324: | Line 320: | ||
<code java> | <code java> | ||
- | Advancement | + | AdvancementEntry |
// .... | // .... | ||
- | Advancement | + | AdvancementEntry |
</ | </ | ||
* If an advancement doesn' | * If an advancement doesn' | ||
- | We also, of course, changed the titles and descriptions, | + | We also, of course, changed the titles and descriptions, |
===== When To Make a Custom Criterion? ===== | ===== When To Make a Custom Criterion? ===== | ||
Line 343: | Line 339: | ||
===== How To Make a Custom Criterion? ===== | ===== How To Make a Custom Criterion? ===== | ||
- | Our mod is keeping track of how many jumping jacks a player has done, and we want to make an advancement when they complete one hundred. First thing we got to do is make the '' | + | Our mod is keeping track of how many jumping jacks a player has done, and we want to make an advancement when they complete one hundred. First thing we got to do is make the '' |
<code java> | <code java> | ||
Line 386: | Line 382: | ||
</ | </ | ||
- | You'll notice inside the class, there is another class called '' | + | You'll notice inside the class, there is another class called '' |
Let's create an advancement with it now. | Let's create an advancement with it now. | ||
Line 423: | Line 419: | ||
<code bash> | <code bash> | ||
- | ./ | + | ./ |
</ | </ | ||
Line 456: | Line 452: | ||
</ | </ | ||
- | * Because we aren't implementing a full blown mod we pretend a function '' | + | * Because we aren't implementing a full blown mod we pretend a function '' |
+ | |||
+ | * **NOTE:** You must call '' | ||
- | If you run your game now (changing that fake function to a simple '' | + | If you run your game now (changing that fake function to a simple '' |
- | The last thing to do is to make a criterion that takes in some data when created and uses it during when the trigger function is called. (Like how the consume item criterion takes an '' | + | The last thing to do is to make a criterion that takes in some data when created and uses it during when the trigger function is called. (Like how the consume item criterion takes an '' |
===== Criterion with State ===== | ===== Criterion with State ===== | ||
Line 519: | Line 517: | ||
</ | </ | ||
- | Our '' | + | Our '' |
- | You'll also notice that the '' | + | You'll also notice that the '' |
Now we could write our advancement like so: | Now we could write our advancement like so: |
tutorial/datagen_advancements.txt · Last modified: 2023/10/02 23:11 by jmanc3