Skip to content

API Loot Tables

Piggo41 edited this page Oct 12, 2026 · 2 revisions

Loot tables

Lua API / World systems / Loot tables

Loot tables are reusable weighted item distributions. They are a shared world-system resource rather than a structure-only feature. A single table can be used by block drops, entity drops, and structure loot elements.

The public API registers and references loot tables. It does not currently provide a general roll() function for arbitrary gameplay Lua code.

Current consumers

Consumer How the table is used Randomness
Block drop Produces the stacks dropped for one block-drop request. Fresh runtime sample for every request.
Entity drop Produces the stacks dropped by a death or explicit entity:dropLoot() call. Fresh runtime sample for every event.
Structure loot element Produces contents for an inventory placed by a structure. Deterministic sample derived from world generation.

betamoon.lootTables:add(definition)

Registers one table and returns a typed reference. Define pools inline, provide a custom path, or omit both to use the default packaged asset at assets/<namespace>/loot_tables/<key-path>.json.

local materialDrops = betamoon.lootTables:add {
    key = "mymod:material_drops",
    pools = {
        {
            key = "supplies",
            rolls = { min = 3, max = 6 },
            entries = {
                {
                    type = "item",
                    weight = 4,
                    stack = {
                        item = "minecraft:item/ingot_iron",
                        count = { min = 1, max = 4 }
                    }
                },
                { type = "item", weight = 2, stack = { item = "minecraft:item/bread" } },
                { type = "empty", weight = 1 }
            }
        }
    }
}

assert(materialDrops.key == "mymod:material_drops")

Field definitions

Field Behavior
key Required canonical namespace:path key. It must be unique among loot tables.
path Optional mod-package path beginning with assets/, for example assets/mymod/loot_tables/special.json. Mutually exclusive with pools.
pools Optional inline pool list. Mutually exclusive with path.

betamoon.lootTables:get(key) returns a reference or nil; getRequired(key) raises an error when absent. References provide a readable key field and can be used anywhere a loot table field is accepted.

Runtime block and entity drops

Use the same registered table reference for any number of block and entity declarations:

local commonLoot = betamoon.lootTables:add {
    key = "mymod:common_drops",
    pools = {
        {
            key = "main",
            rolls = 1,
            entries = {
                { type = "item", weight = 3, stack = { item = 265 } },
                { type = "empty", weight = 1 }
            }
        }
    }
}

local blockDrops = { table = commonLoot }
local entityDrops = { table = commonLoot }

The drops field also accepts { pools = { ... } } to declare the same pool syntax inline. pools and table are mutually exclusive. Block and entity drops do not use structure placement seeds: every block-drop request, entity death, and explicit entity:dropLoot() call takes a fresh sample from the world's runtime random stream.

The older list of { item, min, max, chance, damage } entries remains available as a compact shorthand. It samples every listed entry independently rather than selecting weighted entries from pools.

Structure inventory contents

A structure loot element can use the same registered tables and inline pools. Structures additionally control the destination inventory, slot selection, handling of existing contents, and overflow behavior. Those placement-specific fields belong to the structure element rather than to the reusable loot table.

See structure inventory loot for the structure syntax and its inventory policies.

JSON assets

JSON and Lua declarations produce the same validated model.

{
  "format": "betamoon_loot_table",
  "pools": [
    {
      "key": "main",
      "rolls": 2,
      "entries": [
        {
          "type": "item",
          "weight": 3,
          "stack": { "item": "minecraft:item/coal", "count": { "min": 1, "max": 4 } }
        },
        { "type": "empty", "weight": 1 }
      ]
    }
  ]
}

Register a default-path asset with only its key:

local materialDrops = betamoon.lootTables:add { key = "mymod:material_drops" }

Files must be strict UTF-8 JSON, are limited to 1 MiB, and reject unknown fields. A malformed or missing asset rejects the declaration when the mod loads.

Pools, rolls, and weights

Pool field definitions

Field Behavior
key Required stable lowercase identifier, unique within this table.
rolls Nonnegative integer or inclusive { min, max }; defaults to 1. Both range fields are required.
entries Required nonempty weighted entry list.

Every pool runs in declaration order. For each pool, BetaMoon samples rolls once and then performs that many independent weighted selections with replacement. An entry's probability is its weight divided by the sum of all weights in that pool.

For example, if pool supplies samples two rolls, it makes two selections and may select the same entry twice. A second pool then runs and appends its results. An item appends one stack, an empty entry appends nothing, and a table entry runs the complete referenced table once and appends every stack it emits. One parent roll can therefore produce several stacks.

Entry definitions

Type Fields Behavior
item stack, optional weight Emits one sampled stack.
empty Optional weight Emits nothing for that roll.
table table, optional weight Runs another registered table. Lua accepts its key or typed reference.

weight defaults to 1 and must be positive. Missing nested references, cycles, excessive nesting, and excessive worst-case output reject the declarations when mods load.

Stack definitions

stack = {
    item = 265,
    count = { min = 1, max = 4 },
    damage = 0
}
Field Behavior
item Required numeric item/block-item ID or supported item name. Numeric IDs are unambiguous.
count Positive integer or inclusive { min, max }; defaults to 1. It may not exceed that item's own stack limit.
damage Nonnegative integer or inclusive { min, max }; defaults to 0. Represents durability or subtype metadata.

Count and damage are sampled independently. Only identity, count, and damage are supported; arbitrary item NBT, enchantments, custom names, and Lua callbacks are not part of this format. A string currently resolves through Minecraft's available item names after optional namespace/type-prefix normalization. The namespace does not disambiguate two items with the same name; use numeric IDs when names could collide.

Randomness

The consumer determines how a loot table receives randomness:

  • Block and entity drops start every evaluation with a fresh value from the world's runtime random stream. Repeated block breaks, deaths, and entity:dropLoot() calls therefore resample the table.
  • Structure loot derives its sample from the world seed and stable placement information. Regenerating the same structure with the same definitions and seed produces the same result.

The shared table definition does not change between these uses. Only the source of randomness differs.

For structure loot, the deterministic inputs also include the loot-element key and position, table definition, pool key, and roll number. Stable pool and element keys keep unrelated structure-generation random streams independent. Pools append results in declaration order; a structure pairs that order with its destination slot order.

Changing a table used by an unfinished saved regional structure prevents that structure from mixing old and new definitions. Restore the matching declaration to complete it. This saved-plan protection is specific to regional structure generation and does not apply to runtime block or entity drops.

Validation limits

Limit Maximum
Pools per table 16
Entries per pool 64
Sum of every pool's maximum direct rolls 64
Nested table-reference levels 8
Worst-case emitted stacks after expanding nested references 128

Worst-case output is validated instead of average output so every legal random result remains bounded. These limits apply equally when a table is consumed by a block, entity, or structure. Structure-only inventory controls are documented under structure inventory loot.

Clone this wiki locally