Events, behaviours and mixins
Status: Implemented for events, behaviour callbacks on your own blocks and items, and the mixin core. Overrides of vanilla content’s behaviour tables and value events are Planned; mixins on game targets cover part of that today.
CLight has three ways to change the game. Start with the simplest one that does the job:
| Mechanism | Changes | Example |
|---|---|---|
| Events (Events) | Whether something happens, and the documented mutable values | Cancel a block break, change the XP dropped, block a chat message |
| Behaviour callbacks | How your own block or item reacts | Right-click your block to open a shop; a wand item that does something on use |
| Mixins (Mixins) | A step inside a game function, at a named, versioned target | Change a damage amount inside hurt, skip a vanilla step |
Plus registries for new content (Registries). All of these are explicit points the engine publishes; nothing patches the game’s machine code, and two mods touching the same point compose in priority order.
Behaviour callbacks
A registered block or item can carry a behaviour table: a struct of callbacks the engine calls for that content only. Leave an entry NULL and vanilla behaviour (of the base block or item) applies.
| Table | Entries | Called when |
|---|---|---|
cl_block_behavior |
use_without_item(ctx, player, hand, out_result) |
A player right-clicks the block with an empty hand or an item that doesn’t use blocks |
attack(ctx, player, out) |
A player left-clicks (starts breaking) it | |
random_tick(ctx, out) |
The block gets a random tick (set the CL_BLOCK_RANDOM_TICKS flag) |
|
cl_item_behavior |
use(ctx, out_result) |
A player uses the item (right-click in the air or on a block) |
Every entry returns cl_override: CL_OVERRIDE_HANDLED (you decided; the result goes through the last parameter) or CL_OVERRIDE_CALL_ORIGINAL (vanilla runs as if you weren’t there).
static cl_override shop_use(const cl_block_ctx* ctx, cl_entity player, cl_hand hand, cl_interaction_result* out) {
(void)ctx; (void)hand;
cl_easy_send_message(player, "Welcome to the shop!");
*out = CL_RESULT_SUCCESS;
return CL_OVERRIDE_HANDLED;
}
static cl_block_behavior g_shop = CL_BLOCK_BEHAVIOR_INIT; /* must outlive the registration */
/* in lifecycle.register: */
g_shop.use_without_item = shop_use;
cl_block_desc d = CL_BLOCK_DESC_INIT;
d.id = CL_STR("my_shop:counter");
d.vanilla_fallback = CL_STR("minecraft:barrel");
d.behavior = &g_shop;
cl_block_register(&d, NULL);
cl.blocks.register{
id = "counter", vanilla_fallback = "minecraft:barrel",
behavior = {
use_without_item = function(ctx, player, hand)
player:send_message("Welcome to the shop!")
return "success" -- handled; return nothing to let the fallback block act
end,
},
}
clight::registry::block(d, {.use_without_item = [](const cl_block_ctx&, clight::Entity player, cl_hand, cl_interaction_result& out) {
player.send_message("Welcome to the shop!");
out = CL_RESULT_SUCCESS;
return CL_OVERRIDE_HANDLED;
}});
The ctx (cl_block_ctx, cl_item_ctx) has the level, the position and state (blocks), or the stack, entity and hand (items). Lua behaviour functions are swapped in place on hot reload.
What can’t be changed, and why
| Not changeable | Reason |
|---|---|
| Arbitrary engine functions or code offsets | No stable meaning across versions. Use a named mixin target; missing targets can be requested. |
| Protocol encoding and decoding | Wire compatibility with vanilla servers and clients. Use payloads (Networking). |
| The job scheduler, allocators, the Vulkan device | Engine invariants (GPU access). |
Requesting new events
If you need an event, a behaviour entry or a mixin target that doesn’t exist, check Mixin targets first, then file a request with the vanilla class and method it would mirror. New entries are added in minor API versions and never removed within a major version (ABI stability and API versioning). cl.has("name") / cl_core_has tells a mod at run time whether the game it runs on has them.
Planned
- Overrides of vanilla content (a behaviour chain on
minecraft:sugar_cane, for example), with more entries (can_survive,entity_inside, …). - Value events: a mutable
resultthat starts as the vanilla value (fall damage, mining speed, FOV), listed in Value event list. - Behaviour tables for entity types and effects.