Minecraft Blogs / Tutorial

Clever datapack trick to add NBT data to custom recipes

  • 625 views, 15 today
  • 8
  • 3
  • 4
GGCrosby avatar GGCrosby
Level 20 : Expert Scribe
32
I found a clever trick for datapacks using a combination of scoreboards and player's NBT data to make custom crafts where the output item comes with custom NBT data.

In this blog, I will outline the steps to do so and how I implemented it to create a custom set of tools worst than wood.



Step 0

Simply put this inside your namespace recipes folder and it will add a brand new recipe for a stone sword.
{
"type": "crafting_shapeless",
"ingredients": [
{
"item": "minecraft:flint"
},
{
"item": "minecraft:stick"
}
],
"result": {
"item": "minecraft:stone_sword",
"count": 1
}
}



Step 1

Step one, you want to create two scoreboards inside your reload function. For this example, I will make a flint knife, which will be a weaker version of a wooden sword.
scoreboard objectives create knife minecraft.crafted:minecraft.stone_sword
scoreboard objectives create success dummy

Here, we create an objective to know when a standard stone sword has been crafted. Right now, it adds a point to the score every time any sword is crafted, we will fix that later. The dummy objective is technically optional, but without it, it's entirely possible that items get either deleted or duplicated.



Step 2

Step two, you want to check for changes in the scoreboard in your tick function. Simply insert the following line:

execute if @a[​scores={knife=1..}] run function <namespace>:knife

What this will do is every time someone crafts a stone sword, it runs a separate function called knife.
In this step, you also want to create a function called knife.



Step 3

Step three, since our flint knife is pre-wood technology, we assume the player does not have access to a crafting table, and as such must use the crafting menu. The following line of code will be put in the knife function and will check for that exact scenario.

execute at @a[​scores={knife=1..}] store success score @p[​scores={knife=1..},nbt={isGuiOpen=1b}] success byte 1 if @p[​scores={knife=1..},nbt={isGuiOpen=1b}] run clear @p[​scores={knife=1..},nbt={isGuiOpen=1b}] stone_sword 1

This is a complicated one, and as such I will explain it one subcommand at a time.

Firstly, the "at" subcommand. It's standard practice to use at with an @a and then changing it to @p when dealing with NBT data in order to always select a single player, this is because NBT manipulation does not work on target selectors such as @a and @e.

Next, the "store" subcommand. This one checks if the stone sword that was crafted actually got cleared so that we can replace it with our new one. We need this as some people don't shift-click the item out of their crafting grid, but instead drag it, taking time after it has been crafted. If you didn't add the optional scoreboard on step one, you can remove this subcommand.
With this part of the command, the function will run once every tick until the player has finished dragging the sword out of their crafting grid.

Next, the "if" subcommand simply checks if both a knife has been crafted and the player is inside their inventory. If one of those is false, the command won't run.

Lastly, "run" simply runs a command deleting a single stone sword from their inventory.



Step 4

This part will also go in the knife function and will stop the function from looping if the sword was crafted in a crafting table.

execute at @a[​scores={knife=1..}] unless @p[​scores={knife=1..},nbt={isGuiOpen=1b}] run scoreboard players remove @p[​scores={knife=1..},nbt={isGuiOpen=0b}] knife 1

This piece is simple, if the sword was crafted in a crafting table, it removes the score you gained when you crafted it.



Step 5

This piece of the datapack is also rather complicated, as it will give the player a stone sword with a custom name and NBT tag attached to it. Again, paste this into knife.

execute if @a[​scores={success=1}] run give @a[​scores={success=1}] minecraft:stone_sword{display:{Name:'[{"text":"Flint Knife"}]'},Tags:["flint_knife"]} 1

Here we have the standard start when dealing with NBT data, with "at" and "if", but where it becomes a bit complicated is with the "run", where we put two pieces of NBT data on the sword, a name and a tag. This tag will help us differentiate this sword from the others without players being able to cheat by changing the name. Currently, this sword deals as much damage as a normal stone sword, but before fixing that, there is another step to do.



Step 6

This step is simple, we just remove the knife score from the player as well as the success score.

execute if @a[​scores={success=1}] run scoreboard players remove @a[​scores={success=1}] knife 1
execute if @a[​scores={success=1}] run scoreboard players set @a[​scores={success=1}] success 0

It's almost the same as step 4, but with an added command removing the success score.



Step 7

This time, for the last step, we change it up and add a line to the tick command, which will weaken the knife. The command is a bit complicated and different from the others.

execute at @a if @p[​nbt={SelectedItem:{tag:["flint_knife"]}}] run effect give @p[​nbt={SelectedItem:{tag:["flint_knife"]}}] weakness 1 0 false


This one simply detects if anyone is holding the knife and if so gives them temporary weakness, as to make the knife weaker than other weapons.



Conclusion

There are definitely ways to make this run with better performance, and I may upgrade this blog in the days to come with performance upgrades, a complete copy+pastable recipe for the knife and complete copy+pastable functions, but I've been writing for an hour now and I'm developing carpal tunnel.



Changelog:

Edit 1: Removed "art" tag (whoops) and fixed structure and colour issues.
Edit 2: Added copy + pastable recipe and cleaned up a lot of the commands where it checked for both success=1 and knife=1.., even though you need knife=1.. to have success=1. Also removed unneeded "at" subcommands where it wasn't dealing with NBT data.
CreditGrammarly for not making me seem like a complete idiot with my writing.
Tags

2
12/15/2020 1:49 pmhistory
Level 25 : Expert Dragonborn
Tigerfury26
Tigerfury26 avatar
Dude. Everyone else already has a different way of doing it that makes a lot less lag.
Step 1: Add recipe

{
"type": "crafting_shapeless",
"ingredients": [
{
"item": "minecraft:flint"
},
{
"item": "minecraft:stick"
}
],
"result": {
"item": "minecraft:knowledge_book",
"count": 1
}
}

Step 2: Add advancements

{ "criteria": {
"Unlocked": {
"trigger": "minecraft:recipe_unlocked",
"conditions": { "recipe": "knife:kniferecipe" }
}
},
"rewards": {
"function": "knife:knife/recipe"
}
}

Step 3: Do a loop function

recipe take @s knife:kniferecipe

advancement revoke @s only knife:kniferecipeadv

give @s minecraft:stone_sword{display:{Name:'[{"text":"Flint Knife"}]'},AttributeModifiers:[{AttributeName:"generic.attack_damage", Name:"generic.attack_damage", Amount:-1.0, Operation:0, UUID:[​I; 42853, 1689024593, -201178, -1559272105]
clear @s minecraft:knowledge_book 1
1
12/15/2020 11:56 pm
Level 20 : Expert Scribe
GGCrosby
GGCrosby avatar
Of course, I already knew this method, however, I heavily dislike it as it is not visually pleasing (using another separate item instead of using the item you want to craft itself like mine) and it can easily catch new users off guard as it did to me when I first used a data pack that used this trick.

Yes, I know mine has some janky things such as adding a cheaper stone sword recipe for crafting tables, but I'd still use my way over using the knowledge book.

Performance isn't as big a concern for me over making the game experience feel better.
2
12/16/2020 12:38 pm
Level 25 : Expert Dragonborn
Tigerfury26
Tigerfury26 avatar
OK, but at least use an attribute instead of infinite weakness.
1
12/16/2020 4:26 pm
Level 20 : Expert Scribe
GGCrosby
GGCrosby avatar
That is true, I hadn't thought about that.
Though it's not actually infinite, it's possible that the weakness rubs off on another slot, so good point! :D

I'll update my blog when I get the chance. Should be updated by tomorrow.
Planet Minecraft Logo

Website

© 2010 - 2021
www.planetminecraft.com

Welcome