# website Full Documentation # Guides ## Why Kore - Kotlin DSL vs Raw Datapacks & Other Generators --- root: .components.layouts.MarkdownLayout title: Why Kore - Kotlin DSL vs Raw Datapacks & Other Generators nav-title: Why Kore description: Compare Kore with raw datapacks, Sandstone, Beet, and other generators. Type safety, autocomplete, one Kotlin language for all JSON and MCFunction. No more error-prone hand-written datapack files. keywords: kore vs sandstone, kore vs beet, datapack generator comparison, kotlin datapack dsl, minecraft datapack alternative, type-safe datapack, why kore, datapack generator benefits, mcfunction generator, minecraft json generator date-created: 2026-06-24 date-modified: 2026-07-02 routeOverride: /docs/guides/why-kore position: 0 --- # Why Kore Datapacks are powerful but painful to write by hand: stringly-typed commands, sprawling JSON, no autocomplete, and silent failures you only discover after `/reload`. Kore replaces all of that with a single, strongly-typed Kotlin DSL that generates the exact same vanilla output - just faster, safer, and without the boilerplate. This page explains what Kore gives you over raw datapacks, and how it compares to other generators. ## The problem with hand-written datapacks A real datapack is a mix of two error-prone formats: - **`.mcfunction`** - plain text commands with no validation. A typo in a selector, a wrong block id, or a misremembered argument order fails silently or breaks at runtime. - **JSON** - loot tables, predicates, advancements, recipes, worldgen, dialogs. Deeply nested, verbose, and easy to get subtly wrong. No editor tells you a field is misspelled until the game refuses to load it. There is no autocomplete, no type checking, no refactoring, and no way to share logic except copy-paste. As a pack grows, this gets worse fast. ## What Kore changes ### One language, no JSON You write Kotlin. Kore generates the `.mcfunction` and JSON for you. You never hand-write a brace. ```kotlin dataPack("example") { function("hello") { tellraw(allPlayers(), textComponent("Hello World!")) } }.generateZip() ``` ### Everything is typed Every vanilla list - blocks, items, entities, effects, enchantments, biomes, sounds - is a generated enum. You cannot misspell `minecraft:diamond_sword`, because you write `Items.DIAMOND_SWORD` and the compiler checks it. The same applies to command arguments, NBT paths, and data-driven schemas. See [Arguments](/docs/concepts/arguments). ### Real code structure Because it is Kotlin, you get everything the language offers: extension functions to split a pack across files, loops and conditionals to generate repetitive content at build time (see [Runtime Logic](/docs/concepts/runtime-logic)), and refactoring/autocomplete from your IDE. Big projects stay maintainable. ### Tested, predictable output Kore is a **build-time generator**. There is no runtime, no plugin, no server mod. The output is exactly the vanilla datapack you would have written by hand - every public feature ships with tests asserting the exact generated JSON and command strings. What you generate is what loads. ### Up to date Kore tracks recent Minecraft versions closely, including newer systems like command macros, dialogs, timelines, and the current pack format. You get modern features with type safety on day one. ## How Kore compares to other generators Kore is not the only datapack generator. Here is an honest, broad-strokes comparison. (Verify specifics against each project before quoting - tooling moves fast.) | Tool | Language | Style | Type safety | Vanilla lists as symbols | |------------------------|-------------------|-------------------------------|------------------------------------|---------------------------------------------| | **Kore** | Kotlin | Type-safe builder DSL | Strong (no `any`, generated enums) | Yes (`Items.DIAMOND_SWORD`, `Blocks.STONE`) | | **Sandstone** | TypeScript | Functional TS API | Good (TS strict) | Partial | | **Beet** (+ **mecha**) | Python | Plugin / pipeline, decorators | Medium (type hints) | Via libraries | | **Raw datapack** | mcfunction + JSON | Hand-written | None | No (plain strings) | **Where Kore wins:** a single strongly-typed Kotlin DSL with generated registries, so vanilla ids are real symbols the compiler checks, plus exact-output tests shipped with every feature. The DSL mirrors Minecraft's own structure, so it reads naturally to anyone who knows datapacks. **Where others may fit better:** Beet has a very mature plugin ecosystem and `mecha`'s command compiler, and is a good fit if your team lives in Python. Sandstone is a strong choice for TypeScript-first teams. If you only need a handful of commands and never plan to scale, raw datapacks are fine. Kore's bet is that for anything beyond trivial, a typed compiler-checked DSL saves more time than it costs to learn. ## When to choose Kore Reach for Kore when: - Your pack is more than a few functions, or you expect it to grow. - You want autocomplete, refactoring, and the compiler catching mistakes before `/reload`. - You already know Kotlin (or are happy to learn a small subset - see [Getting Started](/docs/getting-started)). - You want data-driven content (loot, recipes, advancements, worldgen, dialogs) without writing JSON. ## Next steps - [Getting Started](/docs/getting-started) - build your first datapack - [Runtime Logic](/docs/concepts/runtime-logic) - the one concept that makes everything click - [Creating a Datapack](/docs/guides/creating-a-datapack) - lifecycle and output options - [Cookbook](/docs/guides/cookbook) - practical patterns to copy --- ## Kore Configuration - Datapack Settings, Pack Format & Output Options --- root: .components.layouts.MarkdownLayout title: Kore Configuration - Datapack Settings, Pack Format & Output Options nav-title: Configuration description: Configure your Minecraft datapack output with Kore. Set pack_format, Minecraft version, description, namespace, pretty printing, ZIP/JAR export, and resource pack integration. keywords: minecraft datapack pack_format, pack_format datapack, datapack configuration, kore settings, datapack output, datapack namespace, pack format minecraft, datapack zip export, datapack description, kore configure date-created: 2024-04-06 date-modified: 2026-07-02 routeOverride: /docs/guides/configuration position: 2 --- # DataPack configuration The `configuration { }` block on a [DataPack](https://kore.ayfri.com/docs/guides/creating-a-datapack) controls how Kore serializes JSON (and related formats) and where **generated** functions live. Output **location** and **archive shape** are chosen when you call `generate()`, `generateZip()`, or `generateJar()`. ## Example ```kotlin dataPack("mypack") { configuration { prettyPrint = true prettyPrintIndent = " " } // ... rest of datapack code } ``` ## `prettyPrint` When `prettyPrint` is `true`, Kore’s shared `Json` encoder formats JSON resources (advancements, tags, recipes, worldgen JSON, `pack.mcmeta`, etc.) with line breaks and indentation. When `false`, output is compact (smaller files, slightly faster I/O). - Default: `false` (release-friendly; smaller packs). - Set `true` when you want readable diffs in version control or easier manual inspection while developing. `prettyPrint` does not change game behavior; it only affects on-disk JSON layout. ## Indentation (`prettyPrintIndent`) `prettyPrintIndent` is the indent string passed to Kotlin serialization when `prettyPrint` is enabled. The default is a single tab (`"\t"`). Common choices are `"\t"`, `" "`, or `" "`. For **TOML** serialization (used for some generated files), Kore maps the indent string to [ktoml](https://github.com/akuleshov7/ktoml) styles: tab, two spaces, and four spaces get proper TOML indentation; other values fall back to no extra indentation for TOML output. Matching your JSON indent to one of those three keeps JSON and TOML visually consistent. ## Generated function folder (`generatedFunctionsFolder`) Kore may emit **generated** `.mcfunction` files (for example when `execute` chains are lowered into separate functions). Those files are placed under: `data//function//...` The default folder name is `generated_scopes` (see `DataPack.DEFAULT_GENERATED_FUNCTIONS_FOLDER` in the Kore source). Change `generatedFunctionsFolder` if you want a different directory name (shorter paths, naming that matches your project, or avoiding clashes with hand-written `function/` trees). ## Comments on generated function calls (`generateCommentOfGeneratedFunctionCall`) When Kore inserts a call to a newly generated function from an `execute` block, it can add a **comment line** in the calling function documenting that call, for example: `# Generated function namespace:path/to/caller` This is controlled by `generateCommentOfGeneratedFunctionCall`. Default: `false`. Turn it on while debugging or learning generated control flow; turn it off for minimal `.mcfunction` output in releases. ## Where files go (`path`) and generation modes - **`dataPack.path`** (default: `out`): base directory for generation. The generator resolves packs relative to this path (see below). - **`generate()`** writes an **unzipped folder**: `//` with `pack.mcmeta`, `data/`, etc. Best for pointing Minecraft at a dev folder, CI checks, or tools that expect a plain tree. - **`generateZip()`** writes **`/.zip`**. Same contents as the folder layout, in one archive. Convenient for distribution and often faster for the game to load than thousands of loose files. - **`generateJar()`** writes **`/.jar`**. The comment on the API states this is intended for use * *as a mod**: JAR generation runs optional **providers** (Fabric, Forge, NeoForge, Quilt, etc.) to add loader metadata and package the datapack accordingly. Do not expect a plain datapack ZIP renamed to `.jar` unless you only need the archive format without mod infrastructure. `generate()` and `generateZip()` accept `DataPackGenerationOptions` (for example `mergeWithPacks`). `generateJar()` uses `DataPackJarGenerationOptions`, which supports the same merge list plus loader-specific configuration. ## Development vs release-oriented setups A practical split: | Concern | Development | Release | |------------------------------------------|---------------------------------------------------------------------------|------------------------------------------------------------------------------------| | `prettyPrint` | `true` for readable JSON | `false` for smaller files | | `generateCommentOfGeneratedFunctionCall` | `true` if comments help tracing | `false` for lean functions | | Output | `generate()` to a folder under `path`, or `generateZip()` for quick share | `generateZip()` for vanilla datapacks; `generateJar()` only when shipping as a mod | | `path` | e.g. a world `datapacks` folder or `./build/datapack` | your build output directory or CI artifact path | You can keep one `dataPack { }` definition and branch configuration with build constants, or use separate `main`/`debug` entry points, depending on your Gradle setup. ## Reference | Option | Description | Default | |------------------------------------------|--------------------------------------------------------------------|----------------------| | `generateCommentOfGeneratedFunctionCall` | Insert a comment when calling a generated function from `execute`. | `false` | | `generatedFunctionsFolder` | Subfolder under `function/` for generated `.mcfunction` files. | `"generated_scopes"` | | `prettyPrint` | Pretty-print JSON resources. | `false` | | `prettyPrintIndent` | Indent string when pretty-printing JSON. | `"\t"` | Configuring a datapack is especially useful for debugging and for tuning pack size and readability in production. --- ## Cookbook --- root: .components.layouts.MarkdownLayout title: Cookbook nav-title: Cookbook description: "Practical Kore recipes for common datapack patterns: setup functions, custom items, timers, worldgen, raycasts, and bindings. Copy-paste code adapted for real projects." keywords: minecraft, datapack, kore, cookbook, recipes, patterns, guide date-created: 2026-04-21 date-modified: 2026-04-21 routeOverride: /docs/guides/cookbook position: 3 --- # Cookbook This page collects practical patterns you can lift into a real Kore datapack. It does not try to replace the full reference pages; instead, it shows how several documented features fit together. If your main goal is migrating an already mature datapack architecture, pair this page with [From Datapacks to Kore](/docs/guides/from-datapacks-to-kore). ## Recipe 1 - A clean pack bootstrap Use a dedicated setup function for one-time registration and a tick function for recurring gameplay logic. ```kotlin fun DataPack.registerCoreSystems() { load("setup") { scoreboard.objectives.add("round", "dummy") scoreboard.objectives.add("lives", "dummy") } tick("game_loop") { execute { asTarget(allPlayers()) run { say("tick") } } } } fun main() = dataPack("arena") { registerCoreSystems() }.generateZip() ``` Use this pattern when you want a clear separation between initialization and runtime logic. Related pages: - [Functions](/docs/commands/functions) - [Creating A Datapack](/docs/guides/creating-a-datapack) ## Recipe 2 - Reuse logic by exposing named functions from `Function` Sometimes you want a helper that can be called from multiple places while still generating a normal datapack function. An ergonomic pattern is to attach it directly to `Function`: ```kotlin fun Function.myFunction() = function("my_function") { say("yay") say("also, yay") } load { function(myFunction()) } ``` This is totally fine even if several call sites end up recreating the same named function declaration. Kore is heavily optimized for this kind of reuse, so regenerating the same function is effectively instant and keeps your code much cleaner than manually caching every `FunctionArgument` yourself. Use this when the code should remain callable as a proper datapack function, for example for scheduling, tags, cross-function reuse, or debug visibility. Related pages: - [Functions](/docs/commands/functions) - [Commands](/docs/commands/commands) ## Recipe 3 - Reuse code inline without creating a function Not every reusable snippet needs its own generated function. If you just want to share a small block of commands, regular `Function` extensions are often enough: ```kotlin fun Function.saySomething() { say("yay") say("also, yay") } load { saySomething() } ``` Prefer this pattern when the reused logic is small and should stay inlined at the call site instead of becoming a separate `/function` entry. Related pages: - [Functions](/docs/commands/functions) - [Cookbook](/docs/guides/cookbook) ## Recipe 4 - Gate gameplay with selectors and scores Keep complex target selection in reusable values instead of repeating long selector builders. ```kotlin val activePlayers = allPlayers { scores = scores { "round" greaterThanOrEqualTo 1 "lives" greaterThan 0 } gamemode = !Gamemode.SPECTATOR } function("start_wave") { effect(activePlayers) { give(Effects.RESISTANCE, duration = 5, amplifier = 0) } tellraw(activePlayers, textComponent("Wave started")) } ``` This keeps wave logic readable and centralizes the rules that define an eligible player. Related pages: - [Selectors](/docs/concepts/selectors) - [Scoreboards](/docs/concepts/scoreboards) ## Recipe 5 - Define a custom item and validate it later Combine item components with predicates when the item should remain recognizable after being moved between inventories. ```kotlin val arenaBlade = Items.DIAMOND_SWORD { customName(textComponent("Arena Blade", Color.AQUA)) tooltipDisplay(showInTooltip = true) } val arenaBladePredicate = predicate("arena_blade") { matchTool(arenaBlade) } function("check_weapon") { execute { ifCondition(arenaBladePredicate) run { say("Correct weapon equipped") } } } ``` Use this when a datapack needs both rich item metadata and reliable runtime checks. Related pages: - [Components](/docs/concepts/components) - [Predicates](/docs/data-driven/predicates) - [Item Modifiers](/docs/data-driven/item-modifiers) ## Recipe 6 - Schedule delayed actions instead of duplicating code Wrap delayed logic in a named function and schedule it instead of inlining the same command sequence multiple times. ```kotlin val explosionWarning = function("explosion_warning") { tellraw(allPlayers(), textComponent("Boom in 5 seconds!", Color.RED)) } val explodeNow = function("explode_now") { summon(Entities.TNT, vec3()) } function("trigger_explosion") { function(explosionWarning) schedule.function(explodeNow, 5.seconds) } ``` This pattern is a good default for cutscenes, telegraphs, cooldowns, and delayed effects. Related pages: - [Commands](/docs/commands/commands) - [Helpers Utilities](/docs/helpers/utilities) - [Scheduler](/docs/helpers/scheduler) ## Recipe 7 - Choose between core, helpers, and oop early When a system starts simple, keep it in `kore`. Add `helpers` for reusable glue. Move to `oop` once gameplay objects need long-lived identities. - Use **`kore`** for raw commands, data-driven JSON, tags, functions, and lightweight selectors. - Use **`helpers`** for rendering pipelines, geometry, scheduler utilities, or state delegates. - Use **`oop`** for players, teams, boss bars, timers, spawners, scoreboards, and state machines. That decision alone prevents many documentation and architecture mistakes later. Related pages: - [Home](/docs/home) - [Helpers Utilities](/docs/helpers/utilities) - [OOP Utilities](/docs/oop/oop-utilities) ## Recipe 8 - Import an existing datapack, then wrap it with Kotlin Use `bindings` when you already have a datapack and want typed access to its resources instead of stringly typed calls. Typical flow: 1. Configure a binding source 2. Generate Kotlin wrappers 3. Call imported functions/resources from your own pack This is especially useful for large internal libraries or third-party datapacks that your project depends on. Related pages: - [Bindings](/docs/advanced/bindings) - [Functions](/docs/commands/functions) ## How to use this page Treat these recipes as starting points: - Extract repeating code into small reusable helpers - Move cross-cutting conditions into selectors or predicates - Favor typed arguments over handwritten command strings - Keep links to the relevant reference pages nearby while you iterate --- ## Creating A Datapack --- root: .components.layouts.MarkdownLayout title: Creating A Datapack nav-title: Creating A Datapack description: A guide for creating a Minecraft datapack using Kore. keywords: minecraft, datapack, kore, guide date-created: 2024-02-26 date-modified: 2026-03-31 routeOverride: /docs/guides/creating-a-datapack --- # Creating a DataPack A DataPack in Kore represents a Minecraft datapack that contains custom game data and resources. If you already maintain large hand-written datapacks and want migration/architecture patterns rather than basics, read [From Datapacks to Kore](/docs/guides/from-datapacks-to-kore). To create a DataPack, use the `dataPack` function: ```kotlin dataPack("my_datapack") { // datapack code here }.generate() ``` This will generate the datapack with the given name in the `out` folder by default. If `generate()` is not called, the datapack will not be generated. Check the [Generation](#generation) section for more information. ## Changing Output Folder To change the output folder, use the `path` property: ```kotlin dataPack("my_datapack") { path("%appdata%/.minecraft/saves/my_world/datapacks") } ``` ## Adding Icon To add an icon to the datapack, use the `iconPath` function: ```kotlin dataPack("my_datapack") { iconPath("icon.png") } ``` ## Configuration See [Configuration](/docs/guides/configuration) ## Pack Metadata The `dataPack` function generates a `pack.mcmeta` file containing metadata about the datapack. Configure this metadata using the `pack` block: ```kotlin dataPack("mydatapack") { pack { minFormat(94) maxFormat(94) description = textComponent("My Datapack") } } ``` - `minFormat` - The minimum supported pack format version. - `maxFormat` - The maximum supported pack format version. - `description` - A text component for the datapack description. `minFormat` and `maxFormat` are shortcut functions that accept the same arguments as `packFormat()`: ```kotlin pack { minFormat(94) // plain integer minFormat(94, 0) // [major, minor] pair maxFormat(94) } ``` You can also assign a `PackFormat` value directly: ```kotlin pack { minFormat = packFormat(94) maxFormat = packFormat(94) } ``` ### Legacy `supportedFormats` Kore automatically handles backward compatibility for older game versions. If your `minFormat` is below the threshold (82 for DataPacks, 65 for ResourcePacks), Kore will automatically include the legacy `pack_format` and `supported_formats` fields in the generated `pack.mcmeta` file to ensure compatibility with older versions of Minecraft. You can also set `supportedFormats` explicitly with a small DSL: ```kotlin dataPack("mydatapack") { pack { minFormat(48) maxFormat(60) description = textComponent("My Datapack") supportedFormats(48..60) supportedFormats(min = 48) // max is optional } } ``` ### Targeting Minecraft 1.21.9+ Starting with Minecraft 1.21.9 (25w31a), `min_format` and `max_format` are the primary fields in `pack.mcmeta`. The`pack_format` field can be a decimal value to represent snapshots or minor versions. You can set this using `packFormat(Double)`: ```kotlin dataPack("my_datapack") { pack { minFormat(94) maxFormat(94) packFormat = packFormat(94.1) description = textComponent("Targeting 1.21.9") } } ``` Note that `minFormat` and `maxFormat` do not accept decimal values - use a plain integer or a `[major, minor]` pair. ## Overlays Overlays allow you to apply different resources depending on the pack format version of the client. Use the `overlays` DSL to declare overlay entries: ```kotlin dataPack("my_datapack") { overlays { entry("my_overlay") { minFormat(82) maxFormat(93) } } } ``` Each `entry` takes a directory name and a block where you configure `minFormat` and `maxFormat` using the same shortcut functions as in the `pack` block. ## Filters Filters are used to filter out certain files from the datapack. For now, you can only filter out block files. For example, to filter out all `.txt` files: ```kotlin dataPack("my_datapack") { filter { blocks("stone*") } } ``` This will filter out all block files that start with `stone`. ## Content The main content of the datapack is generated from the various builder functions like `biome`, `lootTable`, etc. For example: ```kotlin dataPack("my_datapack") { // ... recipes { craftingShaped("enchanted_golden_apple") { pattern( "GGG", "GAG", "GGG" ) key("G", Items.GOLD_BLOCK) key("A", Items.APPLE) result(Items.ENCHANTED_GOLDEN_APPLE) } } } ``` This demonstrates adding a custom recipe to the datapack. ## Generation To generate the datapack, call the `generate()` function: ```kotlin dataPack("my_datapack") { // datapack code here }.generate() ``` This will generate the datapack with the given name in the `out` folder by default.
To change the output folder, use the `path` function: ```kotlin dataPack("my_datapack") { path("%appdata%/.minecraft/saves/my_world/datapacks") }.generate() ``` ### Zip Generation To generate a zip file of the datapack, use the `generateZip` function: ```kotlin dataPack("my_datapack") { // datapack code here }.generateZip() ``` Generated ZIP entries follow the ZIP specification and always use forward slashes (`/`) internally. This keeps the archive compatible with strict tools such as Windows Explorer in addition to WinRAR and other archive managers. ### Jar Generation To generate a JAR file for your datapack, use the `generateJar` function. This function packages the datapack into a JAR file which can then be used directly with your Minecraft installation or distributed for others to use. ```kotlin dataPack("my_datapack") { // datapack code here }.generateJar() ``` By calling `generateJar()`, the generated JAR file will be placed in the default output folder. If you wish to specify a different location, use the `path` function: ```kotlin dataPack("my_datapack") { path("path/to/output/folder") }.generateJar() ``` You can also configure the JAR generation for different mod loaders such as Fabric, Forge, Quilt, and NeoForge.
This will add metadata to the JAR file that is specific to the mod loader.
You will be able to include your datapack as a mod for your mod loader and simplify the installation process for users. Below are examples of how to set up these mod loaders: #### Fabric To configure Fabric mod loader, use the `fabric` block inside the `generateJar` function: ```kotlin dataPack("my_datapack") { // datapack code here }.generateJar { fabric { version = "1.2.5" contact { email = "kore@kore.kore" homepage = "https://kore.ayfri.com" } author("Ayfri") } } ``` This sets the Fabric version, and includes contact information and the author's name. #### Forge To configure Forge mod loader, use the `forge` block: ```kotlin dataPack("my_datapack") { // datapack code here }.generateJar { forge { mod { authors = "Ayfri" credits = "Generated by Kore" dependency("my_dependency") { mandatory = true version = "1.2.5" } } } } ``` This sets the mod authors, credits, and dependencies for Forge. #### Quilt To configure Quilt mod loader, use the `quilt` block: ```kotlin dataPack("my_datapack") { // datapack code here }.generateJar { quilt("kore") { metadata { contact { email = "kore@kore.kore" homepage = "https://kore.ayfri.com" } contributor("Ayfri", "Author") } version = "1.2.5" } } ``` This sets the metadata such as contact information and contributors for Quilt. #### NeoForge To configure NeoForge mod loader, use the `neoForge` block: ```kotlin dataPack("my_datapack") { // datapack code here }.generateJar { neoForge { mod { authors = "Ayfri" credits = "Generated by Kore" dependency("my_dependency") { type = NeoForgeDependencyType.REQUIRED version = "1.2.5" } } } } ``` This sets the authors, credits, and dependencies for NeoForge. ### Merging with existing datapacks To merge the generated datapack with an existing datapack, use the DSL with the function `mergeWithDatapacks`: ```kotlin dataPack("my_datapack") { // datapack code here }.generate { mergeWithDatapacks("existing_datapack 1", "existing_datapack 2") } ``` If a zip is provided, it will be considered as a datapack and merged with the generated datapack.
Kore creates the temporary directory used for extraction automatically before unzipping, then merges the extracted files with the generated datapack. This temporary folder is not removed automatically. #### Checking for compatibility When merging with other datapacks, Kore will check if the pack format range overlaps. If it does not, it will print a warning message. Example: ```kotlin val myDatapack1 = dataPack("my_datapack 1") { // datapack code here pack { minFormat(40) maxFormat(40) } } val myDatapack2 = dataPack("my_datapack 2") { // datapack code here pack { minFormat(50) maxFormat(50) } } myDatapack1.generate { mergeWithDatapacks(myDatapack2) } ``` This will print out the following message: ``` The pack format range of the other pack is different from the current one. This may cause issues. Format range: current: 40..40 other: 50..50. ``` It also checks for `supportedFormats` and warns if the other pack is not supported. ## What to read next - [From Datapacks to Kore](/docs/guides/from-datapacks-to-kore) - migration strategy, architecture choices, and production workflow for advanced authors - [Cookbook](/docs/guides/cookbook) - practical patterns once your pack structure is in place - [Functions](/docs/commands/functions) - reusable logic, tags, and generated functions - [Selectors](/docs/concepts/selectors) - target entities and players with typed filters - [Configuration](/docs/guides/configuration) - tune JSON formatting and generation behavior ## Publishing and Distribution Once you've generated your datapack, you may want to distribute it to the community. For automated publishing to platforms like Modrinth, CurseForge, and GitHub Releases, see the [GitHub Actions Publishing](/docs/advanced/github-actions-publishing) guide. #### Tags When merging with other datapacks, Kore will merge the tags `minecraft/tags/function/load.json` and `minecraft/tags/functions/tick.json`. Example: ```kotlin val myDatapack1 = dataPack("my_datapack 1") { // datapack code here load("my_main_function") { say("Hello World!") } } val myDatapack2 = dataPack("my_datapack 2") { // datapack code here load("load") { say("Hello Everyone!") } } myDatapack1.generate { mergeWithDatapacks(myDatapack2) } ``` The resulting `load.json` file will contain: ```json { "replace": false, "values": [ "my_datapack_1:generated_scope/my_main_function", "my_datapack_2:generated_scope/load" ] } ``` --- ## From Datapacks to Kore --- root: .components.layouts.MarkdownLayout title: From Datapacks to Kore nav-title: Datapack Veterans description: Deep technical guide for experienced datapack authors adopting Kore and Kotlin in production. keywords: minecraft, datapack, kore, kotlin, advanced, migration, architecture, production date-created: 2026-04-22 date-modified: 2026-04-22 routeOverride: /docs/guides/from-datapacks-to-kore --- # From Datapacks to Kore (Advanced) This page is for datapack authors who already ship real projects and want to adopt Kore without losing low-level control. You already understand vanilla systems, resource formats, and function/tag architecture. The goal here is to map that experience to Kore's model, explain the boundaries clearly, and provide practical migration patterns with production-style Kotlin. ## Who this guide is for You are the target audience if you already: - Structure large datapacks with folders, tags, and shared utility functions. - Work with scoreboards, predicates, loot tables, recipes, and worldgen. - Care about maintainability, testability, and deterministic generation. - Want type safety and refactors without losing low-level control. If you are new to datapacks, start with [Getting Started](/docs/getting-started) first. ## Why Kotlin (for datapack veterans) Kotlin does not replace Minecraft logic. It replaces fragile authoring workflows. Minecraft still runs generated `.mcfunction` and JSON. Kotlin gives you a safer, composable way to produce them. For the high-level pitch and a comparison with other generators, see [Why Kore](/docs/guides/why-kore). The practical gains for experienced datapack teams are: - **Typed APIs over stringly-typed commands**: fewer invalid IDs, selectors, and argument combinations. - **Refactorability**: IDE rename/find-usages works across your gameplay code. - **Composition**: extract reusable builders instead of copy-pasting command blocks. - **Expressive abstraction**: extensions and data classes let you encode conventions once and reuse everywhere. - **Deterministic output**: generation from code makes large packs easier to audit and reproduce. If you want a quick baseline first, read [Creating A Datapack](/docs/guides/creating-a-datapack), then come back here. ## Kore mental model in one sentence Kore is a **compile-time authoring DSL and generator**, not an in-game runtime framework. That distinction matters: - Kore code runs on your machine (or CI) during generation. - Generated datapack files run in Minecraft. - Kotlin objects and functions do not exist in-game after generation. Think of Kore as a programmable build system for datapack content. ## What Kore gives you At a high level, Kore ships as four installable modules: - `kore`: core DSL for functions, commands, and data-driven resources. - `oop`: higher-level gameplay utilities (entities, teams, timers, scoreboards, events, and more). - `helpers`: utility layer (renderers, math, raycasts, delegates, visual helpers, scheduler patterns). - `bindings`: importer that generates Kotlin bindings from external datapacks (**experimental**). Use `kore` as your baseline, then add modules only when you need their abstractions. For the canonical module overview, see [Home](/docs/home). ## What Kore does not give you (or not yet) Important boundaries and limitations: - **Not a resource pack tool**: Kore currently targets datapacks, not resource packs. - **Some SNBT gaps**: heterogeneous SNBT lists and SNBT operations like `bool(arg)`/`uuid(arg)` are not fully supported yet. - **No magical runtime optimization**: Kore improves authoring quality; Minecraft execution cost is still defined by your generated logic. - **Bindings stability caveat**: `bindings` is explicitly experimental and may evolve quickly. For known caveats, see [Known Issues](/docs/advanced/known-issues). ## How Kore works under the hood (practical pipeline) A practical pipeline view: 1. You describe datapack content in Kotlin builders. 2. Kore builds an in-memory model of functions/resources. 3. Kore serializes this model to `.mcfunction` and JSON files. 4. It writes output via `.generate()`, `.generateZip()`, or `.generateJar()`. Key implications: - Generation is deterministic from your Kotlin source and config. - You can inspect generated output at any time. - CI can regenerate and diff output to enforce consistency. Output targets and packaging strategy are explained in detail in [Creating A Datapack](/docs/guides/creating-a-datapack). ## Vanilla-to-Kore mapping If your current pack is hand-written, this is the direct conceptual mapping: - `data//function/...` -> `fun Function.someFeature() = function("feature/some_feature") { ... }` - `minecraft:load` tag editing -> `load("...") { function(someFeature()) }` - `minecraft:tick` tag editing -> `tick("...") { function(runtimeStep()) }` - JSON resources -> dedicated typed builders (`advancement`, `lootTable`, `recipe`, `predicate`, `enchantment`, `worldgen`, ...). Kore does not hide vanilla concepts. It formalizes them. ## A realistic project shape A scalable source layout for Kore projects: - `pack/` for pack bootstrap and configuration. - `feature/` for domain modules (combat, quests, economy, UI, progression). - `runtime/` for lifecycle and tick routing. - `resources/` for data-driven definitions. - `interop/` for imported/bound external packs. This keeps gameplay code readable while preserving direct datapack semantics in generated output. Example: ```kotlin data object Objectives { const val LIVES = "lives" const val ROUND = "round" } fun Function.combatInit() = function("feature/combat/init") { tellraw(allPlayers(), textComponent("[combat] initialized")) } fun Function.combatTick() = function("feature/combat/tick") { // Keep tick work small and dispatch if it grows. } fun Function.progressionTick() = function("feature/progression/tick") { // Keep progression routing isolated from combat. } fun DataPack.registerLifecycle() { load("system/bootstrap") { scoreboard.objectives.add(Objectives.LIVES, "dummy") scoreboard.objectives.add(Objectives.ROUND, "dummy") function(combatInit()) } tick("runtime/main") { function(combatTick()) function(progressionTick()) } } fun main() { dataPack("arena_core") { registerLifecycle() }.generate() } ``` For deeper lifecycle docs, see [Functions](/docs/commands/functions). ## Kotlin patterns that actually pay off in Kore ### 1) Type-safe function references first (recommended) Prefer function factories over string paths when wiring lifecycle hooks. You get refactors, find usages, and compile-time safety on every caller: ```kotlin fun Function.welcomeAnnounce() = function("feature/welcome/announce") { tellraw(allPlayers(), textComponent("Welcome to the server")) } fun Function.joinEffects() = function("feature/welcome/join_effects") { effect(allPlayers()) { give(Effects.RESISTANCE, duration = 3, amplifier = 0) } say("Join effects applied") } fun DataPack.registerJoinFlow() { load("system/join_bootstrap") { function(welcomeAnnounce()) function(joinEffects()) } } ``` ### 2) Extension-based feature modules Use `DataPack` extensions for registration, and `Function` extensions for reusable command snippets. ```kotlin fun Function.combatPipeline() = function("feature/combat/pipeline") { applyJoinEffects() runRoundRules() } fun Function.applyJoinEffects() { effect(allPlayers()) { give(Effects.RESISTANCE, duration = 3, amplifier = 0) } } fun Function.runRoundRules() { say("Round rules applied") } fun DataPack.registerCombatPipeline() { tick("runtime/combat_router") { function(combatPipeline()) } } ``` ### 3) Typed selectors as reusable domain rules Avoid rewriting long selector constraints inline. Keep domain intent in one selector value and reuse it across systems. ```kotlin val activePlayers = allPlayers { gamemode = !Gamemode.SPECTATOR scores = scores { "lives" greaterThan 0 "round" greaterThanOrEqualTo 1 } } fun DataPack.registerRoundMessaging() { function("feature/round/status") { tellraw(activePlayers, textComponent("Round running")) } } ``` See [Selectors](/docs/concepts/selectors) and [Scoreboards](/docs/concepts/scoreboards) for full syntax. ### 4) Data classes for repeatable feature config When you duplicate numeric tuning values, move them into typed configs. ```kotlin data class WaveConfig( val id: String, val title: String, val warningSeconds: Int, ) fun DataPack.registerWave(config: WaveConfig) { val warning = function("feature/waves/${config.id}_warning") { tellraw(allPlayers(), textComponent(config.title)) } function("feature/waves/${config.id}_start") { function(warning) schedule.function(warning, config.warningSeconds.seconds) } } ``` This keeps balancing changes local and reviewable. ## Advanced example: command + data-driven feature in one flow A common production pattern is to pair a command function with a typed data resource and lifecycle wiring. ```kotlin fun DataPack.registerArenaBlade() { val arenaBlade = Items.DIAMOND_SWORD { customName(textComponent("Arena Blade", Color.AQUA)) tooltipDisplay(showInTooltip = true) } val arenaBladePredicate = predicate("arena_blade") { matchTool(arenaBlade) } fun Function.checkArenaBlade() = function("feature/items/check_arena_blade") { execute { ifCondition(arenaBladePredicate) run { tellraw(allPlayers(), textComponent("Arena Blade detected")) } } } load("system/items_bootstrap") { function(checkArenaBlade()) } } ``` Reference pages used in that pattern: - [Components](/docs/concepts/components) - [Predicates](/docs/data-driven/predicates) - [Functions](/docs/commands/functions) ## Migration strategy for existing packs (incremental, no big-bang) When you already have stable gameplay in vanilla datapack files, migrate slice-by-slice. 1. **Freeze behavior** with a smoke test checklist (`/reload`, bootstrap output, one command per feature). 2. **Port one vertical slice** (for example onboarding flow or one combat mechanic). 3. **Generate to folder** with `.generate()` and inspect the output. 4. **Compare runtime behavior** in-game against your baseline. 5. **Repeat by subsystem**, then standardize shared Kotlin helpers. If your project depends on another datapack, import it with [Bindings](/docs/advanced/bindings) instead of string literals. ## Minecraft parity checkpoints (official docs) Use these vanilla checkpoints when validating generated output. They match what Kore emits and help avoid stale assumptions: - **`pack.mcmeta` format evolution**: modern packs use `min_format`/`max_format`, with compatibility behavior for older formats. See [Minecraft Wiki - pack.mcmeta](https://minecraft.wiki/w/Pack.mcmeta) and [Minecraft Wiki - pack format](https://minecraft.wiki/w/Pack_format). - **Datapack root + namespace rules**: generated folder/zip output should keep vanilla root conventions. See [Minecraft Wiki - data pack](https://minecraft.wiki/w/Data_pack). - **Lifecycle tags**: `load` and `tick` are still function-tag wiring under the hood. Kore gives you typed composition, but the runtime behavior remains vanilla tag dispatch. - **Scheduling semantics**: `schedule function ...` behavior is still Minecraft-native. Kore only improves authoring ergonomics around it. When something looks surprising in-game, inspect generated files and compare with these references first. ## Interop with existing datapacks via `bindings` This is useful when your pack relies on internal shared packs or third-party resources. ```kotlin import io.github.ayfri.kore.bindings.api.importDatapacks importDatapacks { configuration { outputPath("src/main/kotlin") packagePrefix = "kore.dependencies" } github("pixigeko.minecraft-default-data:1.21.11") { subPath = "data" } } ``` Then consume generated constants in your own functions instead of hand-written IDs. See the full flow in [Bindings](/docs/advanced/bindings). ## Choosing between `kore`, `helpers`, and `oop` Use this rule of thumb: - Stay on `kore` when the logic is still easy to reason about with plain builders. - Add `helpers` when you repeat infrastructure glue (rendering, scheduler, math, state delegates, raycasts). - Add `oop` when systems need stable gameplay objects and cross-system coordination (teams, timers, entities, state machines). Related deep dives: - [Helpers Utilities](/docs/helpers/utilities) - [OOP Utilities](/docs/oop/oop-utilities) - [Dynamic Strings](/docs/oop/dynamic-strings) ## Recent Kore features worth using in migration projects If your mental model is still from older Kore versions, these are high-impact upgrades: - **Pack metadata parity for modern Minecraft**: `minFormat`/`maxFormat`, overlays, and legacy compatibility handling are available directly in the pack DSL. - **Interop at scale with `bindings`**: import external datapacks and consume generated Kotlin constants instead of hand-maintained IDs. - **Dynamic Strings (`oop`)**: a macro-backed string toolkit over storage/NBT for advanced runtime text pipelines (substring, split, replace, case conversion, trim/pad, lists). - **Multiple output targets in the same workflow**: keep `.generate()` for review and CI diffs, then switch to `.generateZip()`/`.generateJar()` for releases. ## Verification workflow for advanced teams A robust dev/release loop: 1. Generate unpacked output with `.generate()` for reviewability. 2. Run focused smoke checks in-game (`/reload`, lifecycle hooks, one key command per feature). 3. Check generated tags/resources for namespace and path correctness. 4. Package releases with `.generateZip()` or `.generateJar()` only after behavior checks. 5. Keep generated outputs deterministic so CI and code review can catch regressions early. For packaging details (zip/jar/merge), see [Creating A Datapack](/docs/guides/creating-a-datapack). ## Common migration mistakes (and fixes) - **Mistake**: Porting file-by-file instead of behavior-by-behavior. **Fix**: Migrate vertical slices and validate each runtime path before moving on. - **Mistake**: Building giant wrappers too early. **Fix**: Start with direct DSL usage and extract only repeated patterns. - **Mistake**: Ignoring naming conventions in generated paths. **Fix**: Adopt stable prefixes (`feature/`, `runtime/`, `system/`) from day one. - **Mistake**: Treating Kotlin as runtime state. **Fix**: Remember Kotlin runs at generation time only. - **Mistake**: Keeping critical IDs as ad-hoc strings everywhere. **Fix**: Centralize objectives/resource IDs in constants and helper APIs. ## Detailed migration checklist Before migration: - Freeze current pack behavior (manual test matrix or GameTest strategy). - Identify shared naming conventions and objective IDs. - Decide your initial module set (`kore` only, or `kore` + `helpers`/`oop`). First week: - Port lifecycle (`load`, `tick`) and one gameplay feature. - Introduce extension-based registration (`DataPack.registerX()`). - Add one data-driven resource with typed builder for parity checks. Stabilization: - Add reusable selector/predicate helpers. - Introduce typed config objects for balancing-heavy systems. - Optional: integrate external resources through `bindings`. ## Should you adopt Kore? Kore is an excellent fit if you want: - Long-term maintainability for non-trivial datapacks. - Safer refactors and shared abstractions. - Team workflows with code review and generation checks. Stay hand-written if your project is very small, short-lived, or intentionally one-off. ## Where to go next - [Getting Started](/docs/getting-started) for a minimal end-to-end baseline. - [Creating A Datapack](/docs/guides/creating-a-datapack) for output and generation details. - [Functions](/docs/commands/functions) for function composition and lifecycle hooks. - [Commands](/docs/commands/commands) for typed command usage. - [Cookbook](/docs/guides/cookbook) for practical composition patterns. - [OOP Utilities](/docs/oop/oop-utilities) for higher-level gameplay abstractions. - [Helpers Utilities](/docs/helpers/utilities) for reusable utility patterns. - [Bindings](/docs/advanced/bindings) for importing external datapacks. - [Known Issues](/docs/advanced/known-issues) for current limitations. --- # Commands ## Minecraft Commands in Kore - Type-Safe Command DSL --- root: .components.layouts.MarkdownLayout title: Minecraft Commands in Kore - Type-Safe Command DSL nav-title: Commands description: Every Minecraft command in a type-safe Kotlin DSL. From /say, /teleport, and /give to /execute, /data, /scoreboard, and /summon -- all with code examples and generated mcfunction output. keywords: minecraft commands, kore commands, kotlin commands dsl, mcfunction generator, execute command, data command, teleport command, summon command, minecraft command builder, type-safe commands date-created: 2026-02-03 date-modified: 2026-07-02 routeOverride: /docs/commands/commands --- # Commands Kore provides type-safe builders for all Minecraft commands. This page covers both simple and complex command usage with examples. Commands are used inside [Functions](/docs/commands/functions) to perform actions in the game. For dynamic command arguments, see [Macros](/docs/commands/macros). ## Simple Commands Simple commands are straightforward and take basic arguments like strings, numbers, or [selectors](/docs/concepts/selectors). ### Say Command The `say` command broadcasts a message to all players in the chat. The message appears with the sender's name (the entity executing the command). For more advanced chat formatting, see [Chat Components](/docs/concepts/chat-components). ```kotlin function("greetings") { say("Hello, world!") say("Welcome to the server!") } ``` Generated output: ```mcfunction say Hello, world! say Welcome to the server! ``` ### Teleport Command The `teleport` (or `tp`) command instantly moves entities to a new location. You can teleport to absolute coordinates, relative positions, or another entity's location. Optionally specify rotation (yaw/pitch) for the entity to face after teleporting. ```kotlin function("teleport_examples") { // Teleport to coordinates teleport(allPlayers(), vec3(100, 64, 100)) // Teleport to another entity teleport(allPlayers(), self()) // Teleport with rotation teleport(self(), vec3(0, 100, 0), rotation(0.rot, 90.rot)) } ``` Generated output: ```mcfunction tp @a 100 64 100 tp @a @s tp @s 0 100 0 0 90 ``` ### Give Command The `give` command adds items directly to a player's inventory. If the inventory is full, items drop on the ground. You can specify item count and use [Components](/docs/concepts/components) for custom item data. ```kotlin function("give_items") { give(allPlayers(), Items.DIAMOND_SWORD) give(allPlayers(), Items.GOLDEN_APPLE, 64) } ``` Generated output: ```mcfunction give @a minecraft:diamond_sword give @a minecraft:golden_apple 64 ``` ### Kill Command The `kill` command instantly removes entities from the world. Killed entities trigger death events (drops, death messages for players). Use selectors to target specific entity types. ```kotlin function("cleanup") { kill(allEntities { type = EntityTypes.ZOMBIE }) kill(self()) } ``` Generated output: ```mcfunction kill @e[type=minecraft:zombie] kill @s ``` ### Effect Command The `effect` command applies or removes status effects (like Speed, Regeneration, Poison) from entities. Effects have duration (in seconds or infinite) and amplifier levels (0 = level I, 1 = level II, etc.). ```kotlin function("effects") { effect(allPlayers()) { give(Effects.SPEED, duration = 60, amplifier = 1) } effect(self()) { giveInfinite(Effects.REGENERATION) } effect(allPlayers()) { clear() } effect(self()) { clear(Effects.POISON) } } ``` Generated output: ```mcfunction effect give @a minecraft:speed 60 1 effect give @s minecraft:regeneration infinite effect clear @a effect clear @s minecraft:poison ``` ### Gamemode Command The `gamemode` command changes a player's game mode (Survival, Creative, Adventure, Spectator). Each mode has different abilities and restrictions. ```kotlin function("modes") { gamemode(Gamemode.CREATIVE, allPlayers()) gamemode(Gamemode.SURVIVAL, player("Steve")) } ``` Generated output: ```mcfunction gamemode creative @a gamemode survival Steve ``` ### Time Command The `time` command controls world clocks. Time is measured in [ticks](/docs/concepts/time) (20 ticks = 1 second, 24 000 ticks = 1 Minecraft day). The `time` property on a `Function` returns a `Time` DSL scope. For a full reference covering world clocks, timelines, time markers, and the `timeCheck` predicate, see [World Clocks](/docs/data-driven/world-clocks). #### Basic Time Operations ```kotlin function("time_control") { time.add(6000) // advance by 6000 ticks time.add(1.days) // advance by one full day time.pause() // freeze the clock time.resume() // unfreeze the clock time.set(TimePeriod.DAY) // jump to a named period time.set(6000) // jump to an exact tick time.query(TimeType.DAYTIME) time.queryTime() // absolute game time as integer } ``` Generated output: ```mcfunction time add 6000 time add 1d time pause time resume time set day time set 6000 time query daytime time query time ``` #### Querying Timelines Use `query(timeline)` to read a timeline's progress, and `queryRepetitions(timeline)` to read how many times it has looped: ```kotlin function("time_query_timeline") { time.query(Timelines.DAY) time.queryRepetitions(Timelines.DAY) } ``` Generated output: ```mcfunction time query minecraft:day time query minecraft:day repetitions ``` #### Setting the Day-Night Cycle Rate Use `rate(rate)` to control how fast the day-night cycle progresses. `1` is the default speed, `0` freezes the cycle, and the maximum is `1000`. This is independent of the server tick rate: ```kotlin function("time_rate") { time.rate(1.0f) // default speed time.rate(0.0f) // freeze the day-night cycle time.rate(2.0f) // double speed time.rate(0.5f) // half speed } ``` Generated output: ```mcfunction time rate 1 time rate 0 time rate 2 time rate 0.5 ``` #### Setting to a Time Marker `TimeMarkerArgument` (created with the `timeMarker()` factory) references a named tick position defined inside a timeline. Pass it to `time.set()` to jump the clock to that position: ```kotlin function("skip_to_noon") { time.set(timeMarker("noon", "mymod")) } ``` Generated output: ```mcfunction time set mymod:noon ``` #### Targeting a Specific Clock with `time.of(clock)` When your datapack defines multiple [world clocks](/docs/data-driven/world-clocks), use `time.of(clock)` to scope every subcommand to that clock. It returns a `TimeWithClock` instance that mirrors the full `Time` API: ```kotlin val seasonClock = worldClock("season") function("season_control") { time.of(seasonClock).add(6000) time.of(seasonClock).pause() time.of(seasonClock).resume() time.of(seasonClock).set(TimePeriod.DAY) time.of(seasonClock).set(timeMarker("summer", "mymod")) time.of(seasonClock).query(TimeType.DAYTIME) time.of(seasonClock).query(Timelines.DAY) time.of(seasonClock).queryRepetitions(Timelines.DAY) time.of(seasonClock).queryTime() time.of(seasonClock).rate(2.0f) } ``` Generated output: ```mcfunction time of mymod:season add 6000 time of mymod:season pause time of mymod:season resume time of mymod:season set day time of mymod:season set mymod:summer time of mymod:season query daytime time of mymod:season query minecraft:day time of mymod:season query minecraft:day repetitions time of mymod:season query time time of mymod:season rate 2 ``` ### Weather Command The `weather` command changes the world's weather state. Clear weather has full sunlight, rain reduces light and affects mob spawning, thunder enables lightning strikes and charged creeper creation. ```kotlin function("weather_control") { weatherClear() weatherRain(6000) weatherThunder() } ``` Generated output: ```mcfunction weather clear weather rain 6000 weather thunder ``` ### Summon Command The `summon` command spawns a new entity at the specified location. You can provide NBT data to customize the entity's properties (name, AI, equipment, etc.). ```kotlin function("spawn_mobs") { summon(EntityTypes.ZOMBIE, vec3(0, 64, 0)) summon(EntityTypes.CREEPER, vec3()) { this["CustomName"] = "\"Boom\"" this["NoAI"] = true } } ``` Generated output: ```mcfunction summon minecraft:zombie 0 64 0 summon minecraft:creeper ~ ~ ~ {CustomName:"\"Boom\"",NoAI:true} ``` ### SetBlock Command The `setblock` command places a single block at the specified coordinates. Use modes to control behavior: `destroy` (drops items), `keep` (only if air), or `replace` (default). ```kotlin function("build") { setBlock(vec3(0, 64, 0), Blocks.DIAMOND_BLOCK) setBlock(vec3(0, 65, 0), Blocks.STONE, SetBlockMode.REPLACE) } ``` Generated output: ```mcfunction setblock 0 64 0 minecraft:diamond_block setblock 0 65 0 minecraft:stone replace ``` ### Fill Command The `fill` command fills a rectangular region with blocks. Modes include: `replace` (all blocks), `hollow` (only outer shell), `outline` (shell without clearing inside), `keep` (only air blocks), and `destroy` (drops items). ```kotlin function("fill_area") { fill(vec3(0, 64, 0), vec3(10, 70, 10), Blocks.STONE) fill(vec3(0, 64, 0), vec3(10, 70, 10), Blocks.AIR, FillMode.REPLACE) fill(vec3(0, 64, 0), vec3(10, 70, 10), Blocks.GLASS, FillMode.HOLLOW) } ``` Generated output: ```mcfunction fill 0 64 0 10 70 10 minecraft:stone fill 0 64 0 10 70 10 minecraft:air replace fill 0 64 0 10 70 10 minecraft:glass hollow ``` ### Enchant Command The `enchant` command adds an enchantment to the item held by the target entity. The enchantment must be compatible with the item type. For more control over enchantments, see [Enchantments](/docs/data-driven/enchantments). ```kotlin function("enchant_examples") { enchant(self(), Enchantments.MENDING) enchant(self(), Enchantments.SHARPNESS, 5) } ``` Generated output: ```mcfunction enchant @s minecraft:mending enchant @s minecraft:sharpness 5 ``` ### Difficulty Command The `difficulty` command gets or sets the world's difficulty level (Peaceful, Easy, Normal, Hard). Difficulty affects mob damage, hunger depletion, and whether hostile mobs spawn. ```kotlin function("difficulty_examples") { difficulty() // Query current difficulty difficulty(Difficulty.HARD) } ``` Generated output: ```mcfunction difficulty difficulty hard ``` ### SpawnPoint Command The `spawnpoint` command sets where a player respawns after death. Each player can have their own spawn point. Optionally specify the facing direction on respawn. ```kotlin function("spawnpoint_examples") { spawnPoint() // Set at current position spawnPoint(self()) spawnPoint(self(), vec3(100, 64, 100)) spawnPoint(self(), vec3(100, 64, 100), rotation(90, 0)) } ``` Generated output: ```mcfunction spawnpoint spawnpoint @s spawnpoint @s 100 64 100 spawnpoint @s 100 64 100 90 0 ``` ### SetWorldSpawn Command The `setworldspawn` command sets the default spawn point for all new players and players without a personal spawn point. This is where the world compass points to. ```kotlin function("worldspawn_examples") { setWorldSpawn() setWorldSpawn(vec3(0, 64, 0)) setWorldSpawn(vec3(0, 64, 0), rotation(0, 0)) } ``` Generated output: ```mcfunction setworldspawn setworldspawn 0 64 0 setworldspawn 0 64 0 0 0 ``` ### StopSound Command The `stopsound` command stops currently playing sounds for players. You can filter by sound source (master, music, weather, etc.) and specific sound. Useful for stopping looping sounds or music. ```kotlin function("stopsound_examples") { stopSound(self()) stopSound(self(), PlaySoundMixer.MASTER) stopSound(self(), PlaySoundMixer.MASTER, Sounds.Mob.Bat.TAKEOFF) stopSoundAllSources(self()) stopSoundAllSources(self(), Sounds.Mob.Bat.TAKEOFF) } ``` Generated output: ```mcfunction stopsound @s stopsound @s master stopsound @s master minecraft:mob/bat/takeoff stopsound @s * stopsound @s * minecraft:mob/bat/takeoff ``` ### Stopwatch Command The `stopwatch` command manages server-side timers that count game ticks. Stopwatches persist across sessions and can be queried in execute conditions. Useful for cooldowns, timed events, and measuring durations. ```kotlin function("stopwatch_examples") { val myStopwatch = stopwatch("my_timer") stopwatchCreate(myStopwatch) stopwatchQuery(myStopwatch) stopwatchRestart(myStopwatch) stopwatchRemove(myStopwatch) } ``` Generated output: ```mcfunction stopwatch my_datapack:my_timer create stopwatch my_datapack:my_timer query stopwatch my_datapack:my_timer restart stopwatch my_datapack:my_timer remove ``` You can also use stopwatches in execute conditions: ```kotlin function("stopwatch_condition") { execute { ifCondition { stopwatch(stopWatch("my_timer"), rangeOrInt(100)) } run { say("Timer reached 100 ticks!") } } } ``` Generated output: ```mcfunction execute if stopwatch my_datapack:my_timer 100 run say Timer reached 100 ticks! ``` ### Message Commands The `msg` command (aliases: `tell`, `w`) sends a private message to a specific player. The `teammsg` command (alias: `tm`) sends a message to all members of the sender's team. See [Scoreboards](/docs/concepts/scoreboards) for team management. ```kotlin function("message_examples") { msg(self(), "Hello!") tell(self(), "Hello!") // Alias for msg w(self(), "Hello!") // Alias for msg teamMsg("Hello team!") tm("Hello team!") // Alias for teamMsg } ``` Generated output: ```mcfunction msg @s Hello! msg @s Hello! msg @s Hello! teammsg Hello team! teammsg Hello team! ``` ### Spectate Command The `spectate` command makes a player in Spectator mode view the game from another entity's perspective. Call without arguments to stop spectating. ```kotlin function("spectate_examples") { spectate() // Stop spectating spectate(self()) // Spectate target spectate(self(), self()) // Target and spectator } ``` Generated output: ```mcfunction spectate spectate @s spectate @s @s ``` ### Debug Commands These commands are server debugging utilities. `debug` starts/stops profiling and creates a report. `perf` captures performance metrics for 10 seconds. `jfr` starts/stops Java Flight Recorder profiling. ```kotlin function("debug_examples") { debugStart() debugStop() perfStart() perfStop() jfrStart() jfrStop() } ``` Generated output: ```mcfunction debug start debug stop perf start perf stop jfr start jfr stop ``` ## Complex Commands Complex commands have nested structures and multiple sub-commands. Kore provides specialized builders for these. ### Execute Command The `execute` command is one of the most powerful commands in Minecraft. It allows you to: - Change the execution context (who/where the command runs) - Add conditions (only run if criteria are met) - Store command results in scores or NBT - Chain multiple modifiers together The examples below cover the basics. For the full subcommand, condition, store, and `run` reference, see the dedicated [Execute](/docs/commands/execute) page. Use `execute` with [Predicates](/docs/data-driven/predicates) for complex conditions. #### Basic Execute ```kotlin function("execute_basic") { execute { asTarget(allPlayers()) run { say("Hello from execute!") } } } ``` Generated output: ```mcfunction execute as @a run say Hello from execute! ``` Conditions (`if`/`unless`), score comparisons, position/dimension/anchoring context, entity relations, and the full subcommand list are documented on the dedicated [Execute](/docs/commands/execute) page. A quick conditional example: ```kotlin function("execute_conditions") { execute { asTarget(allEntities { limit = 3 sort = Sort.RANDOM }) ifCondition { score(self(), "points") greaterThanOrEqualTo 10 } run { say("You have enough points!") } } } ``` Generated output: ```mcfunction execute as @e[limit=3,sort=random] if score @s points >= 10 run say You have enough points! ``` #### Execute Store Store command results in scores or NBT: ```kotlin function("execute_store") { execute { storeResult { score(self(), "my_score") } run { time.query(TimeQuery.DAYTIME) } } } ``` Generated output: ```mcfunction execute store result score @s my_score run time query daytime ``` ### Data Command The `data` command reads and writes NBT (Named Binary Tag) data on entities, block entities (chests, signs, etc.), and command storage. NBT stores complex data like inventory contents, entity attributes, and custom tags. Operations include `get` (read), `merge` (combine), `modify` (change specific paths), and `remove` (delete). #### Basic Data Operations ```kotlin function("data_basic") { data(self()) { get("Health") get("Inventory", 1.0) } } ``` Generated output: ```mcfunction data get entity @s Health data get entity @s Inventory 1 ``` #### Data Merge ```kotlin function("data_merge") { data(self()) { merge { this["CustomName"] = "\"Hero\"" this["Invulnerable"] = true } } } ``` This `merge { ... }` block uses the same NBT builder described in [NBTs](/docs/concepts/nbts), so you can reuse the same assignment patterns in commands, predicates, and chat-related APIs. Generated output: ```mcfunction data merge entity @s {CustomName:"\"Hero\"",Invulnerable:true} ``` #### Data Modify ```kotlin function("data_modify") { data(self()) { modify("Inventory") { append(Items.DIAMOND) } modify("Tags") { prepend("new_tag") } modify("Health") { set(20) } modify("Pos[0]") { set(self(), "Pos[0]") } } } ``` Generated output: ```mcfunction data modify entity @s Inventory append value "minecraft:diamond" data modify entity @s Tags prepend value "new_tag" data modify entity @s Health set value 20 data modify entity @s Pos[0] set from entity @s Pos[0] ``` `data modify ... string ... [start] [end]` is also supported for every string-capable operation (`set`, `append`, `insert`, `merge`, `prepend`): ```kotlin function("data_modify_string_ranges") { data(self()) { modify("foo") { append(self(), "name", 1) } modify("foo") { insert(0, self(), "name", 0, 4) } modify("foo") { merge(self(), "name", -5) } modify("foo") { prepend(self(), "name", 0, 2) } modify("foo") { set(self(), "name", 0, 3) } } } ``` Generated output: ```mcfunction data modify entity @s foo append string entity @s name 1 data modify entity @s foo insert 0 string entity @s name 0 4 data modify entity @s foo merge string entity @s name -5 data modify entity @s foo prepend string entity @s name 0 2 data modify entity @s foo set string entity @s name 0 3 ``` #### Data Remove ```kotlin function("data_remove") { data(self()) { remove("CustomName") remove("Tags[0]") } } ``` Generated output: ```mcfunction data remove entity @s CustomName data remove entity @s Tags[0] ``` ### Scoreboard Command The `scoreboard` command manages objectives (score types) and player/entity scores. Scoreboards are essential for tracking game state, creating timers, and building game mechanics. See [Scoreboards](/docs/concepts/scoreboards) for detailed usage. ```kotlin function("scoreboard_examples") { // Objectives scoreboard.objectives.add("kills", "playerKillCount", textComponent("Player Kills")) scoreboard.objectives.remove("old_objective") scoreboard.objectives.setDisplay(DisplaySlot.SIDEBAR, "kills") // Players scoreboard.players.set(allPlayers(), "kills", 0) scoreboard.players.add(self(), "kills", 1) scoreboard.players.remove(self(), "kills", 5) scoreboard.players.reset(self(), "kills") // Operations scoreboard.players.operation(self(), "total", Operation.ADD, self(), "kills") } ``` ### Bossbar Command The `bossbar` command creates and controls boss bars - the progress bars normally shown during boss fights. Boss bars can display custom text, colors, and progress values. They're useful for timers, progress indicators, and UI elements. ```kotlin function("bossbar_examples") { bossbar.add("my_bar", textComponent("My Boss Bar")) bossbar.set("my_bar") { color(BossBarColor.RED) max(100) value(50) visible(true) players(allPlayers()) style(BossBarStyle.NOTCHED_10) } bossbar.remove("my_bar") } ``` ### Team Command The `team` command creates and manages teams for players and entities. Teams control PvP (friendly fire), name tag visibility, collision, and chat colors. See [Scoreboards](/docs/concepts/scoreboards) for more on teams. ```kotlin function("team_examples") { teams.add("red_team", textComponent("Red Team")) teams.modify("red_team") { color(Color.RED) friendlyFire(false) seeFriendlyInvisibles(true) } teams.join("red_team", allPlayers()) teams.leave(self()) } ``` ### Attribute Command The `attribute` command reads and modifies entity attributes like max health, movement speed, attack damage, and armor. You can get/set base values or add temporary modifiers that stack. ```kotlin function("attribute_examples") { attribute(self(), Attributes.GENERIC_MAX_HEALTH) { get() base.get() base.set(40.0) } attribute(self(), Attributes.GENERIC_MOVEMENT_SPEED) { modifiers.add("speed_boost", 0.1, AttributeModifierOperation.ADD_VALUE) modifiers.remove("speed_boost") } } ``` ### Schedule Command The `schedule` command delays function execution by a specified time. Useful for timers, cooldowns, and delayed effects. Time can be specified in [ticks, seconds, or days](/docs/concepts/time). See [Scheduler Helper](/docs/helpers/scheduler) for advanced scheduling patterns. ```kotlin function("schedule_examples") { val myFunction = function("delayed_action") { say("This runs later!") } schedule.function(myFunction, 100.ticks) schedule.function(myFunction, 5.seconds, ScheduleMode.REPLACE) schedule.clear(myFunction) } ``` ### Loot Command The `loot` command generates items from [Loot Tables](/docs/data-driven/loot-tables) and distributes them to players, containers, or the world. Sources include fishing, killing entities, mining blocks, or direct loot table references. ```kotlin function("loot_examples") { // Give loot to a player loot(self()) { loot(LootTables.Gameplay.CAT_MORNING_GIFT) } // Fish loot with a tool loot(self()) { fish(LootTables.Gameplay.CAT_MORNING_GIFT, vec3(), Items.FISHING_ROD) } // Kill loot from an entity loot(self()) { kill(self()) } // Mine loot from a position loot(self()) { mine(vec3(), Items.DIAMOND_PICKAXE) } // Insert loot into a container loot { target { insert(vec3()) } source { kill(self()) } } // Replace block inventory slot loot { target { replaceBlock(vec3(), CONTAINER[0]) } source { loot(LootTables.Gameplay.CAT_MORNING_GIFT) } } // Replace entity equipment slot loot { target { replaceEntity(self(), ARMOR.HEAD) } source { loot(LootTables.Gameplay.CAT_MORNING_GIFT) } } // Replace a mob inventory slot (villager / piglin use mob.inventory.*) loot { target { replaceEntity(self(), MOB.INVENTORY[0]) } source { loot(LootTables.Gameplay.CAT_MORNING_GIFT) } } // Inline loot table definition loot { target { give(self()) } source { loot { pool { rolls(1f) entries { item(Items.ANVIL) } } } } } } ``` Generated output: ```mcfunction loot give @s loot minecraft:gameplay/cat_morning_gift loot give @s fish minecraft:gameplay/cat_morning_gift ~ ~ ~ minecraft:fishing_rod loot give @s kill @s loot give @s mine ~ ~ ~ minecraft:diamond_pickaxe loot insert ~ ~ ~ kill @s loot replace block ~ ~ ~ container.0 loot minecraft:gameplay/cat_morning_gift loot replace entity @s armor.head loot minecraft:gameplay/cat_morning_gift loot replace entity @s mob.inventory.0 loot minecraft:gameplay/cat_morning_gift loot give @s loot {pools:[{rolls:1.0f,entries:[{type:"minecraft:item",name:"minecraft:anvil"}]}]} ``` ### Particle Command The `particle` command spawns visual particle effects in the world. Particles have position, spread (delta), speed, and count. Use `force` mode to make particles visible from far away or through blocks. ```kotlin function("particle_examples") { // Simple particle particle(Particles.ASH) // Particle at position with delta and count particle(Particles.ASH, vec3(), vec3(), 1.0, 2) // Particle with force mode (visible from far away) particle(Particles.ASH, vec3(), vec3(), 1.0, 2, ParticleMode.FORCE) // Particle visible only to specific players particle(Particles.ASH, vec3(), vec3(), 1.0, 2, ParticleMode.NORMAL, allEntities()) } ``` Generated output: ```mcfunction particle minecraft:ash particle minecraft:ash ~ ~ ~ ~ ~ ~ 1 2 particle minecraft:ash ~ ~ ~ ~ ~ ~ 1 2 force particle minecraft:ash ~ ~ ~ ~ ~ ~ 1 2 normal @e ``` #### Special Particle Types ```kotlin function("special_particles") { particles { // Block particles with state block(Blocks.STONE_SLAB(states = mapOf("half" to "top"))) // Block crumble effect blockCrumble(Blocks.STONE) // Block marker (invisible barrier visualization) blockMarker(Blocks.STONE) // Falling dust fallingDust(Blocks.STONE) // Colored dust particles dust(Color.PURPLE, 2.0) dust(rgb(0xabcdef), 2.0) // Dust color transition dustColorTransition(Color.BLUE, 2.0, Color.RED) // Entity effect with color entityEffect(color = Color.GREEN) // Item particle with components item(Items.DIAMOND_SWORD { enchantments { enchantment(Enchantments.SHARPNESS, 5) } }) // Sculk charge with angle sculkCharge(PI / 2) // Shriek with delay shriek(100) // Trail particle trail(Color.RED, Triple(1, 2, 3), 10) // Vibration to position vibration(vec3(1, 2, 3), 10) } } ``` ### Clone Command The `clone` command copies blocks from one region to another. Supports cross-dimension cloning, filtering by block type, and different modes: `replace` (all blocks), `masked` (non-air only), `move` (removes source). Use `strict` to fail if regions overlap incorrectly. ```kotlin function("clone_examples") { // Basic clone clone { begin = vec3(0, 64, 0) end = vec3(10, 74, 10) destination = vec3(100, 64, 100) } // Clone between dimensions clone { begin = vec3(0, 64, 0) end = vec3(10, 74, 10) destination = vec3(0, 64, 0) from = Dimensions.THE_NETHER to = Dimensions.OVERWORLD } // Clone with mask mode clone { begin = vec3(0, 64, 0) end = vec3(10, 74, 10) destination = vec3(100, 64, 100) masked(CloneMode.MOVE) // Only non-air blocks, move instead of copy } // Clone with block filter clone { begin = vec3(0, 64, 0) end = vec3(10, 74, 10) destination = vec3(100, 64, 100) filter(Tags.Block.BASE_STONE_OVERWORLD, CloneMode.FORCE) } // Strict mode (fail if regions overlap incorrectly) clone { begin = vec3(0, 64, 0) end = vec3(10, 74, 10) destination = vec3(5, 64, 5) strict = true } } ``` Generated output: ```mcfunction clone 0 64 0 10 74 10 100 64 100 clone from minecraft:the_nether 0 64 0 10 74 10 to minecraft:overworld 0 64 0 clone 0 64 0 10 74 10 100 64 100 masked move clone 0 64 0 10 74 10 100 64 100 filtered #minecraft:base_stone_overworld force clone 0 64 0 10 74 10 5 64 5 strict ``` ### WorldBorder Command The `worldborder` command controls the world border size, position, damage, and warning settings. The time parameter for `add` and `set` is specified in ticks. ```kotlin function("worldborder_examples") { worldBorder { // Expand border by 10 blocks over 200 ticks (10 seconds) add(10.0, time = 200) // Set border to 1000 blocks instantly set(1000.0) // Set border to 500 blocks over 6000 ticks (5 minutes) set(500.0, time = 6000) // Set center center(0.0, 0.0) // Damage settings damageAmount(0.2f) damageBuffer(5.0) // Warning settings setWarningDistance(10) setWarningTime(15) // Query current size get() } } ``` Generated output: ```mcfunction worldborder add 10 200 worldborder set 1000 worldborder set 500 6000 worldborder center 0 0 worldborder damage amount 0.2 worldborder damage buffer 5 worldborder warning distance 10 worldborder warning time 15 worldborder get ``` ## Selectors Selectors target entities in the world. Kore provides type-safe selector builders with filters for entity type, distance, scores, NBT, and more. If you want a selector-focused walkthrough beyond the command examples below, read the [Selectors](/docs/concepts/selectors) page alongside this reference: ```kotlin function("selector_examples") { // All players say(allPlayers()) // Nearest player teleport(nearestPlayer(), vec3(0, 64, 0)) // Random player give(randomPlayer(), Items.DIAMOND) // All entities with filters kill(allEntities { type = EntityTypes.ZOMBIE limit = 10 sort = Sort.NEAREST distance = rangeOrIntEnd(10) }) // Entities with scores effect(allEntities { scores { score("kills") greaterThanOrEqualTo 5 } }) { give(Effects.STRENGTH, duration = 60) } // Entities with NBT kill(allEntities { nbt = nbt { this["CustomName"] = "\"Target\"" } }) } ``` ## Macros Macros allow dynamic command arguments that are substituted at runtime. They're useful for creating reusable functions with parameters. ```kotlin function("greet_player") { say("Hello, ${macro("player_name")}!") } // Call with arguments load { function("greet_player", arguments = nbt { this["player_name"] = "Steve" }) } ``` Generated output: ```mcfunction $say Hello, $(player_name)! ``` For detailed macro usage including macro classes and validation, see [Macros](/docs/commands/macros). ## Raw Commands For commands not yet supported by Kore or for special cases, use `addLine`. This is also useful when working with [Macros](/docs/commands/macros) for fully dynamic commands: ```kotlin function("raw_commands") { addLine("say This is a raw command") addLine("execute as @a run say Hello") } ``` > Note: Using raw commands bypasses type safety. Prefer the DSL builders when available. ## Custom Commands Create your own command builders for mods or custom functionality. See [Functions](/docs/commands/functions) for more details on the Function context: ```kotlin fun Function.myModCommand(target: EntityArgument, value: Int) = addLine(command("mymod", literal(target.asString()), int(value))) // Usage function("custom") { myModCommand(self(), 42) } ``` Generated output: ```mcfunction mymod @s 42 ``` For broader composition patterns such as extracting reusable wrappers around commands, the [Cookbook](/docs/guides/cookbook) gives more realistic project-scale examples. ## See Also - [Functions](/docs/commands/functions) - Create and organize command functions - [Macros](/docs/commands/macros) - Dynamic command arguments - [Chat Components](/docs/concepts/chat-components) - Formatted text in commands - [Cookbook](/docs/guides/cookbook) - Practical command composition patterns in real datapacks - [World Clocks](/docs/data-driven/world-clocks) - World clocks, timelines, time markers, and `timeCheck` ### External Resources - [Minecraft Wiki: Commands](https://minecraft.wiki/w/Commands) - Complete command reference - [Minecraft Wiki: Target selectors](https://minecraft.wiki/w/Target_selectors) - Selector syntax --- ## Execute Command - Type-Safe Context, Conditions & Stores in Kore --- root: .components.layouts.MarkdownLayout title: Execute Command - Type-Safe Context, Conditions & Stores in Kore nav-title: Execute description: Master the /execute command with Kore's type-safe DSL. Context subcommands (as, at, positioned), conditions (if/unless), stores (score, bossbar, storage), and the run clause. Full guide with mcfunction examples. keywords: minecraft execute command, execute as at positioned, execute if unless, execute store, datapack execute, kore execute, minecraft command conditions, execute run, context subcommands date-created: 2026-06-24 date-modified: 2026-06-24 routeOverride: /docs/commands/execute --- # Execute `execute` is the most important command in any datapack. It modifies the **context** a command runs in (who runs it, where, facing which way), **branches** on world state, and **stores** a command's result. Almost all runtime logic flows through it - see [Runtime Logic](/docs/concepts/runtime-logic) for the bigger picture, and the [Minecraft Wiki](https://minecraft.wiki/w/Commands/execute) for the vanilla command semantics. In Kore you build an execute chain with the `execute { }` builder. Each call inside the block appends one subcommand, in order, and the final `run` clause is the command that actually runs: ```kotlin function("greet_nearby") { execute { asTarget(allPlayers()) at(self()) run { say("Hello!") } } } ``` This generates `execute as @a at @s run say Hello!`. ## Context subcommands These change who, where, and how the chained command runs. They can be combined freely and apply left to right. ```kotlin execute { align(Axes.XYZ) // floor the position to block grid anchored(Anchor.EYES) // set the local-coordinate anchor asTarget(allPlayers()) // run as each player (changes @s) at(self()) // run at the executor's position/rotation/dimension facing(vec3(10, 64, 10)) // face an absolute position facingEntity(self(), Anchor.EYES) // face an entity's eyes/feet inDimension(Dimensions.THE_END) // switch dimension on(Relation.OWNER) // hop to a related entity (owner, vehicle, ...) positioned(vec3(0, 64, 0)) // override the position positionedAs(self()) // take the position from a target positionedOver(HeightMap.WORLD_SURFACE) // snap Y to a heightmap rotated(rotation(0.rot, 0.rot)) // override the rotation rotatedAs(self()) // take rotation from a target summon(EntityTypes.MARKER) // summon and run as the new entity run { say("context set") } } ``` | Subcommand | Effect | |-------------------------------------------------|-----------------------------------------------------------------------------| | `align(axes, offset?)` | Floors the position onto the block grid on the given axes | | `anchored(anchor)` | Sets `EYES`/`FEET` anchor for `^ ^ ^` and `facing` | | `asTarget(target)` | Runs as each matched entity, changing `@s` and the executor | | `at(target)` | Sets position, rotation, and dimension to the target's | | `facing(vec3)` / `facingEntity(target, anchor)` | Rotates to face a point or an entity | | `inDimension(dimension)` | Switches the execution dimension | | `on(relation)` | Moves to a related entity (`OWNER`, `VEHICLE`, `TARGET`, `PASSENGERS`, ...) | | `positioned(vec3)` / `positionedAs(target)` | Sets the position absolutely or from a target | | `positionedOver(heightMap)` | Sets Y to the top block of a heightmap at the current X/Z | | `rotated(rotation)` / `rotatedAs(target)` | Sets the rotation absolutely or from a target | | `summon(entityType)` | Summons a new entity and runs as/at it | ## Conditions: if / unless `ifCondition` and `unlessCondition` gate the rest of the chain. A block can hold several checks - they are ANDed together. ```kotlin function("conditional") { execute { ifCondition { entity(allPlayers()) // at least one player exists block(vec3(0, 63, 0), Blocks.STONE) // block at pos is stone score(self(), "coins", rangeOrInt(10)) // score matches 10.. } unlessCondition { score(self(), "frozen", rangeOrInt(1)) // and NOT frozen >= 1 } run { say("All conditions matched") } } } ``` Available checks inside the condition block: | Check | Meaning | |---------------------------------------------|----------------------------------------------------| | `biome(pos, biome)` | The biome at `pos` matches a biome or biome tag | | `block(pos, block)` | The block at `pos` matches a block or block tag | | `blocks(start, end, dest, mode)` | A region matches another region (`ALL` / `MASKED`) | | `data(target, path)` | The data target has something at the NBT path | | `dimension(dimension)` | The execution is in the given dimension | | `entity(target)` | The selector matches at least one entity | | `function(function)` | A function returns a non-zero value | | `items(source, slots, predicate)` | Items in a container's slots match a predicate | | `loaded(pos)` | The chunk at `pos` is fully loaded | | `predicate(...)` | A predicate passes (by id, name, or inline block) | | `score(target, obj, range)` | A score matches an int range | | `score(target, obj, src, srcObj, relation)` | Two scores compare with a relation | | `stopwatch(id, range)` | A stopwatch has elapsed within a range (ms) | ### Comparing scores fluently Inside a condition block, `score(target, objective)` returns a handle with the full set of infix comparison operators: | Kotlin DSL | Generated syntax | |---------------------------------------------------|-----------------------------------| | `score(self(), "points") equalTo 10` | `if score @s points matches 10` | | `score(self(), "points") greaterThan 10` | `if score @s points > 10` | | `score(self(), "points") greaterThanOrEqualTo 10` | `if score @s points >= 10` | | `score(self(), "points") lessThan 10` | `if score @s points < 10` | | `score(self(), "points") lessThanOrEqualTo 10` | `if score @s points <= 10` | | `score(self(), "points") matches 1..5` | `if score @s points matches 1..5` | | `score(self(), "a") equalTo score(self(), "b")` | `if score @s a = @s b` | The relation operators also accept another score handle to compare two scores directly: ```kotlin execute { ifCondition { val coins = score(self(), "coins") coins greaterThanOrEqualTo 10 // if score @s coins matches 10.. coins matches 1..5 // if score @s coins matches 1..5 val lives = score(self(), "lives") coins greaterThan lives // if score @s coins > @s lives } run { say("rich and winning") } } ``` ### Referencing predicates directly If you already have a [Predicate](/docs/data-driven/predicates), pass it straight to `ifCondition`: ```kotlin val isRaining = predicate("is_raining") { weatherCheck(raining = true, thundering = false) } execute { ifCondition(isRaining) run { say("It is raining") } } ``` You can also write a one-off inline predicate without registering a file: ```kotlin execute { ifCondition { predicate { randomChance(0.5f) } } run { say("Heads") } } ``` ## Stores: capturing the result `storeResult` writes the chained command's numeric **return value**; `storeSuccess` writes `1`/`0` for whether it succeeded. Both can target a score, storage, entity NBT, block NBT, or a boss bar. ```kotlin function("count_players") { execute { storeResult { score(literal("#total"), "players") // store the count into a fake player's score } run { // `data get` returns the player count via the @a selector trick / entity count data(storage("state", "my_pack")) { get("player_count") } } } } ``` Store destinations: | Destination | Builder call | |-------------|---------------------------------------| | Score | `score(target, objective)` | | Storage | `storage(target, path, type, scale)` | | Entity NBT | `entity(target, path, type, scale)` | | Block NBT | `block(pos, path, type, scale)` | | Boss bar | `bossBarValue(id)` / `bossBarMax(id)` | The `type` is a [`DataType`](/docs/concepts/data-storage) (`BYTE`, `SHORT`, `INT`, `LONG`, `FLOAT`, `DOUBLE`) and `scale` is a multiplier applied before writing. ## The run clause `run` is always last. It accepts three forms: ```kotlin // 1. Inline block - a single command is inlined, multiple commands become a generated function execute { at(self()) run { say("inline") } } // 2. An existing function val reward = function("give_reward") { give(self(), Items.DIAMOND) } execute { ifCondition { score(self(), "coins", rangeOrInt(100)) } run(reward) } // 3. A newly named generated function execute { asTarget(allPlayers()) run("welcome") { say("Welcome!") } } ``` If you omit `run` entirely, Kore emits the bare `execute ...` chain (useful when the last subcommand, like `summon`, already has an effect). ## Ordering matters Subcommands apply in the order you call them, exactly like vanilla. `asTarget` then `at` is different from `at` then `asTarget`. Keep `run` last - anything after a `run` in the same block replaces the previous run. ## See also - [Runtime Logic](/docs/concepts/runtime-logic) - why execute is the backbone of in-game logic - [Predicates](/docs/data-driven/predicates) - reusable conditions for `ifCondition` - [Commands](/docs/commands/commands) - the full command reference --- ## Minecraft Datapack Functions - Create MCFunctions with Kore DSL --- root: .components.layouts.MarkdownLayout title: Minecraft Datapack Functions - Create MCFunctions with Kore DSL nav-title: Functions description: Create Minecraft datapack functions with Kore's Kotlin DSL. Build tick.json and load.json tags, organize commands into reusable functions, and generate clean MCFunction output. keywords: datapack functions, mcfunction, tick.json datapack, load.json datapack, minecraft function tags, tags/function datapack, kore functions, datapack mcfunction generator, function scheduling, minecraft function creator date-created: 2024-04-06 date-modified: 2026-07-02 routeOverride: /docs/commands/functions --- # Functions Functions represent reusable pieces of logic callable in a datapack. Create a function with the `function` builder: ```kotlin function("my_function") { say("Hello world!") } ``` Then in game, call the function with `/function my_datapack:my_function`. To call functions from other datapacks, see [Bindings](/docs/advanced/bindings). The `function` builder returns a `FunctionArgument` object that you can reuse to call the function from other functions: ```kotlin val myFunction = function("my_function") { say("Hello world!") } function("my_second_function") { function(myFunction) } ``` You can also package this pattern into reusable `Function` extensions: ```kotlin fun Function.myFunction() = function("my_function") { say("Hello world!") } load { function(myFunction()) } ``` That helper may be called from several places without worry. Kore is optimized for recreating the same named function, so using this pattern stays effectively instant while keeping your code easy to organize. If you only want to reuse a small block of commands without generating a separate `/function`, prefer a regular extension instead: ```kotlin fun Function.saySomething() { say("yay") say("also, yay") } load { saySomething() } ``` ## Tags You can set the tag of the current function you're working in with the `setTag` function: ```kotlin function("my_function") { setTag(tagFile = "load", tagNamespace = "minecraft") } ``` This will add the function to the `minecraft:load` tag. But you have simpler builders for the most common tags: ```kotlin load { say("Hello world!") } tick { execute { ifCondition(myPredicate) run { say("Hello world!") } } } ``` - `load` tag: `minecraft:load` - `tick` tag: `minecraft:tick` This will create functions with randomly generated names, but you can also specify the name of the function: ```kotlin load("my_load_function") { say("Hello world!") } ``` # Commands Many common commands have convenience builders like `say`, `teleport`, etc. See the [Commands](/docs/commands/commands) page for a comprehensive guide with examples. For example: ```kotlin function("commands") { say("Hello!") // say command teleport(player("Steve"), 100.0, 64.0, 100.0) // tp command } ``` You can also build raw command strings and execute them: ```kotlin addLine("say Hello from raw command!") ``` > Note: This is not recommended, but can be useful for commands not yet supported by the DSL, or if you > use [Macros](/docs/commands/macros). ## Available Commands All commands from the version cited in the [README](https://github.com/Ayfri/Kore/blob/master/README.md) are available. For detailed documentation on each command, see [Commands](/docs/commands/commands). ## Custom Commands You can pretty easily add new commands by creating your own builders. For example, imagine you created a mod that adds a new command `/my_command` that takes a player name and a message as arguments. You can create a builder for this command like this: ```kotlin import io.github.ayfri.kore.functions.Function fun Function.myCommand(player: String, message: String) = addLine(command("my_command", literal(player), literal(message))) ``` Then you can use it like any other command: ```kotlin function("my_function") { myCommand("Steve", "Hello!") } ``` For commands that take complex types as arguments, you should use the `.asArg()` function inside `literal()` function. For Argument types, you don't have to use this. See the code of the repository for more examples.
[Link to `time` command.](https://github.com/Ayfri/Kore/blob/master/kore/src/main/kotlin/commands/Time.kt)
[Link to `weather` command.](https://github.com/Ayfri/Kore/blob/master/kore/src/main/kotlin/commands/Weather.kt) ## Complex Commands Some commands are more complex and require more than just a few arguments. For example, the [`execute`](/docs/commands/execute) or [`data`](/docs/concepts/data-storage) commands. In that case, you can use complex builders that includes all the arguments of the command. But the syntax may vary depending on the command, so pairing this page with the broader [Commands](/docs/commands/commands) reference and selector-heavy examples from [Selectors](/docs/concepts/selectors) is often helpful. An example of the `execute` command: ```kotlin execute { asTarget(allEntities { limit = 3 sort = Sort.RANDOM }) ifCondition { score(self(), "test") lessThan 10 predicate(myPredicate) } run { // be sure to import the run function, do not use the one from kotlin. teleport(entity) } } ``` You can use predicates in the `ifCondition` block to check complex conditions. See the [Predicates](/docs/data-driven/predicates) documentation for more details. You may also have commands where you can create "contexts". An example of the `data` command: ```kotlin data(self()) { modify("Health", 20) modify("Inventory[0]", Items.DIAMOND_SWORD) } ``` # Macros See [Macros](/docs/commands/macros). # Generated Functions The same way the `load` and `tick` builders generate functions with random names, the `execute` builder also generates a function with a random name if you call multiple commands inside the `run` block. ```kotlin execute { run { say("Hello world!") say("Hello world2!") } } ``` This will generate a function with a random name that will be called by the `execute` command. > Note: The generated functions will be generated inside a folder named `generated_scopes` in the `functions` folder. > You can change the folder to whatever you want in [Configuration](/docs/guides/configuration). > Note: The generated name will have this pattern `generated_${hashCode()}`, where `hashCode()` is the hash code of the function. > This means that if you use the same `execute` builder multiple times, it will generate the same function name and reuse the same function. If you want to turn that into an explicit project pattern, the [Cookbook](/docs/guides/cookbook) shows how to wrap reusable logic in `Function` extensions with or without dedicated generated functions. # Debugging You have multiple ways to debug your functions. First, a `debug` function is available, it is pretty much the same as `tellraw` but always displaying the message to everyone. ```kotlin function("my_function") { debug("Hello world!", Color.RED) } ``` You also have a `debug` block for printing a log message to the console for each command you call inside the block. ```kotlin function("my_function") { debug { say("hello !") } } ``` This will add a command call to `tellraw` command, writing the exact command generated, clicking on the text will also call the command. Example of what is generated: ```mcfunction say hello ! tellraw @a {"text":"/say hello !","click_event":{"action":"suggest_command","command":"say hello !"},"hoverEvent":{"action":"show_text","value":{"text":"Click to copy command","color":"gray","italic":true}}} ``` The last example is a function call to `startDebug()` (which is called by the `debug` block), this will add log messages to the start and the end of the function, plus a log message for each command called inside the function. ```mcfunction tellraw @a [{"text":"Running function ","color":"gray","italic":true},{"text":"my_datapack:my_function","color":"white","bold":true,"click_event":{"action":"run_command","command":"function my_datapack:my_function"},"hoverEvent":{"action":"show_text","value":{"text":"Click to execute function","color":"gray","italic":true}},"italic":true}] say hello ! tellraw @a {"text":"/say hello !","click_event":{"action":"suggest_command","command":"say hello !"},"hoverEvent":{"action":"show_text","value":{"text":"Click to copy command","color":"gray","italic":true}}} tellraw @a [{"text":"Finished running function ","color":"gray","italic":true},{"text":"my_datapack:my_function","color":"white","bold":true,"click_event":{"action":"run_command","command":"function my_datapack:my_function"},"hoverEvent":{"action":"show_text","value":{"text":"Click to execute function","color":"gray","italic":true}},"italic":true}] ``` You can call the command by clicking on the debug texts added. Also running `toString()` in a function will return the generated function as a string, so you can manipulate it as you want. ## See Also - [Commands](/docs/commands/commands) - Complete command reference - [Macros](/docs/commands/macros) - Dynamic command arguments - [Tags](/docs/data-driven/tags) - Function tags for load and tick events - [Cookbook](/docs/guides/cookbook) - Practical patterns for reusable function helpers ### External Resources - [Minecraft Wiki: Function](https://minecraft.wiki/w/Function_(Java_Edition)) - Official function format --- ## Macros --- root: .components.layouts.MarkdownLayout title: Macros nav-title: Macros description: A guide for using macros in Minecraft functions. keywords: minecraft, datapack, kore, guide, macros, functions date-created: 2024-04-06 date-modified: 2026-02-03 routeOverride: /docs/commands/macros --- # Macros Macros allow dynamic command arguments that are substituted at runtime. Added in Minecraft 1.20.2, they enable creating reusable functions with parameters. They are one of the runtime tools covered in [Runtime Logic](/docs/concepts/runtime-logic), and their values typically come from [data storage](/docs/concepts/data-storage). For basic command usage, see [Commands](/docs/commands/commands). ## Using Macros To define a macro, use the `macro()` function: ```kotlin say("I'm gonna use the macro ${macro("foo")}") ``` Inside a Minecraft function: ```kotlin function("my_function") { say("This is my macro: ${macro("bar")}") } ``` When called, this will substitute the actual text of the macro. You can also evaluate a list of macros and have fully dynamic commands: ```kotlin eval("command", "arg1", "arg2") // equals to minecraft code: // $$(command) $(arg1) $(arg2) ``` ## Calling functions with macros You can call a function with macros by using the new `arguments` argument. ```kotlin function("my_function", arguments = nbt { this["bar"] = "baz" }) ``` That can also be a DataArgument (block position/entity selector/storage). ```kotlin function( "my_function", arguments = allEntities { type = EntityTypes.MARKER name = "test" }, path = "data.test" // optional path is available ) ``` ## Defining Macro Classes For more complex macro usage, you can create a `Macros` subclass to define your macros: ```kotlin class MyMacros : Macros() { val myMacro by "my_macro" } ``` Then pass an instance to your function: ```kotlin function("my_function", ::MyMacros) { say(macros.myMacro) } ``` Now you can access the macros on the `macros` property. This also allows validating macros that are required when calling the function with an NBT Compound. Exemple: ```kotlin class TeleportMacros : Macros() { val player by "player" } datapack { val teleportToSpawn = function("teleport_to_spawn", ::TeleportMacros) { teleport(player(macros.player), vec3()) } load { function(teleportToSpawn, arguments = nbt { this["name"] = "jeb_" }) // Will throw an error because function expects "player" macro function(teleportToSpawn, arguments = nbt { this["player"] = "jeb_" }) // Works fine } } ``` ## Best Practice When using macros, you can create a function with arguments that calls the function with the macros: ```kotlin fun main() { dataPack { function("teleport_to_spawn") { teleport(player(macro("player")), vec3()) } } } fun Function.teleportToSpawn(player: String) { function("teleport_to_spawn", arguments = nbt { this["player"] = player }) } ``` Then you can call this function with your argument as a macro: ```kotlin teleportToSpawn("jeb_") ``` ## Limitations - Macros can only be used in functions. - Macros aren't variables, they are just text substitutions, you can't do operations on them. - Macros are not type-checked. - It would be very difficult and long for Kore to allow macros as any argument of commands because of the wide variety of argument types and contexts in Minecraft commands. --- # Data driven ## Minecraft Advancements with Kore - Type-Safe DSL Guide --- root: .components.layouts.MarkdownLayout title: Minecraft Advancements with Kore - Type-Safe DSL Guide nav-title: Advancements description: Create custom Minecraft advancements with Kore's Kotlin DSL. Covers all triggers, criteria, rewards (functions, loot, recipes), display settings, and frames. Replace hand-written JSON with type-safe Kotlin. keywords: minecraft advancements, datapack advancements, advancement triggers, using_item trigger, inventory_changed, minecraft achievement, kore advancements, custom advancements, advancement criteria, advancement rewards date-created: 2024-01-08 date-modified: 2026-07-02 routeOverride: /docs/data-driven/advancements --- # Advancements Advancements are a system in Minecraft Java Edition that guides players through the game by setting goals and challenges to complete. They serve as in-game achievements that track player progress across various activities. ## Overview Advancements have several key characteristics: - **World-specific**: Progress is saved per world, not globally - **Game mode independent**: Can be completed in any game mode (Survival, Creative, Adventure, Spectator) - **Non-linear**: Can be completed in any order, regardless of parent-child relationships - **Notification system**: Completed advancements trigger toast notifications and chat messages - **Customizable**: Data packs can add custom advancements with unique criteria and rewards ## File Structure Advancements are stored as JSON files in data packs at: ``` data//advancement/.json ``` For complete JSON specification, see the [Minecraft Wiki - Advancement Definition](https://minecraft.wiki/w/Advancement_definition). ## Creating Advancements Use the `advancement` builder function to create advancements in Kore: ```kotlin dataPack("my_datapack") { advancement("my_first_advancement") { display(Items.DIAMOND, "My First Advancement", "Complete this challenge!") criteria { inventoryChanged("get_diamond", Items.DIAMOND) } } } ``` This generates `data/my_datapack/advancement/my_first_advancement.json`. ## Display Properties The display configuration controls how the advancement appears in the advancement screen and notifications. ### Basic Display ```kotlin advancement("example") { display(Items.DIAMOND_SWORD, "Title", "Description") { frame = AdvancementFrameType.TASK } } ``` ### Display with Chat Components For styled text with colors and formatting: ```kotlin advancement("styled_advancement") { display( icon = Items.GOLDEN_APPLE, title = textComponent("Golden Achievement") { color = Color.GOLD }, description = textComponent("Eat a golden apple") { color = Color.GRAY } ) { frame = AdvancementFrameType.GOAL } } ``` ### Display Properties Reference | Property | Type | Default | Description | |------------------|------------------------|----------|---------------------------------------------| | `icon` | `AdvancementIcon` | Required | Item displayed as the advancement icon | | `title` | `ChatComponents` | Required | Title shown in the advancement screen | | `description` | `ChatComponents` | Required | Description text below the title | | `frame` | `AdvancementFrameType` | `TASK` | Frame style: `TASK`, `GOAL`, or `CHALLENGE` | | `background` | `ModelArgument?` | `null` | Background texture (root advancements only) | | `showToast` | `Boolean?` | `true` | Show toast notification on completion | | `announceToChat` | `Boolean?` | `true` | Announce completion in chat | | `hidden` | `Boolean?` | `false` | Hide until completed (and hide children) | ### Frame Types Each frame type produces different visual feedback: | Frame | Notification Header | Header Color | Sound | |-------------|-----------------------|--------------|---------------| | `TASK` | "Advancement Made!" | Yellow | Standard | | `GOAL` | "Goal Reached!" | Yellow | Standard | | `CHALLENGE` | "Challenge Complete!" | Pink | Special music | > **Note:** Root advancements (without a parent) don't trigger notifications or chat messages. ### Icon with Components Customize the icon with item components like enchantments: ```kotlin advancement("enchanted_icon") { display(Items.DIAMOND_SWORD, "Master Swordsman", "Wield a legendary blade") { icon(Items.DIAMOND_SWORD, count = 1) { enchantments { enchantment(Enchantments.SHARPNESS, 5) enchantment(Enchantments.UNBREAKING, 3) } customName(textComponent("Legendary Sword", Color.GOLD)) } frame = AdvancementFrameType.CHALLENGE } } ``` ### Hidden Advancements Hidden advancements remain invisible (along with their children) until completed: ```kotlin advancement("secret_discovery") { display(Items.ENDER_EYE, "???", "A mysterious discovery") { hidden = true frame = AdvancementFrameType.CHALLENGE } // ...criteria } ``` ## Parent Advancements Set a parent to position the advancement in an existing tree: ```kotlin advancement("child_advancement") { // Reference vanilla advancement parent = Advancements.Story.ROOT display(Items.IRON_PICKAXE, "Mining Progress", "Continue your journey") // ... } ``` Or reference a custom advancement: ```kotlin advancement("child_advancement") { parent = AdvancementArgument("my_root", "my_namespace") // ... } ``` ### Creating a New Tab To create a new advancement tab, create a root advancement (no parent) with display and a background: ```kotlin advancement("my_custom_tab") { display(Items.COMPASS, "Custom Adventures", "Begin your journey") { frame = AdvancementFrameType.TASK background = Textures.Gui.Advancements.Backgrounds.STONE } criteria { tick("auto_grant") // Grants immediately } } ``` ## Criteria Criteria define the conditions that must be met to complete the advancement. Each criterion has a **trigger ** that activates when specific game events occur. ### Basic Criteria ```kotlin advancement("eat_apple") { criteria { consumeItem("eat_golden_apple") { item { items = listOf(Items.GOLDEN_APPLE) } } } } ``` ### Multiple Criteria Add multiple criteria to an advancement: ```kotlin advancement("multi_criteria") { criteria { inventoryChanged("get_diamond", Items.DIAMOND) inventoryChanged("get_emerald", Items.EMERALD) enterBlock("enter_water") { block = Blocks.WATER } } } ``` ### Criteria with Predicate Conditions Add predicate conditions to criteria for additional checks: ```kotlin advancement("conditional_criteria") { criteria { consumeItem("eat_apple_lucky") { item { items = listOf(Items.GOLDEN_APPLE) } conditions { randomChance(0.5f) // 50% chance timeCheck(6000f..18000f) // Daytime only } } } } ``` For a complete guide on predicates, see the [Predicates](/docs/data-driven/predicates) documentation. ## Triggers Triggers are the events that activate criteria. Kore supports all vanilla triggers: | Trigger | Description | |--------------------------------|-------------------------------------------| | `allayDropItemOnBlock` | Allay drops an item on a block | | `anyBlockUse` | Player uses any block | | `avoidVibrations` | Player avoids a vibration while sneaking | | `beeNestDestroyed` | Player breaks a bee nest/beehive | | `bredAnimals` | Player breeds two animals | | `brewedPotion` | Player takes item from brewing stand | | `changedDimension` | Player travels between dimensions | | `channeledLightning` | Player uses Channeling enchantment | | `constructBeacon` | Beacon structure is updated | | `consumeItem` | Player consumes an item | | `crafterRecipeCrafted` | Crafter crafts a recipe | | `curedZombieVillager` | Player cures a zombie villager | | `defaultBlockUse` | Player uses a block (default interaction) | | `effectsChanged` | Player's effects change | | `enchantedItem` | Player enchants an item | | `enterBlock` | Player enters a block | | `entityHurtPlayer` | Entity hurts the player | | `entityKilledPlayer` | Entity kills the player | | `fallAfterExplosion` | Player falls after an explosion | | `fallFromHeight` | Player falls from a height | | `filledBucket` | Player fills a bucket | | `fishingRodHooked` | Player hooks something with fishing rod | | `heroOfTheVillage` | Player becomes Hero of the Village | | `impossible` | Never triggers (manual grant only) | | `inventoryChanged` | Player's inventory changes | | `itemDurabilityChanged` | Item durability changes | | `itemUsedOnBlock` | Player uses item on a block | | `killedByArrow` | Player kills entities with arrows | | `killMobNearSculkCatalyst` | Kill a mob near sculk catalyst | | `levitation` | Player has Levitation effect | | `lightningStrike` | Lightning strikes near player | | `location` | Player is at a specific location | | `netherTravel` | Player travels via Nether | | `placedBlock` | Player places a block | | `playerGeneratesContainerLoot` | Player generates container loot | | `playerHurtEntity` | Player hurts an entity | | `playerInteractedWithEntity` | Player interacts with entity | | `playerKilledEntity` | Player kills an entity | | `playerShearedEquipment` | Player shears equipment from entity | | `recipeCrafted` | Player crafts a recipe | | `recipeUnlocked` | Player unlocks a recipe | | `rideEntityInLava` | Player rides entity in lava | | `shotCrossbow` | Player shoots a crossbow | | `sleptInBed` | Player sleeps in bed | | `slideDownBlock` | Player slides down a block | | `spearMobs` | Player spears mobs | | `startedRiding` | Player starts riding | | `summonedEntity` | Player summons an entity | | `tameAnimal` | Player tames an animal | | `targetHit` | Player hits a target block | | `thrownItemPickedUpByEntity` | Entity picks up thrown item | | `thrownItemPickedUpByPlayer` | Player picks up thrown item | | `tick` | Every game tick (use for auto-grant) | | `usedEnderEye` | Player uses Eye of Ender | | `usedTotem` | Player uses Totem of Undying | | `usingItem` | Player is using an item | | `villagerTrade` | Player trades with villager | | `voluntaryExile` | Player gets Bad Omen | For detailed trigger documentation, see the [Triggers](/docs/data-driven/advancements/triggers) page. ### Trigger Examples ```kotlin advancement("trigger_examples") { criteria { // Dimension travel changedDimension("enter_nether") { from = Dimensions.OVERWORLD to = Dimensions.THE_NETHER } // Block interaction enterBlock("step_on_pressure_plate") { block = Blocks.STONE_PRESSURE_PLATE } // Entity interaction playerKilledEntity("kill_zombie") { entity { type(EntityTypes.ZOMBIE) } } // Effect-based effectsChanged("get_speed") { effect(Effects.SPEED) { amplifier = rangeOrInt(1..3) duration = rangeOrInt(100..200) } } // Never triggers - for manual grant via commands impossible("manual_only") } } ``` ## Requirements Requirements define how criteria combine to complete the advancement. By default, **all criteria must be completed** (AND logic). ### Simple Requirements Require specific criteria by name: ```kotlin advancement("single_requirement") { criteria { inventoryChanged("get_diamond", Items.DIAMOND) inventoryChanged("get_emerald", Items.EMERALD) } // Only diamond is required (emerald is optional) requirements("get_diamond") } ``` ### AND Logic (All Required) Require multiple criteria (all must be met): ```kotlin advancement("and_requirements") { criteria { inventoryChanged("get_diamond", Items.DIAMOND) inventoryChanged("get_emerald", Items.EMERALD) } // Both required requirements("get_diamond", "get_emerald") } ``` ### OR Logic (Any Required) Use nested lists for OR groups: ```kotlin advancement("or_requirements") { criteria { inventoryChanged("get_diamond", Items.DIAMOND) inventoryChanged("get_emerald", Items.EMERALD) inventoryChanged("get_gold", Items.GOLD_INGOT) } // Need diamond OR emerald, AND gold requirements( listOf("get_diamond", "get_emerald"), // Either diamond or emerald listOf("get_gold") // AND gold ) } ``` ## Rewards Define rewards granted when the advancement is completed: ```kotlin advancement("rewarding_advancement") { // ...display and criteria rewards { experience = 100 loots(LootTables.Chests.IGLOO_CHEST) recipes(Recipes.DIAMOND_SWORD) } } ``` ### Reward Properties | Property | Type | Description | |--------------|----------------------------|-----------------------------------| | `experience` | `Int?` | Experience points awarded | | `function` | `FunctionArgument?` | Function to execute on completion | | `loot` | `List?` | Loot tables to roll | | `recipes` | `List?` | Recipes to unlock | ### Function Rewards Execute commands when the advancement is completed: ```kotlin // Anonymous generated function rewards { function { say("Congratulations!") } } // Named function rewards { function("celebration") { say("You did it!") playsound(Sounds.UI_TOAST_CHALLENGE_COMPLETE, PlaySoundMixer.MASTER, self()) } } // Reference existing function rewards { function = myExistingFunction } ``` ### Multiple Rewards ```kotlin advancement("full_rewards") { rewards { experience = 500 function("reward_function") { give(self(), Items.DIAMOND, 10) effect(self(), Effects.REGENERATION, 200, 2) } loots( LootTables.Chests.END_CITY_TREASURE, LootTables.Chests.STRONGHOLD_CORRIDOR ) recipes( Recipes.DIAMOND_PICKAXE, Recipes.DIAMOND_SWORD ) } } ``` ## Telemetry Control whether completing this advancement sends telemetry data: ```kotlin advancement("tracked_advancement") { sendsTelemetryEvent = true // Default is false } ``` ## Managing Advancements with Commands Use the `/advancement` command to grant, revoke, or test advancements. ### Using the Advancement Command Block ```kotlin function("manage_advancements") { advancement { // Grant/revoke everything grantEverything(self()) revokeEverything(self()) // Specific advancement grant(self(), Advancements.Adventure.KILL_A_MOB) revoke(self(), Advancements.Adventure.KILL_A_MOB) // With route and criterion grant(self(), AdvancementRoute.ONLY, Advancements.Story.ROOT, "criterion_name") } } ``` ### Target-Specific Block ```kotlin function("player_advancements") { advancement(self()) { grantEverything() grant(Advancements.Story.IRON_TOOLS) revoke(AdvancementRoute.FROM, Advancements.Nether.ROOT) } } ``` ### Advancement Routes | Route | Description | |-----------|--------------------------------------------| | `ONLY` | Only the specified advancement | | `FROM` | Advancement and all its children | | `THROUGH` | Advancement, all parents, and all children | | `UNTIL` | Advancement and all its parents | ## Complete Example Here's a comprehensive example demonstrating multiple features: ```kotlin dataPack("adventure_pack") { // Create a custom tab val customRoot = advancement("custom/root") { display(Items.COMPASS, "Custom Adventures", "Begin your custom journey") { frame = AdvancementFrameType.TASK background = Textures.Gui.Advancements.Backgrounds.ADVENTURE } criteria { tick("start") } } // Child advancement with multiple criteria advancement("custom/explorer") { parent = customRoot display(Items.MAP, "Explorer", "Visit multiple biomes") { frame = AdvancementFrameType.GOAL showToast = true announceToChat = true } criteria { location("visit_forest") { location { biome = Biomes.FOREST } } location("visit_desert") { location { biome = Biomes.DESERT } } location("visit_ocean") { location { biome = Biomes.OCEAN } } } // Any two biomes complete the advancement requirements( listOf("visit_forest", "visit_desert"), listOf("visit_forest", "visit_ocean"), listOf("visit_desert", "visit_ocean") ) rewards { experience = 50 } } // Challenge advancement advancement("custom/master") { parent = customRoot display(Items.NETHERITE_SWORD, "Master Adventurer", "Complete the ultimate challenge") { icon(Items.NETHERITE_SWORD) { enchantments { enchantment(Enchantments.SHARPNESS, 5) } } frame = AdvancementFrameType.CHALLENGE hidden = true } criteria { playerKilledEntity("kill_dragon") { entity { type(EntityTypes.ENDER_DRAGON) } } playerKilledEntity("kill_wither") { entity { type(EntityTypes.WITHER) } } } rewards { experience = 1000 function("master_reward") { title(self(), textComponent("MASTER ADVENTURER", Color.GOLD), textComponent("")) } } } } ``` ## Best Practices ### 1. Logical Progression Structure advancements to guide players naturally, even though completion order is flexible. ### 2. Meaningful Rewards Match reward value to advancement difficulty - challenging advancements should have worthwhile rewards. ### 3. Clear Descriptions Write descriptions that clearly explain what players need to do. ### 4. Use Hidden Sparingly Reserve hidden advancements for genuine surprises or easter eggs. ### 5. Test Criteria Verify criteria trigger correctly in-game before releasing your data pack. ## See Also - [Triggers](/docs/data-driven/advancements/triggers) - Complete trigger reference - [Predicates](/docs/data-driven/predicates) - Conditions for advancement criteria - [Loot Tables](/docs/data-driven/loot-tables) - Loot rewards - [Functions](/docs/commands/functions) - Function rewards - [Tags](/docs/data-driven/tags) - Use tags in conditions ## External Resources - [Minecraft Wiki: Advancement](https://minecraft.wiki/w/Advancement) - Game mechanics overview - [Minecraft Wiki: Advancement Definition](https://minecraft.wiki/w/Advancement_definition) - JSON format specification --- ## Advancements Triggers --- root: .components.layouts.MarkdownLayout title: Advancements Triggers nav-title: Advancements Triggers description: A guide for using advancements triggers in Minecraft with Kore. keywords: minecraft, datapack, kore, guide, advancements, triggers date-created: 2024-08-01 date-modified: 2026-04-25 routeOverride: /docs/data-driven/advancements/triggers --- ## Available Triggers Below is the comprehensive list of available trigger types. Each trigger includes a description, its properties with explanations, and an example usage in Kotlin. --- ### `allayDropItemOnBlock` **Description:** Triggers when an allay drops an item on a block. **Properties:** - `location`: The location where the item is dropped. **Example:** ```kotlin allayDropItemOnBlock("allay_drop") { location { block { blocks(Blocks.GRASS_BLOCK, Blocks.DIRT) } } } ``` --- ### `anyBlockUse` **Description:** Triggers when a player uses any block. **Properties:** _None._ **Example:** ```kotlin anyBlockUse("use_block") { conditions { playerProperties { lookingAt(Blocks.CRAFTING_TABLE) } } } ``` --- ### `avoidVibrations` **Description:** Triggers when a player avoids vibrations. **Properties:** - `location`: The location where vibrations are avoided. **Example:** ```kotlin avoidVibrations("avoid_sculk") { conditions { location { block = Blocks.SCULK_SENSOR } } } ``` --- ### `beeNestDestroyed` **Description:** Triggers when a bee nest is destroyed. **Properties:** - `block`: The type of block that was destroyed. - `item`: The item involved in the destruction. - `numBeesInside`: The number of bees that were inside the nest. **Example:** ```kotlin beeNestDestroyed("destroy_nest") { block = Blocks.BEE_NEST numBeesInside = rangeOrInt(1) item { item(Items.HONEYCOMB) } } ``` --- ### `bredAnimals` **Description:** Triggers when animals are bred. **Properties:** - `child`: The child animal resulting from the breeding. - `parent`: One of the parent animals. - `partner`: The other parent animal. **Example:** ```kotlin bredAnimals("breed_animals") { child { conditions { entityProperties { type(EntityTypes.COW) } } } parent { conditions { entityProperties { type(EntityTypes.COW) } } } partner { conditions { entityProperties { type(EntityTypes.COW) } } } } ``` --- ### `brewedPotion` **Description:** Triggers when a potion is brewed (player takes item from brewing stand). **Properties:** - `potion`: The potion that was brewed. **Example:** ```kotlin brewedPotion("brewed_potion") ``` --- ### `changedDimension` **Description:** Triggers when a player changes dimension. **Properties:** - `from`: The original dimension. - `to`: The new dimension. **Example:** ```kotlin changedDimension("enter_nether") { from = Dimensions.OVERWORLD to = Dimensions.NETHER } ``` --- ### `channeledLightning` **Description:** Triggers when lightning is channeled. **Properties:** - `victims`: A list of entities affected by the lightning. **Example:** ```kotlin channeledLightning("lightning_rod") { victim { conditions { entityProperties { type(EntityTypes.CREEPER) } } } } ``` --- ### `constructBeacon` **Description:** Triggers when a beacon is constructed. **Properties:** - `level`: The level of the beacon. **Example:** ```kotlin constructBeacon("make_beacon") { level = rangeOrInt(4) } ``` --- ### `consumeItem` **Description:** Triggers when an item is consumed. **Properties:** - `item`: The item that was consumed. **Example:** ```kotlin consumeItem("eat_apple") { item { items = listOf(Items.GOLDEN_APPLE) } } ``` --- ### `crafterRecipeCrafted` **Description:** Triggers when a recipe is crafted. **Properties:** - `recipeId`: The ID of the crafted recipe. - `ingredients`: The ingredients used in the recipe. **Example:** ```kotlin crafterRecipeCrafted("craft_diamond") { recipeId = Recipes.DIAMOND ingredient(Items.DIAMOND) { components { damage(0) } } } ``` --- ### `curedZombieVillager` **Description:** Triggers when a zombie villager is cured. **Properties:** - `villager`: The villager involved in the curing. - `zombie`: The zombie involved in the curing. **Example:** ```kotlin curedZombieVillager("cure_zombie") { villager { conditions { entityProperties { type(EntityTypes.VILLAGER) } } } zombie { conditions { entityProperties { type(EntityTypes.ZOMBIE) } } } } ``` --- ### `defaultBlockUse` **Description:** Triggers when a block is used with default interaction. **Properties:** _None._ **Example:** ```kotlin defaultBlockUse("use_default") { conditions { playerProperties { lookingAt(Blocks.CHEST) } } } ``` --- ### `effectsChanged` **Description:** Triggers when a player's effects change. **Properties:** - `effects`: The effects that have changed. - `source`: The source of the effect changes. **Example:** ```kotlin effectsChanged("get_effect") { effect(Effects.SPEED) { amplifier = rangeOrInt(1..3) duration = rangeOrInt(100..200) } source { conditions { entityProperties { type(EntityTypes.WITCH) } } } } ``` --- ### `enchantedItem` **Description:** Triggers when an item is enchanted. **Properties:** - `item`: The item that was enchanted. - `levels`: The levels of enchantment applied. **Example:** ```kotlin enchantedItem("enchant_item") { item { item(Items.DIAMOND_SWORD) } levels = rangeOrInt(1..3) } ``` --- ### `enterBlock` **Description:** Triggers when a player enters a specific block. **Properties:** - `block`: The block being entered. - `states`: The state properties of the block. **Example:** ```kotlin enterBlock("enter_block") { block = Blocks.REDSTONE_LAMP states { this["lit"] = "true" } } ``` --- ### `entityHurtPlayer` **Description:** Triggers when an entity hurts a player. **Properties:** - `damage`: Details about the damage inflicted. **Example:** ```kotlin entityHurtPlayer("hurt_player") { damage { sourceEntity { type(EntityTypes.ZOMBIE) } taken = rangeOrDouble(5.0..10.0) type { tag(Tags.DamageType.IS_FALL) } } } ``` --- ### `entityKilledPlayer` **Description:** Triggers when an entity kills a player. **Properties:** - `entity`: The entity that killed the player. - `killingBlow`: Details about the killing blow. **Example:** _Not provided in the original examples._ --- ### `fallAfterExplosion` **Description:** Triggers after falling from an explosion. **Properties:** - `startPosition`: The starting position of the fall. - `distance`: The distance fallen. - `cause`: The cause of the fall. **Example:** ```kotlin fallAfterExplosion("tnt_launch") { startPosition { position { y = rangeOrInt(100..200) } } distance { horizontal(10f) } } ``` --- ### `fallFromHeight` **Description:** Triggers when falling from a height. **Properties:** - `startPosition`: The starting position of the fall. - `distance`: The distance fallen. **Example:** ```kotlin fallFromHeight("high_fall") { distance { vertical(20f) } } ``` --- ### `filledBucket` **Description:** Triggers when a bucket is filled. **Properties:** - `item`: The bucket item that was filled. **Example:** ```kotlin filledBucket("fill_bucket") { item { item(Items.WATER_BUCKET) } } ``` --- ### `fishingRodHooked` **Description:** Triggers when a fishing rod hooks something. **Properties:** - `entity`: The entity hooked by the fishing rod. - `item`: The item used as the fishing rod. - `rod`: Details about the fishing rod. **Example:** ```kotlin fishingRodHooked("catch_fish") { item { item(Items.FISHING_ROD) } rod { components { enchantments { enchantment(Enchantments.LUCK_OF_THE_SEA, 3) } } } } ``` --- ### `heroOfTheVillage` **Description:** Triggers when becoming a hero of the village. **Properties:** _None._ **Example:** ```kotlin heroOfTheVillage("save_village") { conditions { location { dimension = Dimensions.OVERWORLD } } } ``` --- ### `impossible` **Description:** Prevents the advancement from being achieved. Useful for creating advancements that should only trigger functions. **Properties:** _None._ **Example:** ```kotlin impossible("impossible") ``` --- ### `inventoryChanged` **Description:** Triggers when inventory contents change. **Properties:** - `items`: The items involved in the inventory change. - `slots`: The inventory slots affected. **Example:** ```kotlin inventoryChanged("get_diamond") { item { item(Items.DIAMOND) } slots { empty = rangeOrInt(1..3) } } ``` --- ### `itemDurabilityChanged` **Description:** Triggers when item durability changes. **Properties:** - `delta`: The change in durability. - `durability`: The current durability of the item. - `item`: The item whose durability changed. **Example:** ```kotlin itemDurabilityChanged("tool_break") { delta = rangeOrInt(-10..-1) item { item(Items.DIAMOND_PICKAXE) } } ``` --- ### `itemUsedOnBlock` **Description:** Triggers when an item is used on a block. **Properties:** - `location`: The location where the item was used. **Example:** ```kotlin itemUsedOnBlock("bone_meal_use") { location { predicate { locationCheck { block { blocks(Blocks.GRASS_BLOCK, Blocks.DIRT) } } } } } ``` --- ### `killedByArrow` **Description:** Triggers when killed by a crossbow. **Properties:** - `firedFromWeapon`: The weapon used to fire the arrow. - `uniqueEntityTypes`: The number of unique entity types involved. - `victims`: The entities that were killed. **Example:** ```kotlin killedByArrow("killed_by_arrow") { firedFromWeapon { items = listOf(Items.BOW) components { enchantments { enchantment(Enchantments.POWER, 5) } } } uniqueEntityTypes = rangeOrInt(1..5) victim { conditions { entityProperties { type(EntityTypes.PLAYER) } } } } ``` --- ### `killMobNearSculkCatalyst` **Description:** Triggers when a mob is killed near a sculk catalyst. **Properties:** - `entity`: The entity that was killed. - `killingBlow`: Details about the killing blow. **Example:** ```kotlin killMobNearSculkCatalyst("kill_mob") { entity { type(EntityTypes.ZOMBIE) } killingBlow { sourceEntity { type(EntityTypes.PLAYER) } } } ``` --- ### `levitation` **Description:** Triggers during levitation. **Properties:** - `distance`: The distance of levitation. - `duration`: The duration of levitation. **Example:** ```kotlin levitation("float_up") { distance { y(10f) } duration = rangeOrInt(10..20) } ``` --- ### `lightningStrike` **Description:** Triggers on a lightning strike. **Properties:** - `bystander`: The bystanders affected by the lightning. - `lightning`: Details about the lightning strike. **Example:** ```kotlin lightningStrike("struck") { bystander { type { conditions { entityProperties { type(EntityTypes.CREEPER) } } } } } ``` --- ### `location` **Description:** Triggers every second based on location conditions. **Properties:** - `location`: The specific location conditions for the trigger. **Example:** ```kotlin location("reach_end") { conditions { location { dimension = Dimensions.THE_END } } } ``` --- ### `netherTravel` **Description:** Triggers when a player enters or exits the Nether. **Properties:** - `distance`: The distance traveled during the dimension change. - `startPosition`: The starting position before the change. **Example:** ```kotlin netherTravel("enter_nether") { distance { horizontal(100f) } startPosition { position { x = rangeOrInt(0..100) z = rangeOrInt(0..100) } } } ``` --- ### `placedBlock` **Description:** Triggers when a block is placed. **Properties:** - `location`: The location where the block was placed. **Example:** ```kotlin placedBlock("place_block") { conditions { location { biomes(Biomes.PLAINS) } } } ``` --- ### `playerGeneratesContainerLoot` **Description:** Triggers when container loot is generated. **Properties:** - `lootTable`: The loot table used to generate the container loot. **Example:** ```kotlin playerGeneratesContainerLoot("find_treasure", LootTables.Chests.BURIED_TREASURE) ``` --- ### `playerHurtEntity` **Description:** Triggers when a player hurts an entity. **Properties:** - `damage`: Details about the damage inflicted. - `entity`: The entity that was hurt. **Example:** ```kotlin playerHurtEntity("hurt_mob") { damage { taken = rangeOrDouble(5.0..10.0) } } ``` --- ### `playerInteractedWithEntity` **Description:** Triggers when a player interacts with an entity. **Properties:** - `item`: The item used during the interaction. - `entity`: The entity that was interacted with. **Example:** ```kotlin playerInteractedWithEntity("interact_with_golem") { item { items = listOf(Items.IRON_INGOT) } entity { conditionEntity { type(EntityTypes.IRON_GOLEM) } } } ``` --- ### `playerKilledEntity` **Description:** Triggers when a player kills an entity. **Properties:** - `entity`: The entity that was killed. - `killingBlow`: Details about the killing blow. **Example:** ```kotlin playerKilledEntity("kill_mob") { entity { conditions { entityProperties { type(EntityTypes.ZOMBIE) } } } } ``` --- ### `playerShearedEquipment` **Description:** Triggers after a player shears equipment off of a mob, such as wolf armor. **Properties:** - `entity`: The entity whose equipment was sheared. - `item`: The item of equipment that was sheared off. **Example:** ```kotlin playerShearedEquipment("shear_wolf_armor") { entity { type(EntityTypes.WOLF) } item { item(Items.LEATHER) } } ``` ### `recipeCrafted` **Description:** Triggers when a recipe is crafted. **Properties:** - `recipeId`: The ID of the crafted recipe. - `ingredients`: The ingredients used in the recipe. **Example:** ```kotlin recipeCrafted("craft_diamond") { recipeId = Recipes.DIAMOND ingredient(Items.DIAMOND) { components { damage(0) } } } ``` --- ### `recipeUnlocked` **Description:** Triggers when a recipe is unlocked. **Properties:** - `recipe`: The recipe that was unlocked. **Example:** ```kotlin recipeUnlocked("unlock_recipe", Recipes.DIAMOND) ``` --- ### `rideEntityInLava` **Description:** Triggers when riding an entity in lava. **Properties:** - `distance`: The distance traveled while riding in lava. - `startPosition`: The starting position before riding. **Example:** ```kotlin rideEntityInLava("lava_ride") { distance { horizontal(10f) } startPosition { position { y = rangeOrInt(100..200) } } } ``` --- ### `shotCrossbow` **Description:** Triggers when shooting a crossbow. **Properties:** - `item`: The crossbow item that was shot. **Example:** ```kotlin shotCrossbow("shoot_crossbow") { item { item(Items.CROSSBOW) enchantments { enchantment(Enchantments.MULTISHOT, 1) } } } ``` --- ### `sleptInBed` **Description:** Triggers when a player sleeps in a bed. **Properties:** _None._ **Example:** ```kotlin sleptInBed("sleep_in_bed") ``` --- ### `slideDownBlock` **Description:** Triggers when sliding down a block. **Properties:** - `block`: The block being slid down. **Example:** ```kotlin slideDownBlock("slide_down") { block { blocks(Blocks.SNOW_BLOCK) } } ``` --- ### `spearMobs` **Description:** Triggers when a player spears mobs. **Properties:** - `count`: The number of mobs speared. **Example:** ```kotlin spearMobs("spear_mobs") { count = 3 } ``` --- ### `startedRiding` **Description:** Triggers when a player starts riding an entity. **Properties:** _None._ **Example:** ```kotlin startedRiding("ride_horse") { conditions { vehicle { type(EntityTypes.HORSE) } } } ``` --- ### `summonedEntity` **Description:** Triggers when an entity is summoned. **Properties:** - `entity`: The entity that was summoned. **Example:** ```kotlin summonedEntity("summon_iron_golem") { entity { type(EntityTypes.IRON_GOLEM) } } ``` --- ### `tameAnimal` **Description:** Triggers when an animal is tamed. **Properties:** - `entity`: The animal that was tamed. **Example:** ```kotlin tameAnimal("tame_wolf") { entity { type(EntityTypes.WOLF) } } ``` --- ### `targetHit` **Description:** Triggers when a target block is hit. **Properties:** - `signalStrength`: The strength of the signal when the target is hit. - `projectile`: The projectile used to hit the target. **Example:** ```kotlin targetHit("hit_target") { signalStrength = rangeOrInt(1..15) projectile { conditions { entityProperties { type(EntityTypes.ARROW) } } } } ``` --- ### `thrownItemPickedUpByEntity` **Description:** Triggers when a thrown item is picked up by an entity. **Properties:** - `entity`: The entity that picked up the item. - `item`: The item that was picked up. **Example:** ```kotlin thrownItemPickedUpByEntity("feed_animal") { entity { type(EntityTypes.COW) } item { item(Items.WHEAT) } } ``` --- ### `thrownItemPickedUpByPlayer` **Description:** Triggers when a thrown item is picked up by a player. **Properties:** - `entity`: The entity that picked up the item. - `item`: The item that was picked up. **Example:** ```kotlin thrownItemPickedUpByPlayer("catch_trident") { item { item(Items.TRIDENT) } } ``` --- ### `tick` **Description:** Triggers every tick (20 times per second). **Properties:** - `conditions`: Conditions that must be met for the trigger to activate. **Example:** ```kotlin tick("game_tick") { conditions { timeCheck(6000..18000) // Daytime only } } ``` --- ### `usedEnderEye` **Description:** Triggers when an ender eye is used. **Properties:** - `distance`: The distance traveled using the ender eye. **Example:** ```kotlin usedEnderEye("find_stronghold") { distance { horizontal(100f) } } ``` --- ### `usedTotem` **Description:** Triggers when a totem is used. **Properties:** - `item`: The totem item that was used. **Example:** ```kotlin usedTotem("save_life") { item { item(Items.TOTEM_OF_UNDYING) } } ``` --- ### `usingItem` **Description:** Triggers while using an item. **Properties:** - `item`: The item being used. **Example:** ```kotlin usingItem("shield_block") { item { items = listOf(Items.SHIELD) } } ``` --- ### `villagerTrade` **Description:** Triggers when a villager trades. **Properties:** - `item`: The item involved in the trade. - `villager`: The villager involved in the trade. **Example:** ```kotlin villagerTrade("trade") { item { item(Items.EMERALD) } villager { conditions { entityProperties { team = "villager" } } } } ``` --- ### `voluntaryExile` **Description:** Triggers when a player causes a raid in a village. **Properties:** - `location`: The location where the raid occurred. **Example:** ```kotlin voluntaryExile("raid_village") { conditions { location { dimension = Dimensions.OVERWORLD } } } ``` --- Each trigger example demonstrates the basic usage with common properties and conditions. You can customize these triggers by adding more conditions and requirements to suit your specific advancement needs. --- ## Dialogs --- root: .components.layouts.MarkdownLayout title: Dialogs nav-title: Dialogs description: Create interactive dialog screens in Minecraft with Kore's comprehensive dialog system. keywords: minecraft, datapack, kore, dialogs, ui, interactive, forms, confirmation, notice date-created: 2025-09-18 date-modified: 2025-09-18 routeOverride: /docs/data-driven/dialogs --- # Dialogs Minecraft includes a powerful dialog system that allows creating interactive modal windows for displaying information and receiving player input. Dialogs are native Minecraft features introduced in Java Edition 1.21.6 that enable sophisticated user interfaces within the game. With **Kore**, you can easily create and manage these dialogs using a comprehensive Kotlin DSL that maps directly to Minecraft's dialog format. Minecraft's dialog system supports various interaction types including: - Displaying rich text with formatting and clickable elements - Receiving player input through text fields, toggles, sliders, and option selections - Executing commands via action buttons (with appropriate permissions) - Navigating between multiple dialogs using nested structures - Integration with the pause menu and quick actions hotkey For the vanilla reference, see the [Minecraft Wiki - Dialog](https://minecraft.wiki/w/Dialog) and [Commands/dialog](https://minecraft.wiki/w/Commands/dialog). ## Minecraft Dialog System Overview Minecraft dialogs consist of three main elements: - **Header**: Contains the title and warning button - **Body elements**: Labels, inputs, buttons, and submit actions (scrollable if needed) - **Optional footer**: Confirmation buttons and submit actions When a dialog opens, player controls are temporarily disabled until the user exits through an action button, the Escape key, or the warning button. In single-player mode, dialogs can be configured to pause the game and trigger an autosave. ## Set Up Your Data Pack Function Begin by creating a function within your `DataPack` where you'll define your dialogs: ```kotlin fun DataPack.createDialogs() { // Your dialog definitions will go here } ``` ## Initialize the Dialogs Block Use the `dialogBuilder` to start defining your dialogs: ```kotlin val myDialog = dialogBuilder.confirmation("welcome", "Welcome!") { // Define dialog properties here } ``` Or use the `dialogs` DSL: ```kotlin dialogs { confirmation("my-dialog", "Title!") { // Define dialog properties here } } ``` ## Dialog Types Minecraft currently supports five different dialog types: ### Confirmation Dialog A dialog with two action buttons (yes/no) for binary choices: ```kotlin val confirmDialog = dialogBuilder.confirmation("delete_world", "Delete World?") { afterAction = AfterAction.WAIT_FOR_RESPONSE externalTitle("Delete", Color.RED) pause = true bodies { plainMessage("Are you sure you want to delete this world? This action cannot be undone.") } yes("Delete") { action { runCommand { say("World deleted!") } } } no("Cancel") { action { suggestChatMessage("Cancelled deletion") } } } ``` ### Notice Dialog A simple dialog with a single action button for displaying information: ```kotlin val noticeDialog = dialogBuilder.notice("achievement", "Achievement Unlocked!") { bodies { item(Items.DIAMOND_SWORD) { description = ItemDescription(textComponent("Your first diamond tool!")) showTooltip = true } plainMessage("You've crafted your first diamond sword!") } action("Awesome!") { tooltip("Click to continue") action { dynamicCustom("celebrate") { this["achievement"] = "first_diamond_tool" } } } } ``` ### Multi Action Dialog A dialog with multiple action buttons arranged in columns, perfect for menus: ```kotlin val menuDialog = dialogBuilder.multiAction("main_menu", "Server Menu") { columns = 3 inputs { text("player_name", "Your Name") { maxLength = 16 initial = "Steve" } numberRange("difficulty", "Difficulty", range = 1..10, initial = 5) { step = 1f } boolean("pvp_enabled", "Enable PVP") { initial = false onTrue = "PVP On" onFalse = "PVP Off" } } actions { action("Start Game") { action { runCommand { say("Game starting with settings!") } } } action("Settings") { action { openUrl("https://example.com/settings") } } action("Quit") { action { dynamicRunCommand { kick(allPlayers(), textComponent("Thanks for playing!")) } } } } } ``` ### Dialog List A dialog that displays a scrollable list of other dialogs: ```kotlin val listDialog = dialogBuilder.dialogList("dialog_menu", "Available Dialogs") { columns = 2 buttonWidth = 200 dialogs(confirmDialog, noticeDialog, menuDialog) // or use a tag: // dialogs(Tags.Dialog.PAUSE_SCREEN_ADDITIONS) exitAction("Back to Game") { action { dynamicRunCommand { say("Returning to game...") } } } } ``` ### Server Links Dialog A specialized dialog for displaying server links (configured server-side): ```kotlin val linksDialog = dialogBuilder.serverLinks("server_links", "Server Links") { buttonWidth = 150 columns = 3 exitAction("Close") { action { dynamicRunCommand { say("Links closed") } } } } ``` ## Dialog Properties All dialogs share common properties that can be customized: ### Basic Properties ```kotlin dialogBuilder.confirmation("example", "Title") { // External title shown on buttons leading to this dialog externalTitle("Custom Button Text", Color.AQUA) // Action performed after dialog interactions afterAction = AfterAction.WAIT_FOR_RESPONSE // or CLOSE // Whether dialog can be dismissed with Escape key canCloseWithEscape = true // Whether to pause the game in single-player pause = true } ``` ### After Actions Control what happens after dialog interactions: - `AfterAction.NONE` - Do nothing - `AfterAction.CLOSE` - Close the dialog (default) - `AfterAction.WAIT_FOR_RESPONSE` - Keep dialog open awaiting response ## Body Elements Dialogs can contain rich content between the title and action buttons: ### Plain Messages Display text content: ```kotlin bodies { plainMessage("Welcome to our server!") { width = 300 } plainMessage(textComponent("Colored text", Color.GREEN)) } ``` ### Items Display items with descriptions: ```kotlin bodies { item(Items.ENCHANTED_BOOK) { description = ItemDescription(textComponent("A mysterious tome")) showTooltip = true showDecorations = false height = 64 width = 64 } } ``` ## Input Controls Multi-action dialogs can include various input controls for user interaction: ### Text Input Single-line or multi-line text input: ```kotlin inputs { text("username", "Username") { maxLength = 20 initial = "Player" width = 200 labelVisible = true } text("bio", "Biography") { multiline(maxLines = 5, height = 100) maxLength = 500 } } ``` ### Number Range Slider controls for numeric input: ```kotlin inputs { numberRange("volume", "Volume", range = 0..100, initial = 50) { step = 5f labelFormat = "Volume: %d%%" width = 250 } // Float ranges also supported numberRange("speed", "Speed", range = 0.1f..2.0f, initial = 1.0f) { step = 0.1f } } ``` ### Boolean Toggle Checkbox-style boolean input: ```kotlin inputs { boolean("notifications", "Enable Notifications") { initial = true onTrue = "✓ Enabled" onFalse = "✗ Disabled" } } ``` ### Single Option Dropdown-style selection: ```kotlin inputs { singleOption("gamemode", "Game Mode") { width = 200 labelVisible = true option("survival", "Survival", initial = true) option("creative", "Creative") option("adventure", "Adventure") option("spectator", "Spectator") } } ``` ## Actions Dialog actions define what happens when buttons are clicked: ### Available Action Types ```kotlin action { // Run a command runCommand { say("Hello world!") } // Suggest a chat message suggestChatMessage("/gamemode creative") // Open a URL openUrl("https://minecraft.net") // Copy text to clipboard copyToClipboard("Server IP: mc.example.com") // Change page in a book changePage(5) // Dynamic commands with macros named after the inputs dynamicRunCommand { say("Player name is ${macro('username')}") } // Custom dynamic actions, for sending custom packets for server plugins/mods dynamicCustom("custom_action") { this["data"] = "value" this["count"] = 42 } } ``` ### Action Properties Enhance actions with labels, tooltips, and sizing: ```kotlin action("My Button") { tooltip("Click me for awesome results!") width = 150 action { runCommand { say("Button clicked!") } } } ``` ## Using Dialogs in Commands Commands can show and clear dialogs to players, using a reference or an inline dialog: ```kotlin load { // Show dialog to specific players dialogShow(allPlayers(), myDialog) // Create and show dialog inline dialogShow(allPlayers()) { confirmation("inline_dialog", "Quick Confirmation") { yes("Yes") { action { runCommand { say("Yes selected") } } } no("No") { action { runCommand { say("No selected") } } } } } // Clear dialogs dialogClear(allPlayers()) } ``` ## Advanced Examples ### Complex Form Dialog ```kotlin val registrationForm = dialogBuilder.multiAction("register", "Player Registration") { columns = 1 bodies { plainMessage("Welcome! Please fill out your information:") } inputs { text("display_name", "Display Name") { maxLength = 32 labelVisible = true } text("email", "Email Address") { maxLength = 100 } numberRange("age", "Age", range = 13..99, initial = 18) { step = 1f } singleOption("region", "Region") { option("na", "North America") option("eu", "Europe") option("as", "Asia") option("other", "Other") } boolean("newsletter", "Subscribe to Newsletter") { initial = false } text("comments", "Additional Comments") { multiline(maxLines = 3, height = 80) maxLength = 200 } } actions { action("Register") { action { dynamicRunCommand { say("Registration submitted!") give(allPlayers(), Items.WRITTEN_BOOK) } } } action("Cancel") { action { suggestChatMessage("Registration cancelled") } } } } ``` ### Interactive Tutorial System ```kotlin val tutorialDialog = dialogBuilder.dialogList("tutorials", "Tutorial Menu") { columns = 2 buttonWidth = 180 bodies { plainMessage("Choose a tutorial to begin:") item(Items.BOOK) { description = ItemDescription(textComponent("Learn the basics")) } } // Reference other tutorial dialogs dialogs( basicTutorial, advancedTutorial, pvpTutorial ) exitAction("Skip Tutorials") { action { runCommand { advancement.grant(allPlayers(), AdvancementArgument("tutorial:skipped")) } } } } ``` ## Best Practices 1. **Keep dialogs focused**: Each dialog should serve a single, clear purpose 2. **Use appropriate dialog types**: - Confirmation for yes/no decisions - Notice for information display - Multi-action for complex forms or menus 3. **Provide clear labels**: Make button and input labels descriptive 4. **Include tooltips**: Add helpful tooltips for complex actions 5. **Handle edge cases**: Provide cancel/exit options where appropriate ## Integration with Other Systems Dialogs work seamlessly with other Kore features: ```kotlin val conditionalDialog = dialogBuilder.confirmation("weather_change", "Change Weather?") { // Only show if it's currently raining yes("Make Sunny") { action { runCommand { weatherClear() } } } no("Keep Current") { action { suggestChatMessage("Weather unchanged") } } } val firstDeathScoreboard = "first_death" advancement("first_death") { criteria { tick("check_each_ticks") { conditions { entityProperties { nbt { this["Health"] = 0f } } } } } display(Items.AIR) { announceToChat = false hidden = true } rewards { function { scoreboard.objective(self(), firstDeathScoreboard).set(1) execute { ifCondition { score(self(), firstDeathScoreboard) equalTo 1 } run { dialogShow(self(), conditionalDialog) scoreboard.objective(self(), firstDeathScoreboard).set(2) // Prevent re-triggering } } } } } // Integration with advancements load { // Define the objective scoreboard.objective(firstDeathScoreboard).create(ScoreboardCriteria.DUMMY) } ``` ## See also - [Advancements](/docs/data-driven/advancements) - Create custom conditions and rewards for dialogs - [Components](/docs/concepts/components) - Learn about the component system used in Kore - [Predicates](/docs/data-driven/predicates) - Create custom conditions for dialogs --- ## Enchantments --- root: .components.layouts.MarkdownLayout title: Enchantments nav-title: Enchantments description: Create custom Minecraft enchantments using Kore's type-safe Kotlin DSL with support for all vanilla effect components and level-based values. keywords: minecraft, datapack, kore, enchantments, effects, custom enchantments date-created: 2025-03-02 date-modified: 2026-02-03 routeOverride: /docs/data-driven/enchantments --- # Enchantments Enchantments are data-driven definitions that modify item behavior, apply effects, change damage calculations, and alter various game mechanics. In Minecraft Java Edition 1.21+, enchantments are fully customizable through data packs, allowing you to create entirely new enchantments with unique effects. ## Overview Custom enchantments have several key characteristics: - **Data-driven**: Defined as JSON files in data packs, not hardcoded - **Effect components**: Modular system of 30+ effect types - **Level-based scaling**: Values can scale with enchantment level - **Slot-aware**: Effects apply based on equipment slot configuration - **Conditional**: Effects can have predicate requirements ### Enchantment Properties Every enchantment defines these core properties: | Property | Description | |-------------------------|-----------------------------------------------------| | `description` | Text component displayed on items | | `supported_items` | Items that can receive the enchantment | | `primary_items` | Items where enchantment appears in enchanting table | | `exclusive_set` | Incompatible enchantments | | `weight` | Probability weight (1-1024) | | `max_level` | Maximum level (1-255) | | `min_cost` / `max_cost` | Enchanting table level requirements | | `anvil_cost` | Base cost for anvil application | | `slots` | Equipment slots where effects apply | | `effects` | Effect components that define behavior | ## File Structure Enchantments are stored as JSON files in data packs at: ``` data//enchantment/.json ``` For complete JSON specification, see the [Minecraft Wiki - Enchantment definition](https://minecraft.wiki/w/Enchantment_definition). ## Creating Enchantments Use the `enchantment` builder function to create enchantments in Kore: ```kotlin dataPack("my_datapack") { enchantment("fire_aspect_plus") { description("Fire Aspect+") supportedItems(Items.DIAMOND_SWORD, Items.NETHERITE_SWORD) primaryItems(Tags.Item.SWORDS) exclusiveSet(Enchantments.FIRE_ASPECT) weight = 2 maxLevel = 3 minCost(15, 10) // base 15, +10 per level maxCost(65, 10) anvilCost = 4 slots(EquipmentSlot.MAINHAND) effects { // Define effects here } } } ``` This generates `data/my_datapack/enchantment/fire_aspect_plus.json`. ## Basic Properties ### Description The text shown on enchanted items: ```kotlin enchantment("test") { // Simple string description("Test Enchantment") // Or with text component for formatting description(textComponent("Test") { color = Color.GOLD }) } ``` ### Supported and Primary Items ```kotlin enchantment("bow_enchant") { // Items that can have this enchantment (anvil/commands) supportedItems(Items.BOW, Items.CROSSBOW) // Items where it appears in enchanting table (subset of supported) primaryItems(Tags.Item.BOW_ENCHANTABLE) } ``` ### Exclusive Set Enchantments that cannot coexist: ```kotlin enchantment("protection_variant") { exclusiveSet(Tags.Enchantment.ARMOR_EXCLUSIVE) // Or individual enchantments exclusiveSet(Enchantments.PROTECTION, Enchantments.FIRE_PROTECTION) } ``` ### Cost and Weight ```kotlin enchantment("rare_enchant") { weight = 1 // Very rare (compare to Mending: 2, Unbreaking: 5) maxLevel = 5 // Level cost formula: base + (level - 1) * per_level_above_first minCost(base = 1, perLevelAboveFirst = 11) // 1, 12, 23, 34, 45 maxCost(base = 21, perLevelAboveFirst = 11) // 21, 32, 43, 54, 65 anvilCost = 8 // Expensive to combine } ``` ### Equipment Slots Where the enchantment's effects apply: ```kotlin enchantment("armor_enchant") { slots(EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET) } enchantment("weapon_enchant") { slots(EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND) } ``` Available slots: `ANY`, `HAND`, `MAINHAND`, `OFFHAND`, `ARMOR`, `FEET`, `LEGS`, `CHEST`, `HEAD`, `BODY`, `SADDLE`. ## Effect Components Effects define what the enchantment actually does. Kore supports all vanilla effect components. ### Value Effect Components These components modify numeric values with level-based scaling: | Component | Description | |-----------------------------|------------------------------------| | `ammoUse` | Ammunition consumption | | `armorEffectiveness` | Armor effectiveness multiplier | | `blockExperience` | XP from breaking blocks | | `crossbowChargeTime` | Crossbow charge time | | `damage` | Bonus attack damage | | `damageProtection` | Damage reduction (max 80% total) | | `equipmentDrops` | Equipment drop chance | | `fishingLuckBonus` | Fishing luck bonus | | `fishingTimeReduction` | Fishing speed bonus | | `itemDamage` | Durability loss multiplier | | `knockback` | Knockback strength | | `mobExperience` | XP from killing mobs | | `projectileCount` | Projectiles fired | | `projectilePiercing` | Targets pierced | | `projectileSpread` | Accuracy spread in degrees | | `repairWithXp` | Durability repaired per XP | | `smashDamagePerFallenBlock` | Mace bonus damage per block fallen | | `tridentReturnAcceleration` | Trident return speed | | `tridentSpinAttackStrength` | Riptide attack strength | ```kotlin effects { // Simple damage bonus damage { add(linearLevelBased(2, 0.5)) // +2 base, +0.5 per level } // Protection with conditions damageProtection { add(constantLevelBased(4)) { requirements { damageType(DamageTypes.IN_FIRE) } } } // Multiple value modifications armorEffectiveness { add(5) multiply(1.5) set(10) removeBinomial(0.5) // 50% chance to remove 1 allOf { add(2) multiply(1.2) } } } ``` ### Entity Effect Components These components trigger actions on entities: | Component | Description | |----------------------|-----------------------------------------------| | `hitBlock` | After hitting a block with the enchanted item | | `postAttack` | After damaging an entity | | `postPiercingAttack` | After a piercing attack with an item | | `projectileSpawned` | When a projectile is created | | `tick` | Every game tick while equipped | ```kotlin effects { // Apply effects when hitting blocks hitBlock { applyMobEffect(Effects.SPEED) { minDuration(5) maxDuration(10) minAmplifier(0) maxAmplifier(2) } } // Periodic effects tick { damageEntity(DamageTypes.MAGIC, 0.5, 1.0) } // Post-attack effects (like Thorns) postAttack { damageEntity( PostAttackSpecifier.ATTACKER, PostAttackSpecifier.VICTIM, DamageTypes.THORNS, 1, 3 ) } } ``` ### Special Effect Components | Component | Description | |--------------------------|--------------------------------------| | `attributes` | Applies attribute modifiers | | `crossbowChargingSounds` | Custom crossbow sounds | | `damageImmunity` | Grants immunity to damage types | | `preventArmorChange` | Prevents removing from armor slot | | `preventEquipmentDrop` | Prevents item from dropping on death | | `tridentSound` | Custom trident sounds | ```kotlin effects { // Damage immunity (like totems) damageImmunity { sound { requirements { damageType(DamageTypes.FALLING_BLOCK) } } } // Curse-like effects preventEquipmentDrop() preventArmorChange() // Attribute modifiers attributes { attribute( "bonus_speed", name, Attributes.MOVEMENT_SPEED, AttributeModifierOperation.ADD_MULTIPLIED_BASE, 0.1 // +10% speed ) } // Custom sounds crossbowChargingSounds { crossbowChargingSound { start(SoundEvents.Item.Crossbow.QUICK_CHARGE_1) mid(SoundEvents.Item.Crossbow.QUICK_CHARGE_2) end(SoundEvents.Item.Crossbow.QUICK_CHARGE_3) } } } ``` ## Entity Effects Entity effects are actions that can be triggered by effect components: ### Apply Exhaustion ```kotlin applyExhaustion(amount = 5) ``` ### Apply Impulse ```kotlin applyImpulse( direction = Vec3f(0f, 1f, 0f), // local coordinates applied to entity look vector coordinateScale = Vec3f(1f, 1f, 1f), // world-space scaling per axis magnitude = constantLevelBased(2) // final scaling ) ``` ### Apply Mob Effect ```kotlin applyMobEffect(Effects.SLOWNESS, Effects.WEAKNESS) { minDuration(5) maxDuration(linearLevelBased(5, 5)) minAmplifier(0) maxAmplifier(constantLevelBased(1)) } ``` ### Damage Entity ```kotlin damageEntity(DamageTypes.MAGIC, minDamage = 1, maxDamage = 5) ``` ### Explode ```kotlin explode( attributeToUser = true, createFire = false, blockInteraction = BlockInteraction.TNT, smallParticle = Particles.EXPLOSION, largeParticle = Particles.EXPLOSION_EMITTER, sound = Sounds.Entity.Generic.EXPLODE ) { radius(linearLevelBased(2, 1)) } ``` ### Ignite ```kotlin ignite(duration = linearLevelBased(4, 4)) // seconds ``` ### Play Sound ```kotlin playSound(SoundEvents.Entity.Firework.LAUNCH, volume = 1f) ``` ### Replace Block/Disk ```kotlin replaceBlock(simpleStateProvider(Blocks.FIRE)) { offset(0, 1, 0) triggerGameEvent = GameEvents.BLOCK_PLACE } replaceDisk(simpleStateProvider(Blocks.ICE)) { radius(linearLevelBased(2, 1)) height(1) } ``` ### Spawn Particles ```kotlin spawnParticles( Particles.FLAME, horizontalPositionType = ParticlePositionType.IN_BOUNDING_BOX, verticalPositionType = ParticlePositionType.IN_BOUNDING_BOX ) { horizontalVelocity(base = 0.1f, movementScale = 0f) verticalVelocity(base = 0.5f, movementScale = 0f) speed(0.5f) } ``` ### Run Function ```kotlin runFunction(FunctionArgument("on_hit", "my_datapack")) ``` ### Summon Entity ```kotlin summonEntity(EntityTypes.LIGHTNING_BOLT) ``` ### Change Item Damage ```kotlin changeItemDamage(linearLevelBased(1, 1)) // Durability consumed ``` ## Level-Based Values Level-based values allow effects to scale with enchantment level: | Type | Description | Example | |--------------------------------------|-------------------|---------------------------------------------| | `clampedLevelBased(value, min, max)` | Clamped range | `clampedLevelBased(linear, 1.0, 10.0)` | | `constantLevelBased(value)` | Fixed value | `constantLevelBased(5)` | | `exponentLevelBased(base, power)` | Exponential | `exponentLevelBased(1, 5)` → 1, 5, 25... | | `fractionLevelBased(num, denom)` | Fractional | `fractionLevelBased(1, 2)` → 0.5, 1, 1.5... | | `levelsSquaredLevelBased(base)` | Quadratic scaling | `levelsSquaredLevelBased(1)` → 1, 4, 9... | | `linearLevelBased(base, perLevel)` | Linear scaling | `linearLevelBased(2, 0.5)` → 2, 2.5, 3... | | `lookupLevelBased(list, fallback)` | Lookup table | `lookupLevelBased(listOf(1, 3, 7), 10)` | ```kotlin effects { damage { // Linear: 2 + 0.5 per level → 2, 2.5, 3, 3.5, 4 for levels 1-5 add(linearLevelBased(2, 0.5)) } blockExperience { // Complex combination allOf { add(clampedLevelBased(linearLevelBased(1, 2), 0.0, 10.0)) multiply(levelsSquaredLevelBased(0.1)) } } } ``` ## Requirements (Conditions) Effect components can have requirements that must be met: ```kotlin effects { damage { add(5) { requirements { // Only in rain weatherCheck(raining = true) } } } damageProtection { add(4) { requirements { // Only against fire damage damageType(DamageTypes.IN_FIRE, DamageTypes.ON_FIRE) } } } postAttack { applyMobEffect( PostAttackSpecifier.ATTACKER, PostAttackSpecifier.VICTIM, Effects.POISON ) { requirements { // Only against undead entityProperties { type(EntityTypes.ZOMBIE, EntityTypes.SKELETON) } } } } } ``` ## Full Example ```kotlin dataPack("custom_enchants") { enchantment("vampiric") { description(textComponent("Vampiric") { color = Color.DARK_RED }) supportedItems(Tags.Item.SWORDS) primaryItems(Tags.Item.SWORD_ENCHANTABLE) exclusiveSet(Enchantments.MENDING) weight = 2 maxLevel = 3 minCost(20, 15) maxCost(50, 15) anvilCost = 8 slots(EquipmentSlot.MAINHAND) effects { // Lifesteal on hit postAttack { applyMobEffect( PostAttackSpecifier.ATTACKER, PostAttackSpecifier.ATTACKER, Effects.INSTANT_HEALTH ) { minAmplifier(0) maxAmplifier(0) minDuration(1) maxDuration(1) requirements { randomChance(linearLevelBased(0.1, 0.1)) // 10/20/30% chance } } } // Bonus damage to undead damage { add(linearLevelBased(2, 1)) { requirements { entityProperties { type(Tags.EntityType.UNDEAD) } } } } // Visual feedback hitBlock { spawnParticles( Particles.CRIMSON_SPORE, horizontalPositionType = ParticlePositionType.ENTITY_POSITION, verticalPositionType = ParticlePositionType.ENTITY_POSITION ) { speed(0.2f) } } } } } ``` ### Generated JSON ```json { "description": { "text": "Vampiric", "color": "dark_red" }, "supported_items": "#minecraft:swords", "primary_items": "#minecraft:sword_enchantable", "exclusive_set": "minecraft:mending", "weight": 2, "max_level": 3, "min_cost": { "base": 20, "per_level_above_first": 15 }, "max_cost": { "base": 50, "per_level_above_first": 15 }, "anvil_cost": 8, "slots": [ "mainhand" ], "effects": { "minecraft:post_attack": [ { "enchanted": "attacker", "affected": "attacker", "effect": { "type": "minecraft:apply_mob_effect", "to_apply": "minecraft:instant_health", "min_amplifier": 0, "max_amplifier": 0, "min_duration": 1, "max_duration": 1 }, "requirements": { "condition": "minecraft:random_chance", "chance": { "type": "minecraft:linear", "base": 0.1, "per_level_above_first": 0.1 } } } ], "minecraft:damage": [ { "effect": { "type": "minecraft:add", "value": { "type": "minecraft:linear", "base": 2, "per_level_above_first": 1 } }, "requirements": { "condition": "minecraft:entity_properties", "predicate": { "type": "#minecraft:undead" } } } ] } } ``` ## Enchantment Providers Enchantment providers are used by enchanting tables and loot functions to select enchantments, so they often appear next to [Loot Tables](/docs/data-driven/loot-tables) and runtime [Item Modifiers](/docs/data-driven/item-modifiers): ```kotlin enchantmentProvider("custom_table") { single { enchantment = Enchantments.SHARPNESS } } enchantmentProvider("cost_based") { byCost { // Configuration for cost-based selection } } ``` ## Best Practices 1. **Balance carefully** - Test enchantment power at all levels; use appropriate weights 2. **Use exclusive sets** - Prevent overpowered combinations with incompatible enchantments 3. **Scale appropriately** - Use level-based values that provide meaningful progression 4. **Add requirements** - Use conditions to create situational bonuses 5. **Consider slots** - Ensure effects only apply in appropriate equipment slots 6. **Test thoroughly** - Verify effects work correctly in all contexts (PvP, PvE, etc.) ## See Also - [Predicates](/docs/data-driven/predicates) - Conditions for enchantment effect requirements - [Components](/docs/concepts/components) - Item components and matchers - [Tags](/docs/data-driven/tags) - Use enchantment and item tags - [Villager Trades](/docs/data-driven/villager-trades) - `doubleTradePriceEnchantments` and enchanting villager trade outputs ### External Resources - [Minecraft Wiki: Enchantment definition](https://minecraft.wiki/w/Enchantment_definition) - Official JSON format reference - [Minecraft Wiki: Enchanting](https://minecraft.wiki/w/Enchanting) - Enchanting mechanics overview --- ## Item Modifiers --- root: .components.layouts.MarkdownLayout title: Item Modifiers nav-title: Item Modifiers description: Transform item stacks using Kore's type-safe DSL for loot functions - set counts, add enchantments, copy data, and more. keywords: minecraft, datapack, kore, item modifiers, loot functions, /item modify, components date-created: 2025-08-11 date-modified: 2026-06-16 routeOverride: /docs/data-driven/item-modifiers --- # Item Modifiers Item modifiers (also called loot functions) transform item stacks by adjusting counts, adding enchantments, copying data, setting components, and more. They can be defined as standalone JSON files referenced by commands, or used inline within loot tables. ## Overview Item modifiers have several key characteristics: - **Composable**: Chain multiple functions together for complex transformations - **Conditional**: Each function can have predicate conditions - **Context-aware**: Access loot context for killer, tool, block entity, etc. - **Reusable**: Define once as a file, reference anywhere ### Common Use Cases | Use Case | Functions | |----------------------|-----------------------------------------------------------| | Set stack count | `setCount` | | Add enchantments | `enchantRandomly`, `enchantWithLevels`, `setEnchantments` | | Modify durability | `setDamage` | | Copy NBT/components | `copyComponents`, `copyCustomData`, `copyName` | | Set name/lore | `setName`, `setLore` | | Create explorer maps | `explorationMap` | | Fill containers | `setContents`, `setLootTable` | | Apply formulas | `applyBonus`, `enchantedCountIncrease` | ## File Structure Item modifiers are stored as JSON files in data packs at: ``` data//item_modifier/.json ``` For complete JSON specification, see the [Minecraft Wiki - Item modifier](https://minecraft.wiki/w/Item_modifier). ## Creating Item Modifiers Use the `itemModifier` builder function to create item modifiers in Kore: ```kotlin dataPack("my_datapack") { val modifier = itemModifier("fortune_bonus") { enchantRandomly { options += Enchantments.FORTUNE } setCount(uniform(1f, 5f)) } } ``` This generates `data/my_datapack/item_modifier/fortune_bonus.json`. ## Using Item Modifiers ### With Commands Apply modifiers to items using the `/item modify` command: ```kotlin load { items { // Modify item in player's mainhand modify(self(), WEAPON.MAINHAND, modifier) // Modify item in container modify(block(0, 64, 0), slot(0), modifier) } } ``` ### In Loot Tables Use functions directly in loot tables at table, pool, or entry level: ```kotlin lootTable("treasure") { // Table-level functions (applied to all drops) functions { enchantRandomly() } pool { // Pool-level functions functions { setCount(uniform(1f, 3f)) } entries { item(Items.DIAMOND) { // Entry-level functions functions { setName("Lucky Diamond") } } } } } ``` ## Function Reference ### Count and Damage #### setCount Sets or modifies the stack count: ```kotlin itemModifier("set_count") { // Exact count setCount(5f) // Random range setCount(uniform(1f, 10f)) // Add to current count setCount(5f, add = true) // With condition setCount(10f) { conditions { killedByPlayer() } } } ``` #### setDamage Sets item durability (1.0 = full, 0.0 = broken): ```kotlin itemModifier("damage") { // Set to 80% durability setDamage(0.8f) // Random damage setDamage(uniform(0.5f, 1.0f)) // Add to current damage setDamage(-0.1f, add = true) // Repair 10% } ``` #### limitCount Clamps stack count to a range: ```kotlin itemModifier("limit") { // Exact limit limitCount(64) // Range limitCount(providersRange(min = constant(1f), max = constant(32f))) } ``` ### Enchantments #### enchantRandomly Adds a random enchantment: ```kotlin itemModifier("random_enchant") { // Any enchantment enchantRandomly() // From specific list enchantRandomly { options += Enchantments.SHARPNESS options += Enchantments.SMITE options += Enchantments.BANE_OF_ARTHROPODS } // Only compatible enchantments enchantRandomly(onlyCompatible = true) // Include the additional cost component from trade costs enchantRandomly(Enchantments.SHARPNESS) { includeAdditionalCostComponent = true } } ``` #### enchantWithLevels Enchants as if using an enchanting table: ```kotlin itemModifier("table_enchant") { // Fixed level enchantWithLevels(levels = constant(30f)) // Random level range enchantWithLevels(levels = uniform(20f, 39f)) // Limit to specific enchantments enchantWithLevels(Enchantments.PROTECTION, levels = constant(30f)) // Include the additional cost component from trade costs enchantWithLevels(levels = constant(30f)) { includeAdditionalCostComponent = true } } ``` #### setEnchantments Sets specific enchantments and levels: ```kotlin itemModifier("specific_enchants") { setEnchantments { enchantment(Enchantments.SHARPNESS, 5) enchantment(Enchantments.UNBREAKING, 3) enchantment(Enchantments.MENDING, 1) } } ``` #### enchantedCountIncrease Increases count based on enchantment level (like Looting): ```kotlin itemModifier("looting_bonus") { enchantedCountIncrease(Enchantments.LOOTING, count = 1f, limit = 5) } ``` ### Names and Lore #### setName Sets the item's display name: ```kotlin itemModifier("named") { // Simple string setName("Legendary Sword") // Text component with formatting setName(textComponent("Legendary Sword") { color = Color.GOLD bold = true }) // Set item name vs custom name setName("Base Name") { target = SetNameTarget.ITEM_NAME // or CUSTOM_NAME } } ``` #### setLore Sets or modifies item lore: ```kotlin itemModifier("lore") { setLore { lore("First line", Color.GRAY) lore("Second line", Color.DARK_GRAY) // Insert at specific position mode(Mode.INSERT, offset = 0) } } ``` ### Components #### setComponents Directly set item components: ```kotlin itemModifier("components") { setComponents { customName(textComponent("Custom Item", Color.GOLD)) damage(10) unbreakable(showInTooltip = false) // Remove component with ! !food {} } } ``` #### copyComponents Copy components from a source: ```kotlin itemModifier("copy_from_block") { copyComponents { source = Source.BLOCK_ENTITY // Include specific components include(ItemComponentTypes.CUSTOM_NAME, ItemComponentTypes.LORE) // Or exclude specific components exclude(ItemComponentTypes.DAMAGE) } } ``` #### copyName Copy entity/block name to item: ```kotlin itemModifier("named_drop") { copyName(Source.BLOCK_ENTITY) // Or from entity copyName(Source.THIS) copyName(Source.KILLER) } ``` #### setCustomData Set custom NBT data on an item: ```kotlin itemModifier("custom_data") { setCustomData { this["test"] = 1 } } ``` #### setCustomModelData Set custom model data on an item: ```kotlin itemModifier("custom_model") { setCustomModelData( colors = listOf(Color.RED, Color.BLUE), flags = listOf(true, false), floats = listOf(1.0f, 2.0f), strings = listOf("test1", "test2") ) } ``` #### copyCustomData Copy NBT data to custom_data component: ```kotlin itemModifier("copy_nbt") { copyCustomData { source(Source.BLOCK_ENTITY) operations { operation("Items", "BlockItems", CopyOperation.REPLACE) operation("Lock", "OriginalLock", CopyOperation.MERGE) } } } ``` ### Container Contents #### setContents Fill container items (bundles, shulker boxes): ```kotlin itemModifier("filled_bundle") { setContents(ContentComponentTypes.BUNDLE_CONTENTS) { entries { item(Items.DIAMOND) { functions { setCount(16f) } } item(Items.EMERALD) { functions { setCount(32f) } } } } } ``` #### setLootTable Set a container's loot table: ```kotlin itemModifier("chest_loot") { setLootTable(BlockEntityTypes.CHEST, LootTables.Chests.SIMPLE_DUNGEON, seed = 42) } ``` #### modifyContents Apply modifiers to items inside a container: ```kotlin itemModifier("enchant_bundle_contents") { modifyContents(ContentComponentTypes.BUNDLE_CONTENTS) { modifiers { enchantRandomly() } } } ``` ### Maps and Exploration #### explorationMap Convert empty map to explorer map: ```kotlin itemModifier("treasure_map") { explorationMap { destination = Tags.Worldgen.Structure.BURIED_TREASURE decoration = MapDecorationTypes.RED_X zoom = 2 searchRadius = 50 skipExistingChunks = true } } ``` ### Special Items #### setInstrument Set a goat horn instrument using a tag, a single ID, or multiple IDs/tags: ```kotlin // tag itemModifier("horn_tag") { setInstrument(Tags.Instrument.GOAT_HORNS) } // single ID itemModifier("horn_id") { setInstrument(Instruments.ADMIRE_GOAT_HORN) } // list of IDs/tags itemModifier("horn_list") { setInstrument(Instruments.ADMIRE_GOAT_HORN, Instruments.SING_GOAT_HORN) } ``` #### setItem Change the item type: ```kotlin itemModifier("change_item") { setItem(Items.APPLE) } ``` #### setOminousBottleAmplifier Set the amplifier of an ominous bottle: ```kotlin itemModifier("ominous_bottle") { setOminousBottleAmplifier(5) } ``` #### setPotion Set potion type: ```kotlin itemModifier("potion") { setPotion(Potions.HEALING) } ``` #### setRandomPotion Set a random potion from a list of options (or tags): ```kotlin itemModifier("random_potion") { // Random from specific list setRandomPotion(Potions.HEALING, Potions.SWIFTNESS) } ``` #### setRandomDyes Set a random number of dyes on the item using a number provider: ```kotlin itemModifier("random_dyes") { // Fixed count setRandomDyes(3f) // Dynamic count setRandomDyes(uniform(1f, 5f)) } ``` #### setStewEffect Set suspicious stew effects: ```kotlin itemModifier("stew") { setStewEffect { potionEffect(Potions.NIGHT_VISION, constant(200f)) } } ``` #### setFireworkExplosion Set a single firework explosion: ```kotlin itemModifier("firework_explosion") { setFireworkExplosion(FireworkExplosionShape.STAR) { colors = listOf(Color.RED.toRGB()) fadeColors = listOf(Color.BLUE.toRGB()) hasFlicker = true hasTrail = true } } ``` #### setFireworks Configure firework rocket: ```kotlin itemModifier("firework") { setFireworks { flightDuration = 5 explosions { explosion(FireworkExplosionShape.BURST) { colors(Color.RED) fadeColors(Color.BLUE) hasTrail = true hasFlicker = true } mode(Mode.REPLACE_ALL) } } } ``` #### setBookCover Set written book cover: ```kotlin itemModifier("book") { setBookCover( title = "Adventure Log", author = "Player", generation = 0 ) } ``` #### setWritableBookPages Set pages of a writable book: ```kotlin itemModifier("writable_book") { setWritableBookPages { page("test", filtered = "filtered") mode(Mode.INSERT, 1) } } ``` #### setWrittenBookPages Set pages of a written book: ```kotlin itemModifier("written_book") { setWrittenBookPages { page("test", filtered = "test2") } } ``` ### Attributes #### setAttributes Add attribute modifiers: ```kotlin itemModifier("buffed") { setAttributes { attribute( attribute = Attributes.ATTACK_DAMAGE, operation = AttributeModifierOperation.ADD_VALUE, amount = constant(5f), id = "bonus_damage", slot = EquipmentSlot.MAINHAND ) attribute( attribute = Attributes.MOVEMENT_SPEED, operation = AttributeModifierOperation.ADD_MULTIPLIED_BASE, amount = constant(0.1f), id = "speed_boost", slot = EquipmentSlot.FEET ) } } ``` ### Banners and Patterns #### setBannerPattern Add banner patterns: ```kotlin itemModifier("banner") { setBannerPattern(append = true) { bannerPattern(BannerPatterns.CREEPER, FormattingColor.BLACK) } } ``` ### Block State #### copyState Copy block state to item: ```kotlin itemModifier("block_state") { copyState(Blocks.FURNACE) { properties("facing", "lit") } } ``` ### Bonus Formulas #### applyBonus Apply enchantment-based bonus formulas: ```kotlin itemModifier("fortune") { // Ore drops formula applyBonus(Enchantments.FORTUNE) { formula = OreDrops() } // Uniform bonus applyBonus(Enchantments.FORTUNE) { formula = UniformBonusCount(bonusMultiplier = 1f) } // Binomial distribution applyBonus(Enchantments.FORTUNE) { formula = BinomialWithBonusCount(extra = 3, probability = 0.5f) } } ``` ### Smelting and Decay #### furnaceSmelt Smelt the item as if in a furnace: ```kotlin itemModifier("auto_smelt") { furnaceSmelt() } ``` #### explosionDecay Random chance to destroy items based on explosion: ```kotlin itemModifier("explosion") { explosionDecay() } ``` ### Player Heads #### fillPlayerHead Set player head skin: ```kotlin itemModifier("head") { fillPlayerHead(Source.KILLER) } ``` ### Tooltips #### toggleTooltips Show/hide tooltip sections: ```kotlin itemModifier("clean_tooltip") { toggleTooltips { toggle(true, ItemComponentTypes.TRIM, ItemComponentTypes.CAN_PLACE_ON) toggles(ItemComponentTypes.DYED_COLOR to false) } } ``` ### Composition #### sequence Run multiple functions in sequence: ```kotlin itemModifier("complex") { sequence { setCount(1f) enchantRandomly() setName("Mystery Item") } } ``` #### discard Replaces the produced item stack with an empty one: ```kotlin itemModifier("discard_example") { discard() } ``` #### filtered Apply functions depending on whether the item matches a filter: ```kotlin itemModifier("filter") { filtered { itemFilter(Items.DIAMOND, Items.EMERALD) onFail { discard() } onPass { setCount(uniform(1f, 5f)) } } } ``` #### reference Reference another item modifier: ```kotlin val baseModifier = itemModifier("base") { setCount(1f) } itemModifier("extended") { reference(baseModifier) enchantRandomly() } ``` ## Conditions Every function can have conditions that must pass: ```kotlin itemModifier("conditional") { setCount(10f) { conditions { // Multiple conditions are AND-ed killedByPlayer() randomChance(0.5f) } } enchantRandomly { conditions { weatherCheck(raining = true) } } } ``` See [Predicates](/docs/data-driven/predicates) for all available conditions. ## Full Example ```kotlin dataPack("legendary_items") { val legendaryModifier = itemModifier("legendary_weapon") { // High-level enchantments enchantWithLevels(levels = constant(30f)) { conditions { randomChance(0.3f) } } // Guaranteed enchantments setEnchantments { enchantment(Enchantments.UNBREAKING, 3) } // Custom name with formatting setName(textComponent("Legendary Weapon") { color = Color.GOLD bold = true }) // Lore setLore { lore("Forged in ancient flames", Color.GRAY) lore("", Color.WHITE) lore("▸ +5 Attack Damage", Color.GREEN) mode(Mode.REPLACE_ALL) } // Attributes setAttributes(replace = false) { attribute( attribute = Attributes.ATTACK_DAMAGE, operation = AttributeModifierOperation.ADD_VALUE, amount = constant(5f), id = "legendary_damage", slot = EquipmentSlot.MAINHAND ) } // Full durability setDamage(1.0f) } // Use in loot table lootTable("boss_weapon") { pool { rolls = constant(1f) entries { item(Items.DIAMOND_SWORD) { functions { reference(legendaryModifier) } } } } } // Use with command load { items { modify(self(), WEAPON.MAINHAND, legendaryModifier) } } } ``` ### Generated JSON ```json [ { "function": "minecraft:enchant_with_levels", "levels": 30.0, "conditions": [ { "condition": "minecraft:random_chance", "chance": 0.3 } ] }, { "function": "minecraft:set_enchantments", "enchantments": { "minecraft:unbreaking": 3 } }, { "function": "minecraft:set_name", "name": { "text": "Legendary Weapon", "color": "gold", "bold": true } }, { "function": "minecraft:set_lore", "lore": [ { "text": "Forged in ancient flames", "color": "gray" }, { "text": "" }, { "text": "▸ +5 Attack Damage", "color": "green" } ], "mode": "replace_all" }, { "function": "minecraft:set_attributes", "modifiers": [ { "attribute": "minecraft:attack_damage", "id": "minecraft:legendary_damage", "amount": 5.0, "operation": "add_value", "slot": "mainhand" } ], "replace": false }, { "function": "minecraft:set_damage", "damage": 1.0 } ] ``` ## Best Practices 1. **Keep modifiers focused** - Create small, reusable modifiers and compose with `reference()` 2. **Use conditions wisely** - Guard expensive operations with appropriate conditions 3. **Prefer components** - Use `setComponents` for direct component manipulation when possible 4. **Consider context** - Some functions require specific loot contexts (killer, tool, etc.) 5. **Test thoroughly** - Verify modifiers work in all intended contexts (loot, commands, etc.) ## See Also - [Predicates](/docs/data-driven/predicates) - Conditions for item functions - [Components](/docs/concepts/components) - Understanding item components - [Loot Tables](/docs/data-driven/loot-tables) - Use item modifiers in loot tables - [Commands](/docs/commands/commands) - Using the `/item` command - [Villager Trades](/docs/data-driven/villager-trades) - Apply item modifiers to villager trade outputs via `givenItemModifiers` ### External Resources - [Minecraft Wiki: Item modifier](https://minecraft.wiki/w/Item_modifier) - Official JSON format reference --- ## Loot Tables --- root: .components.layouts.MarkdownLayout title: Loot Tables nav-title: Loot Tables description: Create and customize Minecraft loot tables using Kore's type-safe Kotlin DSL for drops, container contents, fishing, and more. keywords: minecraft, datapack, kore, loot tables, pools, entries, item modifiers, drops date-created: 2025-08-11 date-modified: 2026-06-26 routeOverride: /docs/data-driven/loot-tables --- # Loot Tables Loot tables are JSON files that dictate what items should generate in various game situations. They control drops from mobs and blocks, contents of naturally generated containers (chests, barrels, dispensers), fishing rewards, archaeology brushing results, bartering exchanges, and more. ## Overview Loot tables have several key characteristics: - **Context-dependent**: Different loot contexts provide different parameters (killer entity, tool, luck level, etc.) - **Randomized**: Use number providers for rolls and weighted entries for varied results - **Conditional**: Apply predicates to pools, entries, and functions - **Composable**: Reference other loot tables as entries for modularity - **Transformable**: Apply item modifier functions to modify generated items ## File Structure Loot tables are stored as JSON files in data packs at: ``` data//loot_table/.json ``` For complete JSON specification, see the [Minecraft Wiki - Loot table](https://minecraft.wiki/w/Loot_table). ## Creating Loot Tables Use the `lootTable` builder function to create loot tables in Kore: ```kotlin dataPack("my_datapack") { lootTable("custom_chest") { pool { rolls = constant(3f) entries { item(Items.DIAMOND) { weight = 1 } item(Items.GOLD_INGOT) { weight = 5 } item(Items.IRON_INGOT) { weight = 10 } } } } } ``` This generates `data/my_datapack/loot_table/custom_chest.json`. ## Table Structure A loot table consists of: | Property | Type | Description | |------------------|--------------------------|-----------------------------------------------------| | `type` | `LootTableType` | Optional context type for validation | | `pools` | `List` | One or more pools that generate items | | `functions` | `ItemModifier` | Optional global item functions applied to all drops | | `randomSequence` | `RandomSequenceArgument` | Optional deterministic random sequence | ### Setting the Type The type validates that the loot table uses appropriate context parameters: ```kotlin lootTable("entity_drops") { type = LootTableType.ENTITY pool { // Entity context allows accessing killer, damage source, etc. } } ``` Available types: `ADVANCEMENT_ENTITY`, `ADVANCEMENT_LOCATION`, `ADVANCEMENT_REWARD`, `ARCHEOLOGY`, `BARTER`, `BLOCK`, `BLOCK_USE`, `CHEST`, `COMMAND`, `EMPTY`, `ENTITY`, `EQUIPMENT`, `FISHING`, `GIFT`, `GENERIC`, `SELECTOR`, `SHEARING`, `VAULT`, `VILLAGER_TRADE`. ### Global Functions Apply item modifier functions to all items dropped by the table: ```kotlin lootTable("enchanted_loot") { functions { enchantRandomly { options += Enchantments.LOOTING } } pool { entries { item(Items.DIAMOND_SWORD) } } } ``` ## Pools Each pool represents an independent set of rolls. A table can have multiple pools that all contribute to the final loot. ### Pool Properties | Property | Type | Description | |--------------|-------------------|------------------------------------------------| | `rolls` | `NumberProvider` | How many times to select from entries | | `bonusRolls` | `NumberProvider` | Additional rolls per luck level | | `conditions` | `Predicate` | Conditions that must pass for pool to activate | | `entries` | `List` | Possible entries to select from | | `functions` | `ItemModifier` | Functions applied to items from this pool | ### Basic Pool ```kotlin lootTable("simple_pool") { pool { rolls = constant(2f) bonusRolls = constant(1f) entries { item(Items.EMERALD) } } } ``` ### Conditional Pool ```kotlin lootTable("weather_dependent") { pool { rolls = constant(1f) conditions { weatherCheck(raining = true) } entries { item(Items.WATER_BUCKET) } } } ``` ### Pool with Functions ```kotlin lootTable("modified_drops") { pool { rolls = constant(1f) entries { item(Items.DIAMOND_PICKAXE) } functions { setDamage(0.5f) enchantWithLevels(levels = constant(30f)) } } } ``` ## Number Providers Number providers determine dynamic numeric values for rolls, counts, and other quantities. | Provider | Description | Example | |-----------------------------------|-----------------------------------------------------------|-------------------------------------------------------------------------| | `binomial(n, p)` | Binomial distribution | `binomial(5, 0.5f)` | | `constant(value)` | Fixed value | `constant(5f)` | | `enchantmentLevel(...)` | Based on enchantment level (requires enchantment context) | `enchantmentLevel(5)` | | `environmentAttribute(attribute)` | Current value of a numeric env attribute | `environmentAttribute(EnvironmentAttributes.Visual.FOG_START_DISTANCE)` | | `scoreNumber(...)` | Value from a scoreboard objective | `scoreNumber("kills", EntityType.THIS)` | | `storageNumber(storage, path)` | Value from command storage | `storageNumber("my_pack:data", "player.health")` | | `sum(...)` | Sum of multiple providers | `sum(constant(1f), uniform(1f, 3f))` | | `uniform(min, max)` | Random value between min and max | `uniform(1f, 5f)` | ```kotlin pool { rolls = uniform(2f, 5f) // 2-5 rolls randomly bonusRolls = constant(1f) // +1 roll per luck level entries { item(Items.GOLD_INGOT) } } ``` ## Entries Entries define what can be selected during a pool roll. There are singleton entries (yield items) and composite entries (combine other entries). ### Singleton Entries #### Item Entry Drops a specific item: ```kotlin entries { item(Items.DIAMOND) { weight = 1 quality = 2 conditions { randomChance(0.5f) } functions { setCount(uniform(1f, 3f)) } } } ``` #### Loot Table Entry References another loot table: ```kotlin entries { lootTable(LootTables.Gameplay.PIGLIN_BARTERING) { weight = 1 functions { setCount(2f) } } } ``` #### Tag Entry Drops items from an item tag: ```kotlin entries { tag(Tags.Item.ARROWS) { expand = true // Each item becomes a separate entry weight = 1 } } ``` #### Dynamic Entry For block-specific drops (decorated pot sherds or shulkers contents): ```kotlin entries { dynamic(LootEntryDynamicName.SHERDS) { // Drops contents of decorated pot sherds } } ``` #### Empty Entry A weighted entry that drops nothing (useful for rarity): ```kotlin entries { empty { weight = 10 // 10x more likely than weight=1 entries } } ``` ### Composite Entries #### Alternatives Selects the first entry whose conditions pass: ```kotlin entries { alternatives { children { item(Items.DIAMOND) { conditions { randomChance(0.1f) } } item(Items.GOLD_INGOT) { conditions { randomChance(0.3f) } } item(Items.IRON_INGOT) // Fallback } } } ``` #### Group All children are added to the pool if conditions pass: ```kotlin entries { group { conditions { weatherCheck(raining = true) } children { item(Items.WATER_BUCKET) item(Items.FISH) } } } ``` #### Sequence Children are added until one fails its conditions: ```kotlin entries { sequence { children { item(Items.DIAMOND) { conditions { randomChance(0.5f) } } item(Items.EMERALD) { conditions { randomChance(0.5f) } } item(Items.GOLD_INGOT) } } } ``` #### Slots Entry Selects items from inventory slots specified by a slot source: ```kotlin entries { slots { slotSources { slotRange(SlotSourceOrigin.THIS, HOTBAR) } } } ``` ### Slot Sources Slot sources specify which inventory slots to select from. They can be combined - when multiple sources are provided, they serialize as an `InlinableList` (single element as object, multiple as array). #### Contents Selects all non-empty slots from the inventory component of items: ```kotlin slotSources { contents(InventoryComponentType.CONTAINER) { slotSource { slotRange(SlotSourceOrigin.BLOCK_ENTITY, "container.*") } } } ``` Available component types: `BUNDLE_CONTENTS`, `CHARGED_PROJECTILES`, `CONTAINER`. #### Empty An empty selection containing no slots: ```kotlin slotSources { empty() } ``` #### Filtered Applies an item filter to the selected slots, excluding non-matching ones: ```kotlin slotSources { filtered { slotSource { slotRange(SlotSourceOrigin.THIS, HOTBAR.all()) empty() } itemFilter { count = rangeOrInt(16..64) } } } ``` #### Group Merges several slot sources into one: ```kotlin slotSources { group { slotRange(SlotSourceOrigin.THIS, HOTBAR.all()) empty() } } ``` #### Limit Slots Limits the number of slots provided: ```kotlin slotSources { limitSlots(5) { slotSource { slotRange(SlotSourceOrigin.THIS, HOTBAR.all()) } } } ``` #### Slot Range Selects slots within a range from an entity or block entity inventory: ```kotlin slotSources { // Using a RangeItemSlot (e.g., HOTBAR, ARMOR) slotRange(SlotSourceOrigin.THIS, HOTBAR) // Using a specific ItemSlotWrapper slotRange(SlotSourceOrigin.BLOCK_ENTITY, ARMOR.HEAD) // Using a raw slot string slotRange(SlotSourceOrigin.THIS, "container.*") } ``` Available origins: `ATTACKING_ENTITY`, `BLOCK_ENTITY`, `DIRECT_ATTACKER`, `INTERACTING_ENTITY`, `LAST_DAMAGE_PLAYER`, `TARGET_ENTITY`, `THIS`. ### Entry Properties Singleton entries share these properties: | Property | Type | Description | |--------------|----------------|----------------------------------------------------------| | `weight` | `Int` | Selection weight (higher = more likely) | | `quality` | `Int` | Modifies weight based on luck: `weight + quality × luck` | | `conditions` | `Predicate` | Entry only available if conditions pass | | `functions` | `ItemModifier` | Functions applied to this entry's items | ## Conditions (Predicates) Conditions control when pools, entries, or functions apply. They use the same Predicate system as advancements. ```kotlin pool { conditions { // Multiple conditions are AND-ed weatherCheck(raining = true) randomChance(0.5f) // Check entity properties entityProperties { type(EntityTypes.PLAYER) } // Check killer killedByPlayer() // Check tool matchTool { items = listOf(Items.DIAMOND_PICKAXE) } } } ``` See [Predicates](/docs/data-driven/predicates) for the complete list of available conditions. ## Functions (Item Modifiers) Functions transform the generated items. They can be applied at table, pool, or entry level. ### Common Functions ```kotlin functions { // Set stack count setCount(uniform(1f, 5f)) // Apply enchantments enchantRandomly { options += Enchantments.FORTUNE } // Set damage (durability) setDamage(0.8f) // Add custom name setName("Legendary Sword") // Conditional function setCount(10f) { conditions { killedByPlayer() } } } ``` See [Item Modifiers](/docs/data-driven/item-modifiers) for the complete list of available functions. ## Full Example ```kotlin dataPack("treasure_hunt") { // Custom boss drop table lootTable("boss_drops") { type = LootTableType.ENTITY // Global enchantment on all drops functions { enchantRandomly() } // Guaranteed drops pool { rolls = constant(1f) entries { item(Items.NETHER_STAR) } } // Rare equipment drops pool { rolls = constant(1f) bonusRolls = constant(0.5f) conditions { killedByPlayer() } entries { item(Items.NETHERITE_SWORD) { weight = 1 functions { enchantWithLevels(levels = constant(30f)) setName("Boss Slayer") } } item(Items.DIAMOND_SWORD) { weight = 5 functions { enchantWithLevels(levels = uniform(15f, 25f)) } } empty { weight = 10 } } } // Bonus loot from existing table pool { rolls = uniform(1f, 3f) entries { lootTable(LootTables.Chests.END_CITY_TREASURE) } } } } ``` ### Generated JSON ```json { "type": "minecraft:entity", "functions": [ { "function": "minecraft:enchant_randomly" } ], "pools": [ { "rolls": 1.0, "entries": [ { "type": "minecraft:item", "name": "minecraft:nether_star" } ] }, { "rolls": 1.0, "bonus_rolls": 0.5, "conditions": [ { "condition": "minecraft:killed_by_player" } ], "entries": [ { "type": "minecraft:item", "name": "minecraft:netherite_sword", "weight": 1, "functions": [ { "function": "minecraft:enchant_with_levels", "levels": 30.0 }, { "function": "minecraft:set_name", "name": "Boss Slayer" } ] }, { "type": "minecraft:item", "name": "minecraft:diamond_sword", "weight": 5, "functions": [ { "function": "minecraft:enchant_with_levels", "levels": { "type": "minecraft:uniform", "min": 15.0, "max": 25.0 } } ] }, { "type": "minecraft:empty", "weight": 10 } ] }, { "rolls": { "type": "minecraft:uniform", "min": 1.0, "max": 3.0 }, "entries": [ { "type": "minecraft:loot_table", "name": "minecraft:chests/end_city_treasure" } ] } ] } ``` ## Using with Commands Spawn loot from a table using the `/loot` command. The surrounding command builders are documented in [Commands](/docs/commands/commands), while reusable conditions usually come from [Predicates](/docs/data-driven/predicates): ```kotlin load { // Give loot directly to player loot(self(), myLootTable) // Spawn loot at position loot(vec3(0, 64, 0), myLootTable) // Insert loot into container loot(block(0, 64, 0), myLootTable) } ``` ## Overriding Vanilla Tables To modify vanilla loot tables, create a file with the same path in your datapack. You can combine that with [Item Modifiers](/docs/data-driven/item-modifiers) when you want reusable post-processing logic instead of duplicating functions inside every pool: ```kotlin dataPack("better_zombies") { // This overrides minecraft:entities/zombie lootTable("entities/zombie") { namespace = "minecraft" pool { rolls = constant(1f) entries { item(Items.ROTTEN_FLESH) { functions { setCount(uniform(0f, 2f)) lootingEnchant(uniform(0f, 1f)) } } } } // Add custom drops pool { rolls = constant(1f) conditions { randomChance(0.1f) } entries { item(Items.DIAMOND) } } } } ``` ## Best Practices 1. **Use appropriate types** - Set the `type` field to catch invalid context parameter usage early 2. **Organize with multiple pools** - Use separate pools for different drop categories (guaranteed, rare, conditional) 3. **Leverage composition** - Reference other loot tables instead of duplicating entries 4. **Weight appropriately** - Use meaningful weights (e.g., 1/5/10/50) for clear rarity tiers 5. **Apply conditions at the right level** - Pool conditions for entire categories, entry conditions for specific items ## See Also - [Item Modifiers](/docs/data-driven/item-modifiers) - Functions applied to loot table items - [Advancements](/docs/data-driven/advancements) - Rewards can reference loot tables - [Tags](/docs/data-driven/tags) - Use item tags for tag entries ### External Resources - [Minecraft Wiki: Loot table](https://minecraft.wiki/w/Loot_table) - Official JSON format reference - [Minecraft Wiki: Loot context](https://minecraft.wiki/w/Loot_context) - Understanding loot contexts --- ## Minecraft Predicates - Type-Safe Condition DSL in Kore --- root: .components.layouts.MarkdownLayout title: Minecraft Predicates - Type-Safe Condition DSL in Kore nav-title: Predicates description: Create Minecraft predicates with Kore's type-safe Kotlin DSL. Covers entity properties, location, weather, time, enchantments, damage, and NBT checks. Use in execute if/unless, loot tables, and advancements. keywords: minecraft predicates, datapack conditions, execute if predicate, entity properties check, location check, weather check, time check, damage predicate, kore predicates, minecraft condition dsl date-created: 2024-01-08 date-modified: 2026-07-02 routeOverride: /docs/data-driven/predicates --- # Predicates Predicates are JSON structures used in data packs to check conditions within the world. They return a pass or fail result to the invoker, which acts differently based on the result. In practical terms, predicates are a flexible way for data packs to encode "if this, then that" logic without needing custom code. Predicates can be used in: - **Commands**: Via [`execute if predicate`](/docs/commands/execute) or target selector argument `predicate=` - **Loot tables**: As conditions for loot entries - **Advancements**: As trigger conditions - **Other predicates**: Via the `reference` condition Kore provides a type-safe DSL to create predicates, eliminating the need to write raw JSON. ## Basic Usage Here's a simple example of creating a predicate that checks if a player is holding a diamond pickaxe: ```kotlin val myPredicate = predicate("test") { matchTool { item(Items.DIAMOND_PICKAXE) } } ``` The `predicate` function creates and registers a predicate in your DataPack. It produces a file at `data//predicate/.json` and returns a `PredicateArgument` that can be used in commands. ## Conditions Predicates can have multiple conditions that must be met. You can combine them using `allOf` or `anyOf`: ```kotlin predicate("complex_test") { allOf { enchantmentActiveCheck(true) randomChance(0.5f) randomChanceWithEnchantedBonus( unenchantedChance = 0.3f, enchantedChance = 2, Enchantments.EFFICIENCY ) weatherCheck(raining = true, thundering = false) } } ``` You can also use the `inverted` condition to invert the result of a predicate: ```kotlin predicate("inverted_test") { inverted { randomChance(0.5f) } } ``` ### Available Conditions Conditions are categorized by their **loot context requirements **. Some conditions can be invoked from any context, while others require specific data to be available. #### Universal Conditions (invokable from any context) | Condition | Description | |-----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `allOf` | Evaluates a list of predicates and passes if **all** of them pass | | `anyOf` | Evaluates a list of predicates and passes if **any one** of them passes | | `entityProperties` | Checks properties of an entity | | `environmentAttributeCheck` | Passes if the specified environment attribute currently matches the given value | | `inverted` | Inverts another predicate condition | | `randomChance` | Passes if a random float between 0.0 and 1.0 is below the given `NumberProvider` value | | `reference` | Invokes another predicate file and returns its result (cannot be cyclic) | | `timeCheck` | Compares a world clock's time against a `NumberProvider` range (optional `period` for modulo, optional `clock` to select which clock) - see [World Clocks](/docs/data-driven/world-clocks#timecheckpredicatecondition) | | `valueCheck` | Compares a `NumberProvider` value against another `NumberProvider` or range | | `weatherCheck` | Checks the current game weather (raining, thundering) | > `randomChance`, `timeCheck`, and `valueCheck` accept a [ `NumberProvider`](/docs/data-driven/loot-tables#number-providers) for their numeric arguments, so you can use dynamic > values like scoreboard scores, enchantment levels, or environment attributes instead of plain floats. ### Environment Attribute Check `environmentAttributeCheck` passes when the specified environment attribute equals the given value. The value type is inferred from the attribute - booleans for toggle attributes, floats for numeric ones, strings for enum-like ones (moon phase, villager activity), and objects for compound ones (ambient sounds, background music). ```kotlin predicate("is_daytime") { // Boolean attribute - convenience overload, no wrapping needed environmentAttributeCheck(EnvironmentAttributes.Gameplay.MONSTERS_BURN, true) } predicate("dim_sky") { // Float attribute - convenience overload, no wrapping needed environmentAttributeCheck(EnvironmentAttributes.Visual.SKY_LIGHT_FACTOR, 0.5f) } predicate("full_moon") { // Builder block: call exactly one typed helper from EnvironmentAttributesScope. // It sets both the attribute ID and the expected value automatically. environmentAttributeCheck { moonPhase(Textures.Environment.Celestial.Moon.FULL_MOON) } } ``` The builder block accepts any number of calls from the same scope helpers used in dimension types and biomes ( `moonPhase`, `beesStayInHive`, `fogColor`, `ambientSounds`, etc.). Each attribute set in the block produces one `environment_attribute_check` condition, so multiple attributes are an implicit AND - all must match for the predicate to pass. #### Context-Dependent Conditions Most of these conditions require specific loot context data and will **always fail** if not provided. Three exceptions have optional context with graceful fallback behavior (noted in the table): | Condition | Required Context | Description | |----------------------------------|-----------------------------|---------------------------------------------------------------------------------------| | `blockStateProperty` | Block state | Checks the mined block and its block states | | `damageSourceProperties` | Origin + damage source | Checks properties of the damage source | | `enchantmentActiveCheck` | Enchantment active status | Checks if an enchantment is active (only usable from `enchanted_location` context) | | `entityScores` | Specified entity | Checks scoreboard scores of an entity against `NumberProvider` ranges | | `killedByPlayer` | `attacking_player` entity | Checks if there is an attacking player entity | | `locationCheck` | Origin | Checks the current location against location criteria (supports offsets) | | `matchTool` | Tool | Checks tool used to mine the block | | `randomChanceWithEnchantedBonus` | Attacker entity (optional) | Random chance modified by enchantment level (level 0 if no attacker) | | `survivesExplosion` | Explosion radius (optional) | Returns success with 1 ÷ explosion radius probability (always passes if no explosion) | | `tableBonus` | Tool (optional) | Passes with probability from a list indexed by enchantment power (level 0 if no tool) | ## Entity Properties The `entityProperties` condition allows you to check various properties of an entity. You must specify which entity to check using the `entity` parameter: ### Entity Context Options | Value | Description | |----------------------|-----------------------------------------------------------| | `this` | The entity that invoked the predicate (default) | | `attacker` | The entity that attacked | | `direct_attacker` | The direct cause of damage (e.g., arrow, not the shooter) | | `attacking_player` | The attacking player specifically | | `target_entity` | The targeted entity | | `interacting_entity` | The entity interacting with something | ### Entity Predicate Example ```kotlin predicate("entity_check") { entityProperties { // Check entity components (e.g., axolotl variant) components { axolotlVariant(AxolotlVariants.CYAN) damage(12) !unbreakable() // Negated component check } // Check effects effects { this[Effects.INVISIBILITY] = effect { amplifier = rangeOrInt(1) } } // Check equipment equipment { mainHand = itemStack(Items.DIAMOND_SWORD) } // Check entity flags flags { isBaby = true } // Check location location { block { blocks(Blocks.STONE) } } // Check movement movement { x(1.0, 4.0) horizontalSpeed(1.0) } // Check what affects entity movement movementAffectedBy { canSeeSky = true } // Check NBT data nbt { this["foo"] = "bar" } // Check entity passenger passenger { team = "foo" } // Check custom data predicates predicates { customData { this["foo"] = "bar" } } // Check specific inventory slots slots { this[WEAPON.MAINHAND] = itemStack(Items.DIAMOND_SWORD) } // Check block the entity is standing on steppingOn { blocks(Blocks.STONE) components { damage(5) } predicates { customData { this["foo"] = "bar" } } state("up", "bottom") } // Check entity type type(EntityTypes.MARKER) // Check player-specific properties playerTypeSpecific { gamemodes(Gamemode.SURVIVAL) } // Check entity vehicle with distance vehicle { distance { x(1f..4f) z(1f) } } } } ``` ## Sub-Predicates Sub-predicates are nested data structures that allow you to define specific properties to check within a predicate condition. Each condition type can have its own set of sub-predicates. ### Entity Sub-Predicates The `entityProperties` condition supports various sub-predicates to check different aspects of an entity: | Sub-Predicate | Description | Example | |----------------------|------------------------------------------|--------------------------------------------------------------------------| | `components` | Check entity data components | `components { axolotlVariant(AxolotlVariants.CYAN) }` | | `distance` | Check distance between entities | `distance { x(1f..4f) }` | | `effects` | Check potion effects | `effects { this[Effects.SPEED] = effect { amplifier = rangeOrInt(1) } }` | | `equipment` | Check equipped items | `equipment { mainHand = itemStack(Items.DIAMOND_SWORD) }` | | `flags` | Check entity flags (baby, on fire, etc.) | `flags { isBaby = true }` | | `location` | Check entity location | `location { block { blocks(Blocks.STONE) } }` | | `movement` | Check entity movement | `movement { x(1.0, 4.0); horizontalSpeed(1.0) }` | | `movementAffectedBy` | Check what affects entity movement | `movementAffectedBy { canSeeSky = true }` | | `nbt` | Check entity NBT data | `nbt { this["foo"] = "bar" }` | | `passenger` | Check entity passenger | `passenger { team = "foo" }` | | `periodicTicks` | Check entity periodic ticks | `periodicTicks = 20` | | `predicates` | Check custom data predicates | `predicates { customData { this["key"] = "value" } }` | | `slots` | Check specific inventory slots | `slots { this[WEAPON.MAINHAND] = itemStack(Items.DIAMOND_SWORD) }` | | `steppingOn` | Check block the entity is standing on | `steppingOn { blocks(Blocks.STONE) }` | | `targetedEntity` | Check entity being targeted | `targetedEntity { type(EntityTypes.ZOMBIE) }` | | `team` | Check entity team | `team = "my_team"` | | `type` | Check entity type | `type(EntityTypes.MARKER)` | | `typeSpecific` | Check type-specific properties | See [Type-Specific Properties](#entity-type-specific-properties) | | `vehicle` | Check entity vehicle | `vehicle { distance { x(1f..4f) } }` | The `Entity` class provides all the functions for these sub-predicates. ### Entity Type-Specific Properties Entities can still expose a handful of hard-coded type-specific predicates (mainly utility ones such as fishing hooks, lightning, player, raider, sheep and slime). All the visual *variant* checks that existed before snapshot **25w04a** were migrated by Mojang to the new **components ** system. Kore therefore removed the dedicated helpers (`axolotlTypeSpecific`, `catTypeSpecific`, …) in favor of component matching. #### Component-based variant checks (25w04a +) You can now query an entity’s data components directly from `entityProperties` with the `components` block: ```kotlin // Check axolotl variant via its component predicate("axolotl_component_check") { entityProperties { components { axolotlVariant(AxolotlVariants.LUCY) } } } ``` Any component you can put on an **item** can be matched on an **entity ** in exactly the same way - just call the corresponding extension inside the `components {}` scope. #### Remaining built-in `typeSpecific` helpers These helpers are still available because they cover information that is **not** represented by components: ##### Fishing Hook Check if a fishing hook is in open water: ```kotlin predicate("fishing_hook_check") { entityProperties { fishingHookTypeSpecific(inOpenWater = true) } } ``` ##### Lightning Check lightning bolt properties like blocks set on fire: ```kotlin predicate("lightning_check") { entityProperties { lightningTypeSpecific { blocksSetOnFire = rangeOrInt(1..5) } } } ``` ##### Player Check player-specific properties including gamemode, food stats, unlocked recipes, and input state: ```kotlin predicate("player_check") { entityProperties { playerTypeSpecific { gamemodes(Gamemode.CREATIVE) food { level = rangeOrInt(5..15) saturation = rangeOrDouble(1.0, 10.0) } recipes { this[Recipes.BOW] = true } input { forward = true backward = false left = true right = false jump = true sneak = false sprint = true } } } } ``` ##### Raider Check raider properties like raid participation and captain status: ```kotlin predicate("raider_check") { entityProperties { raiderTypeSpecific(hasRaid = true, isCaptain = false) } } ``` ##### Sheep Check if a sheep has been sheared: ```kotlin predicate("sheep_check") { entityProperties { sheepTypeSpecific(sheared = true) } } ``` ##### Slime Check slime size: ```kotlin predicate("slime_check") { entityProperties { slimeTypeSpecific(rangeOrInt(2)) } } ``` > **Note** All former `*TypeSpecific` helpers that dealt with variants (axolotl, cat, fox, frog, horse, llama, mooshroom, painting, parrot, pig, rabbit, salmon, tropical fish, villager, wolf) have been removed. Update your predicates to use component matching instead. ### Item Sub-Predicates When using `matchTool` or checking equipment, you can use item sub-predicates. There are two main ways to check item properties: 1. Basic item properties: ```kotlin predicate("basic_item_check") { matchTool { item(Items.DIAMOND_SWORD) count = rangeOrInt(1..64) durability = rangeOrInt(0..100) } } ``` 2. Component Matchers - A powerful system to check component properties: ```kotlin predicate("component_check") { matchTool { item(Items.DIAMOND_SWORD) predicates { // Check damage and durability damage { durability(1) damage = rangeOrInt(4..5) } // Check enchantments enchantments { enchantment(Enchantments.SHARPNESS, level = 3) } } } } ``` Component Matchers allow you to check various item components like: - Attribute modifiers - Container contents (bundles, shulker boxes) - Damage and durability - Enchantments - Firework properties - Book contents - And many more Each matcher corresponds to a component type in Minecraft and provides type-safe ways to check their properties. See the [Available Component Matchers](/docs/concepts/components#available-component-matchers) table in the Components guide for the full list. ## Using Predicates in Commands Predicates can be invoked in commands in two ways: ### Execute If Predicate Use `/execute if predicate` to conditionally run commands. If you need a refresher on the surrounding execution DSL, the [Commands](/docs/commands/commands) page covers the broader command surface: ```kotlin function("test") { execute { ifCondition { predicate(myPredicate) } run { debug("predicate validated!") } } } ``` ### Target Selector Argument Use the `predicate=` selector argument to filter entities. This pairs naturally with Kore's typed [Selectors](/docs/concepts/selectors): ```kotlin function("filter_entities") { // Kill all entities matching the predicate kill(allEntities { predicate = myPredicate }) } ``` ### Pairing with Inventory Manager Predicates excel at validating complex item properties. When you need to both validate and actively manage inventories ( e.g., keep a GUI slot populated with an item matching specific [Components](/docs/concepts/components)), use them alongside the [Inventory Manager](/docs/helpers/inventory-manager). ## Item Predicates Item predicates check the item involved in a predicate context - most commonly the tool used to mine a block via `matchTool`, but the same shape is used for `equipment` slots and `slots` checks inside `entityProperties` (see [Entity Predicate Example](#entity-predicate-example) above). A basic item predicate matches on the item type plus optional `count`/`durability` ranges: ```kotlin predicate("enchanted_tool") { matchTool { item(Items.DIAMOND_PICKAXE) predicates { enchantments(enchantment(Enchantments.EFFICIENCY)) } } } ``` The `predicates { }` block accepts any [component matcher](/docs/concepts/components#component-matchers--item-predicates) - `damage`, `enchantments`, `storedEnchantments`, `customData`, `container`, and more - so you can gate a predicate on arbitrary component state, not just enchantments. If you instead need the inline command-syntax form (`minecraft:diamond_sword[damage=10]`) for use outside a predicate file - e.g. in `/give`, `/clear`, or the `items` selector - see [Item Predicates](/docs/concepts/components#item-predicates) and [Component Matchers (Sub-Predicates)](/docs/concepts/components#component-matchers-sub-predicates) in the Components guide, which cover both forms side by side with more examples (existence checks, partial matching, negation, OR). ## Referencing Other Predicates Use the `reference` condition to invoke another predicate file, which keeps larger predicate sets composable in the same spirit as helper extraction in the [Cookbook](/docs/guides/cookbook): ```kotlin val basePredicate = predicate("base_check") { weatherCheck(raining = true) } predicate("combined_check") { allOf { reference(basePredicate) randomChance(0.5f) } } ``` > **Warning**: Cyclic references (predicate A references B, which references A) will cause a parsing failure. ## Best Practices 1. **Descriptive names**: Give your predicates names that reflect their purpose (e.g., `is_holding_sword`, `in_rain_at_night`) 2. **Logical composition**: Use `allOf` and `anyOf` to combine multiple conditions clearly 3. **Reusability**: Keep predicates focused on a single concern and use `reference` to compose them 4. **Context awareness **: Be mindful of which loot context your predicate will be invoked from. Context-dependent conditions will silently fail if required data is missing 5. **Testing**: Test your predicates in-game using `/execute if predicate ` to verify they work as expected Predicates are powerful tools for creating complex conditions in your datapack. They enable sophisticated game mechanics and enhance player experience without requiring custom code. ## See Also - [Loot Tables](/docs/data-driven/loot-tables) - Use predicates as conditions for loot entries - [Advancements](/docs/data-driven/advancements) - Use predicates as trigger conditions - [Item Modifiers](/docs/data-driven/item-modifiers) - Modify items conditionally with predicates - [Components](/docs/concepts/components#component-matchers--item-predicates) - Item predicates and component matchers in depth: command-syntax predicates, sub-predicate matchers, existence checks, and a complete tool-upgrade example - [Inventory Manager](/docs/helpers/inventory-manager) - Pair predicates with inventory management - [Villager Trades](/docs/data-driven/villager-trades) - Gate trade availability via `merchantPredicate` ### External Resources - [Minecraft Wiki: Predicate](https://minecraft.wiki/w/Predicate) - Official JSON format reference - [Minecraft Wiki: Loot context](https://minecraft.wiki/w/Loot_context) - Understanding loot contexts for conditions --- ## Recipes --- root: .components.layouts.MarkdownLayout title: Recipes nav-title: Recipes description: Create custom Minecraft recipes using Kore's type-safe Kotlin DSL for crafting, smelting, smithing, and more. keywords: minecraft, datapack, kore, recipes, crafting, smelting, smithing, stonecutting date-created: 2024-01-08 date-modified: 2026-06-20 routeOverride: /docs/data-driven/recipes --- # Recipes Recipes define how items are transformed through crafting tables, furnaces, smithing tables, stonecutters, and other workstations. Kore provides a type-safe DSL to create all vanilla recipe types programmatically. ## Overview Recipes have several key characteristics: - **Type-specific**: Each workstation has its own recipe format - **Discoverable**: Recipes can be unlocked via advancements - **Customizable results**: Output items can have custom components - **Tag-based ingredients**: Use item tags for flexible ingredient matching ### Recipe Types | Type | Workstation | Description | |---------------------------------------|----------------|-------------------------------------| | `blasting` | Blast Furnace | Faster ore smelting | | `campfire_cooking` | Campfire | Slow food cooking | | `crafting_decorated_pot` | Crafting Table | Craft a decorated pot from sherds | | `crafting_dye` | Crafting Table | Dye an item with a dye | | `crafting_imbue` | Crafting Table | Imbue items (e.g. tip arrows) | | `crafting_shaped` | Crafting Table | Pattern-based crafting | | `crafting_shapeless` | Crafting Table | Order-independent crafting | | `crafting_special_bannerduplicate` | Crafting Table | Copy a banner pattern | | `crafting_special_bookcloning` | Crafting Table | Copy a written book | | `crafting_special_firework_rocket` | Crafting Table | Craft a firework rocket | | `crafting_special_firework_star` | Crafting Table | Craft a firework star | | `crafting_special_firework_star_fade` | Crafting Table | Add a fade colour to a star | | `crafting_special_mapextending` | Crafting Table | Extend a map with paper | | `crafting_special_shielddecoration` | Crafting Table | Apply a banner to a shield | | `crafting_special_*` | Crafting Table | Remaining hardcoded special recipes | | `crafting_transmute` | Crafting Table | Transform item with material | | `smelting` | Furnace | Standard smelting | | `smithing_transform` | Smithing Table | Upgrade items | | `smithing_trim` | Smithing Table | Apply armor trims | | `smoking` | Smoker | Faster food cooking | | `stonecutting` | Stonecutter | Cut blocks | ## File Structure Recipes are stored as JSON files in data packs at: ``` data//recipe/.json ``` For complete JSON specification, see the [Minecraft Wiki - Recipe](https://minecraft.wiki/w/Recipe). ## Creating Recipes Use the `recipes` block inside a data pack to define recipes: ```kotlin dataPack("my_datapack") { recipes { craftingShaped("diamond_sword_upgrade") { pattern( " E ", " D ", " S " ) keys { "E" to Items.EMERALD "D" to Items.DIAMOND_SWORD "S" to Items.STICK } result(Items.DIAMOND_SWORD) { enchantments { enchantment(Enchantments.SHARPNESS, 5) } } } } } ``` This generates `data/my_datapack/recipe/diamond_sword_upgrade.json`. ## Crafting Recipes ### Banner Duplicate Copy a banner's pattern onto a blank banner: ```kotlin recipes { craftingSpecialBannerDuplicate("banner_copy") { banner(Tags.Item.BANNERS) result(Items.WHITE_BANNER) } } ``` ### Book Cloning Copy a written book, with an optional generation limit: ```kotlin recipes { craftingSpecialBookCloning("book_clone") { source(Items.WRITTEN_BOOK) material(Items.WRITABLE_BOOK) result(Items.WRITTEN_BOOK) allowedGenerations = rangeOrInt(0, 2) } } ``` ### Decorated Pot Craft a decorated pot from sherds: ```kotlin recipes { craftingDecoratedPot("decorated_pot") { back(Tags.Item.DECORATED_POT_INGREDIENTS) front(Tags.Item.DECORATED_POT_INGREDIENTS) left(Tags.Item.DECORATED_POT_INGREDIENTS) right(Tags.Item.DECORATED_POT_INGREDIENTS) result(Items.DECORATED_POT) } } ``` ### Dye Crafting Dye an item using a dye ingredient. _Replaces the old `crafting_special_armordye` recipe_: ```kotlin recipes { craftingDye("red_wool_dye") { dye(Items.RED_DYE) target(Tags.Item.WOOL) result(Items.RED_WOOL) } } ``` ### Firework Rocket Craft a firework rocket from its component ingredients: ```kotlin recipes { craftingSpecialFireworkRocket("firework_rocket") { fuel(Items.GUNPOWDER) shell(Items.PAPER) star(Items.FIREWORK_STAR) result(Items.FIREWORK_ROCKET) } } ``` ### Firework Star Craft a firework star with dye, fuel, optional shape modifiers, trail, and twinkle effects: ```kotlin recipes { craftingSpecialFireworkStar("red_burst_star") { dye(Items.RED_DYE) fuel(Items.GUNPOWDER) shape("burst", Items.FIRE_CHARGE) trail(Items.DIAMOND) twinkle(Items.GLOWSTONE_DUST) result(Items.FIREWORK_STAR) } } ``` ### Firework Star Fade Add a fade colour to an existing firework star: ```kotlin recipes { craftingSpecialFireworkStarFade("blue_fade_star") { dye(Items.BLUE_DYE) target(Items.FIREWORK_STAR) result(Items.FIREWORK_STAR) } } ``` ### Imbue Crafting Imbue items with properties from a source (e.g. tip arrows with lingering potions). _Replaces the old `crafting_special_tippedarrow` recipe_: ```kotlin recipes { craftingImbue("tipped_arrow") { material(Tags.Item.ARROWS) source(Items.LINGERING_POTION) result(Items.TIPPED_ARROW) } } ``` ### Map Extending Extend a map by combining it with paper: ```kotlin recipes { craftingSpecialMapExtending("extended_map") { map(Items.FILLED_MAP) material(Items.PAPER) result(Items.FILLED_MAP) } } ``` ### Shaped Crafting Pattern-based recipes where ingredient positions matter: ```kotlin recipes { craftingShaped("my_pickaxe") { // Define the pattern (up to 3x3) pattern( "DDD", " S ", " S " ) // Map characters to items key("D", Items.DIAMOND) key("S", Items.STICK) // Or use keys block keys { "D" to Items.DIAMOND "S" to Items.STICK } // Set the result result(Items.DIAMOND_PICKAXE) // Optional: set category for recipe book category = CraftingCategory.EQUIPMENT } } ``` #### Pattern Rules - Patterns can be 1x1 to 3x3 - Use space ` ` for empty slots - Each character must be mapped in `key()` or `keys {}` - Patterns are automatically trimmed (no need for padding) ```kotlin // 2x2 recipe craftingShaped("torch") { pattern( "C", "S" ) keys { "C" to Items.COAL "S" to Items.STICK } result(Items.TORCH) count = 4 } // Using tags as ingredients craftingShaped("planks") { pattern("L") key("L", Tags.Item.LOGS) result(Items.OAK_PLANKS) count = 4 } ``` ### Shapeless Crafting Order-independent recipes: ```kotlin recipes { craftingShapeless("mushroom_stew") { ingredient(Items.BOWL) ingredient(Items.BROWN_MUSHROOM) ingredient(Items.RED_MUSHROOM) result(Items.MUSHROOM_STEW) } } ``` #### Multiple of Same Ingredient ```kotlin craftingShapeless("book") { ingredient(Items.PAPER) ingredient(Items.PAPER) ingredient(Items.PAPER) ingredient(Items.LEATHER) result(Items.BOOK) } ``` #### Using Tags ```kotlin craftingShapeless("dye_mix") { ingredient(Tags.Item.DYES) ingredient(Tags.Item.DYES) result(Items.MAGENTA_DYE) count = 2 } ``` ### Shield Decoration Apply a banner pattern to a shield: ```kotlin recipes { craftingSpecialShieldDecoration("shield_decor") { banner(Tags.Item.BANNERS) target(Items.SHIELD) result(Items.SHIELD) } } ``` ### Special Crafting Remaining hardcoded special recipes with no configurable ingredients: ```kotlin recipes { craftingSpecial("repair", CraftingSpecialRepairItem) craftingSpecial("shulker_color", CraftingSpecialShulkerBoxColoring) } ``` These are useful when the vanilla datapack is disabled and you need to re-enable specific special recipes. ### Transmute Crafting Transform an item while preserving its components: ```kotlin recipes { craftingTransmute("dye_shulker") { input(Tags.Item.SHULKER_BOXES) material(Items.BLUE_DYE) result(Items.BLUE_SHULKER_BOX) } } ``` The result item copies all components from the input item. ## Cooking Recipes All cooking recipes share a similar structure: | Property | Description | |---------------|-----------------------------------| | `ingredient` | Input item or tag | | `result` | Output item | | `experience` | XP awarded when collecting output | | `cookingTime` | Time in ticks | ### Blasting (Blast Furnace) Twice as fast as smelting (100 ticks default): ```kotlin recipes { blasting("iron_ingot_fast") { ingredient(Items.RAW_IRON) result(Items.IRON_INGOT) experience = 0.7 cookingTime = 100 // 5 seconds (default) } } ``` ### Campfire Cooking Slow cooking without fuel: ```kotlin recipes { campfireCooking("baked_potato") { ingredient(Items.POTATO) result(Items.BAKED_POTATO) experience = 0.35 cookingTime = 600 // 30 seconds (default) } } ``` ### Smelting (Furnace) ```kotlin recipes { smelting("iron_ingot") { ingredient(Items.RAW_IRON) result(Items.IRON_INGOT) experience = 0.7 cookingTime = 200 // 10 seconds (default) } // Using tags smelting("glass") { ingredient(Tags.Item.SMELTS_TO_GLASS) result(Items.GLASS) experience = 0.1 } } ``` ### Smoking (Smoker) For food items, twice as fast as furnace: ```kotlin recipes { smoking("cooked_beef") { ingredient(Items.BEEF) result(Items.COOKED_BEEF) experience = 0.35 cookingTime = 100 } } ``` ## Smithing Recipes ### Smithing Transform Upgrade items at the smithing table: ```kotlin recipes { smithingTransform("netherite_sword") { template(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE) base(Items.DIAMOND_SWORD) addition(Items.NETHERITE_INGOT) result(Items.NETHERITE_SWORD) } } ``` The result item copies components from the base item. #### Multiple Addition Options ```kotlin smithingTransform("custom_upgrade") { template(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE) base(Items.DIAMOND_SWORD) addition(Items.NETHERITE_INGOT, Items.NETHERITE_SCRAP) // Either works result(Items.NETHERITE_SWORD) } ``` ### Smithing Trim Apply armor trims: ```kotlin recipes { smithingTrim("sentry_trim") { template(Items.SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE) base(Tags.Item.TRIMMABLE_ARMOR) addition(Tags.Item.TRIM_MATERIALS) pattern = TrimPatterns.SENTRY } } ``` ## Stonecutting Single-item recipes for the stonecutter: ```kotlin recipes { stoneCutting("stone_slab") { ingredient(Items.STONE) result(Items.STONE_SLAB) count = 2 } stoneCutting("stone_stairs") { ingredient(Items.STONE) result(Items.STONE_STAIRS) } // Multiple outputs from same ingredient (separate recipes) stoneCutting("stone_bricks") { ingredient(Items.STONE) result(Items.STONE_BRICKS) } } ``` ## Result Items with Components Add custom components to recipe results: ```kotlin recipes { craftingShaped("enchanted_book") { pattern( "E E", " B ", "E E" ) keys { "E" to Items.EMERALD "B" to Items.BOOK } result(Items.ENCHANTED_BOOK) { enchantments { enchantment(Enchantments.SHARPNESS, 5) } } } craftingShaped("damaged_sword") { pattern( " D", " D", " S" ) keys { "D" to Items.DAMAGED_DIAMOND "S" to Items.STICK } result(Items.DIAMOND_SWORD) { damage(100) // Partially damaged } } craftingShapeless("named_diamond") { ingredient(Items.DIAMOND) ingredient(Items.PAPER) result(Items.DIAMOND) { customName(textComponent("Certified Diamond", Color.AQUA)) lore(textComponent("100% Genuine", Color.GRAY)) } } } ``` ## Recipe Categories Organize recipes in the recipe book: ```kotlin craftingShaped("tool") { // ... pattern and keys result(Items.DIAMOND_PICKAXE) category = CraftingCategory.EQUIPMENT } smelting("food") { // ... ingredient and result category = SmeltingCategory.FOOD } ``` ### Crafting Categories - `BUILDING` - Building blocks - `REDSTONE` - Redstone components - `EQUIPMENT` - Tools, weapons, armor - `MISC` - Everything else ### Cooking Categories - `FOOD` - Food items - `BLOCKS` - Block transformations (sand → glass) - `MISC` - Everything else ## Recipe Groups Group similar recipes in the recipe book: ```kotlin recipes { craftingShaped("oak_planks") { pattern("L") key("L", Items.OAK_LOG) result(Items.OAK_PLANKS) count = 4 group = "planks" } craftingShaped("birch_planks") { pattern("L") key("L", Items.BIRCH_LOG) result(Items.BIRCH_PLANKS) count = 4 group = "planks" } } ``` Recipes with the same group appear together in the recipe book. ## Using Recipes in Commands ### Reference Recipes Store a recipe reference for use in commands: ```kotlin val myRecipe = recipesBuilder.craftingShaped("special_item") { pattern( " G ", "GBG", " G " ) keys { "G" to Items.GOLD_BLOCK "B" to Items.DIAMOND_BLOCK } result(Items.BEACON) } load { // Give recipe to all players recipeGive(allPlayers(), myRecipe) } ``` ### Give/Take Recipes ```kotlin load { // Give specific recipe recipeGive(self(), myRecipe) // Take recipe recipeTake(self(), myRecipe) // Give all recipes recipeGive(allPlayers(), "*") } ``` ## Overriding Vanilla Recipes Override vanilla recipes by using the minecraft namespace: ```kotlin dataPack("better_recipes") { recipes { // Override vanilla diamond sword recipe craftingShaped("diamond_sword") { namespace = "minecraft" pattern( " D ", " D ", " S " ) keys { "D" to Items.DIAMOND "S" to Items.STICK } result(Items.DIAMOND_SWORD) { enchantments { enchantment(Enchantments.UNBREAKING, 1) } } } } } ``` ## Full Example ```kotlin dataPack("custom_recipes") { recipes { // Shaped crafting with components craftingShaped("legendary_sword") { pattern( " N ", " N ", " B " ) keys { "N" to Items.NETHERITE_INGOT "B" to Items.BLAZE_ROD } result(Items.NETHERITE_SWORD) { customName(textComponent("Blade of Flames", Color.GOLD)) enchantments { enchantment(Enchantments.FIRE_ASPECT, 2) enchantment(Enchantments.SHARPNESS, 5) } unbreakable() } category = CraftingCategory.EQUIPMENT } // Shapeless recipe craftingShapeless("quick_tnt") { ingredient(Items.GUNPOWDER) ingredient(Items.GUNPOWDER) ingredient(Items.GUNPOWDER) ingredient(Items.GUNPOWDER) ingredient(Tags.Item.SAND) result(Items.TNT) } // Transmute recipe craftingTransmute("repaint_bed") { input(Tags.Item.BEDS) material(Items.WHITE_DYE) result(Items.WHITE_BED) } // Smelting with experience smelting("ancient_debris") { ingredient(Items.ANCIENT_DEBRIS) result(Items.NETHERITE_SCRAP) experience = 2.0 cookingTime = 200 category = SmeltingCategory.MISC } // Smithing upgrade smithingTransform("netherite_boots") { template(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE) base(Items.DIAMOND_BOOTS) addition(Items.NETHERITE_INGOT) result(Items.NETHERITE_BOOTS) } // Smithing trim smithingTrim("ward_trim") { template(Items.WARD_ARMOR_TRIM_SMITHING_TEMPLATE) base(Tags.Item.TRIMMABLE_ARMOR) addition(Tags.Item.TRIM_MATERIALS) pattern = TrimPatterns.WARD } // Stonecutting variants stoneCutting("cut_copper_slab") { ingredient(Items.COPPER_BLOCK) result(Items.CUT_COPPER_SLAB) count = 8 } } // Reference recipe in function val beaconRecipe = recipesBuilder.craftingShaped("easy_beacon") { pattern( "GGG", "GSG", "OOO" ) keys { "G" to Items.GLASS "S" to Items.NETHER_STAR "O" to Items.OBSIDIAN } result(Items.BEACON) } load { recipeGive(allPlayers(), beaconRecipe) } } ``` ### Generated JSON (Shaped Recipe) ```json { "type": "minecraft:crafting_shaped", "category": "equipment", "pattern": [ " N ", " N ", " B " ], "key": { "N": "minecraft:netherite_ingot", "B": "minecraft:blaze_rod" }, "result": { "id": "minecraft:netherite_sword", "components": { "custom_name": { "text": "Blade of Flames", "color": "gold" }, "enchantments": { "minecraft:fire_aspect": 2, "minecraft:sharpness": 5 }, "unbreakable": {} } } } ``` ## Best Practices 1. **Use meaningful names** - Recipe file names should describe the output 2. **Group related recipes** - Use the `group` field for recipe book organization 3. **Prefer tags** - Use item tags for flexible ingredient matching 4. **Set categories** - Help players find recipes in the recipe book 5. **Test in-game** - Verify recipes work as expected in all crafting interfaces 6. **Consider balance** - Ensure custom recipes maintain game balance ## See Also - [Advancements](/docs/data-driven/advancements) - Unlock recipes as advancement rewards - [Components](/docs/concepts/components) - Customize recipe result items - [Commands](/docs/commands/commands) - Give or take recipes with commands - [Tags](/docs/data-driven/tags) - Use item tags for flexible ingredient matching ### External Resources - [Minecraft Wiki: Recipe](https://minecraft.wiki/w/Recipe) - Official JSON format reference - [Minecraft Wiki: Crafting](https://minecraft.wiki/w/Crafting) - Crafting mechanics overview --- ## Tags --- root: .components.layouts.MarkdownLayout title: Tags nav-title: Tags description: Create and manage tags for grouping game elements with Kore's type-safe DSL keywords: minecraft, datapack, kore, tags, grouping, blocks, items, entities, functions date-created: 2026-02-03 date-modified: 2026-02-03 routeOverride: /docs/data-driven/tags --- # Tags Tags are JSON structures used in data packs to group related game elements together. They allow you to reference multiple items, blocks, entities, or other resources as a single unit. Tags are extensively used in commands, loot tables, advancements, recipes, and other data-driven features. ## Basic Usage Kore provides a generic `tag` function as well as specialized helper functions for each tag type: ```kotlin // Generic tag with explicit type tag("my_blocks", "block") { add(Blocks.STONE) add(Blocks.GRANITE) add(Blocks.DIORITE) } // Specialized helper function blockTag("my_blocks") { add(Blocks.STONE) add(Blocks.GRANITE) add(Blocks.DIORITE) } ``` This creates a tag file at `data//tags/block/my_blocks.json`. ## Adding Values There are several ways to add values to a tag: ### Simple Addition ```kotlin blockTag("building_blocks") { // Add a single block add(Blocks.STONE) // Using operators this += Blocks.COBBLESTONE this += "minecraft:granite" // Add with namespace add("custom_stone", namespace = "mymod") } ``` ### Adding Other Tags You can include other tags within a tag by prefixing with `#`: ```kotlin blockTag("all_stones") { // Reference another tag add("#minecraft:stone_bricks", tag = true) // Or using the name/namespace form add("base_stone_overworld", namespace = "minecraft", tag = true) } ``` ### Optional Entries Mark entries as optional with the `required` parameter. Optional entries won't cause errors if they don't exist: ```kotlin itemTag("optional_items") { add(Items.DIAMOND, required = true) // Must exist add("mymod:custom_gem", required = false) // Optional // Using TagEntry directly this += TagEntry("minecraft:emerald", required = false) } ``` ### Replace Mode By default, tags merge with existing tags of the same name. Set `replace = true` to completely override: ```kotlin // This will replace the vanilla tag entirely blockTag("logs", namespace = "minecraft", replace = true) { add(Blocks.OAK_LOG) add(Blocks.BIRCH_LOG) // Other logs won't be included } ``` ## Tag Types Kore provides specialized helper functions for all tag types. Here are the most commonly used ones: ### Block Tags ```kotlin blockTag("fragile_blocks") { add(Blocks.GLASS) add(Blocks.ICE) add(Blocks.GLOWSTONE) } ``` ### Item Tags ```kotlin itemTag("valuable_gems") { add(Items.DIAMOND) add(Items.EMERALD) add(Items.AMETHYST_SHARD) } ``` ### Entity Type Tags ```kotlin entityTypeTag("friendly_mobs") { add(EntityTypes.VILLAGER) add(EntityTypes.IRON_GOLEM) add(EntityTypes.CAT) } ``` ### Function Tags Function tags are special - they define groups of functions that can be called together or triggered by game events: ```kotlin // Create functions to be tagged function("on_load") { say("Datapack loaded!") } function("setup_scores") { scoreboard.objectives.add("kills", ScoreboardCriteria.PLAYER_KILL_COUNT) } // Tag them to run on load functionTag("load", namespace = "minecraft") { add("on_load", namespace = name) add("setup_scores", namespace = name) } ``` The `minecraft:load` and `minecraft:tick` function tags are special: - `minecraft:load` - Functions run once when the datapack loads - `minecraft:tick` - Functions run every game tick ### Biome Tags ```kotlin biomeTag("hot_biomes") { add(Biomes.DESERT) add(Biomes.BADLANDS) add(Biomes.SAVANNA) } ``` ### Damage Type Tags ```kotlin damageTypeTag("magic_damage") { add(DamageTypes.MAGIC) add(DamageTypes.INDIRECT_MAGIC) add(DamageTypes.DRAGON_BREATH) } ``` ### Enchantment Tags ```kotlin enchantmentTag("combat_enchants") { add(Enchantments.SHARPNESS) add(Enchantments.SMITE) add(Enchantments.BANE_OF_ARTHROPODS) } ``` ### Fluid Tags ```kotlin fluidTag("dangerous_fluids") { add(Fluids.LAVA) add(Fluids.FLOWING_LAVA) } ``` ## Complete List of Tag Helpers Kore provides helpers for all vanilla tag types: | Function | Tag Type | Path | |-------------------------------|----------------------|---------------------------------------------| | `bannerPatternTag` | Banner patterns | `tags/banner_pattern` | | `biomeTag` | Biomes | `tags/worldgen/biome` | | `blockTag` | Blocks | `tags/block` | | `catVariantTag` | Cat variants | `tags/cat_variant` | | `configuredCarverTag` | World carvers | `tags/worldgen/configured_carver` | | `configuredFeatureTag` | World features | `tags/worldgen/configured_feature` | | `configuredStructureTag` | Structures | `tags/worldgen/structure` | | `damageTypeTag` | Damage types | `tags/damage_type` | | `enchantmentTag` | Enchantments | `tags/enchantment` | | `entityTypeTag` | Entity types | `tags/entity_type` | | `flatLevelGeneratorPresetTag` | Flat world presets | `tags/worldgen/flat_level_generator_preset` | | `fluidTag` | Fluids | `tags/fluid` | | `frogVariantTag` | Frog variants | `tags/frog_variant` | | `functionTag` | Functions | `tags/function` | | `gameEventTag` | Game events | `tags/game_event` | | `instrumentTag` | Goat horns | `tags/instrument` | | `itemTag` | Items | `tags/item` | | `noiseSettingsTag` | Noise settings | `tags/worldgen/noise_settings` | | `noiseTag` | Noise | `tags/worldgen/noise` | | `paintingVariantTag` | Paintings | `tags/painting_variant` | | `pigVariantTag` | Pig variants | `tags/pig_variant` | | `placedFeatureTag` | Placed features | `tags/worldgen/placed_feature` | | `pointOfInterestTypeTag` | POI types | `tags/point_of_interest_type` | | `processorListTag` | Structure processors | `tags/worldgen/processor_list` | | `structureTag` | Structures | `tags/worldgen/structure` | | `templatePoolTag` | Jigsaw pools | `tags/worldgen/template_pool` | | `trimMaterialTag` | Trim materials | `tags/trim_material` | | `trimPatternTag` | Trim patterns | `tags/trim_pattern` | | `wolfVariantTag` | Wolf variants | `tags/wolf_variant` | | `worldPresetTag` | World presets | `tags/worldgen/world_preset` | ## Modifying Existing Tags Use `addToTag` to append to an existing tag without creating duplicates: ```kotlin // First creation blockTag("my_ores") { add(Blocks.IRON_ORE) add(Blocks.GOLD_ORE) } // Later in code, add more entries addToTag("my_ores", "block") { add(Blocks.DIAMOND_ORE) add(Blocks.EMERALD_ORE) } ``` ## Using Tags in Commands Tags can be referenced in commands with the `#` prefix, so they appear naturally across the [Commands](/docs/commands/commands) API surface: ```kotlin function("clear_valuables") { // Clear all items matching a tag clear(allPlayers(), tag = ItemTagArgument("valuable_gems", name)) } function("kill_hostiles") { // Kill entities matching a tag kill(allEntities { type = "#minecraft:raiders" }) } ``` ## Using Tags in Predicates Tags work seamlessly with [Predicates](/docs/data-driven/predicates): ```kotlin predicate("holding_tool") { matchTool { items(Tags.Item.PICKAXES) } } predicate("in_hot_biome") { locationCheck { biomes(BiomeTagArgument("hot_biomes", name)) } } ``` ## Using Tags in Recipes Tags are commonly used in [Recipes](/docs/data-driven/recipes) for flexible ingredient matching: ```kotlin craftingShapeless("any_planks_to_sticks") { ingredient(Tags.Item.PLANKS) ingredient(Tags.Item.PLANKS) result(Items.STICK, 4) } ``` ## Generated JSON A basic tag generates JSON like this: ```json { "replace": false, "values": [ "minecraft:stone", "minecraft:granite", "minecraft:diorite" ] } ``` With optional entries: ```json { "replace": false, "values": [ "minecraft:diamond", { "id": "mymod:custom_gem", "required": false } ] } ``` With tag references: ```json { "replace": false, "values": [ "#minecraft:stone_bricks", "minecraft:cobblestone" ] } ``` ## Best Practices 1. **Use meaningful names**: Name tags based on their purpose (e.g., `mineable/pickaxe` not `pickaxe_blocks`) 2. **Leverage existing tags**: Reference vanilla tags when appropriate instead of duplicating entries 3. **Keep tags focused**: Each tag should serve a single, clear purpose 4. **Use optional entries**: Mark modded content as `required = false` for cross-mod compatibility 5. **Avoid replace when possible**: Merging with existing tags maintains compatibility with other datapacks ## See Also - [Predicates](/docs/data-driven/predicates) - Use tags in predicate conditions - [Recipes](/docs/data-driven/recipes) - Use tags for flexible recipe ingredients - [Loot Tables](/docs/data-driven/loot-tables) - Use tags in loot conditions - [Trims](/docs/data-driven/trims) - Trim material and pattern tags ### External Resources - [Minecraft Wiki: Tag (Java Edition)](https://minecraft.wiki/w/Tag_(Java_Edition)) - Complete reference for all tag types and vanilla tags --- ## Timelines --- root: .components.layouts.MarkdownLayout title: Timelines nav-title: Timelines description: Learn how to use timelines in your Kore datapacks keywords: minecraft, datapack, kore, timelines, environment attributes, easing, keyframes, time markers, world clock date-created: 2026-02-10 date-modified: 2026-06-16 routeOverride: /docs/data-driven/timelines --- # Timelines Timelines control game behaviour and visuals based on a world clock through environment attributes. They define tracks that animate environment attributes over time using keyframes and easing functions. Optional named **time markers** act as labelled tick positions inside a timeline. Timelines were added in snapshot [**25w45a**](https://minecraft.wiki/w/Java_Edition_25w45a) (Minecraft 1.21.11). For a broader overview that covers world clocks, the `/time` command, and the `timeCheck` predicate condition together, see [World Clocks](/docs/data-driven/world-clocks). ## Basic Usage Every timeline must be bound to a `WorldClockArgument`. Register a clock first, then pass it when creating the timeline: ```kotlin val dayClock = dataPack.worldClock("day") val myTimeline = dataPack.timeline("day_fog", clock = dayClock) { periodTicks = 24000 track(EnvironmentAttributes.Visual.FOG_START_DISTANCE) { ease = Linear keyframe(0) { value(0.0f) } keyframe(12000) { value(100.0f) } } } ``` The `timeline` function creates and registers a timeline in your DataPack. It produces a file at `data//timeline/.json` and returns a `TimelineArgument`. ## Timeline Properties | Property | Type | Description | |---------------|--------------------------------|-------------------------------------------------------------------------------| | `clock` | `WorldClockArgument` | **Required.** The world clock this timeline reads from. | | `periodTicks` | `Int?` | Duration in ticks before the timeline loops. Omit for a one-shot timeline. | | `timeMarkers` | `Map?` | Named tick positions inside this timeline. See [Time Markers](#time-markers). | ## Tracks Tracks map environment attributes to keyframe-based animations. Each track specifies an easing type, an optional modifier, and a list of keyframes. ```kotlin dataPack.timeline("multi_track", clock = dayClock) { periodTicks = 24000 track(EnvironmentAttributes.Visual.FOG_START_DISTANCE) { ease = Linear keyframe(0) { value(0.0f) } keyframe(12000) { value(100.0f) } } track(EnvironmentAttributes.Visual.FOG_END_DISTANCE) { ease = InOutCubic keyframe(0) { value(50.0f) } keyframe(6000) { value(200.0f) } } } ``` ### Track Properties | Property | Type | Description | |-------------|--------------------------------|----------------------------------------------------------------------| | `ease` | `EasingType` | The easing type for interpolation between keyframes. Default: linear | | `modifier` | `EnvironmentAttributeModifier` | The environment attribute modifier ID. Default: `OVERRIDE` | | `keyframes` | `List` | A list of keyframes defining values at specific ticks | ## Keyframes Each keyframe defines a value at a specific tick within the timeline period: ```kotlin keyframe(0) { value(0.0f) } keyframe(12000) { value(100.0f) } ``` The `value` function accepts `Float`, `Int`, `Boolean`, `String`, `Color`, or any `EnvironmentAttributesType` (e.g., `FloatValue`, `BooleanValue`, `ColorValue`). Using typed values with `EnvironmentAttributesType`: ```kotlin keyframe(0) { value(RGB(255, 128, 0)) // Color value } keyframe(12000) { value(FloatValue(1.0f)) // Explicit EnvironmentAttributesType } ``` ## Time Markers Time markers are named tick positions inside a timeline. Commands can jump a clock to a marker position via `/time set `, and they appear in command auto-complete when `showInCommands` is `true`. ```kotlin dataPack.timeline("seasons", clock = seasonClock) { periodTicks = 96000 timeMarker("spring", ticks = 0, showInCommands = true) timeMarker("summer", ticks = 24000, showInCommands = true) timeMarker("autumn", ticks = 48000, showInCommands = true) timeMarker("winter", ticks = 72000, showInCommands = true) } ``` Reference a marker in a function using `TimeMarkerArgument`: ```kotlin function("skip_to_summer") { time.set(timeMarker("summer", "mymod")) } ``` See [World Clocks - Time Markers](/docs/data-driven/world-clocks#time-markers) for the full command usage. ## Easing Types Easing types control how values are interpolated between keyframes. ### Non-interpolating Types | Easing Type | Description | |-------------|-----------------------------------------------------| | `Constant` | Always selects the value from the previous keyframe | | `Linear` | Linearly interpolates between keyframes (lerp) | ### Interpolating Types Each interpolation kind is available in three forms: `In*`, `Out*`, and `InOut*`. | Kind | Ease In | Ease Out | Ease In-Out | |---------|-------------|--------------|----------------| | Back | `InBack` | `OutBack` | `InOutBack` | | Bounce | `InBounce` | `OutBounce` | `InOutBounce` | | Circ | `InCirc` | `OutCirc` | `InOutCirc` | | Cubic | `InCubic` | `OutCubic` | `InOutCubic` | | Elastic | `InElastic` | `OutElastic` | `InOutElastic` | | Expo | `InExpo` | `OutExpo` | `InOutExpo` | | Quad | `InQuad` | `OutQuad` | `InOutQuad` | | Quart | `InQuart` | `OutQuart` | `InOutQuart` | | Quint | `InQuint` | `OutQuint` | `InOutQuint` | | Sine | `InSine` | `OutSine` | `InOutSine` | ### Cubic Bezier For custom easing curves, use `CubicBezier` with two control points: ```kotlin dataPack.timeline("bezier_example", clock = dayClock) { periodTicks = 12000 track(EnvironmentAttributes.Gameplay.SKY_LIGHT_LEVEL) { ease = CubicBezier(0.25f, 0.1f, 0.25f, 1.0f) keyframe(0) { value(0) } keyframe(6000) { value(15) } } } ``` This serializes as: ```json { "ease": { "cubic_bezier": [ 0.25, 0.1, 0.25, 1.0 ] } } ``` ## Environment Attributes Tracks reference environment attributes from the `EnvironmentAttributes` sealed interface, organized into categories: - **`EnvironmentAttributes.Audio`** - Sound-related attributes (ambient sounds, music volume, etc.) - **`EnvironmentAttributes.Gameplay`** - Gameplay mechanics (monster burning, bed rules, sky light level, etc.) - **`EnvironmentAttributes.Visual`** - Visual effects (fog, clouds, sky color, particles, etc.) ## Complete Example Here's a complete example of a day/night cycle timeline: ```kotlin val dayClock = dataPack.worldClock("day") dataPack.timeline("day_night_cycle", clock = dayClock) { periodTicks = 24000 timeMarker("noon", ticks = 6000, showInCommands = true) timeMarker("midnight", ticks = 18000, showInCommands = true) track(EnvironmentAttributes.Visual.FOG_START_DISTANCE) { ease = InOutSine modifier = EnvironmentAttributeModifier.ADD keyframe(0) { value(10.0f) } keyframe(6000) { value(100.0f) } keyframe(12000) { value(100.0f) } keyframe(18000) { value(10.0f) } } track(EnvironmentAttributes.Gameplay.MONSTERS_BURN) { ease = Constant keyframe(0) { value(true) } keyframe(12000) { value(false) } } track(EnvironmentAttributes.Visual.SKY_LIGHT_FACTOR) { ease = CubicBezier(0.42f, 0.0f, 0.58f, 1.0f) keyframe(0) { value(1.0f) } keyframe(12000) { value(0.0f) } } } ``` ## See Also - [World Clocks](/docs/data-driven/world-clocks) - Clocks, time markers, the `/time` command, and `timeCheck` - [Environment Attributes](/docs/data-driven/worldgen/environment-attributes) - Environment attributes used in timeline tracks - [Tags](/docs/data-driven/tags) - Use tags to group timelines ### External Resources - [Minecraft Wiki: Timeline](https://minecraft.wiki/w/Timeline) - Official JSON format reference --- ## Trims --- root: .components.layouts.MarkdownLayout title: Trims nav-title: Trims description: Create custom armor trim materials and patterns with Kore's type-safe DSL keywords: minecraft, datapack, kore, trims, armor, trim material, trim pattern, customization date-created: 2026-02-03 date-modified: 2026-02-03 routeOverride: /docs/data-driven/trims --- # Trims Armor trims are a customization system that allows players to add decorative patterns to their armor pieces. Trims consist of two components: **materials** (which determine the color/texture) and **patterns ** (which determine the shape/design). Kore provides type-safe DSL builders for creating custom trim materials and patterns. ## Trim Materials Trim materials define the color palette and appearance when a trim is applied to armor. Each material specifies: - **Asset name**: Points to the color palette texture - **Description**: The text shown in-game when hovering over trimmed armor - **Override armor materials**: Optional per-armor-type color overrides (e.g., different colors for netherite vs. iron armor) ### Basic Usage ```kotlin trimMaterial("ruby", TrimColorPalettes.AMETHYST, textComponent("Ruby Trim")) { description("Ruby", Color.RED) } ``` This creates a trim material file at `data//trim_material/ruby.json`. ### Material with Armor Overrides Some materials look different depending on the base armor material. For example, netherite armor uses a darker variant: ```kotlin trimMaterial("custom_gold", TrimColorPalettes.GOLD, textComponent("Custom Gold")) { description("Custom Gold Trim", Color.GOLD) overrideArmorMaterial(ArmorMaterial.NETHERITE, Color.hex("4a3c2e")) } ``` You can also set multiple overrides at once: ```kotlin trimMaterial("rainbow", TrimColorPalettes.AMETHYST, textComponent("Rainbow")) { description("Rainbow Trim") overrideArmorMaterials( ArmorMaterial.IRON to Color.hex("c0c0c0"), ArmorMaterial.GOLD to Color.hex("ffd700"), ArmorMaterial.DIAMOND to Color.hex("00ffff"), ArmorMaterial.NETHERITE to Color.hex("4a4a4a") ) } ``` ### Generated JSON A trim material generates JSON like this: ```json { "asset_name": "minecraft:amethyst", "description": { "text": "Ruby", "color": "#FF0000" } } ``` With armor overrides: ```json { "asset_name": "minecraft:gold", "description": { "text": "Custom Gold Trim", "color": "gold" }, "override_armor_materials": { "netherite": "#4a3c2e" } } ``` ## Trim Patterns Trim patterns define the visual design applied to armor. Each pattern specifies: - **Asset ID**: Points to the pattern texture model - **Description**: The text shown in-game when hovering over trimmed armor - **Decal**: Whether the pattern should render as a decal overlay (like netherite patterns) ### Basic Usage ```kotlin trimPattern("stripes", Models.TRIMS_MODELS_ARMOR_COAST, textComponent("Stripes")) { description("Striped Pattern", Color.GRAY) } ``` This creates a trim pattern file at `data//trim_pattern/stripes.json`. ### Pattern as Decal Setting `decal = true` makes the pattern render as an overlay, which is useful for patterns that should appear on top of the base armor texture without replacing it (similar to how netherite trim patterns work): ```kotlin trimPattern("overlay", Models.TRIMS_MODELS_ARMOR_SENTRY, textComponent("Overlay"), decal = true) { description("Overlay Pattern") } ``` ### Generated JSON A trim pattern generates JSON like this: ```json { "asset_id": "minecraft:trims/models/armor/coast", "description": { "text": "Striped Pattern", "color": "gray" }, "decal": false } ``` With decal enabled: ```json { "asset_id": "minecraft:trims/models/armor/sentry", "description": { "text": "Overlay Pattern" }, "decal": true } ``` ## See Also - [Chat Components](/docs/concepts/chat-components) - For trim description text formatting - [Tags](/docs/data-driven/tags) - Organize trim materials and patterns into groups ### External Resources - [Minecraft Wiki: Tutorial - Adding custom trims](https://minecraft.wiki/w/Tutorial:Adding_custom_trims) - Official guide for creating custom trims - [Minecraft Wiki: Armor - Trimming](https://minecraft.wiki/w/Armor#Trimming) - Information about armor trimming mechanics --- ## Variants --- root: .components.layouts.MarkdownLayout title: Variants nav-title: Variants description: Define entity and painting variants with Kore's type-safe DSL keywords: minecraft, datapack, kore, variants, cat, cow, chicken, frog, pig, wolf, zombie nautilus, painting, sound variants date-created: 2026-02-03 date-modified: 2026-06-26 routeOverride: /docs/data-driven/variants --- # Variants Variants allow you to customize the appearance and spawn conditions of various entities and paintings in Minecraft. Kore provides type-safe DSL builders for creating custom variants for cats, cows, chickens, frogs, pigs, wolves, zombie nautiluses, and paintings. ## Entity Variants ### Spawn Conditions Most entity variants support spawn conditions that control when and where the variant appears. Available condition types: - **add(priority)**: Base condition with just a priority - **biome(priority, biomes...)**: Spawn in specific biomes or biome tags - **moonBrightness(priority, value)**: Spawn based on moon brightness (single value) - **moonBrightness(priority, min, max)**: Spawn based on moon brightness (range) - **structures(priority, structures...)**: Spawn near specific structures or structure tags Higher priority values take precedence when multiple conditions match. ### Cat Variants Cat variants define the texture and spawn conditions for cats. You can specify biomes, moon brightness, and structures as spawn conditions. ```kotlin catVariant("test_cat_variant", Textures.Entity.Cat.TABBY) { spawnConditions { add(10) biome(5, Biomes.PLAINS) biome(2, Tags.Worldgen.Biome.IS_OVERWORLD) moonBrightness(1, 1.0) moonBrightness(1, 0.5, 0.75) structures(0, ConfiguredStructures.VILLAGE_PLAINS) } } ``` Produces JSON: ```json { "asset_id": "minecraft:entity/cat/tabby", "spawn_conditions": [ { "priority": 10 }, { "priority": 5, "condition": { "type": "minecraft:biome", "biomes": "minecraft:plains" } }, { "priority": 2, "condition": { "type": "minecraft:biome", "biomes": "#minecraft:is_overworld" } }, { "priority": 1, "condition": { "type": "minecraft:moon_brightness", "range": 1.0 } }, { "priority": 1, "condition": { "type": "minecraft:moon_brightness", "range": { "min": 0.5, "max": 0.75 } } }, { "priority": 0, "condition": { "type": "minecraft:structure", "structures": "minecraft:village_plains" } } ] } ``` ### Cow Variants Cow variants define the texture, model, and spawn conditions for cows. ```kotlin cowVariant("test_cow_variant", Textures.Entity.Cow.COLD_COW, CowModel.COLD) { spawnConditions { structures(0, Tags.Worldgen.Structure.MINESHAFT) } } ``` Produces JSON: ```json { "asset_id": "minecraft:entity/cow/cold_cow", "model": "cold", "spawn_conditions": [ { "priority": 0, "condition": { "type": "minecraft:structure", "structures": "#minecraft:mineshaft" } } ] } ``` ### Chicken Variants Chicken variants define the texture, model, and spawn conditions for chickens. ```kotlin chickenVariant("test_chicken_variant", Textures.Entity.Chicken.TEMPERATE_CHICKEN, ChickenModel.NORMAL) { spawnConditions { structures(0, Tags.Worldgen.Structure.VILLAGE) } } ``` Produces JSON: ```json { "asset_id": "minecraft:entity/chicken/temperate_chicken", "model": "normal", "spawn_conditions": [ { "priority": 0, "condition": { "type": "minecraft:structure", "structures": "#minecraft:village" } } ] } ``` ### Frog Variants Frog variants define the texture and spawn conditions for frogs. ```kotlin frogVariant("test_frog_variant", Textures.Entity.Frog.TEMPERATE_FROG) { spawnConditions { add(10) biome(5, Biomes.SNOWY_PLAINS) biome(2, Tags.Worldgen.Biome.SPAWNS_COLD_VARIANT_FROGS) moonBrightness(1, 1.0) moonBrightness(1, 0.5, 0.75) structures(0, ConfiguredStructures.END_CITY) } } ``` Produces JSON: ```json { "asset_id": "minecraft:entity/frog/temperate_frog", "spawn_conditions": [ { "priority": 10 }, { "priority": 5, "condition": { "type": "minecraft:biome", "biomes": "minecraft:snowy_plains" } }, { "priority": 2, "condition": { "type": "minecraft:biome", "biomes": "#minecraft:spawns_cold_variant_frogs" } }, { "priority": 1, "condition": { "type": "minecraft:moon_brightness", "range": 1.0 } }, { "priority": 1, "condition": { "type": "minecraft:moon_brightness", "range": { "min": 0.5, "max": 0.75 } } }, { "priority": 0, "condition": { "type": "minecraft:structure", "structures": "minecraft:end_city" } } ] } ``` ### Pig Variants Pig variants define the texture, model, and spawn conditions for pigs. ```kotlin pigVariant("test_pig_variant", Textures.Entity.Pig.COLD_PIG, PigModel.COLD) { spawnConditions { structures(0, Tags.Worldgen.Structure.ON_TREASURE_MAPS) } } ``` Produces JSON: ```json { "asset_id": "minecraft:entity/pig/cold_pig", "model": "cold", "spawn_conditions": [ { "priority": 0, "condition": { "type": "minecraft:structure", "structures": "#minecraft:on_treasure_maps" } } ] } ``` ### Wolf Variants Wolf variants define separate textures for angry, tame, and wild states, along with spawn conditions. ```kotlin wolfVariant("test_wolf_variant") { assets( angry = Textures.Entity.Wolf.WOLF_STRIPED, tame = Textures.Entity.Wolf.WOLF_RUSTY_ANGRY, wild = Textures.Entity.Wolf.WOLF_BLACK, ) spawnConditions { biome(5, Biomes.OCEAN, Biomes.SNOWY_SLOPES) } } ``` Produces JSON: ```json { "assets": { "angry": "minecraft:entity/wolf/wolf_striped", "tame": "minecraft:entity/wolf/wolf_rusty_angry", "wild": "minecraft:entity/wolf/wolf_black" }, "spawn_conditions": [ { "priority": 5, "condition": { "type": "minecraft:biome", "biomes": [ "minecraft:ocean", "minecraft:snowy_slopes" ] } } ] } ``` ### Zombie Nautilus Variants Zombie nautilus variants define the texture, model, and spawn conditions for zombie nautiluses. ```kotlin zombieNautilusVariant("test_zombie_nautilus_variant", Textures.Entity.Nautilus.ZOMBIE_NAUTILUS_CORAL, ZombieNautilusModel.WARM) { spawnConditions { structures(0, Tags.Worldgen.Structure.ON_TREASURE_MAPS) } } ``` Produces JSON: ```json { "asset_id": "minecraft:entity/nautilus/zombie_nautilus_coral", "model": "warm", "spawn_conditions": [ { "priority": 0, "condition": { "type": "minecraft:structure", "structures": "#minecraft:on_treasure_maps" } } ] } ``` ## Sound Variants ### Cat Sound Variants Cat sound variants define custom sounds for cats. Sounds are split into `adultSounds` (required) and `babySounds` ( optional - falls back to `adultSounds` when absent). ```kotlin catSoundVariant("funny") { adultSounds { ambientSound = SoundEvents.Entity.Cat.AMBIENT begForFoodSound = SoundEvents.Entity.Cat.BEG_FOR_FOOD deathSound = SoundEvents.Entity.Cat.DEATH eatSound = SoundEvents.Entity.Cat.EAT hissSound = SoundEvents.Entity.Cat.HISS hurtSound = SoundEvents.Entity.Cat.HURT purreowSound = SoundEvents.Entity.Cat.PURREOW purrSound = SoundEvents.Entity.Cat.PURR strayAmbientSound = SoundEvents.Entity.Cat.STRAY_AMBIENT } } ``` Produces JSON: ```json { "adult_sounds": { "ambient_sound": "minecraft:entity.cat.ambient", "beg_for_food_sound": "minecraft:entity.cat.beg_for_food", "death_sound": "minecraft:entity.cat.death", "eat_sound": "minecraft:entity.cat.eat", "hiss_sound": "minecraft:entity.cat.hiss", "hurt_sound": "minecraft:entity.cat.hurt", "purreow_sound": "minecraft:entity.cat.purreow", "purr_sound": "minecraft:entity.cat.purr", "stray_ambient_sound": "minecraft:entity.cat.stray_ambient" } } ``` ### Chicken Sound Variants Chicken sound variants define custom sounds for chickens. Sounds are split into `adultSounds` (required) and `babySounds` (optional - falls back to `adultSounds` when absent). ```kotlin chickenSoundVariant("clucky") { adultSounds { ambientSound = SoundEvents.Entity.Chicken.AMBIENT deathSound = SoundEvents.Entity.Chicken.DEATH hurtSound = SoundEvents.Entity.Chicken.HURT stepSound = SoundEvents.Entity.Chicken.STEP } } ``` Produces JSON: ```json { "adult_sounds": { "ambient_sound": "minecraft:entity.chicken.ambient", "death_sound": "minecraft:entity.chicken.death", "hurt_sound": "minecraft:entity.chicken.hurt", "step_sound": "minecraft:entity.chicken.step" } } ``` ### Cow Sound Variants Cow sound variants define custom sounds for cows. Unlike other sound variants, cows use a flat structure without age-group nesting. ```kotlin cowSoundVariant("moody") { ambientSound = SoundEvents.Entity.Cow.AMBIENT deathSound = SoundEvents.Entity.Cow.DEATH hurtSound = SoundEvents.Entity.Cow.HURT stepSound = SoundEvents.Entity.Cow.STEP } ``` Produces JSON: ```json { "ambient_sound": "minecraft:entity.cow.ambient", "death_sound": "minecraft:entity.cow.death", "hurt_sound": "minecraft:entity.cow.hurt", "step_sound": "minecraft:entity.cow.step" } ``` ### Pig Sound Variants Pig sound variants define custom sounds for pigs. Sounds are split into `adultSounds` (required) and `babySounds` ( optional - falls back to `adultSounds` when absent). ```kotlin pigSoundVariant("oinking") { adultSounds { ambientSound = SoundEvents.Entity.Pig.AMBIENT deathSound = SoundEvents.Entity.Pig.DEATH eatSound = SoundEvents.Entity.Pig.AMBIENT hurtSound = SoundEvents.Entity.Pig.HURT stepSound = SoundEvents.Entity.Pig.STEP } } ``` Produces JSON: ```json { "adult_sounds": { "ambient_sound": "minecraft:entity.pig.ambient", "death_sound": "minecraft:entity.pig.death", "eat_sound": "minecraft:entity.pig.ambient", "hurt_sound": "minecraft:entity.pig.hurt", "step_sound": "minecraft:entity.pig.step" } } ``` ### Wolf Sound Variants Wolf sound variants define custom sounds for wolves. Sound variants are independent of color variants and spawning biome. Wolves will make the sounds associated with their variant when they bark, pant, whine, growl, die, or get hurt. Sounds are split into two groups: `adultSounds` (required) and `babySounds` (optional - falls back to `adultSounds` when absent). ```kotlin wolfSoundVariant("funny") { adultSounds { ambientSound = SoundEvents.Entity.Pig.AMBIENT deathSound = SoundEvents.Entity.Creeper.DEATH growlSound = SoundEvents.Entity.Player.LEVELUP hurtSound = SoundEvents.Entity.Zombie.HURT pantSound = SoundEvents.Entity.EnderDragon.FLAP whineSound = SoundEvents.Entity.Cat.PURR } } ``` Produces JSON: ```json { "adult_sounds": { "ambient_sound": "minecraft:entity.pig.ambient", "death_sound": "minecraft:entity.creeper.death", "growl_sound": "minecraft:entity.player.levelup", "hurt_sound": "minecraft:entity.zombie.hurt", "pant_sound": "minecraft:entity.ender_dragon.flap", "whine_sound": "minecraft:entity.cat.purr" } } ``` With separate baby sounds: ```kotlin wolfSoundVariant("funny") { adultSounds { ambientSound = SoundEvents.Entity.Wolf.AMBIENT deathSound = SoundEvents.Entity.Wolf.DEATH growlSound = SoundEvents.Entity.Wolf.GROWL hurtSound = SoundEvents.Entity.Wolf.HURT pantSound = SoundEvents.Entity.Wolf.PANT whineSound = SoundEvents.Entity.Wolf.WHINE } babySounds { ambientSound = SoundEvents.Entity.Pig.AMBIENT deathSound = SoundEvents.Entity.Pig.DEATH hurtSound = SoundEvents.Entity.Pig.HURT } } ``` Produces JSON: ```json { "adult_sounds": { "ambient_sound": "minecraft:entity.wolf.ambient", "death_sound": "minecraft:entity.wolf.death", "growl_sound": "minecraft:entity.wolf.growl", "hurt_sound": "minecraft:entity.wolf.hurt", "pant_sound": "minecraft:entity.wolf.pant", "whine_sound": "minecraft:entity.wolf.whine" }, "baby_sounds": { "ambient_sound": "minecraft:entity.pig.ambient", "death_sound": "minecraft:entity.pig.death", "growl_sound": "minecraft:entity.wolf.growl", "hurt_sound": "minecraft:entity.pig.hurt", "pant_sound": "minecraft:entity.wolf.pant", "whine_sound": "minecraft:entity.wolf.whine" } } ``` ## Other Variants ### Painting Variants Painting variants define custom paintings with dimensions and optional metadata like author and title. ```kotlin // Basic painting variant paintingVariant( assetId = Textures.Painting.KEBAB, height = 16, width = 16 ) ``` Produces JSON: ```json { "asset_id": "minecraft:kebab", "height": 16, "width": 16 } ``` With default dimensions (1x1): ```kotlin paintingVariant( assetId = Textures.Painting.AZTEC ) ``` Produces JSON: ```json { "asset_id": "minecraft:aztec", "height": 1, "width": 1 } ``` With author and title: ```kotlin paintingVariant( assetId = Textures.Painting.AZTEC, ) { author = textComponent("Ayfri") title = textComponent("Aztec") } ``` Produces JSON: ```json { "asset_id": "minecraft:aztec", "height": 1, "width": 1, "author": "Ayfri", "title": "Aztec" } ``` ### See Also - [Chat Components](/docs/concepts/chat-components) - For painting title and author text formatting - [Tags](/docs/data-driven/tags) - Use variant tags for spawn conditions --- ## Villager Trades - Custom Trade Sets & Merchant Tables in Kore --- root: .components.layouts.MarkdownLayout title: Villager Trades - Custom Trade Sets & Merchant Tables in Kore nav-title: Villager Trades description: Define custom villager trades and trade sets for Minecraft 26.1+ with Kore's type-safe Kotlin DSL. Configure items, prices, demand, and profession-level trade tables without hand-writing JSON. keywords: minecraft villager trade, custom villager trades, datapack trade_set, datapack villager_trade, kore villager trades, minecraft merchant trades, custom trades datapack, profession trades, villager trade generator date-created: 2026-06-15 date-modified: 2026-06-15 routeOverride: /docs/data-driven/villager-trades --- # Villager Trades Villager trades are data-driven JSON files introduced in Minecraft Java Edition 26.1 that define what individual trades a villager can offer and how they are grouped into trade sets per profession level. This system fully replaces the old hardcoded trade lists and lets data packs control everything about villager economies - what items are bought and sold, at what quantities, for how many uses, with what item modifier functions applied to the output, and under what conditions. ## Overview The trade system uses two file types that work together: - **`villager_trade`** - a single trade offer: inputs the villager wants, the output it gives, limits, and rewards. - **`trade_set`** - a pool of `villager_trade` references that Minecraft samples from when a villager gains a level. A villager profession's trade list is built from a stack of trade sets, one per level. Each time a villager levels up, Minecraft draws `amount` trades at random from the appropriate trade set. ## File Structure ``` data//villager_trade/.json data//trade_set/.json ``` For the full JSON specification see: - [Minecraft Wiki: Villager trade definition](https://minecraft.wiki/w/Villager_trade_definition) - [Minecraft Wiki: Trade set definition](https://minecraft.wiki/w/Trade_set_definition) --- ## Villager Trade ### Creating a Trade Use `villagerTrade` on your `DataPack`. Call `wants` and `gives` inside the block to set the required items - both accept an `ItemArgument`, an optional fixed `count`, and an optional component builder. ```kotlin datapack.villagerTrade("wheat_for_emerald") { wants(Items.WHEAT, count = 20) gives(Items.EMERALD) maxUses = constant(12f) xp = constant(1f) } ``` ### Item Slots `wants`, `gives`, and `additionalWants` all follow the same shape: an item id, an optional stack size, and an optional block to set data components on the item. ```kotlin datapack.villagerTrade("enchanted_sword") { wants(Items.EMERALD, count = 30) gives(Items.DIAMOND_SWORD) { enchantments { add(Enchantments.SHARPNESS, 5) } } maxUses = constant(3f) xp = constant(30f) } ``` Two-input trades use `additionalWants` for the second slot: ```kotlin datapack.villagerTrade("book_trade") { wants(Items.EMERALD, count = 5) additionalWants(Items.BOOK) gives(Items.ENCHANTED_BOOK) maxUses = constant(1f) xp = constant(15f) } ``` ### VillagerTrade Fields All fields are optional except `wants` and `gives`, which must be set before the data pack is generated. | Field | Type | Description | |--------------------------------|--------------------------------------------|-----------------------------------------------------------------------------------| | `additionalWants` | `ItemStack?` | Second item slot the villager requests alongside `wants`. | | `doubleTradePriceEnchantments` | `InlinableList?` | Enchantments on the player's item that double the trade cost. | | `givenItemModifiers` | `ItemModifierAsList?` | Item modifier functions applied to the output item before delivery. | | `gives` | `ItemStack?` | Item the villager offers in return. **Required.** | | `maxUses` | `NumberProvider?` | Maximum uses before the trade locks. Unlocks when the villager restocks. | | `merchantPredicate` | `PredicateCondition?` | Condition checked against the merchant entity; trade only appears when it passes. | | `reputationDiscount` | `NumberProvider?` | Price multiplier applied based on the player's village reputation. | | `wants` | `ItemStack?` | Primary item the villager requests. **Required.** | | `xp` | `NumberProvider?` | XP points awarded to the villager when the trade completes. | ### Applying Item Modifiers to the Output Use `givenItemModifiers` to run item modifier functions on the item the villager gives. This is how you add random enchantments, custom lore, or any other post-processing: ```kotlin datapack.villagerTrade("random_enchanted_book") { wants(Items.EMERALD, count = 10) additionalWants(Items.BOOK) gives(Items.ENCHANTED_BOOK) givenItemModifiers { enchantRandomly() } maxUses = constant(1f) xp = constant(15f) } ``` See [Item Modifiers](/docs/data-driven/item-modifiers) for all available functions. ### Gating a Trade with a Predicate `merchantPredicate` is a condition evaluated against the villager entity. The trade only appears in the merchant's offer list when the condition passes - useful for biome-locked or NBT-gated trades. ```kotlin datapack.villagerTrade("desert_trade") { wants(Items.SAND, count = 8) gives(Items.GLASS) merchantPredicate = LocationCheck(predicate = LocationPredicate(biomes = listOf(Biomes.DESERT))) maxUses = constant(16f) xp = constant(2f) } ``` See [Predicates](/docs/data-driven/predicates) for all available condition types. ### Double-Price Enchantments `doubleTradePriceEnchantments` lists enchantments that, when present on the player's traded-in item, cause the villager to charge twice as much. Vanilla uses this for the `Curse of Binding` and similar effects. ```kotlin doubleTradePriceEnchantments = listOf(Enchantments.BINDING_CURSE) ``` --- ## Trade Set ### Creating a Trade Set A `TradeSet` groups references to `villager_trade` files and controls how many are offered per level. Pass the list of trade references (returned by `villagerTrade`) and an `amount` provider: ```kotlin val wheatTrade = datapack.villagerTrade("wheat_for_emerald") { wants(Items.WHEAT, count = 20) gives(Items.EMERALD) xp = constant(1f) } val potatoTrade = datapack.villagerTrade("potato_for_emerald") { wants(Items.POTATO, count = 26) gives(Items.EMERALD) xp = constant(1f) } datapack.tradeSet( "novice_farmer", trades = listOf(wheatTrade, potatoTrade), amount = constant(2f), ) ``` ### Sampling with Tags You can mix individual trade references with tag references in the same pool: ```kotlin datapack.tradeSet( "apprentice_farmer", trades = listOf( VillagerTradeTagArgument("farmer_apprentice", "mymod"), myCustomTrade, ), amount = uniform(constant(1f), constant(3f)), ) { allowDuplicates = false } ``` ### TradeSet Fields | Field | Type | Description | |-------------------|---------------------------------------------|--------------------------------------------------------------------| | `allowDuplicates` | `Boolean?` | Whether the same trade can be drawn more than once per level-up. | | `amount` | `NumberProvider` | How many trades are drawn from this set when a villager levels up. | | `randomSequence` | `RandomSequenceArgument?` | Named random sequence for reproducible sampling. | | `trades` | `InlinableList` | Trade references or tags to sample from. | --- ## Full Example: Custom Farmer Profession Level 1 ```kotlin datapack { val hayTrade = villagerTrade("hay_for_emerald") { wants(Items.HAY_BLOCK, count = 1) gives(Items.EMERALD) maxUses = constant(16f) xp = constant(2f) } val wheatTrade = villagerTrade("wheat_for_emerald") { wants(Items.WHEAT, count = 20) gives(Items.EMERALD) maxUses = constant(16f) xp = constant(1f) } val breadTrade = villagerTrade("emerald_for_bread") { wants(Items.EMERALD) gives(Items.BREAD, count = 6) maxUses = constant(16f) xp = constant(1f) } tradeSet( "custom_farmer_novice", trades = listOf(hayTrade, wheatTrade, breadTrade), amount = constant(2f), ) { allowDuplicates = false } } ``` --- ## See Also - [Item Modifiers](/docs/data-driven/item-modifiers) - Apply functions to the item a villager gives - [Predicates](/docs/data-driven/predicates) - Gate trade availability via `merchantPredicate` - [Enchantments](/docs/data-driven/enchantments) - `doubleTradePriceEnchantments` and enchanting trade outputs - [Tags](/docs/data-driven/tags) - Group trades into reusable `villager_trade` tags for trade sets - [Loot Tables](/docs/data-driven/loot-tables) - Related data-driven item generation system ### External Resources - [Minecraft Wiki: Villager trade definition](https://minecraft.wiki/w/Villager_trade_definition) - [Minecraft Wiki: Trade set definition](https://minecraft.wiki/w/Trade_set_definition) - [Minecraft Wiki: Trading](https://minecraft.wiki/w/Trading) - How the vanilla trading system works - [Minecraft Wiki: Villager](https://minecraft.wiki/w/Villager) - Villager behavior, professions, and leveling --- ## World Clocks - Custom Time Systems & TimeCheck Predicates in Kore --- root: .components.layouts.MarkdownLayout title: World Clocks - Custom Time Systems & TimeCheck Predicates in Kore nav-title: World Clocks description: Create custom world clocks and timelines in Kore datapacks. Define named time counters, time markers, timeCheck predicates, and control the /time command. Integrates with dimension types and environment timelines. keywords: minecraft world_clock, timeCheck predicate, custom time system datapack, datapack timeline, time marker minecraft, kore world clock, dimension_type clock, datapack time command, minecraft time counter date-created: 2026-06-16 date-modified: 2026-06-16 routeOverride: /docs/data-driven/world-clocks --- # World Clocks Minecraft's time system is built around **world clocks** - named counters that advance every tick. Timelines animate environment attributes by reading from a clock. The `/time` command lets you read and manipulate clocks at runtime. Time markers are named tick positions inside a timeline that commands and predicates can reference. All of these features were introduced alongside the environment-attributes overhaul in snapshot **26.1** and are fully supported in Kore's type-safe Kotlin DSL. --- ## World Clock A world clock is a data-driven resource with no properties. Its mere existence registers a named ticker under `data//world_clock/.json`. ```kotlin val dayClock = dataPack.worldClock("day") val seasonClock = dataPack.worldClock("season") ``` Each call registers the clock and returns a `WorldClockArgument` that you can pass to timelines, dimension types, and `/time of` commands. ### File Structure ``` data//world_clock/.json ``` The generated JSON is an empty object: ```json {} ``` --- ## Timelines Timelines animate environment attributes by reading from a `WorldClockArgument`. Every track is a keyframe curve tied to one attribute; the timeline drives it forward as the clock ticks. ### Creating a Timeline ```kotlin val dayClock = dataPack.worldClock("day") val dayNight = dataPack.timeline("day_night", clock = dayClock) { periodTicks = 24000 track(EnvironmentAttributes.Visual.FOG_START_DISTANCE) { ease = Linear keyframe(0) { value(10.0f) } keyframe(6000) { value(100.0f) } keyframe(18000) { value(10.0f) } keyframe(24000) { value(10.0f) } } track(EnvironmentAttributes.Gameplay.MONSTERS_BURN) { ease = Constant keyframe(0) { value(true) } keyframe(12000) { value(false) } } } ``` `timeline()` produces `data//timeline/.json` and returns a `TimelineArgument`. ### Timeline Properties | Property | Type | Description | |---------------|-----------------------------------------------------------------|-------------------------------------------------------------------------------| | `clock` | `WorldClockArgument` | **Required.** Clock this timeline reads from. | | `periodTicks` | `Int?` | Loop period in ticks. Omit for a one-shot timeline that runs to the end. | | `timeMarkers` | `Map?` | Named tick positions inside this timeline. See [Time Markers](#time-markers). | | `tracks` | `Map?` | Attribute animations. | ### Tracks Each `track()` call maps an `EnvironmentAttributeArgument` to an animation curve: ```kotlin track(EnvironmentAttributes.Visual.SKY_LIGHT_FACTOR) { ease = CubicBezier(0.42f, 0.0f, 0.58f, 1.0f) modifier = EnvironmentAttributeModifier.OVERRIDE keyframe(0) { value(1.0f) } keyframe(12000) { value(0.0f) } } ``` The `value()` function inside a keyframe block accepts `Float`, `Int`, `Boolean`, `String`, `Color`, or any `EnvironmentAttributesType`. ### Easing Types | Type | Description | |---------------|------------------------------------------------------| | `Constant` | Holds the previous keyframe value until the next one | | `Linear` | Straight lerp between keyframes | | `CubicBezier` | Custom four-point Bézier curve | Interpolating variants are available as `In*`, `Out*`, and `InOut*` for: `Back`, `Bounce`, `Circ`, `Cubic`, `Elastic`, `Expo`, `Quad`, `Quart`, `Quint`, `Sine`. --- ## Time Markers Time markers are named tick positions inside a timeline. Commands can target them with `/time set ` to jump the clock to that exact position. They also serve as human-readable labels for `/time query`. ### Defining Time Markers ```kotlin dataPack.timeline("seasons", clock = seasonClock) { periodTicks = 96000 // 4 × 24000 - one in-game "year" timeMarker("spring", ticks = 0) timeMarker("summer", ticks = 24000) timeMarker("autumn", ticks = 48000) timeMarker("winter", ticks = 72000, showInCommands = true) } ``` `showInCommands` controls whether the marker appears in command auto-complete suggestions. When omitted (or `null`), the default game behaviour applies. ### Referencing a Time Marker in Commands Use `TimeMarkerArgument` (or the `timeMarker()` factory) to pass a marker to `/time set`: ```kotlin function("skip_to_summer") { time.set(timeMarker("summer", "mymod")) } ``` ```kotlin function("skip_to_summer_on_clock") { time.of(seasonClock).set(timeMarker("summer", "mymod")) } ``` --- ## The `/time` Command Kore's `time` DSL mirrors the full Minecraft `/time` command tree. Access it via the `time` property on any `Function`: ```kotlin function("my_func") { time.add(1000) time.set(TimePeriod.NOON) time.query(TimeType.DAYTIME) } ``` ### Subcommands | DSL call | Emitted command | Effect | |--------------------------------|------------------------------------|-----------------------------------------------| | `time.add(1000)` | `time add 1000` | Advance the default clock by 1000 ticks | | `time.add(1.days)` | `time add 1d` | Advance by one full day | | `time.pause()` | `time pause` | Freeze the default clock | | `time.resume()` | `time resume` | Unfreeze the default clock | | `time.set(6000)` | `time set 6000` | Jump to tick 6000 | | `time.set(TimePeriod.NOON)` | `time set noon` | Jump to noon | | `time.set(marker)` | `time set :` | Jump to a named time marker | | `time.query(TimeType.DAYTIME)` | `time query daytime` | Output current daytime | | `time.query(timeline)` | `time query :` | Output progress through a timeline | | `time.queryRepetitions(tl)` | `time query : repetitions` | Output how many times the timeline has looped | | `time.queryTime()` | `time query time` | Output absolute game time | ### Targeting a Specific Clock with `time.of(clock)` When your datapack defines multiple world clocks, use `time.of(clock)` to scope every subcommand to that specific clock: ```kotlin function("advance_season") { time.of(seasonClock).add(6000) time.of(seasonClock).set(timeMarker("summer", "mymod")) time.of(seasonClock).query(TimeType.DAYTIME) } ``` Or use the builder form to avoid repeating `of(seasonClock)`: ```kotlin function("advance_season") { val seasonTime = time.of(seasonClock) seasonTime.add(6000) seasonTime.query(TimeType.DAYTIME) } ``` `time.of(clock)` returns a `TimeWithClock` instance. It supports the same `add`, `pause`, `resume`, `set`, `query`, `queryRepetitions`, and `queryTime` methods as the default `Time` DSL. --- ## `timeCheck` Predicate Condition The `timeCheck` condition passes when the queried world time falls within a specified range. The optional `clock` parameter selects which clock to query; it defaults to the standard day clock. ```kotlin predicate("is_daytime") { timeCheck(value = 0f..12000f) } ``` Pass a `period` to apply a modulo first - useful for checking time within a repeating sub-cycle: ```kotlin predicate("is_second_quarter") { timeCheck(min = 6000f, max = 12000f, period = 24000) } ``` Target a specific world clock: ```kotlin predicate("is_summer") { timeCheck(min = 24000f, max = 48000f, clock = seasonClock) } ``` See [Predicates](/docs/data-driven/predicates) for the full condition reference. --- ## `defaultClock` in Dimension Type `DimensionType` has an optional `defaultClock` field that selects which world clock drives the dimension's default time-dependent behaviour (sunrise/sunset, mob spawning light threshold, etc.). When omitted, the standard overworld day clock is used. ```kotlin dataPack.dimensionType("twilight_dimension") { defaultClock = dayClock hasSkylight = true natural = true logicalHeight = 256 infiniburn = Tags.Block.INFINIBURN_OVERWORLD minY = -64 height = 384 monsterSpawnBlockLightLimit = 0 monsterSpawnLightLevel = constant(0) } ``` See [World Generation](/docs/data-driven/worldgen) for the full `DimensionType` reference. --- ## Complete Example The following snippet wires together all the concepts in this guide: ```kotlin dataPack("my_mod") { // 1. Register a custom clock val season = worldClock("season") // 2. Build a timeline driven by that clock timeline("seasons", clock = season) { periodTicks = 96000 timeMarker("spring", ticks = 0, showInCommands = true) timeMarker("summer", ticks = 24000, showInCommands = true) timeMarker("autumn", ticks = 48000, showInCommands = true) timeMarker("winter", ticks = 72000, showInCommands = true) track(EnvironmentAttributes.Visual.FOG_END_DISTANCE) { ease = InOutSine keyframe(0) { value(200.0f) } keyframe(24000) { value(300.0f) } keyframe(48000) { value(200.0f) } keyframe(72000) { value(80.0f) } } } // 3. Wire the clock to a custom dimension val dimType = dimensionType("my_dimension_type") { defaultClock = season natural = true hasSkylight = true logicalHeight = 256 infiniburn = Tags.Block.INFINIBURN_OVERWORLD minY = -64 height = 384 monsterSpawnBlockLightLimit = 0 monsterSpawnLightLevel = constant(0) } // 4. Predicate: is it currently summer? predicate("is_summer") { timeCheck(min = 24000f, max = 48000f, clock = season) } // 5. Command: skip to winter function("skip_to_winter") { time.of(season).set(timeMarker("winter", "my_mod")) } // 6. Command: advance the season clock function("tick_season") { time.of(season).add(1) time.of(season).query(TimeType.DAYTIME) } } ``` --- ## See Also - [Timelines](/docs/data-driven/timelines) - detailed track, keyframe, and easing reference - [Predicates](/docs/data-driven/predicates) - all available predicate conditions including `timeCheck` - [World Generation](/docs/data-driven/worldgen) - `DimensionType` and other worldgen resources - [Environment Attributes](/docs/data-driven/worldgen/environment-attributes) - attributes available in timeline tracks ### External Resources - [Minecraft Wiki: World clock](https://minecraft.wiki/w/World_clock) - [Minecraft Wiki: Timeline](https://minecraft.wiki/w/Timeline) - [Minecraft Wiki: Commands/time](https://minecraft.wiki/w/Commands/time) - [Minecraft Wiki: Predicate - time_check](https://minecraft.wiki/w/Predicate#time_check) --- ## Minecraft World Generation - Custom Dimensions, Biomes & Noise with Kore --- root: .components.layouts.MarkdownLayout title: Minecraft World Generation - Custom Dimensions, Biomes & Noise with Kore nav-title: Worldgen description: Create custom world generation datapacks with Kore's Kotlin DSL. Dimensions, biomes, noise settings, density functions, structures, features, and world presets -- all type-safe, no hand-written JSON. keywords: minecraft worldgen, datapack worldgen, custom dimension minecraft, custom biome, noise settings minecraft, minecraft noise router, density function, datapack terrain generation, minecraft world preset, custom world generation date-created: 2025-08-11 date-modified: 2026-07-02 routeOverride: /docs/data-driven/worldgen --- # World Generation This guide covers custom world generation using Kore's Kotlin DSL. It maps common datapack JSON files to concise Kotlin builders. ## What is World Generation? World generation (worldgen) is the procedural generation process Minecraft uses to algorithmically generate terrain, biomes, features, and structures. Because there are over 18 quintillion (2⁶⁴) possible worlds, the game generates them using randomness, algorithms, and some manually built decorations. The generation process uses **gradient noise algorithms** (like Perlin noise) to ensure terrain has both continuity and randomness. Multiple noise functions with different frequencies and amplitudes (called **octaves**) are combined to create natural-looking variation with hills, valleys, and other terrain features. See [World generation](https://minecraft.wiki/w/World_generation) for the full technical breakdown. ## Generation Steps Minecraft generates chunks through multiple sequential steps. Incomplete chunks are called **proto-chunks**, while fully generated chunks accessible to players are **level chunks**: 1. **structures_starts** - Calculate starting points for structure pieces 2. **structures_references** - Store references to nearby structure starts 3. **biomes** - Determine and store biomes (no terrain yet) 4. **noise** - Generate base terrain shape and liquid bodies 5. **surface** - Replace terrain surface with biome-dependent blocks 6. **carvers** - Carve caves and canyons 7. **features** - Place features, structures, and generate heightmaps 8. **light** - Calculate light levels for all blocks 9. **spawn** - Spawn initial mobs 10. **full** - Generation complete, proto-chunk becomes level chunk Reference: [World generation steps](https://minecraft.wiki/w/World_generation#Steps) ## Documentation Structure World generation is split into focused pages: - [**Biomes**](/docs/data-driven/worldgen/biomes) - Climate, visuals, mob spawns, carvers, and feature lists - [**Dimensions**](/docs/data-driven/worldgen/dimensions) - Dimensions and dimension types - [**Environment Attributes**](/docs/data-driven/worldgen/environment-attributes) - Visual, audio, and gameplay attributes for biomes and dimensions - [**Features**](/docs/data-driven/worldgen/features) - Configured and placed features (trees, ores, vegetation) - [**Noise & Terrain**](/docs/data-driven/worldgen/noise) - Density functions, noise definitions, and noise settings - [**Structures**](/docs/data-driven/worldgen/structures) - Structures, template pools, processors, and structure sets - [**World Presets**](/docs/data-driven/worldgen/world-presets) - World presets and flat level generator presets ## Decoration Steps Minecraft runs 11 decoration steps in order for each chunk; structures of a step place before features in that step. | Step | Name | Examples | |------|--------------------------|---------------------------------------------| | 1 | `raw_generation` | Small end islands | | 2 | `lakes` | Lava lakes | | 3 | `local_modifications` | Geodes, icebergs | | 4 | `underground_structures` | Trial chambers, mineshafts | | 5 | `surface_structures` | Desert wells, blue ice patches | | 6 | `strongholds` | Unused (strongholds use surface_structures) | | 7 | `underground_ores` | Ore blobs, sand/gravel/clay disks | | 8 | `underground_decoration` | Infested blobs, nether gravel/blackstone | | 9 | `fluid_springs` | Water/lava springs | | 10 | `vegetal_decoration` | Trees, cacti, kelp, vegetation | | 11 | `top_layer_modification` | Freeze top layer | Reference: [Decoration steps](https://minecraft.wiki/w/World_Generation#Decoration_steps) ## Output Paths Kore APIs generate JSON under standard datapack directories (replace `` with your namespace): | API | Output Path | |---------------------------------|--------------------------------------------------------------| | `biome(...)` | `data//worldgen/biome/.json` | | `configuredCarver(...)` | `data//worldgen/configured_carver/.json` | | `configuredFeature(...)` | `data//worldgen/configured_feature/.json` | | `densityFunction(...)` | `data//worldgen/density_function/.json` | | `dimension(...)` | `data//dimension/.json` | | `dimensionType(...)` | `data//dimension_type/.json` | | `flatLevelGeneratorPreset(...)` | `data//worldgen/flat_level_generator_preset/.json` | | `noise(...)` | `data//worldgen/noise/.json` | | `noiseSettings(...)` | `data//worldgen/noise_settings/.json` | | `processorList(...)` | `data//worldgen/processor_list/.json` | | `structureSet(...)` | `data//worldgen/structure_set/.json` | | `structures { ... }` | `data//worldgen/structure/.json` | | `templatePool(...)` | `data//worldgen/template_pool/.json` | | `worldPreset(...)` | `data//worldgen/world_preset/.json` | ## Environment Attributes Biomes and dimension types support a flexible `attributes` map for visuals, audio, and gameplay rules shared across environments. ```kotlin import io.github.ayfri.kore.features.worldgen.AttributeModifier import io.github.ayfri.kore.features.worldgen.environmentattributes.* attributes { skyColor(0x78A7FF) // When a modifier is set, the value expands to { "argument": ..., "modifier": ... } fogColor(0xC0D8FF, AttributeModifier.ADD) } ``` ## Quick Start Example ```kotlin val dp = DataPack("my_pack") // 1) Dimension type val dimType = dp.dimensionType("example_type") { minY = -64 height = 384 hasSkylight = true } // 2) Noise settings val terrain = dp.noiseSettings("example_noise") { noiseOptions(-64, 384, 1, 2) } // 3) Biome with features val plains = dp.biome("example_plains") { temperature = 0.8f downfall = 0.4f hasPrecipitation = true attributes { skyColor(0x78A7FF) fogColor(0xC0D8FF) waterFogColor(0x050533) } effects { waterColor = color(0x3F76E4) } } // 4) Dimension val dim = dp.dimension("example_dimension", type = dimType) { // noiseGenerator(settings = terrain, biomeSource = ...) } // 5) World preset dp.worldPreset("example_preset") { dimension(DimensionTypes.OVERWORLD) { type = dimType } } ``` ## Tips & Testing - **In-game commands:** - Teleport: `/execute in : run tp @s 0 200 0` - Locate: `/locate structure :` - Reload: `/reload` - **Validation:** Check your configs against the [Minecraft Wiki](https://minecraft.wiki/w/World_generation) JSON schemas. - **Performance:** Keep feature counts and structure spacing reasonable. - **Testing:** Use GameTest for deterministic validation; see [Test Features](/docs/advanced/test-features). ## Cross-References - [Colors](/docs/concepts/colors) - RGB and ARGB color formats used in environment attributes - [Environment Attributes](/docs/data-driven/worldgen/environment-attributes) - Full reference for visual, audio, and gameplay attributes - [Predicates](/docs/data-driven/predicates) - Condition logic for features - [Test Features](/docs/advanced/test-features) - Automated validation with GameTest - [Timelines](/docs/data-driven/timelines) - Animate environment attributes over time using keyframes and easing functions - [World Clocks](/docs/data-driven/world-clocks) - World clocks, time markers, the `/time` command, and `timeCheck` - used by `DimensionType.defaultClock` --- ## Biomes --- root: .components.layouts.MarkdownLayout title: Biomes nav-title: Biomes description: Define biomes with climate, effects, spawns, carvers, and features using Kore's DSL. keywords: minecraft, datapack, kore, worldgen, biome, carver, spawner, effects date-created: 2026-02-03 date-modified: 2026-02-04 routeOverride: /docs/data-driven/worldgen/biomes --- # Biomes Biomes define climate, visuals, mob spawns, carvers, and the placed features list for each decoration step. In Minecraft, biomes control not just the terrain appearance but also weather behavior, mob spawning rules, and which features generate. ## How Biomes Work In the Overworld, biome placement is determined by 6 climate parameters: - **Temperature** - Controls snow/ice coverage and vegetation types (5 levels from frozen to hot) - **Humidity** - Affects vegetation density (5 levels from arid to humid) - **Continentalness** - Determines ocean/beach/inland placement - **Erosion** - Controls flat vs mountainous terrain (7 levels) - **Weirdness** - Triggers biome variants (e.g., Jungle → Bamboo Jungle) - **Depth** - Determines surface vs cave biomes These parameters form a 6D space where each biome occupies defined intervals. The game selects the closest matching biome for any given location. References: [Biome](https://minecraft.wiki/w/Biome), [Biome definition](https://minecraft.wiki/w/Biome_definition) ## Basic Biome ```kotlin val myBiome = dp.biome("my_biome") { temperature = 0.8f downfall = 0.4f hasPrecipitation = true attributes { skyColor(0x78A7FF) fogColor(0xC0D8FF) waterFogColor(0x050533) } effects { waterColor = color(0x3F76E4) } } ``` ## Environment Attributes Biome visuals/audio/gameplay are partially controlled by **environment attributes** (`attributes`), a shared system used by both biomes and dimension types. See the [Environment Attributes](/docs/data-driven/worldgen/environment-attributes) page for the full list of attributes, modifiers, and interpolation rules. ```kotlin attributes { // Simple values serialize as a raw JSON value (equivalent to "minecraft:override") skyColor(0x78A7FF) // Expanded form when a modifier is provided fogColor(0xC0D8FF, AttributeModifier.ADD) } ``` ## Effects The `effects` block controls biome-specific colors like water/foliage/grass. Visual sky/fog/water fog, particles and sounds are handled by `attributes`. Reference: [Biome definition - Effects](https://minecraft.wiki/w/Biome_definition#Effects) ```kotlin effects { // Water color (serialized as a decimal int in JSON) waterColor = color(0x3F76E4) // Optional colors foliageColor = color(0x59AE30) grassColor = color(0x79C05A) } ``` ## Spawners Define mob spawn rules per category. Each spawner entry specifies the entity type, spawn weight (relative probability), and count range. Higher weights mean more frequent spawns relative to other entries in the same category. Reference: [Biome definition - Mob spawning](https://minecraft.wiki/w/Biome_definition#Mob_spawning) ```kotlin spawners { creature { spawner(EntityTypes.COW, weight = 6, minCount = 2, maxCount = 4) spawner(EntityTypes.SHEEP, weight = 8, minCount = 2, maxCount = 4) } monster { spawner(EntityTypes.SKELETON, weight = 80, minCount = 1, maxCount = 2) spawner(EntityTypes.ZOMBIE, weight = 80, minCount = 1, maxCount = 2) } // Other categories: ambient, waterCreature, undergroundWaterCreature, waterAmbient, misc, axolotls } ``` ## Spawn Costs Spawn costs control mob density using an energy budget system. Each mob type has an `energyBudget` (max population density) and `charge` ( cost per mob). This prevents overcrowding while allowing natural mob distribution. Reference: [Biome definition - Spawn costs](https://minecraft.wiki/w/Biome_definition#Spawn_costs) ```kotlin spawnCosts { this[EntityTypes.COW] = spawnCost(energyBudget = 1.2f, charge = 0.1f) this[EntityTypes.SHEEP] = spawnCost(energyBudget = 1.0f, charge = 0.08f) } ``` ## Carvers Carvers hollow out terrain to create caves and canyons. They run during the `carvers` generation step, after terrain noise but before features. Two carving modes exist: `air` for standard caves and `liquid` for underwater caves. Reference: [Carver](https://minecraft.wiki/w/Carver) ```kotlin carvers { air(myCaveCarver) // Carves air (caves) liquid(myUnderwaterCave) // Carves underwater caves } ``` See [Carvers](#carvers-cavescanyons) below for creating configured carvers. ## Features Features are attached to biomes via decoration steps. Each step runs in order during chunk generation, with structures placing before features within the same step. See the [main worldgen page](/docs/data-driven/worldgen#decoration-steps) for the full step list. Reference: [Biome definition - Features](https://minecraft.wiki/w/Biome_definition#Features) ```kotlin features { fluidSprings = listOf(...) lakes = listOf(...) localModifications = listOf(...) rawGeneration = listOf(...) strongholds = listOf(...) surfaceStructures = listOf(...) topLayerModification = listOf(...) undergroundDecoration = listOf(...) undergroundOres = listOf(orePlaced) undergroundStructures = listOf(...) vegetalDecoration = listOf(treePlaced, flowerPlaced) } ``` See [Features](/docs/data-driven/worldgen/features) for creating configured and placed features. --- # Carvers (Caves/Canyons) Configured carvers remove terrain to form cave systems and canyons. They use noise-based algorithms to create natural-looking underground spaces. Carvers run after terrain generation but before features, ensuring caves don't destroy placed decorations. Minecraft has two carver types: - **Cave carvers** - Create winding tunnel systems with variable radius - **Canyon carvers** - Create deep ravines with steep walls References: [Carver](https://minecraft.wiki/w/Carver), [Configured carver](https://minecraft.wiki/w/Configured_carver) ## Cave Carver ```kotlin val caveCfg = caveConfig { floorLevel = constant(-0.2f) horizontalRadiusMultiplier = constant(1.0f) lavaLevel = absolute(8) probability = 0.08 verticalRadiusMultiplier = constant(0.7f) y = uniformHeightProvider(32, 128) yScale = constant(0.5f) } val cave = dp.configuredCarver("my_cave", caveCfg) {} ``` ## Canyon Carver ```kotlin val canyonCfg = canyonConfig { lavaLevel = absolute(8) probability = 0.02 y = uniformHeightProvider(10, 67) yScale = constant(3.0f) // Additional canyon-specific settings... } val canyon = dp.configuredCarver("my_canyon", canyonCfg) {} ``` --- # Complete Biome Example ```kotlin fun DataPack.createHighlandsBiome() { // Create a cave carver val caveCfg = caveConfig { floorLevel = constant(-0.2f) horizontalRadiusMultiplier = constant(1.0f) lavaLevel = absolute(8) probability = 0.08 verticalRadiusMultiplier = constant(0.7f) y = uniformHeightProvider(32, 128) yScale = constant(0.5f) } val cave = configuredCarver("highlands_cave", caveCfg) {} // Create placed features (see Features page) val treePlaced = /* ... */ val orePlaced = /* ... */ // Create the biome biome("highlands") { temperature = 0.8f downfall = 0.3f hasPrecipitation = true attributes { fogColor(0xBFEFFF) skyColor(0x99D9FF) waterFogColor(0x0A2C4F) } effects { waterColor = color(0x34A7F0) } spawners { creature { spawner(EntityTypes.COW, 6, 2, 4) spawner(EntityTypes.SHEEP, 8, 2, 4) } monster { spawner(EntityTypes.SKELETON, 80, 1, 2) spawner(EntityTypes.ZOMBIE, 80, 1, 2) } } spawnCosts { this[EntityTypes.COW] = spawnCost(1.2f, 0.1f) this[EntityTypes.SHEEP] = spawnCost(1.0f, 0.08f) } carvers { air(cave) } features { undergroundOres = listOf(orePlaced) vegetalDecoration = listOf(treePlaced) } } } ``` ## See Also - [Dimensions](/docs/data-driven/worldgen/dimensions) - Dimension types and generators - [Environment Attributes](/docs/data-driven/worldgen/environment-attributes) - Full reference for visual, audio, and gameplay attributes - [Features](/docs/data-driven/worldgen/features) - Configured and placed features - [World Generation](/docs/data-driven/worldgen) - Overview of the worldgen system --- ## Dimensions --- root: .components.layouts.MarkdownLayout title: Dimensions nav-title: Dimensions description: Create custom dimensions and dimension types with Kore's DSL. keywords: minecraft, datapack, kore, worldgen, dimension, dimension type, generator date-created: 2026-02-03 date-modified: 2026-06-20 routeOverride: /docs/data-driven/worldgen/dimensions --- # Dimensions Dimensions are complete, separate worlds within Minecraft. Each dimension combines a **dimension type** (world rules like height, lighting, and behavior) with a **generator** (how terrain is created). Vanilla Minecraft has three dimensions: Overworld, Nether, and End. With datapacks, you can create unlimited custom dimensions with unique terrain, rules, and atmosphere. Players can travel between dimensions using portals or commands. References: [Dimension](https://minecraft.wiki/w/Dimension), [Dimension definition](https://minecraft.wiki/w/Dimension_definition), [Custom dimension](https://minecraft.wiki/w/Custom_dimension) --- ## Dimension Type Dimension types define the fundamental rules of a world: vertical bounds, lighting behavior, time flow, and special mechanics. These settings affect gameplay significantly-for example, use environment attributes like `waterEvaporates` and `fastLava` to make a Nether-like environment. See [Environment Attributes](/docs/data-driven/worldgen/environment-attributes) for the full list of attributes and modifiers. Reference: [Dimension type](https://minecraft.wiki/w/Dimension_type) ```kotlin val myDimType = dp.dimensionType("my_dim_type") { ambientLight = 0f hasCeiling = false hasSkylight = true height = 384 logicalHeight = 384 minY = -64 natural = true attributes { canStartRaid(true) respawnAnchorWorks(false) piglinsZombify(true) waterEvaporates(false) fastLava(false) increasedFireBurnout(false) bedRule( BedRule( canSleep = BedSleepRule.ALWAYS, canSetSpawn = BedSleepRule.ALWAYS, explodes = false, ) ) } } ``` ### Dimension Type Properties | Property | Description | |-----------------------|-------------------------------------------------------------------| | `ambientLight` | Base light level (0.0 to 1.0) | | `attributes` | Environment attributes (visual/audio/gameplay rules) | | `cardinalLight` | Cardinal light type (`CardinalLight.DEFAULT` or `NETHER`) | | `hasCeiling` | Whether dimension has bedrock ceiling | | `hasEnderDragonFight` | Whether the Ender Dragon fight can exist in this dimension | | `hasFixedTime` | Whether the day-night cycle is frozen | | `hasSkylight` | Whether sky provides light | | `height` | Total height (multiple of 16, max 4064) | | `infiniburn` | Block tag for infinite burning | | `logicalHeight` | Max height for teleportation/portals | | `minY` | Minimum Y coordinate (multiple of 16) | | `natural` | Compasses/clocks work normally | | `skybox` | Skybox type (`SkyboxType.NONE`, `OVERWORLD`, or `END`) | | `timelines` | List of [timelines](/docs/data-driven/timelines) or timeline tags | --- ## Dimension A dimension combines a dimension type with a generator that produces terrain. The generator determines the terrain algorithm and biome distribution. ```kotlin val dim = dp.dimension("my_dimension", type = myDimType) { // Choose a generator (see below) } ``` ### Noise Generator The noise generator is the standard terrain generator used by vanilla dimensions. It combines **noise settings** (terrain shape algorithm) with a **biome source** (which biomes appear where). Reference: [Noise generator](https://minecraft.wiki/w/Dimension_definition#Noise_generator) ```kotlin dimension("my_dimension", type = myDimType) { noiseGenerator( settings = myNoiseSettings, biomeSource = /* BiomeSource */ ) } ``` #### Biome Sources Biome sources determine how biomes are distributed across the dimension. Different sources suit different use cases: Reference: [Biome source](https://minecraft.wiki/w/Biome_source) ```kotlin // Single biome everywhere (simplest option) noiseGenerator( settings = terrain, biomeSource = fixed(myBiome) ) // Checkerboard pattern noiseGenerator( settings = terrain, biomeSource = checkerboard(scale = 3, biome1, biome2, biome3) ) // Multi-noise (vanilla-like biome distribution) noiseGenerator( settings = terrain, biomeSource = multiNoise { // biome entries with climate parameters } ) // The End biome source noiseGenerator( settings = terrain, biomeSource = theEnd() ) ``` ### Flat Generator The flat generator creates superflat worlds with user-defined block layers. Useful for testing, creative building, or specialized gameplay. Reference: [Superflat](https://minecraft.wiki/w/Superflat) ```kotlin dimension("flat_world", type = myDimType) { flatGenerator(biome = Biomes.PLAINS) { layers { layer(Blocks.BEDROCK, height = 1) layer(Blocks.DIRT, height = 2) layer(Blocks.GRASS_BLOCK, height = 1) } // structureOverrides = ... } } ``` ### Debug Generator The debug generator creates a world showing every block state in a grid pattern. Primarily used for development and testing. Reference: [Debug mode](https://minecraft.wiki/w/Debug_mode) ```kotlin dimension("debug_world", type = myDimType) { debugGenerator() } ``` --- ## Complete Example ```kotlin fun DataPack.createSkyDimension() { // 1) Dimension type with high ambient light val skyType = dimensionType("sky_type") { ambientLight = 0.5f hasCeiling = false hasSkylight = true height = 256 logicalHeight = 256 minY = 0 natural = true attributes { canStartRaid(false) respawnAnchorWorks(false) piglinsZombify(true) waterEvaporates(false) fastLava(false) increasedFireBurnout(false) bedRule( BedRule( canSleep = BedSleepRule.ALWAYS, canSetSpawn = BedSleepRule.ALWAYS, explodes = false, ) ) } } // 2) Simple noise settings val skyTerrain = noiseSettings("sky_terrain") { noiseOptions(minY = 0, height = 256, sizeHorizontal = 1, sizeVertical = 2) defaultBlock(Blocks.STONE) {} defaultFluid(Blocks.WATER) { this["level"] = "0" } } // 3) Create a biome val skyBiome = biome("sky_biome") { temperature = 0.5f downfall = 0.0f hasPrecipitation = false attributes { skyColor(0xFFFFFF) fogColor(0xFFFFFF) waterFogColor(0x050533) } effects { waterColor = color(0x3F76E4) } } // 4) Create the dimension dimension("sky", type = skyType) { noiseGenerator( biomeSource = fixed(skyBiome), settings = skyTerrain, ) } } ``` ## See Also - [Biomes](/docs/data-driven/worldgen/biomes) - Climate, visuals, mob spawns, and features - [Environment Attributes](/docs/data-driven/worldgen/environment-attributes) - Full reference for visual, audio, and gameplay attributes - [World Presets](/docs/data-driven/worldgen/world-presets) - World presets and flat level generator presets - [World Generation](/docs/data-driven/worldgen) - Overview of the worldgen system --- ## Environment Attributes --- root: .components.layouts.MarkdownLayout title: Environment Attributes nav-title: Environment Attributes description: Data-driven environment attributes to control visual, audio, and gameplay systems in biomes and dimensions. keywords: minecraft, datapack, kore, worldgen, environment attributes, biome, dimension type, fog, sky, music date-created: 2026-02-09 date-modified: 2026-06-16 routeOverride: /docs/data-driven/worldgen/environment-attributes --- # Environment Attributes Environment Attributes provide a data-driven way to control a variety of visual, audio, and gameplay systems. Each attribute controls a specific effect: for example, `visual/sky_color` controls the color of the sky, and `gameplay/water_evaporates` controls whether water can be placed at a given location. Both **biomes** and **dimension types** can define environment attributes via the `attributes` block. References: [Biome definition](https://minecraft.wiki/w/Biome_definition), [Dimension type](https://minecraft.wiki/w/Dimension_type) --- ## Sources & Priority Environment Attribute values can be provided by the following sources (low → high priority): 1. **Dimensions** - base values for the entire dimension 2. **Biomes** - override or modify per-biome When a biome provides an attribute, it takes priority over the dimension value. For example, if the overworld dimension sets `sky_color = green` and the plains biome sets `sky_color = red`, a player in the plains biome will see a red sky. ## Modifiers By default, an attribute value uses the **override** modifier, fully replacing any lower-priority value. However, you can apply a different modifier to combine with the preceding value instead. ```kotlin attributes { // Simple override (default modifier) skyColor(0x78A7FF) // Explicit modifier - multiplies the preceding value fogEndDistance(0.85f, EnvironmentAttributeModifier.MULTIPLY) } ``` When a modifier is set, the JSON expands to `{ "argument": ..., "modifier": "..." }`. ### Boolean Modifiers Applicable to boolean attributes. Argument format: `boolean`. | Modifier | Description | |------------|---------------------------------------| | `OVERRIDE` | Replaces the preceding value entirely | | `AND` | Logical AND with the preceding value | | `NAND` | Logical NAND with the preceding value | | `OR` | Logical OR with the preceding value | | `NOR` | Logical NOR with the preceding value | | `XOR` | Logical XOR with the preceding value | | `XNOR` | Logical XNOR with the preceding value | ### Float Modifiers Applicable to float attributes. Argument format: `float`. | Modifier | Description | |------------|-------------------------------------------------------| | `OVERRIDE` | Replaces the preceding value entirely | | `ADD` | Adds the argument to the preceding value | | `SUBTRACT` | Subtracts the argument from the preceding value | | `MULTIPLY` | Multiplies the preceding value by the argument | | `MINIMUM` | Takes the minimum of the preceding value and argument | | `MAXIMUM` | Takes the maximum of the preceding value and argument | ### Color Modifiers Applicable to color attributes. Argument format: RGB color (except `ALPHA_BLEND` which uses ARGB). | Modifier | Description | |---------------|----------------------------------------------------------------------| | `OVERRIDE` | Replaces the preceding value entirely | | `ADD` | Component-wise additive color blending | | `SUBTRACT` | Component-wise subtractive color blending | | `MULTIPLY` | Component-wise multiplicative color blending | | `ALPHA_BLEND` | Traditional alpha blending (ARGB argument; alpha=1 acts as override) | | `BlendToGray` | Blends toward gray with configurable `brightness` and `factor` | ## Interpolation Some attributes support **smooth interpolation** between biomes. As a player moves between biomes, interpolated attributes will gradually transition based on biomes within an 8-block radius of the camera. Non-interpolated attributes use only the biome at the exact position. --- ## All Environment Attributes All attributes are listed below in alphabetical order by their Minecraft ID. --- ### `audio/ambient_sounds` Controls which ambient sounds are played around the camera: looping sounds, mood-based sounds, and additional random sounds. | Property | Value | |---------------|--------------------------------------------------------------------------------| | Value type | Object | | Default value | `{}` | | Modifiers | `override` only | | Interpolated | No | | Resolved at | Camera position | | Replaces | Biome `effects.ambient_sound`, `effects.mood_sound`, `effects.additions_sound` | **Fields:** - `loop` - optional Sound Event, continually looped sound - `mood` - optional object for mood sounds: - `sound` - Sound Event to play - `tickDelay` - ticks between mood sounds (default: `6000`) - `blockSearchExtent` - radius for light level sampling (default: `8`) - `offset` - distance offset for produced sounds (default: `2.0`) - `additions` - list of additional random sounds: - `sound` - Sound Event to play - `tickChance` - probability within a tick to play the sound ```kotlin attributes { ambientSounds(loop = SoundEvents.Ambient.CAVE) { mood(sound = SoundEvents.Ambient.CAVE) addition(SoundEvents.Ambient.CAVE, 0.01f) } } ``` --- ### `audio/background_music` Controls how and which background music is played. | Property | Value | |---------------|-----------------------| | Value type | Object | | Default value | `{}` | | Modifiers | `override` only | | Interpolated | No | | Resolved at | Camera position | | Replaces | Biome `effects.music` | **Fields:** - `default` - optional music track with: - `sound` - Sound Event to play - `minDelay` - minimum delay in ticks between tracks - `maxDelay` - maximum delay in ticks between tracks - `replaceCurrentMusic` - optional boolean (default: `false`) - `creative` - optional track, overrides `default` when in Creative Mode - `underwater` - optional track, overrides `default` when underwater ```kotlin attributes { backgroundMusic { default( sound = SoundEvents.Music.CREATIVE, minDelay = 100, maxDelay = 200, replaceCurrentMusic = true, ) } } ``` --- ### `audio/firefly_bush_sounds` Controls whether firefly bush sounds are played. | Property | Value | |---------------|-------------------| | Value type | Boolean | | Default value | `false` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Firefly bush | ```kotlin attributes { fireflyBushSounds(true) } ``` --- ### `audio/music_volume` The volume at which music should play. Any music playing will fade over time to this value. | Property | Value | |---------------|------------------------------| | Value type | Float (0 to 1) | | Default value | `1.0` | | Modifiers | Float Modifiers | | Interpolated | No | | Resolved at | Camera position | | Replaces | Biome `effects.music_volume` | ```kotlin attributes { musicVolume(0.8f) } ``` --- ### `gameplay/bed_rule` Controls whether a Bed can be used to sleep, set a respawn point, or whether it explodes. | Property | Value | |---------------|-----------------------------------------------------| | Value type | Object | | Default value | `{canSleep: "when_dark", canSetSpawn: "when_dark"}` | | Modifiers | `override` only | | Interpolated | No | | Resolved at | Head position of the Bed block | | Replaces | Dimension Type `bed_works` | **Fields:** - `canSleep` - one of `ALWAYS`, `WHEN_DARK`, `NEVER` - `canSetSpawn` - one of `ALWAYS`, `WHEN_DARK`, `NEVER` - `explodes` - optional boolean, if `true` the Bed explodes when interacted with (default: `false`) - `errorMessage` - optional Text Component shown when unable to sleep ```kotlin attributes { bedRule( canSleep = BedSleepRule.ALWAYS, canSetSpawn = BedSleepRule.WHEN_DARK, explodes = false, errorMessage = textComponent("Cannot sleep here"), ) } ``` --- ### `gameplay/baby_villager_activity` Controls the activity of baby villagers. | Property | Value | |---------------|--------------------------| | Value type | Mob Activity enum | | Default value | `minecraft:idle` | | Modifiers | `override` only | | Interpolated | No | | Resolved at | Position of the villager | ```kotlin attributes { babyVillagerActivity(Activities.PLAY, EnvironmentAttributeModifier.OVERRIDE) } ``` --- ### `gameplay/bees_stay_in_hive` Controls whether bees stay in their hive. | Property | Value | |---------------|-------------------| | Value type | Boolean | | Default value | `false` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Position of hive | ```kotlin attributes { beesStayInHive(true) } ``` --- ### `gameplay/can_pillager_patrol_spawn` Controls whether Pillager patrols can spawn. Replaces `#without_patrol_spawns`. | Property | Value | |---------------|------------------------------------| | Value type | Boolean | | Default value | `true` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Position of the patrol spawn | | Replaces | `#without_patrol_spawns` Biome Tag | ```kotlin attributes { canPillagerPatrolSpawn(false) } ``` --- ### `gameplay/can_start_raid` If `false`, a Raid cannot be started by a player with Raid Omen. | Property | Value | |---------------|--------------------------------| | Value type | Boolean | | Default value | `true` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Position where the Raid starts | | Replaces | Dimension Type `has_raids` | ```kotlin attributes { canStartRaid(false) } ``` --- ### `gameplay/cat_waking_up_gift_chance` The chance for a cat to give a waking up gift. Interpolated. | Property | Value | |---------------|-----------------| | Value type | Float | | Default value | `0.0` | | Modifiers | Float Modifiers | | Interpolated | Yes | | Resolved at | Position of cat | ```kotlin attributes { catWakingUpGiftChance(0.5f) } ``` --- ### `gameplay/creaking_active` Controls whether the Creaking is active. | Property | Value | |---------------|--------------------------| | Value type | Boolean | | Default value | `false` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Position of the Creaking | ```kotlin attributes { creakingActive(true) } ``` --- ### `gameplay/eyeblossom_open` Controls whether Eyeblossoms are open. Can be `true`, `false`, or `"default"`. | Property | Value | |---------------|---------------------------------| | Value type | Enum (`true`/`false`/`default`) | | Default value | `"default"` | | Modifiers | `override` only | | Interpolated | No | | Resolved at | Position of the Eyeblossom | ```kotlin attributes { eyeblossomOpen(EyeblossomOpenState.TRUE) // With a modifier eyeblossomOpen(EyeblossomOpenState.DEFAULT, EnvironmentAttributeModifier.OVERRIDE) } ``` --- ### `gameplay/fast_lava` Controls whether Lava should spread faster and further, as well as have a stronger pushing force on entities when flowing. | Property | Value | |---------------|--------------------------------------------| | Value type | Boolean | | Default value | `false` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Whole dimension (cannot be set on a Biome) | | Replaces | Dimension Type `ultrawarm` | ```kotlin attributes { fastLava(true) } ``` --- ### `gameplay/increased_fire_burnout` Controls whether Fire blocks burn out more rapidly than normal. | Property | Value | |---------------|-------------------------------------| | Value type | Boolean | | Default value | `false` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Position of the burning Fire block | | Replaces | `#increased_fire_burnout` Biome Tag | ```kotlin attributes { increasedFireBurnout(true) } ``` --- ### `gameplay/monsters_burn` Controls whether monsters burn in sunlight. | Property | Value | |---------------|-------------------| | Value type | Boolean | | Default value | `false` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Position of mob | ```kotlin attributes { monstersBurn(true) } ``` --- ### `gameplay/nether_portal_spawns_piglin` Controls whether Nether Portal blocks can spawn Piglins. | Property | Value | |---------------|------------------------------------------| | Value type | Boolean | | Default value | `false` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Position of a random Nether Portal block | | Replaces | Dimension Type `natural` | ```kotlin attributes { netherPortalSpawnsPiglin(true) } ``` --- ### `gameplay/piglins_zombify` Controls whether Piglins and Hoglins should zombify. | Property | Value | |---------------|-----------------------------------| | Value type | Boolean | | Default value | `true` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Position of the zombifying entity | | Replaces | Dimension Type `piglin_safe` | ```kotlin attributes { piglinsZombify(false) } ``` --- ### `gameplay/respawn_anchor_works` Controls whether Respawn Anchors can be used to set spawn. If `false`, the Respawn Anchor will explode once charged. | Property | Value | |---------------|---------------------------------------| | Value type | Boolean | | Default value | `false` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Position of the Respawn Anchor block | | Replaces | Dimension Type `respawn_anchor_works` | ```kotlin attributes { respawnAnchorWorks(true) } ``` --- ### `gameplay/snow_golem_melts` Controls whether a Snow Golem should be damaged. | Property | Value | |---------------|-------------------------------| | Value type | Boolean | | Default value | `false` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Position of the Snow Golem | | Replaces | `#snow_golem_melts` Biome Tag | ```kotlin attributes { snowGolemMelts(true) } ``` --- ### `gameplay/sky_light_level` The sky light level for the dimension. | Property | Value | |---------------|--------------------------------------------| | Value type | Float | | Default value | `15.0` | | Modifiers | Float Modifiers | | Interpolated | No | | Resolved at | Whole dimension (cannot be set on a Biome) | ```kotlin attributes { skyLightLevel(15.0f) } ``` --- ### `gameplay/surface_slime_spawn_chance` The chance for surface slime to spawn. Interpolated. | Property | Value | |---------------|-------------------| | Value type | Float | | Default value | `0.0` | | Modifiers | Float Modifiers | | Interpolated | Yes | | Resolved at | Position of spawn | ```kotlin attributes { surfaceSlimeSpawnChance(0.1f) } ``` --- ### `gameplay/turtle_egg_hatch_chance` The chance for turtle eggs to hatch. Interpolated. | Property | Value | |---------------|----------------------------| | Value type | Float | | Default value | `0.0` | | Modifiers | Float Modifiers | | Interpolated | Yes | | Resolved at | Position of the turtle egg | ```kotlin attributes { turtleEggHatchChance(0.05f) } ``` --- ### `gameplay/villager_activity` Controls the activity of villagers. | Property | Value | |---------------|--------------------------| | Value type | Mob Activity enum | | Default value | `minecraft:idle` | | Modifiers | `override` only | | Interpolated | No | | Resolved at | Position of the villager | ```kotlin attributes { villagerActivity(Activities.WORK, EnvironmentAttributeModifier.OVERRIDE) } ``` --- ### `gameplay/water_evaporates` If `true`, Water cannot be placed with a Bucket, melting Ice will not produce water, Wet Sponge will dry out when placed, and Dripstone will not produce water from Mud blocks. | Property | Value | |---------------|-----------------------------| | Value type | Boolean | | Default value | `false` | | Modifiers | Boolean Modifiers | | Interpolated | No | | Resolved at | Position of the interaction | | Replaces | Dimension Type `ultrawarm` | ```kotlin attributes { waterEvaporates(true) // With a modifier waterEvaporates(true, EnvironmentAttributeModifier.OR) } ``` --- ### `visual/ambient_light_color` The ambient light color used to tint the scene's ambient illumination. Interpolated. | Property | Value | |---------------|-----------------| | Value type | RGB Color | | Default value | `#000000` | | Modifiers | Color Modifiers | | Interpolated | Yes | | Resolved at | Camera position | ```kotlin attributes { ambientLightColor(rgb(20, 20, 20)) } ``` --- ### `visual/ambient_particles` Controls ambient particles that randomly spawn around the camera. | Property | Value | |---------------|--------------------------| | Value type | List of particle entries | | Default value | `[]` | | Modifiers | `override` only | | Interpolated | No | | Resolved at | Camera position | | Replaces | Biome `effects.particle` | Each entry has: - `options` - a particle type (e.g. `Particles.ASH`) - `probability` - float between 0 and 1, the chance to spawn in an empty space ```kotlin attributes { ambientParticles( Particle(ParticleOptions(Particles.ASH), 0.01f), ) } ``` --- ### `visual/block_light_tint` The tint color applied to block-emitted light. Interpolated. | Property | Value | |---------------|-----------------| | Value type | RGB Color | | Default value | `#000000` | | Modifiers | Color Modifiers | | Interpolated | Yes | | Resolved at | Camera position | ```kotlin attributes { blockLightTint(rgb(255, 180, 80)) // With a modifier blockLightTint(rgb(255, 180, 80), EnvironmentAttributeModifier.MULTIPLY) } ``` --- ### `visual/cloud_color` The color of clouds, expressed as an ARGB hex string. | Property | Value | |---------------|-----------------| | Value type | ARGB Color | | Default value | `#00000000` | | Modifiers | Color Modifiers | | Interpolated | Yes | | Resolved at | Camera position | ```kotlin attributes { cloudColor(ARGB(255, 128, 64, 32)) } ``` --- ### `visual/cloud_fog_end_distance` The distance in blocks from the camera at which cloud fog ends. | Property | Value | |---------------|--------------------| | Value type | Non-negative float | | Default value | `1024.0` | | Modifiers | Float Modifiers | | Interpolated | Yes | | Resolved at | Camera position | ```kotlin attributes { cloudFogEndDistance(256.0f) } ``` --- ### `visual/cloud_height` The height at which all clouds appear. | Property | Value | |---------------|-------------------------------------------------------------------------| | Value type | Float | | Default value | `192.33` | | Modifiers | Float Modifiers | | Interpolated | Yes | | Resolved at | Camera position for rendering, or Happy Ghast position for regeneration | | Replaces | Dimension Type `cloud_height` | ```kotlin attributes { cloudHeight(192.33f) } ``` --- ### `visual/default_dripstone_particle` The default particle to be dripped from Dripstone blocks when no fluid is placed above. | Property | Value | |---------------|--------------------------------------| | Value type | Particle Options | | Default value | `{type: "dripping_dripstone_water"}` | | Modifiers | `override` only | | Interpolated | No | | Resolved at | Position of the Dripstone block | | Replaces | Dimension Type `ultrawarm` | ```kotlin attributes { defaultDripstoneParticle(Particles.DRIPPING_DRIPSTONE_WATER) } ``` --- ### `visual/moon_angle` The angle of the moon in degrees. Interpolated. | Property | Value | |---------------|------------------| | Value type | Float | | Default value | `0.0` | | Modifiers | Float Modifiers | | Interpolated | Yes | | Resolved at | Overworld camera | ```kotlin attributes { moonAngle(45.0f) } ``` --- ### `visual/moon_phase` Controls the moon phase. | Property | Value | |---------------|------------------| | Value type | MoonPhase | | Default value | `full_moon` | | Modifiers | `override` only | | Interpolated | No | | Resolved at | Overworld camera | ```kotlin attributes { moonPhase(Textures.Environment.Celestial.Moon.FULL_MOON, EnvironmentAttributeModifier.OVERRIDE) } ``` --- ### `visual/fog_color` The color of fog when the camera is not submerged in another substance. The final value is also affected by the time of day, weather, and potion effects. | Property | Value | |---------------|---------------------------| | Value type | RGB Color | | Default value | `#000000` | | Modifiers | Color Modifiers | | Interpolated | Yes | | Resolved at | Camera position | | Replaces | Biome `effects.fog_color` | ```kotlin attributes { fogColor(rgb(255, 170, 0)) // With a modifier fogColor(rgb(255, 255, 0), EnvironmentAttributeModifier.ADD) } ``` --- ### `visual/fog_end_distance` The distance in blocks from the camera at which fog ends. | Property | Value | |---------------|--------------------| | Value type | Non-negative float | | Default value | `1024.0` | | Modifiers | Float Modifiers | | Interpolated | Yes | | Resolved at | Camera position | ```kotlin attributes { fogEndDistance(192.0f) } ``` --- ### `visual/fog_start_distance` The distance in blocks from the camera at which fog starts. | Property | Value | |---------------|--------------------| | Value type | Non-negative float | | Default value | `0.0` | | Modifiers | Float Modifiers | | Interpolated | Yes | | Resolved at | Camera position | ```kotlin attributes { fogStartDistance(0.0f) } ``` --- ### `visual/night_vision_color` The tint color applied to the player's vision while under the Night Vision effect. Interpolated. | Property | Value | |---------------|-----------------| | Value type | RGB Color | | Default value | `#000000` | | Modifiers | Color Modifiers | | Interpolated | Yes | | Resolved at | Camera position | ```kotlin attributes { nightVisionColor(rgb(0, 255, 128)) } ``` --- ### `visual/sky_color` The color of the sky. This color is only visible for the overworld sky. The final value is also affected by the time of day and weather. | Property | Value | |---------------|---------------------------| | Value type | RGB Color | | Default value | `#000000` | | Modifiers | Color Modifiers | | Interpolated | Yes | | Resolved at | Camera position | | Replaces | Biome `effects.sky_color` | ```kotlin attributes { skyColor(Color.RED) // or skyColor(0x78A7FF) } ``` --- ### `visual/sky_fog_end_distance` The distance in blocks from the camera at which sky fog ends. | Property | Value | |---------------|--------------------| | Value type | Non-negative float | | Default value | `512.0` | | Modifiers | Float Modifiers | | Interpolated | Yes | | Resolved at | Camera position | ```kotlin attributes { skyFogEndDistance(320.0f) } ``` --- ### `visual/water_fog_color` The color of fog when submerged in water. The final value is also affected by the time of day, weather, and potion effects. | Property | Value | |---------------|---------------------------------| | Value type | RGB Color | | Default value | `#050533` | | Modifiers | Color Modifiers | | Interpolated | Yes | | Resolved at | Camera position | | Replaces | Biome `effects.water_fog_color` | ```kotlin attributes { waterFogColor(rgb(5, 5, 51)) } ``` --- ### `visual/water_fog_end_distance` The distance in blocks from the camera at which underwater fog ends. | Property | Value | |---------------|-----------------| | Value type | float | | Default value | `-8.0` | | Modifiers | Float Modifiers | | Interpolated | Yes | | Resolved at | Camera position | ```kotlin attributes { waterFogEndDistance(96.0f) } ``` --- ### `visual/water_fog_start_distance` The distance in blocks from the camera at which underwater fog starts. | Property | Value | |---------------|-----------------| | Value type | Float | | Default value | `0.0` | | Modifiers | Float Modifiers | | Interpolated | Yes | | Resolved at | Camera position | ```kotlin attributes { waterFogStartDistance(0.0f) } ``` --- ## Blend To Gray Modifier The `BlendToGray` modifier is a special color modifier that blends the preceding color toward gray. Unlike other modifiers which are simple constants, `BlendToGray` is a data class with two parameters: - `brightness` - controls the brightness of the gray target - `factor` - controls the blending factor (0 = no change, 1 = fully gray) ```kotlin attributes { fogColor(rgb(255, 170, 0), EnvironmentAttributeModifier.BlendToGray(brightness = 0.5f, factor = 0.8f)) } ``` This serializes to: ```json { "argument": 16755200, "modifier": { "type": "blend_to_gray", "brightness": 0.5, "factor": 0.8 } } ``` --- ## Complete Example ```kotlin fun DataPack.createCustomDimensionWithAttributes() { val dimType = dimensionType("custom_type") { ambientLight = 0.1f hasCeiling = false hasSkylight = true height = 384 logicalHeight = 384 minY = -64 natural = true attributes { // Gameplay canStartRaid(true) fastLava(false) waterEvaporates(false) piglinsZombify(true) respawnAnchorWorks(false) increasedFireBurnout(false) netherPortalSpawnsPiglin(false) snowGolemMelts(false) bedRule( canSleep = BedSleepRule.ALWAYS, canSetSpawn = BedSleepRule.ALWAYS, ) // Visual cloudColor(ARGB(255, 255, 255, 255)) cloudHeight(192.33f) fogStartDistance(0.0f) fogEndDistance(192.0f) skyFogEndDistance(320.0f) // Audio musicVolume(0.8f) backgroundMusic { default( sound = SoundEvents.Music.CREATIVE, minDelay = 100, maxDelay = 200, ) } } } biome("custom_biome") { temperature = 0.8f downfall = 0.4f hasPrecipitation = true attributes { skyColor(0x78A7FF) fogColor(0xC0D8FF) waterFogColor(0x050533) waterFogEndDistance(96.0f) waterFogStartDistance(0.0f) ambientParticles( Particle(ParticleOptions(Particles.ASH), 0.01f), ) ambientSounds(loop = SoundEvents.Ambient.CAVE) { mood(sound = SoundEvents.Ambient.CAVE) addition(SoundEvents.Ambient.CAVE, 0.01f) } } effects { waterColor = color(0x3F76E4) } } } ``` ## See Also - [Biomes](/docs/data-driven/worldgen/biomes) - Biomes can define environment attributes to control per-biome visuals and audio - [Colors](/docs/concepts/colors) - RGB and ARGB color formats used by color attributes - [Dimensions](/docs/data-driven/worldgen/dimensions) - Dimension types can define base environment attributes for the entire dimension - [Timelines](/docs/data-driven/timelines) - Animate environment attributes over time using keyframes and easing functions - [World Generation](/docs/data-driven/worldgen) - Overview of the worldgen system --- ## Features --- root: .components.layouts.MarkdownLayout title: Features nav-title: Features description: Create configured and placed features (trees, ores, vegetation) with Kore's DSL. keywords: minecraft, datapack, kore, worldgen, configured feature, placed feature, tree, ore date-created: 2026-02-03 date-modified: 2026-06-26 routeOverride: /docs/data-driven/worldgen/features --- # Features Features are world generation elements like trees, ores, flowers, and other decorations placed during the `features` generation step. They represent everything from single blocks to complex multi-block structures like trees and geodes. ## Two-Part System Minecraft separates feature definition into two parts: - **Configured feature** - Defines *what* to place (tree species, ore type, flower) with all its parameters (block types, sizes, shapes) - **Placed feature** - Defines *where* and *how often* to place (count per chunk, height range, rarity, biome restrictions) This separation allows reusing the same configured feature with different placement rules. For example, one tree configuration can be placed densely in forests but sparsely in plains. References: [Configured feature](https://minecraft.wiki/w/Configured_feature), [Placed feature](https://minecraft.wiki/w/Placed_feature), [Feature](https://minecraft.wiki/w/Feature) --- ## Configured Features Configured features define the feature type and its parameters. Kore provides builder functions for common feature types. ### Tree Trees are complex features with trunk placers, foliage placers, and decorators. The trunk and foliage providers define which blocks to use, while placers control the shape. ```kotlin val treeCfg = tree { blobFoliagePlacer(radius = constant(2), offset = constant(0), height = 3) foliageProvider = simpleStateProvider(Blocks.OAK_LEAVES) straightTrunkPlacer(baseHeight = 6, heightRandA = 3, heightRandB = 1) trunkProvider = simpleStateProvider(Blocks.OAK_LOG) belowTrunkProvider = ruleBasedStateProvider { fallback = simpleStateProvider(Blocks.DIRT) rule { ifTrue { hasSturdyFace(direction = Direction.DOWN) } then(simpleStateProvider(Blocks.GRASS_BLOCK)) } } } val tree = dp.configuredFeature("my_tree", treeCfg) {} ``` --- ### Block State Providers Block state providers determine which block state is placed at a given position. Every feature field typed as `BlockStateProvider` accepts any of the following. | Provider | Picks based on | |-------------------------------|------------------------------------------------| | `dualNoiseProvider { }` | Two-layer Perlin noise | | `noiseProvider { }` | Single-layer Perlin noise | | `noiseTresholdProvider { }` | Noise threshold between two blocks | | `randomizedIntProvider { }` | Int-provider-driven index into a state list | | `rotatedBlockProvider(state)` | Fixed block with random rotation | | `ruleBasedStateProvider { }` | Ordered predicate rules with optional fallback | | `simpleStateProvider(state)` | Fixed block | | `weightedStateProvider { }` | Weighted random across several blocks | #### `ruleBasedStateProvider` Evaluates rules top-to-bottom and uses the first matching block state, or `fallback` when nothing matches. All three `rule` styles are available inside the provider block: ```kotlin ruleBasedStateProvider { fallback = simpleStateProvider(Blocks.STONE) // Style 1: receiver block: ifTrue { } and then(...) called on the rule rule { ifTrue { solid() } then(simpleStateProvider(Blocks.DIRT)) } // Style 2: direct values rule( ifTrue = hasSturdyFace(direction = Direction.DOWN), then = simpleStateProvider(Blocks.GRAVEL), ) // Style 3: trailing lambda for the predicate; then is a normal argument rule(then = simpleStateProvider(Blocks.SAND)) { not { matchingBlockTag(tag = Tags.Block.CANNOT_REPLACE_BELOW_TREE_TRUNK) } solid() } } ``` The `ifTrue { }` block in Style 1 and the trailing lambda in Style 3 both run on a `MutableList` receiver, so all block predicate extensions (`solid()`, `not { }`, `matchingBlocks()`, `hasSturdyFace()`, `matchingBlockTag()`, etc.) work inside them. A single-element list is used as-is; multiple entries are automatically wrapped in `allOf`. --- ### Ore Ore features place clusters of blocks that replace existing terrain. The `size` controls maximum vein size, while `discardChanceOnAirExposure` prevents ores from generating in caves (set to 0 for full veins, 1 to skip all exposed blocks). Reference: [Ore feature](https://minecraft.wiki/w/Ore_(feature)) ```kotlin val oreCfg = ore( size = 10, // Max blocks per vein discardChanceOnAirExposure = 0.1, // Skip blocks exposed to air targets = listOf(Target()) // Rule tests for replacement ) val ore = dp.configuredFeature("my_ore", oreCfg) {} ``` ### Simple Block ```kotlin val flowerCfg = simpleBlock(toPlace = simpleStateProvider(Blocks.DANDELION)) val flower = dp.configuredFeature("my_flower", flowerCfg) {} ``` ### Other Feature Types Kore supports all vanilla configured feature types. Functions are listed alphabetically: | Feature Type | Description | Example Use | |-----------------------------------|--------------------------------------|--------------------------------| | `bamboo(probability)` | Bamboo stalks | Jungle bamboo | | `basaltColumns(reach, height)` | Paired basalt pillar columns | Nether basalt deltas | | `blockBlob(...)` | Small block blob on a surface | Mossy cobblestone in forests | | `blockColumn(...)` | Vertical stack of blocks with layers | Custom pillars | | `blockPile(...)` | Piles of blocks | Pumpkin/melon patches | | `deltaFeature(...)` | Basalt delta with contents and rim | Nether basalt deltas | | `disk(...)` | Circular disk of blocks | Clay, sand, gravel patches | | `dripstoneCluster(...)` | Dense dripstone growth | Cave dripstone rooms | | `endGateway(...)` | End gateway portal | End outer islands | | `endSpike(...)` | End obsidian pillar with crystal | The End respawn pillars | | `fillLayer(...)` | Fill a layer with blocks | Custom dimension layers | | `fossil(...)` | Structure-based fossil | Underground fossils | | `geode(...)` | Hollow structure with layered shells | Amethyst geodes | | `hugeBrownMushroom(...)` | Large brown mushroom | Swamp/mushroom island fungi | | `hugeFungus(...)` | Huge nether fungus | Crimson/warped forests | | `hugeRedMushroom(...)` | Large red mushroom | Swamp/mushroom island fungi | | `iceberg(...)` | Iceberg structure | Frozen ocean icebergs | | `lake(...)` | Liquid pool | Underground lava lakes | | `largeDripstone(...)` | Tall stalactite or stalagmite | Cave ceilings/floors | | `multifaceGrowth(...)` | Multi-face block spread | Glow lichen, sculk vein | | `netherForestVegetation(...)` | Nether plant scatter | Warped/crimson forest floors | | `netherrackReplaceBlobs(...)` | Replace netherrack with blobs | Nether gravel/blackstone blobs | | `pointedDripstone(...)` | Single pointed dripstone | Cave stalactites/stalagmites | | `randomBooleanSelector(...)` | Picks one of two features randomly | Symmetric ore variants | | `randomSelector(...)` | Weighted random feature picker | Mixed ore deposits | | `replaceSingleBlock(...)` | Replace blocks by rule targets | Custom block swaps | | `rootSystem(...)` | Root placer for trees | Mangrove roots | | `scatteredOre(...)` | Scattered ore deposits | Nether gold ore blobs | | `sculkPatch(...)` | Sculk spread with catalyst | Ancient city surroundings | | `seagrass(probability)` | Seagrass placement | Ocean floors | | `seaPickle(count)` | Sea pickle colonies | Warm ocean floors | | `simpleRandomSelector(...)` | Uniform random feature picker | Coral type variety | | `spike(...)` | Tall spiky columns | Ice spikes in frozen biomes | | `springFeature(...)` | Fluid source block | Water/lava springs | | `twistingVines(...)` | Twisting vine growth | Warped forest floors | | `underwaterMagma(...)` | Underwater magma blocks | Ocean floors | | `vegetationPatch(...)` | Vegetation on surfaces | Cave moss patches | | `waterloggedVegetationPatch(...)` | Waterlogged vegetation patches | Underwater cave plants | ### No-Config Features These feature types have no configuration fields and are used directly as Kotlin `data object` values: ```kotlin configuredFeature("basalt_pillar", BasaltPillar) configuredFeature("desert_well", DesertWell) ``` | Object | Description | |---------------------|----------------------------------| | `BasaltPillar` | Single basalt pillar | | `BlueIce` | Blue ice patch on icebergs | | `BonusChest` | Bonus chest at spawn | | `ChorusPlant` | Chorus plant on End islands | | `CoralClaw` | Coral claw structure | | `CoralMushroom` | Coral mushroom structure | | `CoralTree` | Coral tree structure | | `DesertWell` | Desert well structure | | `EndIsland` | Small End island | | `EndPlatform` | Obsidian end platform | | `FreezeTopLayer` | Freeze/snow the top layer | | `GlowstoneBlob` | Glowstone blob on Nether ceiling | | `Kelp` | Kelp stalk | | `MonsterRoom` | Monster spawner room | | `NoOp` | Does nothing (placeholder) | | `Vines` | Random vine placement | | `VoidStartPlatform` | Void dimension start platform | | `WeepingVines` | Weeping vines in the Nether | Reference: [Feature types](https://minecraft.wiki/w/Configured_feature#Types) --- ## Placed Features Placed features wrap a configured feature with **placement modifiers** that control where and how often the feature generates. Modifiers are applied in sequence, filtering and transforming placement positions. Reference: [Placed feature](https://minecraft.wiki/w/Placed_feature) ```kotlin val treePlaced = dp.placedFeature("my_tree_placed", treeConfigured) { inSquare() count(constant(10)) heightRange(uniformHeightProvider(64, 128)) biome() } ``` ### Placement Modifiers Modifiers process in order, each one filtering or transforming the placement stream. Common patterns: - Start with `count()` or `rarityFilter()` to control frequency - Use `inSquare()` to spread horizontally within the chunk - Apply `heightRange()` or `heightMap()` for vertical positioning - End with `biome()` to respect biome boundaries Reference: [Placement modifier](https://minecraft.wiki/w/Placed_feature#Placement_modifiers) | Modifier | Description | |---------------------------------------|--------------------------------------------------| | `biome()` | Only place in valid biomes | | `blockPredicateFilter(predicate)` | Custom block condition | | `carvingMask(step)` | Only place in blocks carved by `air` or `liquid` | | `count(n)` | Place n times per chunk | | `countOnEveryLayer(n)` | Place n times on every layer | | `environmentScan(...)` | Scan for valid placement | | `fixedPlacement(...)` | Place at specific absolute positions | | `heightMap(type)` | Place relative to heightmap | | `heightRange(provider)` | Vertical placement range | | `inSquare()` | Spread horizontally in chunk | | `noiseBasedCount(...)` | Count based on noise value at the position | | `noiseThresholdCount(...)` | Fixed count chosen by noise threshold | | `randomOffset(xzSpread, ySpread)` | Scatter placement within an XZ/Y radius | | `rarityFilter(chance)` | 1/chance probability to place | | `surfaceRelativeThresholdFilter(...)` | Surface-relative placement | | `surfaceWaterDepthFilter(maxDepth)` | Max water depth filter | ### Height Providers Height providers control vertical distribution. Different providers create different ore/feature distributions: - **Uniform** - Equal chance at all heights (good for evenly distributed ores) - **Trapezoid** - Peaks in the middle, tapers at edges (vanilla iron ore pattern) - **Biased to bottom** - Concentrates near the minimum Y - **Very biased to bottom** - More extreme bottom concentration (vanilla diamond pattern) - **Weighted list** - Picks from multiple providers by weight Reference: [Height provider](https://minecraft.wiki/w/Height_provider) ```kotlin // Uniform distribution between min and max heightRange(uniformHeightProvider(minInclusive = 0, maxInclusive = 64)) // Triangular distribution (peaks at center) heightRange(trapezoidHeightProvider(minInclusive = 0, maxInclusive = 64, plateau = 20)) // Constant absolute Y heightRange(constantAbsolute(32)) // Constant offset above world bottom heightRange(constantAboveBottom(8)) // Constant offset below world top heightRange(constantBelowTop(8)) // Biased toward the bottom heightRange(biasedToBottomHeightProvider(minInclusive = -64, maxInclusive = 0)) // Strongly biased toward the bottom heightRange(veryBiasedToBottomHeightProvider(minInclusive = -64, maxInclusive = 16)) ``` ### Float Providers Float providers supply a float value sampled at runtime. They appear in configured feature fields like `heightScale`, `stalactiteBluntness`, and `windSpeed`, as well as enchantment effect fields like `volume` and `pitch`. | Provider | Behaviour | |--------------------------------------------|--------------------------------------------------------------------------------------------| | `constant(value)` | Always returns `value`. Serializes as a plain float, no wrapper object. | | `uniform(minInclusive, maxExclusive)` | Uniform random float in `[min, max)`. `maxExclusive` cannot be less than `minInclusive`. | | `clampedNormal(mean, deviation, min, max)` | Samples a normal distribution (`mean`/`deviation`) and clamps the result to `[min, max]`. | | `trapezoid(min, max, plateau)` | Samples a trapezoid distribution spanning `[min, max]` with a flat top of width `plateau`. | Each function also has a `*FloatProvider` alias (`constantFloatProvider`, `uniformFloatProvider`, etc.) for use when both float and int provider imports are in scope. ```kotlin // Fixed scale heightScale = constant(1.5f) // Random uniform pitch 0.8..1.2 (exclusive upper) pitch = uniform(0.8f, 1.2f) // Normal distribution centered at 0.5, clamped to 0..1 heightScale = clampedNormal(mean = 0.5f, deviation = 0.2f, min = 0.0f, max = 1.0f) // Trapezoid: peaks in the center of 0..2, plateau width 0.5 heightScale = trapezoid(min = 0.0f, max = 2.0f, plateau = 0.5f) ``` --- ### Int Providers Int providers supply an integer value sampled at runtime. They are used wherever Minecraft expects a variable count or size, for example `count()`, `countOnEveryLayer()`, or block state providers. | Provider | Behaviour | |--------------------------------------------------------|-------------------------------------------------------------------------------------| | `biasedToBottom(minInclusive, maxInclusive)` | Random integer in `[min, max]`, weighted towards the minimum. | | `clamped(minInclusive, maxInclusive, source)` | Evaluates `source` and clamps its result to `[min, max]`. | | `clampedNormal(minInclusive, maxInclusive, mean, dev)` | Samples a normal distribution (`mean`/`dev`) and clamps the result to `[min, max]`. | | `constant(value)` | Always returns `value`. Serializes as a plain integer, no wrapper object. | | `uniform(minInclusive, maxInclusive)` | Uniform random integer in `[min, max]`. | | `weightedList { }` | Randomly selects one entry from a weighted pool. | ```kotlin // Fixed count count(constant(10)) // Random 3-8 times per chunk, biased towards 3 count(biasedToBottom(3, 8)) // Normal distribution centered at 5, clamped to 1-10 count(clampedNormal(1, 10, mean = 5.0f, deviation = 2.0f)) // Clamped source: reroll uniform(0, 20) but never below 4 or above 12 count(clamped(4, 12, uniform(0, 20))) // Weighted pool: 70% chance of 1, 30% chance of 3 count(weightedList { add(weightedEntry(7, constant(1))) add(weightedEntry(3, constant(3))) }) ``` --- ## Complete Example ```kotlin fun DataPack.createForestFeatures() { // 1) Tree configured feature val oakTreeCfg = tree { blobFoliagePlacer(radius = constant(2), offset = constant(0), height = 3) foliageProvider = simpleStateProvider(Blocks.OAK_LEAVES) straightTrunkPlacer(baseHeight = 5, heightRandA = 2, heightRandB = 0) trunkProvider = simpleStateProvider(Blocks.OAK_LOG) } val oakTree = configuredFeature("oak_tree", oakTreeCfg) {} // 2) Tree placed feature val oakTreePlaced = placedFeature("oak_tree_placed", oakTree) { inSquare() count(constant(8)) heightRange(uniformHeightProvider(64, 100)) biome() } // 3) Flower configured feature val flowerCfg = simpleBlock(toPlace = simpleStateProvider(Blocks.POPPY)) val flower = configuredFeature("forest_flower", flowerCfg) {} // 4) Flower placed feature val flowerPlaced = placedFeature("forest_flower_placed", flower) { inSquare() rarityFilter(4) heightRange(uniformHeightProvider(64, 100)) biome() } // 5) Ore configured feature val ironOreCfg = ore( size = 9, discardChanceOnAirExposure = 0.0, targets = listOf(Target()) ) val ironOre = configuredFeature("iron_ore", ironOreCfg) {} // 6) Ore placed feature val ironOrePlaced = placedFeature("iron_ore_placed", ironOre) { inSquare() count(constant(20)) heightRange(uniformHeightProvider(-64, 72)) biome() } // 7) Use in biome biome("custom_forest") { temperature = 0.7f downfall = 0.8f hasPrecipitation = true attributes { skyColor(0x78A7FF) fogColor(0xC0D8FF) waterFogColor(0x050533) } effects { waterColor = color(0x3F76E4) } features { undergroundOres = listOf(ironOrePlaced) vegetalDecoration = listOf(oakTreePlaced, flowerPlaced) } } } ``` --- ## Noise & Terrain --- root: .components.layouts.MarkdownLayout title: Noise & Terrain nav-title: Noise description: Define terrain shaping with density functions, noise definitions, and noise settings. keywords: minecraft, datapack, kore, worldgen, noise, density function, noise settings, terrain date-created: 2026-02-03 date-modified: 2026-02-03 routeOverride: /docs/data-driven/worldgen/noise --- # Noise & Terrain Noise and density functions are the mathematical foundation of Minecraft's terrain generation. They control everything from mountain heights to cave shapes, creating the continuous, natural-looking landscapes players explore. ## How Terrain Generation Works Minecraft uses **density functions** to determine whether each position in 3D space should be solid or air. Positive density = solid block, negative density = air. These functions sample from **noise definitions** (Perlin noise with configurable octaves) to create smooth, natural variation. The **noise router** connects density functions to specific terrain aspects: base terrain shape, cave carving, aquifer placement, ore vein distribution, and biome parameters. References: [Density function](https://minecraft.wiki/w/Density_function), [Noise](https://minecraft.wiki/w/Noise), [Noise settings](https://minecraft.wiki/w/Noise_settings) --- ## Density Functions Density functions are composable mathematical operations that output a density value for any 3D position. They can be combined, transformed, and cached to build complex terrain shapes from simple primitives. Reference: [Density function](https://minecraft.wiki/w/Density_function) ```kotlin val df = dp.densityFunction("my_density", type = /* DensityFunctionType */) {} ``` ### Common Density Function Types | Type | Description | |-----------------------------------------------|--------------------------------| | `constant` | Fixed value everywhere | | `noise` | Sample from a noise definition | | `yClampedGradient` | Gradient based on Y coordinate | | `add`, `mul` | Combine two density functions | | `min`, `max` | Take min/max of two functions | | `blend_density` | Blend between functions | | `cache_2d`, `cache_once`, `cache_all_in_cell` | Caching wrappers | | `interpolated` | Smooth interpolation | | `flat_cache` | 2D cache for flat operations | | `spline` | Cubic spline interpolation | --- ## Noise Definitions Noise definitions configure Perlin noise parameters. Perlin noise creates smooth, continuous random values that look natural. **Octaves** layer multiple noise samples at different scales-lower octaves create large features (continents), higher octaves add fine detail (small hills). Reference: [Noise](https://minecraft.wiki/w/Noise) ```kotlin val noise = dp.noise("my_noise") { firstOctave = -7 amplitudes = listOf(1.0, 1.0, 0.5) } ``` ### Parameters | Parameter | Description | |---------------|-------------------------------------------| | `firstOctave` | Starting octave (negative = larger scale) | | `amplitudes` | List of amplitude weights per octave | **Understanding octaves:** `firstOctave = -7` means the first octave operates at 2⁷ = 128 block scale. Each subsequent octave doubles in frequency (halves in scale). Amplitudes weight each octave's contribution-typically decreasing for higher octaves to add detail without overwhelming the base shape. --- ## Noise Settings Noise settings define the complete terrain generation configuration for a dimension. They specify world bounds, default blocks, the noise router (which density functions control which terrain aspects), and surface rules. Reference: [Noise settings](https://minecraft.wiki/w/Noise_settings) ```kotlin val terrain = dp.noiseSettings("my_terrain") { // Vertical bounds noiseOptions(minY = -64, height = 384, sizeHorizontal = 1, sizeVertical = 2) // Default blocks defaultBlock(Blocks.STONE) {} defaultFluid(Blocks.WATER) { this["level"] = "0" } // Noise router (terrain shaping) // noiseRouter { ... } // Surface rules // surfaceRule = ... // Spawn target // spawnTarget = ... } ``` ### Noise Options ```kotlin noiseOptions( minY = -64, // Minimum Y level height = 384, // Total height (must be multiple of 16) sizeHorizontal = 1, // Horizontal noise size (1, 2, or 4) sizeVertical = 2 // Vertical noise size (1, 2, or 4) ) ``` ### Default Blocks ```kotlin // Solid terrain block defaultBlock(Blocks.STONE) {} // Fluid block with properties defaultFluid(Blocks.WATER) { this["level"] = "0" } ``` ### Noise Router The noise router maps density functions to specific terrain generation roles. Each field controls a different aspect of world generation: Reference: [Noise router](https://minecraft.wiki/w/Noise_settings#Noise_router) ```kotlin noiseRouter { // Core terrain finalDensity = /* density function */ initialDensity = /* density function */ // Aquifers and ore veins barrier = /* density function */ fluidLevelFloodedness = /* density function */ fluidLevelSpread = /* density function */ lava = /* density function */ veinToggle = /* density function */ veinRidged = /* density function */ veinGap = /* density function */ // Biome and erosion continents = /* density function */ erosion = /* density function */ depth = /* density function */ ridges = /* density function */ temperature = /* density function */ vegetation = /* density function */ } ``` ### Surface Rules Surface rules determine which blocks appear on the terrain surface. They're evaluated top-to-bottom, with the first matching rule winning. Conditions can check biome, depth, noise values, and more. Reference: [Surface rule](https://minecraft.wiki/w/Surface_rule) ```kotlin surfaceRule = sequence( condition( biome(Biomes.DESERT), block(Blocks.SAND) ), condition( stoneDepthFloor(offset = 0, addSurfaceDepth = false, secondaryDepthRange = 0), block(Blocks.GRASS_BLOCK) ), block(Blocks.STONE) ) ``` --- ## Complete Example ```kotlin fun DataPack.createCustomTerrain() { // 1) Custom noise definition val hillsNoise = noise("hills_noise") { firstOctave = -5 amplitudes = listOf(1.0, 0.5, 0.25) } // 2) Noise settings for terrain val terrain = noiseSettings("custom_terrain") { noiseOptions(minY = -64, height = 384, sizeHorizontal = 1, sizeVertical = 2) defaultBlock(Blocks.STONE) {} defaultFluid(Blocks.WATER) { this["level"] = "0" } } // 3) Use in dimension val dimType = dimensionType("custom_type") { minY = -64 height = 384 hasSkylight = true } dimension("custom_world", type = dimType) { noiseGenerator( settings = terrain, biomeSource = /* your biome source */ ) } } ``` --- ## Structures --- root: .components.layouts.MarkdownLayout title: Structures nav-title: Structures description: Create structures with template pools, processors, and structure sets using Kore's DSL. keywords: minecraft, datapack, kore, worldgen, structure, template pool, processor, jigsaw date-created: 2026-02-03 date-modified: 2026-02-15 routeOverride: /docs/data-driven/worldgen/structures --- # Structures Structures are large, complex generated features like villages, temples, strongholds, and dungeons. Unlike simple features (trees, ores), structures can span multiple chunks and consist of interconnected pieces assembled using the **jigsaw system**. ## Structure Generation Pipeline Structure generation involves four interconnected components: 1. **Processor list** - Modifies blocks when placing structure pieces (aging, randomization, gravity adjustment) 2. **Template pool** - Defines weighted collections of structure pieces that can connect via jigsaw blocks 3. **Configured structure** - Specifies the structure type, starting pool, biome restrictions, and terrain adaptation 4. **Structure set** - Controls world-scale placement: spacing between structures, clustering, and exclusion zones Structures generate during the `structures_starts` step, before terrain features. This allows terrain to adapt around structures rather than structures cutting through terrain. References: [Structure](https://minecraft.wiki/w/Structure), [Structure definition](https://minecraft.wiki/w/Structure_definition), [Structure set](https://minecraft.wiki/w/Structure_set), [Template pool](https://minecraft.wiki/w/Template_pool), [Processor list](https://minecraft.wiki/w/Processor_list) --- ## Processor List Processor lists transform blocks when structure pieces are placed. They enable effects like aging (cracked bricks, mossy stone), randomization (varied block types), and terrain adaptation (gravity for surface structures). Reference: [Processor list](https://minecraft.wiki/w/Processor_list) ```kotlin val processors = dp.processorList("my_processors") { processors = listOf( // Add processor entries here ) } ``` ### Common Processors | Processor | Description | |--------------------|---------------------------------------------| | `block_rot` | Randomly rotates blocks | | `block_ignore` | Ignores certain blocks during placement | | `block_age` | Ages blocks (cracks, moss) | | `gravity` | Adjusts Y position to terrain | | `rule` | Replaces blocks based on rules | | `protected_blocks` | Prevents certain blocks from being replaced | | `capped` | Limits processor applications | --- ## Template Pool Template pools define weighted collections of structure pieces for jigsaw structures. The jigsaw system connects pieces by matching jigsaw block names, allowing modular structure assembly. Each pool can reference other pools for recursive generation (e.g., village houses connecting to streets connecting to more houses). Reference: [Template pool](https://minecraft.wiki/w/Template_pool) ```kotlin val pool = dp.templatePool("my_pool") { fallback = TemplatePools.Empty elements { // Add weighted template pool entries } } ``` ### Pool Elements ```kotlin elements { // Single piece with weight singlePoolElement( location = "my_namespace:structures/house", projection = Projection.RIGID, processors = myProcessors, weight = 1 ) // Empty element (for spacing) emptyPoolElement(weight = 1) // Feature element featurePoolElement( feature = myPlacedFeature, projection = Projection.TERRAIN_MATCHING, weight = 1 ) // List of elements (all placed together) listPoolElement( elements = listOf(/* ... */), projection = Projection.RIGID, weight = 1 ) } ``` ### Projection Types | Type | Description | |--------------------|--------------------------| | `RIGID` | Maintains original shape | | `TERRAIN_MATCHING` | Adapts to terrain height | --- ## Configured Structure Configured structures define the structure type, starting template pool, biome restrictions, generation step, and terrain adaptation settings. The structure type determines the generation algorithm (jigsaw assembly, single piece, or specialized logic). Reference: [Structure definition](https://minecraft.wiki/w/Structure_definition) ```kotlin dp.structures { // Use the StructuresBuilder DSL } ``` ### Structure Types Common structure types include: - `jigsaw` - Modular structures using template pools - `buried_treasure` - Single buried chest - `desert_pyramid` - Desert temple - `end_city` - End city - `fortress` - Nether fortress - `igloo` - Igloo with optional basement - `jungle_temple` - Jungle temple - `mineshaft` - Underground mineshaft - `monument` - Ocean monument - `nether_fossil` - Nether fossil - `ocean_ruin` - Ocean ruins - `ruined_portal` - Ruined portal - `shipwreck` - Shipwreck - `stronghold` - Stronghold - `swamp_hut` - Witch hut - `woodland_mansion` - Woodland mansion ### Terrain Adaptation | Value | Description | |---------------|---------------------------------------------------------------| | `NONE` | No adaptation | | `BEARD_THIN` | Generates terrain under the structure, removes terrain inside | | `BEARD_BOX` | Advanced alternative of beard_thin | | `BURY` | Generates terrain surrounding the structure to make it buried | | `ENCAPSULATE` | Advanced alternative of bury (used by Trial Chambers) | ### Pool Aliases Pool aliases rewire jigsaw pool connections by redirecting pool references on individual structure instances. ```kotlin poolAliases { // Direct: rewire alias to a specific target directPoolAlias(TemplatePools.Empty, TemplatePools.Empty) // Random: rewire alias to a randomly selected weighted target randomPoolAlias(TemplatePools.Empty) { weightedPoolEntry(1, myPool) weightedPoolEntry(2, otherPool) } // Random group: select a weighted group of pool aliases randomGroupPoolAlias { weightedGroupEntry(1) { directPoolAlias(TemplatePools.Empty, myPool) randomPoolAlias(TemplatePools.Empty) { weightedPoolEntry(1, otherPool) } } } } ``` --- ## Structure Set Structure sets control world-scale placement using a grid-based system. **Spacing** defines the grid cell size (average distance), while * *separation** ensures minimum distance between structures. Multiple structures can share a set with weights for mutual exclusion (only one generates per cell). Reference: [Structure set](https://minecraft.wiki/w/Structure_set) ```kotlin val structSet = dp.structureSet("my_structures") { structure(myConfiguredStructure, weight = 1) // Placement type randomSpreadPlacement(spacing = 32, separation = 8) { // Optional: salt, spreadType, etc. } } ``` ### Placement Types #### Random Spread The most common placement type. Divides the world into a grid where each cell may contain one structure at a random position. The `salt` value ensures different structure sets don't align their grids. ```kotlin randomSpreadPlacement( spacing = 32, // Average distance between structures separation = 8 // Minimum distance between structures ) { salt = 12345 // Seed modifier for randomization spreadType = SpreadType.LINEAR // or TRIANGULAR } ``` #### Concentric Rings Places structures in expanding rings around the world origin. Used by strongholds to ensure they're distributed at increasing distances from spawn. Reference: [Structure set - Concentric rings](https://minecraft.wiki/w/Structure_set#concentric_rings) ```kotlin concentricRingsPlacement( distance = 32, spread = 3, count = 128 ) ``` --- ## Complete Example ```kotlin fun DataPack.createCustomVillage() { // 1) Processor list for aging blocks val villageProcessors = processorList("village_processors") { processors = listOf( // Add aging, gravity, etc. ) } // 2) Template pool for houses val housesPool = templatePool("village/houses") { fallback = TemplatePools.Empty elements { singlePoolElement( location = "my_pack:village/house_small", projection = Projection.RIGID, processors = villageProcessors, weight = 3 ) singlePoolElement( location = "my_pack:village/house_large", projection = Projection.RIGID, processors = villageProcessors, weight = 1 ) } } // 3) Start pool (village center) val startPool = templatePool("village/start") { fallback = TemplatePools.Empty elements { singlePoolElement( location = "my_pack:village/center", projection = Projection.RIGID, processors = villageProcessors, weight = 1 ) } } // 4) Configured structure (via structures builder) structures { // Define jigsaw structure referencing startPool } // 5) Structure set for placement structureSet("custom_villages") { // structure(customVillage, weight = 1) randomSpreadPlacement(spacing = 34, separation = 8) { salt = 10387312 } } } ``` --- ## World Presets --- root: .components.layouts.MarkdownLayout title: World Presets nav-title: World Presets description: Create world presets and flat level generator presets with Kore's DSL. keywords: minecraft, datapack, kore, worldgen, world preset, flat, superflat date-created: 2026-02-03 date-modified: 2026-02-04 routeOverride: /docs/data-driven/worldgen/world-presets --- # World Presets World presets define complete world configurations that appear in the "World Type" dropdown during world creation. They specify which dimensions exist and how each generates terrain. Vanilla presets include Default, Superflat, Large Biomes, Amplified, and Single Biome. Custom world presets let you offer players pre-configured world types with your custom dimensions, terrain, and biomes. Reference: [World preset](https://minecraft.wiki/w/World_preset) --- ## World Preset A world preset defines the complete dimension configuration for a world. At minimum, it should include an Overworld dimension, but can also customize or replace the Nether and End, or add entirely new dimensions. ```kotlin dp.worldPreset("my_preset") { dimension(DimensionTypes.OVERWORLD) { type = myDimType // Generator configuration } // Optionally add NETHER, END, or custom dimensions } ``` ### Basic Example ```kotlin dp.worldPreset("custom_world") { // Overworld with custom terrain dimension(DimensionTypes.OVERWORLD) { type = myOverworldType noiseGenerator( settings = myNoiseSettings, biomeSource = multiNoise { /* ... */ } ) } // Standard Nether dimension(DimensionTypes.THE_NETHER) { type = DimensionTypes.THE_NETHER noiseGenerator( settings = NoiseSettings.NETHER, biomeSource = multiNoise { /* ... */ } ) } // Standard End dimension(DimensionTypes.THE_END) { type = DimensionTypes.THE_END noiseGenerator( settings = NoiseSettings.END, biomeSource = theEnd() ) } } ``` ### Custom Dimension in Preset ```kotlin dp.worldPreset("aether_world") { // Replace Overworld with custom dimension dimension(DimensionTypes.OVERWORLD) { type = aetherDimType noiseGenerator( settings = aetherNoise, biomeSource = checkerboard(scale = 3, highlands, forest, shores) ) } } ``` --- ## Flat Level Generator Preset Flat level generator presets appear in the Superflat customization screen, offering quick-select layer configurations. Vanilla presets include Classic Flat, Tunnelers' Dream, Water World, and Redstone Ready. Reference: [Superflat - Presets](https://minecraft.wiki/w/Superflat#Presets) ```kotlin val flatPreset = dp.flatLevelGeneratorPreset("classic_flat") { // Display item in UI // displayItem = Items.GRASS_BLOCK // Flat world settings // layers, biome, structure overrides } ``` ### Flat Generator Layers When using a flat generator in a dimension: ```kotlin dimension("flat_world", type = myDimType) { flatGenerator(biome = Biomes.PLAINS) { layers { layer(Blocks.BEDROCK, height = 1) layer(Blocks.STONE, height = 3) layer(Blocks.DIRT, height = 3) layer(Blocks.GRASS_BLOCK, height = 1) } // structureOverrides = ... } } ``` --- ## Complete Example ```kotlin fun DataPack.createSkylandsPreset() { // 1) Custom dimension type val skyType = dimensionType("skylands_type") { minY = 0 height = 256 hasSkylight = true hasCeiling = false natural = true ambientLight = 0.1f attributes { canStartRaid(true) bedRule( BedRule( canSleep = BedSleepRule.ALWAYS, canSetSpawn = BedSleepRule.ALWAYS, explodes = false, ) ) } } // 2) Noise settings val skyNoise = noiseSettings("skylands_noise") { noiseOptions(minY = 0, height = 256, sizeHorizontal = 2, sizeVertical = 1) defaultBlock(Blocks.STONE) {} defaultFluid(Blocks.WATER) { this["level"] = "0" } } // 3) Biome val skyBiome = biome("skylands_biome") { temperature = 0.5f downfall = 0.5f hasPrecipitation = true attributes { skyColor(0x87CEEB) fogColor(0xC0D8FF) waterFogColor(0x050533) } effects { waterColor = color(0x3F76E4) } } // 4) World preset worldPreset("skylands") { dimension(DimensionTypes.OVERWORLD) { type = skyType noiseGenerator( settings = skyNoise, biomeSource = fixed(skyBiome) ) } } } ``` ## See Also - [Biomes](/docs/data-driven/worldgen/biomes) - Climate, visuals, mob spawns, and features - [Dimensions](/docs/data-driven/worldgen/dimensions) - Dimension types and generators - [Environment Attributes](/docs/data-driven/worldgen/environment-attributes) - Visual, audio, and gameplay attributes for biomes and dimensions - [World Generation](/docs/data-driven/worldgen) - Overview of the worldgen system --- # Concepts ## Runtime Logic - Kotlin vs Minecraft: Variables, Conditions & Loops --- root: .components.layouts.MarkdownLayout title: "Runtime Logic - Kotlin vs Minecraft: Variables, Conditions & Loops" nav-title: Runtime Logic description: "The key concept for Kore datapacks: how compile-time Kotlin maps to runtime Minecraft logic. Variables via scoreboards and storage, conditions via execute if/unless, and loops via tick functions and schedulers." keywords: minecraft runtime logic, datapack variables, datapack conditions, datapack loops, kore runtime, datapack tick function, execute if unless, minecraft scoreboard variable, datapack programming, kore compile time date-created: 2026-06-24 date-modified: 2026-06-24 routeOverride: /docs/concepts/runtime-logic position: 2 --- # Runtime Logic This is the single most important concept to understand when moving from raw datapacks (or any imperative language) to Kore. Get this right and everything else clicks into place. ## The two worlds When you write Kore, your code runs in **two completely separate worlds** at two different times: | | Compile-time (build) | Runtime (in-game) | |---------------------|--------------------------------------------------------|----------------------------------------------------| | **When** | When you run your `main` function to generate the pack | When Minecraft executes the generated functions | | **Language** | Kotlin | Minecraft commands (`.mcfunction`) | | **`val` / `var`** | Real Kotlin variables | Do not exist - use scoreboards / storage | | **`if` / `else`** | Real Kotlin branches | Do not exist - use `execute if` / predicates | | **`for` / `while`** | Real Kotlin loops | Do not exist - use recursion / `schedule` / macros | | **Knows** | Everything in your Kotlin code | Only the live world state | Kotlin `val`, `var`, `if`, `for`, `while` are **generation-time** tools. They decide *what commands get written into your datapack*. They are gone by the time the pack runs. They never look at the player, the world, or a score. To react to the live game (a player's score, a block in the world, an entity that exists right now), you need **runtime tools**: scoreboards, data storage, the `execute` command, predicates, and macros. ## Compile-time: Kotlin builds your commands Standard Kotlin runs once, when you generate the pack. Use it to remove repetition and assemble functions. ```kotlin function("setup_teams") { // This Kotlin `for` runs at generation time. It does NOT loop in-game. // It writes 3 separate command lines into the generated function. for (color in listOf("red", "blue", "green")) { scoreboard.objectives.add("kills_$color") } } ``` The generated `.mcfunction` is just three flat lines: ```mcfunction scoreboard objectives add kills_red dummy scoreboard objectives add kills_blue dummy scoreboard objectives add kills_green dummy ``` There is no loop left in the output. The `for` was a **code generator**, not in-game behavior. The same goes for `if`: ```kotlin val debugMode = true function("tick") { movePlayers() if (debugMode) { // Included only because `debugMode` was true AT BUILD TIME. // Flip it to false and this command simply isn't generated. say("debug: tick ran") } } ``` ## Runtime: variables In-game you cannot store a value in a Kotlin `var`. The two runtime containers are **scoreboards** (for integers) and **data storage** (for any NBT: strings, lists, compounds, decimals). ### Scoreboards - integer variables See [Scoreboards](/docs/concepts/scoreboards) for the full command reference. ```kotlin load { scoreboard.objectives.add("coins") } function("give_coin") { // runtime: read-modify-write a per-player integer scoreboard.players.add(self(), "coins", 1) } ``` For arithmetic between scores, use `operation`, or reach for [Scoreboard Math](/docs/helpers/scoreboard-math) when you need trigonometry/algebra. ### Data storage - everything else See [Data Storage](/docs/concepts/data-storage) for the full guide. Storage holds strings, lists and compounds that scores cannot: ```kotlin val state = storage("state", "my_pack") function("set_name") { data(state) { set("player_name", "Steve") } } ``` ## Runtime: conditions (if / else) There is no in-game `if`. You branch with the `execute if` / `execute unless` chain ( see [Execute](/docs/commands/execute)) or by referencing a [Predicate](/docs/data-driven/predicates). ```kotlin function("reward_rich_players") { // runtime: "if the player's coins >= 100, run the reward" execute { ifCondition { score(self(), "coins", rangeOrInt(100)) // matches 100.. } run { say("You are rich!") } } } ``` ### Emulating if / else Minecraft has no `else`. The cleanest pattern is two mirrored checks (`if` then `unless`), or an early `return` so the second branch only runs when the first did not. ```kotlin function("check_score") { execute { ifCondition { score(self(), "coins", rangeOrInt(100)) } run { say("rich") } } execute { unlessCondition { score(self(), "coins", rangeOrInt(100)) } run { say("poor") } } } ``` For reusable, complex conditions, build a [Predicate](/docs/data-driven/predicates) once and reference it: ```kotlin val isRaining = predicate("is_raining") { weatherCheck(raining = true, thundering = false) } function("rain_warning") { execute { ifCondition(isRaining) run { say("It is raining") } } } ``` ## Runtime: loops There is no in-game `for` or `while`. The three runtime looping patterns are **function recursion**, **`schedule`**, and **iterating an entity selector**. ### Recursion (loop a fixed/conditional number of times) A function that calls itself loops once per tick step. Use a score as the counter and `execute if`/`unless` as the guard so it stops. ```kotlin load { scoreboard.objectives.add("countdown") scoreboard.players.set(self(), "countdown", 5) } val tickFunction = function("countdown_tick") { say("tick") scoreboard.players.remove(self(), "countdown", 1) // keep going only while countdown > 0 execute { ifCondition { score(self(), "countdown", rangeOrInt(1)) } // 1.. run(this@function) // self-recursion: call this same function again } } ``` ### `schedule` (loop over time) `schedule` re-runs a function after a delay - ideal for spacing work across ticks instead of hammering every tick. See [Time](/docs/concepts/time) for the `.ticks` / `.seconds` helpers. ```kotlin val loop = function("spawn_wave") { summon(EntityTypes.ZOMBIE, vec3()) schedule(2.seconds, this@function) // re-run myself in 2 seconds } ``` ### Iterating entities To "loop over all players", run the body **as** each matched entity - the selector does the iteration: ```kotlin function("heal_everyone") { execute { asTarget(allPlayers()) run { effect(self()) { give(Effects.REGENERATION, duration = 5) } } } } ``` ## Macros: when text must be dynamic A score holds a number, storage holds NBT, but sometimes you need to inject a runtime value into a part of a command that is normally fixed text (a name, a coordinate). That is what [Macros](/docs/commands/macros) are for - runtime string substitution. They are not variables: you cannot do math on them, only paste them into the command text. ```kotlin function("greet") { // `$(name)` is filled in from the NBT passed when the function is called say("Hello ${macro("name")}!") } ``` ## Mental model cheat sheet - Need to **remove repetition while writing** the pack? Use Kotlin `for` / `if` / functions. (compile-time) - Need to **remember a number** in-game? Scoreboard. (runtime) - Need to **remember text / a list / decimals** in-game? Data storage. (runtime) - Need to **branch** on live world state? `execute if` / `unless` or a predicate. (runtime) - Need to **repeat** in-game? Recursion, `schedule`, or an entity selector. (runtime) - Need to **paste a runtime value into command text**? Macro. (runtime) ## See also - [Execute](/docs/commands/execute) - the runtime control-flow command - [Data Storage](/docs/concepts/data-storage) - the runtime NBT variable container - [Scoreboards](/docs/concepts/scoreboards) - runtime integer variables --- ## Data Storage - Runtime NBT Variables with /data Command in Kore --- root: .components.layouts.MarkdownLayout title: Data Storage - Runtime NBT Variables with /data Command in Kore nav-title: Data Storage description: Use Minecraft data storage as runtime NBT variables in Kore. Set, modify, copy, and read values with the /data command DSL. Store strings, lists, and compounds beyond integer-only scoreboards. keywords: minecraft data storage, /data command, datapack nbt storage, data modify, data get, data merge, runtime variables minecraft, kore data, storage macros, datapack variable container date-created: 2026-06-24 date-modified: 2026-06-24 routeOverride: /docs/concepts/data-storage position: 3 --- # Data Storage Data storage is Minecraft's general-purpose **runtime variable container**. Where a [scoreboard](/docs/concepts/scoreboards) only holds integers, storage holds any NBT value: strings, decimals, lists, and nested compounds. It is the natural place to keep in-game state that is not a plain number. If you are unsure when to use Kotlin variables versus storage, read [Runtime Logic](/docs/concepts/runtime-logic) first - storage lives entirely at **runtime**, in the running world, not at generation time. This page covers the storage form of the [`/data` command](https://minecraft.wiki/w/Commands/data). The same DSL also works on entities (`data(self())`) and blocks (`data(blockPos)`); only the target changes. ## Creating a storage handle A storage is identified by a namespaced id. Create a typed handle with `storage(...)`: ```kotlin val state = storage("state", "my_pack") // -> my_pack:state ``` The first argument is the path, the second is the namespace (defaults to `minecraft`). Reuse the same handle everywhere you read or write that storage. ## Writing values Open the `/data` DSL with `data(target) { ... }` and write with `set`: ```kotlin function("init_state") { data(state) { set("player_name", "Steve") // string set("level", 1) // int set("ratio", 0.5f) // float set("active", true) // boolean } } ``` Each `set("path", value)` emits a `data modify storage my_pack:state set value ` line. ### Writing compounds and lists For structured data, use `merge` with an NBT builder, which writes a whole compound at once: ```kotlin function("init_player") { data(state) { merge { this["name"] = "Steve" this["level"] = 1 this["inventory"] = nbtListOf("sword", "shield") } } } ``` See [NBTs](/docs/concepts/nbts) for the full NBT builder DSL. ## Reading values Use `get` to read a value (Minecraft prints it / returns it as a command result): ```kotlin function("show_level") { data(state) { get("level") // data get storage my_pack:state level get("ratio", scale = 100.0) // read and scale the numeric result } } ``` The `scale` parameter multiplies a numeric result - handy for moving a value into a scoreboard with a fixed-point factor (see [Bridging storage and scoreboards](#bridging-storage-and-scoreboards)). ## Modifying values `modify` exposes every `/data modify` operation - `set`, `merge`, `append`, `prepend`, `insert`, and the `from`/`string` source forms. The block receiver is `DataModifyOperation`: ```kotlin function("update_state") { data(state) { // overwrite a path modify("level") { set(2) } // copy a value from another data source (entity, block, or storage) modify("position") { set(self(), "Pos") } // list operations modify("inventory") { append("bow") } modify("inventory") { prepend("helmet") } modify("inventory") { insert(1, "potion") } // substring of a string source modify("initial") { set(self(), "SelectedItem.id", 0, 1) } } } ``` There are convenient shorthands for the common `set` cases: ```kotlin data(state) { modify("level", 5) // set to a literal modify("owner", self(), "UUID") // copy from another target's path } ``` ## Removing values ```kotlin function("reset_state") { data(state) { remove("inventory") remove("level") } } ``` ## Bracket shorthand For one-off reads and writes you can skip the block and use index syntax: ```kotlin function("quick") { data(state)["level"] = 5 // write data(state)["level"] // read (data get) } ``` ## Bridging storage and scoreboards Storage and scoreboards are the two runtime containers, and you often move values between them. Use `execute store` to write a command's numeric result into either one (see [Execute](/docs/commands/execute)): ```kotlin function("level_to_score") { // read storage `level` and store it into the `levels` scoreboard objective execute { storeResult { score(self(), "levels") } run { data(state) { get("level") } } } } ``` The reverse - score into storage - is the same pattern with `storeResult { storage(state, "level", DataType.INT, 1.0) }`. ## Macros read straight from storage Storage is the canonical source for [macro](/docs/commands/macros) arguments. You can pass a storage path as the arguments to a function call, and its compound becomes the macro inputs: ```kotlin val teleport = function("teleport") { teleport(player(macro("name")), vec3()) } function("run_teleport") { // fills $(name) from the `target` compound in storage function(teleport, arguments = state, path = "target") } ``` ## When to use storage vs scoreboards | Use a **scoreboard** when... | Use **storage** when... | |------------------------------------------|-----------------------------------------------------| | The value is a single integer | The value is text, a decimal, a list, or a compound | | You need fast arithmetic / comparisons | You need to pass structured data to a macro | | It is per-entity (uses the score holder) | It is global or grouped state | | You branch on it with `execute if score` | You branch on it with `execute if data` | In practice most packs use both: scoreboards for counters and math, storage for everything structured. ## See also - [Runtime Logic](/docs/concepts/runtime-logic) - where storage fits in the compile-time vs runtime model - [NBTs](/docs/concepts/nbts) - the NBT builder DSL used by `set` / `merge` - [Execute](/docs/commands/execute) - `store` results into storage, branch with `if data` --- ## Chat Components --- root: .components.layouts.MarkdownLayout title: Chat Components nav-title: Chat Components description: A guide for creating Chat Components in a Minecraft datapack using Kore. keywords: minecraft, datapack, kore, guide, chat-components date-created: 2024-09-05 date-modified: 2026-06-26 routeOverride: /docs/concepts/chat-components --- # Chat Components Chat Components are used to create rich text messages in Minecraft. They can include formatting, interactivity, and nested components. Kore has functions to create and manipulate Chat Components in a datapack.
Note that they always work by groups named `ChatComponents`, whenever you create a chat component, you actually create a `ChatComponents`, and you can chain multiple components together using the `+` operator. Minecraft sometimes does not allow "complex" chat components with data resolving (`score`, `nbt` and `entity` chat components), if you use them, you'll get an empty text component. Simple chat components are inheriting the `SimpleComponent` interface, and you have a `containsOnlySimpleComponents` property to check if a `ChatComponents` only contains simple components. You also have a `containsOnlyText()` function to check if a `ChatComponents` only contains plain text components with no formatting. ### Common Properties - `bold` - Whether the text is bold. - `clickEvent` - The action to perform when the text is clicked. - `color` - The color of the text. - `extra` - Additional components to display after this one (prefer using the `+` operator). - `font` - The font to use. - `hoverEvent` - The action to perform when the text is hovered over. - `insertion` - The text to insert into the chat when the text is shift-clicked. - `italic` - Whether the text is italic. - `obfuscated` - Whether the text is obfuscated. - `shadowColor` - The color of the shadow behind the text. - `strikethrough` - Whether the text is strikethrough. - `text` - The text to display. - `underlined` - Whether the text is underlined. ## PlainTextComponent The `PlainTextComponent` displays simple text with optional formatting such as color and bold.
To create a `PlainTextComponent`, use the `textComponent` function. ### Example ```kotlin val plainText = textComponent("Hello, world!") { color = Color.RED bold = true } ``` In-game output:
![Simple Hello World in bold red](/doc/chat-components/hello-world.png) See how to set custom colors in the [Colors](/docs/concepts/colors) article. ### Combined Components Components can be combined using the `+` operator, use the `text` function to create a simple text component and not a `ChatComponents`. ```kotlin val combinedComponents = textComponent("Hello, ") + text("world!") { color = Color.RED bold = true } ``` In-game output:
![Combined Hello World](/doc/chat-components/combined-hello-world.png) > (only the "world!" part is bold and red) ## EntityComponent The `EntityComponent` displays the name of an entity selected by a selector. If multiple entities are found, their names are displayed in the form `Name1, Name2` etc.
The `separator` property can be used to change the separator between the names of the entities.
If no entities are found, the component displays nothing. ### Example ```kotlin val entityComponent = entityComponent(self()) ``` In-game example:
![Hello World of the player](/doc/chat-components/entity.png) ## KeybindComponent The `KeybindComponent` displays a keybind. The keybind is displayed in the player's keybind settings. ### Example ```kotlin val keybindComponent = keybindComponent("key.sprint") ``` In-game example:
![Keybind Component Example](/doc/chat-components/keybind.png) ## NbtComponent The `NbtComponent` displays NBT data from a block, an entity, or a storage. The `interpret` property can be used to interpret the NBT data as a text component, if the parsing fails, nothing is displayed.
The `plain` property suppresses SNBT key/value coloring when set to `true`; it cannot be combined with `interpret`.
The `nbt` property can be used to specify the path to the NBT data.
If `nbt` points to an array, then it will display all the elements joined in the form `Element1, Element2` etc.
The `separator` property can be used to change the separator between the elements of the array. If you need a refresher on how Kore builds NBT in general, see [NBTs](/docs/concepts/nbts) for the shared builder DSL, common helpers, and other contexts that use the same patterns. ### Example ```kotlin val nbtComponent = nbtComponent("Health", entity = nearestEntity { type = EntityType.CREEPER }) ``` You can also point it at block positions or storages depending on the source you want to read from. In-game output:
![NBT Component Example](/doc/chat-components/nbt-health.png) ## ScoreComponent The `ScoreComponent` displays the score of an entity for a specific objective. The `name` property can be used to specify the name of the entity whose score to display, it can be a selector or a literal name (will use the player with that name). It can also be `*` to select the entity seeing the text component.
The `objective` property can be used to specify the name of the objective to display the score of.
A `value` property can be used to specify a fixed value to display regardless of the score. ### Example ```kotlin val scoreComponent = scoreComponent("test") ``` In-game output:
![Score Component Example](/doc/chat-components/score.png) ## TranslatedTextComponent The `TranslatedTextComponent` displays translated text using translation keys. You can also pass arguments to the translation key with the `with` argument, which is a list of strings or a list of components - so the result of any component factory ( `scoreComponent`, `entityComponent`, `textComponent`, etc) can be passed directly.
A `fallback` property can be used to specify a fallback text if the translation key is not found. ### Example ```kotlin // Strings are wrapped as text components automatically. val translatedFromStrings = translatedTextComponent("chat.type.text", listOf("Ayfri", "Hello !")) // Or pass components directly, no need to unwrap them. val translatedFromComponents = translatedTextComponent( "chat.type.text", listOf( textComponent("Ayfri", color = Color.AQUA), scoreComponent("kills", self()), ) ) ``` In-game output:
![Translated Text Component Example](/doc/chat-components/translation.png) ## Hover Event Hover events display extra information when the text is hovered over, it can be either text, an item, or an entity. Use `showText` to display text, `showItem` to display an item, and `showEntity` to display an entity.
Note that to show an entity, you have to have its UUID as a string. ### Hover Event Example ```kotlin val hoverEventComponent = textComponent("Hover over me!") { hoverEvent { showText("Hello, world!") } } ``` In-game output:
![Hover Event Example](/doc/chat-components/hover.png) ### Hover Item Example ```kotlin val hoverItemComponent = textComponent("Hover over me!") { hoverEvent { showItem(Items.DIAMOND_SWORD { damage(5) }) } } ``` In-game output:
![Hover Event with an Item Example](/doc/chat-components/hover-item.png) ## Click Event Click events perform an action when the text is clicked. The action can be to: - Change the page of the book if reading a book - Copy some text to the clipboard - Open a file - Open a URL - Run a command - Suggest a command (insert the command in the chat but don't run it) ### Click Event Example ```kotlin val clickEventComponent = textComponent("Click me!") { clickEvent { runCommand { say("Hello, world!") } } } ``` ## Object Components Object components render atlas sprites or player skins inside chat. They require the `ObjectTextComponent` family and can be built via `objectComponent` or `playerObjectComponent` depending on the source. All object components share a `fallback` property: a `ChatComponents` value used when the object cannot be displayed (for example, when printing messages in server logs or during narration). Pass it directly to the factory or set it in the builder block. ### AtlasObjectTextComponent - `atlas` - The atlas that contains the sprite. Optional when the sprite already resolves to an atlas entry, otherwise provide an explicit `AtlasArgument`. - `fallback` - Text component used when the sprite cannot be displayed (e.g. in server logs or during narration). - `sprite` - The `ModelArgument` that identifies the sprite to render and is required. Use `objectComponent` to construct atlas objects, optionally passing an atlas override and a fallback. ```kotlin val atlasObject = objectComponent( sprite = Textures.Block.COMMAND_BLOCK_BACK, atlas = Atlases.BLOCKS ) val atlasObjectWithFallback = objectComponent( sprite = Textures.Block.COMMAND_BLOCK_BACK, fallback = textComponent("command block") ) ``` In-game output:
![object-command-block.png](/doc/chat-components/object-command-block.png) ### PlayerObjectTextComponent - `fallback` - Text component used when the player model cannot be displayed (e.g. in server logs or during narration). - `hat` - Whether to display the player's hat layer (true/false) or leave it untouched when null. - `player` - A `PlayerProfile` describing the skin whose head should render; provide either a name, UUID, or both plus properties. `playerObjectComponent` accepts a `PlayerProfile`, name, or `UUIDArgument`, and the nested `player` block lets you add `PlayerProperty` estimations. ```kotlin val playerObject = playerObjectComponent("ayfri") { player { property("textures", "base64_encoded_texture_data") } } val playerObjectWithFallback = playerObjectComponent( playerName = "ayfri", fallback = textComponent("ayfri's head") ) ``` In-game output:
![player.png](/doc/chat-components/player.png) Notice that there is a shadow on the player's head, you can disable it by setting `shadowColor` to 0. ```kotlin val playerObject = playerObjectComponent("ayfri") { shadowColor = argb(0, 0, 0, 0) } ``` In-game output:
![player-no-shadow.png](/doc/chat-components/player-no-shadow.png) These components respect the same formatting as any other chat component, so you can still chain them, color them, or attach hover and click behaviors. ## Parsing existing components Chat components round-trip: besides building them in Kotlin, you can decode vanilla JSON (or SNBT) back into `ChatComponents` using `ChatComponents.serializer()`. Every component type is supported (text, translatable, score, selector, keybind, nbt, object), along with nested `extra`, styling, and hover/click events. A bare string, a single object, and an array of components are all accepted. ```kotlin val component = Json.decodeFromString( ChatComponents.serializer(), """{"type": "text", "text": "Hello", "color": "red"}""", ) ``` This is what the [datapack importer](/docs/advanced/bindings) uses to read components (such as a `pack.mcmeta` description) from existing packs. --- ## Colors --- root: .components.layouts.MarkdownLayout title: Colors nav-title: Colors description: Guide to using colors in Kore, including named colors, RGB/ARGB, dye colors, and how different contexts serialize them. keywords: minecraft, kore, colors, rgb, argb, dyes, components, particles date-created: 2025-08-11 date-modified: 2026-02-04 routeOverride: /docs/concepts/colors --- # Overview Kore provides a unified `Color` API that covers three families of colors used by Minecraft: - `FormattingColor` and `BossBarColor` (named colors for chat, UI, teams, etc.) - `RGB` and `ARGB` (numeric colors) - `DyeColors` (the 16 dye colors used by entities and items) For the vanilla reference on color behavior, see the [Minecraft Wiki - Color](https://minecraft.wiki/w/Color). ## Color types in Kore - `Color` (sealed interface): umbrella type accepted by most helpers. - `FormattingColor`: named chat/formatting colors (e.g. `Color.RED`, `Color.AQUA`). - `BossBarColor`: bossbar’s named colors. - `RGB` / `ARGB`: numeric colors. `RGB` is `#rrggbb`, `ARGB` is `#aarrggbb`. - `DyeColors`: 16 dye colors (white, orange, magenta, …, black) for collars, shulkers, sheep, tropical fish, etc. Helpers to create numeric colors: ```kotlin import io.github.ayfri.kore.arguments.colors.* val c1 = color(85, 255, 255) // RGB val c2 = color('#55ffff') // RGB from hex string val c3 = color(0x55ffff) // RGB from decimal val c4 = argb(255, 85, 255, 255) // ARGB val c5 = argb('#ff55ffff') // ARGB from hex string ``` Conversions and utils: ```kotlin val rgb = Color.AQUA.toRGB() // Named/Bossbar/ARGB → RGB val argb = rgb.toARGB(alpha = 200) val mixed = mix(rgb(255, 0, 0), 0.25, rgb(0, 0, 255), 0.75) ``` ## Random colors Kore provides static `random()` helpers on the color classes to simplify testing and procedural generation. You can also use a `Random` instance to generate random colors with a specific seed. These helpers are available on: - **`RGB`**: `RGB.random(random: Random = Random)`: returns a random RGB - **`ARGB`**: `ARGB.random(random: Random = Random, alpha: Boolean = false)`: returns a random ARGB; set `alpha = true` to randomize the alpha channel - **`FormattingColor`**: `FormattingColor.random(random: Random = Random)`: returns a random named formatting color - **`BossBarColor`**: `BossBarColor.random(random: Random = Random)`: returns a random named bossbar color ### Example usage: ```kotlin import kotlin.random.Random import io.github.ayfri.kore.arguments.colors.* import io.github.ayfri.kore.arguments.enums.DyeColors val randomRgb = RGB.random() val randomArgb = ARGB.random(random = Random(12345)) val randomArgbWithAlpha = ARGB.random(alpha = true) val randomFormatting = FormattingColor.random() ``` These helpers were added to make it easy to generate example content, tests, or procedurally-generated visuals. ## Serialization formats by context Different Minecraft systems expect colors in different formats. Kore picks the right format automatically via serializers. - Chat components (`color`, `shadow_color`): string - Named colors emit lowercase names (e.g. `"red"`). - `RGB` emits `"#rrggbb"`; `ARGB` emits `"#aarrggbb"`. - Item components (decimal ints): - `dyedColor(..)`: decimal (or object with `rgb` decimal when tooltip flag is present) [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/arguments/components/item/DyedColorComponent.kt#L14) ```kotlin @Serializable(RGB.Companion.ColorAsDecimalSerializer::class) var rgb: RGB, ``` - `mapColor(..)`: decimal [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/arguments/components/item/MapColorComponent.kt#L13) ```kotlin InlineSerializer(RGB.Companion.ColorAsDecimalSerializer, MapColorComponent::color) ``` - `potionContents(customColor=..)`: decimal [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/arguments/components/item/PotionContentsComponent.kt#L29-L30) ```kotlin @Serializable(RGB.Companion.ColorAsDecimalSerializer::class) var customColor: RGB? = null, ``` - Firework explosion `colors` / `fade_colors`: decimal list [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/arguments/components/item/FireworkExplosionComponent.kt#L30-L32) ```kotlin var colors: List<@Serializable(RGB.Companion.ColorAsDecimalSerializer::class) RGB>? = null, @SerialName("fade_colors") var fadeColors: List<@Serializable(RGB.Companion.ColorAsDecimalSerializer::class) RGB>? = null, ``` - Worldgen Biomes (decimal ints): - `effects.waterColor`, `effects.grassColor`, `effects.foliageColor`, etc. use decimal ints. - Sky/fog/water fog colors are now set via **environment attributes** (`attributes`). [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/features/worldgen/biome/types/BiomeEffects.kt) ```kotlin // BiomeEffects (decimal ints in JSON) @Serializable(ColorAsDecimalSerializer::class) var waterColor: Color = color(4159204) @Serializable(ColorAsDecimalSerializer::class) var grassColor: Color? = null @Serializable(ColorAsDecimalSerializer::class) var foliageColor: Color? = null @Serializable(ColorAsDecimalSerializer::class) var dryFoliageColor: Color? = null // Environment attributes (also typically decimal ints for worldgen colors) attributes { skyColor(0x78A7FF) fogColor(0xC0D8FF) waterFogColor(0x050533) } ``` - Particles: - Command particles (decimal ints): Dust, DustColorTransition, Trail [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/commands/particle/types/DustParticleType.kt#L21) ```kotlin var color: @Serializable(ColorAsDecimalSerializer::class) Color, ``` [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/commands/particle/types/DustColorTransitionParticleType.kt#L22-L25) ```kotlin var fromColor: @Serializable(ColorAsDecimalSerializer::class) Color, var toColor: @Serializable(ColorAsDecimalSerializer::class) Color, ``` [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/commands/particle/types/TrailParticleType.kt#L22) ```kotlin var color: @Serializable(ColorAsDecimalSerializer::class) Color, ``` - Enchantment effect particles (double arrays `[r, g, b]` in 0..1): [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/features/enchantments/effects/entity/spawnparticles/types/DustParticleType.kt#L11) ```kotlin var color: @Serializable(ColorAsDoubleArraySerializer::class) Color, ``` [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/features/enchantments/effects/entity/spawnparticles/types/DustColorTransitionParticleType.kt#L12-L14) ```kotlin var fromColor: @Serializable(ColorAsDoubleArraySerializer::class) Color, var toColor: @Serializable(ColorAsDoubleArraySerializer::class) Color, ``` [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/features/enchantments/effects/entity/spawnparticles/types/EntityEffectParticleType.kt#L11) ```kotlin var color: @Serializable(ColorAsDoubleArraySerializer::class) Color, ``` - UI and commands using named colors (strings): - Teams, Scoreboards, Bossbar: `FormattingColor` / `BossBarColor` [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/commands/Teams.kt#L43) ```kotlin fun color(color: FormattingColor) = fn.addLine(..., literal("color"), color) ``` [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/commands/BossBar.kt#L57) ```kotlin fun setColor(color: BossBarColor) = fn.addLine(..., literal("color"), color) ``` ## Dye colors and where they’re used `DyeColors` are used for entity variants and certain item/entity data components: - `catCollar(..)`, `wolfCollar(..)`, `sheepColor(..)`, `shulkerColor(..)` [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/arguments/components/entity/CatCollar.kt#L11-L22) ```kotlin data class CatCollar(var color: DyeColors) // ... existing code ... fun ComponentsScope.catCollar(color: DyeColors) ``` [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/arguments/components/entity/WolfCollar.kt#L11-L22) ```kotlin data class WolfCollar(var color: DyeColors) // ... existing code ... fun ComponentsScope.wolfCollar(color: DyeColors) ``` [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/arguments/components/entity/SheepColor.kt#L11-L22) ```kotlin data class SheepColor(var color: DyeColors) // ... existing code ... fun ComponentsScope.sheepColor(color: DyeColors) ``` [See on GitHub](https://github.com/Ayfri/Kore/tree/master/kore/src/main/kotlin/io/github/ayfri/kore/arguments/components/entity/ShulkerColor.kt#L11-L22) ```kotlin data class ShulkerColor(var color: DyeColors) // ... existing code ... fun ComponentsScope.shulkerColor(color: DyeColors) ``` ## Practical examples Chat components (string serialization): ```kotlin import io.github.ayfri.kore.arguments.chatcomponents.textComponent import io.github.ayfri.kore.arguments.colors.Color val title = textComponent('Legendary Sword', Color.AQUA) ``` Dyed leather color (decimal serialization): ```kotlin import io.github.ayfri.kore.generated.Items import io.github.ayfri.kore.arguments.colors.Color val dyedHelmet = Items.LEATHER_HELMET { dyedColor(Color.AQUA) } ``` Map color (decimal serialization): ```kotlin import io.github.ayfri.kore.generated.Items import io.github.ayfri.kore.arguments.colors.rgb val withMapColor = Items.STONE { mapColor(rgb(85, 255, 255)) } ``` Fireworks (decimal lists): ```kotlin import io.github.ayfri.kore.generated.Items import io.github.ayfri.kore.generated.FireworkExplosionShape import io.github.ayfri.kore.arguments.colors.Color val rocket = Items.FIREWORK_ROCKET { fireworks(flightDuration = 1) { explosion(FireworkExplosionShape.BURST) { colors(Color.AQUA) fadeColors(Color.BLACK, Color.WHITE) hasTrail = true hasFlicker = true } } } ``` Biome effects (decimal): ```kotlin import io.github.ayfri.kore.features.worldgen.biome.types.BiomeEffects import io.github.ayfri.kore.arguments.colors.color val effects = BiomeEffects( waterColor = color(4159204), grassColor = color(0x79C05A) ) ``` Particles - Command dust (decimal): ```kotlin import io.github.ayfri.kore.commands.particle.types.Dust import io.github.ayfri.kore.arguments.colors.Color val p = Dust(color = Color.RED, scale = 1.0) ``` - Enchantment dust (double array): ```kotlin import io.github.ayfri.kore.features.enchantments.effects.entity.spawnparticles.types.DustParticleType import io.github.ayfri.kore.generated.arguments.types.ParticleTypeArgument import io.github.ayfri.kore.arguments.colors.rgb val enchantDust = DustParticleType( type = ParticleTypeArgument('minecraft:dust'), color = rgb(255, 0, 0) ) ``` Entity variant dye usage: ```kotlin import io.github.ayfri.kore.generated.Items import io.github.ayfri.kore.arguments.enums.DyeColors val cat = Items.CAT_SPAWN_EGG { catCollar(DyeColors.RED) } ``` ## Notes - Passing `Color` to component helpers that use decimal or double-array formats is safe: Kore converts automatically via `toRGB()`. - Use `DyeColors` when the game mechanic expects a dye color (collars, sheep, shulkers, tropical fish), and `FormattingColor`/ `BossBarColor` for chat/UI tints. ## Further reading - [Chat Components](/docs/concepts/chat-components) - Use colors in chat components - [Minecraft Wiki - Color](https://minecraft.wiki/w/Color) --- ## Components --- root: .components.layouts.MarkdownLayout title: Components nav-title: Components description: A guide for using components in Minecraft with Kore. keywords: minecraft, datapack, kore, guide, components date-created: 2024-01-08 date-modified: 2026-07-01 routeOverride: /docs/concepts/components --- In Minecraft, data components are structured key-value properties used to define and store behavior and attributes. They are attached to different things: - Item components: properties that live on item stacks (e.g., `enchantments`, `food`, `attribute_modifiers`). They affect how items behave in inventories, commands, containers, etc. - Entity variant components: properties exposed as components for certain entity variants when represented as items or spawn eggs (e.g., `wolf/variant`, `cat/collar`). These follow the same component mechanics but target entity-specific customization. This page focuses on using item components with Kore. For the vanilla reference and exhaustive definitions, see the [Minecraft Wiki - Data component format](https://minecraft.wiki/w/Data_component_format). The Kore library provides a comprehensive and user-friendly way to work with these components, enabling you to create custom items with ease. This article will guide you through the process of using components with Kore, showcasing examples and best practices. ## Creating Custom Items with Components Let's dive into creating custom items with various components using Kore. Below are examples of how to define and manipulate item properties such as attribute modifiers, enchantments, and more. ### Attribute Modifiers Attribute modifiers allow you to alter the attributes of an item, such as increasing damage or changing the scale. Here's how to define a stone sword with an attribute modifier using Kore: ```kotlin import io.github.ayfri.kore.commands.AttributeModifierOperation import io.github.ayfri.kore.generated.Items import io.github.ayfri.kore.generated.Attributes val attributeModifiersTest = Items.STONE_SWORD { attributeModifiers { modifier( type = Attributes.SCALE, amount = 1.0, name = "big", operation = AttributeModifierOperation.ADD_VALUE, ) } } ``` ### Enchantments You can add enchantments to items to give them special abilities. Here’s an example of adding the Sharpness enchantment to a stone sword: ```kotlin import io.github.ayfri.kore.generated.Enchantments val enchantmentsTest = Items.STONE_SWORD { enchantments(mapOf(Enchantments.SHARPNESS to 5)) } ``` Check out the [Enchantments](/docs/data-driven/enchantments) article for more information on how to use enchantments with Kore. ### Custom Names and Lore Custom names and lore can be added to items to give them unique identifiers and background stories: ```kotlin import io.github.ayfri.kore.arguments.chatcomponents.textComponent import io.github.ayfri.kore.arguments.colors.Color val customNameTest = Items.STONE_SWORD { customName(textComponent("Legendary Sword", Color.AQUA)) } ``` ### Fireworks You can define the properties of fireworks, including the shape and colors of the explosions: ```kotlin import io.github.ayfri.kore.generated.FireworkExplosionShape import io.github.ayfri.kore.arguments.colors.Color val fireworksTest = Items.FIREWORK_ROCKET { fireworks(flightDuration = 1) { explosion(FireworkExplosionShape.BURST) { colors(Color.AQUA) fadeColors(Color.BLACK, Color.WHITE) hasTrail = true hasFlicker = true } } } ``` See how to set custom colors in the [Colors](/docs/concepts/colors) article. ### Custom Block Data You can define custom properties for blocks using block entity data. Here's an example of adding custom data to a bee nest block: ```kotlin import io.github.ayfri.kore.generated.Blocks import io.github.ayfri.kore.generated.Items val blockEntityDataTest = Items.BEE_NEST { blockEntityData(Blocks.BEE_NEST) { this["test"] = "test" } } ``` ### Profile The profile component can be either a player profile or a texture-based profile. #### Player Profile A player profile uses a player's name or UUID: ```kotlin Items.PLAYER_HEAD { playerProfile("Notch") } ``` #### Texture Profile A texture profile allows you to specify textures and models: ```kotlin Items.PLAYER_HEAD { textureProfile(texture = "tex") { model = MannequinModel.SLIM } } ``` ### Recipes result with components You can define recipes with components as well. Here's an example of crafting a custom enchanted golden apple using a shaped recipe: ```kotlin recipes { craftingShaped("enchanted_golden_apple") { pattern( "GGG", "GAG", "GGG" ) key("G", Items.GOLD_BLOCK) key("A", Items.APPLE) result(Items.ENCHANTED_GOLDEN_APPLE { food( nutrition = 10f, saturation = 5.0f, ) { effect( probability = 1f, id = Effects.REGENERATION, duration = 40, amplifier = 1, ambient = true, showParticles = true, showIcon = true ) } }) } } ``` ## Example Usage To give yourself an item with custom components using the `/give` command, you can define the item and its components as shown in the following example: ```kotlin import io.github.ayfri.kore.generated.Items import io.github.ayfri.kore.utils.set // Define the item with a custom name val customStone = Items.STONE { fireResistant() customName(textComponent("Special Stone", Color.AQUA)) rarity(Rarities.EPIC) lore( textComponent("A stone with special properties.", Color.GRAY) + text("Use it wisely!", Color.GRAY) ) } // Use the /give command to give the item to yourself give(self(), customStone) ``` This example creates a custom stone item with a special name "Special Stone" in aqua color and gives it to the player using the `/give` command. ### Full list of Item components Below is an alphabetical list of all item component helpers available in Kore. The names match the DSL functions you call inside an `Items.* { }` builder. | Helper | Description | |--------------------------------------|----------------------------------------------------------------------------------------------------------| | `additionalTradeCost(..)` | Sets an extra emerald cost added on top of the base price for villager trades. | | `attackRange(..)` | Configures the attack range of an item (min/max range, hitbox margin, mob factor). | | `attributeModifiers(..)` | Modifies entity attributes (e.g., attack damage, speed, armor) when the item is equipped or held. | | `bannerPatterns(..)` | Defines the layered patterns displayed on a banner or shield. | | `baseColor(..)` | Sets the base color of a banner before patterns are applied. | | `bees { .. }` | Stores bee entities inside a beehive or bee nest item. | | `blockEntityData(..)` | Attaches custom NBT data to a block entity when the item is placed. | | `blocksAttacks(..)` | Configures how the item blocks incoming attacks when used (like a shield). | | `blockState(..)` | Sets block state properties (e.g., facing, powered) when the item is placed. | | `breakSound(..)` | Specifies the sound played when the item breaks from durability loss. | | `bucketEntityData(..)` | Stores entity data for mobs captured in buckets (e.g., fish, axolotl). | | `bundleContents(..)` | Defines the items stored inside a bundle. | | `canBreak(..)` | Restricts which blocks this item can break in Adventure mode. | | `canPlaceOn(..)` | Restricts which blocks this item can be placed on in Adventure mode. | | `chargedProjectiles(..)` | Stores projectiles loaded into a crossbow. | | `consumable(..) { .. }` | Makes the item consumable with configurable eating time, animation, sound, and effects. | | `container(..)` | Stores items inside a container item (e.g., shulker box). | | `containerLoot(..)` | References a loot table to generate container contents when opened. | | `customData(..)` | Attaches arbitrary custom NBT data for use by datapacks or mods. | | `customModelData(..)` | Provides numeric values for custom item model selection in resource packs. | | `customName(..)` | Sets a custom display name for the item (supports text components). | | `damage(..)` | Sets the current damage/durability consumed on a damageable item. | | `damageResistant(..)` | Makes the item entity resistant to specific damage types (e.g., fire, explosions). | | `damageType(..)` | Specifies the damage type dealt when attacking with this item. | | `deathProtection(..)` | Prevents death and applies effects when the holder would die (like a totem). | | `debugStickState(..)` | Stores the selected block state property for the debug stick per block type. | | `dye(..)` | Sets the dye color of an item using a `DyeColors` value. | | `dyedColor(..)` | Sets the dye color for leather armor or other dyeable items. | | `enchantable(..)` | Defines the enchantability value affecting enchantment quality at enchanting tables. | | `enchantmentGlintOverride(..)` | Forces the enchantment glint on or off regardless of enchantments. | | `enchantments(..)` | Applies enchantments with their levels to the item. | | `entityData(..)` | Stores entity NBT data for spawn eggs or items that spawn entities. | | `equippable(..)` | Configures equipment slot, sounds, and model when the item is worn. | | `fireworkExplosion(..)` | Defines a single firework star explosion shape, colors, and effects. | | `fireworks(..)` | Configures firework rocket flight duration and explosion effects. | | `food(..)` | Makes the item edible with nutrition, saturation, and optional effects. | | `glider()` | Enables elytra-like gliding when equipped in the chest slot. | | `instrument(..)` | Specifies the goat horn sound variant when the item is used. | | `intangibleProjectile()` | Makes projectiles from this item pass through entities without collision. | | `itemModel(..)` | Overrides the item's model with a custom model resource location. | | `itemName(..)` | Sets the item's base name (different from custom name; not italicized). | | `jukeboxPlayable(..)` | Allows the item to be played in a jukebox with a specified music disc track. | | `kineticWeapon(..) { .. }` | Configures kinetic weapon properties for mounted combat (damage multiplier, conditions). | | `lock(..)` | Locks a container so only players holding a matching item (item predicate) can open it. | | `lodestoneTarget(..)` | Makes a compass point to specific coordinates in a dimension. | | `lore(..)` | Adds tooltip lines below the item name for descriptions or flavor text. | | `mapColor(..)` | Sets the color tint for filled map item textures. | | `mapDecorations(..)` | Adds custom icons/markers displayed on a filled map. | | `mapId(..)` | Links the item to a specific map data ID for filled maps. | | `maxDamage(..)` | Sets the maximum durability before the item breaks. | | `maxStackSize(..)` | Overrides how many items can stack in a single inventory slot (1-99). | | `minimumAttackCharge(..)` | Sets the minimum attack charge (0.0-1.0) required for full damage. | | `noteBlockSound(..)` | Specifies the sound a note block plays when this player head is above it. | | `ominousBottleAmplifier(..)` | Sets the Bad Omen effect amplifier (0-4) when consuming an ominous bottle. | | `piercingWeapon(..) { .. }` | Configures piercing weapon properties (knockback, dismount behavior). | | `playerProfile(..)` | Sets the player skin displayed on a player head item. | | `potDecorations(..)` | Defines the pottery sherds or bricks on each face of a decorated pot. | | `potionContents(..)` | Configures potion color, effects, and custom potion mixtures. | | `potionDurationScale(..)` | Multiplies the duration of potion effects from this item. | | `providesBannerPatterns(..)` | Registers this item as a banner pattern source for the loom. | | `providesTrimMaterial(..)` | Registers this item as an armor trim material for the smithing table. | | `rarity(..)` | Sets the item name color tier (common, uncommon, rare, epic). | | `recipes(..)` | Unlocks specified recipes when this knowledge book is used. | | `repairable(..)` | Defines which items can repair this item on an anvil. | | `repairCost(..)` | Sets the anvil repair cost penalty for combining or renaming. | | `storedEnchantments(..)` | Stores enchantments in an enchanted book for anvil application. | | `suspiciousStewEffectsComponent(..)` | Defines the status effects applied when consuming suspicious stew. | | `swingAnimation(..)` | Configures the swing animation type (none, stab, whack) and duration. | | `tool { .. }` | Configures mining speeds, suitable blocks, and durability cost for tools. | | `tooltipDisplay(..)` | Controls which tooltip sections are shown or hidden. | | `tooltipStyle(..)` | Applies a custom tooltip background/border style from a resource pack. | | `trim(..)` | Applies an armor trim pattern and material to armor items. | | `unbreakable()` | Prevents the item from taking durability damage. | | `useCooldown(..)` | Applies a cooldown period after using this item. | | `useEffects(..)` | Configures use effects like allowing sprinting, interacting vibrations and speed multiplier while using. | | `useRemainder(..)` | Specifies an item left behind after this item is fully consumed. | | `weapon(..)` | Configures melee weapon properties like damage and attack speed. | | `writableBookContent(..)` | Stores editable pages in a book and quill. | | `writtenBookContent(..)` | Stores signed book content including title, author, and pages. | ## Works great with Inventory Manager If you build rich items with components and want to enforce them in player GUIs or chest slots, pair them with the [Inventory Manager](/docs/helpers/inventory-manager). It lets you keep specific items in slots, react to takes, and clean up other slots while preserving all component data. ## Patch items When you need to patch components on existing stacks (set name/lore, toggle tooltips, edit container contents, etc.) at runtime, use [Item Modifiers](/docs/data-driven/item-modifiers). Kore maps the vanilla functions like `set_components`, `set_contents`, `set_fireworks`, and more. ## Custom Component You can create custom components by extending the `CustomComponent` class. Here's an example of a custom component that adds a custom attribute to an item: ```kotlin package your.package import io.github.ayfri.kore.arguments.components.ComponentsScope import io.github.ayfri.kore.arguments.components.types.CustomComponent import io.github.ayfri.kore.arguments.types.resources.FunctionArgument import io.github.ayfri.kore.arguments.types.resources.SoundArgument import io.github.ayfri.kore.utils.nbt import kotlinx.serialization.Serializable import kotlinx.serialization.SerialName @Serializable data class UseComponent( var function: FunctionArgument, @SerialName("durability_damages") // properties aren't renamed to snake_case because of a limitation in KNBT library var durabilityDamages: Int? = null, // optional property, equals to 0 in Minecraft var cooldown: Float? = null, // optional property, equals to 0 in Minecraft var consume: Boolean? = null, // optional property, equals to false in Minecraft var sound: SoundArgument? = null, // optional property, equals to null in Minecraft ) : CustomComponent( nbt { this["function"] = function this["damage"] = damage this["cooldown"] = cooldown this["consume"] = consume this["sound"] = sound } ) fun ComponentsScope.use( function: FunctionArgument, damage: Int? = null, cooldown: Float? = null, consume: Boolean? = null, sound: SoundArgument? = null, ) = apply { this["use_component"] = UseComponent(function, damage, cooldown, consume, sound) } ``` And here's how you can use this custom component in an item definition: ```kotlin import io.github.ayfri.kore.generated.Items import io.github.ayfri.kore.generated.Sounds import your.package.use val customItem = Items.DIAMOND_SWORD { val myFunction = function("use_weapon") { // Your function code here. } use( function = myFunction, durabilityDamages = 4, cooldown = 1.5f, sound = Sounds.Entity.Player.Attack.CRIT1 ) } // Result: minecraft:diamond_sword[use_component ={ function:"datapack:use_weapon", damage:4, cooldown:1.5f, sound:"entity/player/attack/crit1" }] ``` ## Entity Variant Components (25w04a+) > *Introduced in snapshot [25w04a](https://www.minecraft.net/en-us/article/minecraft-snapshot-25w04a)* > > Entity variants such as axolotl colours, cat collars or tropical-fish patterns are now exposed as **data components ** and can be used on entities, spawn-egg items, mob buckets and paintings. This replaces the old `type_specific` NBT fields. Kore ships dedicated helpers for each of these components. You can attach them to an `Items.*` builder the exact same way you attach any other component: ```kotlin import io.github.ayfri.kore.generated.Items import io.github.ayfri.kore.arguments.enums.* // Axolotl bucket with the blue variant val blueAxolotlBucket = Items.AXOLOTL_BUCKET { axolotlVariant(AxolotlVariants.BLUE) } // Cat spawn-egg with a red collar val redCollarCat = Items.CAT_SPAWN_EGG { catCollar(DyeColors.RED) } // Painting item selecting the "kebab" variant (namespace implied) val kebabPainting = Items.PAINTING { paintingVariant(PaintingVariants.KEBAB) } ``` These components can also be queried inside predicates: ```kotlin predicate("only_blue_axolotls") { entityProperties { components { axolotlVariant(AxolotlVariants.BLUE) } } } ``` The full list of variant helpers currently included in Kore is: - `axolotlVariant(..)` - `catCollar(..)` / `catVariant(..)` - `chickenVariant(..)` - `cowVariant(..)` - `foxVariant(..)` - `frogVariant(..)` - `horseVariant(..)` - `llamaVariant(..)` - `mooshroomVariant(..)` - `paintingVariant(..)` - `parrotVariant(..)` - `pigVariant(..)` - `rabbitVariant(..)` - `salmonSize(..)` - `sheepColor(..)` - `shulkerColor(..)` - `tropicalFishBaseColor(..)` / `tropicalFishPattern(..)` / `tropicalFishPatternColor(..)` - `villagerVariant(..)` - `wolfCollar(..)` / `wolfSoundVariant(..)` / `wolfVariant(..)` - `zombieNautilusVariant(..)` They follow the exact same naming and DSL pattern you already know: ```kotlin fun ComponentsScope.wolfVariant(variant: WolfVariants) { /*…*/ } ``` Because the logic lives in regular data components, you automatically get: • Compatibility with `itemStack` / `Items.*` DSL • Predicate support through `components {}` • Correct serialisation back to the vanilla command-/NBT-syntax Feel free to mix several variant components on the same `ComponentsScope`: ```kotlin Items.WOLF_SPAWN_EGG { wolfCollar(DyeColors.BLACK) wolfVariant(WolfVariants.SNOWY) } ``` ## Component Matchers & Item Predicates Kore provides powerful tools for matching and filtering items based on their components. This is useful in predicates, execute conditions, and loot tables. There are two distinct forms: - **Item predicates** (`.predicate { }` / `itemPredicate { }`) produce the inline command syntax `[predicate]`, used anywhere an item argument is accepted - `/give`, `/clear`, the `items` selector, `execute if items`. - **Component matchers** (`predicates { }` inside `matchTool { }`, or `subPredicates { }` inside `.predicate { }`) check the same components from within a predicate *file* - see [Item Predicates](/docs/data-driven/predicates#item-predicates) and [Item Sub-Predicates](/docs/data-driven/predicates#item-sub-predicates) in the Predicates guide for how they plug into a full predicate. Both forms share the same set of component checks - see [Available Component Matchers](#available-component-matchers) below for the full list. ### Item Predicates Item predicates let you filter items by their components using the command syntax `[predicate]`: ```kotlin import io.github.ayfri.kore.arguments.components.* import io.github.ayfri.kore.arguments.components.item.* import io.github.ayfri.kore.generated.Items import io.github.ayfri.kore.generated.ItemComponentTypes // Match items with specific component values val damagedSword = Items.DIAMOND_SWORD.predicate { damage(10) } // Result: minecraft:diamond_sword[damage=10] // Match any item with a component present (existence check) val hasInstrument = itemPredicate { isPresent(ItemComponentTypes.INSTRUMENT) } // Result: *[instrument] // Partial matching with ~ syntax val customDataMatch = Items.STONE.predicate { customData { this["myKey"] = "myValue" } partial(ItemComponentTypes.CUSTOM_DATA) } // Result: minecraft:stone[custom_data~{myKey:"myValue"}] // Negated predicates (component must NOT have this value) val notDamaged = Items.DIAMOND_SWORD.predicate { !damage(0) } // Result: minecraft:diamond_sword[!damage=0] // Multiple alternatives with OR val multipleValues = Items.STONE.predicate { damage(1) or damage(2) or damage(3) } // Result: minecraft:stone[damage=1|damage=2|damage=3] // Count predicate val stackOf10 = Items.DIAMOND.predicate { count(10) } // Result: minecraft:diamond[count=10] ``` #### Practical Example: Clearing Items by Name A common vanilla pattern is clearing every item with a specific `item_name`, regardless of its item type - the raw command looks like `clear @s *[minecraft:item_name="Blank"] 2`. It breaks down into three pieces: `@s` is the target, `*[minecraft:item_name="Blank"]` is an item predicate matching **any** item (`*`) whose `item_name` component equals `"Blank"`, and `2` is the max count to remove. Build the same thing with Kore's `clear` command and `itemPredicate { }`: ```kotlin import io.github.ayfri.kore.commands.clear import io.github.ayfri.kore.commands.selectors.self function("clear_blank_items") { clear(self(), itemPredicate { itemName("Blank") }, 2) } ``` This generates `clear @s *[item_name="Blank"] 2`. Because no `ItemArgument` is passed to `itemPredicate { }`, it defaults to `*` (any item) - pass an item to `.predicate { }` instead (e.g. `Items.PAPER.predicate { itemName("Blank") }`) if you want to restrict the match to a specific item type too. ### Component Matchers (Sub-Predicates) For matching logic beyond a plain item predicate, use the `predicates { }` builder inside `matchTool { }` (or `subPredicates { }` inside `.predicate { }`) with component matchers: ```kotlin import io.github.ayfri.kore.arguments.components.matchers.* import io.github.ayfri.kore.arguments.numbers.ranges.rangeOrInt predicate("upgradeable_pickaxe") { matchTool { item(Items.DIAMOND_PICKAXE) predicates { // Match damage component with range damage { durability = rangeOrInt(1..100) damage = rangeOrInt(0..10) } // Match enchantments enchantments { enchantment(Enchantments.SHARPNESS, level = 3) } // Match potion contents potionContents(Effects.SPEED, Effects.STRENGTH) } } } ``` ### Existence Checks You can check if a component exists on an item without matching a specific value. In an item predicate (command form), use `isPresent`: ```kotlin val hasInstrument = itemPredicate { isPresent(ItemComponentTypes.INSTRUMENT) } // Result: *[instrument] ``` Inside a `predicates { }` / `subPredicates { }` block, use `exists`: ```kotlin predicate("has_instrument") { matchTool { predicates { exists(ItemComponentTypes.INSTRUMENT) exists(ItemComponentTypes.DAMAGE) } } } ``` ### Available Component Matchers | Matcher | Description | |---------------------------|------------------------------------------------| | `attributeModifiers { }` | Match attribute modifier properties | | `bundlerContents { }` | Match bundle contents | | `container { }` | Match container slot contents | | `customData { }` | Match custom NBT data | | `damage { }` | Match damage/durability values | | `enchantments { }` | Match enchantment types and levels | | `exists(component)` | Check if component exists (empty `{}` matcher) | | `fireworkExplosion { }` | Match firework star properties | | `fireworks { }` | Match firework rocket properties | | `jukeboxPlayable { }` | Match jukebox song | | `potionContents(..)` | Match potion effects | | `storedEnchantments { }` | Match stored enchantments (enchanted books) | | `trim { }` | Match armor trim pattern/material | | `writableBookContent { }` | Match book pages | | `writtenBookContent { }` | Match signed book content | ### Complete Example: Custom Tool Upgrade System Here's a practical example showing how to use item predicates to create a tool upgrade system that detects enchanted, damaged tools and replaces them with upgraded versions: ```kotlin dataPack("tool_upgrades") { // Predicate to find diamond swords that need upgrading predicate("upgradeable_sword") { matchTool { items(Items.DIAMOND_SWORD) predicates { // Must have Sharpness enchantment enchantments { enchantment(Enchantments.SHARPNESS, level = rangeOrInt(1..4)) } // Must be damaged (durability used) damage { damage = rangeOrInt(1..1000) } } } } // Function to check player's held item and upgrade it function("check_upgrade") { // Check if holding an upgradeable sword execute { ifCondition { items( self(), ItemSlot.WEAPON_MAINHAND, Items.DIAMOND_SWORD.predicate { subPredicates { enchantments { enchantment(Enchantments.SHARPNESS, level = rangeOrInt(3..4)) } } } ) } run { // Replace with netherite sword keeping enchantments items.modify(self(), ItemSlot.WEAPON_MAINHAND, itemModifier("upgrade_to_netherite")) tellraw(self(), textComponent("Your sword has been upgraded!", Color.GOLD)) } } } // Clear specific items from inventory using predicates function("clear_broken_tools") { // Clear any tool with 1 durability left clear(allPlayers(), itemPredicate { subPredicates { damage { durability = rangeOrInt(1) } } }) } // Give reward only if player has specific item combination function("check_collection") { execute { // Check for a goat horn (any variant) ifCondition { items( self(), ItemSlot.INVENTORY, itemPredicate { isPresent(ItemComponentTypes.INSTRUMENT) } ) } // Check for enchanted book with Mending ifCondition { items( self(), ItemSlot.INVENTORY, Items.ENCHANTED_BOOK.predicate { subPredicates { storedEnchantments { enchantment(Enchantments.MENDING) } } } ) } run { give(self(), Items.NETHER_STAR) } } } } ``` ## Conclusion Components are a powerful tool for customizing Minecraft objects, and the Kore library makes it easier than ever to work with these components programmatically. Whether you're adding custom attributes, enchantments, or creating complex items with multiple components, Kore provides a robust and intuitive API for enhancing your Minecraft experience. By following the examples and practices outlined in this article, you can leverage the full potential of components in your Minecraft projects, creating richer and more engaging content for players. Happy crafting! ## See Also - [Predicates](/docs/data-driven/predicates) - Use components in predicate conditions; see [Item Predicates](/docs/data-driven/predicates#item-predicates) and [Item Sub-Predicates](/docs/data-driven/predicates#item-sub-predicates) for how the matchers on this page plug into a full `predicate { }` file - [Item Modifiers](/docs/data-driven/item-modifiers) - Patch components at runtime - [Recipes](/docs/data-driven/recipes) - Use components in recipe results - [Inventory Manager](/docs/helpers/inventory-manager) - Enforce component-rich items in slots ### External Resources - [Minecraft Wiki: Data component format](https://minecraft.wiki/w/Data_component_format) - Official component reference --- ## NBTs --- root: .components.layouts.MarkdownLayout title: NBTs nav-title: NBTs description: Work with Minecraft NBT data in Kore using a shared Kotlin DSL across commands, predicates, and chat components. Includes SNBT helpers, path access, and reuse patterns. keywords: minecraft, datapack, kore, nbt, snbt, knbt, chat components, predicates, data command date-created: 2026-05-29 date-modified: 2026-05-29 routeOverride: /docs/concepts/nbts --- # NBTs NBT (Named Binary Tag) is Minecraft's structured data format. Kore uses it anywhere vanilla expects embedded NBT or SNBT, such as: - command payloads like `summon`, `data merge`, or [storage writes](/docs/concepts/data-storage) - chat components that read values from blocks, entities, or storage - predicate sub-structures that expose an `nbt { ... }` block - helpers and domain objects that serialize themselves with `toNbt()` Kore's NBT support is built on top of [`knbt`](https://github.com/BenWoodworth/knbt), so the same builder style is reused throughout the DSL. An NBT **compound** is the object/map-shaped tag in NBT: a group of named entries such as `CustomName`, `Health`, or `display`. In Kore, `nbt { ... }` builds that compound structure. ## Core builder The main entry point is `nbt { ... }`, which creates an `NbtCompound`. ```kotlin val customData = nbt { this["CustomName"] = "\"Hero\"" this["Health"] = 20 this["Invulnerable"] = true this["Tags"] = nbtListOf("kore", "example") this["Weapon"] = nbt { this["id"] = "minecraft:diamond_sword" this["Count"] = 1.toByte() } } ``` This pattern is used by Kore in most places that accept raw NBT. When you write compounds manually, it is often worth sorting keys by name to keep large payloads easier to scan and diff. ## Common ways to build values Inside an `nbt { ... }` block, the most common pattern is assigning with `this["key"] = value`. ### Primitive values ```kotlin val payload = nbt { this["cooldown"] = 40.toShort() this["count"] = 1.toByte() this["enabled"] = true this["level"] = 3 this["name"] = "Kore" this["seed"] = 1234L this["speed"] = 0.5 } ``` Vanilla key names are not perfectly consistent across Minecraft versions. Mojang used `PascalCase` for most older keys, then introduced some newer keys in `camelCase` for a while, and more recent additions often use `snake_case`. The migration is slow, so real-world NBT frequently mixes conventions in the same compound. Because of that, I advise you to not guess key names. Always verify them against the Minecraft Wiki, or inspect the exact live data with `/data get entity ...`, `/data get block ...`, or `/data get storage ...` in-game. ### Nested compounds Use another `nbt { ... }` block for a nested compound when one key contains another group of named values: ```kotlin val nested = nbt { this["display"] = nbt { this["Name"] = "\"Treasure\"" } } ``` ### Lists Use `nbtListOf(...)` for a homogeneous NBT list when you already know the elements: ```kotlin val listExample = nbt { this["Pos"] = nbtListOf(0.0, 64.0, 0.0) this["Tags"] = nbtListOf("boss", "phase_1") } ``` `knbt` lists are typed, so a single NBT list must contain the same kind of values. If you want to build a list incrementally, use `nbtList { ... }`: ```kotlin val passengers = nbtList { addNbtCompound { this["CustomName"] = "\"Left Guard\"" this["id"] = "minecraft:armor_stand" } addNbtCompound { this["CustomName"] = "\"Right Guard\"" this["id"] = "minecraft:armor_stand" } } ``` This is especially useful for lists of compounds, where each element is itself a small NBT object. ### Raw SNBT when needed Most of the time you should prefer the typed builders above. If you need a hand-written SNBT fragment, Kore also exposes helpers such as `stringifiedNbt(...)` for contexts that accept SNBT text directly. See [Known Issues](/docs/advanced/known-issues#nbt-and-snbt-via-knbt) for the main `knbt` limitations and trade-offs. ## Where you use NBT in Kore Different APIs expose NBT in different ways, but the underlying builder style stays the same. ### Commands Commands usually accept an `NbtCompound` directly. ```kotlin function("summon_example") { summon(EntityTypes.ARMOR_STAND, vec3(0, 64, 0), nbt = nbt { this["CustomName"] = "\"Guide\"" this["NoGravity"] = true }) } ``` The `data` command also uses NBT builders naturally: ```kotlin function("storage_seed") { data(self()) { merge { this["CustomName"] = "\"Hero\"" this["Invulnerable"] = true } } } ``` If you are learning the command surface itself, see [Commands](/docs/commands/commands#data-command). ### Chat components `NbtComponent` reads a value from block, entity, or storage NBT and displays it in chat. ```kotlin val nameFromStorage = nbtComponent("player.name", storage("kore:ui")) { interpret = true separator = textComponent(", ") } ``` Common properties in this context: - `nbt`: the NBT path to read - `interpret`: parse the resulting text as a chat component when the stored value contains component JSON - `separator`: custom separator when the path resolves to multiple values - source-specific arguments: block position, entity selector, or storage id See [Chat Components](/docs/concepts/chat-components#nbtcomponent) for the full component guide. ### Predicates and sub-predicates Some predicate builders expose an `nbt { ... }` block directly. For example, block sub-predicates can match block-entity NBT: ```kotlin block(Blocks.CHEST) { nbt { this["CustomName"] = "\"Loot Chest\"" } } ``` That mirrors the attached `Block` predicate DSL, where `fun Block.nbt(block: NbtCompoundBuilder.() -> Unit)` stores the resulting compound in the predicate JSON. When a predicate surface exposes `predicates { customData { ... } }` or another nested NBT-aware structure, you still use the same value assignment style. See [Predicates](/docs/data-driven/predicates) for the surrounding condition DSL. ### Objects and helpers with `toNbt()` Several Kore types can serialize themselves to NBT using `toNbt()`. ```kotlin val entityNbt = myDisplayEntity.toNbt() ``` This is convenient when an API already knows its target NBT shape and you only need to pass the generated compound into a command or another builder. Examples appear in helper docs such as [Display Entities](/docs/helpers/display-entities) and [Mannequins](/docs/helpers/mannequins). ## Typical methods by context Here is the short version of what you usually reach for: | Context | Typical methods | |----------------------------|--------------------------------------------------------| | Build a compound | `nbt { ... }` | | Build a list from values | `nbtListOf(...)` | | Build a list with a DSL | `nbtList { ... }`, `addNbtCompound { ... }` | | Write entries | `this["key"] = value` | | Nest another compound | `this["key"] = nbt { ... }` | | Reuse generated object NBT | `toNbt()` | | Read NBT into chat | `nbtComponent(path, block/entity/storage)` | | Match NBT in a DSL | context-specific `nbt { ... }` methods | | Hand-write SNBT text | `stringifiedNbt(...)` when the target API expects text | ## Practical tips - Prefer the typed builder over raw SNBT strings whenever possible. - Keep reusable compounds in local variables when several commands share the same payload. - Remember that list element types must stay homogeneous. - If you want readable generated output while iterating, enable `prettyPrint` in your configuration. - When an API already exposes higher-level builders or `toNbt()`, prefer those over manually recreating the same shape. ## NBT vs SNBT in short `Nbt` is the structured tag model itself: compounds, lists, strings, numbers, and the other tag types Kore builds in memory with `nbt { ... }`, `nbtListOf(...)`, `nbtList { ... }`, and `toNbt()`. `Snbt` (stringified NBT) is the text form of that same data, written as a string such as `{CustomName:"\"Hero\"",Health:20}`. In Kore, you usually work with typed `Nbt` objects first, then let Kore serialize them when needed. Reach for SNBT helpers such as `stringifiedNbt(...)` when a target API specifically expects NBT as text instead of an `NbtTag` object. ## Related pages - [Chat Components](/docs/concepts/chat-components) - includes `NbtComponent` - [Commands](/docs/commands/commands) - especially the data command and NBT-carrying commands - [Predicates](/docs/data-driven/predicates) - NBT-aware predicate helpers - [Components](/docs/concepts/components) - item and custom component structures that often embed NBT-backed data - [Known Issues](/docs/advanced/known-issues#nbt-and-snbt-via-knbt) - `knbt`-specific constraints --- ## Scoreboards --- root: .components.layouts.MarkdownLayout title: Scoreboards nav-title: Scoreboards description: A guide for managing scoreboards in a Minecraft datapack using Kore. keywords: minecraft, datapack, kore, guide, scoreboards date-created: 2024-04-06 date-modified: 2026-02-03 routeOverride: /docs/concepts/scoreboards --- # Scoreboards Scoreboards track numeric values for players and entities. They're one of the two runtime variable containers in a datapack (the other being [data storage](/docs/concepts/data-storage)), and are essential for game mechanics, timers, and counters. If you're unsure when to use a scoreboard versus a Kotlin variable, read [Runtime Logic](/docs/concepts/runtime-logic) first. For the full scoreboard command reference, see [Commands](/docs/commands/commands#scoreboard-command). You can manage scoreboards with the `scoreboard` command: ```kotlin scoreboard.objectives.add("my_objective", ScoreboardCriteria.DUMMY) ``` ## Creating objectives You have multiple forms of the `scoreboard` command: ```kotlin scoreboard { objectives { add("my_objective", ScoreboardCriteria.DUMMY) // this form lets you manage multiple objectives at once } } scoreboard { objective("my_objective") { add(ScoreboardCriteria.DUMMY) // this form lets you manage a single objective } } ``` ## Managing objectives You can add, remove, set display name, set display slot, set render type of objectives: ```kotlin scoreboard { objective("my_objective") { add(ScoreboardCriteria.DUMMY, displayName = textComponent("My Objective", Color.GOLD)) setDisplaySlot(DisplaySlots.sidebar) setRenderType(RenderType.INTEGER) } } ``` ## Manage players You can manage players with the `players` block: ```kotlin scoreboard { players { add(allPlayers(), "my_objective", 1) remove(self(), "my_objective", 5) reset(self(), "my_objective") set(self(), "my_objective", 10) operation(self(), "my_objective", Operation.ADD, self(), "my_objective") } player(self()) { add("my_objective", 1) remove("my_objective", 5) reset("my_objective") set("my_objective", 10) operation("my_objective", Operation.ADD, self(), "my_objective") } } ``` You can also manage an objective for multiple selectors at once: ```kotlin scoreboard { players { objective("my_objective") { add(self(), 1) remove(self(), 5) reset(self()) set(self(), 10) operation(self(), Operation.ADD, self(), objective) } } } ``` Or also manage an objective for a single selector: ```kotlin scoreboard { player(self()) { objective("my_objective") { add(1) remove(5) reset() set(10) operation(Operation.ADD, self(), objective) } } } ``` These methods offer a more readable way to manage objectives, and avoid repetition operations invoking multiple times the same selector/objective. ## Scoreboard Displays Scoreboard Displays are a new helper that let you manage right sidebar displays, like on servers. You can create a display with the `scoreboardDisplay` function: ```kotlin scoreboardDisplay("my_display") { displayName = textComponent("My Display", Color.GOLD) setLine(0, textComponent("Line 1", Color.AQUA)) appendLine(textComponent("Line 2", Color.AQUA)) emptyLine() appendLine("Line 4", Color.AQUA) appendLine(textComponent("Line 2", Color.AQUA)) { createIf { // this line will only be created if the condition is true, this is executed in an `execute if` block predicate("stonks") } } } ``` You can also change the line numbers display: ```kotlin scoreboardDisplay("my_display") { decreasing = false startingScore = 0 } ``` #### New since 1.20.3 You can now hide the values of the lines: ```kotlin scoreboardDisplay("my_display") { appendLine("a") { hideValue = true // this will hide the value of the line } appendLine("b") hideValues() // this will hide the values of all lines // you can also provide a range of indices for the lines to hide } ``` Feel free to add feedback if you have any idea to improve this or to use other features from the new `scoreboard players display numberformat` subcommand. ### Resetting Scoreboard Displays You can reset all scoreboards with the `resetAll` function: ```kotlin ScoreboardDisplay.resetAll() ``` ### Limitations Scoreboard Displays are displayed the same way to everyone, so you can't have different displays for different players. You can at least have different displays for different team colors, but that's all (so there's a property to set the display slot). The sidebar is limited to 15 lines, so you can't have more than 15 lines in a display. ### How it works Scoreboard Displays are generated using fake players and teams, it will create teams with randomized numbers as name to avoid conflicts. Each line = 1 team, and each team has a suffix with the line text, then a fake player is added to the team with the score of the line number. For dynamic animations of displays, there aren't any solution for that currently. The only way to do that is to use a binary tree of functions, checking the score of the player between 0 and the middle of the maximum score, then between the middle and the maximum, and split the function in two, and so on. Then, when you arrive to the last function, you can call the `setLine` function to set the line text. And you repeat this for each line. If you have a better solution, maybe using macros, feel free to create functions for that and create a pull request. #### New since 1.20.3 Now scoreboard displays can be created more easily as you can now customize the display of each player as a text component. No teams are created anymore, and the display is generated using the `scoreboard players display name` command, achieving the same result. --- ## Selectors --- root: .components.layouts.MarkdownLayout title: Selectors nav-title: Selectors description: Build Minecraft target selectors in Kore with typed Kotlin builders. Compose entity filters, sorting, and score-based conditions instead of writing @e[...] strings by hand. keywords: minecraft, datapack, kore, selectors, target selectors, entities, players, commands date-created: 2026-04-21 date-modified: 2026-04-21 routeOverride: /docs/concepts/selectors --- # Selectors Minecraft target selectors choose players or entities without hardcoding a UUID or exact player name. Kore exposes them as typed builders, so you can compose filters in Kotlin instead of manually writing `@e[...]` strings. For the vanilla syntax reference, see the [Minecraft Wiki target selectors page](https://minecraft.wiki/w/Target_selectors). ## Base selector helpers Kore provides helpers for the common Java Edition selector bases: - `allPlayers()` -> `@a` - `allEntities()` -> `@e` - `nearestPlayer()` -> `@p` - `nearestEntity()` -> `@n` - `randomPlayer()` -> `@r` - `self()` -> `@s` - `player("Name")` -> player-name-filtered `@a[...]` ```kotlin val everyone = allPlayers() val executor = self() val nearest = nearestPlayer() ``` ## Filtering targets Each selector helper accepts a `SelectorArguments` builder. ```kotlin val nearbyZombies = allEntities { type = EntityTypes.ZOMBIE distance = rangeOrIntEnd(16) sort = Sort.NEAREST limit = 5 } ``` This generates a selector equivalent to: ```mcfunction @e[type=minecraft:zombie,distance=..16,sort=nearest,limit=5] ``` ## Common selector arguments Kore exposes the main Java Edition selector filters directly as mutable properties. - position: `x`, `y`, `z` - volume: `dx`, `dy`, `dz` - distance: `distance` - scoreboard filters: `scores` - advancement filters: `advancements` - sort and cap: `sort`, `limit` - player/entity metadata: `name`, `team`, `tag`, `gamemode`, `type`, `predicate`, `nbt` - rotations: `xRotation`, `yRotation` Example with position and volume: ```kotlin val entitiesInRoom = allEntities { x = 10.0 y = 64.0 z = -4.0 dx = 8.0 dy = 4.0 dz = 8.0 } ``` ## Score-based filtering Selectors integrate nicely with [Scoreboards](/docs/concepts/scoreboards) and other scoreboard-driven logic. ```kotlin val activePlayers = allPlayers { scores = scores { "round" greaterThanOrEqualTo 1 "lives" greaterThan 0 } } ``` That is especially useful in [`execute`](/docs/commands/commands), timers, game loops, and mini-game state tracking. ## Inverting filters Several selector filters support inversion. ```kotlin val nonSpectators = allPlayers { gamemode = !Gamemode.SPECTATOR team = !"admins" } ``` You can also invert `type`, `predicate`, and `nbt` filters. ## Limit and sorting Kore keeps the vanilla `sort` + `limit` pattern explicit. ```kotlin val oneRandomPlayer = allPlayers { sort = Sort.RANDOM limit = 1 } val nearestMarkedEntity = allEntities(limitToOne = true) { tag = "arena_marker" sort = Sort.NEAREST } ``` Use `limitToOne = true` when you want a concise single-target selector without repeating `limit = 1`. ## Using selectors in commands Selectors can be reused anywhere an `EntityArgument`, `DataArgument`, `PossessorArgument`, or `ScoreHolderArgument` is accepted, so they show up naturally across the [Commands](/docs/commands/commands) and [Functions](/docs/commands/functions) APIs. ```kotlin val fighters = allPlayers { tag = "fighter" } function("round_start") { effect(fighters) { give(Effects.SPEED, duration = 10, amplifier = 1) } tellraw(fighters, textComponent("Fight!")) scoreboard.players.set(fighters, "combo", 0) } ``` ## Practical tips - Prefer reusable selector values when the same filter appears in several functions. - Use `self()` when logic should apply to the current execution context. - Use generated entity types and predicates instead of raw strings whenever possible. - Keep complex filters readable by assigning them to `val`s before entering large command blocks, and check the [Cookbook](/docs/guides/cookbook) if you want to turn those values into reusable helpers. ## See also - [Arguments Internals](/docs/concepts/arguments) - contributor-facing details about Kore's broader argument system - [Minecraft Wiki: Target selectors](https://minecraft.wiki/w/Target_selectors) - vanilla syntax and semantics --- ## TimeNumber - Minecraft Ticks, Seconds & Days in Kore --- root: .components.layouts.MarkdownLayout title: TimeNumber - Minecraft Ticks, Seconds & Days in Kore nav-title: Time description: Work with Minecraft time in Kore using TimeNumber. Type-safe ticks, seconds, and days with arithmetic, conversions, and integration with commands, schedulers, and timers. keywords: minecraft time, ticks to seconds, minecraft tick timer, kore TimeNumber, datapack duration, tick conversion, minecraft time command, schedule delay, minecraft day cycle, time arithmetic date-created: 2026-06-16 date-modified: 2026-06-16 routeOverride: /docs/concepts/time --- # Overview Minecraft time is measured in **[ticks](https://minecraft.wiki/w/Tick)** (20 ticks = 1 second, 24 000 ticks = 1 day). Kore models this with `TimeNumber`, a typed value that carries both the numeric amount and the time unit (`TICKS`, `SECONDS`, `DAYS`). Commands that accept a duration - `schedule`, `title times`, `time add`, `weather`, `worldborder` - take a `TimeNumber` argument, so you never have to remember the raw tick math yourself. ## Creating time values Use the extension properties on any `Number`: ```kotlin import io.github.ayfri.kore.arguments.numbers.ticks import io.github.ayfri.kore.arguments.numbers.seconds import io.github.ayfri.kore.arguments.numbers.days val a = 100.ticks // 100t → 5 seconds val b = 5.seconds // 5s val c = 2.days // 2d → 48 000 ticks val d = 1.5.seconds // 1.5s (fractional values are preserved) ``` Or use the `time()` factory for dynamic construction: ```kotlin import io.github.ayfri.kore.arguments.numbers.time import io.github.ayfri.kore.arguments.numbers.TimeType val e = time(200) // 200t val f = time(10, TimeType.SECONDS) // 10s ``` ## Serialization (command output) `TimeNumber.toString()` produces what Minecraft commands expect: | Expression | Output | |---------------|--------| | `100.ticks` | `100` | | `1.5.ticks` | `1.5` | | `5.seconds` | `5s` | | `1.5.seconds` | `1.5s` | | `2.days` | `2d` | | `0.2.days` | `0.2d` | Integer values drop the `.0` suffix; fractional values are preserved as-is. ## Arithmetic `TimeNumber` supports the standard operators (same unit required for meaningful results): ```kotlin val delay = 3.seconds + 2.seconds // TimeNumber(5.0, SECONDS) val half = 10.ticks / 2.ticks // TimeNumber(5.0, TICKS) val neg = (-1).days // TimeNumber(-1.0, DAYS) ``` ## Unit conversions Convert between units while keeping the logical duration the same: ```kotlin val twentyTicks = 20.ticks twentyTicks.inSeconds() // TimeNumber(1.0, SECONDS) twentyTicks.inDays() // TimeNumber(1/1200 ≈ 0.000833, DAYS) val oneDay = 1.days oneDay.inTicks() // TimeNumber(24000.0, TICKS) oneDay.inSeconds() // TimeNumber(1200.0, SECONDS) ``` `toTicks()` / `toSeconds()` / `toDays()` reinterpret the raw number without converting (rarely needed): ```kotlin 100.ticks.toSeconds() // TimeNumber(100.0, SECONDS) - still 100, just retagged as "s" ``` ## Usage in commands Any command that takes a duration accepts `TimeNumber` directly: ```kotlin import io.github.ayfri.kore.arguments.numbers.seconds import io.github.ayfri.kore.arguments.numbers.ticks import io.github.ayfri.kore.arguments.numbers.days // schedule schedule.function(myFunction, 5.seconds) schedule.function(myFunction, 100.ticks, ScheduleMode.REPLACE) // title times (fade-in, stay, fade-out) title(self(), 0.5.seconds, 3.seconds, 0.5.seconds) // world time time.add(1.days) // weather weatherClear(30.seconds) // worldborder grow worldBorder.add(10.0, 200.ticks) ``` ## Further reading - [Schedule command](/docs/commands/commands#schedule) - scheduling functions with a delay - [Minecraft Wiki - Schedule command](https://minecraft.wiki/w/Commands/schedule) - vanilla `/schedule` syntax and behavior - [Scheduler helper](/docs/helpers/scheduler) - OOP wrapper for recurring schedules - [Timers](/docs/oop/timers) - OOP timer utilities built on ticks - [Minecraft Wiki - Tick](https://minecraft.wiki/w/Tick) --- # Helpers ## Helpers Utilities --- root: .components.layouts.MarkdownLayout title: Helpers Utilities nav-title: Helpers Utilities description: Overview of helper-focused utilities in Kore - renderers, display entities, inventories, mannequins, math, raycasts, scheduling, state delegates, and particle helpers. keywords: minecraft, datapack, kore, helpers, ansi, markdown, minimessage, raycast, math, area, state, vfx, particles, text, display, inventory, mannequin, scheduler date-created: 2026-03-31 date-modified: 2026-04-01 routeOverride: /docs/helpers/utilities position: 0 --- # Helpers Utilities The `helpers` module contains utility-style features that build on top of Kore and, when needed, the OOP abstractions. These helpers are not centered around long-lived object models, so they now live outside the `oop` module. ## Why use `helpers` Use `helpers` when you want higher-level building blocks without introducing gameplay objects such as teams, timers, or entity wrappers. - **Rendering helpers** convert human-friendly text formats into Minecraft text components. - **Display and entity helpers** cover display entities, mannequins, and other world-facing utility objects. - **Math, scheduling, and geometry helpers** pre-generate command logic for raycasts, particle shapes, spatial zones, delayed execution, or fixed-point math. - **State helpers** let you write concise Kotlin that still compiles to vanilla-friendly scoreboard and storage commands. The module is designed to stay composable: you can use it with plain Kore functions or mix it with the [`oop` module](/docs/oop/oop-utilities) when a system grows beyond a few stateless helpers. ## Install this module Add the `helpers` artifact when you want renderer, display, inventory, mannequin, math, raycast, scheduler, delegate, or particle utilities on top of Kore. ```kotlin dependencies { implementation("io.github.ayfri.kore:helpers:VERSION") } ``` ## Typical workflow Most helper APIs follow the same pattern: 1. **Register or build** a helper once (`registerMath()`, `raycast { ... }`, `drawCircle(...)`, etc.). 2. **Call it from functions** wherever you need the generated commands. 3. **Combine it with core Kore or OOP** if you need selectors, scoreboards, teams, timers, or reusable gameplay objects. That makes helpers a good fit for packs that start simple and progressively adopt more structure only where needed. ## All Features - **[ANSI Renderer](/docs/helpers/ansi-renderer)** - Convert ANSI SGR escape sequences into Minecraft text components when your source text already contains terminal-style formatting. - **[Area](/docs/helpers/area)** - Work with axis-aligned 3D regions for containment checks, intersections, unions, and coordinate transforms. - **[Display Entities](/docs/helpers/display-entities)** - Configure block, item, and text display entities with shared transformations, billboards, brightness, and interpolation settings. - **[Inventory Manager](/docs/helpers/inventory-manager)** - Register slot listeners and container policies for player, entity, or block inventories. - **[Mannequins](/docs/helpers/mannequins)** - Build mannequin entities with profiles, hidden layers, poses, and hand selection. - **[Markdown Renderer](/docs/helpers/markdown-renderer)** - Turn Markdown snippets into rich Minecraft text for chat, titles, signs, or boss bars. - **[MiniMessage Renderer](/docs/helpers/minimessage-renderer)** - Parse Adventure MiniMessage tags into Minecraft text components while keeping authoring ergonomic. - **[Raycasts](/docs/helpers/raycasts)** - Generate recursive step-based raycasts with callbacks for hits, misses, and per-step side effects. - **[Scheduler](/docs/helpers/scheduler)** - Schedule delayed or repeating functions with load-time registration and cancelation helpers. - **[Scoreboard Math](/docs/helpers/scoreboard-math)** - Reuse fixed-point math routines such as trigonometry, square-root, distance, and projectile formulas. - **[State Delegates](/docs/helpers/state-delegates)** - Map scoreboard objectives or NBT storage paths to Kotlin properties for terser command-generation code. - **[VFX Particles](/docs/helpers/vfx-particles)** - Generate circles, spheres, spirals, helixes, and lines as reusable particle functions. ## Helpers vs OOP Choose the `helpers` module when you mainly need: - data conversion and rendering, - world-facing utility objects such as displays, mannequins, and inventory controllers, - geometry or math utilities, - scheduling helpers, - lightweight compile-time sugar over vanilla commands. Choose the [`oop` module](/docs/oop/oop-utilities) when you need named gameplay objects such as players, teams, scoreboards, timers, spawners, or state machines. If you need entities, teams, scoreboards, items, timers, or other object-oriented gameplay abstractions, see the [OOP Utilities](/docs/oop/oop-utilities) page. --- ## ANSI Text Renderer --- root: .components.layouts.MarkdownLayout title: ANSI Text Renderer nav-title: ANSI Renderer description: Convert ANSI SGR escape sequences into Minecraft text components with the Kore helpers module. keywords: minecraft, datapack, kore, helpers, ansi, sgr, escape, text, renderer, color, bold, italic date-created: 2026-03-03 date-modified: 2026-03-31 routeOverride: /docs/helpers/ansi-renderer --- # ANSI Text Renderer Converts text containing [ANSI SGR escape sequences](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters) into Minecraft `ChatComponents` for use in [tellraw](https://minecraft.wiki/w/Commands/tellraw), title commands, or boss bar names. ANSI codes are stripped from the output and mapped to Minecraft text component styles. ## Basic usage ```kotlin val lines = ansiToTextComponents("\u001B[1;31mBold red\u001B[0m normal text") // Produces: [{bold:true, color:"red", text:"Bold red"}, {text:" normal text"}] ``` Each input line becomes a `ChatComponents` instance. Consecutive characters sharing the same style are merged into runs for efficiency. ## With config defaults ```kotlin val lines = ansiToTextComponents("\u001B[32mGreen\u001B[0m rest") { color = Color.WHITE } // "Green" gets green from ANSI, "rest" gets white from config fallback ``` ## Supported ANSI SGR codes | ANSI code | Minecraft property | Description | |-----------------------|------------------------|--------------------------| | `\x1B[1m` | `bold = true` | Bold on | | `\x1B[3m` | `italic = true` | Italic on | | `\x1B[4m` | `underlined = true` | Underline on | | `\x1B[8m` | `obfuscated = true` | Obfuscated on | | `\x1B[9m` | `strikethrough = true` | Strikethrough on | | `\x1B[22m` | `bold = null` | Bold off | | `\x1B[23m` | `italic = null` | Italic off | | `\x1B[24m` | `underlined = null` | Underline off | | `\x1B[28m` | `obfuscated = null` | Obfuscated off | | `\x1B[29m` | `strikethrough = null` | Strikethrough off | | `\x1B[30m`-`\x1B[37m` | `color` | Standard foreground | | `\x1B[90m`-`\x1B[97m` | `color` | Bright foreground | | `\x1B[38;5;Nm` | `color` (RGB) | 256-color palette | | `\x1B[38;2;R;G;Bm` | `color` (RGB) | 24-bit RGB color | | `\x1B[39m` | `color = null` | Default foreground color | | `\x1B[0m` | reset all | Reset all attributes | ANSI styles override the config defaults (`color`, `bold`, `italic`). When no ANSI style is active, the config values are used as fallback. ## Configuration | Property | Default | Description | |----------|---------|----------------------------------| | `color` | `null` | Fallback text color | | `bold` | `null` | Fallback bold styling | | `italic` | `null` | Fallback italic styling | | `font` | `null` | Minecraft font resource location | --- ## Area --- root: .components.layouts.MarkdownLayout title: Area nav-title: Area description: Axis-aligned 3D bounding box with the Kore helpers module - geometric operations, containment checks, and spatial queries. keywords: minecraft, datapack, kore, helpers, area, bounding box, vec3, intersect, union, contains date-created: 2026-03-03 date-modified: 2026-03-31 routeOverride: /docs/helpers/area --- # Area The `Area` class represents an axis-aligned 3D bounding box defined by two `Vec3` corners. It provides geometric operations useful for zone detection, region math, and spatial queries. Because it is purely geometric, `Area` is especially useful when you need to pre-compute regions in Kotlin and then reuse the resulting coordinates in multiple commands, predicates, or generated functions. ## Creating an area ```kotlin val zone = area(vec3(0, 0, 0), vec3(10, 5, 10)) zone.center // vec3(5, 2.5, 5) zone.size // vec3(10, 5, 10) zone.radius // vec3(5, 2.5, 5) val expanded = zone.expand(2) // grow by 2 in all directions val moved = zone.move(vec3(5, 0, 0)) // shift the area val overlap = zone.intersect(otherZone) // intersection of two areas val combined = zone.union(otherZone) // union of two areas // Containment checks val inside = vec3(3, 2, 3) in zone // true val contains = smallerZone in zone // true // Operator shortcuts val shifted = zone + vec3(1, 0, 0) val back = zone - vec3(1, 0, 0) // Range operator val area = vec3(0, 0, 0)..vec3(10, 10, 10) ``` ## Practical example ```kotlin val lobby = area(vec3(-8, 64, -8), vec3(8, 72, 8)) val arena = lobby.expand(16) val bossRoom = arena.move(vec3(32, 0, 0)) val entrance = bossRoom.center val safeZone = bossRoom.contract(2) val overlapsLobby = bossRoom.intersect(lobby) ``` This style works well when you want a single source of truth for multiple related regions: the base area defines the layout and the derived areas stay consistent even if the original dimensions change. ## Common use cases - Define lobby, arena, checkpoint, or boss-room bounds once in Kotlin. - Derive a slightly larger trigger zone with `expand(...)`. - Compute a smaller "safe interior" with `contract(...)`. - Test whether a point or another region belongs inside a larger gameplay area. ## Function reference | Function / Property | Description | |---------------------|------------------------------------| | `center` | Center point of the area | | `contains` (`in`) | Check if a point or area is inside | | `contract` | Shrink the area inward | | `expand` | Grow the area outward | | `intersect` | Intersection with another area | | `move` | Translate the area by a vector | | `radius` | Half-dimensions | | `size` | Dimensions (x, y, z) | | `union` | Union with another area | ## See also - [Raycasts](/docs/helpers/raycasts) - Combine spatial bounds with line-of-sight checks or interaction beams. - [Entities & Players](/docs/oop/entities-and-players) - Reuse computed areas to place, move, or query gameplay entities. - [Predicates](/docs/data-driven/predicates) - Turn region logic into reusable condition checks when needed. --- ## Display Entities --- root: .components.layouts.MarkdownLayout title: Display Entities nav-title: Display Entities description: A guide for creating Display Entities in the world. keywords: minecraft, datapack, kore, guide, display-entities date-created: 2024-04-06 date-modified: 2026-06-16 routeOverride: /docs/helpers/display-entities --- # Display Entities Display entities share a common set of world-rendering options and then add a few type-specific fields for blocks, items, or text. ## Shared display settings All display entities inherit these properties from the shared `DisplayEntity` base type: - `billboardMode` - how the display faces the camera (`FIXED`, `VERTICAL`, `HORIZONTAL`, `CENTER`). - `brightness` - optional block and light overrides for rendering. - `glowColorOverride` - replace the outline color with a custom RGB value. - `height` / `width` - resize the display bounds. - `interpolationDuration` / `startInterpolation` - animate transformation changes over time. - `shadowRadius` / `shadowStrength` - control the projected shadow. - `transformation` - combine translation, rotation, scale, or custom matrices. - `viewRange` - control when the entity is rendered from a distance. ## Entity Displays Entity displays are used to display blocks/items/text in the world. You can define multiple properties for the display, such as transformation, billboard mode, shadow etc. ```kotlin val entityDisplay = blockDisplay { blockState(Blocks.GRASS_BLOCK) { properties { this["snowy"] = true } } transformation { leftRotation { quaternionNormalized(0.0, 0.0, 0.0, 1.0) } scale = vec3(2.0) translation { y = 2.0 } } billboardMode = BillboardMode.CENTER shadowRadius = 0.5f } summon(entity = entityDisplay.entityType, pos = vec3(0, 0, 0), nbt = entityDisplay.toNbt()) // will summon a grass block with snow on top, scaled by 2, rotated by 0 degrees and translated by 2 blocks on the y axis at the position 0, 0, 0 ``` ## Block Displays Block displays are used to display blocks in the world. They are created by calling the `blockDisplay()` DSL. ```kotlin val blockDisplay = blockDisplay { blockState(Blocks.GRASS_BLOCK) { properties { this["snowy"] = true } } } ``` ## Item Displays Item displays are used to display items in the world. They are created by calling `itemDisplay()` DSL. The optional `displayMode` property uses `ItemDisplayModelMode`, which serializes to the lowercase values Minecraft expects: - `FIRSTPERSON_LEFTHAND` - `FIRSTPERSON_RIGHTHAND` - `FIXED` - `GROUND` - `GUI` - `HEAD` - `NONE` - `ON_SHELF` - `THIRDPERSON_LEFTHAND` - `THIRDPERSON_RIGHTHAND` ```kotlin val itemDisplay = itemDisplay { item(Items.DIAMOND_SWORD) { name = textComponent("test") enchantments { Enchantments.SHARPNESS at 1 Enchantments.UNBREAKING at 3 } modifiers { modifier(Attributes.ATTACK_DAMAGE, 1.0, AttributeModifierOperation.ADD) } } } ``` ## Text Displays Text displays are used to display text in the world. They are created by calling `textDisplay()` DSL. `alignment` uses `TextAlignment`, which currently supports: - `LEFT` - `CENTER` - `RIGHT` ```kotlin val textDisplay = textDisplay { text("test", Color.RED) { bold = true } } ``` ## Transformations Transformations are used to modify the translation, left/right rotations and scale of displays. They are created by calling `transformation` DSL. You can also apply directly matrix transformations and use quaternions, axis angles or use Euler angles for rotations. ```kotlin transformation { leftRotation { quaternionNormalized(0.0, 0.0, 0.0, 1.0) } scale = vec3(2.0) translation { y = 2.0 } } ``` ## Interpolations You can convert your display entity into an "interpolable" display entity by calling `interpolable()` on it. This will allow you to interpolate between the current transformation and the target transformation in a given time. ```kotlin val interpolableEntityDisplay = blockDisplay { blockState(Blocks.STONE_BLOCK) }.interpolable(position = vec3(0, 0, 0)) interpolableEntityDisplay.summon() interpolableEntityDisplay.interpolateTo(duration = 2.seconds) { translation { y = 2.0 } } ``` Interpolation is especially useful when you want display entities to move or morph smoothly between ticks without rebuilding the entity from scratch. ## OOP Entity Handles After creating an interpolable, call `toEntity()` to get a typed OOP entity handle (`BlockDisplayEntity`, `ItemDisplayEntity`, or `TextDisplayEntity`). This gives access to all `Entity` extension functions such as `kill`, `teleportTo`, `addTag`, and more. ```kotlin val display = blockDisplay { blockState(Blocks.STONE) }.interpolable(vec3(0, 64, 0)) display.summon() val entity: BlockDisplayEntity = display.toEntity() as BlockDisplayEntity // use any Entity OOP extension entity.addTag("my_display") entity.teleportTo(0, 65, 0) entity.kill() ``` You can also construct the typed entity handles directly when you already have a UUID: ```kotlin val uuid = uuid("12345678-1234-1234-1234-123456789012") val block = BlockDisplayEntity(uuid) val item = ItemDisplayEntity(uuid) val text = TextDisplayEntity(uuid) ``` All three target their entity with `@e[type=minecraft:,nbt={UUID:[I;...]}]`. --- ## Inventory Manager --- root: .components.layouts.MarkdownLayout title: Inventory Manager nav-title: Inventory Manager description: Listen to slot events and control containers (players, blocks) with Kore's Inventory Manager. keywords: minecraft, datapack, kore, inventory, container, slots, events, gui date-created: 2025-08-11 date-modified: 2025-08-11 routeOverride: /docs/helpers/inventory-manager --- # Inventory Manager Kore’s Inventory Manager lets you declaratively control [inventories](https://minecraft.wiki/w/Inventory) on entities or blocks and react to slot events. - Manage items in any `ContainerArgument` (players, entities, or block containers). - Register slot listeners that fire when an item is taken from a slot. - Keep a slot populated, clear other slots, or run custom logic every tick. - Auto-generate the required load/tick functions and minimal scoreboards to drive the listeners. ## Quick start ```kotlin import io.github.ayfri.kore.arguments.types.literals.nearestPlayer import io.github.ayfri.kore.arguments.colors.Color import io.github.ayfri.kore.arguments.chatcomponents.textComponent import io.github.ayfri.kore.commands.TitleLocation import io.github.ayfri.kore.generated.Items import io.github.ayfri.kore.helpers.inventorymanager.inventoryManager function("inventory_demo") { val playerInv = inventoryManager(nearestPlayer()) playerInv.slotEvent(HOTBAR[0], Items.NETHER_STAR { this["display"] = nbt { this["Name"] = textComponent("Do not move me", color = Color.RED).toJsonString() } }) { onTake { title(self(), TitleLocation.ACTIONBAR, textComponent("Stop taking me!", color = Color.RED)) } duringTake { setItemInSlot() } onTick { clearAllItemsNotInSlot(); killAllItemsNotInSlot() } setItemInSlot() // seed the slot once } // Start listeners for this manager playerInv.generateSlotsListeners() } ``` Tip: Use the builder variant to both declare listeners and auto-generate them in one go: ```kotlin inventoryManager(nearestPlayer()) { slotEvent(HOTBAR[0], Items.DIAMOND) { setItemInSlot() } generateSlotsListeners() } ``` ## Block containers You can target block inventories as well by passing a `Vec3` and (optionally) placing a container block first: ```kotlin val chestPos = vec3(0, -59, 0) inventoryManager(chestPos) { setBlock(Blocks.CHEST) slotEvent(CONTAINER[0], Items.DIAMOND_SWORD) { onTake { tellraw(allPlayers(), text("You took the sword!", Color.RED)) } duringTake { setItemInSlot() } onTick { clearAllItemsNotInSlot(); killAllItemsNotInSlot() } setItemInSlot() } generateSlotsListeners() } ``` ## API overview - `inventoryManager(container)` - Create a manager for any `ContainerArgument` (`EntityArgument` or `Vec3`). Internally uses [`/item`](https://minecraft.wiki/w/Commands/item) to place items in slots. - `slotEvent(slot, expectedItem) { … }` - Register handlers for a single slot. - `onTake { … }` - Fires once when the slot transitions from expected item to something else. - `duringTake { … }` - Fires every tick while the slot is not holding the expected item; useful to enforce state. - `onTick { … }` - Runs every tick regardless of state; convenient for housekeeping. - Helpers inside the scope: - `setItemInSlot()` - Put back the expected item into the slot. - `clearAllItemsNotInSlot([targets])` - Clear all other slots. - `killAllItemsNotInSlot()` - Remove dropped items that don’t belong to this slot. - `generateSlotsListeners()` - Emits the `load`/`tick` functions and scoreboard wiring for all registered listeners. - `setBlock(block)` - When the container is a position, place a block (e.g., a chest) before managing its contents. - `clear(slot)`, `clearAll()`, `clearAll(item)` - Utilities to wipe inventory content. Internally, Inventory Manager relies on a scoreboard objective and a tiny helper marker entity (for non-entity containers) to detect state transitions. Names are auto-namespaced and unique per datapack. ## Removing detectors To clean up objectives created by Inventory Manager across runs: ```kotlin dataPack("my_dp") { InventoryManager.removeClickDetectors() } ``` ## Full example This combines a player inventory policy with messaging and a chest that constantly re-seeds its first slot. It mirrors the test coverage used in Kore’s own suite. ```kotlin fun Function.inventoryManagerTests() { val counter = "take_counter" val playerInv = inventoryManager(nearestPlayer()) playerInv.slotEvent(HOTBAR[0], Items.NETHER_STAR) { onTake { title(self(), TitleLocation.ACTIONBAR, text("Don’t take me", Color.RED)) scoreboard.players.add(self(), counter, 1) } duringTake { setItemInSlot() } onTick { clearAllItemsNotInSlot(); killAllItemsNotInSlot() } setItemInSlot() } playerInv.generateSlotsListeners() datapack.load { scoreboard.objectives.add(counter) scoreboard.players.set(playerInv.container as ScoreHolderArgument, counter, 0) } inventoryManager(vec3(0, -59, 0)) { setBlock(Blocks.CHEST) slotEvent(CONTAINER[0], Items.DIAMOND_SWORD) { onTake { tellraw(allPlayers(), text("You took the diamond sword from the chest", Color.RED)) } duringTake { setItemInSlot() } onTick { clearAllItemsNotInSlot(); killAllItemsNotInSlot() } setItemInSlot() } generateSlotsListeners() } } ``` ## See also - [Scheduler](/docs/helpers/scheduler) - Run repeated or delayed logic that complements inventory policies. - [Components](/docs/concepts/components) - Define complex items (names, lore, enchantments) you can enforce in slots. - [Predicates](/docs/data-driven/predicates) - Validate component-based item properties in other contexts. - [Scoreboards](/docs/concepts/scoreboards) - Background knowledge on objectives used under the hood. --- ## Mannequins --- root: .components.layouts.MarkdownLayout title: Mannequins nav-title: Mannequins description: A guide for creating Mannequins in the world. keywords: minecraft, datapack, kore, guide, mannequins date-created: 2026-01-25 date-modified: 2026-06-16 routeOverride: /docs/helpers/mannequins --- # Mannequins Mannequins are special entities that can display player skins and textures. They are highly customizable, allowing you to change their profile, hidden layers, and main hand. ## Creating a Mannequin You can create a mannequin using the `mannequin` DSL. ```kotlin val myMannequin = mannequin { hiddenLayers(MannequinLayer.CAPE, MannequinLayer.HAT) mainHand = MannequinHand.LEFT playerProfile("Ayfri") } summon(myMannequin.entityType, vec3(), myMannequin.toNbt()) ``` ## Profiles Mannequins can have two types of profiles: `PlayerProfile` and `TextureProfile`. ### Player Profile A player profile uses a player's name or UUID to fetch their skin and properties. ```kotlin mannequin { playerProfile(name = "Steve", id = uuid("8667ba71-b85a-4004-af54-457a9734eed7")) } ``` ### Texture Profile A texture profile allows you to specify a direct texture, and optionally a cape, elytra, and model type. ```kotlin mannequin { textureProfile(texture = "tex") { cape = model("cape") model = MannequinModel.SLIM } } ``` ## Customization Mannequins support additional fields for further customization: ```kotlin mannequin { description = textComponent("Test") hideDescription = false immovable = true pose = MannequinPose.CROUCHING } ``` ### Pose The `pose` field allows you to set the mannequin's pose. Available poses are: - `STANDING` - `CROUCHING` - `SWIMMING` - `FALL_FLYING` - `SLEEPING` ## Hidden Layers You can hide specific layers of the mannequin's skin using the `hiddenLayers` function. Available layers: - `CAPE` - `HAT` - `JACKET` - `LEFT_PANTS_LEG` - `LEFT_SLEEVE` - `RIGHT_PANTS_LEG` - `RIGHT_SLEEVE` ```kotlin mannequin { hiddenLayers(MannequinLayer.JACKET, MannequinLayer.HAT) } ``` ## Main Hand You can set which hand is the main hand of the mannequin. ```kotlin mannequin { mainHand = MannequinHand.RIGHT } ``` ## Summoning and OOP Handle Use `summon()` inside a function to spawn the mannequin and receive a `MannequinEntity` handle. The handle uniquely identifies this instance by its UUID, giving access to all OOP entity commands. ```kotlin val myMannequin = mannequin { pose = MannequinPose.STANDING playerProfile("Ayfri") } // summon() spawns the entity and returns a typed handle val handle: MannequinEntity = myMannequin.summon(vec3(0, 64, 0)) // all Entity OOP extensions work on the handle handle.swing(SwingHand.MAINHAND) handle.kill() handle.teleportTo(0, 64, 5) ``` The generated selector is `@e[type=minecraft:mannequin,nbt={UUID:[I;...]}]`, uniquely targeting the spawned instance. --- ## Markdown Text Renderer --- root: .components.layouts.MarkdownLayout title: Markdown Text Renderer nav-title: Markdown Renderer description: Convert Markdown-formatted text into Minecraft text components with the Kore helpers module. keywords: minecraft, datapack, kore, helpers, markdown, text, renderer, bold, italic, link, heading, list date-created: 2026-03-03 date-modified: 2026-03-31 routeOverride: /docs/helpers/markdown-renderer --- # Markdown Text Renderer Converts [Markdown](https://commonmark.org/)-formatted text into Minecraft `ChatComponents` for use in [tellraw](https://minecraft.wiki/w/Commands/tellraw), title commands, or boss bar names. ## Basic usage ```kotlin val lines = markdownToTextComponents( """ # Welcome Hello **world**! Click [here](https://example.com). - item one - item two """.trimIndent() ) ``` Each input line becomes a `ChatComponents` instance. Inline styles are parsed and mapped to Minecraft text component properties. ## Supported inline syntax | Markdown syntax | Minecraft property | Description | |---------------------|------------------------|----------------------------------| | `**text**` | `bold = true` | Bold | | `*text*` / `_text_` | `italic = true` | Italic | | `~~text~~` | `strikethrough = true` | Strikethrough | | `__text__` | `underlined = true` | Underline (Minecraft extension) | | `\|\|text\|\|` | `obfuscated = true` | Obfuscated (Minecraft extension) | | `` `code` `` | `color` (codeColor) | Inline code span | | `[label](url)` | `clickEvent = OpenUrl` | Clickable link | | `§(#rrggbb)text§()` | `color` (RGB) | Custom colored span | ## Supported block syntax | Markdown syntax | Rendering | |------------------------|--------------------------------------| | `# Heading` - `######` | Bold + heading color (configurable) | | `- item` / `* item` | Unordered list with bullet prefix | | `1. item` | Ordered list with number prefix | | `> quote` | Blockquote with `│ ` prefix | | `---` / `***` / `___` | Horizontal rule (strikethrough line) | ## Not supported (Minecraft limitations) The following Markdown features are **not supported** because Minecraft text components cannot represent them: - Images (`![alt](url)`) - Tables - Nested blockquotes - Multi-line code blocks (fenced ` ``` `) - HTML tags - Footnotes - Task lists (`- [ ]` / `- [x]`) - Reference-style links (`[text][ref]`) ## Examples ```kotlin // Bold + italic combined val styled = markdownToTextComponents("**bold and *italic* text**") // Link with custom color val link = markdownToTextComponents("Visit [Kore](https://kore.ayfri.com)") { linkColor = Color.GREEN } // Custom color syntax val colored = markdownToTextComponents("§(#ff0000)red text§() normal text") // Heading with inline styles val heading = markdownToTextComponents("# Welcome to **Kore**") ``` ## Configuration | Property | Default | Description | |--------------------|---------------|----------------------------------------------| | `color` | `null` | Default text color | | `bold` | `null` | Default bold state | | `italic` | `null` | Default italic state | | `font` | `null` | Minecraft font resource location | | `headingColors` | level 1-6 map | Color per heading level (gold, yellow, etc.) | | `codeColor` | `Color.GRAY` | Color for inline code spans | | `linkColor` | `Color.AQUA` | Color for link text | | `linkUnderline` | `true` | Whether links are underlined | | `blockquotePrefix` | `"│ "` | String prepended to blockquote lines | | `bulletChar` | `"• "` | Bullet string for unordered list items | | `hrChar` | `"─"` | Character repeated for horizontal rules | | `hrLength` | `20` | Number of repetitions for horizontal rules | --- ## MiniMessage Renderer & Viewer - Parse Adventure Format in Minecraft --- root: .components.layouts.MarkdownLayout title: MiniMessage Renderer & Viewer - Parse Adventure Format in Minecraft nav-title: MiniMessage Renderer description: Parse Adventure MiniMessage format into Minecraft text components with Kore. Supports colors, decorations, click/hover events, gradients, and fonts. Use as a MiniMessage viewer for rich text in datapacks. keywords: minimessage, minimessage viewer, minimessage renderer, minimessage parser, adventure text, minecraft text components, minimessage generator, mini message format, kore minimessage, minimessage to chat component date-created: 2026-03-03 date-modified: 2026-07-02 routeOverride: /docs/helpers/minimessage-renderer --- # MiniMessage Renderer The `helpers` module includes a MiniMessage renderer that parses [Adventure MiniMessage](https://docs.advntr.dev/minimessage/format.html) format strings into Kore `ChatComponents`. This lets you write human-readable styled text that compiles into Minecraft's JSON text component format. MiniMessage is part of the [Adventure](https://github.com/KyoriPowered/adventure) library, widely used by Paper, Velocity, and other Minecraft server platforms. You can preview MiniMessage text in the [MiniMessage Web Viewer](https://webui.advntr.dev/) without starting a Minecraft instance. ## Basic Usage ```kotlin import io.github.ayfri.kore.text.miniMessageToTextComponents val components = miniMessageToTextComponents("Hello world!") ``` The function returns a `ChatComponents` instance that can be used anywhere Kore expects text components. ## Configuration Pass a configuration lambda to customize defaults: ```kotlin val components = miniMessageToTextComponents("Styled text") { color = Color.AQUA // default color for unstyled text bold = true // default bold state italic = false // default italic state font = "minecraft:alt" // default font strict = true // throw on parse errors } ``` ## Colors ### Named Colors All vanilla formatting colors are supported: ``` Red text Blue text Purple text ``` Aliases `` and `` are also supported: ``` Red text Blue text ``` ### Hexadecimal Colors ``` <#ff0000>Red text Green text Blue text ``` ### Gradients Gradient tags are recognized and apply the first color in the gradient: ``` Gradient text ``` ### Rainbow & Transition Rainbow and transition tags are recognized as style tags: ``` Rainbow text Transition text ``` ## Decorations | Tag | Aliases | Effect | |-------------------|---------------|---------------| | `` | `` | **Bold** | | `` | ``, `` | *Italic* | | `` | `` | Underlined | | `` | `` | Strikethrough | | `` | `` | Obfuscated | All decorations support closing tags to limit their scope: ``` Bold and italic just bold ``` ### Reset The `` (or ``) tag clears all active styles and returns to defaults: ``` Styled textNormal text ``` ## Click Events ``` Click to visit Click to spawn Click to message Next page Click to copy ``` ## Hover Events ``` Tooltip text'>Hover me Hover for item Hover for entity ``` The `show_text` value is itself parsed as MiniMessage, so you can use tags inside hover text. ## Fonts ``` Uniform font text Icon font ``` ## Insertion Shift-clicking the rendered component inserts the specified text into the chat prompt: ``` Shift-click me ``` ## Newlines ``` Line oneLine two Line one
Line two ``` ## Advanced Components ### Translatable (I18n) ``` ``` ### Keybinds ``` ``` ### Selectors ``` ``` ### Scoreboards ``` ``` ### NBT Data ``` ``` ## Escaping & Preformatted Text ### Backslash Escaping Prefix a tag with `\` to render it as literal text: ``` \This is not red ``` ### Preformatted Blocks Everything inside `
...
` is treated as raw text: ```
This renders as literal  tags
``` ## Tag Resolvers Custom placeholder tags can be resolved dynamically at render time: ```kotlin val components = miniMessageToTextComponents(" joined the game") { tagResolvers = mapOf( "player_name" to TagResolver { text("Ayfri") { color = Color.GOLD } } ) } ``` The resolved component inherits the current style context (color, bold, italic, font) unless it defines its own. ## Strict Mode Enable strict mode to throw a `MiniMessageParseException` on parse errors: ```kotlin miniMessageToTextComponents("Unclosed tag") { strict = true // throws MiniMessageParseException("Unclosed tags: bold") } ``` Strict mode catches: - Unclosed tags - Unknown/unrecognized tags - Closing tags with no matching opening tag ## References - [MiniMessage Format Specification](https://docs.advntr.dev/minimessage/format.html) - full tag reference from the Adventure docs. - [MiniMessage Web Viewer](https://webui.advntr.dev/) - interactive playground to preview MiniMessage text. - [Adventure GitHub Repository](https://github.com/KyoriPowered/adventure) - the library that defines the MiniMessage format. - [Minecraft Wiki - Raw JSON Text](https://minecraft.wiki/w/Raw_JSON_text_format) - the underlying component format MiniMessage compiles to. --- ## Raycasts --- root: .components.layouts.MarkdownLayout title: Raycasts nav-title: Raycasts description: Recursive raycast system with the Kore helpers module - step-based raycasting with block hit, max distance, and per-step callbacks. keywords: minecraft, datapack, kore, helpers, raycast, ray, block, hit, step, recursive date-created: 2026-03-03 date-modified: 2026-04-01 routeOverride: /docs/helpers/raycasts --- # Raycasts Raycasts generate a set of recursive functions that step forward from the entity's eyes until they hit a block or reach max distance. Each step is a local-coordinate [`execute positioned`](https://minecraft.wiki/w/Commands/execute) call, so precision scales with the step size. They are ideal for "look at" interactions, custom tools, line-of-sight checks, or visual debugging because the helper pre-builds the recursive command chain for you. ## API overview The helper is centered around two entry points: - `raycast { ... }` - builds a fresh `RaycastConfig` inline. - `raycast(config)` - reuses an already configured `RaycastConfig` instance. The generated `RaycastHandle` exposes a single `cast()` method that launches the raycast from the current function context. `RaycastConfig` defaults: - `name = "raycast"` - `maxDistance = 100` - `step = 0.5` - `onHitBlock = {}` - `onStep = null` - `onMaxDistance = null` ## DSL builder ```kotlin val ray = raycast { name = "my_ray" maxDistance = 50 step = 0.5 onHitBlock = { say("Hit!") } onMaxDistance = { say("Too far!") } onStep = { particle(Particles.FLAME, vec3()) } } function("use_ray") { with(ray) { cast() } } ``` ## Callback lifecycle - `onStep` runs for every successful step before the ray stops. - `onHitBlock` runs when the next step collides with a block. - `onMaxDistance` runs when the ray reaches the configured limit without hitting anything. If `onMaxDistance` is omitted, the ray quietly removes its internal tag when it reaches the limit, so the generated functions stop recursing without firing a fallback callback. This makes it easy to keep gameplay logic explicit: particles can live in `onStep`, impact logic in `onHitBlock`, and fallback behavior in `onMaxDistance`. ## Practical usage pattern ```kotlin val scanner = raycast { name = "scanner" maxDistance = 24 step = 0.25 onStep = { particle(Particles.END_ROD, vec3()) } onHitBlock = { say("Target acquired") } onMaxDistance = { say("No target found") } } function("scan_once") { with(scanner) { cast() } } ``` For precise interaction beams, prefer a smaller `step`; for cheaper "good enough" scans, use a larger one. The step value is measured in blocks and is applied through a local-position offset, so smaller values increase precision while also generating more recursive calls. ## See also - [Area](/docs/helpers/area) - Define spatial zones that complement what a ray can detect or trigger. - [VFX Particles](/docs/helpers/vfx-particles) - Use particles inside `onStep` for visual debugging or beam effects. - [Entities & Players](/docs/oop/entities-and-players) - Execute raycasts from player or mob contexts with reusable selectors. --- ## Minecraft Datapack Scheduler - Loop, Delay & Schedule Tasks with Kore --- root: .components.layouts.MarkdownLayout title: Minecraft Datapack Scheduler - Loop, Delay & Schedule Tasks with Kore nav-title: Scheduler description: Schedule and loop tasks in Minecraft datapacks with Kore. Tick-based loops, delayed actions, repeating schedules, and timed callbacks without complex scoreboard chains. keywords: datapack scheduler, minecraft schedule, timer datapack, datapack loop, tick loop minecraft, schedule function, repeating task datapack, delay command minecraft, kore scheduler, datapack timer loop date-created: 2025-03-26 date-modified: 2026-07-02 routeOverride: /docs/helpers/scheduler --- # Scheduler in Kore This document explains how to schedule and run tasks at specific times or intervals using Kore's built-in scheduler. Schedulers help automate recurring actions, delayed tasks, and cleanup when tasks are no longer needed. They are the higher-level way to do the time-based loops described in [Runtime Logic](/docs/concepts/runtime-logic). ## Overview A "Scheduler" in Kore lets you: - Schedule a one-time execution of a function or a block of code. - Schedule repeating tasks with a fixed period. - Persist references to scheduled tasks so they can be modified or canceled. All scheduling logic revolves around three core classes: 1. [Scheduler](https://github.com/Ayfri/Kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/helpers/Scheduler.kt#L34) - Represents a single scheduled task (with optional delay and period). 2. [UnScheduler](https://github.com/Ayfri/Kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/helpers/UnScheduler.kt#L34) - Cancels, or clears, repeating tasks. 3. [SchedulerManager](https://github.com/Ayfri/Kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/helpers/SchedulerManager.kt#L42) - Maintains a list of schedulers for a given DataPack and offers convenience methods to add or remove them. **Note:** **Schedulers are saved and loaded from a `scheduler_setup` function that is added to the `minecraft/load.json` tag.** ## Basic Usage Use the DataPack extension function schedulerManager to get or create a SchedulerManager for your datapack: ```kotlin val datapack = dataPack("my_datapack") { // ... schedulerManager { // ... } // ... } ``` Inside the schedulerManager block, you can add schedulers with different behaviors by calling addScheduler. Common calls are: - `addScheduler(delay)` - Executes once after a given delay ([`TimeNumber`](/docs/concepts/time)). - `addScheduler(delay, period)` - Executes once after delay, then repeats every period. - `addScheduler(block)` - Executes right away if no delay or period is specified. In many cases, you'll pass a function block (Function.() -> Command) so you can include DSL commands: ### One-Time Execution If you only want to run a function once after a delay: ```kotlin schedulerManager { addScheduler(5.seconds) { say("I run after 5 seconds!") } } ``` ### Recurrent Execution For periodic tasks: ```kotlin schedulerManager { addScheduler(3.seconds, 1.seconds) { // This code runs first after 3 seconds, then every 1 second. debug("Repeated task!") } } ``` ### Schedule by reference You can also schedule a task by reference: ```kotlin val myFunction = function("my_function") { debug("Hello, world!") } schedulerManager { addScheduler(myFunction, 10.seconds) } ``` ### Canceling a Repeating Task If you have a repeating scheduler, you can unschedule it when you no longer need it: 1. Pass a named function or store the return value of addScheduler. 2. Call unSchedule or removeScheduler. Example removing by reference: ```kotlin val repeatingScheduler = addScheduler(2.seconds, 2.seconds) { debug("Repeat every 2 seconds!") } // Later in the code, for instance in another function: unSchedule(repeatingScheduler.function) // stops the repeating task ``` Or remove by function name: ```kotlin removeScheduler("my_function_to_remove") ``` ### Canceling all tasks You can cancel all tasks by calling clearSchedulers: ```kotlin unScheduleAll() ``` ## Complex Example Below is a more advanced scenario showing how to: 1. Run a periodic task (initial delay + repeating period). 2. Store custom data in a named storage using the /data command. 3. Use execute to conditionally run commands based on stored data. In this example, we keep a running "counter" in a storage and increment it every time the repeating task runs. We also demonstrate how to read from that storage in subsequent commands. ### Full Example ```kotlin import io.github.ayfri.kore.DataPack import io.github.ayfri.kore.arguments.numbers.seconds import io.github.ayfri.kore.arguments.types.resources.StorageArgument import io.github.ayfri.kore.commands.data import io.github.ayfri.kore.commands.execute import io.github.ayfri.kore.commands.value import io.github.ayfri.kore.functions.function import io.github.ayfri.kore.generated.EntityTypes fun DataPack.complexSchedulerExample() { // Create a storage reference for storing and reading data val myStorage = storage("kore_example:counter_storage") // A function that resets the counter at any time function("reset_counter") { data(myStorage) { merge { value("counter", 0) } } say("Counter has been reset to 0!") } schedulerManager { // Turn on debug logs for demonstration debug = true // Create a repeating scheduler. It starts after 2 seconds, repeats every 4 seconds. addScheduler(2.seconds, 4.seconds) { val tempEntity = entity("#temp_entity") // 1) Store the value in a score execute { storeResult { score(tempEntity, "counter") } run { data(myStorage) { get("counter") } } } // 2) Increment the score scoreboard.objective(tempEntity, "counter").add(1) // 3) Store the score in the storage execute { storeResult { storage(myStorage, "counter") } run { scoreboard.objective(tempEntity, "counter").get() } } // 4) Print out the current counter using execute + data get execute { // We can conditionally run commands if the counter is above a threshold, etc. run { // Show the updated counter in chat every time this repeats data(myStorage) { get("counter") } // This prints the raw integer. Let's also do a friendly message: say("Counter incremented!") } } // 5) Condition example: if the counter >= 5, summon something or do logic // Check if the score is >= 5, as we already stored the value in a score execute { // Compare the counter with a threshold, e.g. 5 ifCondition { score(tempEntity, "counter") greaterOrEqual 5 } run { summon(EntityTypes.LIGHTNING_BOLT) say("Counter is >= 5. Summoned lightning!") } } } // Another single-run task in 10 seconds to reset everything addScheduler(10.seconds) { function("reset_counter") say("All done, resetting!") } } } ``` Explanation: 1. We create a custom storage named "kore_example:counter_storage" to maintain a key called "counter". 2. We set up a repeating task (delayed by 2 seconds, repeats every 4 seconds). Inside that repeating schedule: - We store the counter in a score - We increment the counter in storage. - We show the updated counter using data get and say commands. - We run a condition (ifData … >= 5) to check if "counter" has reached 5 or more, then summon a lightning bolt. 3. We also add a single-run scheduler at 10 seconds that calls a function to reset the counter and prints a final message. ## Conclusion - Schedulers let you automate tasks in your datapack with fixed delays or repetition. - Use a SchedulerManager on your DataPack via `schedulerManager { … }`. - Add, remove, or clear schedulers by referencing either the assigned function or the function name. - Combine schedulers with any usual commands for fully automated or repeated logic (debugging, storing data, advanced "execute" conditions, etc.). This powerful system helps keep your datapack logic neatly organized and easy to maintain when you need repeated or delayed operations. --- ## Scoreboard Math Engine --- root: .components.layouts.MarkdownLayout title: Scoreboard Math Engine nav-title: Scoreboard Math description: Trigonometric and algebraic functions using scoreboard operations with Kore. Sine, cosine, square root, distance, and parabolic trajectory via fixed-point math on scoreboards. keywords: minecraft, datapack, kore, helpers, math, scoreboard, trigonometry, sine, cosine, sqrt, distance, parabola date-created: 2026-03-03 date-modified: 2026-04-01 routeOverride: /docs/helpers/scoreboard-math --- # Scoreboard Math Engine The math module provides trigonometric and algebraic functions using scoreboard operations. All values use fixed-point arithmetic scaled by **1000** to preserve decimal precision inside integer-only scoreboards. ## Registering the math module ```kotlin val math = registerMath() ``` This generates a **load function** that creates the `kore_math` objective and sets useful constants (`#2`, `#360`, `#scale`). ## Reading the results Because scoreboards only store integers, every result is scaled by `1000`: - `1000` means `1.0` - `500` means `0.5` - `-707` means approximately `-0.707` That convention stays consistent across trigonometric helpers and formulas, which makes it easier to combine several math operations in the same datapack. ## Trigonometric functions Sine and cosine use a pre-computed 360-entry lookup table (one entry per degree). The input score holds an angle in degrees; the output receives `value × 1000`. ```kotlin function("trig_demo") { math.apply { cos(player, "angle", "cos_result") sin(player, "angle", "sin_result") } } ``` Negative angles are normalized safely before the lookup, so inputs such as `-90` behave exactly like `270` even though Minecraft scoreboards keep the sign when using `%`. This is particularly handy for scoreboard-driven movement systems, orbiting particles, or knockback calculations where the input angle is already tracked as an integer. ### Delegate-based syntax If you already use [scoreboard delegates](/docs/helpers/state-delegates), the math helpers also expose infix wrappers that preserve the same runtime behavior while removing string boilerplate: ```kotlin function("trig_delegate_demo") { val launchAngle = player.scoreboard("launch_angle") val cosAngle = player.scoreboard("cos_angle") val sinAngle = player.scoreboard("sin_angle") math.apply { launchAngle cosTo cosAngle launchAngle sinTo sinAngle } } ``` ## Square root An iterative Babylonian / Newton approximation (8 iterations by default): ```kotlin function("sqrt_demo") { math.sqrt(player, "input_val", "sqrt_result") } ``` The initial guess is clamped away from zero, which prevents the scoreboard division step from failing for inputs like `0` or `1`. Use `sqrt` when you need a real distance magnitude from squared values, or when another formula requires a root instead of a squared distance. ## Euclidean distance (squared) Computes `(x2−x1)² + (y2−y1)² + (z2−z1)²`: ```kotlin function("distance_demo") { math.distanceSquared(player, "x1", "y1", "z1", "x2", "y2", "z2", "dist_sq") } ``` Computing the squared distance is often enough for range checks and is cheaper to chain with threshold comparisons than an actual square root. You can also call the helper with scoreboard delegates directly: ```kotlin function("distance_delegate_demo") { val x1 = player.scoreboard("x1") val y1 = player.scoreboard("y1") val z1 = player.scoreboard("z1") val x2 = player.scoreboard("x2") val y2 = player.scoreboard("y2") val z2 = player.scoreboard("z2") val distSq = player.scoreboard("dist_sq") math.distanceSquared(Triple(x1, y1, z1), Triple(x2, y2, z2), distSq) } ``` ## Parabolic trajectory Computes `Y = v0 × t − (g × t²) / 2` for projectile simulation: ```kotlin function("parabola_demo") { math.parabola(player, "time", "#v0", "#gravity", "para_y") } ``` There is also a delegate-based overload when velocity, gravity, time, and output are all tracked as scoreboards. ## Example: projectile preview ```kotlin function("projectile_preview") { math.apply { sin(player, "launch_angle", "sin_angle") cos(player, "launch_angle", "cos_angle") parabola(player, "travel_time", "#launch_speed", "#gravity", "height_offset") } } ``` The helpers are intentionally small and composable: you can build a more complex simulation by combining multiple scoreboard operations rather than relying on one giant black-box function. ## Function reference | Function | Description | |------------------------------|----------------------------------------------| | `cos` | Cosine lookup (degrees → scaled result) | | `sin` | Sine lookup (degrees → scaled result) | | `sqrt` | Integer square root (Newton's method) | | `distanceSquared` | Squared 3D Euclidean distance | | `parabola` | Parabolic Y from time, velocity, and gravity | | `cosTo` / `sinTo` / `sqrtTo` | Delegate-based infix wrappers | ## See also - [State Delegates](/docs/helpers/state-delegates) - Write scoreboard-backed values with less boilerplate before feeding them into math helpers. - [Cooldowns](/docs/oop/cooldowns) - Pair time-based gameplay gates with scoreboard-driven calculations. - [Scoreboards](/docs/oop/scoreboards) - Higher-level scoreboard utilities that fit naturally around these formulas. --- ## State Delegates --- root: .components.layouts.MarkdownLayout title: State Delegates nav-title: State Delegates description: Kotlin property delegates that map scoreboard objectives or NBT storage to simple var properties with the Kore helpers module. keywords: minecraft, datapack, kore, helpers, state, delegate, scoreboard, storage, nbt, property date-created: 2026-03-03 date-modified: 2026-04-01 routeOverride: /docs/helpers/state-delegates --- # State Delegates Kotlin property delegates that map scoreboard objectives or [data storage](/docs/concepts/data-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: - `ScoreboardDelegate` for integer scoreboard-backed state. - `StorageDelegate` for NBT-backed storage paths. ## Scoreboard delegate ```kotlin function("mana_system") { var mana by player.scoreboard("mana_obj", default = 100) mana = 80 // emits: /scoreboard players set mana_obj 80 } ``` 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: ```kotlin function("mana_delta") { val manaObj = player.scoreboardEntity("mana_obj") manaObj += 10 manaObj -= 20 } ``` `scoreboardEntity(...)` returns a `ScoreboardEntity`, which exposes the same intent in command form: - `set(value)` for absolute updates. - `add(value)` and `remove(value)` for relative updates. - `plusAssign` / `minusAssign` as Kotlin operator sugar for those relative updates. ## Storage delegate ```kotlin function("storage_demo") { var customTag by player.storage("my_namespace:data", "customTag", default = "hello") customTag = "world" // emits: /data modify storage my_namespace:data customTag set value "world" } ``` `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: ```kotlin function("combat_state") { val player = entity() var combo by player.scoreboard("combo", default = 0) val comboScore = player.scoreboardEntity("combo") var phase by player.storage("my_namespace:state", "combat.phase", default = "idle") var shieldReady by player.storage("my_namespace:state", "combat.shield_ready", default = false) combo = 1 comboScore += 4 phase = "charged" shieldReady = true debug("Combat state updated") } ``` This emits concise vanilla commands while keeping your Kotlin code expressive: - `combo` stays easy to reuse with other scoreboard-based helpers such as cooldowns, timers, selectors, or math. - `phase` and `shieldReady` live 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. ```kotlin function("combo_ready") { val player = entity() val combo = player.scoreboard("combo", default = 0) var comboValue by combo comboValue = 45 runIf(combo equalTo 45) { say("Combo is exactly 45") } } ``` This still generates an `execute if score 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 ` for literal values, or `=` for another score | | `notEqualTo(...)` | `unless score ... matches ` style negation | | `greaterThan(...)` | `>` | | `greaterThanOrEqualTo(...)` | `>=` | | `lessThan(...)` | `<` | | `lessThanOrEqualTo(...)` | `<=` | ```kotlin function("combo_comparisons") { val player = entity() val combo = player.scoreboard("combo", default = 0) val threshold = player.scoreboard("threshold", default = 10) runIf(combo equalTo 10) { say("combo == 10") } runIf(combo notEqualTo 10) { say("combo != 10") } runIf(combo greaterThan 10) { say("combo > 10") } runIf(combo greaterThanOrEqualTo 10) { say("combo >= 10") } runIf(combo lessThan 10) { say("combo < 10") } runIf(combo lessThanOrEqualTo 10) { say("combo <= 10") } runIf(combo greaterThan threshold) { say("combo > threshold") } } ``` You can also compare two delegated scores directly: ```kotlin function("combo_threshold") { val player = entity() val combo = player.scoreboard("combo", default = 0) val threshold = player.scoreboard("threshold", default = 0) var comboValue by combo var thresholdValue by threshold comboValue = 45 thresholdValue = 45 runIf(combo equalTo threshold) { say("Combo reached the threshold") } } ``` That form emits `execute if score combo = 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: ```kotlin function("combo_loops") { val player = entity() val combo = player.scoreboard("combo", default = 0) var comboValue by combo comboValue = 3 runWhile(combo greaterThan 0, name = "combo_while") { say("Combo loop") combo.scoreboardEntity() -= 1 } comboValue = 9 repeat(combo, name = "combo_repeat") { i -> runIf(i equalTo 1) { say("Second iteration") } say("Repeat once per score point") } } ``` - `runIf(...)` wraps a single `execute if score ... run function ...` call. - `runWhile(...)` generates a recursive helper function that reruns itself while the score condition stays true. - `repeat(...)` is a small `for`-style helper built on top of `runWhile(...)`: 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 pass `counter = ...` to reuse an existing delegated score as the loop counter instead. - The lambda parameter (`it`) is itself a `ScoreboardDelegate` for the current iteration index, so you can compare it, pass it to `runIf(...)`, or even delegate it again with `var 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(...)`** and **`storage(...)`** 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` | Generic storage delegate implementation. | ## See also - [Scoreboard Math](/docs/helpers/scoreboard-math) - Feed delegated scoreboard values into trigonometric or algebraic helpers. - [Scheduler](/docs/helpers/scheduler) - Pair delegated state with delayed or repeating helper callbacks. - [Cooldowns](/docs/oop/cooldowns) - A concrete scoreboard-based gameplay system where delegated state can stay concise. - [Scoreboards](/docs/oop/scoreboards) - Broader patterns for organizing objectives and player state. --- ## Geometric Particle VFX Engine --- root: .components.layouts.MarkdownLayout title: Geometric Particle VFX Engine nav-title: VFX Particles description: "Generate geometric particle effects with Kore: circles, lines, spheres, spirals, and helixes. Pre-computed positions emitted as generated functions." keywords: minecraft, datapack, kore, helpers, vfx, particles, shape, circle, line, sphere, spiral, helix, geometry date-created: 2026-03-03 date-modified: 2026-03-31 routeOverride: /docs/helpers/vfx-particles --- # Geometric Particle VFX Engine The VFX engine generates [particle](https://minecraft.wiki/w/Commands/particle) commands for geometric shapes. Each shape is emitted as a generated function containing pre-computed positions. This is especially useful when you want repeatable visual effects without manually writing dozens of particle commands. You describe the geometry once and then call the generated function wherever you need it. ## Drawing shapes ```kotlin drawCircle("fire_ring", Particles.FLAME, radius = 5.0, points = 16) drawShape("soul_helix") { shape = Shape.HELIX particle = Particles.SOUL_FIRE_FLAME radius = 2.0 points = 40 height = 5.0 turns = 4 } ``` ## Choosing between helpers - Use `drawCircle(...)` when you only need a quick single-purpose helper. - Use `drawShape(...)` when you want one DSL entry point that can switch shape types or expose more parameters. Both approaches generate reusable functions, so you can keep expensive geometry decisions at generation time rather than recomputing them mentally for every particle command. ## Available shapes | Shape | Description | |----------|--------------------------------------------------| | `CIRCLE` | Flat circle on the XZ plane | | `LINE` | Straight line along a direction vector | | `SPHERE` | Fibonacci-distributed points on a sphere surface | | `SPIRAL` | Expanding spiral that rises along Y | | `HELIX` | Fixed-radius helix that rises along Y | ## VfxShape properties | Property | Default | Used by | |------------|---------|-------------------------------| | `particle` | - | All shapes | | `radius` | `1.0` | CIRCLE, SPHERE, SPIRAL, HELIX | | `points` | `20` | All shapes | | `height` | `3.0` | SPIRAL, HELIX | | `length` | `5.0` | LINE | | `dx/dy/dz` | `1,0,0` | LINE direction | | `turns` | `3` | SPIRAL, HELIX | ## Example: arena intro effect ```kotlin drawShape("arena_intro") { shape = Shape.SPIRAL particle = Particles.HAPPY_VILLAGER radius = 4.0 points = 60 height = 6.0 turns = 5 } ``` This kind of effect works well for spawn platforms, ritual circles, victory moments, or waypoint markers. --- # Oop ## OOP Utilities --- root: .components.layouts.MarkdownLayout title: OOP Utilities nav-title: OOP Utilities description: Overview of object-oriented gameplay utilities in the Kore OOP module - entities, teams, scoreboards, items, events, timers, spawners, and state machines. keywords: minecraft, datapack, kore, oop, entity, player, commands, teams, scoreboard, items, events, cooldown, bossbar, effects, timer, spawner, gamestate date-created: 2026-02-21 date-modified: 2026-03-31 routeOverride: /docs/oop/oop-utilities position: 0 --- # OOP Utilities The OOP module provides high-level, object-oriented wrappers around Minecraft systems such as entities, teams, scoreboards, timers, and gameplay state. Each feature is documented on its own page - see the links below. ## Install this module Add the `oop` artifact when you want object-oriented gameplay abstractions on top of the core Kore DSL. ```kotlin dependencies { implementation("io.github.ayfri.kore:oop:VERSION") } ``` Generated resource names for OOP-specific features are centralized in `OopConstants` so they're easy to find and override. Helper-specific generated names now live in `HelpersConstants` inside the `helpers` module. Utility-style features such as renderers, math helpers, raycasts, areas, state delegates, and VFX now live in the [`helpers` module](/docs/helpers/utilities). ## All Features - **[Boss Bars](/docs/oop/boss-bars)** - Register, configure, and manage boss bars. - **[Cooldowns](/docs/oop/cooldowns)** - Scoreboard-based cooldown system that decrements every [tick](/docs/concepts/time). - **[Entities & Players](/docs/oop/entities-and-players)** - Create entities and players, execute helpers, batch commands, entity commands, and entity effects. - **[Events](/docs/oop/events)** - Advancement-based event system for player and entity actions. - **[Game State Machine](/docs/oop/game-state-machine)** - Scoreboard-based state machine with transition helpers. - **[Items](/docs/oop/items)** - Object-oriented item creation and spawning. - **[Scoreboards](/docs/oop/scoreboards)** - Objective management and per-entity score operations. - **[Spawners](/docs/oop/spawners)** - Reusable entity spawner handles for summoning mobs. - **[Teams](/docs/oop/teams)** - Object-oriented team management with colors, collision rules, and nametag visibility. - **[Timers](/docs/oop/timers)** - Scoreboard-based timers with optional boss bar integration. ## Why use `oop` Choose the `oop` module when your datapack starts to revolve around reusable gameplay concepts rather than isolated commands. - **Entities and players** become named handles instead of repeated selectors. - **Systems such as timers, cooldowns, boss bars, and spawners** generate their own supporting commands and objectives. - **Your Kotlin code reads closer to gameplay intent**, which makes larger datapacks easier to maintain. You do not have to go "all in": the OOP layer is meant to sit on top of Kore, not replace it. ## Typical workflow Most OOP utilities follow a common structure: 1. **Register or declare** the gameplay object once (`team(...)`, `registerCooldown(...)`, `registerSpawner(...)`, etc.). 2. **Let Kore generate** the supporting commands, objectives, or load/tick handlers. 3. **Use the handle in functions** with concise methods such as `player.giveEffect(...)`, `cooldown.start(...)`, or `spawner.spawn()`. That workflow keeps setup centralized while leaving your gameplay functions focused on intent. ## Vanilla Kore vs OOP Kore The OOP module wraps the low-level command DSL into object-oriented abstractions. Here's a complete side-by-side comparison showing how the same mini-game setup looks with each approach. ### Vanilla Kore ```kotlin dataPack("arena") { val namespace = "arena" // --- Scoreboard objectives --- function("setup") { scoreboard.objectives.add("kills", "dummy", textComponent("Kills")) scoreboard.objectives.add("game_state", "dummy") scoreboard.objectives.add("cooldown_dash", "dummy") teams { team("red") { color = FormattingColor.RED collisionRule = CollisionRule.PUSH_OTHER_TEAMS } team("blue") { color = FormattingColor.BLUE collisionRule = CollisionRule.PUSH_OTHER_TEAMS } } } // --- Player setup (manual selectors) --- function("join_red") { val player = allPlayers { limit = 1 sort = Sort.NEAREST } teams.join("red", player) gamemode(Gamemode.SURVIVAL, player) effect(player) { give(Effects.SPEED, duration = 999999, amplifier = 1) } scoreboard.players.set(player, "kills", 0) scoreboard.players.set(player, "cooldown_dash", 0) } function("join_blue") { val player = allPlayers { limit = 1 sort = Sort.NEAREST } teams.join("blue", player) gamemode(Gamemode.SURVIVAL, player) effect(player) { give(Effects.SPEED, duration = 999999, amplifier = 1) } scoreboard.players.set(player, "kills", 0) scoreboard.players.set(player, "cooldown_dash", 0) } // --- State transitions (manual scoreboard) --- function("start_game") { scoreboard.players.set(literal("#game_state"), "game_state", 1) execute { asTarget(allPlayers()) run { title(self()) { title(textComponent("Game Started!") { color = Color.GREEN bold = true }) } } } } // --- Cooldown tick (manual decrement) --- function("tick_cooldowns") { execute { ifCondition { score(allPlayers(), "cooldown_dash", 1..Int.MAX_VALUE) } run { scoreboard.players.remove(allPlayers(), "cooldown_dash", 1) } } } // --- Spawning a mob (manual summon) --- function("spawn_guardian") { summon(EntityTypes.IRON_GOLEM, vec3(0, 64, 0)) } } ``` ### OOP Kore ```kotlin dataPack("arena") { // --- Players as objects --- val redPlayer = player("RedPlayer") val bluePlayer = player("BluePlayer") // --- Teams --- val redTeam = team("red") { color = FormattingColor.RED collisionRule = CollisionRule.PUSH_OTHER_TEAMS } val blueTeam = team("blue") { color = FormattingColor.BLUE collisionRule = CollisionRule.PUSH_OTHER_TEAMS } // --- Scoreboard --- val kills = scoreboard("kills") // --- Cooldown --- val dashCooldown = registerCooldown("dash", 3.seconds) // --- Game states --- val states = registerGameStates { state("lobby") state("running") state("finished") } // --- Spawner --- val guardian = registerSpawner("guardian", EntityTypes.IRON_GOLEM) { position = vec3(0, 64, 0) } // --- Player setup --- function("join_red") { redPlayer.joinTeam("red") redPlayer.setGamemode(Gamemode.SURVIVAL) redPlayer.giveEffect(Effects.SPEED, duration = 999999, amplifier = 1) kills.set(redPlayer, 0) } function("join_blue") { bluePlayer.joinTeam("blue") bluePlayer.setGamemode(Gamemode.SURVIVAL) bluePlayer.giveEffect(Effects.SPEED, duration = 999999, amplifier = 1) kills.set(bluePlayer, 0) } // --- State transition --- function("start_game") { states.transitionTo("running") redPlayer.title(textComponent("Game Started!") { color = Color.GREEN bold = true }) bluePlayer.title(textComponent("Game Started!") { color = Color.GREEN bold = true }) } // --- Spawning --- function("spawn_guardian") { guardian.spawn() } } ``` ### Key Differences | Aspect | Vanilla Kore | OOP Kore | |-----------------------|---------------------------------------------------------------------------------|------------------------------------------------------------------------------| | **Entity references** | Manual selectors (`allPlayers { ... }`) repeated everywhere | Named objects (`player("RedPlayer")`) reused across functions | | **Commands** | Low-level calls like `scoreboard.players.set(...)`, `effect(...) { give(...) }` | Method calls on entities: `player.giveEffect(...)`, `player.joinTeam(...)` | | **Game state** | Manual scoreboard objectives and raw `set` calls | `registerGameStates { state("running") }` + `states.transitionTo("running")` | | **Cooldowns** | Manual scoreboard decrement loops | `registerCooldown("dash", 3.seconds)` - tick function auto-generated | | **Spawning** | Raw `summon(EntityTypes.X, pos)` | `registerSpawner(...)` + `spawner.spawn()` | | **Boilerplate** | Selector construction, objective registration, execute blocks | Handled internally by the OOP abstractions | The OOP module doesn't replace vanilla Kore - it builds on top of it. You can freely mix both styles, using OOP utilities where they simplify your code and dropping to vanilla commands when you need fine-grained control. --- ## Boss Bars --- root: .components.layouts.MarkdownLayout title: Boss Bars nav-title: Boss Bars description: Object-oriented boss bar management with the Kore OOP module - register, configure, show, hide, and update boss bars. keywords: minecraft, datapack, kore, oop, bossbar, boss bar, color, style, notched, team, handle, config date-created: 2026-03-03 date-modified: 2026-04-01 routeOverride: /docs/oop/boss-bars --- # Boss Bars The OOP module wraps [Minecraft boss bars](https://minecraft.wiki/w/Commands/bossbar) into a simple config + handle pattern. This is useful when you want one place to configure a bar and then reuse it across multiple gameplay functions. `BossBarConfig` stores the initial registration settings, while `BossBarHandle` exposes the runtime commands you call from functions. ## Registering a boss bar ```kotlin val bar = registerBossBar("my_bar", name) { color = BossBarColor.RED max = 200 style = BossBarStyle.NOTCHED_10 value = 50 } ``` A load function is generated that creates the bar and applies all initial settings. ## Typical workflow ```kotlin function("show_phase_bar") { bar.apply { setPlayers(player) setValue(150) show() } } function("hide_phase_bar") { bar.hide() } ``` In practice, boss bars often pair well with timers, boss fights, or round-based activities where the bar is configured once and then updated from several different functions. ## Manipulating a boss bar ```kotlin function("boss_fight") { bar.apply { setValue(100) setColor(BossBarColor.BLUE) setPlayers(player) show() hide() remove() } } ``` You can also target all members of a team: ```kotlin bar.apply { setPlayers(team) setStyle(BossBarStyle.NOTCHED_12) } ``` ## Configuration vs handle methods `BossBarConfig` controls the values that are written when the bar is registered: - `color` - `displayName` - `max` - `style` - `value` - `visible` `BossBarHandle` exposes the runtime methods listed below. ## Function reference | Function | Description | |----------------------|--------------------------------------------------| | `hide` | Hide the bar without deleting its configuration | | `remove` | Remove the boss bar entirely | | `setColor` | Change the boss bar color | | `setMax` | Update the maximum value used to render progress | | `setName` | Change the displayed boss bar name | | `setPlayers(entity)` | Control which players currently see the bar | | `setPlayers(team)` | Show the bar to every member of a team | | `setStyle` | Change the boss bar rendering style | | `setValue` | Update the current boss bar value | | `show` | Make the bar visible to the assigned players | --- ## Cooldowns --- root: .components.layouts.MarkdownLayout title: Cooldowns nav-title: Cooldowns description: Scoreboard-based cooldown system with the Kore OOP module - register, start, check, and reset cooldowns. keywords: minecraft, datapack, kore, oop, cooldown, scoreboard, timer, tick date-created: 2026-03-03 date-modified: 2026-03-31 routeOverride: /docs/oop/cooldowns --- # Cooldowns Cooldowns use a [scoreboard objective](https://minecraft.wiki/w/Scoreboard) that decrements every [tick](/docs/concepts/time). When the score reaches 0 the cooldown is ready. Durations are expressed as [`TimeNumber`](/docs/concepts/time) values - `2.seconds`, `40.ticks`, etc. They are a good fit for abilities, interactions, item usage limits, or any mechanic that should be reusable for several players without hand-writing the decrement logic every time. ## Registering a cooldown ```kotlin val cd = registerCooldown("attack_cd", 2.seconds) ``` This generates: - A **load function** that creates the scoreboard objective. - A **tick function** that decrements the score for all players with score ≥ 1. ## Typical usage pattern ```kotlin function("dash_skill") { with(cd) { ifReady(player) { say("Dash!") } } } function("dash_hit") { cd.start(player) } ``` This split keeps the "can I use it?" check separate from the event or action that actually starts the cooldown. ## Using a cooldown ```kotlin function("combat") { with(cd) { start(player) // sets the score to the duration ifReady(player) { // runs only when score == 0, then restarts say("Attack ready!") } reset(player) // forces score to 0 } } ``` ## Function reference | Function | Description | |-----------|----------------------------------------------------------------| | `start` | Set the player score to the configured duration | | `ifReady` | Run a block only when the cooldown is ready | | `reset` | Force the cooldown back to `0` | | tick hook | Auto-generated function that decrements active cooldown scores | ## See also - [Timers](/docs/oop/timers) - Use timers when you need scheduled callbacks rather than per-player readiness checks. - [Events](/docs/oop/events) - Start or reset cooldowns from gameplay triggers such as clicks, kills, or item use. - [State Delegates](/docs/helpers/state-delegates) - Reduce scoreboard boilerplate in adjacent stateful systems. --- ## Entities & Players --- root: .components.layouts.MarkdownLayout title: Entities & Players nav-title: Entities & Players description: Create and manage entities and players with the Kore OOP module - selectors, execute helpers, batch commands, entity commands, and entity effects. keywords: minecraft, datapack, kore, oop, entity, player, commands, execute, batch, effects, teleport, kill, damage date-created: 2026-03-03 date-modified: 2026-06-16 routeOverride: /docs/oop/entities-and-players --- # Entities & Players The OOP module models Minecraft entities and players as Kotlin objects with selectors and context-aware extension functions. ## Creating entities ```kotlin val player = player("Steve") { gamemode = Gamemode.SURVIVAL team = "red" } val arenaMobs = entity("ArenaMob", limitToOne = false) { tag = "arena" } val zombie = entity { type = EntityTypes.ZOMBIE } ``` `player()` creates a `Player` instance (subclass of `Entity`) with `type = minecraft:player`, `limit = 1`, and the given name. `entity()` creates a generic `Entity` with custom selector arguments, and can also start from a named entity selector when you already know the exact entity name to target. Use `player(...)` when you want a selector already scoped to players, and `entity { ... }` when you need a reusable selector for mobs, armor stands, projectiles, or a more generic execute target. Use `entity("Name", ...)` when you want the same convenience as `player("Name")` without forcing the selector to `minecraft:player`. ### Creating entities from an EntityType You can also construct an `Entity` handle directly from an `EntityTypes` value using `toEntity()` or the typed overload of `entity()`: ```kotlin // Extension on EntityTypeArgument - the type is set automatically val creeper = EntityTypes.CREEPER.toEntity() val skeletons = EntityTypes.SKELETON.toEntity(limitToOne = false) { team = "arena" } // Named factory overload - equivalent, mirrors entity("Name", ...) style val spider = entity(EntityTypes.SPIDER) val endermen = entity(EntityTypes.ENDERMAN, limitToOne = false) { tag = "target" } ``` Both forms set `selector.type` automatically so you never need to write `type = EntityTypes.X` by hand. Use `toEntity()` when calling from an `EntityTypeArgument` receiver; use `entity(type, ...)` when you want a form that reads like the other `entity(...)` overloads. ## Execute helpers Entity-scoped execute shortcuts emit `/execute as`, `/execute at`, or both: ```kotlin function("teleport_self") { player.executeAs { run { it.teleportTo(it) } } player.executeAt { run { it.giveItem(Items.DIAMOND) } } player.executeAsAt { run { it.sendMessage("Hello from my location!") } } } ``` These helpers are especially valuable when you would otherwise repeat the same `execute as`, `execute at`, or `execute as ... at ...` boilerplate around several commands. ## Batch `batch()` creates a named sub-function that groups multiple commands under a single entity context: ```kotlin function("setup") { player.batch("init_player") { giveItem(Items.DIAMOND) giveEffect(Effects.SPEED, duration = 200) sendMessage("Welcome!") } } ``` `batch()` is a good fit for onboarding flows, class kits, respawn setup, or any repeated multi-command routine that should stay grouped under one entity context. ## Entity Commands Extension functions on `Entity` for common [Minecraft commands](https://minecraft.wiki/w/Commands): ```kotlin function("commands_demo") { player.kill() player.damage(5f) player.addTag("vip") player.removeTag("vip") player.giveXp(10.levels) player.setXp(0.points) player.setGamemode(Gamemode.CREATIVE) player.sendMessage("Hello!") player.showTitle(textComponent("Title"), textComponent("Subtitle")) player.showActionBar(textComponent("Action bar text")) player.playSound(Sounds.ENTITY_EXPERIENCE_ORB_PICKUP) player.mount(zombie) player.dismount() player.clearItems() player.giveItem(Items.DIAMOND) player.replaceItem(ItemSlotType.MAINHAND, itemStack(Items.NETHERITE_SWORD)) } ``` | Function | Description | |-----------------|-------------------------------------------| | `addTag` | Add a scoreboard tag | | `clearItems` | Clear inventory (optionally filtered) | | `damage` | Deal damage with optional damage type | | `dismount` | Dismount from current vehicle | | `giveItem` | Give an item stack | | `giveXp` | Add experience (levels or points) | | `kill` | Kill the entity | | `mount` | Mount another entity | | `playSound` | Play a sound at the entity | | `removeTag` | Remove a scoreboard tag | | `replaceItem` | Replace an item in a specific slot | | `sendMessage` | Send a tellraw message | | `setGamemode` | Change the player's gamemode | | `setXp` | Set experience to an exact value | | `showActionBar` | Display text on the action bar | | `showTitle` | Display a title and optional subtitle | | `teleportTo` | Teleport to coordinates or another entity | | `swing` | Swing the left or right hand | ## Practical pattern ```kotlin function("round_start") { player.batch("round_start_player") { giveItem(Items.DIAMOND) giveEffect(Effects.SPEED, duration = 200) showActionBar(textComponent("Fight!")) } } ``` This combines one reusable player selector with several entity-scoped actions, which is the core value of the OOP entity API. ## Entity Effects Extension functions on `Entity` for giving, clearing, and managing [mob effects](https://minecraft.wiki/w/Effect): ```kotlin function("buff_player") { player.giveEffect(Effects.SPEED, duration = 200, amplifier = 1) player.giveInfiniteEffect(Effects.NIGHT_VISION, hideParticles = true) player.clearEffect(Effects.SPEED) player.clearAllEffects() } ``` | Function | Description | |----------------------|---------------------------------------| | `giveEffect` | Give a timed effect with optional amp | | `giveInfiniteEffect` | Give an infinite-duration effect | | `clearEffect` | Remove a specific effect | | `clearAllEffects` | Remove all effects | | `effects { ... }` | Builder block for multiple operations | ## See also - [Items](/docs/oop/items) - Reuse item stacks with `giveItem`, `replaceItem`, or summon-based reward flows. - [Events](/docs/oop/events) - Attach gameplay reactions directly to the entity and player handles you define here. - [Spawners](/docs/oop/spawners) - Pair selectors and entity utilities with reusable spawning entry points. --- ## Events --- root: .components.layouts.MarkdownLayout title: Events nav-title: Events description: Advancement-based event system for player and entity actions with the Kore OOP module. keywords: minecraft, datapack, kore, oop, events, advancement, player, entity, death, click, consume, kill, recipe, dimension, riding, tame, bed, target, fishing, crossbow, totem, tick, bucket, potion date-created: 2026-03-03 date-modified: 2026-06-23 routeOverride: /docs/oop/events --- # Events Events use [advancements](https://minecraft.wiki/w/Advancement/JSON_format) to detect player/entity actions and dispatch them to [function tags](https://minecraft.wiki/w/Tag#Function_tags). Multiple handlers can be registered for the same event - they all fire together. This makes events a convenient bridge between vanilla triggers and OOP-style gameplay code: you register interest once, then let the generated dispatchers call your handlers when Minecraft reports the action. ## Registering events Event helpers only need a `DataPack` in scope, so you can register them straight in the `datapack { }` block, without wrapping them in a `function { }`: ```kotlin datapack("my_pack") { val player = player("Steve") player.onKill { say("Kill!") } } ``` Registering them inside a `function { }` still works (the surrounding datapack is in scope there too), which is handy when you want to mix event registration with other commands. ### Handler receives the entity Each handler is invoked with the entity/player handle it was registered on, so you can keep chaining the OOP API without re-declaring the handle: ```kotlin datapack("my_pack") { val player = player("Steve") player.onKill { self -> self.setScore("kills", 1) say("Kill counted!") } } ``` > Minecraft runs reward functions **as** the player, so the handle you get back is always the player/entity the event > was registered on. The other entity involved (the mob you killed, the attacker, etc.) is not exposed by the game and > cannot be passed in. ## Player events ```kotlin val player = player("Steve") player.onBlockUse { say("Interacted with a block!") } player.onConsumeItem(Items.GOLDEN_APPLE) { say("Golden apple!") } player.onFishingRodHooked { say("Got a bite!") } player.onRecipeCrafted(Recipes.CRAFTING_TABLE) { say("Crafted a recipe!") } player.onRightClick(Items.STICK) { say("Right click with stick!") } player.onUsedTotem { say("Cheated death!") } ``` Available player events (alphabetical): | Function | Trigger | |------------------------|---------------------------------------| | `onBlockUse` | Right-click any block | | `onBredAnimals` | Breed two animals | | `onBrewedPotion` | Take a potion out of a brewing stand | | `onChangeDimension` | Change dimension | | `onConsumeItem` | Consume any item (food, potion, etc.) | | `onConsumeItem(item)` | Consume a specific item | | `onEffectsChanged` | Effects on the player change | | `onEnchantItem` | Enchant an item | | `onEntityHurtPlayer` | A player is hurt by an entity | | `onFallFromHeight` | Fall from a height | | `onFilledBucket` | Fill a bucket | | `onFishingRodHooked` | Hook something with a fishing rod | | `onHurtEntity` | Deal damage to an entity | | `onInteractWithEntity` | Right-click an entity | | `onInventoryChange` | Inventory contents change | | `onItemUsedOnBlock` | Use an item on a block | | `onKill` | Kill an entity | | `onKilledByArrow` | Get killed by an arrow | | `onPlaceBlock` | Place a block | | `onRecipeCrafted` | Craft a recipe | | `onRightClick(item)` | Right-click while holding an item | | `onShotCrossbow` | Shoot a crossbow | | `onSleptInBed` | Sleep in a bed | | `onStartRiding` | Start riding an entity | | `onTameAnimal` | Tame an animal | | `onTargetHit` | Hit a target block | | `onTick` | Every tick (per player) | | `onUsedEnderEye` | Use an eye of ender | | `onUsedTotem` | Trigger a totem of undying | ## Typical workflow 1. Declare the entity or player handle that should receive the event helpers. 2. Register one or more event handlers, either directly in the datapack or inside a function. 3. Keep the handler bodies focused on gameplay reactions such as score updates, messaging, or spawning. This pattern works well for mini-games where multiple systems need to react to the same player action. ## Entity events ```kotlin val zombie = entity(EntityTypes.ZOMBIE) { tag = "my_tag" } zombie.onDeath { self -> say("A ${self.type?.name} died!") } ``` The death event uses a loot-table trigger: on death the entity drops a hidden item detected by a tick dispatcher that runs all death handlers then removes the item. ## See also - [World Events](/docs/oop/world-events) - The world-side counterpart: tick, weather, day/night, and interval triggers. - [Cooldowns](/docs/oop/cooldowns) - Gate event-driven abilities or interactions so players cannot spam them. - [Entities & Players](/docs/oop/entities-and-players) - Build the selectors and entity handles that receive these event helpers. - [Items](/docs/oop/items) - React to item usage or rewards with reusable item stacks. --- ## Game State Machine --- root: .components.layouts.MarkdownLayout title: Game State Machine nav-title: Game State Machine description: Scoreboard-based game state machine with the Kore OOP module - register states, transition between them, and react to state changes. keywords: minecraft, datapack, kore, oop, game state, state machine, scoreboard, transition, lobby date-created: 2026-03-03 date-modified: 2026-03-31 routeOverride: /docs/oop/game-state-machine --- # Game State Machine The game state system uses a [scoreboard](https://minecraft.wiki/w/Scoreboard) to track the current state and dispatches handlers when the state matches. It is a good fit for lobbies, round systems, multi-phase boss fights, tutorials, or any flow that repeatedly switches between a known set of named states. ## Registering states ```kotlin val states = registerGameStates { state("lobby") state("playing") state("ended") } ``` This generates a **load function** that creates the `kore_state` objective and sets the initial state. ## Typical lifecycle ```kotlin function("prepare_game") { states.transitionTo("lobby") } function("start_game") { states.transitionTo("playing") } function("finish_game") { states.transitionTo("ended") } ``` Keeping transitions explicit like this makes it easier to reason about which setup code belongs to each phase. ## Transitioning and reacting ```kotlin function("game_loop") { states.transitionTo("playing") states.whenState("playing") { say("The game is in progress!") } states.whenState("ended") { say("Game over!") } } ``` ## Game state actions Helper functions integrate states with other OOP systems: ```kotlin // Transition to a state only when a cooldown is ready states.transitionWithCooldown("playing", cooldown, player) // Spawn entities when entering a state states.whenStateSpawn("playing", zombieSpawner, count = 3) // Start a timer when entering a state states.whenStateStartTimer("playing", timer, player) ``` ## Best practices - Keep the state list small and meaningful (`lobby`, `playing`, `ended`, etc.). - Reserve `whenState(...)` for behavior that should only run in one phase. - Use the integration helpers when a state change should also start a timer, consume a cooldown, or trigger a spawn. --- ## Items --- root: .components.layouts.MarkdownLayout title: Items nav-title: Items description: Object-oriented item creation and spawning with the Kore OOP module. keywords: minecraft, datapack, kore, oop, items, item stack, summon, give date-created: 2026-03-03 date-modified: 2026-03-31 routeOverride: /docs/oop/items --- # Items The OOP module keeps item usage concise by letting you build an [item stack](https://minecraft.wiki/w/Item) once and then reuse it for giving, spawning, or embedding it in wider entity workflows. ## Basic usage ```kotlin function("item_demo") { val sword = itemStack(Items.DIAMOND_SWORD) { enchantments { sharpness(5) unbreaking(3) } } player.giveItem(sword) sword.summon() // summon as item entity at 0 0 0 sword.summon(textComponent("My Sword", Color.GOLD)) // summon with custom name } ``` ## Practical example ```kotlin function("reward_drop") { val reward = itemStack(Items.NETHERITE_INGOT) { lore(textComponent("A rare reward dropped by the champion", Color.GRAY)) } player.executeAt { run { reward.summon(textComponent("Champion Reward", Color.GOLD)) } } } ``` This pattern is useful when the same item should be given directly in one context and spawned as a visible reward in another. ## See also - [Entities & Players](/docs/oop/entities-and-players) - Give, replace, or spawn item stacks from entity-scoped helpers. - [Events](/docs/oop/events) - React to item use or consumption with event-driven logic. - [Components](/docs/concepts/components) - Define richer custom names, lore, and metadata for the items you build. --- ## Scoreboards --- root: .components.layouts.MarkdownLayout title: Scoreboards nav-title: Scoreboards description: Object-oriented scoreboard management with the Kore OOP module - objectives, display slots, and per-entity score operations. keywords: minecraft, datapack, kore, oop, scoreboard, objective, score, display slot date-created: 2026-03-03 date-modified: 2026-03-31 routeOverride: /docs/oop/scoreboards --- # Scoreboards Wraps [Minecraft scoreboards](https://minecraft.wiki/w/Scoreboard) with objective management and per-entity score operations. This split between objective handles and per-entity score handles maps well to how vanilla scoreboards already work, but with a more readable API. ## Objectives ```kotlin function("scoreboard_setup") { scoreboard("kills") { create() setDisplaySlot(DisplaySlots.sidebar) setDisplayName("Kill Count") } } ``` | Function | Description | |------------------|-----------------------| | `create` | Create the objective | | `remove` | Remove the objective | | `setDisplaySlot` | Assign a display slot | | `setDisplayName` | Set the display name | | `setRenderType` | Set the render type | ## Practical pattern ```kotlin function("match_setup") { val kills = scoreboard("kills") kills.create() kills.setDisplaySlot(DisplaySlots.sidebar) val playerKills = player.getScoreEntity("kills") playerKills.set(0) } ``` The usual pattern is to configure the objective once, then retrieve entity-specific score handles wherever gameplay code needs to increment, reset, or copy values. ## Per-entity scores ```kotlin function("score_ops") { val score = player.getScoreEntity("kills") score.set(10) score.add(5) score.remove(2) score.reset() score.copyFrom(player.asSelector(), "deaths") } ``` | Function | Description | |------------|---------------------------------------------| | `set` | Set score to a value | | `add` | Add to the score | | `remove` | Subtract from the score | | `reset` | Reset the score | | `copyTo` | Copy this score to another holder/objective | | `copyFrom` | Copy from another holder/objective | --- ## Spawners --- root: .components.layouts.MarkdownLayout title: Spawners nav-title: Spawners description: Reusable entity spawner handles with the Kore OOP module - register, spawn, and batch-summon entities. keywords: minecraft, datapack, kore, oop, spawner, summon, entity, mob, wave date-created: 2026-03-03 date-modified: 2026-03-31 routeOverride: /docs/oop/spawners --- # Spawners Spawners wrap [entity summoning](https://minecraft.wiki/w/Commands/summon) into reusable, pre-configured handles. They are useful whenever the same mob or entity should be spawned multiple times with the same base configuration. ## Registering a spawner ```kotlin val zombieSpawner = registerSpawner("zombie", EntityTypes.ZOMBIE) { position = vec3(0, 64, 0) } ``` Registering a spawner once helps keep coordinates, entity type, and spawn behavior in one predictable place. ## Using a spawner ```kotlin function("spawn_wave") { with(zombieSpawner) { spawn() // summon at configured position spawnAt(vec3(10, 64, 10)) // summon at a specific position spawnMultiple(5) // summon multiple at configured position } } ``` | Function | Description | |-----------------|-------------------------------------| | `spawn` | Summon at the configured position | | `spawnAt` | Summon at a specific position | | `spawnMultiple` | Summon N entities at configured pos | ## Example: spawning a wave ```kotlin function("spawn_wave") { with(zombieSpawner) { spawnMultiple(5) spawnAt(vec3(12, 64, 12)) } } ``` This makes spawners a natural fit for waves, encounter scripts, arena refills, or scripted boss phases. ## See also - [Entities & Players](/docs/oop/entities-and-players) - Operate on the spawned entities afterwards with higher-level helpers. - [Teams](/docs/oop/teams) - Assign spawned waves to teams when organizing PvE or faction-based encounters. - [Events](/docs/oop/events) - React to deaths or interactions involving spawned entities. --- ## Teams --- root: .components.layouts.MarkdownLayout title: Teams nav-title: Teams description: Object-oriented team management with the Kore OOP module - create, configure, and manage Minecraft teams. keywords: minecraft, datapack, kore, oop, teams, scoreboard, collision, nametag, friendly fire date-created: 2026-03-03 date-modified: 2026-03-31 routeOverride: /docs/oop/teams --- # Teams Wraps [Minecraft teams](https://minecraft.wiki/w/Scoreboard#Teams) into an object-oriented API: ```kotlin function("team_setup") { val red = team("red") { ensureExists() setColor(Color.DARK_RED) setPrefix(textComponent { text = "RED "; color = Color.DARK_RED; bold = true }) setFriendlyFire(false) setCollisionRule(CollisionRule.NEVER) setNametagVisibility(Visibility.HIDE_FOR_OTHER_TEAMS) addMembers(player) } player.joinTeam(red) player.leaveAnyTeam() } ``` The main benefit is that configuration stays grouped by team, which makes lobby setup, role assignment, and PvP rules much easier to read than a long list of raw `team modify` commands. Teams can also act as a bridge to other OOP features. Once you have a `Team` handle, you can reuse its members as an entity selector for [Scoreboards](/docs/oop/scoreboards), [Boss Bars](/docs/oop/boss-bars), or any API that already works with `Entity`. They also integrate nicely with `execute` conditions and score tracking helpers, which makes it easy to express checks like "does this team still have this player?" or "how many players are still alive in this team?" without rebuilding selectors by hand. ## Reusing a team in other OOP features ```kotlin val red = team("red") val phaseBar = registerBossBar("phase", name) val points = scoreboard("phase.points") function("sync_red_team") { phaseBar.setPlayers(red) points.getScore(red).set(10) red.clearMembers() } ``` This keeps team-centric logic in one place: the same `Team` wrapper can drive visibility, score updates, and member management without rebuilding selectors manually. ## Conditions and counters ```kotlin val red = team("red") val tracker = player("Tracker") val membersLeft = tracker.getScoreEntity("red.members") function("check_red_team") { execute { ifCondition { hasMembers(red) hasPlayer(red, "Ayfri") hasScore(red, "round.points", rangeOrInt(3)) } run { say("Red team is still in the round") } } membersLeft.copyMemberCountFrom(red) membersLeft.copyTo(storage("match", namespace = name), "state.red_members") } ``` This pattern is useful when several OOP systems need to exchange state. A `Team` can expose conditions for `execute`, while a `ScoreboardEntity` can cache the current member count or mirror that count into entity/storage NBT for later reuse by timers, [Events](/docs/oop/events), or custom game rules. ## Team functions | Function | Description | |-----------------------------|-----------------------------------------------------| | `ensureExists` | Create the team if it doesn't exist | | `delete` | Delete the team | | `setDisplayName` | Set the team display name | | `setPrefix` / `setSuffix` | Set name prefix/suffix | | `setColor` | Set team color | | `setFriendlyFire` | Toggle friendly fire | | `setSeeFriendlyInvisibles` | Toggle seeing invisible teammates | | `setCollisionRule` | Set collision rule | | `setNametagVisibility` | Set nametag visibility | | `setDeathMessageVisibility` | Set death message visibility | | `addMembers` | Add entities to the team | | `hasMembers` | Check if the team still has at least one member | | `hasPlayer` / `hasMember` | Check if a specific player or entity is in the team | | `hasScore` | Check a score range directly on the team selector | | `members` | Reuse the team as an `Entity` selector | | `clearMembers` | Remove every current team member | ## Practical workflow - Define the team once with its visual identity and gameplay rules. - Add members when players join a role or side. - Reuse `members()` or higher-level helpers like `bossBar.setPlayers(team)` and `scoreboard.getScore(team)` when other features need to target that whole team. - Reuse `player.joinTeam(...)` and `player.leaveAnyTeam()` in gameplay functions instead of raw selectors. ## See also - [Entities & Players](/docs/oop/entities-and-players) - Build the player and entity handles that join, leave, or target teams. --- ## Minecraft Timer Datapack - Scoreboard Timers in Kore OOP --- root: .components.layouts.MarkdownLayout title: Minecraft Timer Datapack - Scoreboard Timers in Kore OOP nav-title: Timers description: Scoreboard-based timers with Kore's OOP module. Countdown timers, boss bar timers, tick-based schedules, and reusable handles. Build cooldowns and game timers without raw command blocks. keywords: timer datapack, minecraft timer, datapack timer, scoreboard timer, countdown timer, minecraft cooldown, boss bar timer, tick timer, kore timer, datapack schedule date-created: 2026-03-03 date-modified: 2026-07-02 routeOverride: /docs/oop/timers --- # Timers Timers use a [scoreboard objective](https://minecraft.wiki/w/Scoreboard) that increments every [tick](/docs/concepts/time). When the score reaches the configured duration, completion handlers fire. This is a strong fit for round timers, capture phases, delayed rewards, warmups, or any mechanic that should complete after a predictable amount of [ticks](/docs/concepts/time). Durations are expressed as [ `TimeNumber`](/docs/concepts/time) values - `5.seconds`, `200.ticks`, etc. ## Registering a timer ```kotlin val timer = registerTimer("round_timer", 5.seconds) ``` This generates: - A **load function** that creates the scoreboard objective. - A **tick function** that increments the score for all players with score ≥ 0. ## Typical lifecycle ```kotlin function("round_start") { timer.start(player) } function("round_cancel") { timer.stop(player) } ``` Using dedicated start and stop points keeps it clear which gameplay events begin or cancel the countdown. ## Using a timer ```kotlin function("round") { with(timer) { start(player) onComplete(player) { say("Time's up!") } stop(player) } } ``` | Function | Description | |--------------|--------------------------------------------------------| | `start` | Set the score to 0, beginning the countdown | | `stop` | Set the score to −1, halting the timer | | `onComplete` | Register a handler that fires when duration is reached | ## Timer with Boss Bar Combines a timer with an auto-managed boss bar: ```kotlin val timedBar = registerTimerWithBossBar("boss_timer", 10.seconds) { color = BossBarColor.GREEN style = BossBarStyle.NOTCHED_20 } function("boss_round") { with(timedBar) { start(player) onComplete(player) { say("Boss round over!") } stop(player) } } ``` The boss-bar variant is useful when you want a countdown that is both mechanical and visible to players without having to manually synchronize a separate UI layer. --- ## World Events - Tick, Weather & Day/Night Event System in Kore --- root: .components.layouts.MarkdownLayout title: World Events - Tick, Weather & Day/Night Event System in Kore nav-title: World Events description: React to world-level events in Minecraft with Kore's OOP module. Tick events, weather changes (rain/thunder), day/night cycle triggers (noon/midnight), and configurable interval timers. keywords: minecraft world events, datapack tick event, minecraft weather event, day night cycle datapack, kore world events, datapack interval timer, rain thunder event minecraft, world load event, datapack time of day date-created: 2026-06-23 date-modified: 2026-06-23 routeOverride: /docs/oop/world-events --- # World Events World events are the world-side counterpart of the [entity/player events](/docs/oop/events): instead of reacting to an entity action, they react to the world itself ticking, the weather changing, the day/night cycle, or a fixed interval elapsing. Everything stays **100% datapack-side** - no in-world command blocks. Dynamic data is read with predicates and scoreboards, and where a value has to be read at runtime you should reach for [macros](/docs/commands/macros) rather than command blocks. Like entity events, multiple handlers can be registered for the same event and they all fire together. Each event is backed by a function registered in the vanilla `tick`/`load` tag that dispatches to a per-event [function tag](https://minecraft.wiki/w/Tag#Function_tags). ## The world handle Register events on a `world()` handle. Pass a dimension to scope a handler so it runs with the execution context set to that dimension (`execute in run ...`): ```kotlin datapack("my_pack") { val world = world() val nether = world(Dimensions.THE_NETHER) world.onTick { say("Runs every tick, globally.") } nether.onTick { say("Runs every tick, executed in the Nether.") } } ``` World event helpers only need a `DataPack` in scope, so you can register them straight in the `datapack { }` block, or inside a `function { }` when you want to mix them with other commands. ## Available events | Function | Trigger | |----------------------|-----------------------------------------------------------------------| | `onDayStart` | The tick `daytime` enters `0..11999` (dawn) | | `onInterval(period)` | Every `period` ticks (scoreboard counter, immune to a frozen daytime) | | `onLoad` | Once on datapack load / `/reload` | | `onMidnight` | The tick `daytime` reaches `18000` | | `onNightStart` | The tick `daytime` enters `13000..23999` | | `onNoon` | The tick `daytime` reaches `6000` | | `onRainStart` | The tick precipitation starts (rain or thunder) | | `onRainStop` | The tick precipitation stops | | `onThunderStart` | The tick a thunderstorm starts | | `onThunderStop` | The tick a thunderstorm stops | | `onTick` | Every tick (20 times per second) | | `onTimeOfDay(time)` | The tick `daytime` reaches `time` (`0..23999`) | ```kotlin datapack("my_pack") { val world = world() world.onLoad { say("Pack loaded!") } world.onInterval(5.seconds) { say("Tick every 5 seconds.") } world.onRainStart { say("It started raining!") } world.onThunderStop { say("The storm passed.") } world.onDayStart { say("Good morning!") } world.onNoon { say("High noon.") } world.onNightStart { say("Watch out for mobs!") } world.onTimeOfDay(23000) { say("Sunrise is near.") } } ``` ## How edge events work `onRainStart`, `onThunderStart`, `onDayStart` and friends are **edge-triggered**: they fire only on the single tick the condition flips, not every tick the condition is true. The dispatcher stores the current state into a `kore_world` scoreboard, compares it to the previous tick, runs the handlers on a transition, then saves the new state: ```mcfunction # dispatch_on_rain_start execute store result score #on_rain_start.now kore_world if predicate {condition:"minecraft:weather_check",raining:1b} execute if score #on_rain_start.now kore_world matches 1 if score #on_rain_start.prev kore_world matches 0 run function #my_pack:on_rain_start scoreboard players operation #on_rain_start.prev kore_world = #on_rain_start.now kore_world ``` Because the previous state is unset on the first tick after a reload, edge events never fire spuriously on load. `onInterval` instead keeps a counter on the same objective, so it stays accurate even when `doDaylightCycle` is off: ```mcfunction # dispatch_on_interval scoreboard players add #on_interval.counter kore_world 1 execute if score #on_interval.counter kore_world matches 100.. run function #my_pack:on_interval execute if score #on_interval.counter kore_world matches 100.. run scoreboard players set #on_interval.counter kore_world 0 ``` ## Notes - `onRainStart`/`onRainStop` track precipitation in general (a thunderstorm also counts as raining). Use the thunder events when you specifically care about storms. - Weather and time are global in vanilla; binding an event to a dimension changes **where the handler runs**, not which world's weather is read. - The shared `kore_world` objective is created once per datapack in the generated `kore_world_init` load function. - `onNoon` and `onMidnight` are thin wrappers over `onTimeOfDay`. Use `onTimeOfDay` directly for sunset (`12000`), sunrise (`23000`), or any custom moment. Moon-phase logic can be layered on top: react in `onNightStart`, then read the game time with a macro to compute `(day % 8)`. ## See also - [Events](/docs/oop/events) - the entity/player event system this mirrors. - [Timers](/docs/oop/timers) - count up to a duration per entity, with an optional boss bar. - [Cooldowns](/docs/oop/cooldowns) - gate abilities so they cannot be spammed. --- # Advanced ## Bindings --- root: .components.layouts.MarkdownLayout title: Bindings nav-title: Bindings description: Import existing datapacks and generate Kotlin bindings. keywords: kore, bindings, import, datapack, github, modrinth, curseforge date-created: 2026-01-23 date-modified: 2026-04-21 routeOverride: /docs/advanced/bindings position: 3 --- # Bindings (Import Existing Datapacks) > [!WARNING] > The bindings module is **experimental**. APIs and generated output may change without notice. The bindings module lets you import existing datapacks and generates Kotlin types so you can reference functions, resources, and tags safely in your code. ## Install this module Add the `bindings` artifact when you want to import an existing datapack and generate Kotlin bindings from it. ### Artifact ```kotlin dependencies { implementation("io.github.ayfri.kore:bindings:VERSION") } ``` ### Best fit - Use `kore` for the main DSL. - Add `bindings` when you want type-safe access to resources coming from an external datapack. - Combine it with `oop` or `helpers` only if your project also needs those higher-level utilities. ## Quick start 1. Add the dependency. 2. Import `importDatapacks`. 3. Configure the output directory and package prefix. 4. Declare at least one source pack. ```kotlin import io.github.ayfri.kore.bindings.api.importDatapacks importDatapacks { configuration { outputPath("src/main/kotlin") packagePrefix = "kore.dependencies" } github("pixigeko.minecraft-default-data:1.21.8") { subPath = "data" } } ``` This example generates bindings into `src/main/kotlin` under the `kore.dependencies` package. If you need another source, replace `github(...)` with `modrinth(...)`, `curseforge(...)`, or `url(...)`. Those are explained below in the [Download sources](#download-sources) section. ## Using generated bindings When you import a datapack, Kore generates a `data object` with a name derived from the datapack's name (e.g., `VanillaRefresh`). ### Accessing resources Resources are organized by namespace and type. If a datapack has only one namespace, resources are accessible directly: ```kotlin import kore.dependencies.vanillarefresh.VanillaRefresh function("my_function") { // Call a function from the imported datapack function(VanillaRefresh.Functions.MAIN_TICK) // Reference a loot table (see Commands for loot usage) loot(VanillaRefresh.LootTables.BLOCKS.IRON_ORE) } ``` For more on using commands with imported resources, see [Commands](/docs/commands/commands). If the datapack uses multiple namespaces, they are nested: ```kotlin VanillaRefresh.Minecraft.LootTables.CHESTS.ABANDONED_MINESHAFT ``` ### Tags Tags are also imported and can be used wherever a tag of that type is expected: ```kotlin function("my_function") { // Wrap the imported tag in an item predicate so `execute` can read it. execute { ifCondition { // Check if the nearest player has the tagged item in their cursor. items(nearestPlayer(), PLAYER.CURSOR, itemPredicate { itemArgument = VanillaRefresh.Tags.Items.MY_CUSTOM_TAG }) } } } ``` ### Pack metadata The generated object also contains information about the original datapack: ```kotlin val path = VanillaRefresh.PATH // Path to the source file/folder val packMeta = VanillaRefresh.pack // PackSection object from pack.mcmeta ``` When pack metadata is reconstructed in generated bindings, Kore emits the `PackSection` using the same helpers as handwritten code, including `packFormat(...)` for version formats and `SupportedFormats(...)` when legacy supported formats are present. ## Generated structure For each imported datapack, a Kotlin file is generated containing: - A `data object` named after the datapack. - Nested `data object`s for each namespace (if multiple). - Nested `enum`s or `object`s for each resource type: - `Functions`: All `.mcfunction` files. - `Advancements`: All advancements. - `LootTables`: All loot tables. - `Recipes`: All recipes. - `Tags`: All tags, further nested by type (`Blocks`, `Items`, `Functions`, etc.). - `Worldgen`: All worldgen resources, further nested by type (`Biomes`, `Structures`, etc.). Subfolders in the datapack are preserved as nested objects. ## Explore without generating You can explore the content of a datapack programmatically without generating any code. ```kotlin import io.github.ayfri.kore.bindings.api.exploreDatapacks val datapacks = exploreDatapacks { github("user.repo:main") } val pack = datapacks.first() println("Datapack: ${pack.name}") println("Functions: ${pack.functions.size}") pack.functions.forEach { println(" - ${it.id}") } ``` ## Download sources ### GitHub Downloads a repository or a specific asset from a release. For higher API rate limits (or when your environment requires authenticated GitHub API access), set `GITHUB_API_KEY` as an environment variable or `github.api.key` as a system property. Patterns: - `user.repo`: Latest commit on the default branch. - `user.repo:tag`: Specific tag, branch, or commit. - `user.repo:tag:asset.zip`: Specific asset from a release. ```kotlin github("pixigeko.minecraft-default-data:1.21.8") ``` ### Modrinth Downloads the latest or a specific version of a Modrinth project. Patterns: - `slug`: Latest stable version. - `slug:version`: Specific version ID or number. ```kotlin modrinth("vanilla-refresh") ``` ### CurseForge Downloads from CurseForge. Requires the `CURSEFORGE_API_KEY` environment variable or the `curseforge.api.key` system property Patterns: - `projectId`: Latest file for the project. - `projectId:fileId`: Specific file. - `slug`: Project slug. - `slug:fileId`: Specific file for a project slug. - `URL`: Full CurseForge project URL. ```kotlin curseforge("418120") // Project ID ``` ### URL / local path Patterns: - `https://example.com/pack.zip` - `./path/to/pack` (Local folder) - `./path/to/pack.zip` (Local zip) ```kotlin url("https://example.com/pack.zip") ``` ## Configuration ### Global configuration Defined in the `configuration {}` block: | Property | Default | Description | |----------------------|---------------------------------|--------------------------------------------------| | `outputPath` | `build/generated/kore/imported` | Directory where Kotlin files will be generated. | | `packagePrefix` | `kore.dependencies` | Base package for all generated bindings. | | `generateSingleFile` | `true` | If true, generates one Kotlin file per datapack. | | `skipCache` | `false` | If true, re-downloads even if already in cache. | | `debug` | `false` | Prints extra information during the process. | ### Per-datapack configuration Defined in the block following a source: ```kotlin github("user.repo") { packageName = "custom.pkg" // Change the package for this pack subPath = "datapacks/main" // Only import from this subfolder includes = listOf("data/**") // Only include files matching these patterns excludes = listOf("**/test/**") // Exclude files matching these patterns body("{\"token\":\"abc123\"}") // Optional HTTP request body for url("https://...") sources header("Authorization", "Bearer your-token") // Add one request header for url("https://...") headers(mapOf("Accept" to "application/zip")) // Replace all request headers for url("https://...") remappings { objectName("MyPack") // Change the generated object name namespace("old_namespace", "NewNamespace") // Rename a specific namespace object } } ``` > [!NOTE] > The `remappedName` property is deprecated. Use `remappings { objectName("...") }` instead. For HTTP(S) sources declared with `url("https://...")`, you can customize request payload and headers from the per-datapack block with `body("...")`, `header("key", "value")`, and `headers(mapOf(...))`. ### Namespace normalization Namespace names are automatically normalized when generating Kotlin object names: dots (`.`) and other non-alphanumeric characters are replaced with underscores, then converted to PascalCase. For example, `my.namespace` becomes `MyNamespace`. You can override this behavior for any namespace using the `remappings {}` block described above. ## Cache Downloaded files are cached to speed up subsequent runs in a different directory depending on your OS: - On Windows, `LOCALAPPDATA` or `~/AppData/Local/kore`. - On macOS, `~/Library/Caches`. - On Linux, XDG cache directory or fallback to `~/.cache/kore/datapacks`. This can be overridden by the `KORE_CACHE_HOME` environment variable or the `kore.cache.home` system property. Use `skipCache = true` in the global configuration or delete the cache folder to force a re-download. ## Troubleshooting - **Rate Limits**: GitHub API is limited for unauthenticated calls. - **CurseForge API**: Ensure your API key is valid and has permissions for the project. - **Invalid resources**: If a resource type is unknown to Kore, it will be skipped to avoid generating invalid code. --- ## GitHub Actions Publishing --- root: .components.layouts.MarkdownLayout title: GitHub Actions Publishing nav-title: GitHub Actions Publishing description: Automatically publish your Kore datapacks using GitHub Actions with mc-publish. keywords: minecraft, datapack, kore, github actions, publishing, automation, ci/cd date-created: 2025-09-30 date-modified: 2026-06-24 routeOverride: /docs/advanced/github-actions-publishing --- # GitHub Actions Publishing This guide shows you how to automatically publish your Kore-generated datapacks to various platforms using GitHub Actions and the `mc-publish` action. ## Prerequisites - A GitHub repository containing your Kore project - Accounts on target platforms (Modrinth, CurseForge, etc.) - API tokens for each platform you want to publish to ## What is mc-publish? [mc-publish](https://github.com/Kira-NT/mc-publish) is a GitHub Action that simplifies publishing Minecraft projects across multiple platforms including Modrinth, CurseForge, and GitHub Releases. It automatically detects project metadata and handles the complex publication process with minimal configuration. ## Setting Up GitHub Secrets Before configuring your workflow, you'll need to add your platform tokens as GitHub secrets: 1. Go to your repository's **Settings** → **Secrets and variables** → **Actions** 2. Add the following secrets: - `MODRINTH_TOKEN`: Your Modrinth API token - `CURSEFORGE_TOKEN`: Your CurseForge API token - `GITHUB_TOKEN` is automatically provided by GitHub > **Note:** Only add secrets for platforms you plan to publish to. ## Basic Workflow Setup Create `.github/workflows/publish.yml` in your repository: ```yaml name: Publish Datapack on: release: types: [ published ] workflow_dispatch: # Allow manual triggering jobs: publish: runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout repository uses: actions/checkout@v5 - name: Set up JDK 25 uses: actions/setup-java@v5 with: cache: gradle distribution: 'temurin' java-version: 25 - name: Ensure Gradle is executable run: chmod +x gradlew - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 - name: Generate datapack run: ./gradlew run - name: Publish to platforms uses: Kir-Antipov/mc-publish@v3.3 with: # Modrinth configuration modrinth-id: YOUR_PROJECT_ID modrinth-token: ${{ secrets.MODRINTH_TOKEN }} # CurseForge configuration curseforge-id: YOUR_PROJECT_ID curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} # GitHub Releases github-token: ${{ secrets.GITHUB_TOKEN }} ``` Ensure to use `datapack.generateZip()` in your build script to generate a zip file containing your datapack. ## Advanced Configuration For more control over the publishing process, you can customize various aspects: ```yaml - name: Publish to platforms uses: Kir-Antipov/mc-publish@v3.3 with: # Project identification modrinth-id: AANobbMI modrinth-token: ${{ secrets.MODRINTH_TOKEN }} curseforge-id: 394468 curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }} # Version configuration name: "My Datapack v${{ github.ref_name }}" version: ${{ github.ref_name }} version-type: release # alpha, beta, or release # File selection files: | out/*.zip !out/*-unfinished.zip # Supported game versions game-versions: | 1.21.10 1.21.11 # Mod loaders (if exporting to Jars) loaders: | fabric forge # Release configuration changelog-file: CHANGELOG.md dependencies: | fabric-api(required){modrinth:P7dR8mSH}{curseforge:306612} # Platform-specific settings modrinth-featured: true curseforge-java-versions: | Java 21 github-prerelease: ${{ contains(github.ref_name, 'beta') || contains(github.ref_name, 'alpha') }} github-draft: false ``` ## Kore-Specific Configuration Kore generates your datapack from Kotlin code, so the workflow needs a build step that runs your `main()` and produces a zip. Make sure your entry point calls `datapack.generateZip()` (Kore writes the archive to the `out/` directory by default), then point `mc-publish`'s `files` input at it: ```yaml files: out/*.zip ``` Kore projects come in two flavours depending on the build tool you started from. Use the matching build step. ### Gradle (Kore-Template) The default [Kore-Template](https://github.com/Ayfri/Kore-Template) is a Gradle project, so the build step uses the Gradle wrapper: ```yaml - name: Set up JDK 25 uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: 25 - name: Ensure Gradle is executable run: chmod +x gradlew - name: Generate datapack run: ./gradlew run ``` ### Kotlin Toolchain (formerly Amper) Projects configured with the [Kotlin Toolchain](https://kotlinlang.org/docs/multiplatform/amper.html) (the `module.yaml` / `project.yaml` setup, previously called Amper) ship a `kotlin` wrapper script instead of `gradlew`. The wrapper downloads the toolchain and a JDK on first run, so you don't need a separate `setup-java` step: ```yaml - name: Make the Kotlin wrapper executable run: chmod +x kotlin - name: Generate datapack env: CI: "true" run: ./kotlin run ``` For a multi-module project (several datapacks in one repository), target a specific module with `-m`: ```yaml run: ./kotlin run -m my-datapack ``` Gate `generateZip()` behind an environment variable so local runs still emit loose files while CI produces the publishable zip: ```kotlin val isCI get() = System.getenv("CI") != null fun main() { dataPack("my_datapack") { // ... your content ... }.run { if (isCI) generateZip() else generate() } } ``` ## Workflow Triggers You can configure when the publishing workflow runs: ```yaml on: # Trigger on new releases release: types: [ published ] # Trigger on version tags push: tags: - 'v*' # Allow manual triggering workflow_dispatch: inputs: version-type: description: 'Release type' required: true default: 'release' type: choice options: - release - beta - alpha ``` ## Platform-Specific Features ### Modrinth - Supports featured projects - Automatic dependency resolution - Rich markdown changelog support ```yaml modrinth-featured: true modrinth-unfeature-mode: subset ``` ### CurseForge - Java version specification - Custom display name support ```yaml curseforge-java-versions: | Java 17 Java 21 curseforge-display-name: "My Awesome Datapack" ``` ### GitHub Releases - Draft and prerelease support - Asset management ```yaml github-draft: false github-prerelease: ${{ contains(github.ref_name, 'pre') }} github-tag: ${{ github.ref_name }} ``` This helps mc-publish automatically detect project metadata. ## Best Practices ### 1. Version Management Use semantic versioning and Git tags: ```bash git tag v1.0.0 git push origin v1.0.0 ``` ### 2. Changelog Management Maintain a `CHANGELOG.md` file following [Keep a Changelog](https://keepachangelog.com/) format: ```markdown # Changelog ## [1.0.0] - 2025-09-30 ### Added - Initial release with basic functionality - Support for Minecraft 1.21 ### Changed - Improved performance of item generation ### Fixed - Fixed issue with advancement rewards ``` ### 3. Testing Before Publishing Add a test job before publishing: ```yaml jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - name: Set up JDK 21 uses: actions/setup-java@v5 with: java-version: '21' distribution: 'temurin' - name: Run tests run: ./gradlew test publish: needs: test runs-on: ubuntu-latest # ... publishing steps ``` ## Troubleshooting ### Common Issues 1. **Missing files**: Ensure you exported the datapack to the correct directory 2. **Invalid tokens**: Verify your secrets are correctly set in GitHub 3. **Permission errors**: Ensure the workflow has `contents: write` permission ### Debugging Enable debug logging by adding: ```yaml env: ACTIONS_RUNNER_DEBUG: true ACTIONS_STEP_DEBUG: true ``` ## Complete Example Here's a complete workflow for a Kore datapack project: ```yaml name: Publish Datapack on: release: types: [ published ] workflow_dispatch: jobs: publish: runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout repository uses: actions/checkout@v5 - name: Set up JDK 25 uses: actions/setup-java@v5 with: cache: gradle distribution: 'temurin' java-version: 25 - name: Ensure Gradle is executable run: chmod +x gradlew - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 - name: Generate datapack run: ./gradlew run - name: Publish to platforms uses: Kir-Antipov/mc-publish@v3.3 with: name: "${{ github.event.repository.name }} ${{ github.ref_name }}" version: ${{ github.ref_name }} version-type: release files: out/*.zip game-versions: | 1.21.10 1.21.11 modrinth-id: YOUR_MODRINTH_ID modrinth-token: ${{ secrets.MODRINTH_TOKEN }} modrinth-featured: true curseforge-id: YOUR_CURSEFORGE_ID curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }} github-tag: ${{ github.ref_name }} changelog-file: CHANGELOG.md ``` ## See Also - [Creating a Datapack](/docs/guides/creating-a-datapack) - [Configuration](/docs/guides/configuration) - [mc-publish Documentation](https://github.com/Kir-Antipov/mc-publish) - [GitHub Actions Documentation](https://docs.github.com/en/actions) --- ## Known Issues --- root: .components.layouts.MarkdownLayout title: Known Issues nav-title: Known Issues description: Kore-focused limitations, documented DSL constraints, and generation rough edges with links to docs and source. keywords: kore, guide, documentation, known issues, compatibility, limitations, workarounds date-created: 2025-08-27 date-modified: 2026-04-26 routeOverride: /docs/advanced/known-issues --- # Known issues and compatibility This page lists **limitations and rough edges that touch Kore directly**: the `kore` module, **`bindings`**, and * *`helpers`** where Kore documents behavior. It is not a general Minecraft gameplay reference. Each item is tagged: | Category | Meaning | |---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------| | **Kore limitation** | Kore or a dependency Kore wires in (for example [knbt](https://github.com/BenWoodworth/knbt)) cannot express or round-trip the case yet. | | **Documented DSL / helper cap** | Behavior is spelled out in Kore’s own command or helper docs (often because the vanilla command format or text API is narrow). | | **Generation rough edge** | `generate()` / `generateZip()` / merge paths behave as implemented; surprising until you read the generation docs. | For the high-level "what Kore does not include," see [From Datapacks to Kore](/docs/guides/from-datapacks-to-kore#what-kore-does-not-give-you-or-not-yet). --- ## Kore limitations ### NBT and SNBT (via knbt) **Category:** Kore limitation Kore builds NBT and SNBT through **[knbt](https://github.com/BenWoodworth/knbt)** (`StringifiedNbt` and builders). Entry points include [ `NbtTagUtils.kt`](https://github.com/Ayfri/Kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/utils/NbtTagUtils.kt) and the `nbt { }` / `stringifiedNbt(...)` helpers used across commands and components. For normal day-to-day usage and examples, start with [NBTs](/docs/concepts/nbts); this section focuses on limitations and workarounds. Implications: - **Typed NBT lists:** In knbt, `NbtList` is **homogeneous** (one element type per list). That matches Java edition NBT, but it means you cannot build a single list that mixes unrelated tag kinds through the normal DSL. See the [knbt README](https://github.com/BenWoodworth/knbt/blob/main/README.md) (`NbtList` description). - **Exotic SNBT text:** Some SNBT spellings or parser extensions you might see in external tools are **not** necessarily available through Kore’s knbt-backed path. Prefer compounds, homogeneous lists, and literals Kore’s builders support. **Workaround:** Emit a **`literal("...")`** only when you must hand-craft a fragment, or post-process generated files. Upgrading or patching **[knbt](https://github.com/BenWoodworth/knbt)** (Kore pins a version in [ `gradle/libs.versions.toml`](https://github.com/Ayfri/Kore/blob/master/gradle/libs.versions.toml)) is the right place for format-level fixes. ### Resource packs **Category:** Kore limitation Kore generates **datapacks** only (`data/`, functions, JSON registries, `pack.mcmeta`). It does **not** emit **resource packs** (`assets/`). That scope is stated on the site (for example [Home](/docs/home)) and in [From Datapacks to Kore](/docs/guides/from-datapacks-to-kore#what-kore-does-not-give-you-or-not-yet). **Workaround:** Maintain a separate resource-pack project or tooling; you can still keep both in one Gradle repo. ### Bindings importer **Category:** Kore limitation The **`bindings`** module is **experimental**. Official docs: [Bindings](/docs/advanced/bindings). Roadmap and design discussion: [GitHub #176](https://github.com/Ayfri/Kore/issues/176). Notable constraints from Kore’s own docs and README: - Generated APIs may **change** between Kore versions; pin versions and review diffs. - **Unknown resource types** are **skipped** so codegen stays valid ([Bindings troubleshooting](/docs/advanced/bindings#troubleshooting)). - **Macros** in imported `.mcfunction` files are detected via **`$()`-style patterns**, not a full Minecraft parser ([Bindings](/docs/advanced/bindings)). - **CurseForge** downloads need a **CurseForge API key**; **GitHub** may need a token for rate limits ([Download sources](/docs/advanced/bindings#download-sources)). **Workaround:** Treat imports as a typed starting point; simplify or remap packs that confuse the importer ( `remappings { }`, `includes` / `excludes` in [Configuration](/docs/advanced/bindings#configuration)). ### JSON / NBT serialization (generate vs decode) **Category:** Kore limitation Decoding support varies by serializer: - **Chat components** decode fully into their typed forms via `ChatComponents.serializer()` (text, translatable, score, selector, keybind, nbt, object), including nested `extra`, styling, and hover/click events. **`NbtAsJsonSerializer`** decodes JSON/NBT into an `NbtTag`. - **Item components** (`ComponentsSerializer`) decode **generically**: each entry becomes a raw `CustomComponent` keyed by its component name. This round-trips, but the values stay opaque instead of becoming their typed counterparts (such as `DamageComponent`), because `Component` is not a sealed hierarchy and has no name to serializer registry to dispatch on. Typed item-component decoding would require that registry (ideally generated). - Book **page** serializers stay **write-only**: they encode what you build in Kotlin but do not decode vanilla JSON/SNBT. **Workaround:** For the write-only and generic cases, treat your Kotlin project as the **source of truth** and inspect **generated files** under `path` / zip. For contributors extending serializers, see [Arguments](/docs/contributing/arguments) and the relevant feature docs. ### Custom components and `@SerialName` **Category:** Kore limitation When you define **[custom components](/docs/concepts/components)** backed by NBT, property names sometimes need an explicit **`@SerialName("vanilla_json_key")`** because the **KNBT** stack does not always follow the same naming path as Kore’s JSON `namingStrategy` for that shape. The guide shows this in context (for example the `UseComponent` example with `durability_damages`). **Workaround:** Copy patterns from [Components](/docs/concepts/components) and match the keys your target **pack format ** expects (use Minecraft’s registry JSON or Kore’s generators as reference, not guesswork). --- ## Documented DSL / helper caps These are **not Kore bugs**; Kore documents them so authors know what the DSL will and will not do. ### Command macros **Category:** Documented DSL / helper cap [Macros](/docs/commands/macros) require **Minecraft 1.20.2+** for the feature itself. Kore’s doc lists DSL limits: macros only in **functions**, **no type checking**, and macros are **not** threaded through every possible command argument slot. **Workaround:** Prefer normal Kotlin command builders where types matter; keep macro surfaces small and **test in-game **. ### Markdown renderer (`helpers`) **Category:** Documented DSL / helper cap The [Markdown renderer](/docs/helpers/markdown-renderer) turns Markdown into **text components**. The helper lists features Minecraft **cannot** represent (images, tables, fenced code blocks, etc.) in [Not supported (Minecraft limitations)](/docs/helpers/markdown-renderer#not-supported-minecraft-limitations). **Workaround:** Stay in the **supported** subset documented on that page, or build **`textComponent`** trees by hand. ## Quick reference | Need | Where to look | |-----------------------|------------------------------------------------------------------------------------------| | Tune JSON output | [Configuration](/docs/guides/configuration) (`prettyPrint`, comments, paths) | | Folder vs zip vs jar | [Creating A Datapack - Generation](/docs/guides/creating-a-datapack#generation) | | Import external packs | [Bindings](/docs/advanced/bindings) | | Module layout | [From Datapacks to Kore](/docs/guides/from-datapacks-to-kore) | | Report a bug or gap | [Kore on GitHub](https://github.com/Ayfri/Kore/issues) with pack format and Kore version | --- ## Test Features --- root: .components.layouts.MarkdownLayout title: Test Features nav-title: Test Features description: A comprehensive guide for creating test instances and test environments in Minecraft's GameTest framework with Kore. keywords: minecraft, datapack, kore, guide, test, testing, environment, instance, gametest, automation date-created: 2025-01-08 date-modified: 2026-06-26 routeOverride: /docs/advanced/test-features --- # Test Features Minecraft 1.21.5 (Snapshot 25w03a) introduced a major overhaul to the **GameTest framework** - an automated end-to-end testing system for datapack functionality. Kore provides a type-safe Kotlin DSL that generates JSON files for the `test_instance` and `test_environment` registries. ## Test Environments Test environments define the preconditions under which tests run. There are six types: ### Weather Sets a fixed weather condition: ```kotlin testEnvironments { weather("clear_weather", Weather.CLEAR) weather("rain_weather", Weather.RAIN) weather("storm_weather", Weather.THUNDER) } ``` ### Clock Time Locks a world clock to a specific tick value: ```kotlin testEnvironments { clockTime("morning", WorldClocks.OVERWORLD, 1000) clockTime("noon", WorldClocks.OVERWORLD, 6000) clockTime("night", WorldClocks.OVERWORLD, 18000) } ``` ### Game Rules Overrides game rules for controlled conditions: ```kotlin testEnvironments { gameRules("controlled_env") { this[Gamerules.DO_DAYLIGHT_CYCLE] = false this[Gamerules.DO_MOB_SPAWNING] = false this[Gamerules.RANDOM_TICK_SPEED] = 0 } } ``` ### Function Runs datapack functions before (`setup`) and/or after (`teardown`) each test: ```kotlin val setupFn = function("test_setup") { say("Setting up") } val teardownFn = function("test_teardown") { say("Tearing down") } testEnvironments { function("my_function_env") { setup(setupFn) teardown(teardownFn) } } ``` ### Timeline Attributes Applies a set of timelines during test execution, useful for testing time-driven mechanics: ```kotlin val dayCycle = timeline("day_cycle", WorldClocks.OVERWORLD) val endCycle = timeline("end_cycle", WorldClocks.THE_END) testEnvironments { timelineAttributes("timeline_env", dayCycle, endCycle) } ``` ### Combined (allOf) Merges multiple environments into one: ```kotlin testEnvironments { val rules = gameRules("no_mobs") { this[Gamerules.DO_MOB_SPAWNING] = false } val time = clockTime("dawn", WorldClocks.OVERWORLD, 1000) allOf("controlled_dawn", rules, time) } ``` > **Tip:** You can also create environments outside a `testEnvironments` block using `testEnvironmentsBuilder`: > ```kotlin > val env = testEnvironmentsBuilder.weather("clear", Weather.CLEAR) > ``` > This is useful when reusing environments across multiple test instances. ## Test Instances Test instances define the actual tests. Each one references a structure, an environment, and execution parameters. ### Test Types - **Block-based** (`blockBased()`): Test logic is driven by redstone inside the structure using special test blocks (Start, Log, Fail, Accept). - **Function-based** (`functionBased()`): Test logic is handled by a Java method reference (used by Mojang internally and mod developers). Requires a `function` field with a fully qualified method reference (e.g., `"com.example.MyMod::myTest"`). ### Creating Test Instances ```kotlin testInstances { // Block-based test testInstance("redstone_test") { blockBased() environment(env) maxTicks = 100 structure(Structures.AncientCity.Structures.BARRACKS) } // Function-based test testInstance("function_test") { functionBased() environment(env) function("com.example.MyMod::myTest") maxTicks = 200 structure(Structures.Igloo.TOP) } } ``` ### Configuration Options All available properties for a test instance: | Property | Type | Description | |------------------------------------|---------------------------|------------------------------------------------------| | `environment(env)` | `TestEnvironmentArgument` | **Required.** The test environment to use. | | `structure(struct)` | `StructureArgument` | **Required.** The structure template for the test. | | `blockBased()` / `functionBased()` | - | Sets the test type (default: block-based). | | `function(fn)` | `String` | Java method reference for function-based tests. | | `maxTicks` | `Int` | Maximum ticks before timeout (default: 100). | | `setupTicks` | `Int` | Ticks to wait before starting the test. | | `maxAttempts` | `Int` | Maximum retry attempts. | | `requiredSuccesses` | `Int` | Successes needed out of `maxAttempts`. | | `required` | `Boolean` | Whether the test must pass for the suite to succeed. | | `manualOnly` | `Boolean` | Whether the test is only run manually. | | `skyAccess` | `Boolean` | Whether the structure needs sky access. | | `rotation(rot)` | `TestRotation` | Rotation applied to the structure. | Rotation helpers: `noRotation()`, `clockwise90()`, `rotate180()`, `counterclockwise90()`. ## Structures Kore provides constants for all vanilla structures: ```kotlin // Examples structure(Structures.AncientCity.Structures.BARRACKS) structure(Structures.Bastion.Treasure.Bases.LAVA_BASIN) structure(Structures.Igloo.TOP) structure(Structures.TrialChambers.Chamber.ASSEMBLY) structure(Structures.Village.Plains.Houses.PLAINS_SMALL_HOUSE_1) ``` ## Test Commands ### Selectors ```kotlin allTests() // "*:*" - all tests minecraftTests() // "minecraft:*" - minecraft tests testSelector("my_pack:*") // All tests in namespace testSelector("*_combat") // Pattern matching ``` ### Command Usage ```kotlin function("run_tests") { test { val selector = testSelector("my_pack:test_*") run(selector) runClosest() runMultiple(selector, 5) create(TestInstanceArgument("test", "pack")) locate(selector) pos("variable") clearAll() resetClosest() stop() verify(TestInstanceArgument("test1", "pack"), TestInstanceArgument("test2", "pack")) } } ``` ### In-Game Commands ```mcfunction /test run my_datapack:basic_test /test runmultiple my_datapack:basic_test my_datapack:function_test /test runclosest /test runfailed /test create my_datapack:new_test 16 16 16 /test locate my_datapack:test_* /test clearall 15 /test resetclosest /test stop ``` ## Complete Example ```kotlin fun DataPack.createTestSuite() { val setupFn = function("test_setup") { say("Setting up test") } val cleanupFn = function("test_cleanup") { say("Cleaning up test") } // Create reusable environments val controlled = testEnvironmentsBuilder.gameRules("controlled") { this[Gamerules.DO_DAYLIGHT_CYCLE] = false this[Gamerules.DO_MOB_SPAWNING] = false this[Gamerules.RANDOM_TICK_SPEED] = 0 } val dayTime = testEnvironmentsBuilder.clockTime("day", WorldClocks.OVERWORLD, 6000) val controlledDay = testEnvironmentsBuilder.allOf("controlled_day", controlled, dayTime) // Function environment (setup/teardown) testEnvironments { function("test_functions") { setup(setupFn) teardown(cleanupFn) } } testInstances { testInstance("redstone_basic") { blockBased() environment(controlledDay) maxTicks = 100 required = true structure(Structures.AncientCity.Structures.BARRACKS) } testInstance("complex_logic_test") { functionBased() environment(controlled) function("com.example.MyMod::myTest") maxAttempts = 2 maxTicks = 200 required = true structure(Structures.AncientCity.Structures.BARRACKS) } testInstance("directional_blocks") { blockBased() clockwise90() environment(controlled) maxTicks = 120 required = true structure(Structures.AncientCity.Structures.BARRACKS) } } } ``` ## Best Practices - **Combine environments** with `allOf` for complex scenarios. - **Mark critical tests** as `required = true`. - **Set appropriate timeouts** with `maxTicks`. - **Use game rules** to disable randomness (mob spawning, daylight cycle, tick speed). - **Reuse environments** via `testEnvironmentsBuilder` to avoid duplication. ## See Also - [Functions](/docs/commands/functions) - Kore's DSL for writing datapack functions. - [GameTest Framework](https://minecraft.fandom.com/wiki/GameTest_Framework) - Official Minecraft documentation. --- # Contributing ## Contributing: Architecture and Patterns --- root: .components.layouts.MarkdownLayout title: "Contributing: Architecture and Patterns" nav-title: "Architecture and Patterns" description: Detailed internal architecture, project layout, module responsibilities, and recurring implementation patterns for Kore contributors. keywords: architecture, bindings, commands, generator, kore, patterns, serializers, website date-created: 2026-04-10 date-modified: 2026-04-15 routeOverride: /docs/contributing/architecture-and-patterns --- # Contributing: Architecture and Patterns This page documents the contributor-facing architecture of Kore and the implementation patterns worth reusing. It is intentionally focused on the parts that help you answer two questions quickly: 1. *Which module should I edit?* 2. *Which project pattern should I follow instead of inventing a new one?* ## Project tree at a glance ```text Kore/ ├─ bindings/ ├─ build-logic/ ├─ generation/ ├─ helpers/ ├─ kore/ ├─ oop/ └─ website/ ``` This tree is intentionally small. It reflects the modules contributors should reason about first; local-only or git-excluded sandboxes are omitted on purpose. ## How the main modules relate - `bindings/` imports datapacks and emits Kotlin bindings for resources and registries. - `build-logic/` centralizes shared Gradle conventions and project metadata. - `generation/` transforms upstream Minecraft data into generated Kotlin/resources consumed by `kore/`. - `helpers/` and `oop/` layer higher-level APIs on top of the core DSL. - `kore/` is the main DSL and runtime surface most contributors touch first. - `website/` documents both the public API and contributor workflows. ## Module boundaries and edit surfaces ### [`bindings/`][bindings-root] - Purpose: datapack importer and Kotlin binding generator. - Typical flow: explorer -> normalized entities -> writer output. - Common edit surface: [`explorer.kt`][bindings-explorer], [`entities.kt`][bindings-entities], [ `writer.kt`][bindings-writer], then tests under [`bindings/src/test`][bindings-tests]. - Pattern to preserve: single-namespace packs stay compact, multi-namespace packs become namespace-nested objects, and worldgen content is grouped under `Worldgen`. ### [`build-logic/`][build-logic-root] - Purpose: shared Gradle conventions, publishing logic, and project metadata. - Common edit surface: convention plugins and [`Project.kt`][project-kt]. - Edit here when changing build behavior, publication rules, or project versioning. ### [`generation/`][generation-root] - Purpose: source-data processing and generated Kotlin/resource output. - Edit here when a generated enum, registry wrapper, or source-derived structure is wrong. - **Never** fix a generation issue by editing `kore/src/main/generated` or `build/generated/...` directly. - Full walkthrough: [Contributing: The Generation Pipeline][generation-pipeline]. ### [`helpers/`][helpers-root] - Purpose: optional higher-level helpers built on the core DSL. - Edit here only when the issue explicitly targets helper abstractions or reusable convenience APIs. - Mirror core DSL patterns instead of creating a parallel architecture. ### [`kore/`][kore-root] - Purpose: core DSL, typed arguments, command wrappers, serializers, worldgen builders, and data-driven resources. - Common edit surface: feature classes, `DataPack` registration, `Function` extensions, serializers, and tests under [ `kore/src/test`][kore-tests]. - A typical change in this module touches one feature family end to end: model, registration, builder entry point, tests, and docs. ### [`oop/`][oop-root] - Purpose: object-oriented abstractions layered on top of core Kore primitives. - Edit here when the issue is specifically about that façade, not when the underlying DSL itself is wrong. - Keep naming and behavior aligned with `kore/` to avoid divergent APIs. ### [`website/`][website-root] - Purpose: documentation markdown, docs navigation, and frontend rendering. - Docs live in [`website/src/jsMain/resources/markdown/doc`][docs-root]. - Edit this module in the same PR as any user-visible behavior change. ## Core patterns to reuse ### Argument wrappers and literals Kore prefers typed wrappers over raw strings. - `Argument` is the base abstraction for command-safe value types. - Generated argument wrappers are the preferred representation for registry references. - Tag variants encode `#namespace:name` conventions. - Literal helpers such as `literal()`, `int()`, and `float()` keep command assembly explicit and safe. This improves autocomplete quality, reduces malformed command strings, and keeps serialization predictable. ### Command wrappers Command APIs generally live as `Function` extension functions. - Build lines with `addLine(command("name", args...))`. - Accept typed arguments directly when possible. - Keep wrappers thin: syntax composition belongs here, domain state belongs in arguments or data classes. This keeps generated commands deterministic and test-friendly. ### Generator pattern Most data-driven resources in `kore` follow one consistent model: 1. A serializable feature class extends [`Generator`][generator-kt]. 2. The class defines its `resourceFolder`, transient `fileName`, and `generateJson(dataPack)` implementation. 3. [`DataPack`][datapack-kt] registers a typed generator list through `registerGenerator()`. 4. A `DataPack` extension function instantiates and registers the feature. 5. The extension returns a typed `*Argument` for later references. Concrete references: - [`Generator.kt`][generator-kt] - [`DataPack.kt`][datapack-kt] - [`Instrument.kt`][instrument-kt] - [`InstrumentTests.kt`][instrument-tests] For the procedural version of this pattern, use [Contributing: Creating a New Generator][new-generator]. ### Serializer strategy Prefer an existing serializer before creating a new one. Frequently reused serializers, in alphabetical order: - [`EitherInlineSerializer`][serializer-either-inline] - [`InlineAutoSerializer`][serializer-inline-auto] - [`InlinableListSerializer`][serializer-inlinable-list] - [`LowercaseSerializer`][serializer-lowercase] - [`NamespacedPolymorphicSerializer`][serializer-namespaced] - [`NbtAsJsonSerializer`][serializer-nbt-as-json] - [`ProviderSerializer`][serializer-provider] - [`SinglePropertySimplifierSerializer`][serializer-single-property] - [`ToStringSerializer`][serializer-to-string] Decision rule: 1. Check whether an existing serializer already matches the target JSON shape. 2. If not, see whether the model can be expressed with an existing pattern. 3. Only then add a new serializer, with focused tests. ## Fast heuristics when you are unsure where a change belongs - **Build, publishing, or versioning behavior** -> `build-logic/` and root Gradle metadata. - **Contributor or user-facing explanation** -> `website/` in the same PR. - **Datapack import output shape** -> `bindings/` pipeline and tests. - **Generated enum or registry wrapper shape** -> `generation/`, then regenerate and update `kore/` consumers. - **New registry-backed DSL resource** -> usually `kore/`, plus generation if a new argument wrapper is required. ## Testing patterns that speed up contribution - Feature tests usually assert emitted JSON payloads and generated command/resource lines. - Module-specific `testDataPack(...)` helpers provide compact generation setups. - Serializer tests should focus on roundtrip behavior and JSON or SNBT shape checks. When you touch generators, the usual path is: model -> `DataPack` registration -> builder entry point -> tests -> docs. ## Documentation pages Contributor pages are easier to maintain when they link to a single source of truth instead of restating the same rules. Required frontmatter keys, in alphabetical order: - `date-created` - `date-modified` - `description` - `keywords` - `nav-title` - `root` - `routeOverride` - `title` Keep routes stable, keep navigation intentional, and update entry pages when a new doc should become discoverable. ### How to write a documentation page Content rules that keep the docs consistent and trustworthy: - **Example-first.** Every public feature needs at least one copy-pastable Kotlin snippet. Verify each snippet against the real API (the source or a test) before committing - never invent method names or argument shapes. Use tabs for indentation, matching the Kotlin code style. - **State capabilities, not changes.** Write what the API *does*, not what changed between versions. Avoid changelog phrasing like "now possible" or "new in this release" in body copy; that information belongs in commit messages and release notes, not in a reference page that must read correctly a year later. - **Cross-link inline, not in a pile.** Link related pages from the sentence that mentions the concept (for example, link [Scoreboards][scoreboards-doc] the first time you mention scoreboards). Prefer one good inline link over a long trailing list. Keep any `See also` section short - three or four of the most relevant links, not a dump of everything related. - **Link to the Minecraft Wiki for vanilla concepts.** When a page touches a vanilla system (a command, a registry, an NBT structure, a pack format), link the relevant [Minecraft Wiki](https://minecraft.wiki) page. It is high quality and saves Kore from restating vanilla behavior - Kore docs should explain the *Kore* DSL and defer vanilla semantics to the wiki. - **Do not duplicate.** If a concept already has a home page, link it instead of re-explaining it. One source of truth per topic; everything else points at it. [scoreboards-doc]: /docs/concepts/scoreboards ## Why Kore uses these technical choices - **Centralized serializers** keep JSON and NBT output stable across modules and make diffs easier to review. - **Generator-first data-driven features** keep feature additions mechanical instead of bespoke. - **Tests close to feature families** help catch schema drift when Minecraft updates resource definitions. - **Thin command wrappers** preserve command predictability while still covering vanilla syntax broadly. - **Type-safe arguments over raw strings** reduce command regressions and improve IDE discoverability. ## See also - [Contributing: Contributing][contributing] - [Contributing: Creating a New Generator][new-generator] - [Contributing: The Generation Pipeline][generation-pipeline] - [Contributing: Workflow][workflow] [bindings-entities]: https://github.com/ayfri/kore/blob/master/bindings/src/main/kotlin/io/github/ayfri/kore/bindings/entities.kt [bindings-explorer]: https://github.com/ayfri/kore/blob/master/bindings/src/main/kotlin/io/github/ayfri/kore/bindings/explorer.kt [bindings-root]: https://github.com/ayfri/kore/tree/master/bindings [bindings-tests]: https://github.com/ayfri/kore/tree/master/bindings/src/test/kotlin/io/github/ayfri/kore/bindings [bindings-writer]: https://github.com/ayfri/kore/blob/master/bindings/src/main/kotlin/io/github/ayfri/kore/bindings/writer.kt [build-logic-root]: https://github.com/ayfri/kore/tree/master/build-logic [contributing]: /docs/contributing/contributing [datapack-kt]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/DataPack.kt [docs-root]: https://github.com/ayfri/kore/tree/master/website/src/jsMain/resources/markdown/doc [generation-pipeline]: /docs/contributing/generation-pipeline [generation-root]: https://github.com/ayfri/kore/tree/master/generation [generator-kt]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/Generator.kt [helpers-root]: https://github.com/ayfri/kore/tree/master/helpers [instrument-kt]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/features/instruments/Instrument.kt [instrument-tests]: https://github.com/ayfri/kore/blob/master/kore/src/test/kotlin/io/github/ayfri/kore/features/InstrumentTests.kt [kore-root]: https://github.com/ayfri/kore/tree/master/kore [kore-tests]: https://github.com/ayfri/kore/tree/master/kore/src/test/kotlin/io/github/ayfri/kore [new-generator]: /docs/contributing/creating-a-new-generator [oop-root]: https://github.com/ayfri/kore/tree/master/oop [project-kt]: https://github.com/ayfri/kore/blob/master/build-logic/convention/src/main/kotlin/Project.kt [serializer-either-inline]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/serializers/EitherInlineSerializer.kt [serializer-inline-auto]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/serializers/InlineAutoSerializer.kt [serializer-inlinable-list]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/serializers/InlinableListSerializer.kt [serializer-lowercase]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/serializers/LowercaseSerializer.kt [serializer-namespaced]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/serializers/NamespacedPolymorphicSerializer.kt [serializer-nbt-as-json]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/serializers/NbtAsJsonSerializer.kt [serializer-provider]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/serializers/ProviderSerializer.kt [serializer-single-property]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/serializers/SinglePropertySimplifierSerializer.kt [serializer-to-string]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/serializers/ToStringSerializer.kt [website-root]: https://github.com/ayfri/kore/tree/master/website [workflow]: /docs/contributing/contributing-workflow --- ## Contributing: Arguments Internals --- root: .components.layouts.MarkdownLayout title: "Contributing: Arguments Internals" nav-title: Arguments Internals description: Contributor-facing overview of Kore's argument system, including Argument, literals, resource-location wrappers, and tag-aware abstractions. keywords: minecraft, datapack, kore, arguments, internals, contributors, resources, tags, commands date-created: 2026-04-21 date-modified: 2026-04-21 routeOverride: /docs/contributing/arguments --- # Contributing: Arguments Internals This page is mostly for contributors and advanced readers who want to understand how Kore models command inputs internally. If you are just using Kore to build a datapack, you usually do **not** need to learn the full argument architecture. The more practical user-facing pages are [Selectors](/docs/concepts/selectors), [Functions](/docs/commands/functions), and the [Cookbook](/docs/guides/cookbook). ## Why the argument layer exists Kore models most command inputs as typed Kotlin values that implement the `Argument` interface. Instead of assembling raw command strings everywhere, builders pass values that know how to serialize themselves through `asString()`. This is one of the core reasons the DSL stays readable and safe to refactor. Typical examples: - `allPlayers()` serializes to `@a` - `Items.DIAMOND_SWORD` serializes to `minecraft:diamond_sword` - a tag wrapper serializes to `#minecraft:planks` - `literal("replace")` serializes to a raw command token ## The pieces contributors should know ### `Argument` is the common contract At the bottom, Kore uses the `Argument` interface as the shared abstraction for command-safe values. This gives the command layer a uniform way to serialize: - selectors - generated resource enums - tag wrappers - literals - some range-like and time-like values When adding a new command wrapper or argument family, prefer plugging into that existing contract rather than passing plain strings around. ### Literal helpers keep raw tokens explicit Literal helpers are used when a command slot expects a keyword-like token instead of a resource wrapper. Common examples include: - `literal("value")` - `bool(true)` / `bool(false)` - `all()` for wildcard score holders - numeric wrappers such as `int(...)` and `float(...)` They make raw command assembly explicit while still fitting the same typed pipeline. ### Selectors are just another argument family Selectors are user-facing, but internally they matter because they show the expected Kore pattern well: build a typed object first, then serialize late. ```kotlin val nearestZombie = allEntities(limitToOne = true) { type = EntityTypes.ZOMBIE sort = Sort.NEAREST } function("cleanup") { kill(nearestZombie) } ``` For selector usage itself, see [Selectors](/docs/concepts/selectors). ### `ResourceLocationArgument` is the main user-facing thing worth knowing Even though most users do not need the architecture details, one concept *is* worth knowing: a large part of Kore is generated as enums or wrappers that implement resource-location-based argument interfaces. This is why you can write things like: - `Items.DIAMOND_SWORD` - `Blocks.STONE` - `Sounds.Entity.Player.LEVELUP` - generated predicates, loot tables, functions, and tags Those values serialize to the namespaced IDs Minecraft expects, which means users usually do not need to handwrite `minecraft:...` strings. ```kotlin function("starter_kit") { give(allPlayers(), Items.DIAMOND_SWORD) playsound(Sounds.Entity.Player.LEVELUP, self()) } ``` When documenting Kore for users, this is usually the part to emphasize: generated enums and wrappers already model many Minecraft registries. ### Tag-aware parent interfaces preserve vanilla flexibility Some command slots accept either a concrete resource or a tag. Kore models this with dedicated parent interfaces such as: - `BlockOrTagArgument` - `ItemOrTagArgument` - `FunctionOrTagArgument` When the tag variant is used, it serializes with the vanilla `#namespace:name` syntax. This is an important contributor pattern: if vanilla accepts both a resource and its tag counterpart, Kore usually wants an umbrella interface instead of two unrelated overloads. ## When raw strings are still appropriate Raw strings still make sense when: - a new Minecraft command has not been wrapped yet - a mod command has no Kore DSL yet - you deliberately use `addLine(...)` or `command(...)` Even then, contributors should prefer composing raw command assembly with existing typed arguments rather than reverting to fully handwritten command strings. ## Practical contributor checklist When you add or modify argument-related APIs, check the following: 1. Can this reuse `Argument` instead of a plain `String`? 2. Should the value be a literal helper, a resource wrapper, or a tag-aware parent type? 3. Does vanilla allow both resource and tag forms? 4. Is there already a generated enum or wrapper that should be reused instead of inventing a new string API? 5. Do docs for regular users really need this detail, or should it stay in contributor-facing documentation? ## See also - [Selectors](/docs/concepts/selectors) - user-facing selector builders built on the same typed model - [Functions](/docs/commands/functions) - function builders that consume many argument types - [Architecture and Patterns](/docs/contributing/architecture-and-patterns) - broader contributor-facing project patterns - [Cookbook](/docs/guides/cookbook) - practical usage patterns rather than internals - [Minecraft Wiki: Argument types](https://minecraft.wiki/w/Argument_types) - vanilla command argument reference --- ## Contributing: CI/CD and Releases --- root: .components.layouts.MarkdownLayout title: "Contributing: CI/CD and Releases" nav-title: "CI/CD and Releases" description: Project and Minecraft versioning, CI automation, CodeQL scanning, release naming, and operational release practices for Kore maintainers. keywords: cd, ci, kore, maintenance, minecraft, releases, versioning date-created: 2026-04-10 date-modified: 2026-04-15 routeOverride: /docs/contributing/ci-cd-and-releases --- # Contributing: CI/CD and Releases This page summarizes the maintenance and release process used for Kore. ## Version ownership Kore tracks two coordinated version streams: - Minecraft target version in [`gradle.properties`][gradle-properties]. - Project version in [`build-logic/convention/src/main/kotlin/Project.kt`][project-kt]. Expected increment conventions: - Breaking/major change: `+0.1` - Minor fix/addition: `+0.0.1` ## Release naming pattern Observed release tags combine project and Minecraft targets, for example: - `2.0.0-1.21.11` - `1.42.1-1.21.11` - `1.41.1-1.21.11-rc3` This pattern keeps compatibility intent visible directly in release identifiers. ## Minecraft update flow For update cycles: 1. Add/update tests for new snapshot/release behavior. 2. Update project and Minecraft versions. 3. Run relevant module tests. 4. Update docs for API or behavior changes. ## Website release metadata behavior Website build logic includes GitHub release fetching to generate website-side release metadata. Maintainer notes: - `GITHUB_TOKEN` helps avoid API limits and improves reliability. - Generated outputs are artifacts, not hand-maintained source. ## GitHub Actions automation overview Current repository automation is split across dedicated workflows under `.github/workflows`: - `ci.yml`: runs the Gradle test suite on pushes and pull requests targeting `master`. - `codeql.yml`: runs GitHub CodeQL analysis for `actions` and `java-kotlin` on pushes, pull requests, manual dispatch, and a weekly schedule. - `publish.yml`: performs the manual release publication flow. - `publish-snapshot.yml`: publishes snapshot artifacts from `master`. CodeQL is intentionally scoped to the meaningful code in this repository: - `actions` covers the GitHub workflow files themselves. - `java-kotlin` covers the Gradle/Kotlin codebase. The scheduled CodeQL run uses GitHub Actions cron syntax in UTC and is set to once per week to keep regular security coverage without adding noise to every day. ## Commit message conventions - `chore(minecraft): Increase Minecraft version to X.Y.Z.` - `chore(project): Increase project version to X.Y.Z.` - `feat(code): Update project to Minecraft version X.Y.Z.` Consistent messages improve changelog scanning and release auditability. ## Where to start for maintainers - For version bumps: start with test updates, then change version files, then docs. - For release issues: check module labels and recent update issues for similar patterns. - For contribution workflow details: use [Contributing: Workflow][workflow]. ## See also - [Contributing][contributing] - [Contributing: Architecture and Patterns][architecture] - [Contributing: Workflow][workflow] [architecture]: /docs/contributing/architecture-and-patterns [contributing]: /docs/contributing/contributing [gradle-properties]: https://github.com/ayfri/kore/blob/master/gradle.properties [project-kt]: https://github.com/ayfri/kore/blob/master/build-logic/convention/src/main/kotlin/Project.kt [workflow]: /docs/contributing/contributing-workflow --- ## Contributing to Kore --- root: .components.layouts.MarkdownLayout title: Contributing to Kore nav-title: Contributing description: Entry point for contributors who want to work on Kore architecture, workflows, and project quality. keywords: architecture, contributing, kore, patterns, quality, workflow date-created: 2026-04-10 date-modified: 2026-04-15 routeOverride: /docs/contributing/contributing --- # Contributing to Kore This page is the *entry point* for contributors who do not know the codebase yet. Use it to identify the right guide before touching code, tests, or documentation. ## Choose the right guide - **Add a new data-driven feature:** read [Contributing: Creating a New Generator][new-generator] before editing `kore`. - **Add or update DSL features:** start with [Contributing: Architecture and Patterns][architecture], then use [Contributing: Workflow][workflow]. - **Add or fix a generated enum/registry/argument type:** read [Contributing: The Generation Pipeline][generation-pipeline]. - **Prepare an issue or a pull request:** go straight to [Contributing: Workflow][workflow]. - **Ship a release or update versions:** use [Contributing: CI/CD and Releases][releases]. ## Repository map at a glance - `bindings/`: datapack importer and Kotlin bindings code generation. - `build-logic/`: shared Gradle conventions and project metadata. - `generation/`: Minecraft source-data processing and generated Kotlin/resource pipelines. - `helpers/`: optional higher-level helpers built on top of the core DSL. - `kore/`: core DSL, arguments, commands, serializers, and generators. - `oop/`: object-oriented abstractions layered on top of Kore primitives. - `website/`: documentation content, docs navigation, and generated doc indexes. ## Contribution principles - Keep generated files generated: fix the generator or source pipeline, not `build/generated/...` or `kore/src/main/generated`. - Prefer existing serializers, typed arguments, and command helpers before introducing new abstractions. - Ship tests and docs with behavior changes, especially in `bindings/` and `kore/`. - Stay within one clear module boundary when possible; use [Architecture and Patterns][architecture] to decide where a change belongs. ## Suggested first pass for a newcomer 1. Read [Contributing: Architecture and Patterns][architecture] to understand module boundaries. 2. Read [Contributing: Workflow][workflow] to understand tests, docs, and PR expectations. 3. Open one existing feature in `kore` end to end: feature class, `DataPack` registration, tests, then docs. 4. If the change is data-driven, mirror the closest feature with [Contributing: Creating a New Generator][new-generator]. [architecture]: /docs/contributing/architecture-and-patterns [generation-pipeline]: /docs/contributing/generation-pipeline [new-generator]: /docs/contributing/creating-a-new-generator [releases]: /docs/contributing/ci-cd-and-releases [workflow]: /docs/contributing/contributing-workflow --- ## Contributing: Workflow --- root: .components.layouts.MarkdownLayout title: "Contributing: Workflow" nav-title: "Contributing Workflow" description: End-to-end workflow for opening issues, implementing changes, validating them, and preparing pull requests in Kore. keywords: contributing, docs, issues, kore, pull-request, quality, tests, workflow date-created: 2026-04-10 date-modified: 2026-04-15 routeOverride: /docs/contributing/contributing-workflow --- # Contributing: Workflow This page is the *process reference* for changes in Kore. Use it when you already know **what** you want to change and need to validate **how** to carry that change from issue to PR. ## 1) Qualify the issue or proposal first Before writing code, make sure the scope is explicit. If you are opening an issue: - Pick the closest template in [`.github/ISSUE_TEMPLATE`][issue-templates]. - Search for duplicates first. - Include a minimal reproduction or explicit reproduction steps. - Include expected behavior, actual behavior, and the Kore + Minecraft versions you tested. If you are starting from an existing issue or drafting a PR directly: - Keep the first pass focused on one behavior change. - Pick the narrowest module scope possible. - Read one similar merged change before adding new abstractions. Useful scope labels when triaging work: | Scope | Use it for | |-------------------|------------------------------------------------------| | `bindings` | Datapack importer and generated bindings output | | `dsl` | Command DSL and data-driven `kore` APIs | | `generation` | Source-data processing and code generation pipelines | | `helpers` / `oop` | Higher-level APIs built on top of the core DSL | | `update` | Minecraft version tracking and update work | | `website` | Documentation content and docs site behavior | ## 2) Trace the change before editing Before implementation: - Confirm the target module in [Contributing: Architecture and Patterns][architecture]. - Identify symbol usages and nearby call paths. - Reuse an existing helper, serializer, or feature pattern when one already exists. This is the fastest way to avoid duplicate APIs and hidden coupling. If the change is a new data-driven feature in `kore`, use [Contributing: Creating a New Generator][new-generator] instead of inventing a new shape from scratch. ## 3) Implement with tests and docs in the same pass For `bindings` and `kore`, tests are expected alongside code changes. Test locations: - [`bindings/src/test/kotlin/io/github/ayfri/kore/bindings`][bindings-tests] - [`kore/src/test/kotlin/io/github/ayfri/kore`][kore-tests] At minimum, validate: - Output behavior for commands or generated resources. - Regression behavior for bugs. - Serialization or deserialization shapes when JSON/NBT is involved. Any user-visible behavior change should update docs in [`website/src/jsMain/resources/markdown/doc`][docs-root]. Documentation updates usually include: - A usage-oriented example when the feature is public. - A migration note or caveat when behavior changed. - Updated internal links when contributor navigation should change. ## 4) Validate locally before opening the PR Run the checks that match the modules you changed. Typical commands: - `./gradlew :bindings:test` for `bindings` changes. - `./gradlew :kore:test` for core DSL changes. - `./gradlew :oop:test` for OOP module changes. - `./gradlew :helpers:test` for helpers module changes. - Your local website workflow when you touched docs navigation or page structure. Validation checklist: - Docs reflect the final API or DSL shape. - Generated outputs were **not** edited by hand. - Manual lists and registries still follow project ordering conventions. - Tests cover the changed behavior. ## 5) Prepare a reviewable pull request A good Kore PR is easy to review because it stays narrow and links the right context. In the PR body, link: - The docs pages updated in the same PR. - The issue or proposal being solved. - The tests that cover the change. - Any migration impact or behavior caveat for existing users. For the title and commit messages, follow conventional commits. Common examples: - `chore(minecraft): Increase Minecraft version to X.Y.Z.` - `chore(project): Increase project version to X.Y.Z.` - `feat(code): Update project to Minecraft version X.Y.Z.` ## 6) Frequent review blockers - Editing generated output instead of updating the generator or source pipeline. - Mixing refactors and feature behavior changes in one large PR. - Re-implementing a serializer or helper that already exists. - Shipping an API change without matching documentation. ## See also - [Contributing: Architecture and Patterns][architecture] - [Contributing: Contributing][contributing] - [Contributing: Creating a New Generator][new-generator] - [Contributing: CI/CD and Releases][releases] [architecture]: /docs/contributing/architecture-and-patterns [bindings-tests]: https://github.com/ayfri/kore/tree/master/bindings/src/test/kotlin/io/github/ayfri/kore/bindings [contributing]: /docs/contributing/contributing [docs-root]: https://github.com/ayfri/kore/tree/master/website/src/jsMain/resources/markdown/doc [issue-templates]: https://github.com/ayfri/kore/tree/master/.github/ISSUE_TEMPLATE [kore-tests]: https://github.com/ayfri/kore/tree/master/kore/src/test/kotlin/io/github/ayfri/kore [new-generator]: /docs/contributing/creating-a-new-generator [releases]: /docs/contributing/ci-cd-and-releases --- ## Contributing: Creating a New Generator --- root: .components.layouts.MarkdownLayout title: "Contributing: Creating a New Generator" nav-title: "Creating a New Generator" description: Step-by-step contributor guide for adding a new data-driven generator to Kore, from model and registration to tests and documentation. keywords: contributing, datapack, generator, kore, patterns, tests date-created: 2026-04-15 date-modified: 2026-04-15 routeOverride: /docs/contributing/creating-a-new-generator --- # Contributing: Creating a New Generator This page is the end-to-end recipe for adding a new data-driven generator in `kore`. The examples below use a *fictional* `custom_reward` resource so the shape stays easy to transpose to real Minecraft schemas. ## 1) Start from the closest existing feature Before creating files, pick the nearest generator already in Kore and mirror its structure. Good references, in alphabetical order: - [`DamageType`][damage-type] - [`Instrument`][instrument-feature] - [`PaintingVariant`][painting-variant] What you want to mirror: - `DataPack` registration. - `DataPack` extension function. - `Generator` inheritance and path behavior. - Package layout. - Test shape. If the feature needs a brand-new registry argument type, add it through the generation pipeline first - see [Contributing: The Generation Pipeline][generation-pipeline]. Do **not** hand-edit `kore/src/main/generated` or `build/generated/...`. ## 2) Create the feature class Place the feature in the matching package under `kore/src/main/kotlin/io/github/ayfri/kore/features/...`. ```kotlin package io.github.ayfri.kore.features.customrewards import io.github.ayfri.kore.DataPack import io.github.ayfri.kore.Generator import io.github.ayfri.kore.arguments.chatcomponents.ChatComponents import io.github.ayfri.kore.arguments.chatcomponents.textComponent import io.github.ayfri.kore.generated.arguments.types.LootTableArgument import kotlinx.serialization.Serializable import kotlinx.serialization.Transient @Serializable data class CustomReward( @Transient override var fileName: String = "starter_kit", var displayName: ChatComponents = textComponent(), var lootTable: LootTableArgument, var cooldown: Int = 0, ) : Generator("custom_reward") { override fun generateJson(dataPack: DataPack) = dataPack.jsonEncoder.encodeToString(this) } ``` Checklist for the class itself: - Extend [`Generator`][generator-kt] with the correct `resourceFolder`. - Keep `generateJson(dataPack)` thin and delegate to the shared encoder when the structure is straightforward. - Mark `fileName` as `@Transient`. - Make the feature `@Serializable`. - Only override `getPathFromDataDir(...)` when the resource path is genuinely special. ## 3) Register the generator in `DataPack` Add the new list in [`DataPack.kt`][datapack-kt], in alphabetical order with the other registered generators. ```kotlin val customRewards = registerGenerator() ``` This is what makes the feature participate in the normal datapack generation lifecycle. ## 4) Add the `DataPack` extension function The extension function is the public builder entry point. ```kotlin fun DataPack.customReward( fileName: String = "starter_kit", lootTable: LootTableArgument, displayName: ChatComponents = textComponent(), cooldown: Int = 0, init: CustomReward.() -> Unit = {}, ): CustomRewardArgument { val customReward = CustomReward(fileName, displayName, lootTable, cooldown).apply(init) customRewards += customReward return CustomRewardArgument(fileName, customReward.namespace ?: name) } ``` Keep it consistent with the rest of Kore: - Add the instance to the registered list. - Apply `init` last. - Instantiate the feature once. - Return the matching typed argument. If the resource can be referenced by tags, preserve the corresponding `*OrTagArgument` pattern as well. ## 5) Reuse serializers and argument types Before adding custom serialization logic, check [Contributing: Architecture and Patterns][architecture]. In practice, the decision order is: 1. Reuse an existing serializer. 2. Reshape the model if that makes an existing serializer work. 3. Add a new serializer only when the first two options fail. This keeps JSON output aligned with the rest of Kore instead of creating one-off conventions. ## 6) Add tests immediately Generator changes in `kore` should ship with targeted tests under [ `kore/src/test/kotlin/io/github/ayfri/kore`][kore-tests]. For a simple resource, the test usually follows this shape: ```kotlin package io.github.ayfri.kore.features import io.github.ayfri.kore.DataPack import io.github.ayfri.kore.assertions.assertGeneratorsGenerated import io.github.ayfri.kore.assertions.assertsIs import io.github.ayfri.kore.features.customrewards.customReward import io.github.ayfri.kore.generated.LootTables import io.github.ayfri.kore.utils.pretty import io.github.ayfri.kore.utils.testDataPack import io.kotest.core.spec.style.FunSpec fun DataPack.customRewardTests() { customReward("starter_kit", lootTable = LootTables.Chests.SPAWN_BONUS_CHEST) { cooldown = 200 } customRewards.last() assertsIs """ { "display_name": "", "loot_table": "minecraft:chests/spawn_bonus_chest", "cooldown": 200 } """.trimIndent() } class CustomRewardTests : FunSpec({ test("custom reward") { testDataPack("custom_reward") { pretty() customRewardTests() }.apply { assertGeneratorsGenerated() generate() } } }) ``` At minimum, validate: - Edge cases or regressions specific to the feature. - The emitted JSON shape. - The generated file path. ## 7) Update documentation in the same PR Every user-visible feature needs docs under [`website/src/jsMain/resources/markdown/doc`][docs-root]. Typical documentation work includes: - A contributor note when the implementation pattern is non-obvious. - A user-facing usage page when the feature becomes public API. - Updated links from entry pages when navigation changes. For page placement, routing, and required frontmatter keys, reuse the documentation contract described in [Contributing: Architecture and Patterns][architecture]. ## 8) Validate before opening the PR For `kore` changes, the baseline check is: ```bash ./gradlew :kore:test ``` Before opening the PR, verify that: - `DataPack` registration remains alphabetically ordered. - Docs reflect the final API shape. - No generated file was hand-edited. - Tests cover the feature. ## 9) Done checklist You are usually done when the feature includes all of the following: - A `DataPack` extension function returning the typed argument. - A `DataPack` registration entry. - A `Generator` subclass with the correct path behavior. - Documentation updates in `website/.../markdown/doc`. - Tests in `kore/src/test`. ## See also - [Contributing: Architecture and Patterns][architecture] - [Contributing: Contributing][contributing] - [Contributing: The Generation Pipeline][generation-pipeline] - [Contributing: Workflow][workflow] [architecture]: /docs/contributing/architecture-and-patterns [contributing]: /docs/contributing/contributing [generation-pipeline]: /docs/contributing/generation-pipeline [damage-type]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/features/damagetypes/DamageType.kt [datapack-kt]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/DataPack.kt [docs-root]: https://github.com/ayfri/kore/tree/master/website/src/jsMain/resources/markdown/doc [generator-kt]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/Generator.kt [instrument-feature]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/features/instruments/Instrument.kt [kore-tests]: https://github.com/ayfri/kore/tree/master/kore/src/test/kotlin/io/github/ayfri/kore [painting-variant]: https://github.com/ayfri/kore/blob/master/kore/src/main/kotlin/io/github/ayfri/kore/features/paintingvariant/PaintingVariant.kt [workflow]: /docs/contributing/contributing-workflow --- ## Contributing: The Generation Pipeline --- root: .components.layouts.MarkdownLayout title: "Contributing: The Generation Pipeline" nav-title: "Generation Pipeline" description: How Kore's generation module downloads Minecraft source data and codegens enums and argument types. Covers registries, data sources, caching, and the generator extension API for contributors. keywords: arguments, codegen, contributing, generation, kore, registries, minecraft data, enum generation, kotlin codegen, datapack generator internals date-created: 2026-07-01 date-modified: 2026-07-01 routeOverride: /docs/contributing/generation-pipeline --- # Contributing: The Generation Pipeline `generation/` is a standalone Kotlin/JVM app, not a library other modules depend on. Running it writes Kotlin files straight into [`kore/src/main/generated`][kore-generated] - it is the *only* thing allowed to touch that folder. ## What it does `generation/src/main/kotlin/Main.kt` runs, in order: 1. Clear `kore/src/main/generated` and (with `--reload-cache`) the download cache. 2. Download datapacks, the default datapack version, gamerules and item component types. 3. Run every simple generator ([`launchAllSimpleGenerators`][generators-kt]) - lists and registries that become enums or enum trees. 4. Run the argument type generator ([`launchArgumentTypeGenerators`][arguments-kt]) - registries that become typed `*Argument` / `*OrTagArgument` / `*TagArgument` interfaces. 5. Write the resolved Minecraft version into the generated package. Source data is fetched from the [`PixiGeko/Minecraft-generated-data`][source-repo] GitHub repo, pinned to the `minecraft.version` in `gradle.properties`. Downloads are cached under `generation/build/cache`; pass `--reload-cache` to force a re-download after a Minecraft version bump. ## Adding a new generated list or registry Most new registries only need an entry in [`generators/generators.kt`][generators-kt], inside `lists` (plain resource lists, e.g. `loot_table`) or `registries` (vanilla registries, e.g. `item`): ```kotlin gen("TradeSets", "trade_set") ``` `gen(name, fileName) { ... }` ([`generators/Generator.kt`][generator-kt]) takes the enum name and the upstream file name, and exposes a small builder for the common cases: - `argumentClassName` - override the generated `*Argument` type name when it should differ from `name` (for example `"Model M"` routes the argument to `arguments/types/resources` instead of the generated tree - see the `M`-suffix rule in [Contributing: Creating a New Generator][new-generator]). - `transform { ... }` - strip a suffix/prefix from raw entries (`.json`, `.ogg`, `minecraft:`, ...). - `enumTree` / `separator` - force or configure a path-based enum tree instead of a flat enum, for entries that contain `/`. - `extractEnums(...)` - split out a sub-enum from entries sharing a prefix. - `tagsParents(...)` / `subInterfacesParents(...)` - map resource folders or sub-namespaces to their parent argument type, used by the `Tags` and `Textures` generators. Whether an entry lands in `lists` or `registries` only changes which upstream `.txt` folder it reads from (`custom-generated/lists/...` vs `custom-generated/registries/...`); both feed the same enum/enum-tree codegen. Registries that need a typed argument (referenced from other DSL builders, taggable, etc.) are handled separately by `launchArgumentTypeGenerators()` in [`generators/arguments.kt`][arguments-kt] - it reads the registry list straight from the datapack report (`minecraft-generated/reports/datapack.json`) rather than from `generators.kt`, so a vanilla registry usually needs no manual entry at all. `additionalTypes`/`ignoreList` in that file are only for registries the report doesn't expose or that already have a hand-written model (`block`, `item`, `tag`). ## Running it ``` ./gradlew :generation:run ``` Add `--args='--reload-cache'` after bumping the Minecraft version to invalidate the download cache. Once it finishes, diff `kore/src/main/generated` and `kore/src/main/kotlin/io/github/ayfri/kore/generated` (the `Argument`-type files) to confirm the new registry produced the expected enum/argument shape before writing any DSL code against it. ## See also - [Contributing: Architecture and Patterns][architecture] - [Contributing: Creating a New Generator][new-generator] [architecture]: /docs/contributing/architecture-and-patterns [arguments-kt]: https://github.com/ayfri/kore/blob/master/generation/src/main/kotlin/generators/arguments.kt [generator-kt]: https://github.com/ayfri/kore/blob/master/generation/src/main/kotlin/generators/Generator.kt [generators-kt]: https://github.com/ayfri/kore/blob/master/generation/src/main/kotlin/generators/generators.kt [kore-generated]: https://github.com/ayfri/kore/tree/master/kore/src/main/generated [new-generator]: /docs/contributing/creating-a-new-generator [source-repo]: https://github.com/PixiGeko/Minecraft-generated-data --- # Home ## Kore - Type-Safe Minecraft Datapack Generator --- root: .components.layouts.MarkdownLayout title: Kore - Type-Safe Minecraft Datapack Generator nav-title: Home description: Kore is a Kotlin DSL datapack generator for Minecraft Java Edition. Create datapacks with type-safe code instead of writing JSON and MCFunction by hand. Open-source and production-ready. keywords: minecraft datapack generator, datapack maker, minecraft data pack creator, kotlin datapack, kore, minecraft datapack dsl, datapack development, minecraft java edition, mcfunction generator, datapack library date-created: 2024-04-06 date-modified: 2026-07-02 routeOverride: /docs/home position: 0 --- # Kore **Welcome to the Kore wiki!** Kore is a Kotlin library for building Minecraft datapacks with a concise, type-safe Kotlin DSL. It focuses on readable builders, stable generation of datapack JSON, and tight integration with vanilla concepts (functions, loot tables, predicates, worldgen, ...). ## Quick start - **Getting started**: Check out the [Getting Started](/docs/getting-started) guide for a step-by-step introduction to creating your first datapack. - **Prerequisites**: Java 21+ and a Kotlin-capable build environment. - **Starter template**: use the `Kore Template` for a ready-to-run project: [ `Kore Template`](https://github.com/Kore-Minecraft/Kore-Template). - **Create & generate**: see [Creating A Datapack](/docs/guides/creating-a-datapack) for lifecycle and output options (`.generate()`, `.generateZip()`, `.generateJar()`). - **Build faster**: browse the [Cookbook](/docs/guides/cookbook) for practical patterns you can reuse. ## Installable modules Kore is split into installable modules. Start with `kore`, then add the others depending on the abstractions or tooling you need. ### `kore` - Core DSL - Build datapacks with the main Kore DSL. - Artifact: `io.github.ayfri.kore:kore:VERSION` - Snapshot builds from each commit on `master`: add `https://central.sonatype.com/repository/maven-snapshots/` and use `VERSION-SNAPSHOT` - Start here: [Getting Started](/docs/getting-started) ### `oop` - Object-oriented gameplay utilities - Add higher-level abstractions for boss bars, cooldowns, entities, game states, scoreboards, spawners, teams, and timers. - Especially useful when several gameplay systems need to exchange data cleanly, such as syncing a `Team` with a boss bar or reusing an `Entity` handle across scoreboards and commands. - Artifact: `io.github.ayfri.kore:oop:VERSION` - Explore: [OOP Utilities](/docs/oop/oop-utilities) ### `helpers` - Utility-focused helpers - Add renderers, raycasts, scheduler utilities, scoreboard math, state delegates, particle helpers, and related utilities. - These helpers complement the core DSL well for advanced text pipelines, reusable state access, geometric particles, or command-heavy math routines. - Artifact: `io.github.ayfri.kore:helpers:VERSION` - Explore: [Helpers Utilities](/docs/helpers/utilities) ### `bindings` - Datapack importer - Import existing datapacks and generate type-safe Kotlin bindings for their functions, resources, and tags. - Artifact: `io.github.ayfri.kore:bindings:VERSION` - Explore: [Bindings](/docs/advanced/bindings) {{{ .components.doc.FeatureGrid }}} ### Minimal example ```kotlin fun main() { dataPack("example") { function("display_text") { tellraw(allPlayers(), textComponent("Hello World!")) } }.generateZip() } ``` ## Essential reading - **[Getting Started](/docs/getting-started)**: step-by-step guide to create your first datapack. - **[Creating A Datapack](/docs/guides/creating-a-datapack)**: lifecycle, output paths, and generation options. - **[Cookbook](/docs/guides/cookbook)**: practical recipes combining multiple Kore features. - **[Commands](/docs/commands/commands)**: comprehensive guide to all Minecraft commands with examples. - **[Functions](/docs/commands/functions)**: building functions, tags, and command helpers. ## Full documentation index ### Core Guides - [Why Kore](/docs/guides/why-kore) - why use Kore over raw datapacks or other generators. - [From Datapacks to Kore](/docs/guides/from-datapacks-to-kore) - advanced guide for migrating established datapacks to a Kotlin/Kore architecture. - [Configuration](/docs/guides/configuration) - JSON formatting and generation options. - [Cookbook](/docs/guides/cookbook) - practical patterns for common datapack workflows. ### Commands - [Execute](/docs/commands/execute) - context subcommands, conditions, stores, and the run clause. - [Macros](/docs/commands/macros) - dynamic command arguments for reusable functions. ### Concepts - [Runtime Logic](/docs/concepts/runtime-logic) - compile-time Kotlin vs runtime Minecraft: variables, conditions, loops. - [Data Storage](/docs/concepts/data-storage) - the runtime NBT variable container via the `/data` command. - [Components](/docs/concepts/components) - item/component builders and custom components. - [Chat Components](/docs/concepts/chat-components) - formatted messages and text components. - [Colors](/docs/concepts/colors) - chat colors and formatting options. - [NBTs](/docs/concepts/nbts) - the shared NBT builder DSL used across commands and data-driven APIs. - [Selectors](/docs/concepts/selectors) - entity and player targeting with typed filters. - [Scoreboards](/docs/concepts/scoreboards) - objectives, teams, and scoreboard displays. - [Time](/docs/concepts/time) - `TimeNumber` and the `.ticks`, `.seconds`, `.days` extensions for command durations. ### Data-Driven - [Predicates](/docs/data-driven/predicates) - reusable conditions used by loot tables, advancements and item modifiers. - [Loot Tables](/docs/data-driven/loot-tables) & [Item Modifiers](/docs/data-driven/item-modifiers) - tables, pools and `/item modify` helpers. - [Recipes](/docs/data-driven/recipes) & [Advancements](/docs/data-driven/advancements) - crafting, rewards and integration. - [Enchantments](/docs/data-driven/enchantments) - custom enchantment definitions. - [Dialogs](/docs/data-driven/dialogs) - NPC dialog systems. - [Worldgen](/docs/data-driven/worldgen) - biomes, features and dimension examples. - [Tags](/docs/data-driven/tags) - custom tag definitions for grouping items, blocks, entities, etc. ### Helpers - [Helpers Utilities](/docs/helpers/utilities) - overview of helper-focused utilities extracted from the OOP module. - [Display Entities](/docs/helpers/display-entities) - text, block, and item displays. - [Inventory Manager](/docs/helpers/inventory-manager) - inventory manipulation helpers. - [Mannequins](/docs/helpers/mannequins) - armor stand helpers. - [ANSI Renderer](/docs/helpers/ansi-renderer) - ANSI escape codes to text components. - [Area](/docs/helpers/area) - 3D bounding box geometry. - [Markdown Renderer](/docs/helpers/markdown-renderer) - Markdown to text components. - [MiniMessage Renderer](/docs/helpers/minimessage-renderer) - Adventure MiniMessage to text components. - [Raycasts](/docs/helpers/raycasts) - recursive step-based raycasting. - [Scheduler](/docs/helpers/scheduler) - delayed function execution patterns. - [Scoreboard Math](/docs/helpers/scoreboard-math) - trigonometry and algebra via scoreboards. - [State Delegates](/docs/helpers/state-delegates) - Kotlin property delegates for scoreboards/storage. - [VFX Particles](/docs/helpers/vfx-particles) - geometric particle shapes. ### OOP - [OOP Utilities](/docs/oop/oop-utilities) - overview of all OOP module features. - [Entities & Players](/docs/oop/entities-and-players) - entity/player management, commands, and effects. - [Teams](/docs/oop/teams) - object-oriented team management. - [Scoreboards](/docs/oop/scoreboards) - objective and score operations. - [Items](/docs/oop/items) - item creation and spawning. - [Events](/docs/oop/events) - advancement-based event system. - [World Events](/docs/oop/world-events) - tick, weather, day/night, and interval events from the world. - [Cooldowns](/docs/oop/cooldowns) - scoreboard-based cooldowns. - [Boss Bars](/docs/oop/boss-bars) - boss bar management. - [Timers](/docs/oop/timers) - scoreboard-based timers with optional boss bar. - [Spawners](/docs/oop/spawners) - reusable entity spawner handles. - [Game State Machine](/docs/oop/game-state-machine) - scoreboard-based state machine. ### Advanced - [Bindings](/docs/advanced/bindings) - import existing datapacks and generate Kotlin bindings (experimental). - [GitHub Actions Publishing](/docs/advanced/github-actions-publishing) - automate datapack publishing. - [Test Features (GameTest)](/docs/advanced/test-features) - testing datapacks with GameTest. - [Known Issues](/docs/advanced/known-issues) - workarounds and limitations. ## Contributing to Kore If you want to contribute to Kore itself, start with [Contributing to Kore](/docs/contributing/contributing), the hub for architecture, workflow, issue/PR, and maintainer docs. Useful contributor-facing internals: - [Architecture and Patterns](/docs/contributing/architecture-and-patterns) - module boundaries and recurring implementation patterns. - [Arguments Internals](/docs/concepts/arguments) - how the typed argument layer, resource wrappers, and literals fit together. ## Short tips - Keep builders small and reusable; prefer extracting predicates and modifiers. - Enable `prettyPrint` in [`Configuration`](/docs/guides/configuration) during development for readable JSON. - Reach for [`OOP Utilities`](/docs/oop/oop-utilities) when multiple gameplay features should share the same handles instead of re-building selectors and score names manually. - Use [`Components`](/docs/concepts/components) + [`Predicates`](/docs/data-driven/predicates) together for robust item checks and inventory management. - Reach for [`NBTs`](/docs/concepts/nbts) when you need to build a payload once and reuse it across commands, chat, or predicates. - Use [`Helpers Utilities`](/docs/helpers/utilities) to avoid reimplementing common glue code such as renderers, scheduler patterns, raycasts, or scoreboard-based maths. ## Known issues Check out the [Known Issues](/docs/advanced/known-issues) page for a list of known issues and workarounds. ## Community & source - **Repository**: [Kore](https://github.com/Ayfri/Kore) - **Starter template**: [Kore Template](https://github.com/Kore-Minecraft/Kore-Template) - **LLM-friendly documentation**: [llms.txt](https://kore.ayfri.com/llms.txt) | [llms-full.txt](https://kore.ayfri.com/llms-full.txt) - **AI Agents skills**: [Kore-Skill](https://github.com/Kore-Minecraft/Kore-Skill) (optional skills pack for AI-assisted Kore work) For hands-on examples, follow the doc pages above - most pages include runnable snippets and links to test cases in the repository. --- # Getting started ## Getting Started with Kore --- root: .components.layouts.MarkdownLayout title: Getting Started with Kore nav-title: Getting Started description: Step-by-step guide to create your first Minecraft datapack with Kore. Set up a Kotlin project, write type-safe commands and functions, generate the datapack, and test in-game. keywords: minecraft datapack tutorial, kore getting started, create datapack with kotlin, minecraft datapack generator tutorial, kore setup guide, kotlin datapack beginner, minecraft function generator, datapack development guide date-created: 2025-08-21 date-modified: 2026-07-02 routeOverride: /docs/getting-started position: 1 --- # Getting Started This guide takes you from zero to a real development workflow with Kore. Instead of stopping at a minimal "hello world," you will build a small but structured datapack, run it in-game, iterate quickly, and learn how to scale your project. If you already have solid datapack experience and want an architecture-first migration guide, jump to [From Datapacks to Kore](/docs/guides/from-datapacks-to-kore). ## What you will build By the end of this page, you will have: - A Kotlin project configured for Kore. - A datapack with metadata and multiple functions. - A simple game loop entry point (`load` + user-triggered functions). - A practical local development cycle to edit, regenerate, and test quickly. - A clean starting structure you can keep expanding. ## Prerequisites - [Java 21 (JDK 21)](https://jdk.java.net/archive/) or higher. - Gradle (wrapper recommended: `./gradlew`). - IntelliJ IDEA (recommended) or another IDE with Kotlin support. - Basic understanding of Minecraft datapacks (helpful but not required). ## Kotlin basics you need before Kore If you are new to Kotlin, do not worry. You only need a small subset to be productive with Kore. ### `val` and `var` - `val` means read-only reference (preferred by default). - `var` means mutable reference (use only when reassignment is needed). ```kotlin val packName = "starter_kore" var buildNumber = 1 buildNumber += 1 ``` ### Functions You declare functions with `fun`. Kore code is mostly function calls inside builders. ```kotlin fun greet(name: String): String { return "Hello, $name" } ``` ### Null safety Kotlin distinguishes nullable (`String?`) and non-null (`String`) types. ```kotlin val maybePlayer: String? = System.getenv("PLAYER_NAME") val displayName = maybePlayer ?: "Player" ``` Use: - `?.` for safe calls, - `?:` for fallback values (Elvis operator). ### Lambdas and builder blocks Kore uses Kotlin lambdas heavily: ```kotlin function("hello") { tellraw(allPlayers(), textComponent("Hello")) } ``` The `{ ... }` block is a lambda, and inside it Kore exposes a DSL context with helper functions. ### Extension functions (very important in Kore projects) Kotlin lets you add functions to existing types without inheritance. This is ideal for structuring large datapacks. ```kotlin fun DataPack.registerWelcome() { function("feature/welcome") { tellraw(allPlayers(), textComponent("Welcome")) } } ``` You can then call `registerWelcome()` inside your `dataPack {}` builder. ## Step 1: Create your project You have two ways to start. ### Option A: Use the Kore Template (recommended) The fastest option is the template repository, which is already configured for Kotlin + Gradle + Kore. 1. Open [Kore Template](https://github.com/Kore-Minecraft/Kore-Template). 2. Click "Use this template" (or clone directly). 3. Open it in IntelliJ IDEA. 4. Let Gradle sync. 5. Run the `main` function in `src/main/kotlin/Main.kt`. ### Option B: Add Kore to an existing Kotlin project If you already have a Kotlin project, add Kore manually. #### Core modules - `kore` - core DSL to generate datapacks. - `oop` - object-oriented gameplay abstractions. - `helpers` - helper utilities built on top of Kore. - `bindings` - experimental importer for existing datapacks. For your first datapack, use only `kore`. #### Gradle Kotlin DSL ```kotlin dependencies { implementation("io.github.ayfri.kore:kore:VERSION") } ``` #### Gradle Groovy DSL ```groovy dependencies { implementation 'io.github.ayfri.kore:kore:VERSION' } ``` #### Snapshot builds (latest unreleased changes) If you want bleeding-edge features: ```kotlin repositories { mavenCentral() maven("https://central.sonatype.com/repository/maven-snapshots/") } dependencies { implementation("io.github.ayfri.kore:kore:VERSION-SNAPSHOT") } ``` #### Kotlin compiler and JVM settings Kore relies on context parameters, which are stable since Kotlin 2.4. Make sure your `build.gradle.kts` contains: ```kotlin kotlin { jvmToolchain(25) } ``` ## Step 2: Write a first useful datapack Instead of a single command, create a tiny but realistic pack with: - metadata (`pack`), - one function for player feedback, - one function for setup behavior. If you are new to Kotlin syntax, read the code like this: - `val datapack = ...` stores the generated datapack object. - `dataPack("starter_kore") { ... }` creates a builder context. - each `function("...") { ... }` block writes one generated `.mcfunction` file. Create `Main.kt`: ```kotlin fun main() { val datapack = dataPack("starter_kore") { pack { description = textComponent("Starter datapack generated with Kore") } function("hello") { tellraw(allPlayers(), textComponent("Hello from Kore")) } function("setup") { tellraw(allPlayers(), textComponent("Setup complete")) } } datapack.generateZip() } ``` Run `main`, then put the generated zip into your world's `datapacks` folder. ## Step 3: Load and test in Minecraft 1. Open your world. 2. Run `/reload`. 3. Trigger the function: ```mcfunction /function starter_kore:hello ``` If everything is correct, chat displays your message. ## Step 4: Use `load {}` as your real entry point In Kore, using `load {}` is usually better than manually naming a startup function and wiring tags yourself. It directly creates and registers a function in `minecraft:load`, which makes your startup flow explicit and less error-prone. Most datapacks become easier to maintain when you separate: - initialization (`load`), - recurring logic (`tick` when needed), - feature functions (your own namespaced functions). Add this structure in Kore by defining dedicated functions and using consistent names: ```kotlin fun main() { val datapack = dataPack("starter_kore") { pack { description = textComponent("Starter datapack generated with Kore") } load("bootstrap") { tellraw(allPlayers(), textComponent("[starter_kore] datapack loaded")) function("feature/give_welcome") } function("feature/give_welcome") { tellraw(allPlayers(), textComponent("Welcome to the world")) } tick("runtime/checks") { // Keep tick lightweight. Route heavy logic to dedicated functions. } } datapack.generate() } ``` With this approach: - `load("bootstrap")` runs once after `/reload`. - `tick("runtime/checks")` runs every game tick. - `function("feature/...")` stays your reusable API surface. - folder-like names keep generated files organized as the project grows. ## Step 5: Organize code before it gets messy A common beginner mistake is placing everything in one `main` function. Prefer small helpers and focused files early. Example using extensions: ```kotlin fun DataPack.registerCoreFunctions() { function("load") { tellraw(allPlayers(), textComponent("[starter_kore] datapack loaded")) } } fun DataPack.registerFeatureFunctions() { function("feature/give_welcome") { tellraw(allPlayers(), textComponent("Welcome to the world")) } } fun main() { val datapack = dataPack("starter_kore") { pack { description = textComponent("Starter datapack generated with Kore") } registerCoreFunctions() registerFeatureFunctions() } datapack.generateZip() } ``` This pattern scales much better than one giant builder block. ## Step 6: Use a fast development loop During development, your loop should be: 1. Edit Kotlin code. 2. Re-run `main`. 3. Copy or regenerate output into your world datapack folder. 4. In-game: `/reload`. 5. Run the function you are testing. Tips: - Use `.generate()` when you want to inspect generated files locally. - Use `.generateZip()` when you want easy distribution. - Enable pretty JSON in [Configuration](/docs/guides/configuration) when debugging generated resources. ## Step 7: Build an advanced mini-pack with a custom enchantment At this point, create a pack that is closer to production structure: - startup flow with `load`, - runtime flow with regular functions, - one custom data-driven feature (a custom enchantment). Example: ```kotlin fun main() { val datapack = dataPack("starter_kore") { pack { description = textComponent("Starter datapack with a custom enchantment") } // 1) Runtime functions function("feature/welcome") { tellraw(allPlayers(), textComponent("Welcome to starter_kore")) } function("feature/show_vampiric_hint") { tellraw(allPlayers(), textComponent("Try the Vampiric enchantment on a sword")) } // 2) Startup entry point load("bootstrap") { function("feature/welcome") function("feature/show_vampiric_hint") } // 3) Custom enchantment definition (data-driven content) enchantment("vampiric") { description(textComponent("Vampiric")) supportedItems(Tags.Item.SWORDS) primaryItems(Tags.Item.SWORD_ENCHANTABLE) weight = 2 maxLevel = 3 minCost(20, 15) maxCost(50, 15) anvilCost = 8 slots(EquipmentSlot.MAINHAND) effects { // Bonus damage that scales by level damage { add(linearLevelBased(1, 1)) } // Chance to heal attacker on hit postAttack { applyMobEffect( PostAttackSpecifier.ATTACKER, PostAttackSpecifier.ATTACKER, Effects.INSTANT_HEALTH, ) { minAmplifier(0) maxAmplifier(0) minDuration(1) maxDuration(1) requirements { randomChance(linearLevelBased(0.08, 0.08)) } } } } } } datapack.generateZip() } ``` What this gives you: - a generated `data/starter_kore/enchantment/vampiric.json`, - startup player feedback via `minecraft:load`, - a clear split between command functions and data-driven definitions. To validate in-game: 1. Regenerate your datapack. 2. Put it in your world. 3. Run `/reload`. 4. Check logs/chat for load output. 5. Test enchantment behavior with commands or controlled test scenarios. ## Going beyond a minimal datapack Once your first commands work, move to data-driven features: - Add recipes, loot tables, predicates, and tags. - Create multiple function entry points per feature. - Separate "bootstrap" code from "gameplay" code. - Reuse helper functions to avoid duplicated command blocks. Good expansion ideas after the custom enchantment: - A welcome system with per-player conditions. - A starter kit function with basic inventory setup. - A scoreboard-based progression mechanic. - A custom recipe that complements your enchantment. - A balancing pass for enchantment costs, rarity, and max level. ## Kotlin tips that matter specifically in Kore projects - Prefer `val` by default; immutable declarations reduce accidental state issues. - Use extension functions on `DataPack` to keep your DSL composable. - If your IDE imports the wrong DSL symbol, qualify temporarily with `this.` in the builder scope, then fix the import. - Keep function names and file-like paths consistent (`feature/x`, `system/y`) to keep generated output predictable. - Re-declaring the same logical entry in Kore is idempotent: the last declaration wins. - Prefer `load {}` and `tick {}` builders over manual tag wiring for standard lifecycle hooks. ### Quick Kotlin learning resources - [Kotlin documentation](https://kotlinlang.org/docs/home.html) - [Kotlin null safety](https://kotlinlang.org/docs/null-safety.html) - [Kotlin extensions](https://kotlinlang.org/docs/extensions.html) - [Learn X in Y Minutes - Kotlin](https://learnxinyminutes.com/kotlin/) - [Kotlin Playground](https://play.kotlinlang.org/) ## Troubleshooting ### Unresolved Kore DSL symbols - Check that the dependency exists in the correct module. - Confirm you're on Kotlin 2.4 or higher (context parameters are stable there). - Refresh/sync Gradle in your IDE. ### Java/Kotlin toolchain errors - Confirm JDK 25 is installed and selected by Gradle. - Confirm `jvmToolchain(25)` is configured. ### Datapack generates but does not work in-game - Confirm the namespace/function path in `/function`. - Run `/reload` after every regeneration. - Check the world folder path and datapack placement. - Open logs and verify no JSON or command syntax error is reported. ## Recommended learning path after this guide Start here next: 1. [Creating a Datapack](/docs/guides/creating-a-datapack) 2. [Runtime Logic](/docs/concepts/runtime-logic) - how Kotlin `val`/`if`/`for` map to in-game scoreboards, storage, and `execute` 3. [Functions](/docs/commands/functions) 4. [Commands](/docs/commands/commands) 5. [Selectors](/docs/concepts/selectors) 6. [Cookbook](/docs/guides/cookbook) 7. [Recipes](/docs/data-driven/recipes) 8. [Enchantments](/docs/data-driven/enchantments) For the full index, see [Home](/docs/home). ## See also - [Kore Hello World](https://ayfri.com/articles/kore-hello-world/) - [Kore on GitHub](https://github.com/Ayfri/Kore) - [Kore on Maven Central](https://central.sonatype.com/search?q=io.github.ayfri.kore) - [Kore on Discord](https://discord.ayfri.com) - [Minecraft Wiki: Datapack](https://minecraft.wiki/w/Data_pack) ---