Skip to content

Events

Status: Implemented. Subscribing, priorities, cancellation, results, filters, mutable fields written back, zero cost without subscribers, 43 events. Events defined by mods (register / post) and the larger planned event set are Planned.

Function table: event. Every event with its payload: generated event list and Complete event list (what cancel means for each). Concepts: Events.

Types

typedef uint32_t cl_event_type;                        // CL_EV_* constants
typedef void (*cl_handler_fn)(void* payload, void* user);

#define CL_PRIORITY_FIRST   (-2000)
#define CL_PRIORITY_EARLY   (-1000)
#define CL_PRIORITY_NORMAL  0
#define CL_PRIORITY_LATE    1000
#define CL_PRIORITY_LAST    2000
#define CL_PRIORITY_MONITOR 10000

/* cl_event_header.flags, set by the engine: CL_EVF_CANCELLABLE, CL_EVF_HAS_RESULT, CL_EVF_CLIENT, CL_EVF_ASYNC */
/* cl_subscribe_opts.flags: CL_SUB_RECEIVE_CANCELLED, CL_SUB_ONCE (unsubscribe after the first call),
   CL_SUB_DEFERRABLE (reserved) */

typedef enum cl_interaction_result {
    CL_RESULT_PASS, CL_RESULT_SUCCESS, CL_RESULT_CONSUME, CL_RESULT_FAIL
} cl_interaction_result;

typedef struct cl_event_header { uint32_t struct_size; cl_event_type type; uint32_t flags;
                                 uint8_t cancelled; int8_t result; uint16_t reserved; } cl_event_header;

typedef struct cl_subscribe_opts { uint32_t struct_size; int32_t priority; uint32_t flags;
                                   cl_ident filter; cl_level level; } cl_subscribe_opts;
/* CL_SUBSCRIBE_OPTS_INIT */

Functions

cl_result cl_event_subscribe(cl_event_type type, const cl_subscribe_opts* opts, cl_handler_fn fn, void* user, cl_sub* out);
cl_result cl_event_unsubscribe(cl_sub sub);                       // takes effect before the next dispatch
cl_result cl_event_type_lookup(cl_str id, cl_event_type* out);    // "block.break" -> CL_EV_BLOCK_BREAK
cl_str    cl_event_name(cl_event_type type);                      // CL_EV_BLOCK_BREAK -> "block.break"
void      cl_event_cancel(cl_event_header* h);                    // no effect on events that can't be cancelled
bool      cl_event_is_cancelled(const cl_event_header* h);
void      cl_event_set_result(cl_event_header* h, cl_interaction_result r);

All of them work in any context and on both sides. opts may be NULL (normal priority, no filter); out may be NULL when you never unsubscribe.

Bindings

C C++ Lua
cl_event_subscribe(CL_EV_BLOCK_BREAK, &o, fn, u, &s) auto s = clight::on<clight::ev::BlockBreak>(fn, {.priority = ..., .flags = ..., .filter = "...", .level = ...}) → RAII Subscription (unsubscribes on destruction; .detach() keeps it for the mod’s lifetime) local s = cl.on("block.break", fn, { priority = "early", filter = "...", receive_cancelled = true, once = true })
CL_ON(CL_EV_BLOCK_BREAK, fn) (clight_easy.h) cl.once("block.break", fn)
cl_event_unsubscribe(s) s.reset() s:cancel()
cl_event_cancel(&e->header) clight::cancel(e.header) event:cancel()
e->header.cancelled e.header.cancelled event.cancelled, event:is_cancelled()
cl_event_set_result(&e->header, r) cl_event_set_result(&e.header, r) event:set_result("success")

The C++ handler receives the payload struct by reference ([](cl_ev_block_break& e), or [](auto& e)); the type comes from clight::ev::BlockBreak::payload. Lua priorities: "first", "early", "normal", "late", "last", "monitor", or any number.

Event families

Family Events Context
lifecycle.* register, registries_frozen, common_setup, client_setup, server_setup, resources_reloaded, data_reloaded, server_starting, server_started, server_stopping, server_stopped, level_load, level_save, level_unload, mod_reload, shutdown MAIN (level_save: TICK)
tick.* server_pre, server_post, level_pre, level_post, client_pre, client_post TICK
player.* join, leave, respawn, chat, command, interact_block, interact_item, attack_entity; interact_entity (API 1.20) TICK (server)
block.* break, place TICK (server)
entity.* damage, death; tick, anim_event, synced, knockback (API 1.8-1.10), data_changed (1.12), spawn, change_dimension (1.20) TICK (server; tick, anim_event: both; synced, data_changed: client)
level.* block_changed (API 1.11: server at the end of the level tick, client right after the change) TICK (both)
server.* command_register MAIN (server)
client.* connect, disconnect, screen_open, key, chat_received (RENDER), chat_send (TICK), sound_play (ANY) client
config.* reloaded ANY
mod.* permission_changed (API 1.20: to the mod that declared the capability) MAIN

Planned: events defined by mods (a register and post API for other mods to subscribe to), and further vanilla events (chunk load, item tooltip, render stages, more player actions). Entity spawn, tick and dimension changes and entity interaction have arrived (API 1.8, 1.20).