Inventories and menus
Status: Partly implemented. Server container menus: a vanilla menu type (
CL_MENU_CHEST_9X1…9X6,CL_MENU_DISPENSER_3X3,CL_MENU_HOPPER) over a container your mod owns, so vanilla clients use it normally. Slots hold an item and a count (other components are not copied). Player inventories: Players. API 1.11: the slots of any block container in the world (cl_level_container_size/_get/_set, Lualevel:container(pos); full item data) and locked player inventory slots (cl_player_lock_slot). Custom menu types with their own layout and screen, data slots and container events are Planned.
Function table: menu.
Opening a menu
typedef struct cl_menu_desc {
uint32_t struct_size;
cl_menu_kind kind; // CL_MENU_CHEST_9X3 by default
cl_text title; // borrowed for the call
bool locked; // true (default): every click is cancelled unless on_click returns true
cl_menu_click_fn on_click; // (menu, player, slot, button, click_type, user) -> true = let vanilla handle it
cl_menu_close_fn on_close; // (menu, player, user)
void* user;
} cl_menu_desc;
/* CL_MENU_DESC_INIT */
cl_result cl_menu_open(cl_entity player, const cl_menu_desc* desc, cl_menu* out); // server, TICK
cl_result cl_menu_close(cl_menu m);
bool cl_menu_is_open(cl_menu m);
cl_entity cl_menu_player(cl_menu m);
int32_t cl_menu_size(cl_menu m); // container slots (without the player inventory)
cl_result cl_menu_set_item(cl_menu m, int32_t slot, cl_item_stack stack); // copies item + count, syncs to the client
cl_item_stack cl_menu_get_item(cl_menu m, int32_t slot); // owned
Slots are numbered from 0 in the container part (a 9x3 chest has 0-26); clicks in the player’s own inventory part arrive with slot numbers after those. click_type is CL_CLICK_PICKUP, QUICK_MOVE (shift), SWAP (number keys), CLONE, THROW, QUICK_CRAFT (drag) or PICKUP_ALL (double click).
Bindings
| C | C++ | Lua |
|---|---|---|
cl_menu_open(p, &d, &m) |
clight::menu::open(player, {.kind, .title = "Shop", .locked, .on_click = [](Menu, Entity, int32_t slot, int32_t button, cl_click_type) { ... }, .on_close}) → Expected<Menu> (the lambdas are freed when it closes) |
cl.menu.open(player, { kind = "chest_9x1", title = "Shop", on_click = function(m, who, slot, button, click) ... end, on_close = fn }) |
cl_menu_set_item(m, i, s) |
m.set_item(i, s) |
m:set_item(i, "minecraft:diamond") (an id or a stack) |
cl_menu_get_item(m, i) |
m.get_item(i) → ItemStack |
m:get_item(i) |
cl_menu_close(m) |
m.close() |
m:close() |
Lua on_click returns true to let vanilla handle the click (take or place the item); return nothing to cancel it.
Example: a shop (Lua)
local function open_shop(player)
local shop = cl.menu.open(player, {
kind = "chest_9x1",
title = "Ruby shop",
on_click = function(menu, who, slot)
if slot == 0 and who:take("my_mod:ruby", 1) == 1 then
who:give("minecraft:diamond")
who:send_action_bar("Thanks!")
end
end,
})
shop:set_item(0, "minecraft:diamond")
end
cl.on("server.command_register", function()
cl.cmd.register(cl.cmd.literal("shop"):executes(function(ctx)
local p = ctx:player()
if p then open_shop(p) end
end))
end)
The complete version is /rubylua shop in clight-sdk/examples/ruby_lua.
Planned
Generic containers (get, set, add, count) for chests and other blocks, temporary containers, slot filters, more vanilla menu kinds (anvil, crafting, furnace, merchant, …), custom menu types with a fallback for vanilla clients and an RmlUi screen with slot elements, data slots for progress bars, the carried stack, item components in menu slots, and the container open, close and click events.