Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/lib/sidebar/tabs/Guides.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
import IconRuler2 from "~icons/tabler/ruler-2";
import IconMathMaxMin from "~icons/tabler/math-max-min";
import IconCat from "~icons/tabler/cat";
import IconClock from "~icons/tabler/clock";
import IconStar from "~icons/tabler/star";
import IconHourglass from "~icons/tabler/hourglass-empty";
import SidebarPlaceholder from "../navigation/SidebarPlaceholder.svelte";
</script>

Expand Down Expand Up @@ -71,6 +74,15 @@
page="/guide/adding-new-features/custom-items/models" />
</SidebarCategory>

<SidebarCategory name="Cooldown Checks" icon={IconHourglass}>
<SidebarPage label="Summary" icon={IconPennant} page="/guide/cooldown" />

<SidebarHeading label="Techniques" />
<SidebarPage label="Scoreboard" icon={IconScoreboard} page="/guide/cooldown/scoreboard" />
<SidebarPage label="Advancement" icon={IconStar} page="/guide/cooldown/advancement" />
<SidebarPage label="Worldclock" icon={IconClock} page="/guide/cooldown/worldclock" />
</SidebarCategory>

<SidebarCategory name="Right Click Detection" icon={IconMouse}>
<SidebarPage label="Summary" icon={IconPennant} page="/guide/right-click" />

Expand Down
48 changes: 48 additions & 0 deletions src/routes/guide/cooldown/+page.svx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: Cooldown checks
description: Learn how to create and check cooldown timers using several common methods.
version: 26.1
---

# Cooldown checks

A cooldown restricts how frequently a player triggers a custom action. In most
datapacks, these actions involve running functions or commands.

For example, consider a custom wand that shoots fireballs when a player
right clicks. Without a cooldown, players could spam the wand, resulting
in lag or unbalanced gameplay. Adding a cooldown ensures the player waits a few
seconds before shooting another fireball.

## Core concepts
- **Cooldown**: A timer that prevents an action from running again until a specified
amount of time has elapsed since the last execution.
- **Action**: The command or function the cooldown restricts.
- **Namespace**: A unique identifier for your datapack that prevents conflicts with other
datapacks. Use it as a prefix for all functions and resources (for example, `mypack:my_function`).


## Implementation methods

This guide covers three common methods for implementing cooldowns in Minecraft datapacks:
scoreboard-based, advancement-based, and worldclock-based.

### [Scoreboard-based cooldown](/guide/cooldown/scoreboard)

Use a scoreboard objective to store how much time remaining until the cooldown expires.

This method works well for small datapacks, or when you only need a few different cooldowns.

### [Advancement-based cooldown](/guide/cooldown/advancement)

Use an advancement to tick the cooldown.

This method only ticks the cooldown when the player is using the action, making it ideal
for performance-sensitive projects.

### [Worldclock-based cooldown](/guide/cooldown/worldclock)

Use a timespan on a worldclock to measure elapsed time.

This is a non-ticking approach that works well for large datapacks or any setup
that needs many cooldown timers.
102 changes: 102 additions & 0 deletions src/routes/guide/cooldown/advancement/+page.svx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
title: Advancement-based cooldown
description: Learn how to create and check a cooldown timer using an advancement and a
scoreboard objective.
version: 26.1
---

# Advancement-based cooldown

An advancement-based cooldown uses a `minecraft:tick` advancement to run a function while
a player is on cooldown.

Compared to a fully ticking scoreboard approach, this method is semi-ticking:

- If a player is not on cooldown, nothing runs for them.
- If a player is on cooldown, the tick advancement runs a function each tick until the
cooldown ends.

This setup takes a little more work because you need an extra advancement, but it can reduce
the amount of work your datapack does when most players are not on cooldown.

## What you will build

- A `my_cd` scoreboard objective to store the cooldown value (in ticks).
- A tick advancement (`<namespace>:my_cd_adv`) that runs a tick function.
- A `<namespace>:reduce_my_cd` function that counts the cooldown down.
- A `<namespace>:cooldown` function that checks the cooldown before running your action.

:::tip

To learn about advancements, see the [Advancement guide](/wiki/files/advancements).

:::

### 1) Create the tick advancement (`my_cd_adv.json`)

Create an advancement that triggers every tick and runs `<namespace>:reduce_my_cd`
as a reward.

```json:my_cd_adv.json
{
"criteria": {
"tick": {
"trigger": "minecraft:tick"
}
},
"rewards": {
"function": "<namespace>:reduce_my_cd"
}
}
```
The function `<namespace>:reduce_my_cd` only runs when the advancement
is not granted. This happens because advancements only grant their
rewards to players who don't already have them.

### 2) Create the scoreboard objective.

Create a dummy objective named `my_cd` to store the cooldown value.

```mcfunction:load.mcfunction
scoreboard objectives add my_cd dummy
```
### 3) Create the cooldown countdown function (`reduce_my_cd.mcfunction`)

This function runs once per tick for players who do not have the advancement granted.

- While the cooldown is active (`my_cd` ≥ 1), revoke the advancement
to keep it un-granted so the tick function continues to run.
- Reduce the score by 1 each tick.

```mcfunction:reduce_my_cd.mcfunction
# Reduce the cooldown by 1 tick
scoreboard players remove @s my_cd 1
# Keep the advancement un-granted while the cooldown is active
execute if score @s my_cd matches 1.. run advancement revoke @s only <namespace>:my_cd_adv
```

### 4) Create the `cooldown` function

This function checks the cooldown as follows:

- If the player's `my_cd` score ≥ 1, the cooldown has not ended, return fail.
- Set the player's cooldown to 5 seconds (100 ticks).
- Make `<namespace>:my_cd_adv` advancement un-granted.

```mcfunction:cooldown.mcfunction
# If the player is on cooldown, return fail
execute if score @s my_cd matches 1.. run return fail
# Reset the cooldown (change "100" to your cooldown length in ticks)
scoreboard players set @s my_cd 100
# Make the advancement un-granted
advancement revoke @s only <namespace>:my_cd_adv
# Return success
return 1
```

## Testing

Check the cooldown in your function:
```mcfunction:my_function
execute if function <namespace>:cooldown run tellraw @a {"text": "Cooldown Ready!"}
```
69 changes: 69 additions & 0 deletions src/routes/guide/cooldown/scoreboard/+page.svx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: Scoreboard-based cooldown
description: Learn how to create and check cooldown timers using a scoreboard objective.
version: 26.1
---

# Scoreboard-based cooldown

A scoreboard-based cooldown stores a number on each player (or entity) and
changes that number over time.

This guide uses a ticking approach, which means the datapack updates the
cooldown every game tick (20 ticks per second). Ticking cooldowns work well
for small projects with only a few cooldowns and short durations. If you track many cooldowns or
many entities, ticking affects performance.

## What you will build

- A `my_cd` scoreboard objective
- A `tick` function that reduces each player's cooldown over time
- A `cooldown` function that checks the cooldown before doing anything

:::tip

To learn how to trigger a function when a player uses an item, see the
[Right-click menu](/guide/right-click) guide.

:::

### 1) Create the scoreboard objective

Create a dummy objective named `my_cd`.

A dummy objective stores a value that only changes when commands modify it.

```mcfunction:load.mcfunction
scoreboard objectives add my_cd dummy
```

### 2) Create the `tick` function

In your `tick` function which runs every tick, reduce the `my_cd`
score by 1 for any player with `my_cd` ≥ 1

```mcfunction:tick.mcfunction
execute as @a[scores={my_cd=1..}] run scoreboard players remove @s my_cd 1
```

### 3) Create the `cooldown` function

In this function, check the executor’s `my_cd` score.
- If the score is 1 or higher, stop the function and tell the player.
- If the score is 0 or doesn't exist yet, set a new cooldown value and continue.

```mcfunction:cooldown.mcfunction
# If the player is still on cooldown, stop here
execute if score @s my_cd matches 1.. run return fail
# Reset the cooldown (change "100" to your cooldown length in ticks)
scoreboard players set @s my_cd 100
# Return success
return 1
```

## Testing

Check the cooldown in your function:
```mcfunction:my_function
execute if function <namespace>:cooldown run tellraw @a {"text": "Cooldown Ready!"}
```
74 changes: 74 additions & 0 deletions src/routes/guide/cooldown/worldclock/+page.svx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
title: Worldclock-based cooldown
description: Learn how to create and check cooldown timers using the world clock.
version: 26.1
---

# Worldclock-based cooldown

A worldclock cooldown stores a timestamp of when an action was last used in a scoreboard objective.
Your datapack compares this stored time with the current time to determine if the cooldown has ended.

This is a non-ticking approach: your datapack only does work when the player
tries to use the action. This makes it a good fit for larger datapacks with many
different cooldowns to check.

## What you will build
- A `cooldown.json` clock in the world clock folder.
- A `timespan` scoreboard objective that stores when the action was last used.
- A `<namespace>:cooldown` function that checks whether enough time has passed.

### 1) Setup the world clock
In your datapack namespace, create a folder named `world_clock`. Then, create a file named
`cooldown.json` inside the folder.
```json:cooldown.json
{}
```
Restart your world/server, then run `/time of <namespace>:cooldown query time` to verify.
(`/reload` won't work).

### 2) Create the scoreboard objectives

The `timespan` scoreboard objective stores the last time the action was used in the `cooldown` world clock.

```mcfunction
scoreboard objectives add timespan dummy
```

### 3) Create the action function (`do_things.mcfunction`)

When you trigger this function, this is what happens:

- Store the current time in the `#current` score.
- Subtract `timespan` from `#current` to get ticks since last use.
- Subtract the cooldown length from the result.
- If the result is negative, the player is still on cooldown, return fail.
- Otherwise, store the current time into `timespan` and return 1 (success).

```mcfunction:cooldown.mcfunction
# Store the current timespan
execute store result score #current timespan run time of <namespace>:cooldown query time
# ticks since last use = #current - timespan
scoreboard players operation #current timespan -= @s timespan
# cooldown = ticks since last use - cooldown duration (change 100 to your cooldown length in ticks)
scoreboard players remove #current timespan 100
# If the result is negative, the cooldown is still active, return fail.
execute if score #current timespan matches ..-1 run return fail
# Cooldown finished: save the current gametime as the new last_used timestamp
execute store result score @s timespan run time of <namespace>:cooldown query time
# Return success
return 1
```

:::warning

Do not modify the `cooldown` world clock; it will break the cooldown calculations.

:::

## Testing

Check the cooldown in your function:
```mcfunction:my_function
execute if function <namespace>:cooldown run tellraw @a {"text": "Cooldown Ready!"}
```