Skip to content

Callbacks

BlackoutRoulette edited this page Aug 15, 2026 · 1 revision

Callbacks

Callbacks are functions that the library calls automatically when specific events happen, such as receiving a message from the server or disconnecting. You define what should happen by overriding these functions in your client.

The Client class inherits from ClientCallbackInterface, which defines all available callbacks with empty default implementations. You override the ones you care about.

Connection lifecycle

Here is the typical sequence of events when connecting to an Archipelago server:

  1. You call client.start() to initiate the WebSocket connection
  2. Once connected, on_ready() fires — the connection is open but you haven't authenticated yet
  3. The server automatically sends a RoomInfo packet with server details, triggering on_room_info()
  4. You send a Connect packet with your slot name and game to authenticate
  5. The server responds with Connected or ConnectionRefused, triggering on_connected() or on_connection_refused()
  6. During the session, incoming packets are dispatched in order: on_received() (raw JSON string) -> on_packet() (parsed packet, all types) -> the specific handler (e.g. on_print_json())
  7. When the server disconnects, on_connection_closed() fires

Callback reference

The "Async" column indicates whether the callback must be defined with async def (Yes) or regular def (No). See Sync vs async callbacks below for details.

Connection callbacks

Callback Async Parameter Description
on_ready() Yes — WebSocket connection established, ready to send and receive packets
on_connect_error(error) No Connection error Connection attempt failed (e.g. refused, timeout, invalid URI)
on_connection_closed(close_code) No Close code Server closed the connection

Packet callbacks

Each packet callback receives a single argument: the parsed packet object. You can access the packet's fields as attributes (e.g. packet.slot, packet.errors). See the Packets page for the full list of fields on each packet type.

Callback Async Parameter Description
on_received(packet) Yes str Raw JSON string received from the server, before parsing
on_packet(packet) Yes ServerPacket Any parsed packet. Fires before any specific handler, useful for logging
on_connected(packet) Yes Connected Authentication successful. Contains your slot number, player list, etc.
on_connection_refused(packet) Yes ConnectionRefused Authentication rejected. Check packet.errors for reasons
on_room_info(packet) Yes RoomInfo Server info, sent automatically when you first connect
on_room_update(packet) Yes RoomUpdate Room state changed (players joining/leaving, etc.)
on_print_json(packet) Yes PrintJSON Formatted message from the server (chat, hints, item sends, etc.)
on_received_items(packet) Yes ReceivedItems Items delivered to the player
on_location_info(packet) Yes LocationInfo Response to a location scout request
on_data_package(packet) Yes DataPackage Game data (item names, location names, etc.)
on_bounced(packet) Yes Bounced Message relayed from another client via the server
on_retrieved(packet) Yes Retrieved Response to a data storage Get request
on_set_reply(packet) Yes SetReply Response to a data storage Set request
on_invalid_packet(packet) Yes InvalidPacket Server reports a malformed packet was sent

Sync vs async callbacks

Most callbacks are async — they are defined with async def and can use await inside them (e.g. to send packets back to the server).

Two callbacks are synchronous (regular def): on_connect_error and on_connection_closed. These run during connection management where async execution could interfere with reconnection and shutdown logic.

The library enforces this at assignment time. If you accidentally use the wrong type, you'll get a clear error:

# Wrong - on_ready is an async callback, so it must use "async def":
def bad_handler():
    print("ready")

client.on_ready = bad_handler
# TypeError: Cannot monkey patch coroutine function on_ready with non-coroutine function.

# Correct:
async def good_handler():
    print("ready")

client.on_ready = good_handler  # works

Overriding callbacks

There are two ways to override callbacks:

Option 1: Assigning functions directly

You can replace a callback by assigning a new function on the client instance. This is quick and convenient for simple use cases:

from archipelagopy import Client, packets


async def on_print_json(packet: packets.PrintJSON):
    for msg in packet.data:
        if msg.text is not None:
            print(f">> {msg.text}")


client = Client(port=12345)
client.on_print_json = on_print_json  # replaces the default (empty) on_print_json

Option 2: Subclassing (recommended)

For anything beyond a simple script, subclass Client and override the methods you need. This keeps all your callback logic organized in one class:

from archipelagopy import Client, packets
from archipelagopy.callback_interface import OnConnectExceptionUnion


class MyClient(Client):

    async def on_ready(self):
        print("Connected and ready")

    async def on_connected(self, packet: packets.Connected):
        print(f"Authenticated as slot {packet.slot}")

    async def on_connection_refused(self, packet: packets.ConnectionRefused):
        print(f"Refused: {packet.errors}")
        await self.stop()

    # Note: on_connect_error uses "def", not "async def"
    def on_connect_error(self, error: OnConnectExceptionUnion):
        print(f"Connection failed: {error}")

OnConnectExceptionUnion is a type alias imported from archipelagopy.callback_interface. It represents the possible error types: ConnectionRefusedError, TimeoutError, OSError, and several websocket-specific errors. You don't need to import it — it's only useful for type hints.

Using on_packet as a wildcard

on_packet fires for every parsed packet before the specific handler. This is useful for logging or inspecting all traffic:

class DebugClient(Client):

    async def on_packet(self, packet: packets.ServerPacket):
        print(f"Received: {type(packet).__name__}")

Clone this wiki locally