raknet-bedrock
v1.1.2
Published
Pure Node.js implementation of the RakNet 8 protocol. Compatible with Minecraft Bedrock / MCPE 0.15.x.
Maintainers
Readme
raknet-bedrock
Pure Node.js implementation of the RakNet 8 protocol.
Compatible with Minecraft Bedrock / MCPE 0.15.x (protocol 84).
No C. No node-gyp. No native bindings. Just JavaScript.
Features
- ✅ Full RakNet 8 offline handshake (Ping/Pong, OCR1/2)
- ✅ Server — accept connections, manage sessions, broadcast
- ✅ Client — connect to any RakNet server, build bots & proxies
- ✅ Session management — per-client state, timeout, disconnect
- ✅ Split-packet reassembly — automatic fragmentation & rebuild
- ✅ ACK batching — range-compressed ACK flush every tick (20 TPS)
- ✅ MCPE / Bedrock handler — Login (JWT chain), BatchPacket (zlib), PlayStatus
- ✅ Zero dependencies — only Node.js built-ins (
dgram,zlib) - ✅ Node.js ≥ 16
- 🚧 Actively developed — new versions and protocol improvements coming soon
Installation
npm install raknet-bedrockQuick Start — Server
const { RakNetServer, McpeHandler } = require('raknet-bedrock');
class MyServer extends McpeHandler {
getMotd(players) {
return `MCPE;My Server;84;0.15.10;${players};20`;
}
onMcpeLogin(session, proto, username) {
console.log(`${username} joined!`);
this.sendPlayStatus(session, 0); // 0 = login OK
}
}
new RakNetServer('0.0.0.0', 19132)
.setHandler(new MyServer())
.start()
.then(() => console.log('Server running on :19132'));Quick Start — Bot / Client
const { RakNetClient } = require('raknet-bedrock');
const client = new RakNetClient();
client.on('connected', () => {
console.log('Bot connected!');
});
client.on('packet', (buf) => {
console.log('Packet:', buf[0].toString(16));
});
client.on('disconnected', (reason) => {
console.log('Disconnected:', reason);
});
client.connect('play.example.com', 19132);Run the bundled examples:
node examples/server.js # start a server
node examples/bot.js 127.0.0.1 19132 # connect a botAPI Reference
RakNetServer
const { RakNetServer } = require('raknet-bedrock');
const server = new RakNetServer(ip?, port?);| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| ip | string | '0.0.0.0' | Bind address |
| port | number | 19132 | UDP port |
Methods
| Method | Returns | Description |
|--------|---------|-------------|
| setHandler(handler) | this | Set the event handler |
| setLogger(logger) | this | Replace the default logger |
| enableDebug() | this | Enable verbose debug output |
| start() | Promise<void> | Bind socket and start tick loop |
| stop() | void | Gracefully close the server |
| sendRaw(buf, ip, port) | void | Send raw UDP bytes |
| closeSession(key, reason?) | void | Force-close a session |
| broadcastEncapsulated(buf, reliability?) | void | Send to all connected sessions |
EventHandler
Base class. Extend it and override what you need.
const { EventHandler } = require('raknet-bedrock');
class MyHandler extends EventHandler {
/** Called when a client completes the handshake. */
onSessionOpen(session) {}
/** Called when a client disconnects or times out. */
onSessionClose(session, reason) {}
/**
* Called for every fully-assembled payload that
* is not handled internally (ping, handshake, etc.).
* buf[0] is the packet ID.
*/
onPacket(session, buf) {}
/**
* Return the MOTD string for the server browser.
* Format: "MCPE;<name>;<protocol>;<version>;<current>;<max>"
*/
getMotd(currentPlayers) {
return `MCPE;My Server;84;0.15.10;${currentPlayers};20`;
}
}McpeHandler (extends EventHandler)
Higher-level handler for MCPE / Bedrock 0.14-0.15.x.
Decodes the 0xFE wrapper, BatchPacket (zlib), and the Login JWT chain.
const { McpeHandler } = require('raknet-bedrock');
class MyServer extends McpeHandler {
/** Called when a decoded Login packet arrives. */
onMcpeLogin(session, protocol, username) {}
/** Called for any unhandled MCPE packet. */
onMcpeUnknown(session, pid, buf) {}
/** Called for packets without the 0xFE wrapper. */
onRawPacket(session, pid, buf) {}
}Send helpers
// Send a pre-built MCPE payload (auto-prepends 0xFE)
handler.sendMcpe(session, payload);
// Wrap a packet in BatchPacket (zlib) and send it
handler.sendMcpePacket(session, pid, payload);
// Send a PlayStatus packet
// 0 = login success
// 1 = update client
// 2 = update server
// 3 = player spawn
handler.sendPlayStatus(session, 0);
// Kick a client with a message
handler.sendDisconnect(session, 'You have been banned.');Session
Represents one client connection. Passed to every callback.
| Property | Type | Description |
|----------|------|-------------|
| ip | string | Client IP address |
| port | number | Client UDP port |
| clientGuid | BigInt | Client GUID from the handshake |
| mtu | number | Negotiated MTU |
| connected | boolean | true after full handshake |
| lastUpdate | number | Date.now() of last received packet |
| userData | any | Free slot — attach your own data here |
// Attach player data
session.userData = { username: 'Steve', level: 42 };
// Send raw encapsulated data
session.sendEncapsulated(buf, Protocol.RELIABLE_ORDERED);
// Gracefully disconnect
session.disconnect();
// Session key ("ip:port")
session.key();BinaryStream
Typed read / write buffer used internally (and available for your own packets).
const { BinaryStream } = require('raknet-bedrock');
// Write
const buf = BinaryStream.new()
.putByte(0x01)
.putShort(1234)
.putInt(99999)
.putLong(BigInt(Date.now()));
buf._flush(); // finalize — buf.buf is the final Buffer
// Read
const s = BinaryStream.wrap(someBuffer);
const id = s.getByte();
const val = s.getShort();
const addr = s.getAddress(); // { ip, port }Protocol
All RakNet 8 constants.
const { Protocol } = require('raknet-bedrock');
Protocol.RAKNET_PROTOCOL // 8
Protocol.TICK_RATE // 50 (ms)
Protocol.SESSION_TIMEOUT // 10000 (ms)
Protocol.MAGIC // Buffer (16 bytes)
// Reliability
Protocol.UNRELIABLE // 0
Protocol.UNRELIABLE_SEQ // 1
Protocol.RELIABLE // 2
Protocol.RELIABLE_ORDERED // 3
Protocol.RELIABLE_SEQ // 4Architecture
UDP socket
│
RakNetServer._dispatch()
│
├── Offline packets ──────────────────────────────────────────┐
│ (Ping, OCR1, OCR2) │
│ ▼
│ RakNetServer._handlePing / OCR1 / OCR2
│
└── Active session ───────────────────────────────────────────┐
│
Session.handleDatagram()
│
┌───────────────────────┤
│ │
ACK Datagram
flush (encapsulated)
│
EncapsulatedPacket.decode()
│
┌───────────────┤
│ │
hasSplit payload
reassemble │
EventHandler.onPacket()
│
(McpeHandler unwraps 0xFE / zlib)