Skip to content

Receivers & Events

SwoftLang handles server events through receivers — Capitalized top-level blocks, one per engine subject, whose members are fixed-name methods that fire when something happens to that subject. A Player { } block groups everything that can happen to a player; a Mob { } block groups everything that can happen to a mob; and so on.

swoftlang
Player {
    on_join {
        broadcast "<yellow>${player.name} joined the game"
    }

    on_chat {
        send "<gray>You said: ${message}" to player
    }
}

Inside every method the subject is a bare variable named after its type — player, mob, block, and so on. The rest of the event's data is bound alongside it as bare variables, with types fixed by the catalog and the names listed in each receiver's table below.

The receiver catalog

A base receiver is a Capitalized type whose methods fire for every instance of that type. Eleven base receivers cover the engine, plus the special Packet block for raw packets:

ReceiverSubject variableFires for
Playerplayerevery online player
Entityentityevery live entity (players, mobs, projectiles, items)
Mobmobevery server-spawned mob
Itemitem (the item stack)the item involved in an interaction
Blockblockthe positioned block value
Projectileprojectilearrows, snowballs, thrown items in flight
Inventoryinventoryopen-inventory / GUI interactions
Worldworldworld lifecycle, ticks, chunks
Serverserverthe global singleton + pre-login / connection events
NpcnpcNPC clicks and ticks
Hologramhologramhologram clicks and ticks
Packetpacket + playerraw inbound packets, keyed by class name

A method name is checked against its receiver's table at compile time, and so is every variable it reaches for — a handler that would never fire, or one that reaches for data the event never binds, is a compile error (a misspelled method name gets the nearest match suggested):

swoftlang
Player {
    on_join {
        send "<red>Under attack!" to attacker
    }
}
txt
ev.sw:3:38: error: variable 'attacker' is never assigned
        send "<red>Under attack!" to attacker
                                     ^

Base receivers vs. custom declarations

A Capitalized receiver (Mob { }) is the base type — its methods run for every mob. A lowercase declaration with a string id (mob "ghoul" { }, item "rod" { }) is a custom subtype that carries the same method set but scoped to that one id, and overrides the base for its instances.

Player

Every online player. The subject is bound as player.

MethodCancellableBound variables
on_join
on_quit
on_loaded
on_chatyesmessage (String, rw)
on_moveyesnew_position (Location, rw)
on_deathdeath_text (String, rw), chat_message (String, rw)
on_respawnrespawn_position (Location, rw)
on_commandyescommand (String, rw)
on_break_blockyesblock (String), location (Location), face (String)
on_place_blockyesblock (String), location (Location), face (String), hand (String)
on_interact_blockyesblock (String), location (Location), face (String), hand (String)
on_use_itemyesitem (Item), hand (String)
on_use_item_on_blockitem_stack (Item), location (Location), face (String), hand (String)
on_start_diggingyesblock (String), location (Location), face (String)
on_finish_diggingblock (String), location (Location)
on_cancel_diggingblock (String), location (Location)
on_change_held_slotyesnew_slot (Integer, rw), old_slot (Integer)
on_swap_itemyesmain_hand_item (Item, rw), off_hand_item (Item, rw)
on_gamemode_changeyesnew_game_mode (String, rw)
on_start_sprinting · on_stop_sprinting
on_start_flying · on_stop_flying
on_start_elytra · on_stop_elytra
on_interact_entitytarget (Entity), hand (String)
on_spectate_entitytarget (Entity)
on_teleport_to_entitytarget (Entity)
on_pick_entitytarget (Entity)
on_pick_blockblock (String), location (Location)
on_edit_signblock (String), block_position (Location)
on_edit_book
on_anvil_inputinput (String)
on_leave_bedyes
on_hand_animationyes
on_input
on_tick · on_tick_end
on_chunk_load · on_chunk_unloadchunk_x (Integer), chunk_z (Integer)
on_skin_initskin (Skin, rw)
on_settings_change
on_resource_pack_status
on_plugin_message
on_advancement_tab
on_stabitem_stack (Item)
on_pickup_experienceyesexperience_count (Integer, rw)
on_drop_itemyesitem (Item)
on_pickup_item
on_packet_in · on_packet_outyes
on_begin_item_useyes
on_cancel_item_use · on_finish_item_use
on_outgoing_transferyeshost (String, rw), port (Integer, rw)
on_cast_rod · on_fish_bite · on_catch_fish · on_reel_infishing

Entity

Base for every live entity — players, mobs, projectiles, dropped items. The subject is bound as entity.

MethodCancellableBound variables
on_hityesattacker (optional<Entity>)
on_death
on_spawn · on_despawn
on_attacktarget (Entity) — entity is the attacker
on_tick
on_teleportnew_position (Location)
on_velocityyesvelocity (Vec, rw)
on_shootyesprojectile (Entity), to (Location), power (Double, rw), spread (Double, rw)
on_set_fireyesfire_ticks (Integer, rw)
on_fire_extinguishyes
on_item_mergeyes
on_potion_add · on_potion_removeon_potion_add only
on_equipequipped_item (Item, rw), slot (String)
on_pickup_itemyesitem_stack (Item), item_entity (Entity)

Mob

Mob <: Entity — narrows Entity to server-spawned mobs. A lowercase mob "id" { } declaration (Mobs) carries the same method set for one mob type and overrides the base.

MethodCancellableBound variables
on_hitattacker (Entity)
on_deathkiller (optional<Entity>)
on_spawn
on_tick
on_attacktarget (Entity)
on_targettarget (optional<Entity>)
on_clickplayer (Player)
on_despawn
on_teleportnew_position (Location)
on_shootyesprojectile (Entity), to (Location), power (Double, rw), spread (Double, rw)

Item

The item stack involved in an interaction. A lowercase item "id" { } declaration (Items) carries the same method set for one item and overrides the base.

MethodCancellableBound variables
on_useyesplayer (Player)
on_right_clickyesplayer (Player)
on_right_click_blockplayer (Player), location (Location), face (String)
on_left_clickplayer (Player)
on_attack_entityplayer (Player), target (Entity)
on_consumeplayer (Player)
on_dropyesplayer (Player)
on_pickupplayer (Player)
on_swap_toplayer (Player)
on_breakplayer (Player)
on_begin_useyesplayer (Player)
on_cancel_use · on_finish_useplayer (Player)
on_equipentity (Entity), slot (String)

Block

The positioned block value. A lowercase block_handler "id" { } declaration (Blocks) carries the same method set for one block id and overrides the base.

MethodCancellableBound variables
on_placeplayer (Player), location (Location), block (Block)
on_breakyesplayer (Player)
on_destroylocation (Location), block (Block)
on_interactyesplayer (Player), location (Location), block (Block)
on_touchentity (Entity), location (Location)
on_ticklocation (Location), block (Block)
on_dispenseyesitem (Item), direction (String) — see Dispensers
on_updatelocation (Location), block (Block)

Projectile

Projectile <: Entity — projectile lifecycle. The subject is bound as projectile. (The shooter side is reachable via Entity.on_shoot.)

MethodCancellableBound variables
on_hit_blockyesblock (Block), world (World)
on_hit_entityyestarget (Entity)
on_uncollide

Inventory

Open-inventory and GUI interactions.

MethodCancellableBound variables
on_pre_clickyesplayer (Player), slot (Integer), clicked_item (Item)
on_clickplayer (Player), slot (Integer), click_type (String), clicked_item (Item), cursor_item (Item)
on_openyesplayer (Player)
on_closeplayer (Player), from_client (Boolean)
on_button_clickplayer (Player)
on_bundle_selectplayer (Player), selected_item_index (Integer)
on_item_changenew_item (Item), previous_item (Item), slot (Integer)
on_creative_actionyesplayer (Player), slot (Integer), clicked_item (Item, rw)

World

The world (Minestom instance). The subject is bound as world.

MethodCancellableBound variables
on_tickduration (Integer)
on_chunk_load · on_chunk_unloadchunk_x (Integer), chunk_z (Integer)
on_register · on_unregister
on_section_invalidate
on_block_updateblock (Block), block_position (Location)
on_entity_addyesentity (Entity)
on_entity_removeentity (Entity)

Server

The global singleton, plus the pre-login and connection-only events that have no player or entity subject yet. The subject is bound as server (Server config).

MethodCancellableBound variables
on_list_pingyesstatus (String, rw)
on_client_pingyesdelay (Integer, rw), payload (Integer, rw)
on_tick_monitor
on_pre_loginconnection (Any), username (String, rw), game_profile (Any)
on_player_configurationplayer (Player), spawning_instance (World, rw), hardcore (Boolean)
on_tps_changepast (Double), current (Double) — see TPS

No Player before login

on_pre_login, on_client_ping, and on_list_ping fire before there is a Player object — they carry only a raw connection, which is why they live on Server rather than Player.

Npc & Hologram

The NPC and hologram receivers reuse the same method set as their lowercase npc "id" { } / hologram "id" { } declarations:

ReceiverMethods
Npcon_click, on_left_click, on_tick
Hologramon_click, on_line_click, on_tick

Fan-out — one event, several receivers

A single engine event can surface on more than one receiver, so you handle it wherever it reads most naturally. When a player breaks a block, both the block and the player see it; when an entity takes damage, Entity.on_hit fires, and if the entity is a mob, Mob.on_hit fires too.

Engine eventReceivers it surfaces on
block breakBlock.on_break · Player.on_break_block
block placeBlock.on_place · Player.on_place_block
block interactBlock.on_interact · Player.on_interact_block
entity damagedEntity.on_hit · Mob.on_hit
item usedItem.on_use · Player.on_use_item
item droppedItem.on_drop · Player.on_drop_item
item picked upItem.on_pickup · Entity.on_pickup_item · Player.on_pickup_item

The most-specific subject fires first — a custom mob "id" before base Mob before base Entity. A cancel in any handler vetoes the shared underlying event; later handlers still run and can observe or undo the decision.

Overriding a base receiver

A lowercase custom declaration (mob "id" { }, item "id" { }, block_handler "id" { }) carries the same method set as its base receiver, and most-specific wins: when a custom method and the base method both exist, the custom one replaces the base for that id. To keep the base behavior, write call original method from inside the overriding method — optionally with with arguments <expr>, ... to forward values to it:

swoftlang
Mob {
    on_click {
        send "<gray>You poke a ${mob.type}." to player
    }
}

mob "ghoul" {
    type: "ZOMBIE"
    name: "<dark_green>Ghoul"
    health: 40

    on_click {
        send "<green>You poke the ghoul." to player
        call original method            // also run base Mob.on_click
    }

    on_target {
        call original method with arguments target
    }
}

call original method is only legal inside an overriding method — writing it in a base receiver or a method that overrides nothing is a compile error.

Cancelling

cancel event vetoes the underlying server event — a cancelled chat message is never broadcast. It is legal only inside a method the engine marks cancellable (the Cancellable column above), and only before the handler goes async. Anywhere else it is a compile error:

swoftlang
Player {
    on_join {
        cancel event
    }
}
txt
nc.sw:3:9: error: event 'on_join' is not cancellable
        cancel event
        ^

Async methods

A method runs on the tick thread by default. Mark its body async where slow work must not block a tick, following the usual async coloring rules. Cancellation is sync-only, so decide and cancel synchronously, then hand slow work to an async method or a spawned task:

swoftlang
Player {
    on_chat {
        if message contains "spoiler" {
            cancel event
            spawn warn_later(player)
        }
    }
}

async function warn_later(p: Player) {
    wait 1 seconds
    send "<red>No spoilers in chat!" to p
}

The Packet receiver

Packet { } is the raw-packet escape hatch: a listener on inbound Minestom packets keyed by class name, for the rare cases the typed receivers above don't cover. Each on "ClassName" { } handler binds player (the sender) and packet (the raw packet) in scope. See Packets for the full treatment.

swoftlang
Packet {
    on "ClientPlayerActionPacket" {
        broadcast "<gray>${player.name} sent a player-action packet"
    }
}

The typed Player.on_packet_in / on_packet_out methods cover the common "a packet arrived" case; reach for Packet { } only when you need a specific packet class by name.

Commands are separate

command "..." { } declarations are not events — they define the slash-commands players type, and are unchanged. Receivers handle what happens on the server; commands handle what players ask for.