A robust protocol library for Minecraft Java Edition written entirely in pure JavaScript. Inspired by PacketEvents, designed to facilitate the processing and transmission of Minecraft protocol packets with full online mode support.
- Pure JavaScript - No external dependencies, only native Node.js
- TCP Connection - Complete TCP client for Minecraft
- Packet System - Read/write all protocol data types
- Event System - Priority-based events with cancellation and async/await
- Compression - Full zlib compression support
- Encryption - Complete AES-128-CFB8 encryption support for online mode
- Online Mode - Full Mojang/Microsoft authentication support
- Offline Mode - Offline player UUID generation (version 3)
- BungeeCord Forwarding - Legacy IP forwarding support
- Velocity Forwarding - Modern forwarding with HMAC verification
- Complete NBT - Named Binary Tag read/write
- Chat Components - JSON Text Component with colors, formatting, and events
- Multi-version - Support for Minecraft 1.7.2 to 1.21.11 (66 versions)
- Packet Recorder - Record, export, import, and replay packet streams
- Protocol Analyzer - Deep packet inspection, metrics, and traffic analysis
- Middleware System - Plugin-based packet processing pipeline
- Connection Manager - AutoReconnect, HealthMonitor, ConnectionPool, CircuitBreaker
- Node.js 18.0.0 or higher
- ES Modules enabled
npm install packet-events-jsOr clone the repository:
git clone https://github.com/FrannnnDev/PacketEvents-JS.git
cd PacketEvents-JSimport { MinecraftClient, ProtocolVersion } from 'packet-events-js';
const client = new MinecraftClient({
host: 'mc.hypixel.net',
port: 25565,
version: ProtocolVersion.V1_21_11
});
const status = await client.ping();
console.log(`Players: ${status.players.online}/${status.players.max}`);
console.log(`Latency: ${status.latency}ms`);import {
MinecraftClient,
ProtocolVersion,
Logger,
LogLevel,
KeepAliveClientboundPacket,
KeepAliveServerboundPacket
} from 'packet-events-js';
Logger.setGlobalLevel(LogLevel.DEBUG);
const client = new MinecraftClient({
host: 'localhost',
port: 25565,
version: ProtocolVersion.V1_21_11,
username: 'MyBot',
offline: true
});
client.onPacket(KeepAliveClientboundPacket, async (event) => {
const response = new KeepAliveServerboundPacket();
response.keepAliveId = event.packet.keepAliveId;
await client.sendPacket(response);
});
await client.login();
console.log(`Connected as ${client.playerName}`);import { MinecraftEncryption, EncryptedConnection } from 'packet-events-js';
const keyPair = MinecraftEncryption.generateKeyPair();
console.log('Public Key:', keyPair.publicKey);
console.log('Private Key:', keyPair.privateKey);
const verifyToken = MinecraftEncryption.generateVerifyToken();
const sharedSecret = MinecraftEncryption.generateSharedSecret();
const encrypted = MinecraftEncryption.encryptRSA(keyPair.publicKey, sharedSecret);
const decrypted = MinecraftEncryption.decryptRSA(keyPair.privateKey, encrypted);
const aesEncrypted = MinecraftEncryption.encryptAES(sharedSecret, Buffer.from('Hello'));
const aesDecrypted = MinecraftEncryption.decryptAES(sharedSecret, aesEncrypted);
const serverHash = MinecraftEncryption.computeServerIdHash('', sharedSecret, keyPair.publicKey);import { AuthHandler, ClientAuthHandler, AuthMode } from 'packet-events-js';
const serverAuth = new AuthHandler({ mode: AuthMode.ONLINE });
serverAuth.initialize();
const publicKey = serverAuth.getPublicKey();
const verifyToken = serverAuth.generateVerifyToken();
const offlineUUID = serverAuth.generateOfflineUUID('PlayerName');
const clientAuth = new ClientAuthHandler({
accessToken: 'token',
selectedProfile: { id: 'uuid', name: 'Name' }
});import { BungeeCordForwarding, UUID } from 'packet-events-js';
const uuid = UUID.randomUUID();
const handshakeAddress = BungeeCordForwarding.create(
'play.example.com',
'192.168.1.100',
uuid,
[{ name: 'textures', value: '...' }]
);
const result = BungeeCordForwarding.parse(handshakeAddress);
if (result.success) {
console.log(`Client IP: ${result.clientIP}`);
console.log(`UUID: ${result.uuid.toString()}`);
}import { VelocityForwarding, AuthHandler, AuthMode, UUID } from 'packet-events-js';
const auth = new AuthHandler({
mode: AuthMode.VELOCITY,
velocitySecret: 'your-secret-key'
});
const result = auth.handleVelocityForwarding(forwardingData);
if (result.success) {
console.log(`Player: ${result.username}`);
console.log(`UUID: ${result.uuid.toString()}`);
console.log(`IP: ${result.clientIP}`);
}
const uuid = UUID.randomUUID();
const data = VelocityForwarding.create(
'your-secret-key',
'10.0.0.1',
uuid,
'PlayerName',
[{ name: 'textures', value: '...', signature: '...' }]
);import { EventPriority } from 'packet-events-js';
client.packetManager.on('packetSend', (event) => {
if (event.packet.packetName === 'SetPlayerPosition') {
console.log(`Moving to: ${event.packet.x}, ${event.packet.y}, ${event.packet.z}`);
if (event.packet.y < 0) {
event.cancel();
}
}
}, { priority: EventPriority.HIGH });import {
Packet,
defaultRegistry,
ConnectionState,
PacketDirection
} from 'packet-events-js';
class MyCustomPacket extends Packet {
static get packetId() { return 0x50; }
static get packetName() { return 'MyPacket'; }
constructor() {
super();
this.myField = 0;
}
read(buffer, context) {
this.myField = buffer.readVarInt();
}
write(buffer, context) {
buffer.writeVarInt(this.myField);
}
}
defaultRegistry.register({
packetClass: MyCustomPacket,
state: ConnectionState.PLAY,
direction: PacketDirection.CLIENTBOUND,
packetId: 0x50
});Record, export, import, and replay complete packet streams:
import { PacketRecorder, PacketReplayer, PacketRecord } from 'packet-events-js';
const recorder = new PacketRecorder({
includeRaw: true,
maxRecords: 10000,
filter: (packet) => true
});
recorder.start();
client.packetManager.on('packetReceive', (event) => {
recorder.record(event.packet, 'CLIENTBOUND', 'PLAY', event.rawData);
});
const stats = recorder.getStats();
console.log(`Recorded: ${stats.totalPackets} packets, ${stats.totalBytes} bytes`);
console.log(`Duration: ${stats.duration}ms`);
console.log(`Packets by type:`, stats.packetsByType);
const exported = recorder.export();
const json = JSON.stringify(exported, null, 2);
const imported = recorder.import(JSON.parse(json));
const replayer = new PacketReplayer(recorder.records, {
speed: 1.0,
loop: false,
onPacket: (record) => {
console.log(`Replaying: ${record.packetName}`);
}
});
await replayer.start();
replayer.pause();
replayer.resume();
replayer.stop();Deep protocol analysis with metrics and traffic visualization:
import { ProtocolAnalyzer, ProtocolMetrics, PacketInspector } from 'packet-events-js';
const analyzer = new ProtocolAnalyzer({
trackHistory: true,
historySize: 1000,
alertThresholds: {
latency: 500,
packetLoss: 0.1,
throughputMin: 1000
}
});
analyzer.on('alert', (alert) => {
console.log(`Alert: ${alert.type} - ${alert.message}`);
});
analyzer.start();
client.packetManager.on('packetReceive', (event) => {
analyzer.analyzePacket(event.packet, 'CLIENTBOUND', 'PLAY', event.rawData);
});
analyzer.recordLatency(50);
const report = analyzer.getReport();
console.log(`Packets: ${report.packets.total}`);
console.log(`Bytes: ${report.bytes.total}`);
console.log(`Avg Latency: ${report.latency.average}ms`);
const graph = analyzer.getTrafficGraph();
console.log(graph);
const metrics = new ProtocolMetrics();
metrics.recordLatency(100);
metrics.recordPacketLoss(1, 100);
console.log(`Avg Latency: ${metrics.getAverageLatency()}ms`);
console.log(`Packet Loss: ${metrics.getPacketLoss() * 100}%`);
const inspector = new PacketInspector();
const hexDump = inspector.hexDump(packetBuffer);
console.log(hexDump);
const structure = inspector.analyzeStructure(packet);
console.log(structure);Plugin-based packet processing pipeline with built-in middleware:
import {
MiddlewarePipeline,
LoggingMiddleware,
RateLimitMiddleware,
ValidationMiddleware,
TransformMiddleware,
CacheMiddleware,
MetricsMiddleware
} from 'packet-events-js';
const pipeline = new MiddlewarePipeline();
pipeline.use(new LoggingMiddleware({
logLevel: 'debug',
includePayload: true,
filter: (ctx) => ctx.packet.constructor.packetName !== 'KeepAlive'
}));
pipeline.use(new RateLimitMiddleware({
maxPackets: 100,
windowMs: 1000,
onLimit: (ctx) => console.log('Rate limited!')
}));
pipeline.use(new ValidationMiddleware({
rules: {
'ChatMessage': (packet) => packet.message.length <= 256,
'SetPlayerPosition': (packet) => Math.abs(packet.y) < 320
},
onInvalid: (ctx, rule) => console.log(`Invalid: ${rule}`)
}));
pipeline.use(new TransformMiddleware({
transforms: {
'ChatMessage': (packet) => {
packet.message = packet.message.trim();
return packet;
}
}
}));
const metricsMiddleware = new MetricsMiddleware();
pipeline.use(metricsMiddleware);
pipeline.use(async (ctx, next) => {
console.log(`Before: ${ctx.packet.constructor.packetName}`);
await next();
console.log(`After: processing time ${ctx.processingTime}ms`);
});
client.packetManager.on('packetReceive', async (event) => {
const ctx = await pipeline.process({
packet: event.packet,
direction: 'CLIENTBOUND',
state: 'PLAY'
});
if (ctx.cancelled) {
event.cancel();
}
});
const metrics = metricsMiddleware.getMetrics();
console.log(`Processed: ${metrics.processed} packets`);
console.log(`Blocked: ${metrics.blocked} packets`);Advanced connection management with auto-reconnect, health monitoring, and connection pooling:
import {
AutoReconnect,
ReconnectStrategy,
HealthMonitor,
HealthStatus,
ConnectionPool,
CircuitBreaker
} from 'packet-events-js';
const reconnect = new AutoReconnect({
strategy: ReconnectStrategy.EXPONENTIAL,
baseDelay: 1000,
maxDelay: 30000,
maxAttempts: 10,
jitter: true,
onReconnect: (attempt) => console.log(`Reconnecting... attempt ${attempt}`),
onMaxAttempts: () => console.log('Max reconnect attempts reached'),
onSuccess: () => console.log('Reconnected!')
});
client.on('disconnect', async () => {
await reconnect.attempt(async () => {
await client.connect();
await client.login();
});
});
const healthMonitor = new HealthMonitor({
latencyThreshold: 200,
packetLossThreshold: 0.05,
checkInterval: 5000
});
healthMonitor.on('statusChange', (status, previousStatus) => {
console.log(`Health: ${previousStatus} -> ${status}`);
});
healthMonitor.on('alert', (alert) => {
console.log(`${alert.type}: ${alert.message}`);
});
client.packetManager.on('packetReceive', (event) => {
if (event.packet.constructor.packetName === 'KeepAliveClientbound') {
healthMonitor.recordLatency(Date.now() - event.timestamp);
}
});
const pool = new ConnectionPool({
minConnections: 2,
maxConnections: 10,
strategy: 'least-loaded',
healthCheck: async (conn) => conn.isConnected,
healthCheckInterval: 30000
});
await pool.add('lobby', createClient('lobby.server.com'));
await pool.add('game1', createClient('game1.server.com'));
await pool.add('game2', createClient('game2.server.com'));
const { id, connection } = pool.get();
await connection.sendPacket(packet);
pool.release(id);
const breaker = new CircuitBreaker({
failureThreshold: 5,
successThreshold: 3,
timeout: 30000,
onOpen: () => console.log('Circuit OPEN - requests blocked'),
onClose: () => console.log('Circuit CLOSED - requests allowed'),
onHalfOpen: () => console.log('Circuit HALF-OPEN - testing')
});
try {
await breaker.execute(async () => {
await client.sendPacket(packet);
});
} catch (error) {
if (breaker.isOpen) {
console.log('Circuit is open, request blocked');
}
}PacketEvents-JS/
├── src/
│ ├── index.js
│ ├── auth/
│ │ ├── AuthHandler.js
│ │ └── MojangAPI.js
│ ├── client/
│ │ └── MinecraftClient.js
│ ├── crypto/
│ │ └── Encryption.js
│ ├── events/
│ │ ├── EventEmitter.js
│ │ └── PacketEvent.js
│ ├── manager/
│ │ └── PacketManager.js
│ ├── protocol/
│ │ ├── ConnectionState.js
│ │ ├── PacketDirection.js
│ │ ├── ProtocolVersion.js
│ │ ├── types/
│ │ │ ├── VarInt.js
│ │ │ ├── UUID.js
│ │ │ ├── Position.js
│ │ │ ├── NBT.js
│ │ │ └── TextComponent.js
│ │ └── packets/
│ │ ├── Packet.js
│ │ ├── PacketRegistry.js
│ │ ├── handshake/
│ │ ├── status/
│ │ ├── login/
│ │ └── play/
│ ├── advanced/
│ │ ├── PacketRecorder.js
│ │ ├── ProtocolAnalyzer.js
│ │ ├── MiddlewareSystem.js
│ │ └── ConnectionManager.js
│ └── utils/
│ ├── PacketBuffer.js
│ └── Logger.js
└── examples/
├── authentication.js
├── basic-client.js
├── connection-flows.js
├── custom-packets.js
├── data-types.js
├── encryption.js
├── event-system.js
├── packet-buffer.js
├── packet-interception.js
├── packet-types.js
├── protocol-versions.js
└── server-ping.js
const client = new MinecraftClient({
host: string,
port: number,
version: ProtocolVersion,
username: string,
offline: boolean,
accessToken: string,
selectedProfile: object,
registry: PacketRegistry
});
await client.connect();
await client.ping();
await client.login();
await client.sendPacket(packet);
await client.disconnect();
client.isConnected;
client.isReady;
client.uuid;
client.playerName;import { PacketBuffer } from 'packet-events-js';
const buffer = PacketBuffer.writer();
buffer.writeBoolean(true);
buffer.writeByte(42);
buffer.writeShort(1000);
buffer.writeInt(100000);
buffer.writeLong(9999999999n);
buffer.writeFloat(3.14);
buffer.writeDouble(3.14159265);
buffer.writeVarInt(12345);
buffer.writeString("Hello Minecraft");
buffer.writeUUID(uuid);
buffer.writePosition(position);
buffer.writeNBT(nbtCompound);
const data = buffer.getBuffer();
const reader = PacketBuffer.reader(data);
const bool = reader.readBoolean();
const num = reader.readVarInt();
const str = reader.readString();import { MinecraftEncryption, EncryptedConnection } from 'packet-events-js';
const keyPair = MinecraftEncryption.generateKeyPair();
const verifyToken = MinecraftEncryption.generateVerifyToken();
const sharedSecret = MinecraftEncryption.generateSharedSecret();
MinecraftEncryption.encryptRSA(publicKey, data);
MinecraftEncryption.decryptRSA(privateKey, data);
MinecraftEncryption.encryptAES(secret, data);
MinecraftEncryption.decryptAES(secret, data);
MinecraftEncryption.computeServerIdHash(serverId, sharedSecret, publicKey);
const conn = new EncryptedConnection(sharedSecret);
conn.enable();
const encrypted = conn.encrypt(data);
const decrypted = conn.decrypt(data);import { AuthHandler, ClientAuthHandler, AuthMode, BungeeCordForwarding, VelocityForwarding } from 'packet-events-js';
AuthMode.ONLINE;
AuthMode.OFFLINE;
AuthMode.BUNGEECORD;
AuthMode.VELOCITY;
const handler = new AuthHandler({ mode: AuthMode.ONLINE });
handler.initialize();
handler.getPublicKey();
handler.generateVerifyToken();
handler.generateOfflineUUID(username);
const bungeAuth = new AuthHandler({ mode: AuthMode.BUNGEECORD });
const result = bungeAuth.handleBungeeCordForwarding(serverAddress);
const velocityAuth = new AuthHandler({
mode: AuthMode.VELOCITY,
velocitySecret: 'your-secret'
});
const result2 = velocityAuth.handleVelocityForwarding(loginPluginData);import { EventPriority } from 'packet-events-js';
EventPriority.LOWEST;
EventPriority.LOW;
EventPriority.NORMAL;
EventPriority.HIGH;
EventPriority.HIGHEST;
EventPriority.MONITOR;
emitter.on('event', callback, { priority: EventPriority.HIGH });
emitter.on('packet', (event) => {
event.cancel();
});
await emitter.emitAsync('event', data);import { TextComponent, ChatColor } from 'packet-events-js';
const message = TextComponent.text('Hello!')
.color(ChatColor.GREEN)
.bold()
.append(
TextComponent.text(' World')
.color(ChatColor.YELLOW)
.italic()
)
.clickEvent('run_command', '/help')
.showText(TextComponent.text('Click for help'));
const json = message.toString();66 versions supported from 1.7.2 to 1.21.11:
| Range | Versions |
|---|---|
| 1.21.x | 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21 |
| 1.20.x | 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20 |
| 1.19.x | 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19 |
| 1.18.x | 1.18.2, 1.18.1, 1.18 |
| 1.17.x | 1.17.1, 1.17 |
| 1.16.x | 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16 |
| 1.15.x | 1.15.2, 1.15.1, 1.15 |
| 1.14.x | 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14 |
| 1.13.x | 1.13.2, 1.13.1, 1.13 |
| 1.12.x | 1.12.2, 1.12.1, 1.12 |
| 1.11.x | 1.11.2, 1.11.1, 1.11 |
| 1.10.x | 1.10.2, 1.10.1, 1.10 |
| 1.9.x | 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9 |
| 1.8.x | 1.8.9, 1.8.8, 1.8.7, 1.8.6, 1.8.5, 1.8.4, 1.8.3, 1.8.2, 1.8.1, 1.8 |
| 1.7.x | 1.7.10, 1.7.9, 1.7.6, 1.7.5, 1.7.4, 1.7.2 |
See the examples folder for complete usage examples:
basic-client.js- Basic client connectionserver-ping.js- Server list pingpacket-types.js- All packet types demonstrationencryption.js- Encryption usageauthentication.js- Authentication modesevent-system.js- Event system usagepacket-buffer.js- PacketBuffer operationsdata-types.js- Protocol data typesprotocol-versions.js- Protocol version utilitiesconnection-flows.js- Connection flow examplescustom-packets.js- Custom packet creationpacket-interception.js- Packet interception
This project is inspired by:
- PacketEvents - Original Java library
- wiki.vg Protocol - Protocol documentation
- MCProtocolLib - Reference implementation
MIT License