Skip to content

The event list

Lesson 10.3

This page lists every event the game sends today, with its fields. Come back to it whenever you write a new handler.

How to read the tables:

  • Side says where the event happens. Server events run where the world is simulated: in singleplayer, or on a server that has your mod. Client events run in the game window of the player. Client and server explains the difference.
  • Cancel marks events you can stop with event:cancel().
  • Fields in bold can be changed.

Startup and shutdown

These run once, in this order, while the game starts or a world opens.

Event Side Use it for
lifecycle.register both Registering items and blocks.
lifecycle.registries_frozen both After this, nothing more can be registered.
lifecycle.common_setup both Setup that needs the registered content.
lifecycle.client_setup client Keybinds, HUD layers and other client things.
lifecycle.server_setup server Server setup.
lifecycle.server_starting server A world is about to open.
lifecycle.server_started server The world is open.
lifecycle.server_stopping server The world is closing. Save your data here.
lifecycle.server_stopped server The world is closed.
lifecycle.shutdown both The game is quitting.

They have no fields you need.

A few more happen while the game runs:

Event Side When
lifecycle.level_load server Once per world (overworld, nether, end) after it opened. world is that world.
lifecycle.level_save server Before a world is saved: autosave, /save-all, pausing singleplayer, closing. world is the world being saved.
lifecycle.level_unload server A world is about to close.
lifecycle.data_reloaded server After /reload.
lifecycle.resources_reloaded client After resource packs were reloaded (F3 + T, changing packs).
lifecycle.mod_reload both After a hot reload of a mod’s scripts worked (development mode).
config.reloaded both A config file was read again and a value changed (mod_id, file). Filter on your mod id, or use config:on_reload.
When a hot reload adds a handler for lifecycle.register, common_setup, client_setup, server_starting or server_started again, the new handler runs straight away, so a reload behaves like a fresh start.

Ticks

The game runs 20 ticks per second. These events run every tick, so keep their handlers short.

Event Side Fields
tick.server_pre server tick_count: the number of the tick
tick.server_post server tick_count
tick.level_pre server world, tick_count: once per world, before the worlds tick
tick.level_post server world, tick_count: once per world, after they ticked
tick.client_pre client
tick.client_post client

pre runs before the game’s own work for that tick, post after it. When in doubt, use post.

Players

Event Side Cancel Fields
player.join server player
player.leave server player
player.respawn server player
player.chat server yes player, message
player.command server yes player, command (without the /)
player.interact_block server yes player, world, hand, pos, face (result)
player.interact_item server yes player, world, hand, stack, item (result)
player.attack_entity server yes player, target

Events marked result also take event:set_result(...), see Changing and cancelling. hand is "main" or "off". face is the side of the block that was clicked: "down", "up", "north", "south", "west" or "east". stack is the item stack in the hand and item its id.

Blocks

Event Side Cancel Fields
block.break server yes player, world, pos, state, block, tool, item, xp, drop_items
block.place server yes player, world, pos, state, block, hand, replaced_state

state is the block state as a number and block the block’s id as a string. Most of the time you want block. On block.break, tool is a copy of the stack in the player’s hand and item its id (nil for an empty hand). xp is the experience the block drops (ores, sculk, spawners; 0 for most blocks), and you can change it. If you leave xp as it is, the game rolls the amount itself afterwards, exactly as without mods, so a mod that only reads it never changes what players get or the game’s random numbers. The value you read is a real roll of the same dice, but the game’s own roll may come out different.

Block events can be filtered by block id, entity events by entity type, player.interact_item by item id and player.interact_block by the clicked block. Changing and cancelling shows how.

Entities

Event Side Cancel Fields
entity.damage server yes entity, player, world, source, attacker, amount
entity.death server yes entity, player, world, source, attacker

entity is the hurt or dying entity. player is the same entity when it is a player, otherwise nil. source is the damage type, like "minecraft:fall" or "minecraft:player_attack". attacker is whoever caused it, or nil. Cancelling entity.death skips the death. Give the entity some health back with entity:set_health(4) in the same handler, or it has none left.

Commands

Event Side Fields
server.command_register server dedicated: true on a dedicated server

Register your commands in here. Commands shows how.

Client

Event Side Cancel Fields
client.connect client address: the server address
client.disconnect client
client.screen_open client screen_id
client.key client yes key, scancode, action, modifiers, screen_open
client.chat_send client yes message: what the player is about to send
client.chat_received client yes message, overlay (true for action-bar text)
client.sound_play client yes sound, category, pos, volume, pitch, positional

Client events also fire on servers that don’t have your mod. That is what makes client-only mods possible.

More events are coming

The reference lists more events, such as entity ticks, explosions and block updates. They are not sent yet. Code that listens to them is harmless: the handler simply never runs.

Try it

Write one handler that greets a player when they join, and another that tells everybody in the log when a player died and what killed them.

Show a solution
cl.on("player.join", function(event)
  event.player:send_message("Hi " .. event.player.name .. ", have fun!")
end)

cl.on("entity.death", function(event)
  if not event.player then return end  -- only players
  local by = "something"
  if event.attacker then by = event.attacker:type() end
  cl.log("%s died (%s, by %s)", event.player.name, tostring(event.source), by)
end)

entity:type() gives an entity’s type id, like "minecraft:zombie".

Recap: startup events register and set up, tick events run 20 times a second, and player, block, entity and client events report what happens in the game.