Conventions
Status: Implemented. These are the rules
clight.idlgenerates intoclight.h,clight.hpp, the Lua binding and the WASM import table.
Every page in this folder documents one subsystem: what it is for, how to use it, and examples in C, C++ and Lua. The complete, always-current function lists are generated from the IDL into generated/: one table per module with the C, Lua and C++ name, the side, the context and the API version of every function. Anything not in those tables doesn’t exist yet; the hand-written pages mark such parts Planned.
Naming rules
| Concept | C | C++ (clight.hpp) |
Lua |
|---|---|---|---|
| Module function | cl_<module>_<verb> (cl_level_set_block) |
method on the handle: level.set_block(...); free function clight::level::set_block(level, ...) |
cl.<namespace>.<verb>(...), mirroring the C name (cl.level.set_block) |
| Function taking a handle first | cl_living_set_health(e, 5) |
method: e.set_health(5) |
method: e:set_health(5) |
| Getter | cl_living_health(e) |
e.health() |
the common ones are properties: e.health, e.name, e.pos; the call form is e:get_health() |
| Boolean query | cl_entity_is_valid(e) |
e.is_valid() |
e:is_valid() |
| Handle type | cl_entity |
clight::Entity |
userdata |
| Value struct | cl_block_pos |
cl_block_pos (aggregate) |
cl.pos(x, y, z) (a table with a metatable) |
| Descriptor | cl_block_desc + CL_BLOCK_DESC_INIT |
the same C struct (or a clight:: helper taking it) |
a table with the same keys |
| Enum value | CL_DIRECTION_UP |
the C constant | string "up" |
| Flags | CL_BLOCK_REQUIRES_CORRECT_TOOL |
the C constant | boolean key requires_correct_tool = true, or a table of names |
| Event | CL_EV_BLOCK_BREAK, payload cl_ev_block_break |
clight::ev::BlockBreak |
"block.break" |
| Error | cl_result < 0 |
clight::Expected<T> with a cl_result error |
a raised cl.Error (cl.try.<ns>.<fn>(...) returns false, err instead) |
Functions whose C name carries its own family prefix inside a module keep it in Lua: cl_buf_write_i32 (module net) is cl.buf.write_i32, cl_task_cancel is cl.task.cancel, cl_player_give is cl.player.give. The older module spellings (cl.net.buf_write_i32, cl.entity.player_give) are the same functions and keep working.
Strings
- C:
cl_str { const char* ptr; size_t len; }. UTF-8, not required to be NUL-terminated. UseCL_STR("literal")orCL_STR_C(c_string). - Outgoing strings are written into a caller buffer:
(char* buf, size_t cap, size_t* out_len). Ifcapis too small, the call returnsCL_E_BUFFER_TOO_SMALLand sets*out_lento the size needed. - C++:
std::string_viewin,std::stringout (the wrapper does the two-call pattern).clight::s(view)makes acl_str,clight::sv(str)a view. - Lua: Lua strings.
Errors
Every fallible C function returns cl_result: CL_OK (0) on success, a negative CL_E_* code on failure (Error codes). Results go out through pointer parameters. Getters that can’t fail (other than on a stale handle) return the value directly and record the error in a thread-local cl_last_error(); they return a documented default (0, false or the null handle).
Descriptor structs and struct_size
typedef struct cl_block_desc {
uint32_t struct_size; // always first; set by CL_BLOCK_DESC_INIT
cl_str id;
/* ... */
} cl_block_desc;
cl_block_desc d = CL_BLOCK_DESC_INIT; // struct_size and every default
Always start from the _INIT macro. The engine reads only the fields that fit in struct_size, so a mod compiled against API 1.0 keeps working when a later minor version adds fields at the end.
Function entries
The generated tables list every function like this:
cl_result cl_level_set_block(cl_level level, cl_block_pos pos, cl_block_state state, cl_set_block_flags flags);
- Context: where it may be called (
ANY,MAIN,TICK,RENDER; Threading model). - Side:
server,clientorboth. - Since: the API version that added it. On an older game, test with
cl_core_has("level_set_block")/cl.has("level.set_block"). - Owned: a returned handle you must release © or that the C++ class releases for you.
Callback signatures
C callbacks take a void* user as the last parameter: the pointer you passed when registering. The C++ wrapper uses it for its own lambda table (capturing lambdas work everywhere), so with the C++ helpers you capture instead.
Lua specifics
- The global
cltable holds all modules.modis the current mod (mod.id,mod.version,mod.config,mod.persist, which survives hot reloads). - Positions accept
cl.pos(x, y, z)or{x = ..., y = ..., z = ...}. - Block, block-state and item parameters accept id strings (
"minecraft:stone"). - Functions that would return
cl_resultraise acl.Error(err.code,err.message) on failure.cl.try.<namespace>.<fn>(...)returnstrue, results...orfalse, errinstead.