Skip to content

Items and item stacks

Status: Partly implemented. A mod item is a stack of its base item (vanilla_fallback, else copy_from, else minecraft:paper) with custom_data {clight:"<id>"}, item_model "<id>" (its own model on Celestial clients, and on vanilla clients with the mod’s resource pack), item_name and max_stack_size. /give @s <mod>:<item> works, mod items can drop from loot tables, recipes can use and make them, creative_tab puts them in a creative tab, and the use behaviour runs. Default components from code, the larger behaviour table and component access on stacks are Planned.

Function tables: registry, stack, inventory functions on entity. Players and inventories: Players.

Item descriptor

typedef struct cl_item_desc {
    uint32_t  struct_size;
    cl_str    id;                         // "my_mod:ruby" (your own namespace only)
    int32_t   max_stack_size;             // default 64, 1..99
    cl_str    block;                      // this item places that mod block (set automatically by cl_block_desc.item)
    cl_str    copy_from;                  // the base item when vanilla_fallback is empty
    const cl_item_behavior* behavior;     // optional; must stay valid (static storage)
    cl_str    vanilla_fallback;           // the base item ("minecraft:emerald")
    cl_str    creative_tab;               // the creative tab it shows in ("minecraft:ingredients"); empty = none
    void*     user;                       // passed to behaviour callbacks as ctx->user
} cl_item_desc;
/* cl_item_desc d = CL_ITEM_DESC_INIT; */

The name comes from the lang key item.<ns>.<path> (block.<ns>.<path> for block items), the look from assets/<ns>/items/<path>.json and models/item/<path>.json.

creative_tab names a vanilla category tab (minecraft:building_blocks, colored_blocks, natural_blocks, functional_blocks, redstone_blocks, tools_and_utilities, combat, food_and_drinks, ingredients, spawn_eggs; no namespace means minecraft:). The item shows at the end of that tab, after the vanilla items, in registration order, and in the search tab. Like vanilla, the client builds the tab contents itself. Block items made by cl_block_desc.item have no tab; register the item yourself with block and creative_tab to show it.

Behaviour

typedef struct cl_item_ctx { uint32_t struct_size; cl_level level; cl_item_stack stack; cl_entity entity; cl_hand hand; void* user; } cl_item_ctx;
typedef struct cl_item_behavior {
    uint32_t       struct_size;
    cl_item_use_fn use;       // (ctx, cl_interaction_result* out): right-click, server tick
} cl_item_behavior;

Return CL_OVERRIDE_HANDLED with *out set, or CL_OVERRIDE_CALL_ORIGINAL to let the base item act. ctx->stack is borrowed. In Lua return "success" (or another result) to handle it, nothing to pass:

cl.items.register{
  id = "healing_gem", vanilla_fallback = "minecraft:emerald",
  behavior = {
    use = function(ctx)
      ctx.entity:set_health(20)
      ctx.entity:held_item(ctx.hand):shrink(1)   -- uses one up (not in creative)
      return "success"
    end,
  },
}

Item stacks (owned)

cl_item_stack cl_stack_create(cl_item_id item, int32_t count);
cl_item_stack cl_stack_create_by_name(cl_str id, int32_t count);   // vanilla or mod items; null for an unknown id
void          cl_stack_retain(cl_item_stack s);
void          cl_stack_release(cl_item_stack s);
cl_item_id    cl_stack_item(cl_item_stack s);
int32_t       cl_stack_count(cl_item_stack s);
cl_result     cl_stack_set_count(cl_item_stack s, int32_t count);
bool          cl_stack_is_empty(cl_item_stack s);
bool          cl_stack_is(cl_item_stack s, cl_str item);           // "minecraft:diamond", or a mod item

A stack you create or get from cl_player_inventory_get / cl_menu_get_item is owned: release it. Stacks in event payloads and cl_item_ctx are borrowed.

Bindings

C C++ Lua
cl_item_register(&d, &h) clight::registry::item_register(&d), clight::registry::item(d, {.use = ...}) cl.items.register{...}
cl_stack_create_by_name(id, n) clight::item("minecraft:apple", 3) → ItemStack cl.stack("minecraft:apple", 3)
cl_stack_count(s) / cl_stack_set_count s.count() / s.set_count(n) s:count() / s:set_count(n)
cl_stack_is(s, id) s.is(id); C cl_easy_stack_is(s, "id") s:is(id)
cl_stack_release(s) destructor collected, or local s <close> = ...

Giving, taking and counting items in a player’s inventory: Players (player:give, player:take, player:count_item, live slots).

Planned

Default data components from code (food, tools, equipment, consumables), reading and writing components on stacks, more behaviour entries (use on a block or entity, finish using, inventory tick, mining speed, tooltips), overrides of vanilla items, custom creative tabs and changing vanilla tab contents, and stack NBT.