Complete Events Reference
This page documents all events that can be handled in SScript .event.ss files.
Event Lifecycle
- Server startup →
loadevent fires - Player connects →
player_connectevent - Player fully joined →
player_joinevent - Player does actions →
player_chat,block_place,block_break, etc. - Player dies →
player_death+player_deadevents - Player sleeps →
player_sleep,player_sleep_attemptevents - Player respawns →
player_respawnevent
Server Events
load → (no parameters)
Fires once when server starts and all scripts are loaded.
Usage: Initialization, persistent data setup.
on load:
log "Server starting..."
set_global("startup_time", sec(0))
log "Init complete"
end
Player Connection Events
player_connect(player) → object
Fires when a player’s connection is initialized (before full join).
Parameters:
player: Player object
Player object fields:
name— player’s usernameuuid— player’s UUIDtype— entity type (always “minecraft:player”)x,y,z— position coordinatespos— formatted position “X Y Z”dimension— dimension ID (e.g., “minecraft:overworld”)health— current health (0-20)gamemode— game mode (“survival”, “creative”, etc.)tags— list of command tagsnbt— NBT data as string
on player_connect(player):
log "Connection: " + player.name
end
player_join(player) → object
Fires when a player fully joins the server (after login).
Parameters:
player: Player object (see above)
Usage: Welcome messages, permissions setup, data loading.
on player_join(player):
log "Welcome " + player.name
# Grant tag if first time
if not has_tag(player.name, "seen_before"):
tag_add(player.name, "seen_before")
tellraw(player.name, "Welcome to the server!")
end
end
player_respawn(player, alive) → object, boolean
Fires when a player respawns after death.
Parameters:
player: Player objectalive:true= respawned,false= loading old player data
on player_respawn(player, alive):
log player.name + " respawned"
effect_give(player.name, "minecraft:resistance", 5, 0, false)
end
Chat Event
player_chat(player, message) → object, string
Fires when a player sends a chat message.
Parameters:
player: Player objectmessage: The chat message text
Usage: Chat logging, filters, command parsing.
on player_chat(player, message):
log "[" + player.name + "] " + message
# Log to file
file_mkdirs("sscripts/logs")
file_append("sscripts/logs/chat.log", player.name + ": " + message + "\n")
end
Block Events
block_interact(player, block) → object, object
Fires when a player successfully right-clicks a block.
Includes: Door toggle, button press, lever use, etc. (any interaction the server accepts).
Parameters:
player: Player objectblock: Block object (see below)
Block object fields:
id— block ID (e.g., “minecraft:diamond_ore”)x,y,z— block coordinatespos— formatted position “X Y Z”dimension— dimension ID
on block_interact(player, block):
log player.name + " interacted with " + block.id + " at " + block.pos
# Example: Log all door interactions
if contains(block.id, "door"):
log "Door interaction at " + block.pos
end
end
block_place(player, block) → object, object
Fires when a player actually places a new block.
This is semantically different from block_interact:
block_interactfires for any accepted right-click (doors, levers, etc.)block_placefires ONLY when actual block state changes (new block placed)
Parameters:
player: Player objectblock: Block object (the newly placed block)
Usage: Construction logging, grief protection, builds tracking.
on block_place(player, block):
log player.name + " placed " + block.id + " at " + block.pos
# Prevent obsidian building
if block.id == "minecraft:obsidian":
if not has_tag(player.name, "builder"):
run "setblock " + block.x + " " + block.y + " " + block.z + " air"
tellraw(player.name, "You can't place obsidian here")
end
end
end
block_break(player, block) → object, object
Fires when a player breaks a block.
Parameters:
player: Player objectblock: Block object (before destruction)
Usage: Mining restrictions, ore tracking, griefing protection.
on block_break(player, block):
log player.name + " broke " + block.id + " at " + block.pos
# Example: Log all diamond ore mining
if block.id == "minecraft:diamond_ore":
set_global("total_diamonds_mined", num(get_global("total_diamonds_mined")) + 1)
end
end
Player Death Events
player_death(player, location) → object, string
Fires when a player dies (including respawn delay).
Parameters:
player: Player object (at death location)location: Formatted position string “X Y Z”
on player_death(player, location):
log player.name + " died at " + location
end
player_dead(player, location) → object, string
Alternative name for the same player_death event (both fire together for compatibility).
on player_dead(player, location):
# This also fires when player_death fires
end
Sleep Events
player_sleep_attempt(player, bed_location) → object, string
Fires when a player tries to sleep (before success/failure).
Parameters:
player: Player objectbed_location: Formatted position string “X Y Z”
on player_sleep_attempt(player, bed_location):
log player.name + " attempts to sleep"
end
player_sleep(player, bed_location) → object, string
Fires when a player successfully goes to sleep.
Parameters:
player: Player objectbed_location: Formatted position string “X Y Z”
on player_sleep(player, bed_location):
log player.name + " went to sleep at " + bed_location
# Award sleep achievements
tag_add(player.name, "has_slept")
end
Event Handling Patterns
Pattern 1: Conditional Logic
on player_chat(player, message):
if contains(message, "spam"):
log "Blocked spam from " + player.name
end
end
Pattern 2: Tag-Based Filtering
on player_chat(player, message):
if has_tag(player.name, "muted"):
log "Muted player tried to chat: " + player.name
# Could prevent message here
end
end
Pattern 3: Conditional Block Protection
on block_break(player, block):
# Protect specific block types for non-admins
if block.id == "minecraft:obsidian" and not has_tag(player.name, "admin"):
run "setblock " + block.x + " " + block.y + " " + block.z + " " + block.id
tellraw(player.name, "You cannot break obsidian!")
end
end
Pattern 4: Deferred Action with wait
on player_join(player):
log player.name + " joined"
wait send_welcome, player.name
end
func send_welcome(name):
sleep 20 # 1 second delay
tellraw(name, "Welcome to the server!")
end
Pattern 5: Global State Tracking
on player_join(player):
set_global("last_joined", player.name)
end
on player_chat(player, message):
if message == "who_was_last":
last = get_global("last_joined")
log "Last player: " + str(last)
end
end
Event Processing Order
- Event fired by server/mixin
- All handlers registered for that event are queued
- Each handler gets own process on ProcessScheduler
- Handlers execute independently (not necessarily sequentially)
- Errors in one handler don’t affect others
Important Notes
- Event handlers are async: Use
waitto defer heavy operations - Order not guaranteed: Multiple handlers may execute in any order
- Game thread safe: Mixin hooks are thread-safe
- Player objects immutable: Don’t modify player object (read-only)
- Block positions: Use
get_block()to get current state if you need updates
Testing Events
Create test_events.event.ss:
on load:
log "=== SScript Event System Ready ==="
end
on player_join(player):
log "[JOIN] " + player.name + " (" + player.uuid + ")"
end
on player_chat(player, message):
log "[CHAT] " + player.name + ": " + message
end
on block_break(player, block):
log "[BREAK] " + player.name + " broke " + block.id + " at " + block.pos
end
on block_place(player, block):
log "[PLACE] " + player.name + " placed " + block.id + " at " + block.pos
end
on player_death(player, location):
log "[DEATH] " + player.name + " died at " + location
end