ProtocolLib integration
ProtocolLib is a powerful Minecraft plugin that allows other plugins to intercept, read, and modify packets sent between the server and client.
While it's technically possible to access ProtocolLib directly via raw Javascript in scripts, this is not recommended. Unofficial use results in:
Memory leaks
Script instability
Limitations due to Java-JS translation
OpenJS provides official support for ProtocolLib, exposing a clean and stable API.
Enabling ProtocolLib Support
At the very top of your script, include the following feature flag
//!ProtocolLib
Without this flag, the ProtocolLib API is not accessible in the script.
API Overview
ProtocolLib.registerListener(priority, handler, packetTypes)
ProtocolLib.registerListener(priority, handler, packetTypes)
Registers a new packet listener.
priority
:"LOW"
,"NORMAL"
,"HIGH"
, or"MONITOR"
handler
: JavaScript object containingonSend(event)
and/oronReceive(event)
packetTypes
: Array of packet names, e.g.,"Play.Server.BLOCK_CHANGE"
Returns: a listener
object
listener = ProtocolLib.registerListener("NORMAL", {
onSend(event) {
const packet = event.getPacket();
// handle packet here
}
}, ["Play.Server.BLOCK_CHANGE"]);
ProtocolLib.unregisterListener(listener)
ProtocolLib.unregisterListener(listener)
Unregisters a previously registered packet listener.
ProtocolLib.unregisterListener(listener);
Packet Event Object
The event
passed into your handler (onSend
/ onReceive
) provides access to:
getPacket()
Returns the actual ProtocolLib packet
getPacketType()
Returns packet type as enum (e.g. Play.Server.CHAT
)
You can use:
read(index)
/write(index, value)
to access fieldsPacket-specific methods like
getBlockData()
orgetBlockDataArrays()
Example Script: Block Spoofing
This script replaces all outgoing non-air blocks with a spoofed OAK_LOG
block:
//!import org.bukkit.Material
//!import com.comphenix.protocol.wrappers.WrappedBlockData
//!ProtocolLib
const Material = org.bukkit.Material;
const createDataMethod = getMethod(WrappedBlockData, "createData", ["org.bukkit.Material"]);
let SpoofedBlock = createDataMethod.invoke(null, [Material.OAK_LOG]);
const handler = {
onSend(event) {
const packet = event.getPacket();
const type = event.getPacketType().name();
if (type === "BLOCK_CHANGE") {
const blockData = packet.getBlockData().read(0);
if (!blockData.getType().equals(Material.AIR)) {
packet.getBlockData().write(0, SpoofedBlock);
}
}
if (type === "MULTI_BLOCK_CHANGE") {
let blocks = packet.getBlockDataArrays().read(0);
for (let i = 0; i < blocks.length; i++) {
if (!blocks[i].getType().equals(Material.AIR)) {
blocks[i] = SpoofedBlock;
}
}
packet.getBlockDataArrays().write(0, blocks);
}
}
};
const listener = ProtocolLib.registerListener("NORMAL", handler, [
"Play.Server.BLOCK_CHANGE",
"Play.Server.MULTI_BLOCK_CHANGE"
]);
Best Practices
Unregister unused listeners with
ProtocolLib.unregisterListener(...)
Avoid modifying packets in
"MONITOR"
priority (read-only phase)Use
getMethod()
andinvoke()
carefully for wrapper class access
Related Links
Feature Flags Reference – Enable/disable APIs via script headers
Event Handling – Learn how to listen to Bukkit and custom events
Last updated
Was this helpful?