Skip to content

Adding a Bedrock Edition Packet

This guide explains how to implement, encode, decode, and handle a new Minecraft: Bedrock Edition packet in Pumpkin.


Naming Conventions

  • Clientbound packets (Server → Client) must start with C (e.g., CChunkRadiusUpdated, CContainerOpen).
  • Serverbound packets (Client → Server) must start with S (e.g., SRequestChunkRadius, SPlayerAction).

Step 1: Identifying the Packet ID

In the Bedrock protocol, packet IDs are fixed integer constants assigned by Mojang. Verify the numeric ID from the official protocol documentation or network packet traces.

For example:

  • Disconnect packet ID: 5
  • RequestChunkRadius packet ID: 69

Step 2: Implementing a Clientbound Packet

Clientbound packets implement the PacketWrite trait from pumpkin-protocol::serial.

1. Create the Packet File

Place the file in crates/pumpkin-protocol/src/bedrock/client/<packet_name>.rs:

rust
use std::io::{Error, Write};
use pumpkin_macros::packet;
use crate::{codec::var_int::VarInt, serial::PacketWrite};

#[packet(5)]
pub struct CDisconnect {
    pub reason: VarInt,
    pub skip_message: bool,
    pub message: String,
    pub filtered_message: String,
}

impl CDisconnect {
    #[must_use]
    pub const fn new(reason: i32, message: String) -> Self {
        Self {
            reason: VarInt(reason),
            skip_message: message.is_empty(),
            message,
            filtered_message: String::new(),
        }
    }
}

impl PacketWrite for CDisconnect {
    fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
        self.reason.write(writer)?;
        self.skip_message.write(writer)?;
        if !self.skip_message {
            self.message.write(writer)?;
            self.filtered_message.write(writer)?;
        }
        Ok(())
    }
}

2. Export the Module

In crates/pumpkin-protocol/src/bedrock/client/mod.rs:

rust
pub mod disconnect;
pub use disconnect::*;

Step 3: Implementing a Serverbound Packet

Serverbound packets implement the PacketRead trait. Pumpkin provides a procedural derive macro #[derive(PacketRead)] for automatic deserialization when fields implement PacketRead.

1. Create the Packet File

Place the file in crates/pumpkin-protocol/src/bedrock/server/<packet_name>.rs:

rust
use pumpkin_macros::packet;
use crate::{codec::var_int::VarInt, serial::PacketRead};

#[derive(PacketRead, Debug)]
#[packet(69)]
pub struct SRequestChunkRadius {
    pub chunk_radius: VarInt,
    pub max_chunk_radius: u8,
}

If a packet requires custom parsing logic, implement PacketRead manually:

rust
use std::io::{Error, Read};
use crate::serial::PacketRead;

impl PacketRead for SMyCustomPacket {
    fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
        let chunk_radius = VarInt::read(reader)?;
        let max_chunk_radius = u8::read(reader)?;
        Ok(Self { chunk_radius, max_chunk_radius })
    }
}

2. Export the Module

In crates/pumpkin-protocol/src/bedrock/server/mod.rs:

rust
pub mod request_chunk_radius;
pub use request_chunk_radius::*;

Step 4: Dispatching Incoming Packets in pumpkin

Incoming packets are dispatched in crates/pumpkin/src/net/bedrock/mod.rs:

rust
// Inside BedrockClient::handle_game_packet
match packet.id {
    SRequestChunkRadius::PACKET_ID => {
        let packet = SRequestChunkRadius::read(reader)?;
        self.handle_request_chunk_radius(player, &packet);
    }
    _ => {}
}

Step 5: Implementing the Handler Function

Implement the handler logic in crates/pumpkin/src/net/bedrock/play/<packet_name>.rs:

rust
use super::*;
use pumpkin_protocol::bedrock::server::request_chunk_radius::SRequestChunkRadius;

impl BedrockClient {
    pub fn handle_request_chunk_radius(&self, player: &Arc<Player>, packet: &SRequestChunkRadius) {
        let requested_radius = packet.chunk_radius.0;
        
        // Clamp view distance within server configuration limits
        let clamped = requested_radius.clamp(2, 16);

        // Notify client that view radius was accepted
        self.try_enqueue_client_packet(&CChunkRadiusUpdated {
            chunk_radius: VarInt(clamped),
        });
    }
}

Remember to register the new module in crates/pumpkin/src/net/bedrock/play/mod.rs:

rust
pub mod request_chunk_radius;

Step 6: Sending Outgoing Packets

To send a Bedrock packet to a connected client:

rust
// Enqueues the packet into the client's outgoing batch queue
self.try_enqueue_client_packet(&CChunkRadiusUpdated {
    chunk_radius: VarInt(view_distance),
});

Batched packets are automatically compressed, framed with 0xfe, and transmitted over the RakNet/NetherNet socket.

Veröffentlicht unter der MIT-Lizenz.