Minecraft Blogs / Tutorial

Function Data Packs for Dummies #10 Part 2 | NBT: Taking Control (/data & /execute store)

  • 4,027 views, 1 today
  • 25
  • 9
  • 1
Bertiecrafter's Avatar Bertiecrafter
Site Moderator
Level 70 : Legendary Engineer
767
This series of tutorials will teach you how to create your very own data packs, assuming you know absolutely nothing about commands. Although data packs could just contain files that replace built-in assets like resource packs, these posts will focus on adding new features and mechanics to the game. In every part I assume you've read the previous parts.

Recap

In the last tutorial we explored the syntax of NBT and played around with commands that allow us to define NBT during the creation of an item, block or entity. We've also seen that NBT looks a lot like JSON, but distinguishes between a lot more value types. Minecraft doesn't use NBT everywhere though, as the Raw JSON Text Component used to represent text in /tellraw, signs and books is just JSON. In order to use JSON in NBT, we had to surround it in single quotes to turn it into a string type. In this tutorial we'll have a look at how to manipulate NBT using commands and in part 3 we'll look at ways to check for NBT. As you will see, the understanding of NBT is extremely powerful, but also needs a long time to get everything covered. Part 3 will be the last part of the NBT section of this series.

Paths

In order to tell Minecraft where to add, set, remove or get data in several commands, you need to specify a path. Each of the examples will start with the full NBT structure, followed by a path targeting a part of it, followed by the outcome of the selection. This wiki page has been used as source for the path syntax.

The root
Remember from the JSON tutorial that any JSON file only has 1 value. By making that value a compound or list, a more complex data structure can be generated, but this main top-level value is called the root. The same applies to NBT.
NBT: {someKey:"someValue"}
PATH: *empty path*
RESULT: {someKey:"someValue"}

Navigating to values of compounds
Values of objects can be selected using the dot.
NBT: {simpleKey:"simpleValue",deepCompound:{deepKey:"deepValue",anotherCompound:{key:"value"}},list:["value1","value2"]}

PATH: simpleKey
RESULT: "simpleValue"

PATH: deepCompound
RESULT: {deepKey:"deepValue",anotherCompound:{key:"value"}}

PATH: deepCompound.deepKey
RESULT: "deepValue"

PATH: deepCompound.anotherCompound.key
RESULT: "value"

PATH: list
RESULT: ["value1","value2"]

Navigating to values inside lists
Besides targeting an entire list, you can also target a specific item in the list. You can select an item by index, which is zero-based, meaning the first item in the list has index 0. Negative values can be used to target the n-th item from the end.
NBT: {list:["value1",{simpleKey:"simpleValue",moreData:{deepKey:"deepValue"}},["anotherValue1","anotherValue2"]]}

PATH: list
RESULT: ["value1",{simpleKey:"simpleValue",moreData:{deepKey:"deepValue"}},["anotherValue1","anotherValue2"]]

PATH: list[0]
RESULT: "value1"

PATH: list[1]
RESULT: {simpleKey:"simpleValue",moreData:{deepKey:"deepValue"}}

PATH: list[-1]
RESULT: ["anotherValue1","anotherValue2"]

PATH: list[1].simpleKey
RESULT: "simpleValue"

PATH: list[2][0]
RESULT: "anotherValue1"

Navigating through JSON
Unfortunately, this is not possible, because JSON values are always written as strings instead of NBT compounds.
NBT: {Text1:'{"text":"Hey!"}'}

PATH: Text1
RESULT: '{"text":"Hey!"}'

PATH: Text1.text
RESULT: *Error: Found no elements*

Reading and Writing

The /data command can be used to get or modify data on already existing entities and blocks. This is the syntax:
/data get (block|entity|storage) <target> [path] [scale]
/data modify (block|entity|storage) <target> <path> (append|insert <index>|merge|prepend|set) value <value>
/data modify (block|entity|storage) <target> <path> (append|insert <index>|merge|prepend|set) from (block|entity|storage) <target> [path]
/data remove (block|entity|storage) <target> <path>
The "target" argument has a different meaning based on the medium specified in front.
  • For "block", the target is a set of (relative) coordinates.
  • For "entity", the target is a target selector. Only 1 entity can be selected, but this can be solved by using the "limit" and "sort" target selector arguments to only select 1 entity or "/execute as <multiple entities> run data ... entity @s ....." to select multiple entities. Also players cannot be modified using the /data command.
  • For "storage", the target is a namespaced storage name (e.g. bertiecrafter:my_storage). Storage is an unstructured space used to do anything you want with. There is no filled storage space in any fresh world. You can't explicitly create or delete a storage space as this will happen automatically based on first value insertion or last value deletion.
In "/data get", the "scale" argument allows you to multiply or divide the result by a certain number.
In "/data modify", each operation can only be applied to certain data types.
  • For "append", "insert" and "prepend", the target path must specify a list.
  • For "merge" the target path must specify a compound.
  • For "set" the target path must specify a compound key.
Also in "/data modify" you can copy data from a block/entity/storage source instead of just providing a pre-defined value.

To get a better feel for the syntax, let's look at some examples. Remember that the NBT structure for entities and blocks can be found here and the NBT structure of items can be found here.
# Stand on top of a chest and get the item in the first slot:
/data get block ~ ~ ~ Items[0]
# Note that Items[0] is not guaranteed to have the item in the first slot,
# since each Item has a Slot tag that contains the actual slot.
# The NBT Path syntax used to select an item from a list matching a filter
# will be covered in the next tutorial.

# Making all newly spawned creepers charged:
/execute as @e[type=creeper,tag=!creeper_init] run data modify entity @s powered set value 1b
/tag @e[type=creeper,tag=!creeper_init] add creeper_init
# It would be more efficient to make all non-charged creepers charged,
# but checking for NBT will be covered in the next tutorial

# Dropping the item held by the player on the ground:
/summon item ~ ~ ~ {Item:{id:"minecraft:stone",Count:1b},Tags:["new_item"],PickupDelay:40s}
/data modify entity @e[tag=new_item,limit=1] Item set from entity @p SelectedItem
/tag @e[tag=new_item] remove new_item
/replaceitem entity @p weapon.mainhand minecraft:air
# This does not check for an empty hand for the same reasons as before.

Combining Powers: NBT and Scoreboard

Each command returns success and result scores. The wiki page of each command will tell you the exact meaning of these scores. Generally the success score is 0 (fail), 1 (success) or whatever amount of successful operations if multiple entities are selected, while the result score could be anything. For /data get, the result scores are as follows:
If the path specifies a number, that number will be returned
(rounded down for decimals, use scale parameter to see the digits behind the dot)
If the path specifies a string, the length of the string will be returned
If the path specifies a compound, the amount of keys will be returned
If the path specifies a list, the amount of items will be returned
For /scoreboard players get, the result is the score on the scoreboard.

Now the last piece of the puzzle is the /execute store instruction, allowing us to store these values in other places:
/execute store (result|success) (block|entity|storage) <target> <path> (byte|short|int|long|float|double) <scale> ...
/execute store (result|success) score <target> <objective> ...
/execute store (result|success) bossbar <id> (max|value) ...
As you can see, we now have a way to move values between NBT and the scoreboard, giving us even more possibilities. For completeness, let's have a look at how we can update a bossbar to display the health of the nearest zombie.
/execute as @e[type=zombie,limit=1,sort=nearest] store result bossbar bertiecrafter:my_bossbar value run data get entity @s Health
# The commands consists of these instructions:
# As the nearest zombie (defines @s): /execute as @e[type=zombie,limit=1,sort=nearest]
# Store the result of the command in the bossbar: store result bossbar bertiecrafter:my_bossbar value
# Request zombie health, with the value as result of the command: run data get entity @s Health
Moving on to the NBT + Scoreboard combination, /data has no arithmetic operators, while /scoreboard has quite a few. By moving NBT data back and forth and using the operators of scoreboard, the following things (and more?) become possible:
  • Repairing items by decreasing the Damage value.
  • Duplicating items by multiplying the Count value
  • Manually merging or splitting slimes by changing their Size value.
  • Create an interface in chat to calculate color values of fireworks maybe?
  • Calculate creeper explosion power from player experience levels

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.

We are going to make a very odd chicken. Make tagged chickens steal a nearby players selected hotbar item and poop it out at double the amount! The chicken should die after having duplicated the items. Here are some useful hints:
  • First make a function that spawns a chicken with a certain tag. Use the entity format page to figure out the key and value type for this.
  • In the tick function, use /execute to execute another function as any tagged chicken if there is a player within 4 blocks. (use as and if instructions)
  • In the function that is fired from the /execute, use /data to copy a players selected item to one of the armor slots of the chicken. Armor exists, but doesn't render for chickens. Use the player.dat page to figure out the key that contains a players selected item.
  • In that same function, also use /replaceitem (set to air) to clear the selected slot and attach another tag to the chicken indicating that it's occupied. Make sure to add a filter for this tag to the /execute command in the tick function, since we don't want a players item to be overridden on the next tick.
  • In the tick function, use another /execute command that detects chickens with the occupied tag that are about to lay an egg and have it fire another function. Since this tutorial didn't cover checking for NBT, I'll provide you with a command that can be used as base:execute as @e[type=chicken,nbt={EggLayTime:1},tag=chicken_occupied] at @s run ....
  • In the function that is fired from the second /execute, first store the amount of the item in the armor slot on the scoreboard with /execute store and use /scoreboard to multiply by 2 and also put the maximum at 127. You'll have to create fake players (#two and #max_byte) in order to use these values in a scoreboard operation command. Then store the result back into the item in the armor slot. Also place the item in the armor slot on the ground (see example in the "Reading and Writing chapter") and kill the chicken.

What's next?

In the next tutorial we're going to have a look at how you can check for NBT. It will be the last part of the NBT section and it won't be as big as these last couple tutorials.

Subscribe if you want to get notified of new posts.

Function Data Packs for Dummies #10 Part 2 | NBT: Taking Control (/data &amp; /execute store)
Function Data Packs for Dummies #10 Part 2 | NBT: Taking Control (/data &amp; /execute store)
Tags

1 Update Logs

Changed list index parts : by Bertiecrafter 08/10/2020 8:15:47 amAug 10th, 2020

- Removed the list filter syntax, since this will be covered in the next tutorial
- Added that negative indexes can be used to target items from the end of the list.

Create an account or sign in to comment.

3
06/11/2020 10:48 amhistory
Level 70 : Legendary Engineer
Bertiecrafter
Bertiecrafter's Avatar
Thank you ThomasIsdumbbb, Luracasmus, Redfuzzyturtle, SpicyKai, PixieMax, StarLander5772, pettyGamingHD, CorporalKeith, end-user, TofuChild36, DinoDesmond, KingMonsterGames, TheBigPug, SanctuaryThief, Drakio-X, SUPERIONtheKnight, SlyNeptune, Unavalible_User and CVerse for the diamonds!
Planet Minecraft

Website

© 2010 - 2024
www.planetminecraft.com

Welcome