Minecraft Blogs / Tutorial

Function Data Packs for Dummies #11 Part 2 | The return of JSON: The Workshop (+ Custom Recipes)

  • 3,147 views, 2 today
  • 29
  • 13
  • 6
Bertiecrafter's Avatar Bertiecrafter
Retired Moderator
Level 70 : Legendary Engineer
775
This series of tutorials will teach you how to create your very own datapacks, assuming you know absolutely nothing about commands. Datapacks can contain a number of things, but only functions and tags will be covered in these posts. In every part I assume you've read the previous parts.

The Plan

So in the last part you've got an introduction to the other data pack files and their wiki pages. Because these files don't really have core concepts, I'm going with a more hands-on experience for this subject.

Here's the plan: We're going to create our own recipe for a treasure shard. Then we detect if the shard is thrown on top of any empty container, using a predicate in combination with a block tag. Finally, once all checks pass we fill that container with goodies from a loot table. Now as you might have guessed, I twisted and morphed the idea until it uses all the possible JSON files. There are a thousand ways to create something that gives random items at a cost and a shard that has to be applied to a chest is probably the wackiest of them all. Anyways, you're encouraged to open up Minecraft, file explorer and your favourite editor so you can follow along.

Before we begin, a quick overview of the resources:

ResourcePurposePath
AdvancementStory telling + Faster trigger alternative to checking scoreboard every tick.
data/<namespace>/advancements
/[​path/]<​name>.json
Loot TableGenerating mob death or chest loot + Good for random item generation (/loot)
data/<namespace>/loot_tables
/[​path/]<​name>.json
PredicateSame as advancement. Slower, but can be used anywhere (not an entry point), because it's checked with a target selector argument.
data/<namespace>/predicates
/[​path/]<name>.json
RecipesMaking custom items accessible. Often used with Advancements to replace placeholder item with NBT filled item.data/<namespace>/recipes
/[​path/]<​name>.json
TagsGrouping items, entities, blocks or functions. Used to target all or check if (not) any.data/<namespace>/tags/<type>
/[​path/]<name>.json

Oh and btw, this blog is going to be a bit lengthy, but it won't be much work.

The Setup

Open up your testing world (assuming you have one) in Minecraft, navigate to its datapacks folder. Make sure you start Minecraft with the logging window opened up (see Part 4). It'll yell at you in red if you did something wrong, very useful for finding and fixing mistakes. Create a new directory called "Treasure Shards" in the datapacks folder with the following file inside:
# pack.mcmeta
{
"pack": {
"pack_format": 6,
"description": {
"text": "Treasure Shards",
"color": "light_purple"
}
}
}

Make sure to do /reload after any changes, I won't be repeating this throughout the blog. Now when you do /datapack list you should see the new data pack appear in the list.

The Recipe

Let's start with our own recipe file and open up the recipe wiki page. On the wiki page you can see a list of recipe types, we want to go with "crafting_shaped". Press "Show" on "Tags common to all recipes". Here you see that we need a "type" key and a "group" key if we were to have multiple recipes that can be grouped. Add the "type" key to the JSON:
# data/<namespace>/recipes/tsh/shard.json
{
"type": "crafting_shaped"
}
Next we see that they expect a "pattern" key from us, a list of strings of single-character keys. Each string must have the same length (smaller or equal to 3). You can make your own recipe, but I'm going for an ender pearl surrounded by redstone dust and gold ingots, like this:
# data/<namespace>/recipes/tsh/shard.json
{
"type": "crafting_shaped",
"pattern": [
"GRG",
"RER",
"GRG"
]
}
Below that we can read on the wiki page that we use the "key" key to specify what each of the letters (G/R/E) means. Each letter is a key to either an object or a list describing the item(s). Although I only accept ender pearls for E, I'm going to accept gold or a rabbit's foot for G and redstone or glowstone for R.
# data/<namespace>/recipes/tsh/shard.json
{
"type": "crafting_shaped",
"pattern": [
...
],
"key": {
"E": {
"item": "minecraft:ender_pearl"
},
"R": [
{
"item": "minecraft:redstone"
},
{
"item": "minecraft:glowstone_dust"
}
],
"G": [
{
"item": "minecraft:gold_ingot"
},
{
"item": "minecraft:rabbit_foot"
}
]
}
}
The last thing the wiki page tells us to add is a "result". We could just set it to the item that represents the shard, but the problem is that we won't be able to distinguish it from any other item of that kind. To make a distinction, we are going to place a bit of NBT in the item, but the recipe file does not support that. Therefore, we use a placeholder item that is unobtainable in survival, has no added value outside a data pack and can be removed from the inventory at any given time. A knowledge book can be used in adventure maps to unlock recipes when the doLimitedCrafting gamerule is enabled, but we will be using it as placeholder for our recipe:
# data/<namespace>/recipes/tsh/shard.json
{
"type": "crafting_shaped",
"pattern": [
...
],
"key": {
...
},
"result": {
"item": "minecraft:knowledge_book"
}
}
Now you'll be able to craft knowledge books with this recipe, but we need to replace the result with our actual item. Checking for the knowledge book every tick (with /execute if data or a predicate) wouldn't work, because then we don't know which recipe generated it. Hidden advancements to the rescue!

Okay, so open up the wiki page for the Advancement JSON format. In the "File Format" you'll find "The root tag", that's where it all begins. The first tag is "display", it also says it's optional so we're going to ignore it because this is a purely functional advancement. We can skip Parent too, because it's something visual as well. Up next is the "criteria" object, each key is a made-up name and a trigger with parameters. In the list of triggers you can find "minecraft:recipe_unlocked" which we are basically doing if you craft the book for the first time. With this in mind, we can fill in the first bit of our criteria:
# data/<namespace>/advancements/tsh/shard_crafted.json
{
"criteria": {
"this_is_a_unique_name_I_came_up_with": {
"trigger": "minecraft:recipe_unlocked"
}
}
}
The wiki page then goes on to tell us that the conditions are trigger specific, looking at the section for "recipe_unlocked", we can see that it wants a "recipe" string and optionally a "player" list to filter down specific players. We don't want to filter out players, so we're just going to write down the recipe we made earlier:
# data/<namespace>/advancements/tsh/shard_crafted.json
{
"criteria": {
"this_is_a_unique_name_I_came_up_with": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "<namespace>:tsh/shard"
}
}
}
}
Continuing with the top-level keys, we can read that the "requirements" key can be used to create an AND/OR structure if the default "AND" relation is not desired, but that's not applicable here because we only have one criteria. Moving on to "rewards", we could create a loot table to give us the item with NBT, but we want to run a function that also clears the book and resets the recipe + advancement so it can trigger again.
# data/<namespace>/advancements/tsh/shard_crafted.json
{
"criteria": {
...
},
"rewards": {
"function": "<namespace>:tsh/shard_crafted"
}
}
And finally, we have to create the mentioned function that gives the item, clears the knowledge book and resets the recipe + advancement.
# data/<namespace>/functions/tsh/shard_crafted.mcfunction
# As/At: Player who crafted the Treasure Shard
recipe take @s bertiecrafter:tsh/shard
advancement revoke @s only bertiecrafter:tsh/shard_crafted

# Summon item with temporary tag, custom identifier for later (in tag key), a useless enchant just for the pretty glint, a modifier to hide the enchantment and a pretty name.
summon item ~ ~ ~ {Tags:["bctsh_tmp"],Item:{id:"minecraft:emerald",Count:1b,tag:{bctsh_shard:1b,Enchantments:[{"id":"minecraft:unbreaking",lvl:1}],HideFlags:1,display:{Name:'{"text":"Treasure Shard","color":"yellow","bold":true,"italic":false}'}}}}
# Store the amount of books in the Count key of the new item. This allows crafting multiple items at once.
execute store result entity @e[tag=bctsh_tmp,limit=1] Item.Count byte 1 run clear @s minecraft:knowledge_book
tag @e[tag=bctsh_tmp] remove bctsh_tmp
You've done it! You should now be able to craft Treasure Shards with custom data. Let it sink in, take a break if you need to, take a moment to be proud of yourself and then buckle up for the next part =)

The chest detection

So now we're going to make a tick function and use a predicate and block tag to detect containers. An advancement doesn't work here, because it isn't player related and there isn't really a useful trigger for this. Before we create our tick function, we must tell Minecraft that it should be executed 20 times a second by registering it in the minecraft:tick tag:
# data/minecraft/tags/functions/tick.json
{
"values": [
"<namespace>:tsh/tick"
]
}
You must have written it a million times, but if not you should be able to match the text to the given structure on the wiki page. The specified function is really short, but gets a little complex to account for containers that aren't full blocks. Once all checks pass, we can insert the loot and kill the item.
# data/<namespace>/functions/tsh/tick.mcfunction
# As/At: Server
# For full block containers:
execute as @e[type=item,nbt={Item:{tag:{bctsh_shard:1b}}},predicate=<namespace>:tsh/container_below] at @s run function <namespace>:tsh/fill
# Shifting the location before testing the predicate to account for non-full blocks (chests):
execute as @e[type=item,nbt={Item:{tag:{bctsh_shard:1b}}}] at @s positioned ~ ~1 ~ if predicate <namespace>:tsh/container_below run function <namespace>:tsh/fill
# data/<namespace>/functions/tsh/fill.mcfunction
# As: Item
# At: Block above container.
loot replace block ~ ~-1 ~ container.0 loot minecraft:chests/abandoned_mineshaft
kill @s
Let's create the specified predicate, but a little bit faster this time. On the wiki page you can read that it wants a "condition" key in the root tag. We're going for a "location_check". It comes with some simple offset numbers which we set to target the block below us. Then we're going to use the "predicate" key, with "block" key inside and "tag" + "nbt" keys inside that to target empty containers.
# data/<namespace>/predicates/tsh/container_below.json
{
"condition": "location_check",
"offsetX": 0,
"offsetY": -1,
"offsetZ": 0,
"predicate": {
"block": {
"tag": "<namespace>:tsh/containers",
"nbt": "{Items:[]}"
}
}
}
Great, the last piece missing in the detection is the tag that lists all container blocks:
# data/<namespace>/tags/blocks/tsh/containers.json
{
"values": [
"minecraft:chest",
"minecraft:trapped_chest",
"minecraft:barrel"
]
}
Note: Shulker boxes do not have "Items:[]" when they are empty, causing the predicate to fail. Detecting an empty container with "/execute if block ~ ~-1 ~ #<namespace>:tsh/containers unless data block ~ ~-1 ~ Items[​0]" would be a better fit to support all containers, but for the sake of demonstration we're going with predicates here.

Awesome, we can now craft Treasure Shards and apply them to containers. Give yourself a pat on the shoulder! All you have to do now is adding your own custom loot table!

The Loot

Let's start by creating the file. From the wiki page we can see that it wants a "type" string as the very first thing and it gives us the possible values. Using the most appropriate value gives us:
# data/<namespace>/loot_tables/tsh/treasure.json
{
"type": "command"
}
The next key is "functions" which act like modifiers across all the generated loot, we don't need to modify all items so it'll be skipped. Then it wants a "pools" key, containing groups of items to randomly pick from. We'll have 1 pool. Inside we can skip "conditions" and "functions" for obvious reasons. We want to draw 27 items from the pool, one for each slot, so that's what we specify for "rolls". The Luck potion effect should not influence rolls, so we'll set "bonus_rolls" to 0. Lastly there is "entries", we'll create some empty objects that will be filled in the next step.
# data/<namespace>/loot_tables/tsh/treasure.json
{
"type": "chest",
"pools": [
{
"rolls": 27,
"bonus_rolls": 0,
"entries": [
{},
{},
{}
]
}
]
}
Note: The wiki page was already updated to 1.17 at the time of writing, but this is a 1.16 loot table. I used an existing generator to figure out that "rolls" and "bonus_rolls" should be plain numbers, not objects.

The objects inside "entries" allow for a lot of customization, but we're just going for simple items. We're going to skip "conditions" and "functions" again and specify "type" as "item". Then based on the type it wants either a "name" string or a "children" list (and possibly the "expand" boolean). Because our type is "item", we're going to set the "name" key to the appropriate ID and omit "children". We're going to give each item appropriate weights to make sure the valuable items won't get picked as much. We again don't want Luck to affect us, so we'll set quality to 0.
# data/<namespace>/loot_tables/tsh/treasure.json
{
"type": "chest",
"pools": [
{
"rolls": 27,
"bonus_rolls": 0,
"entries": [
{
"type": "item",
"name": "minecraft:iron_ingot",
"weight": 1,
"quality": 0
},
{
"type": "item",
"name": "minecraft:dirt",
"weight": 4,
"quality": 0
},
{
"type": "item",
"name": "minecraft:cobblestone",
"weight": 2,
"quality": 0
},
{
"type": "item",
"name": "minecraft:oak_planks",
"weight": 2,
"quality": 0
}
]
}
]
}
The wiki page tells us that the default amount of items will be 64, unless we use a set_count function. So that's exactly what we're going to add. We could add it to each of the items individually, to the entire pool or to the entire loot table. I'm just going to add it to the entire loot table and set the amount of any item to a random number between 1 and 8.
{
"type": "chest",
"functions": [
{
"function": "set_count",
"count": {
"type": "uniform",
"min": 1,
"max": 8
}
}
],
"pools": [
{
...
}
]
}

Lastly, we should use our loot table in the fill function.
# data/<namespace>/functions/tsh/fill.mcfunction
# As: Item
# At: Block above container.
loot replace block ~ ~-1 ~ container.0 loot <namespace>:tsh/treasure
kill @s

Challenge Yourself

After every tutorial, I'll include a section where you are challenged to apply what you've learned. I recommend you playing with what you've learned, it helps you getting familiar with new concepts and be able to find solutions to problems. You don't have to do exactly what's written below, you can always challenge yourself in a different way.

The advancement we made is invisible and revoked every time, so it can trigger multiple times. For story-telling purposes, it would be nice to have a visible advancement that can only be achieved once. Start off with a copy of the existing advancement, add a "display" object, add a "parent" string and change up the reward. Other than that, you can try add sound and particles to the function that is executed when the shard is applied to the chest.

What's next?

The next tutorial will be about.... uhm.... Not sure actually. All that's left is structure blocks and the role of resource packs I think. Let me know what you'd like to see next!

Subscribe if you want to get notified of new posts.

Function Data Packs for Dummies #11 Part 2 | The return of JSON: The Workshop (+ Custom Recipes)
Function Data Packs for Dummies #11 Part 2 | The return of JSON: The Workshop (+ Custom Recipes)
Tags

Create an account or sign in to comment.

2
05/03/2021 2:12 am
Level 29 : Expert Engineer
SUPERIONtheKnight
SUPERIONtheKnight's Avatar
Awesome tutorials! While I knew most of the contents, I still got something from it! I had no idea that I could use a hex code for text colors(Thinking about it now, no idea why I didn't figure it out sooner. lol)! Also had no idea that there was a workaround to the NBT problem for custom recipes!

Great job! I will definitely use what I learned, and share these tutorials with others in the future. Thanks for making these! :)
2
05/03/2021 11:37 am
Level 70 : Legendary Engineer
Bertiecrafter
Bertiecrafter's Avatar
I'm glad you enjoyed it, thanks for the kind words!
3
01/27/2021 12:37 pm
Level 38 : Artisan Pixel Painter
Dunk__
Dunk__'s Avatar
Yay, I finished!!!!
3
12/31/2020 11:26 am
Level 58 : Grandmaster Theorist
Chimerabot
Chimerabot's Avatar
It really annoys me that Mojang hasn't implemented crafting using items with NBT data yet. That would make this whole process so much easier.
Hopefully they add something like that in 1.17...
4
12/31/2020 11:29 am
Level 70 : Legendary Engineer
Bertiecrafter
Bertiecrafter's Avatar
Yuuuuuuuuuuuuuuuup it's quite dumb that we have to go the long way through advancements and functions.
2
12/31/2020 10:19 amhistory
Level 70 : Legendary Engineer
Bertiecrafter
Bertiecrafter's Avatar
Thank you usernamed_, FishStacks, Luracasmus, Vellaris, Chimerabot, DinoDesmond, Cib, JitteryPluto, PMC, HydroByte, TomConn, TheBigPug, MineFriggs, Yellowglacier, Sir_Wodr, RoBoo1194, Hynii, User3500563G, SUPERIONtheKnight, Blip_Creations, Brownie1111, Carouan, OnlyHouska, BarrowWight and OnlyHouska for the diamonds!
Planet Minecraft

Website

© 2010 - 2024
www.planetminecraft.com

Welcome