Skip to content

Data resources

Not everything a pack needs is a command. Predicates, loot tables, advancements, recipes, and item modifiers are JSON files the game reads. Helix builds them from typed value trees and registers them on the Datapack, handing back a reference you pass around - you never write the file path or the id string twice.

Every registrar follows the same shape: dp.<kind>(name, def) writes the file and returns a typed handle.

RegistrarBuildsReturns
dp.predicate(name, def)a Predicate treePredicateRef
dp.lootTable(name, def)a loot tableLootTableRef
dp.advancement(name, def)an advancementAdvancement
dp.recipe(name, def)a recipeRecipeRef
dp.itemModifier(name, def)an item modifierItemModifierRef

Predicates: the "over NBT" workhorse

A Predicate is a composable condition tree. Its reason to exist: express an entity-state check - including NBT - once, as a typed, engine-evaluated, referenceable file, instead of inlining nbt={…} into every selector.

Leaf conditions are static factories (Predicate.entity, .scores, .blockState, .location, .matchTool, .holding, .weather, .randomChance, .reference), and they compose with .and() / .or() / .not() (or Predicate.all/any/not):

ts
import { Datapack, v26_2, Selector, Predicate, Nbt, Short } from "helix";

const dp = new Datapack("checks", v26_2);

// Register once…
const focused = dp.predicate(
  "focused",
  Predicate.entity({ flags: { is_sneaking: true }, nbt: Nbt({ SleepTimer: Short(0) }) })
    .and(Predicate.scores({ combo: { min: 3 } })),
);

const fn = dp.createFunction("reward");
fn.build((ctx) => {
  // …reference by handle anywhere a predicate is accepted.
  ctx.tellraw(Selector.allPlayers().predicate(focused), "focused bonus!");
});

▶ Open in playground

Compiled output - the real files helix emits for the code above:

txt
tellraw @a[predicate=checks:focused] {"text":"focused bonus!"}
json
{
  "condition": "minecraft:all_of",
  "terms": [
    {
      "condition": "minecraft:entity_properties",
      "entity": "this",
      "predicate": {
        "nbt": "{SleepTimer:0s}",
        "flags": {
          "is_sneaking": true
        }
      }
    },
    {
      "condition": "minecraft:entity_scores",
      "entity": "this",
      "scores": {
        "combo": {
          "min": 3
        }
      }
    }
  ]
}

The PredicateRef (focused) flows into two places, both by handle rather than id string:

  • Selector.predicate(ref) - @a[predicate=checks:focused], checked engine-side.
  • predicateCheck(ref) for ctx.if(...) - execute if predicate checks:focused run ….

Items are their own predicate

Because an Item lowers itself to both a give-stack and an item_predicate, a check built from an item matches the item you granted by construction:

ts
import { Datapack, v26_2, Selector, Item, Enchantment, Predicate } from "helix";

const dp = new Datapack("checks", v26_2);

const wand = Item.STICK.named("Wand").enchant(Enchantment.KNOCKBACK, 1);

const holdingWand = dp.predicate("holding_wand", Predicate.holding(wand));

const fn = dp.createFunction("cast");
fn.build((ctx) => {
  ctx.tellraw(Selector.allPlayers().predicate(holdingWand), "you feel a spark");
});

▶ Open in playground

Compiled output - the real files helix emits for the code above:

txt
tellraw @a[predicate=checks:holding_wand] {"text":"you feel a spark"}
json
{
  "condition": "minecraft:entity_properties",
  "entity": "this",
  "predicate": {
    "equipment": {
      "mainhand": {
        "items": "minecraft:stick",
        "components": {
          "minecraft:custom_name": {
            "text": "Wand"
          },
          "minecraft:enchantments": {
            "minecraft:knockback": 1
          }
        }
      }
    }
  }
}

Predicate.matchTool(item) is the loot/mining-context sibling; Predicate.holding(item, slot) matches an equipment slot on an entity.

Going further

The loot/recipe/advancement builders follow the same "build a typed *Def, register, get a ref" pattern - see them under Data resources in the API reference. For raw JSON the typed builders don't model yet, dp.registryFile(...) is the one sanctioned escape hatch, and validateDatapack checks emitted JSON against the vanilla schema for your target version.

Released under the MIT License · Credits