Minecraft Blogs / Tutorial

⚙️ Datapacking In-Depth: Repeat it over and over again... | Loops | DID 2

  • 4,842 views, 7 today
  • 14
  • 6
  • 3
Kefaku's Avatar Kefaku
Level 42 : Master Nerd
73
Loops


Contents

0. Prerequisites
1. Introduction
2. Infinite Loops
  2.1. Every Tick
  2.2. Any Speed
3. Conditional Loops
  3.1. Repeat While
  3.2. Repeat Until
  3.3. Multiple Conditions
4. Counter Loops
5. Recursion
6. Conclusion and Further Reading
⚙️ Datapacking In-Depth: Repeat it over and over again... | Loops | DID 2
⚙️ Datapacking In-Depth: Repeat it over and over again... | Loops | DID 2
⚙️ Datapacking In-Depth: Repeat it over and over again... | Loops | DID 2



0. Prerequisites

Knowledge of the following topics is required for this explanation. If you don't have that knowledge, I suggest you visit the linked resource and learn about that topic first.

Topic
Suggested Resource
Creating a basic function datapack
Function Datapacks for Dummies by Bertiecrafter, at least quickstart
Scoreboards (creating, setting/adding values)
Function Datapacks for Dummies by Bertiecrafter, at least section 7.1
/execute [​if/unless]
Commands/execute on the Minecarft Wiki, at least section Conditional Subcommands



1. Introduction

So you started creating your own datapacks. You used some commands to implement your first cool ideas, but now you're wondering: How can I do stuff repeatedly? How can I repeat something until something happens? How can I have something happen every x seconds?
Don't worry, this tutorial got you covered. You'll learn about infinite, conditional and counter loops. Sounds cool? Then lets get right into it.


2. Infinite Loops

The first type of loop we'll cover are infinite loops. As the name suggest, once you start a loop of this type it will run forever, or more precisely until the entire datapack stops running. These loops are useful, if you want do have something happening all the time or if you want your datapack to always be ready to react when something is done.

2.1. Every Tick

A game tick is the smallest timeframe in which things can happen in minecraft (usually 20 times per second, depending on lag). As a result, running commands every tick can be seen as running them constantly. Therefore, this method is best, if you want your commands to be able to instantly react to something at any point in time.
The easiest way to implement this is using the #minecraft:tick function tag.
First, we need a basic function we want to run every tick. Let's use this example:

# File Location: ./data/did/functions/loop/infinite/tick
# as/at server

execute as @e[type=minecraft:creeper] at @s run particle minecraft:heart ~ ~1 ~ 0.2 0.1 0.2 0.1 1 force

That command just spawns a particle at every creeper. You don't need to understand it, you can use any other command you want to run every tick, this is just an example.
Now, we need to add this to the tick tag, which we do like this:

# File Location: ./data/minecraft/tags/functions/tick.json

{
  "values":
  [
    "did:loop/infinite/tick"
  ]
}

You can also add multiple functions to that tag by just seperating them with a comma:

# ./data/minecraft/tags/functions/tick.json

{
  "values":
  [
    "did:loop/infinite/tick",
    "some:other/function"
  ]
}

Yay, we did it:



That was easy, right? Now on to the more fancy stuff:

2.2. Any Speed

In many situations you want to have a loop that continues forever, but runs slower. There are many reasons, for example:
  • You want to run many functions in the loop. This can cause lag, running it less frequent can reduce that.
  • You want to have a delay, for example a custom spawner that spawns a mob every x seconds.
In minecraft you can achieve this using /schedule. First, we again need a command we want to repeat. Let's display some particles at every pig this time:

# File Location: ./data/did/functions/loop/infinite/any.mcfunction
# as/at server

execute as @e[type=minecraft:pig] at @s run particle minecraft:heart ~ ~1 ~ 0.2 0.1 0.2 0.1 1 force
schedule function did:loop/infinite/any 1s

As you might have noticed, the first command stayed almost the same, the only difference is that we're using pigs instead of creepers this time.
The bigger difference is, there is an additional command: it schedules itself for 1 second in the future. Scheduling a function basically allows you to tell minecraft to run that function after a specified amount of time has passed (in this example 1s ≈ 1second). That means, after the function finished running, it will run again in 1 second. That time it will again repeat itself after 1 second and so on.
In the /schedule, you can use any other amount of time you want, for example: 2d (2 minecraft days), 200t (200 minecraft ticks), ... and the commands in the loop will repeat once that amount of time has passed.
Looks great, we created a function that repeats itself at a specified speed! Are we done? Sadly not, because there still is 1 problem: the function needs to run once in order to start the loop, otherwise nothing happens. Since it needs to run only once, we can use the #minecraft:load tag, which runs the function once, whenever the datapack loads:

# ./data/minecraft/tags/functions/load.json

{
  "values":
  [
    "did:loop/infinite/any"
  ]
}

Look, the pig is also happy that you learned something:




3. Conditional Loops

3.1. Repeat While

Now, we step it up another level: What if you want to repeat something, while a certain condition is met?
In this example we want to create a function, that says Abacadabra, if any player is holding a potion and stops when no player holds a potion anymore.
We can base this on the any speed loop we created before with just adding a condition before the /schedule:

# File Location: ./data/did/functions/loop/conditional/repeat_while.mcfunction
# as/at server

say Abacadabra!
execute if entity @a[nbt={SelectedItem:{id:"minecraft:potion"}}] run schedule function did:loop/conditional/repeat_while 10t

This basically does the same thing as the any speed loop, but only runs itself, if any player with a potion is present. Therefore, it stops after the condition is no longer met.

3.2. Repeat Until

Of course, you can also repeat something until a certain condition is met, by swapping if with unless:

# File Location: ./data/did/functions/loop/conditional/repeat_until.mcfunction
# as/at server

say Muggle!
execute unless entity @a[nbt={SelectedItem:{id:"minecraft:potion"}}] run schedule function did:loop/conditional/repeat_while 10t

This function says muggle, until there is any player holding a potion.


3.3. Multiple Conditions

You can list multiple conditions in /execute:

execute if <condition1> if <condition2> if <condition3> run
You can also combine if and unless conditions:

execute if <condition1> if <condition2> unless <condition3> run

4. Counter Loops

Lastly, we'll cover counter loops. These are useful, if you want to repeat something a specific amount of times.
The example in this section: Imagine you want to summon exactly 10 zombies at the location of the player. Of course, you can just copy and paste the command for summoning your zombie 10 times:

# File Location: ./data/did/functions/loop/counter/list.mcfunction
# as/at server

execute positioned as @p run summon minecraft:zombie ~ ~ ~
execute positioned as @p run summon minecraft:zombie ~ ~ ~
execute positioned as @p run summon minecraft:zombie ~ ~ ~
execute positioned as @p run summon minecraft:zombie ~ ~ ~
execute positioned as @p run summon minecraft:zombie ~ ~ ~
execute positioned as @p run summon minecraft:zombie ~ ~ ~
execute positioned as @p run summon minecraft:zombie ~ ~ ~
execute positioned as @p run summon minecraft:zombie ~ ~ ~
execute positioned as @p run summon minecraft:zombie ~ ~ ~

But that isn't really elegant and would get extremely hard to do, if you want to repeat something , let's say 100 times. Of course, there's a way to do this smarter and more elegant, which is - you guessed it - a counter loop (in computer science: for loop). It's based on the conditional loop you already learned about, combined with a scoreboard.
First, we need to set up the scoreboard in the load function:

# ./data/minecraft/tags/functions/load.json

{
  "values":
  [
    "did:loop/counter/init_score"
  ]
}

# File Location: ./data/did/functions/loop/counter/init_score.mcfunction
# as/at server

scoreboard objectives add count dummy
scoreboard player set #count count 1

Now, after we've created the scoreboard using another function in the #minecraft:load tag, we can start setting up our conditional loop:

# File Location: ./data/did/functions/loop/conditional/repeat_until.mcfunction
# as/at server

execute positioned as @p run summon minecraft:zombie

scoreboard players add #count count 1
execute unless score #count count matches 10.. run schedule function did:loop/counter/loop 1t
execute if score #count count matches 10.. run scoreboard players set #count count 0

Now what this function does:
  1. It summons a zombie. (the command that should be repeated)
  2. It counts up by 1 on the score of #count on the scoreboard count. (counts how many times it has been repeated)
  3. It schedules itself, if it hasn't been repeated 10 or more times. (stops if it has benn repeated 10 times)
  4. If it has been repeated 10 times (finished) it resets the score of #count on the scoreboard count, so it can be used again in the future.
And that's it. That's all the magic behind counter loops. You did it!




5. Recursion

Recursion is a concept commonly used in computer science. It has lots of use cases and is extremely useful in general, but I'll just cover it briefly in this blog. To put it simple, recursion means a function running itself. This can also be used in combination with basically any type of loop. In minecraft, recursion has 2 advantages over methods I told you about earlier in this blog:
Since it is faster and therefore executed more often, it is also more resource intensive (fancy programmer word beeing laggy). Therefore you really shouldn't use it for infinite loops (although you definitely could). Also, there's no reliable way to change how fast it is, so if you need a slow loop, this also isn't for you. In all other cases, it could be useful. Now you're probably asking yourself: Well, then, how do I do this fancy stuff?

# File Location: ./data/did/functions/loop/recursion
# person executing the function server

say Recursion!
execute if block ~ ~-1 ~ minecraft:stone run function did:loop/recursion

This function just runs itself at the end, simple as that. This general concept could be used with any type, but I made it conditional, because I just told you not to use it with infinite or slow loops. My example condition requires the player executing the function to stand on a stone block.
This is some proper spamming!



Important side note: The speed at which the "Recursion!" messages appear is limited to chat speed, the actual recursion is faster.
Second important side note: There's a limit for recursion in minecraft. Don't ask me why, but a function by default just stops after repeating 65536 times. This can be controlled by changing the maxCommandChainLength gamerule. (/gamerule maxCommandChainLength <value>)




6. Conclusion and Further Reading

You've (hopefully) learned quite a lot while reading this. You learned how to repeat stuff forever, a certain amount of times and how to use conditions with loops. Now you you can continue by coding your own projects, because the best way to learn more is just testing out stuff for yourself. If you don't have any ideas what for own projects yet, you can practice with the following challenge:

assignment Challenge

In this challenge you will create a challenge for other players! :D
The task is simple: combine two loops in a way that will summon 10 creepers at the location of the player every minute (≈1200 ticks).

If you have any further questions, feel free to ask in the comments.
If you want to check out the functions I created for this tutorial, change some things around and test it for yourself, you can download the tutorial datapack here:

🔗 DID Tutorial Datapack: Loops

As a somewhat advanced topic based on this, you might want to take a look at raycasting:

🔗Raycast (r/MinecraftCommads)
🔗Raycasting in Minecraft (Cloud_Wolf)


👍👎
How did you like it?
Please leave your feedback in the comments.

If you want to learn even more about datapacks, you can find other episodes of DID and more in the Datapack Knowledge Book.
Tags

3 Update Logs

Update #3 : by Kefaku 04/12/2023 10:00:59 amApr 12th, 2023

LOAD MORE LOGS

Create an account or sign in to comment.

ToxicalMC
07/23/2023 4:57 pm
Level 1 : New Explorer
ToxicalMC's Avatar
Bertiecrafter Is this possible for set_lore modifiers?
1
Bertiecrafter
11/08/2022 1:35 pm
Level 70 : Legendary Engineer
Bertiecrafter's Avatar
Very awesome collection of techniques! This series is becoming a beautiful addition to the shared knowledge on PMC. Where I focused on learning mechanics step by step, this series seems to combine mechanics from all corners of data packing into themed concepts and know-hows. Excited for the next part :D
3
Kefaku
11/08/2022 2:13 pm
Level 42 : Master Nerd
Kefaku's Avatar
thanks for the great feedback, I'm working on the feedback from your PM
3
Planet Minecraft

Website

© 2010 - 2024
www.planetminecraft.com

Welcome