Important
We have archived ProtocolBurrito in favor of writing helpers for working directly with NMS packets in Idofront. It's much easier to work with deobfuscated NMS classes these days and we wish to avoid depending on reflection and dependencies that take a while to update.
A packet wrapper for ProtocolLib generated from Minecraft's obfuscation mappings, thanks to PaperMC's userdev project. Comes with clean Kotlin syntax and Java support.
This project is currently HIGHLY WIP! Don't use it if you are a fan of stable codebases.
ProtocolLib is great, but it's extremely painful to actually modify data in packets because we need to access fields via integers and constantly refer to the Protocol Wiki. This project takes the server packet classes and exposes all their private fields by accessing them with integers. The userdev Gradle plugin lets you work directly with the data and avoid messy ProtocolLib code.
You lose on some version safety by depending on NMS code. However, with the new mappings, updating is far easier and the code for complex operations more maintainable.
We also provide a clean Kotlin DSL wrapper around ProtocolLib's packet interceptors, plus some extension functions for sending packets, or getting an entity from its id.
This project can be shaded into your plugin, however it's designed to be used as another plugin on your server (similar to ProtocolLib).
repositories {
maven { url 'https://repo.mineinabyss.com/releases' }
}
dependencies {
compileOnly 'com.mineinabyss:protocolburrito:<version>'
}
This is a snippet of code sends zombie as entity type for our custom mobs from another project:
val protocolManager = ProtocolLibrary.getProtocolManager()!!
protocolManager.addPacketListener(object : PacketAdapter(
pluginRef,
ListenerPriority.NORMAL,
PacketType.Play.Server.SPAWN_ENTITY_LIVING
) {
override fun onPacketSending(event: PacketEvent) {
if (Bukkit.getEntity(event.packet.uuiDs.read(0)).isCustomMob)
event.packet.integers.write(1, 102)
}
})
protocolManager(pluginRef) {
onSend<ClientboundAddEntityPacketWrap> { wrap ->
if (entity(wrap.id).isCustomMob)
wrap.type = Registry.ENTITY_TYPE.getId(NMSEntityType.ZOMBIE)
}
}
PacketContainer fakeExplosion = new PacketContainer(PacketType.Play.Server.EXPLOSION);
fakeExplosion.getDoubles().
write(0, player.getLocation().getX()).
write(1, player.getLocation().getY()).
write(2, player.getLocation().getZ());
fakeExplosion.getFloat().write(0, 3.0F);
try {
protocolManager.sendServerPacket(player, fakeExplosion);
} catch (InvocationTargetException e) {
throw new RuntimeException(
"Cannot send packet " + fakeExplosion, e);
}
val loc = player.location
// The NMS class already has a public constructor!
val fakeExplosion = ClientboundExplodePacket(loc.x, loc.y, loc.z, 3.0f, listOf(), null)
fakeExplosion.sendTo(player)
And if the constructor is too complicated, you can fall back to:
val fakeExplosion = PacketContainer(PacketType.Play.Server.EXPLOSION)
(fakeExplosion.handle as ClientboundExplodePacket).wrap().apply {
x = loc.x
y = loc.y
z = loc.z
power = 3.0f
}
fakeExplosion.sendTo(player)
We lost some version safety, but the increased readability ensures future updates will be far easier when something in the packet inevitably changes, no more looking up integers!
We're currently trying to make this seamless.