Scripting
Scripts tell a bot what to do. They use a small, safe, Python-style language with 225 bot functions and 73 events. Every one of them is also a block in the block builder.
View as Markdown · give it to an AI assistant to write scripts for you
Your first script
PASSWORD = "my-password"
async def on_join(bot):
bot.sleep(3)
bot.send_chat(f"/login {PASSWORD}")
async def on_chat(bot, message):
if "hello" in message.lower():
message.reply("hi " + message.sender)- A script is a set of handlers: functions named after an event (
on_join,on_chat,on_kick, …). The bot runs a handler each time its event happens. - The first parameter is always the bot. The others are what the event gives you, like
messageforon_chatorreasonforon_kick. bot.send_chat(...)andsend_chat(...)do the same thing.awaitis optional.- Arguments go by position or by name:
bot.find_block("oak_log", radius=16). - Mistakes come back with the line number and a “did you mean” suggestion.
To run a script, pick it when you start an account, or assign it under Details → Behavior on the Accounts page. The assigned script runs every time the account starts. Its log.info(...) lines and errors appear in the editor's Output panel.
What functions give back
Functions return numbers, text, True/False, lists, None, or records you read with a dot. Records that stand for text act like text: "hi" in message, player == "Steve".
| Record | Fields |
|---|---|
| message | .text, .sender (None for server messages), .kind, .is_whisper, .matches(regex), .reply(text) |
| player | .name, .uuid, .display_name, .prefix, .suffix, .team, .ping, .gamemode, .position, .distance |
| entity | .type, .name, .uuid, .position, .velocity, .health, .distance, .is_player, .is_hostile, .is_item, .item |
| block | .id, .state, .position, .x, .y, .z, .is_air, .is_solid |
| item | .id, .name, .count, .slot, .hotbar |
| position | .x, .y, .z, .distance_to(other), .offset(dx, dy, dz), .floor(), .center() |
Inventory slots use Minecraft's numbers: 5–8 armor, 9–35 main inventory, 36–44 hotbar (hotbar slot 0 is 36), 45 off hand.
Settings and variables
Put settings at the top of the script (DELAY = 30, HOME = pos(0, 64, 0)). A variable set in a handler is shared with every other handler. New names inside a helper function stay inside that function.
kills = 0 # shared by every handler
async def on_attack(bot, entity):
kills += 1
def count_logs(bot):
total = 0 # only exists inside count_logs
for item in bot.find_items("oak_log"):
total += item.count
return totalHelpers, timers, and background tasks
Any def that isn't named after an event is a helper. Call it yourself, or hand it to the bot without quotes or brackets. If its first parameter is bot, the bot is passed in for you.
def patrol(bot):
bot.walk_to(10, 64, 10)
bot.walk_to(-10, 64, -10)
async def on_join(bot):
bot.every(60, patrol) # every minute
bot.after(5, patrol) # once, in 5 seconds
task = bot.run_task(patrol) # in the background: task.pause(), .resume(), .cancel(), .wait()Waiting
Every wait takes timeout= and returns None or False if time runs out.
msg = bot.wait_for_chat("Please log in", timeout=10)
if msg is None:
log.warn("no login prompt")
bot.wait_for_health(15, timeout=30)
bot.wait_until(is_safe, timeout=60) # is_safe is one of your functionsErrors
try:
bot.break_block(10, 64, 10)
except Exception as e:
log.warn("couldn't mine: " + e.message)A failing handler never stops the others. The error is logged with its line number and on_error(bot, error) runs. bot.try_action(fn, retries=3) and bot.retry(fn) retry flaky steps; bot.restart_on_error(True) restarts the script after a crash.
Staying online 24/7
The account's Keep online setting (on by default) already rejoins after kicks and restarts. A script lives as long as its session: handlers keep listening, and a while True loop with a wait inside runs for as long as the bot does. During a reconnect, anything that needs the world (moving, looking, attacking) waits until the bot is back instead of failing, so loops carry on by themselves.
def guard(bot):
while True:
mob = bot.find_entity("hostile", radius=6)
if mob:
bot.attack(mob)
bot.sleep(0.5)
async def on_start(bot):
bot.run_task(guard)
async def on_chat(bot, message): # keeps listening across every rejoin
if message == "!pos":
message.reply(str(bot.get_position()))Variables, timers, and tasks survive a reconnect. on_reconnect runs after the rejoin and on_join runs again. To control reconnects from the script instead, use bot.auto_reconnect(True, delay=10, max_attempts=0) (0 = keep trying). A ban or mute takes the bot off the server and keeps it off.
Anti-AFK
bot.anti_afk(interval=30, jump=True, rotate=True, move=False, swing=False, sneak=False, command=None, no_fly=True) does a small random action every interval (±25%). With no_fly the bot also lands whenever the server has it flying, like ranked players in Hypixel lobbies. It is the same as the account's Anti-AFK setting: calling it replaces that setting for this session, bot.anti_afk(False) turns it off, and bot.afk_settings() shows what is running.
Webhooks
async def on_kick(bot, reason):
bot.webhook(reason, title="Kicked", level="error")
async def on_whisper(bot, message):
bot.webhook(f"{message.sender}: {message.text}", webhook="dms")bot.webhook(message, title=None, level="info", webhook=None) posts to a webhook you added under Webhooks (Discord, Slack, or any URL that accepts JSON). webhook= picks one by name; otherwise your default is used. Scripts never see the URL. Each bot can send 20 per minute.
Raw packets
bot.send_raw_packet("swing", ["varint", 0]) # main hand
bot.send_raw_packet("chat_command", ["string", "spawn"]) # unsigned command
bot.send_raw_packet(0x3F, "00") # id + hex bodyFor experts: sends a serverbound play packet by name (or numeric id) with a body given as hex text or type/value pairs (bool, byte, ubyte, short, ushort, int, long, float, double, varint, varlong, angle, string, uuid, position, bytes). The body isn't checked, so a wrong one gets the bot kicked — use the normal functions when one exists. At most 50 per second.
The language
Supported: numbers, text and f-strings (f"hp={hp:.1f}"), True/False/None, lists with indexing, slicing and .append(), if/elif/else, while, for, break, continue, return, try/except/finally, and/or/not, in, is None, += -= *= /=, and helper functions.
Not supported, on purpose: imports, files, network, classes, lambdas, decorators, dictionaries, comprehensions, and a def inside another def. Scripts are sandboxed: they can only affect their own bot.
Limit: each handler gets about 200,000 steps of work between waits. Any wait (like bot.sleep) refills it, so a loop that never waits is stopped, while a loop that waits can run for days.
Block builder
- Every function and event below is also a block. Drag an event (like When joined server) onto the canvas, then drag blocks under it until they snap.
- If, Repeat, Forever, and the other loop blocks hold blocks inside them.
- Dragging a block takes the blocks under it along. Drop it back on the block list to delete it; Ctrl+Z undoes.
- A stack that isn't under an event is kept on the canvas but doesn't run.
- Type values right on the block. Click a block to see all its options. The
{ }switch next to a field lets you type code instead of a plain value — a variable likemessageor an expression likebot.get_health() < 10. - Script variables holds the settings at the top of a script (
COUNT = 3); they're set once when the script starts and every flow can read them. - The Code block holds lines of Python for anything the other blocks can't show, like
items.append(x). Tab indents inside it. - Saving turns the blocks into the script's code (press Code to read it). Code written in the code editor opens here as blocks, with any line that has no matching block kept in a Code block; it runs exactly the same. Saving from the builder drops comments.
API reference
Functions are called as bot.name(...). Events are handled with async def on_event(bot, ...).
Connection
- async def on_connect(bot)
- The connection to the server is established.
- async def on_login(bot)
- Login finished; the world is loading.
- async def on_spawn(bot)also on_join
- Spawned into the world (after every join and rejoin).
- async def on_ready(bot)
- Spawned and the surrounding chunks are loaded.
- async def on_disconnect(bot, reason)
- The connection ended, for any reason.
- async def on_kick(bot, reason)
- The server sent a disconnect message (reason text as received). If the server closes the socket before the message arrives, only `on_disconnect` fires.
- async def on_ban(bot, reason)
- Disconnected with a ban/restriction message.
- async def on_server_transfer(bot, info)
- Moved between servers behind a proxy (BungeeCord/Velocity) or transferred; `info.type` is "switch" or "transfer".
- bot.reconnect(delay=1.0)
- Drop the connection and rejoin the same server after `delay` seconds. The script keeps running and `on_reconnect` fires after the rejoin.
- bot.disconnect()
- Leave the server. Auto-reconnect is turned off first, so the session ends.
- bot.is_connected() → bool
- True while connected to the server.
- bot.is_spawned() → bool
- True once the bot has spawned into the world.
- bot.last_kick_reason() → str | None
- The raw reason text of the most recent kick, or None.
- bot.last_disconnect_reason() → str | None
- The raw reason of the most recent disconnect of any kind, or None.
- bot.last_kick_classification() → str | None
- How the last disconnect was classified: kick, temporary_ban, permanent_ban, server_restart, network_failure, ...
- bot.wait_for_connect(timeout=None) → bool
- Wait until connected. Returns False on timeout.
- bot.wait_for_spawn(timeout=None) → bool
- Wait until spawned in the world. Returns False on timeout.
Chat
- async def on_chat(bot, message)
- Any chat or system message. `message.text`, `message.sender` (None for system), `message.kind`, `message.matches(regex)`.
- async def on_system_message(bot, message)also on_server_message
- A message from the server itself (not a player).
- async def on_whisper(bot, message)
- A private message to the bot.
- bot.send_chat(text)also chat
- Send a chat message.
- bot.send_command(command)
- Run a server command. The leading `/` is optional.
- bot.whisper(player, text)
- Send a private message (`/msg player text`).
- bot.wait_for_chat(text=None, timeout=None, regex=False) → message | None
- Wait for a chat or system message containing `text` (any message if omitted; a regular expression if `regex=True`). Returns the message, or None on timeout.
Players & tab list
- async def on_player_join(bot, player)also on_player_seen
- A player appeared in the tab list.
- async def on_player_leave(bot, player)also on_player_left
- A player left the tab list.
- async def on_player_list_update(bot, player)
- A tab-list entry changed (display name, game mode, ping).
- bot.get_players() → list[player]
- Everyone in the tab list.
- bot.find_player(name) → player | None
- Look up an online player by name (case-insensitive).
- bot.find_players(prefix=None, suffix=None, team=None, tag=None, regex=None, distance_lt=None) → list[player]
- Filter online players by team prefix/suffix, team name, a tag in their display name, a name regex, or distance (only players in render range have a distance).
- bot.is_player_online(name) → bool
- True if the player is in the tab list.
Movement
- bot.move_forward(seconds=None)
- Walk forward. With `seconds`, walk that long and stop; without, keep walking until `stop_moving()`.
- bot.move_backward(seconds=None)
- Walk backward (see `move_forward`).
- bot.move_left(seconds=None)
- Strafe left (see `move_forward`).
- bot.move_right(seconds=None)
- Strafe right (see `move_forward`).
- bot.move(direction, duration=None)
- Walk in a direction: forward, backward, left, right, forward_left, forward_right, backward_left, backward_right.
- bot.stop_moving()
- Stop walking, sprinting, and following.
- bot.jump()
- Jump once.
- bot.sprint(on=True)
- Start sprinting forward (`sprint(False)` stops).
- bot.crouch(on=True)also sneak
- Hold or release sneak.
- bot.walk_to(x, y=None, z=None, timeout=60.0) → bool
- Walk to coordinates or an entity/player/block without breaking blocks. Returns True when it arrives.
- bot.follow(target, distance=2.0)
- Keep following a player (name or player record) until `stop_following()`.
- bot.stop_following()
- Stop following.
- bot.is_moving() → bool
- True while walking, following, or pathfinding.
- bot.is_sprinting() → bool
- True while sprinting.
- bot.is_crouching() → bool
- True while sneaking.
- bot.is_swimming() → bool
- True while swimming.
- bot.is_flying() → bool
- True while flying (creative/spectator or allowed flight).
- bot.is_on_ground() → bool
- True while standing on a block.
- bot.stop_flying()
- Stop flying and drop to the ground.
Camera
- bot.look(yaw, pitch)
- Face an absolute direction. Yaw: 0 south, 90 west, 180 north, -90 east. Pitch: -90 up, 90 down.
- bot.look_at(x, y=None, z=None)
- Face a point, block, entity, or player.
- bot.turn_left(degrees=90.0)
- Turn left by `degrees`.
- bot.turn_right(degrees=90.0)
- Turn right by `degrees`.
- bot.look_up(degrees=30.0)
- Tilt the camera up.
- bot.look_down(degrees=30.0)
- Tilt the camera down.
- bot.rotate(dyaw, dpitch)
- Turn relative to the current direction.
- bot.get_yaw() → float
- Current yaw in degrees.
- bot.get_pitch() → float
- Current pitch in degrees.
- bot.get_facing_direction() → str
- north, south, east, or west.
Interaction
- bot.attack(target=None) → bool
- Hit an entity: the one given, or whatever is under the crosshair. Returns False if there was nothing to hit.
- bot.hold_attack()
- Keep the attack button held (mines the targeted block / hits repeatedly).
- bot.release_attack()
- Release the attack button.
- bot.use()also interact
- Right-click with the held item.
- bot.hold_use()
- Keep right-click held (eat, draw a bow, block with a shield).
- bot.release_use()
- Release right-click.
- bot.interact_block(x=None, y=None, z=None)
- Right-click a block (door, lever, button, chest...). Defaults to the block under the crosshair. Walks into reach first if needed.
- bot.interact_entity(target=None) → bool
- Right-click an entity (villager, mount...). Defaults to the crosshair target.
- bot.break_block(x=None, y=None, z=None, timeout=15.0) → bool
- Mine a block (crosshair block by default) and wait until it is gone. Walks into reach first if needed. Returns True if it broke.
- bot.place_block(x, y=None, z=None, item_id=None) → bool
- Place the held block (or `item_id`, equipped first) at a position next to an existing block. Walks into reach first if needed. Returns True if the block appeared.
- bot.open_container(x=None, y=None, z=None, timeout=5.0) → screen | None
- Open a chest, barrel, furnace, crafting table, ... (walking into reach first if needed) and wait for it. Returns the open screen or None.
- bot.close_container()also close_screen
- Close the open container.
- bot.swing_hand()
- Play the arm swing animation.
- bot.swap_hands()
- Swap main hand and off hand items (F).
- bot.pick_block(x=None, y=None, z=None) → bool
- Select the hotbar slot holding the targeted block's item, like middle-click.
- bot.respawn()
- Click respawn after dying.
Inventory
- async def on_inventory_change(bot)
- Something in the inventory changed.
- async def on_slot_change(bot, slot, item)
- One slot changed (`item` is None when emptied).
- bot.get_inventory() → inventory
- The player inventory: `.items` (list of items), `.free_slots`, `.is_full`, `.selected_slot`. `inventory.is_full()` also works.
- bot.get_slot(slot) → item | None
- The item in an inventory slot (5–8 armor, 9–35 main, 36–44 hotbar, 45 off hand).
- bot.set_hotbar_slot(slot)
- Select hotbar slot 0–8.
- bot.get_selected_slot() → int
- The selected hotbar slot, 0–8.
- bot.get_held_item() → item | None
- The item in the main hand.
- bot.find_item(item_id) → item | None
- First inventory slot holding `item_id` (e.g. "bread").
- bot.find_items(item_id) → list[item]
- Every inventory slot holding `item_id`.
- bot.has_item(item_id, count=1) → bool
- True if the inventory holds at least `count` of the item.
- bot.count_item(item_id) → int
- Total count of an item across the inventory.
- bot.inventory_count() → int
- Number of non-empty inventory slots.
- bot.use_item(item_id=None) → bool
- Equip `item_id` if given, then right-click with it (eat, drink, throw...).
- bot.equip_item(item_id, hand="main") → bool
- Put an item in the hand (hotbar is used and selected), the off hand (`hand="off"`), or wear armor (`hand="armor"`).
- bot.drop_item(slot=None)
- Drop one item from the held stack (or a slot).
- bot.drop_stack(slot=None)
- Drop the whole held stack (or a slot).
- bot.drop_all(item_id) → int
- Drop every stack of an item. Returns how many stacks were dropped.
- bot.move_item(from_slot, to_slot)
- Move a stack between inventory slots.
- bot.swap_slots(a, b)
- Swap two inventory slots.
- bot.click_slot(slot, button="left")
- Left- or right-click an inventory slot.
- bot.shift_click(slot)
- Shift-click an inventory slot.
- bot.get_armor() → list[item | None]
- Worn armor: [helmet, chestplate, leggings, boots].
- bot.get_offhand() → item | None
- The off hand item.
Containers & menus
- async def on_screen_open(bot, screen)
- Any container/menu opened.
- async def on_screen_close(bot)
- The open container/menu closed.
- async def on_container_open(bot, screen)
- A storage container (chest, barrel, shulker box, ...) opened.
- async def on_container_update(bot, screen)
- The open container's contents changed.
- bot.get_open_screen() → screen | None
- The open container/menu: `.title`, `.type` (e.g. "generic_9x3"), `.id`.
- bot.get_container_slots() → list[item | None]
- The open container's own slots (not your inventory part).
- bot.take_item(item_id, count=None) → intalso withdraw_item
- Move an item from the open container into your inventory. Returns the number moved.
- bot.deposit_item(item_id, count=None) → int
- Move an item from your inventory into the open container. Returns the number moved.
- bot.deposit_all(keep_hotbar=True) → int
- Move all inventory items (hotbar kept by default) into the open container.
- bot.select_trade(index)
- Select a trade in an open merchant screen (0 = first).
- bot.rename_item(name)
- Set the item name in an open anvil.
Player state
- async def on_respawn(bot)
- Respawned after death.
- async def on_death(bot, message)
- The bot died (`message` is the death message).
- async def on_damage(bot, amount, attacker)
- Health went down. `attacker` is the entity responsible, if known.
- async def on_heal(bot, amount)
- Health went up.
- async def on_health_change(bot, health)
- Health changed.
- async def on_hunger_change(bot, food)
- Food level changed.
- async def on_effect_added(bot, effect)
- A potion effect started.
- async def on_effect_removed(bot, effect)
- A potion effect ended.
- async def on_fire(bot)
- The bot caught fire.
- async def on_drown(bot)
- The bot took drowning damage.
- async def on_fall(bot, amount)
- The bot took fall damage.
- async def on_xp_change(bot, xp)
- Total experience changed.
- async def on_level_change(bot, level)
- Experience level changed.
- async def on_position_change(bot, position)
- Moved at least one block (checked once per second).
- async def on_teleport(bot, position)
- The server teleported the bot (lobby/spawn sends, /tp, ...).
- bot.get_health() → floatalso health
- Health, 0–20.
- bot.get_max_health() → float
- Maximum health.
- bot.get_hunger() → int
- Food level, 0–20.
- bot.get_saturation() → float
- Food saturation.
- bot.get_air() → int
- Remaining air, 0–300 ticks.
- bot.get_armor_value() → float
- Armor points, 0–20.
- bot.get_experience() → experience
- Experience: `.level`, `.progress` (0–1), `.total`.
- bot.get_level() → int
- Experience level.
- bot.get_gamemode() → str
- survival, creative, adventure, or spectator.
- bot.get_position() → positionalso position
- Current position (`.x`, `.y`, `.z`).
- bot.get_dimension() → str
- Current dimension, e.g. "overworld", "the_nether".
- bot.get_effects() → list[effect]
- Active potion effects: `.id`, `.amplifier`, `.duration` (ticks).
- bot.has_effect(effect_id) → bool
- True if the effect (e.g. "speed") is active.
- bot.is_dead() → bool
- True while dead.
- bot.is_burning() → bool
- True while on fire.
- bot.is_underwater() → bool
- True when the head is under water.
- bot.is_in_lava() → bool
- True while touching lava.
- bot.is_in_water() → bool
- True while touching water.
- bot.is_riding() → bool
- True while mounted.
- bot.get_vehicle() → entity | None
- The entity being ridden.
World & blocks
- async def on_world_join(bot, dimension)
- Entered a dimension/world.
- async def on_world_leave(bot, dimension)
- Left a dimension/world.
- async def on_block_change(bot, block)
- A block within 32 blocks changed.
- async def on_block_break(bot, block)
- A nearby block became air.
- async def on_block_place(bot, block)
- A nearby air block became solid.
- async def on_weather_change(bot, weather)
- Weather changed: clear, rain, thunder.
- async def on_time_change(bot, phase)
- The time of day crossed into day, sunset, night, or sunrise.
- bot.get_block(x, y=None, z=None) → block | None
- The block at a position: `.id` (e.g. "oak_log"), `.position`, `.state`, `.is_air`, `.is_solid`. None if the chunk is not loaded.
- bot.get_block_state(x, y=None, z=None) → str | None
- Full state text, e.g. "oak_log[axis=y]".
- bot.get_block_under_player() → block | None
- The block the bot stands on.
- bot.get_block_in_front() → block | None
- The block directly in front at foot level (by facing direction).
- bot.find_block(block_id, radius=32.0) → block | None
- Nearest loaded block of a type within `radius`. Accepts a list of ids too.
- bot.find_blocks(block_id, radius=32.0, limit=64) → list[block]
- All loaded blocks of a type within `radius`, nearest first.
- bot.find_nearest_block(block_id) → block | None
- Nearest block of a type anywhere in loaded chunks.
- bot.raycast(distance=4.5) → hit
- What the crosshair hits: `.type` ("block", "entity", "miss"), `.block`, `.entity`, `.position`, `.face`.
- bot.can_see(x, y=None, z=None) → bool
- True if nothing solid is between the bot's eyes and the point/entity.
- bot.is_air(x, y=None, z=None) → bool
- True if the block is air.
- bot.is_solid(x, y=None, z=None) → bool
- True if the block has a collision shape.
- bot.is_walkable(x, y=None, z=None) → bool
- True if a player can stand at this block position (solid below, two free blocks).
- bot.get_world_time() → int
- Time of day in ticks, 0–23999 (0 = sunrise, 6000 = noon, 13000 = night).
- bot.get_weather() → str
- clear, rain, or thunder.
Entities
- async def on_entity_spawn(bot, entity)
- An entity came into range.
- async def on_entity_despawn(bot, entity)
- An entity left range or was removed.
- async def on_entity_move(bot, entity)
- An entity within 16 blocks moved (at most twice a second per entity).
- async def on_entity_damage(bot, entity)
- A nearby entity took damage.
- async def on_entity_death(bot, entity)
- A nearby entity died.
- bot.get_entities() → list[entity]
- Every loaded entity, nearest first (max 256).
- bot.get_nearby_entities(radius=16.0) → list[entity]
- Entities within `radius`, nearest first.
- bot.find_entity(type=None, name=None, radius=64.0) → entity | None
- Nearest entity matching a type ("zombie") and/or name.
- bot.find_entities(type=None, name=None, radius=64.0) → list[entity]
- All entities matching a type and/or name, nearest first.
- bot.get_nearest_entity(type=None) → entity | None
- The nearest entity (optionally of a type).
- bot.get_entity(uuid) → entity | None
- Look up an entity by UUID.
Dropped items
- async def on_item_drop(bot, entity)
- An item entity appeared.
- async def on_item_pickup(bot, item)
- The bot picked up an item.
- bot.get_dropped_items(radius=32.0) → list[entity]
- Item entities on the ground; each has `.item` (`.id`, `.count`).
- bot.find_dropped_item(item_id=None, radius=32.0) → entity | None
- Nearest dropped item, optionally of a type.
- bot.walk_to_item(item=None, timeout=30.0) → bool
- Walk onto a dropped item (nearest one by default, or an item id / item entity) to pick it up.
Combat
- async def on_attack(bot, entity)
- The bot attacked an entity.
- async def on_attacked(bot, attacker)
- Something hurt the bot.
- bot.get_attacker() → entity | None
- The entity that last hurt the bot (within 10 seconds).
- bot.get_target() → entity | None
- The target set with `set_target`.
- bot.set_target(entity)
- Remember an entity as the combat target (used by `attack()` when nothing is in the crosshair).
- bot.nearest_hostile(radius=16.0) → entity | None
- The nearest hostile mob.
- bot.is_under_attack(seconds=5.0) → bool
- True if the bot took damage in the last `seconds`.
- bot.distance_to(x, y=None, z=None) → float
- Distance from the bot to a point, block, entity, or player.
Navigation
- async def on_path_complete(bot, position)
- Arrived at a pathfinding target.
- async def on_path_failed(bot, position)
- Pathfinding gave up.
- bot.pathfind_to(x, y=None, z=None, avoid_lava=True, avoid_fall=True, allow_jump=True, allow_swim=True, allow_mining=False, max_distance=512.0, timeout=120.0) → bool
- Find and follow a path to a point or entity. Returns True on arrival; fires `on_path_complete` / `on_path_failed`.
- bot.stop_pathfinding()
- Cancel the current path.
- bot.can_reach(x, y=None, z=None, max_distance=128.0) → bool
- True if a walking path to the point exists (computed without moving).
- bot.get_path(x, y=None, z=None, max_distance=128.0) → list[position]
- The positions a walking path would visit (empty if unreachable).
- bot.is_pathfinding() → bool
- True while a path is being computed or followed.
Coordinates
- bot.distance_to_player(name) → float | None
- Distance to a player in render range, else None.
- bot.save_position(name, position=None)
- Remember the current (or given) position under a name.
- bot.get_saved_position(name) → position | None
- A position saved with `save_position`.
Scoreboard & server UI
- async def on_bossbar(bot, bar)also on_bossbar_update
- A boss bar was added or changed.
- async def on_scoreboard_update(bot, scoreboard)
- The sidebar changed (throttled to once per second).
- bot.get_scoreboard() → scoreboard | None
- The sidebar: `.title` and `.lines` (top to bottom).
- bot.get_scoreboard_title() → str | None
- The sidebar title.
- bot.get_scoreboard_lines() → list[str]
- Sidebar lines top to bottom, colors stripped.
- bot.get_tab_header() → str
- The tab list header text.
- bot.get_bossbars() → list[bossbar]
- Visible boss bars: `.title`, `.progress` (0–1), `.id`.
Titles & action bar
- async def on_actionbar(bot, text)
- Action bar text above the hotbar.
- async def on_title(bot, text)
- A big title on screen.
- async def on_subtitle(bot, text)
- A subtitle on screen.
- bot.get_title() → str | None
- The most recent title text.
- bot.get_actionbar() → str | None
- The most recent action bar text.
- bot.wait_for_title(text=None, timeout=None) → str | None
- Wait for a title (containing `text`). Returns its text or None.
- bot.wait_for_actionbar(text=None, timeout=None) → str | None
- Wait for an action bar message (containing `text`).
Sounds & particles
- async def on_sound(bot, sound)
- A sound played: `.id`, `.position`, `.volume`, `.pitch`, `.category`.
- async def on_particle(bot, particle)
- Particles spawned: `.id`, `.position`, `.count`.
- bot.wait_for_sound(sound_id, timeout=None, radius=None) → sound | None
- Wait for a sound whose id contains `sound_id` (e.g. "fishing_bobber.splash"), optionally within `radius` blocks.
Packets
- async def on_packet_receive(bot, packet)
- A raw packet arrived: `.type`, `.data` (see `packet_filter`).
- bot.log_packets(enabled=True, types=None)
- Write received packet types to the script log (optionally only `types`, e.g. ["SetHealth"]).
- bot.packet_filter(types)
- Choose which packet types fire `on_packet_receive` (default: everything except chunk and movement spam).
- bot.send_raw_packet(packet, data=None) → intalso send_packet
- Send a serverbound game packet you build yourself. `packet` is a name ("swing", "chat_command", "use_item") or protocol id; `data` is the body as hex text ("0a ff") or type/value pairs (["varint", 0, "string", "hi"]; types: bool, byte, ubyte, short, ushort, int, long, float, double, varint, varlong, angle, string, uuid, position, bytes). Returns the body size. Bodies are not checked: a wrong one gets the bot kicked or banned. At most 50 per second.
Waiting
- bot.sleep(seconds)also wait
- Pause for a number of seconds.
- bot.wait_until(condition, timeout=None, interval=0.25) → bool
- Call `condition` until it returns something true. Returns False on timeout.
- bot.wait_while(condition, timeout=None, interval=0.25) → bool
- Wait while `condition` keeps returning true. Returns False on timeout.
- bot.wait_for_event(event, timeout=None) → anyalso wait_for
- Wait for an event ("chat", "on_death", or a custom one). Returns its first value (or True), None on timeout.
- bot.wait_for_player(name, timeout=None) → bool
- Wait until a player is online.
- bot.wait_for_player_leave(name, timeout=None) → bool
- Wait until a player is no longer online.
- bot.wait_for_health(value, timeout=None, below=False) → bool
- Wait until health is at least `value` (or at most, with `below=True`).
- bot.wait_for_position(x, y=None, z=None, radius=1.5, timeout=None) → bool
- Wait until the bot is within `radius` of a point.
- bot.wait_for_inventory_change(timeout=None) → bool
- Wait until the inventory changes.
- bot.wait_for_block(x, y=None, z=None, block_id=None, timeout=None) → bool
- Wait until the block at a position becomes `block_id` (or changes at all).
Timers
- bot.after(seconds, function, *args) → int
- Run a function once after a delay. Returns a timer id.
- bot.every(seconds, function, *args) → int
- Run a function repeatedly. Returns a timer id.
- bot.set_timeout(function, seconds, *args) → int
- Same as `after`, with the function first.
- bot.set_interval(function, seconds, *args) → int
- Same as `every`, with the function first.
- bot.cancel_timer(timer_id) → bool
- Stop a timer. Returns False if it was already gone.
- bot.schedule_at(time, function, *args) → int
- Run a function at a clock time "HH:MM" (UTC, next occurrence) or a unix timestamp.
- bot.schedule_when(condition, function, interval=1.0) → int
- Run `function` once, as soon as `condition` returns true.
Tasks
- bot.run_task(function, *args) → task
- Run a function in the background. Returns a task: `.cancel()`, `.pause()`, `.resume()`, `.wait()`, `.is_running`.
- bot.cancel_all_tasks()
- Cancel every background task and timer.
- bot.get_tasks() → list[task]
- Background tasks that are still running.
- bot.acquire(name, timeout=None) → bool
- Take a named lock (e.g. "movement") so two tasks don't fight over the same controls. Waits if another task holds it. Released by `release` or when the holder finishes.
- bot.release(name)
- Release a named lock.
Custom events
- bot.on(event, function, priority=0)
- Also run `function` for an event. Higher priority runs first; a listener that returns False stops the rest.
- bot.once(event, function, priority=0)
- Like `on`, but only the next time.
- bot.off(event, function=None)
- Remove a listener added with `on`/`once` (all of them for the event if no function).
- bot.emit(event, data=None)
- Fire a custom event; `on_<event>` handlers and listeners receive `data`.
Reconnect & recovery
- async def on_reconnect(bot, attempts)
- Back in the world after an automatic reconnect.
- async def on_reconnect_attempt(bot, attempt)
- A reconnect attempt is starting.
- async def on_reconnect_failed(bot, attempts)
- Auto-reconnect used up `max_attempts`.
- async def on_timeout(bot)
- No packets for `detect_stuck(packet_timeout=...)` seconds.
- async def on_stuck(bot, reason)
- Logged in but never spawned within `detect_stuck(loading_timeout=...)`.
- bot.auto_reconnect(enabled=True, delay=5.0, max_attempts=10)
- Rejoin automatically after a disconnect. The script keeps its variables, timers, and tasks; `on_reconnect` runs after each rejoin. `max_attempts=0` keeps trying forever. Failed attempts in a row wait longer each time (×1.5, up to 5 minutes).
- bot.reconnect_attempts() → int
- How many reconnect attempts happened since the last successful join.
- bot.detect_stuck(loading_timeout=60.0, packet_timeout=30.0, reconnect=True)
- Fire `on_stuck` when spawning takes too long or `on_timeout` when the server goes silent; optionally reconnect.
- bot.restart_on_error(enabled=True, max_restarts=5)
- Restart the script when a handler crashes (at most `max_restarts` per 10 minutes).
Error handling
- async def on_error(bot, error)
- A handler or task failed: `.message`, `.line`, `.event`, `.trace`.
- async def on_script_crash(bot, error)
- A failure is restarting the script (`restart_on_error`).
- bot.try_action(function, *args, retries=0, delay=1.0, fallback=None) → any
- Call a function; if it fails, retry up to `retries` times, then return `fallback`.
- bot.retry(function, *args, attempts=3, delay=1.0) → any
- Call a function until it returns something true (or stops failing). Returns the last result.
- bot.timeout(function, seconds, *args) → any
- Run a function but give up after `seconds` (returns None).
Logging
- bot.log(message, level="info")
- Write to the script log (shown live in the editor and saved with the session).
- bot.log_info(message)
- `log.info(msg)`.
- bot.log_warn(message)
- `log.warn(msg)`.
- bot.log_error(message)
- `log.error(msg)`.
- bot.log_debug(message)
- `log.debug(msg)` — only written when debug logging is on.
- bot.log_events(chat=True, events=False, commands=True, debug=False)
- Automatically log incoming chat, every event, and the bot's own chat/commands. `debug=True` enables `log.debug`.
Notifications
- bot.notify(message, level="info")
- Send a notification to the dashboard bell (and a desktop notification if the browser allows it).
- bot.webhook(message, title=None, level="info", webhook=None)also send_webhook
- Post a message to one of your webhooks (Settings → Webhooks): Discord, Slack, or any URL that takes JSON. `webhook` picks one by name (default: your default webhook); `level` is info, success, warn, or error (the embed color). The URL never reaches the script. At most 20 per minute per bot.
Script lifecycle
- async def on_start(bot)also on_script_start
- The script starts (once per session, before joining).
- async def on_stop(bot)also on_script_stop
- The script is being stopped (session end or `stop_script()`).
- async def on_reload(bot)also on_script_reload
- After `reload_script()`.
- bot.stop_script()
- Stop this script (the bot stays connected). `on_stop` runs first.
- bot.restart_script()
- Stop everything, clear variables, and start again from `on_start`/`on_join`.
- bot.reload_script()
- Like restart, but fires `on_reload` instead of `on_start`.
- bot.uptime() → float
- Seconds since the script started.
Session info
- bot.server_info() → info
- `.host`, `.port`, `.online_mode`.
- bot.account_info() → info
- `.name`, `.uuid`.
- bot.proxy_info() → info
- `.protocol`, `.host`, `.port` (never credentials).
- bot.get_ping() → int | None
- The bot's latency in ms, from the tab list.
Utilities
- bot.random_delay(min, max) → float
- Wait a random time between `min` and `max` seconds. Returns the time waited.
- bot.repeat(function, times, delay=0.0, *args)
- Call a function `times` times with an optional delay between calls.
- bot.debounce(function, seconds, *args)
- Run a function once things go quiet: every call restarts a `seconds` countdown.
- bot.throttle(function, seconds, *args) → bool
- Run a function now unless it already ran in the last `seconds`. Returns True if it ran.
Debugging
- bot.event_history(limit=20) → list[record]
- The most recent events: `.event`, `.time`, `.summary`.
- bot.stats() → record
- Profiler counters: `.uptime`, `.events`, `.errors`, `.handler_runs`, `.avg_handler_ms`, `.max_handler_ms`, `.fuel_used`, `.tasks`, `.timers`.
- bot.get_movement_state() → record
- What the bot is doing: `.walking`, `.sprinting`, `.crouching`, `.following`, `.pathfinding`, `.on_ground`.
- bot.assert_true(condition, message="check failed") → bool
- Log PASS/FAIL for a condition (useful while testing a script). Returns the condition.
AFK helpers
- async def on_server_restart(bot, reason)
- Disconnected because the server is restarting/closing.
- async def on_sent_to_spawn(bot, position)
- Teleported to within 8 blocks of the world spawn.
- bot.anti_afk(enabled=True, interval=30.0, jump=True, rotate=True, move=False, swing=False, command=None, command_interval=300.0, sneak=False, no_fly=True)also set_afk_mode
- Built-in anti-AFK: every `interval` seconds (±25%) jump, look around, step, swing, or sneak; optionally run a command every `command_interval` seconds. With `no_fly` (on by default) the bot lands whenever the server has it flying, like ranked players in Hypixel lobbies. The same engine as the account's Anti-AFK setting: calling this replaces it for this session; `anti_afk(False)` turns it off.
- bot.afk_settings() → record
- Current anti-AFK: `.enabled`, `.source` ("account" or "script"), `.interval`, `.jump`, `.rotate`, `.move`, `.swing`, `.sneak`, `.command`, `.no_fly`, `.actions` (performed this session).
- bot.is_afk() → bool
- True while anti-AFK mode is running.
- bot.get_keepalive() → record
- `.last_packet` (seconds since any packet), `.last_keepalive`, `.connected_for`.
- bot.wait_for_server(timeout=None) → bool
- After a restart/kick with auto-reconnect on, wait until the bot is back in the world.
Built-in functions
- len(x)
- Length of a string or list.
- str(x)
- Convert to text.
- int(x)
- Convert to a whole number.
- float(x)
- Convert to a decimal number.
- bool(x)
- Convert to True/False.
- list(x)
- Copy a list, or split a string into characters.
- range(stop) / range(start, stop, step)
- A list of numbers.
- abs(x)
- Absolute value.
- min(a, b, ...) / min(list)
- Smallest value.
- max(a, b, ...) / max(list)
- Largest value.
- sum(list)
- Add up numbers.
- round(x, digits=0)
- Round a number.
- floor(x)
- Round down.
- ceil(x)
- Round up.
- sqrt(x)
- Square root.
- sorted(list)
- Sorted copy of a list.
- reversed(list)
- Reversed copy of a list.
- random()
- Random decimal between 0 and 1.
- randint(a, b)
- Random whole number between a and b (inclusive).
- choice(list)
- Random element of a list.
- time()
- Current unix time in seconds.
- distance(a, b)
- Distance between two positions/entities/blocks.
- pos(x, y, z)
- Make a position.
- strip_colors(text)
- Remove Minecraft color codes (§a, &b, ...).
- format_chat_text(text)
- Strip color codes and collapse whitespace.
- parse_chat(text)
- Split "[Rank] Name: message" or "<Name> message" into `.prefix`, `.name`, `.message`.
- regex_match(pattern, text)
- True if the regular expression matches.
- regex_find(pattern, text)
- First match, or None.
- regex_find_all(pattern, text)
- Every match.
- regex_groups(pattern, text)
- Capture groups of the first match, or None.
- regex_replace(pattern, replacement, text)
- Replace matches.
Not available
- on_packet_send — Azalea does not surface outgoing packets as events at the pinned version; `log_packets()` logs packets sent with `send_raw_packet`, and `log_events(commands=True)` logs chat and commands.
- Event cancellation of server events — Incoming server events cannot be cancelled. Listener chains can stop early by returning False.
- Environment variables — Scripts are sandboxed and cannot read the worker's environment. Use top-level constants instead.
- Secrets store — None. Keep secrets out of scripts you share with others.
- Sound notifications — None. `notify()` reaches the dashboard bell and browser notifications; `webhook()` reaches Discord, Slack, or your own URL.
- Breakpoints and step debugging — None. Use `event_history()`, `stats()`, `log_packets()`, and `log.debug()`.
- Hot reload on save — None. Saving a script applies on the next session start; `reload_script()` restarts the running copy.
Known limitations
- Pathfinding never digs or places blocks unless
allow_mining=True, and never crosses lava or long drops. on_block_breakreports what a block became, not what it was.