Minecraft Blogs / Tutorial

Function Data Packs for Dummies #7 Part 2 | The Scoreboard (+ Triggers): We've got to go deeper!

  • 5,745 views, 3 today
  • 31
  • 10
  • 15
Bertiecrafter's Avatar Bertiecrafter
Retired Moderator
Level 70 : Legendary Engineer
772
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.

Introduction

The main purpose of the scoreboard is to generate numbers, which can be used to target players in commands. Think about health, armor, hunger bars, amount of jumps, xp, amount of chests opened, amount of deaths and even how many times you tuned a noteblock. Those numbers are stored in objectives and are player specific.

This is Part 2 of 2, focused on using the complex side of the scoreboard in data packs. There is a lot to talk about and I didn't want to make a part 3, so make sure to take a break if you don't know what you're reading anymore. Feel free to jump into Minecraft and play with what you've learned so far to get a better understanding. Now let's get into it.

Operations, Constants & Read-Only objectives

Operations allow you to do simple calculations using the scores on the scoreboard. The syntax is:
/scoreboard players operation <target> <targetObjective> <operation> <source> <sourceObjective>Keep in mind that <target> and <source> are not just target selectors. For a full list of possible player arguments, refer to the previous blog. To understand the behaviour of this command when using multiple targets or sources, you could read the command as: "For every target, apply the scores of each source, according to the specified operation". See this wiki page for all operations and their behaviours. For example, the kill-death ratio could be calculated using:
/scoreboard players operation @s killDeathRatio = @s kills
/scoreboard players operation @s killDeathRatio /= @s deaths
Which translates to: "ratio = kills / deaths". The notation for "/=" (and "+=" etc.) is actually used in programming. It means: "Left = Left / Right". The notation purely exists, because programmers have always been lazy. Now in programming, you can go one step further, because "variable += 1" is simply "variable++". Isn't that cool?
Note: the scoreboard does not allow decimals, so any decimals will simply be chopped off (rounded down) during division. This also means that the commands above won't give you any useful results, unless kills is more than 2 times the amount of deaths. Otherwise the result would always be 0 or 1. One solution is multiplying everything by a big number like 10000, allowing you to see more digits.

You can add and remove constant values by simply using "/scoreboard players (add|remove) <player> <objective> <amount>", but if you want to multiply or divide by constants, you have to put the number on the scoreboard first. This means that we can improve the commands above like this:
/scoreboard players set #tenthousand global 10000
/scoreboard players operation @s killDeathRatio = @s kills
/scoreboard players operation @s killDeathRatio *= #tenthousand global
/scoreboard players operation @s killDeathRatio /= @s deaths
Multiplying by 10000 allows us to see the first 4 decimals! So if we get a result of "15000" we should read it as "1.5" or "150%", which in turns means that we killed one and a half times as much as we died.

Some objectives are read-only, like the health objective. If you want to edit the scores, you must copy all of them to an editable objective first, like this:
/scoreboard objectives add health health
/scoreboard objectives add healthEditable dummy
/scoreboard players reset * healthEditable
/scoreboard players operation * healthEditable = * health
# You can put the copy command above in the tick function of your data pack.
# Below is an example edit operation.
/scoreboard players add * healthEditable 1


Using Scores in Commands

A common way of using scores in commands is to only execute commands if the score is in a specific range. Ranges are specified in one of the following ways:
[min]..[max] --- 1..2, ..5, 3.., -10..-3, ..-100
<exact value> --- 1, 5, 7, 9, 10
The target selector argument syntax for scores is:
scores={<objective>=<range>,<objective>=<range>,...}For example, to give everyone a speed boost if their health is high and slowness if it's low:
/effect give @a[scores={health=19..}] minecraft:speed 1 0 true
/effect give @a[scores={health=..10}] minecraft:slowness 1 0 true
(Assuming you created a health objective first and you execute this command every tick.)

Scores can also appear in chat, in books and on signs, using the JSON text objects. For example, this is how to print the health of the nearest player, excluding yourself:
/tellraw @s {"text":"The health of ","extra":[{"selector":"@p[distance=1..]"},{"text":" is "},{"score":{"name":"@p[distance=1..]","objective":"health"}}]}With the syntax obviously being:
"score":{"name":"<player>","objective":"<objectiveName>"}Any of the "player" arguments mentioned in the previous post are also valid here.

You can also delay commands by simply creating an objective, adding 1 every tick and executing the commands if the score reaches a certain number. Remember that there are 20 ticks every second. For the sake of completeness, I'll give you an example of the final command, but won't explain it until a later tutorial:
/execute if score #cookieTimer timers matches 600.. run give @a cookie
And lastly you'll use the scoreboard for calculations with data. For example, in order to duplicate item stacks, you would read the item count, multiply by 2 using scoreboard operations and write it back into the item stack. You'll also learn how to do this in a later tutorial. Just remember that the scoreboard is the ONLY place to do calculations (as of 1.15) and numbers appearing anywhere else in the game must be moved into the scoreboard first.

While VS If

A common mistake is to translate "Give a diamond every time a player jumps" into "/give @a[​scores={jumps=1..}] diamond". Which would give any player 1 diamond every tick after jumping only once. The inventory would overflow with diamonds, because you essentially implemented "Give a diamond while the player has jumped". To fix this, make sure to always set the score back to 0 or reset it after the command has fired. So in your tick function you should have:
/give @a[scores={jumps=1..}] diamond
/scoreboard players reset @a[scores={jumps=1..}] jumps

Triggers

There are a lot of commands involved with triggers, so I'm going to walk you through this one using an example. Imagine you created a Cookie Clicker game with a clickable button in chat:
/tellraw @a {"text":"[ GET COOKIE ]","clickEvent":{"action":"run_command","value":"/give @s cookie"}}This only works for OPs. Normal players will get a message saying they don't have permission. The solution to this problem is creating a trigger and giving a cookie to everyone who triggered the button.
/scoreboard objectives add cookieTrigger trigger
#Execute the commands below every tick
/give @a[scores={cookieTrigger=1..}] cookie
/scoreboard players reset @a[scores={cookieTrigger=1..}] cookieTrigger
#Change the tellraw command to:
/tellraw @a {"text":"[ GET COOKIE ]","clickEvent":{"action":"run_command","value":"/trigger cookieTrigger"}}
Players can only trigger the objective if it's enabled for them. If you want anyone to use this trigger whenever, simply run this every tick (syntax should be obvious from the example):
/scoreboard players enable @a cookieTriggerThe syntax for the /trigger command is:
/trigger <objective> [(add|set) <value>]If you omit the last part, it defaults to "add 1" as we have seen in the example above.

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.

Let's create a button in chat to toggle to spectator if you are in creative. Start by creating a trigger objective. Now execute a /tellraw command every tick for all creative players (using built-in target selector arguments) that sets their value for the trigger objective to 3. Then target all players with a score of 3, who are not in spectator mode and make them go into spectator mode. Don't forget to run a scoreboard enable command every tick to enable the trigger for everyone! Also use "\n" a bunch of times at the beginning of the /tellraw command to hide old versions of the message.

You should probably allow the player to go back into creative as well. Run a /tellraw command for all spectators that sets their value for the trigger objective to 1. Target all players with a score of 1 not in creative mode and set their gamemode to creative.

WARNING: If you used "/scoreboard players enable @a", everyone can now switch gamemodes if they figure out the /trigger command. Manually run "/tag <players> add <tag>" and use "@a[​tag=<tag>]" in the commands to target a specific group of players instead.

If this was easy enough, try printing the current trigger value in chat, below the button. You can also try showing buttons for all possible gamemodes, except the one you're currently in. So if you are in adventure, it should display 3 buttons for survival, creative and spectator.

What's next?

Next up we're going to look at changing the command environment with /execute. This will allow us to run commands at different locations, but also as different entities.
Subscribe if you want to get notified of new posts.

Function Data Packs for Dummies #7 Part 2 | The Scoreboard (+ Triggers): We&#039;ve got to go deeper!
Function Data Packs for Dummies #7 Part 2 | The Scoreboard (+ Triggers): We&#039;ve got to go deeper!
Tags

Create an account or sign in to comment.

2
11/10/2021 9:05 am
Level 42 : Master Fox
LuxLacis
LuxLacis's Avatar
I tried to replicate the kdr functionality but found that using @s when scheduling these commands every 2 seconds does not work:

/scoreboard players operation @s killDeathRatio = @s kills/scoreboard players operation @s killDeathRatio *= #tenthousand global/scoreboard players operation @s killDeathRatio /= @s deaths

Instead I had to use @p and then it worked just fine. Why is that? Is it because of Minecraft being updated or something else?
1
11/14/2021 9:17 amhistory
Level 70 : Legendary Engineer
Bertiecrafter
Bertiecrafter's Avatar
@s means "the player currently executing the command". Which for /scheduled functions, the tick function and the load function is this "server entity", not the actual player. What you want to do is run the function as another player, e.g. "/execute as @a run function luxlacis:path/the_actual_function". More on variables and "the command environment" in the next tutorial.
1
11/15/2021 10:50 am
Level 42 : Master Fox
LuxLacis
LuxLacis's Avatar
That makes a lot more sense! Thank you :D
1
07/24/2021 6:54 am
Level 20 : Expert Modder
carnivalChaos
carnivalChaos's Avatar
the challenge idea is great, and i was working on it before i realized a massive issue. not the overflow of chat in servers, but the fact that anyone can use /trigger. the issue with this is anyone could just do /trigger creative and suddenly our entire server has been griefed. any work arounds for this?
1
07/24/2021 11:08 amhistory
Level 70 : Legendary Engineer
Bertiecrafter
Bertiecrafter's Avatar
I'm sorry to hear that. The challenge was written with trusted friends in mind. You can select specific players in the "/scoreboard players enable" command instead of simply using "@a". Players that are not enabled cannot run the trigger. Once enabled, they will always be able to run it, until they did once or you run /scoreboard players disable.

If you use "/tag <players> add admin" (or similar), you can then target all players with that tag using "@a[​tag=admin]" in the both the scoreboard players enable command and the tellraw command for the button. You can also run /scoreboard players disable * to disable the trigger for all known players. (After changing the enable command of course.)

Changed the description.
2
03/28/2021 7:06 pm
Level 1 : New Miner
nathonion
nathonion's Avatar
Great tutorial! I was wondering... in this command:/scoreboard players reset * healthEditable
what does the "*" mean? I can see it's being used as a target selector, but I can't find any documentation about it anywhere. Thanks!
1
03/29/2021 11:22 amhistory
Level 70 : Legendary Engineer
Bertiecrafter
Bertiecrafter's Avatar
Good question! It's a special selector only allowed in the scoreboard command. It means all entities + all fake/offline player names. It comes in handy since you can literally use any string as player name (prefixed by # to make them hidden), see the previous blog =)
1
01/12/2021 3:59 am
Level 38 : Artisan Pixel Painter
Dunk__
Dunk__'s Avatar
I need help! How do I make custom tags?
1
01/12/2021 4:22 am
Level 70 : Legendary Engineer
Bertiecrafter
Bertiecrafter's Avatar
As in entity tags that you can target with @e[.....]:
@e[​tag=<tag>] after using the /tag command to set a tag.

If you mean the kind of tags that group functions, blocks, items, entities etc (like "minecraft:tick"):
Simply create your own .json file in <namespace>/tags/<type>/<any path>, see here.
1
07/09/2020 11:32 pm
Level 26 : Expert Pixel Puncher
Cybear_Tron
Cybear_Tron's Avatar
Really, scoreboards are tough to understand
Planet Minecraft

Website

© 2010 - 2024
www.planetminecraft.com

Welcome