Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 38 — Villager Trades and Other Data-Driven Registries

What You’ll Build

Way back in Chapter 7 you learned that a data pack works by adding files to registries (the game’s master lists of one kind of thing each) and that some registries are dynamic, meaning data packs are allowed to add to them. Since then you’ve filled a lot of those lists: the recipe registry, the loot table registry, the advancement registry, the tag registries. This chapter pulls back and shows you the whole map, the full folder list of every registry a data pack can write to, and then teaches the most interesting new one in modern Minecraft from top to bottom.

By the end you’ll have read the complete registry map, and you’ll have built a working sulfur_cube_archetype: a JSON file that defines how a sulfur cube behaves, whether it floats, what it eats, how hard it hits, and whether it explodes. You’ll attach that behavior to an item, add a custom banner pattern definition, and take a guided tour of how villager trades became data-driven (the villager_trade and trade_set folders, grouped by trade tags). You’ll also learn something just as important: which registries the book can teach you to fill in today, and which ones the game only names, so you know exactly where to look when you need them.

Figure (to be captured). a custom sulfur cube bouncing in water next to a banner showing a custom forge-mark pattern

The Registry Map

Open your data pack’s data/mypack/ folder in your mind. Every folder you’ve made so far (function, recipe, loot_table, advancement, tags/) sits at the same level. Each one is a registry folder: a folder named after a registry, whose .json files become entries in that registry.

Registry folder. A folder under data/<namespace>/<registry name>/. The rule is exact: the file data/<namespace>/<registry name>/<path>.json is loaded into the registry name registry with ID <namespace>:<path>. So a file at data/mypack/recipe/forge_blade.json becomes the recipe mypack:forge_blade. The folder name is the registry name. (Both the registry name and the path can contain slashes, which just makes extra sub-folders.)

That one rule is the whole secret of data packs. You already know it in your hands; now you’ll see the full list of folder names you’re allowed to use. Here is the registry folder list, straight from the Data pack page (worldgen folders are grouped at the bottom and belong to Part XI):

data/<namespace>/
  function                  .mcfunction files with lists of commands
  structure                 .nbt files defining a saved structure of blocks
  tags/                     collections of things (one sub-folder per registry)
  advancement               definitions of advancements
  banner_pattern            * textures and names to use for banner patterns
  cat_variant               * textures and spawn conditions of cat variants
  chat_type                 * formatting of chat messages
  chicken_variant           * textures and spawn conditions of chicken variants
  cow_variant               * textures and spawn conditions of cow variants
  damage_type               * attributes of damage and death messages
  dialog                    * definitions of dialogs            (Chapter 39)
  dimension                 * biome layout and terrain of dimensions
  dimension_type            * properties of dimensions
  enchantment               * enchantment effects, supported items, level cost, etc.
  enchantment_provider      * selection of enchantments for specific uses
  frog_variant              * textures and spawn conditions of frog variants
  instrument                * instruments for goat horns
  item_modifier             loot functions used to modify items
  jukebox_song              * jukebox song definitions
  loot_table                loot from mobs, blocks, chests, etc.
  painting_variant          * size and texture of paintings
  pig_variant               * textures and spawn conditions of pig variants
  predicate                 tests for specific conditions
  recipe                    recipes for crafting, smelting, etc.
  sulfur_cube_archetype     * defines Sulfur Cube archetypes
  test_environment          * groups GameTests with their preconditions
  test_instance             * a test the GameTest framework can run
  timeline                  * events/attributes according to the time of day
  trade_set                 * a set of trades selected by villagers / wandering traders
  trial_spawner             * configuration of trial spawners
  trim_material             * colors, ingredients, name of trim materials
  trim_pattern              * textures and name of trim patterns
  villager_trade            * trades of villagers and wandering traders
  wolf_sound_variant        * sound variants of wolves
  wolf_variant              * textures and spawn conditions of wolf variants
  world_clock               * clocks used to keep track of internal time
  worldgen/                 * the world-generation registries          (Part XI)

That little red * is doing real work. Let’s talk about it.

Experimental-settings folder (the *). Some folders are marked with an asterisk because having a valid file inside any of them will mark the data pack as using experimental settings. A pack that uses experimental settings shows a warning screen when you open the world in singleplayer, and it cannot be uploaded to Realms. For example: defining a custom instrument inside the instrument/ folder counts as experimental, but doing the same thing through item components does not.

So most of the shiny new registry folders in that list (including sulfur_cube_archetype) are experimental folders. That’s not a reason to avoid them. It just means: expect the warning screen, and remember the rule below in What Can Go Wrong about reloading them.

Modern Minecraft. Older tutorials talk about “experimental features” as if they’re half-broken betas you toggle on. In modern Minecraft, an experimental setting is simpler than that: it’s just a flag the game raises because your pack put a file in one of these folders. The reason is precise: internally, most experimental settings use dynamic registries, and dynamic registries can’t be hot-reloaded (more on that at the end of the chapter). The feature itself is shipped and real; the label is about how the game loads it, not about whether it works.

Trades Are Data-Driven Now

Here’s a change worth pausing on. For most of Minecraft’s life, what a villager would sell you was baked into the program. Look at the registry map again: there are now three trade-related entries, villager_trade, trade_set, and (under tags/) villager trade tags.

Modern Minecraft. If you followed an old guide that summoned villagers with giant Offers NBT blobs to fake custom trades, that still describes the runtime shape: when the trade menu is first opened, the game generates an Offers compound holding a Recipes list, where each recipe has a buy cost item, an optional buyB second cost, a sell item, a maxUses, and so on. But you no longer have to hand-build that. The trades themselves are now data pack files.

The three pieces fit together like this, and the Data pack folder list tells us what each one is for:

  • villager_trade (the villager_trade/ folder) — “Trades of villagers and wandering traders.” One file describes one trade offer.
  • trade_set (the trade_set/ folder) — “A set of trades selected by villagers and wandering traders.” A group of trades chosen together.
  • villager trade tag (under tags/) — the grouping and selection layer. In one line: a villager trade tag is a group of villager trades.

Villager trade tag. A tag, exactly like the block and function tags you built in Chapter 14 (a .json file with a values list), that groups villager trades together. The vanilla trade tags follow a clear pattern: one tag per profession and level, like armorer/level_1, cleric/level_3, farmer/level_5, plus special ones such as common_smith/level_1 (shared smith trades) and wandering_trader/common. A villager who is a level-3 cleric draws its offers from the cleric/level_3 trade tag.

So the modern pipeline is: you write trade offers as villager_trade (and group them with trade_set), and a trade tag like #minecraft:villager_trade/cleric/level_3 decides which villager gets them. To add a cleric trade, you’d add your trade to that tag: the same “extend a vanilla tag without replacing it” move you learned in Chapter 14.

One thing this chapter won’t do is make you memorize the exact JSON field names inside a villager_trade or trade_set file. They’re new 26.x registries, and a file format like that is the kind of detail you should read off a reference each time, not carry in your head. So when you build custom trades for real, open the villager_trade / trade_set page on the live wiki (or copy a vanilla example file) and write the field names you find there.

What you can carry in from here is the shape of the idea. The Villager page’s runtime Offers/Recipes data (buy, buyB, sell, maxUses, priceMultiplier, demand, rewardExp, xp) tells you what a trade contains conceptually: a cost (sometimes two), a result, and limits on how often it can be used. That’s the entity’s saved NBT rather than the pack file, so don’t copy it field-for-field, but it’s a faithful mental model of what your trade file will need to express.

That’s the working rule for this whole chapter, and it’s the one that keeps your packs correct: when a registry is brand-new and its file format isn’t settled documentation yet, this book teaches you what the folder is for and points you at the reference for the exact fields, rather than guessing them. Now let’s build the one new registry we can walk all the way through.

Walkthrough: A Sulfur Cube Archetype

The sulfur cube is a 26.x entity, and it’s the perfect teaching example because its whole behavior lives in a data pack file. Sulfur cubes use “archetypes” to define their behavior, and those archetypes are stored as JSON files within a data pack in the path data/<namespace>/sulfur_cube_archetype.

sulfur_cube_archetype. A registry file defining how a sulfur cube of that archetype behaves: what attributes it has, whether it floats, what it eats, how it damages things it touches, whether it explodes, how knockback affects it, and what sounds it makes. The file’s ID is <namespace>:<path>, just like every other registry entry.

Let’s build one called mypack:bouncing_bomb: a cube that floats in water, eats gunpowder, lightly shoves anything it touches, and explodes when ignited. Here is the complete file. Every field in it comes straight from the JSON format for this registry, and after the listing we’ll walk through each one.

mypack/data/mypack/sulfur_cube_archetype/bouncing_bomb.json

{
  "attribute_modifiers": [
    {
      "attribute": "minecraft:max_health",
      "id": "mypack:bouncing_bomb_health",
      "amount": 4.0,
      "operation": "add_value"
    }
  ],
  "buoyant": true,
  "contact_damage": {
    "amount": 2.0,
    "attribute_to_source": true,
    "damage_type": "minecraft:mob_attack"
  },
  "explosion": {
    "causes_fire": false,
    "fuse": 30,
    "power": 3
  },
  "items": "minecraft:gunpowder",
  "knockback_modifiers": {
    "horizontal_power": 1.5,
    "vertical_power": 1.0
  },
  "sound_settings": {
    "hit_sound": "minecraft:entity.tnt.primed",
    "push_sound": "minecraft:block.sand.step",
    "push_sound_cooldown": 0.5,
    "push_sound_impulse_threshold": 0.1
  }
}

Now the field-by-field tour. The root object has these seven keys:

  • attribute_modifiers — “A list of attribute modifiers to apply to sulfur cubes of this archetype.” You met attribute modifiers on items back in Chapter 23, and the shape here is the same family: each modifier is an object with an attribute (the id of the attribute to modify, here minecraft:max_health), a unique id for the modifier, an amount, and an operation. There are three operations: add_value, add_multiplied_base, and add_multiplied_total. We used add_value to give the cube +4 health.

  • buoyant — a true/false value: “Whether or not a sulfur cube of this archetype floats in liquids.” We set it true, so our bomb bobs on top of water instead of sinking.

  • contact_damage — this one is optional: if present, sulfur cubes of this archetype will damage entities on contact. Inside it: amount (the damage caused, here 2.0, one heart), attribute_to_source (whether the damage is attributed to the sulfur cube, which affects who “killed” the victim), and damage_type (which damage type to use; we picked minecraft:mob_attack).

  • explosion — also optional: “if present, sulfur cubes of this archetype can explode when ignited.” Three fields: causes_fire (true/false: does the blast light fires; we said no), fuse (the fuse time in game ticks; 30 ticks is 1.5 seconds), and power (the power of the explosion; 3 is roughly creeper-sized).

  • items — “An item or an item tag containing all items that can be fed to sulfur cubes of this archetype.” We gave a single item, minecraft:gunpowder. Because it accepts an item tag too, you could instead write "#minecraft:coals" (a tag, with the # you learned in Chapter 14) to let the cube eat any coal-like item.

  • knockback_modifiers — “Modifiers to the knockback received by sulfur cubes of this archetype,” with horizontal_power and vertical_power. These scale how far the cube gets shoved when it’s hit; 1.5 horizontal makes it skittish and easy to push around.

  • sound_settings — the sounds the cube makes, with four fields: hit_sound (a sound event played when the cube is hit), push_sound (played when it’s pushed), push_sound_cooldown (the cooldown for the push sound, in seconds), and push_sound_impulse_threshold (the smallest impulse needed to trigger the push sound). The two sound fields take sound-event ids of the kind you worked with in Chapter 30.

Save the file and /reload. Because sulfur_cube_archetype/ is an experimental folder, you may see the experimental-settings warning when you open the world. That’s expected (and there’s a reloading nuance in What Can Go Wrong). Your archetype now exists in the registry as mypack:bouncing_bomb, ready for any sulfur cube assigned to it.

Under the Hood (skippable). The wiki itself is still pinning down the precise in-game effect of some of these settings: exactly which behavior each archetype setting controls is not fully nailed down yet. The fields are documented and correct (that’s what we built); the exact gameplay feel of, say, a particular knockback_modifiers value is the kind of thing you confirm by testing in-game. That’s normal for a brand-new feature.

Putting the Cube Inside an Item

A sulfur cube can hold an item, and there’s an item component for that: sulfur_cube_content.

sulfur_cube_content. An item component storing “the item stored inside the sulfur cube.” The game adds gray italic tooltip text reading “Contains: <item>” on an item, and on a sulfur cube entity it doubles as the body armor slot. It’s the bridge between an ordinary item and the sulfur cube’s contents.

This is an item component, so you set it with the bracket syntax from Chapter 21. Here’s a /give that hands you a sulfur cube item carrying a diamond inside it (typed in chat, so it keeps its leading /):

/give @s minecraft:sulfur_cube[minecraft:sulfur_cube_content={id:"minecraft:diamond",count:1}]

Heads-up on the item id. The component name sulfur_cube_content is exact, but a carrier item’s resource location is the kind of thing to confirm in-game rather than take on faith from a book. The line above uses the natural minecraft:sulfur_cube; if your game rejects it, turn on advanced tooltips (F3+H) and read the real id straight off a sulfur cube in your inventory.

A Real Banner Pattern Definition

A few of these registries (besides the sulfur cube) have fully documented fields, and banner_pattern is the simplest, so let’s build one to prove the pattern.

Banner pattern definition (banner_pattern). A banner pattern is a shape that can be added to a banner, defined by files in the banner_pattern folder. The format has just two fields: asset_id (the resource location for the texture asset) and translation_key (the translation key used to display the banner’s tooltip).

mypack/data/mypack/banner_pattern/forge_mark.json

{
  "asset_id": "mypack:forge_mark",
  "translation_key": "block.minecraft.banner.forge_mark.mypack"
}

The asset_id points at a texture you’d supply on the resource-pack side (the kind of art file you learned to place in Chapter 29); the translation_key is the name that shows in the banner’s tooltip. That’s the entire file, and it’s a clean example of the rhythm you’ll use for any documented registry: read the field list off its page, write exactly those fields, nothing invented.

The Rest of the Map: What Each Folder Is For

The registry map listed more folders than any one project will use. You don’t need the full field list for every one to be productive. You need to know what each folder is for and how to recognize when a build calls for it. Here’s that tour. When you’re ready to author one of these files, open the matching page on the live wiki, or crack open a vanilla data pack and read a real example, and write exactly the fields you find there: the same read-the-fields-then-write-them move you used above.

  • enchantment_provider — a “selection of enchantments for specific uses” (for example, choosing which enchantment a particular tool or loot source applies).
  • jukebox_song — “jukebox song definitions.” Its partner is the item component jukebox_playable, which is fully documented: it points an item at a jukebox song definition to play when inserted into a jukebox, and adds the song’s artist and title to the tooltip. So you already know exactly how an item uses a song.
  • instrument — “instruments for goat horns.” Its partner component instrument is documented (it shows the instrument description in an item’s tooltip), and defining an instrument in this folder counts as experimental while doing it through the component does not.
  • painting_variant — “size and texture of paintings.” Its partner component painting/variant sets which painting an item shows, displaying the name, artist, and size in the tooltip.
  • trim_material / trim_pattern — “colors, ingredients, and name of materials for trimming” and “textures and name of patterns for trimming.” You already met armor trims from the item side: the trim component back in Chapter 24, and the smithing_trim recipe type in Chapter 15; these two folders are where the materials and patterns themselves are defined.
  • trial_spawner — “configuration of trial spawners” (the wave and reward setup behind trial chambers).
  • timeline — “a timeline which specifies events and attributes according to the time of day.”
  • world_clock — “clocks used to keep track of internal time.”

Notice the pattern: several registries come in pairs, a definition folder (the registry) plus an item component that points at it. jukebox_songjukebox_playable, painting_variantpainting/variant, instrumentinstrument, banner_pattern ↔ the banner’s pattern data, sulfur_cube_archetypesulfur_cube_content. When you meet a new registry, ask “what component points at it?” The component side is usually the better-documented half, and it tells you half the story for free before you ever open the definition file.

Practice

  1. A gentle floating cube. Make a second archetype, mypack/data/mypack/sulfur_cube_archetype/water_buddy.json, that floats (buoyant: true) and eats bread ("items": "minecraft:bread") but has no contact_damage and no explosion (just leave those two optional fields out entirely, since both are optional). Give it a gentle sound_settings using soft sound events. Reload and confirm it loads with no errors. This proves you understand which fields are required and which you can omit.

  2. Your own banner pattern. Write mypack/data/mypack/banner_pattern/your_mark.json with an asset_id of mypack:your_mark and a translation_key you choose. You don’t need the texture to exist yet for the file to load. You’re practicing the definition file, the same two-field shape every banner pattern uses.

  3. Read the map. Without looking back, list three registry folders that are marked experimental (*) and one that is not. Then, for one registry the chapter only points you toward (say trial_spawner), write one sentence saying what its folder is for (straight from the map) and one sentence saying where you’d go to find its actual fields. This is the skill the chapter is really teaching: knowing the difference between “I can build this now” and “I know what this is and where to learn it.”

What Can Go Wrong

The experimental-settings warning screen appears. As soon as you put a valid file in an experimental folder (like sulfur_cube_archetype/), the game flags your whole pack as using experimental settings and warns you when you open the world in singleplayer. This is expected, not an error, so click through it. Just remember the two consequences: the warning will keep appearing, and you won’t be able to upload that world to Realms.

/reload doesn’t pick up your archetype change. This is the big one. Experimental settings use dynamic registries, and any changes regarding these features cannot be loaded using the reload command: the world must be exited and reopened (singleplayer), or the server rebooted (multiplayer) for the changes to take effect. So if you edit bouncing_bomb.json and /reload seems to do nothing, that’s not a bug: fully exit the world and re-enter (or reboot the server). Compare that to recipes, loot tables, and tags from earlier chapters, which /reload can refresh live. Dynamic-registry folders are the exception.

A path typo silently makes the wrong ID. Remember the registry rule: the folder name is the registry name and the file path is the ID. If you save your archetype to data/mypack/sulfur_cube_archetypes/ (plural) or misspell the folder, the game won’t find a registry by that name and your file just won’t load as an archetype, often with no obvious complaint. Double- check the folder is spelled exactly as it appears in the map: sulfur_cube_archetype, singular. The same goes for banner_pattern, villager_trade, and the rest: copy the names from the map, don’t trust your memory.