State Delegates
Kotlin property delegates that map scoreboard objectives or NBT storage paths to simple var properties. Writing to the property emits the corresponding Minecraft command.
This helper reduces repetitive boilerplate in command-generation code. You write Kotlin that looks like state mutation, while Kore still emits explicit vanilla commands underneath.
The two main delegate types are:
ScoreboardDelegatefor integer scoreboard-backed state.StorageDelegate<T>for NBT-backed storage paths.
Scoreboard delegate
When the property is read during code generation, the delegate returns the compile-time default value. The real runtime value still lives in the scoreboard, so you should think of the delegate as a concise command emitter, not a live synchronized Kotlin variable.
The objective is created lazily the first time the property is accessed or assigned, and it uses dummy by default.
If you need relative changes instead of absolute sets, use the paired scoreboard entity handle:
scoreboardEntity(...) returns a ScoreboardEntity, which exposes the same intent in command form:
set(value)for absolute updates.add(value)andremove(value)for relative updates.plusAssign/minusAssignas Kotlin operator sugar for those relative updates.
Storage delegate
storage(...) accepts Int, Float, String, and Boolean directly; other values are stringified before being written.
Mixing delegates with other helpers
State delegates become more useful when you mix them with other command helpers in the same function. A common pattern is to keep an integer on a scoreboard for arithmetic, while richer UI or session state stays in storage:
This emits concise vanilla commands while keeping your Kotlin code expressive:
combostays easy to reuse with other scoreboard-based helpers such as cooldowns, timers, selectors, or math.phaseandshieldReadylive in storage, which fits better for descriptive or boolean state.scoreboardEntity(...)keeps relative changes (+=,-=) readable next to direct assignments.
You can also combine scoreboard-backed delegates with selector-heavy flows. For example, use a delegated score for the canonical state, then feed the same objective into execute if score, inventory listeners, or scheduler callbacks.
If you want a condition like if score == 45, you can now keep the delegate itself around and feed it directly to a helper. Internally, these helpers lean on the same ExecuteCondition.score(...) and Relation primitives as the regular execute DSL, so the generated syntax stays aligned with the rest of Kore.
This still generates an execute if score <target> combo matches 45 run ... command, but without manually opening an execute block every time. In practice, equalTo(45) is the most readable way to express an exact score check.
If you want a quick reference for every comparison helper available with delegated scores, they map directly to the same scoreboard comparisons as the execute DSL:
| Kotlin helper | Generated score comparison |
|---|---|
equalTo(...) |
matches <value> for literal values, or = for another score |
notEqualTo(...) |
unless score ... matches <value> style negation |
greaterThan(...) |
> |
greaterThanOrEqualTo(...) |
>= |
lessThan(...) |
< |
lessThanOrEqualTo(...) |
<= |
You can also compare two delegated scores directly:
That form emits execute if score <target> combo = <target> threshold run ..., which is useful when both the current value and the threshold are computed elsewhere in your datapack.
For repeated checks, the same delegate can drive higher-level control flow helpers:
runIf(...)wraps a singleexecute if score ... run function ...call.runWhile(...)generates a recursive helper function that reruns itself while the score condition stays true.repeat(...)is a smallfor-style helper built on top ofrunWhile(...): by default it creates an internal counter score with a generated unique name, copies the input score into it, and decrements that internal counter so the main delegated score stays intact. You can still passcounter = ...to reuse an existing delegated score as the loop counter instead.- The lambda parameter (
it) is itself aScoreboardDelegatefor the current iteration index, so you can compare it, pass it torunIf(...), or even delegate it again withvar iteration by it.
When to use which delegate
- Use
scoreboard(...)for integers that must participate in score comparisons, timers, cooldowns, or arithmetic. - Use
storage(...)for richer state that fits naturally in NBT-backed data trees. - Use
scoreboardEntity(...)when you want concise+=/-=style operations instead of direct assignment. - Mix
scoreboard(...)andstorage(...)when you need both arithmetic-friendly counters and descriptive session data in the same workflow.
API summary
| Function / type | Purpose |
|---|---|
scoreboard(...) |
Create a scoreboard-backed delegate for an entity. |
scoreboardEntity(...) |
Create a score handle for relative arithmetic. |
runIf(...) |
Run a block when a delegated score condition matches. |
runWhile(...) |
Re-run a block while a delegated score condition stays true. |
repeat(...) |
Run a block once per score point, with an optional separate counter score and iteration delegate. |
storage(...) |
Create an NBT storage-backed delegate. |
ScoreboardDelegate |
Lazy scoreboard delegate implementation plus score conditions. |
StorageDelegate<T> |
Generic storage delegate implementation. |
See also
- Scoreboard Math – Feed delegated scoreboard values into trigonometric or algebraic helpers.
- Scheduler – Pair delegated state with delayed or repeating helper callbacks.
- Cooldowns – A concrete scoreboard-based gameplay system where delegated state can stay concise.
- Scoreboards – Broader patterns for organizing objectives and player state.
