Packets
Inspect, cancel, and rewrite the raw packets between client and server.
Endstone raises an event for every packet that crosses the wire: PacketReceiveEvent for packets coming from a client, and PacketSendEvent for packets going to one. Both are cancellable and expose the packet's raw bytes, so you can observe, block, or rewrite traffic the higher-level API doesn't reach.
This is the lowest level of the API. payload is the raw packet data excluding the header - to read or change anything inside it you must decode and re-encode it yourself according to the Bedrock protocol (varints and all). Get it wrong and the client disconnects. Reach for a higher-level API first; use packets only when nothing else exposes what you need.
Register a packet handler like any other event. Each event gives you:
packet_id- the numeric type of the packetpayload- the raw bytes after the header (get and set)player- the player involved, orNonefor packets sent before login completessub_client_id-0for the primary client,1-3for split-screen
Observe packets
The simplest use is watching traffic. Filter by packet_id - logging every packet is overwhelming:
from endstone.event import event_handler, PacketSendEvent
# packet IDs come from the Bedrock protocol; they can change between versions
TEXT_PACKET = 9
@event_handler
def on_packet_send(self, event: PacketSendEvent):
if event.packet_id == self.TEXT_PACKET:
who = event.player.name if event.player else "<pre-login>"
self.logger.info(f"text packet to {who}: {len(event.payload)} bytes")Drop a packet
Because the events are cancellable, setting is_cancelled stops the packet from being sent or processed:
from endstone.event import event_handler, PacketReceiveEvent
@event_handler
def on_packet_receive(self, event: PacketReceiveEvent):
if event.packet_id == self.BLOCKED_PACKET:
event.is_cancelled = TrueRewrite a payload
To change a packet, decode payload, edit it, and assign the new bytes back. Decoding is on you - the snippet below just shows the read/modify/write shape:
@event_handler
def on_packet_send(self, event: PacketSendEvent):
if event.packet_id != self.TEXT_PACKET:
return
data = bytearray(event.payload)
# ... decode per the Bedrock protocol, modify, re-encode ...
event.payload = bytes(data)player can be None for packets exchanged during the login handshake - always check it before using the player.