Skip to content

API Worldgen Structure Loot

Piggo41 edited this page Oct 12, 2026 · 2 revisions

Structure inventory loot

Lua API / World generation / Structure documents / Inventory loot

A loot element decorates an inventory block after that block and its tile entity exist. It does not place the chest or other inventory itself; the target block must be part of the same resolved structure branch.

Choosing a content mode

Exactly one content mode is required:

Mode Use it for
items Exact stacks in exact slots. No random selection.
pools Random content private to this one structure element.
table Random content shared through a registered loot table.

Randomized pools and table modes require the loot element's own stable key. Do not confuse it with a loot-table registration key or a pool key: all three protect a different deterministic random decision.

Fixed items

{
  "type": "loot",
  "pos": [0, 1, 0],
  "items": [
    {
      "slot": 0,
      "stack": { "item": 265, "count": 3, "damage": 0 }
    },
    {
      "slot": 4,
      "stack": { "item": 297, "count": 1 }
    }
  ],
  "existing": "require_empty"
}

Field definitions

Field Behavior
pos Inventory block coordinate in structure-local space.
items Nonempty exact { slot, stack } list. Slot indexes are zero-based.
existing require_empty by default; also preserve or replace.

For fixed items, require_empty checks only the explicitly targeted slots. preserve skips an occupied target slot. replace overwrites targeted slots but does not clear unrelated inventory slots. slots and overflow are invalid in fixed mode.

An invalid slot, incompatible target, or stack exceeding the target inventory's stack limit rejects the transaction.

Inline randomized pools

{
  "type": "loot",
  "key": "dungeon_supplies",
  "pos": [0, 1, 0],
  "pools": [
    {
      "key": "food",
      "rolls": { "min": 1, "max": 2 },
      "entries": [
        { "type": "item", "weight": 3, "stack": { "item": 297, "count": 1 } },
        { "type": "empty", "weight": 1 }
      ]
    }
  ],
  "slots": "random_empty",
  "existing": "require_empty",
  "overflow": "reject"
}

Inline pools use the same pool, entry, stack, roll, and limit rules as reusable loot tables.

Reusable loot table

{
  "type": "loot",
  "key": "main_chest",
  "pos": [0, 1, 0],
  "table": "mymod:dungeon_supplies",
  "slots": [0, 1, 2, 3, 4, 5],
  "existing": "require_empty",
  "overflow": "reject"
}

Register mymod:dungeon_supplies through betamoon.lootTables:add before the structure declarations are validated.

Random slot policies

Field Default Values
slots random_empty random_empty, ordered_empty, or an explicit zero-based integer list.
existing require_empty require_empty, preserve, or replace.
overflow discard discard or reject.

Random loot is assigned in this order:

  1. Run every pool in declaration order and produce an ordered stack list.
  2. Build the eligible slot set from all inventory slots or the explicit list.
  3. Apply the existing-content policy.
  4. Shuffle slots deterministically for random_empty and explicit lists, or retain ascending order for ordered_empty.
  5. Put one generated stack in each available slot.
  6. Discard excess stacks or reject the complete transaction according to overflow.

Important details:

  • existing = "replace" clears every eligible slot before insertion, including eligible slots that receive no new stack.
  • existing = "require_empty" checks every eligible slot even if random generation emits nothing.
  • generated stacks are not merged with existing stacks or with each other;
  • overflow = "discard" deletes excess generated results; it does not drop them into the world;
  • explicit slot indexes can only be checked against the actual inventory size during placement.

Use overflow = "reject" while authoring when silent loss could hide an undersized inventory.

Stack definitions

{
"stack": {
  "item": 265,
  "count": { "min": 1, "max": 3 },
  "damage": 0
}
}
Field Behavior
item Numeric registered item/stack ID, or a supported registered-name string.
count Exact positive integer or inclusive { min, max }; defaults to 1 and cannot exceed the item's stack limit.
damage Exact nonnegative integer or inclusive { min, max }; defaults to 0.

String lookup accepts a registered item name with an optional namespace and item/ or block/ prefix. The namespace does not disambiguate two items with the same name; use numeric IDs when names could collide. Only identity, count, and damage/subtype metadata are supported; arbitrary item NBT, enchantments, custom names, and Lua callbacks are not.

Compatibility, failure, and rollback

A compatible target is an inventory tile at the transformed coordinate. The inventory block and its loot element must resolve together—for conditional chests, keep both elements inside the same chance or choice branch.

Reason Meaning
loot_target_missing No compatible inventory exists after planned blocks are placed.
loot_inventory_size A slot is outside the inventory or its stack limit cannot accept the stack.
loot_existing_contents require_empty found an occupied eligible slot.
loot_overflow Generated stacks did not fit and overflow = "reject".
loot_mutation_failed The inventory failed during mutation.

On failure, BetaMoon restores the previous blocks, typed tile data, and inventory contents for that transaction. A local placement is one transaction. A regional structure is transactional per intersecting chunk slice, not across all chunks in the complete regional layout.

Next: loot tables.

Clone this wiki locally