Skip to content

Players

Status: Partly implemented (API 1.11). Name, messages and the action bar, titles, give, inventory get / set / take / count / shrink / consume (nothing used up in creative, like ItemStack#consume), game mode, selected slot, the online player list, broadcasts, the local client player, plus every entity function. API 1.6 kicks; API 1.11 adds the camera, movement modifiers, model parts and part models, animation layers, disabled hands, locked slots, input overrides, food, saturation, exhaustion, air and natural regeneration (Guide: Player Control). Abilities, experience, permission checks, respawn points, stats, advancements and the tab list are Planned.

Function table: entity (the cl_player_* and cl_server_* functions live in the entity module). Players are entities (cl_entity): every cl_entity_* and cl_living_* function applies. The cl_player_* functions return CL_E_WRONG_TYPE (or a default) for other entities.

Server-side functions

Group C Lua C++
Name cl_player_name(p, buf, cap, &n), C cl_easy_player_name(p, buf, cap) p.name p.name() ("" on error), p.try_name()
Chat cl_player_send_message(p, text), cl_easy_send_message(p, "Hi"), cl_easy_send_messagef(p, "%d", n) p:send_message("Hi") (any value, or a text) p.send_message("Hi")
Action bar cl_player_send_action_bar(p, text), cl_easy_send_action_bar p:send_action_bar("Hi") p.send_action_bar("Hi")
Title cl_player_send_title(p, title, subtitle, fade_in, stay, fade_out) (-1 keeps a time; null subtitle keeps the current one), cl_player_clear_title(p, reset_times), cl_easy_send_title(p, "Title", "Sub") p:send_title("Title", "Sub", { fade_in = 10, stay = 70, fade_out = 20 }), p:clear_title() p.send_title("Title", "Sub"), p.clear_title()
Give cl_player_give(p, stack) (what doesn’t fit is dropped), cl_easy_give(p, "minecraft:apple", 3) p:give("minecraft:apple", 3) p.give("minecraft:apple", 3)
Take cl_player_take(p, CL_STR(id), n) → removed (slots 0-40 in order, like /clear; every game mode) p:take(id, n) p.take(id, n)
Count cl_player_count_item(p, CL_STR(id)) p:count_item(id), p:has_item(id, n) p.count_item(id)
Slots cl_player_inventory_get(p, slot) (owned copy), cl_player_inventory_set(p, slot, stack), cl_player_inventory_shrink(p, slot, n), cl_player_inventory_consume(p, slot, n) p:slot(n) / p:held_item("main" or "off"): a live slot with .id, .count, .empty, :shrink(n) (consume), :remove(n), :set(id, n), :clear(), :stack() p.inventory_get(slot), inventory_set, inventory_shrink, inventory_consume, p.consume_held(n)
Selected slot cl_player_selected_slot(p) (0-8) p:selected_slot() p.selected_slot()
Game mode cl_player_game_mode(p) → CL_GAMEMODE_SURVIVAL, … p.gamemode ("survival", "creative", "adventure", "spectator") p.game_mode()

Slots use vanilla numbers: 0-8 hotbar, 9-35 main inventory, 36-39 armour, 40 offhand. inventory_set with the same item already in the slot only changes the count (name, enchantments and damage stay); an empty stack clears the slot. inventory_consume removes nothing in creative mode; inventory_shrink and take always remove.

All of these run on the server tick (TICK).

Player control (API 1.11)

Group C Lua Side
Movement modifiers cl_player_add_movement_modifier(p, &m) (cl_movement_modifier: id, speed_mult, jump_mult, step_height, can_sprint, can_jump, sway), cl_player_remove_movement_modifier(p, id), cl_player_has_movement_modifier, cl_player_movement(p, &state) p:add_movement_modifier{ id = "broken_leg", speed_mult = 0.6, can_sprint = false }, p:remove_movement_modifier(id), p:movement() server (movement: both)
Model parts cl_player_set_part_visible(p, CL_PART_LEFT_ARM, false), cl_player_part_visible, cl_player_set_part_model(p, part, path, &opts) (cl_part_model_opts: scale, offset, rotation, keep_part, clip) p:set_part_visible("left_arm", false), p:set_part_model("right_leg", "my_mod:models/peg_leg.glb", { scale = 1 }) (nil path: the vanilla part) both (server: synced)
Animation layers cl_render_player_animations(path, &model) once, then the cl_entity_anim_* functions on players cl.render.player_animations(path), p:anim_play("limp", { layer = 1 }) both (server: synced)
Hands cl_player_set_hand_disabled(p, CL_HAND_OFF, true), cl_player_hand_disabled p:set_hand_disabled("off_hand", true), p:hand_disabled("off_hand") server (query: both)
Slots cl_player_lock_slot(p, slot, locked, select_lock), cl_player_slot_locked p:lock_slot(40), p:lock_slot(0, true, true), p:unlock_slot(0) server (query: both)
Input cl_player_set_input_override(p, &in) (cl_input_override: forward … sprint, each -1 / 0 / 1), cl_player_clear_input_override, cl_player_input_override p:set_input_override{ crouch = true, sprint = false }, p:input_override(), p:clear_input_override() both
Food cl_player_food, cl_player_set_food (0…20), cl_player_saturation, cl_player_set_saturation, cl_player_exhaustion, cl_player_exhaust(p, amount) p:food(), p:set_food(6), p:saturation(), p:exhaust(2) server (reads: both for the local player)
Air cl_entity_air(e), cl_entity_max_air(e), cl_entity_set_air(e, ticks) (every living entity) e:air(), e:set_air(60) server (reads: both for the local player)
Regeneration cl_player_set_natural_regen(p, false), cl_player_natural_regen p:set_natural_regen(false) server
Camera cl_camera_get(&info) (pos, forward, up, yaw, pitch, fov, first_person, detached), cl_camera_position, cl_camera_is_first_person cl.camera.get(), cl.camera.position(), cl.camera.is_first_person() client

Speed, jump and step height are vanilla attribute modifiers (seecraft:clight/<mod>/<id>, not saved), so every client’s movement prediction applies them: no rubber-banding, vanilla clients included. Celestial clients with CLight also get the rest (no sprinting, sway, hidden parts and models, animation layers, locks, forced keys) through clight:entities; vanilla clients get nothing and the server enforces what it can (it refuses locked slots and disabled hands, keeps a vanilla client’s crouch held and sprint released in its own copy, takes away the sprint bonus). Modifiers, parts and locks last until removed or the player leaves; they survive death. Function table: entity, camera.

The player list

cl_result cl_server_players(cl_entity* out, size_t cap, size_t* out_count);   // online players
cl_result cl_server_broadcast(cl_text message);                               // a chat line to everyone
C Lua C++
cl_server_players(buf, cap, &n) cl.entity.server_players() → a list clight::entity::server_players() → Expected<std::vector<Entity>>
cl_server_broadcast(text), cl_easy_broadcast("Hi") cl.entity.server_broadcast("Hi") clight::broadcast("Hi")

Client side

C Description Context
cl_entity cl_client_player(void) The local player (null when not in a world) ANY
cl_level cl_client_level(void) The client level ANY
cl_client_show_message(text, overlay) A chat line (or action bar) only this client sees client TICK
cl_client_show_title(title, subtitle, fade_in, stay, fade_out) A title only this client sees client TICK

Lua: cl.entity.client_player(), cl.client.message("Hi"), cl.client.action_bar("Hi"), cl.client.title("Hi", "sub"). C: cl_easy_show_message("Hi").

Player events

Event Cancellable Mutable fields
player.join no
player.leave no
player.respawn no
player.chat yes message
player.command yes command
player.interact_block yes (and a result)
player.interact_item yes (and a result)
player.attack_entity yes

Payload fields: generated event list.

cl.on("player.join", function(event)
  local p = event.player
  if p:count_item("minecraft:bread") == 0 then p:give("minecraft:bread", 3) end
  p:send_title("Welcome", p.name)
end)

Planned

Abilities (fly, speeds), experience, permission checks, transfers, respawn points, stats and advancements, cooldowns, the tab list, per-viewer visibility, the player’s locale and client brand, and more player events (login, move, game mode change, container clicks).