ProtoWeaver
ProtoWeaver is a powerful library for creating custom network protocols that run directly on Minecraft's built-in Netty server. No more redirecting client connections through proxies for data transfer — everything now works on the same port!
What does this mean in practice?
Tired of complex workarounds for data exchange between server and proxy? ProtoWeaver solves this problem by allowing you to create custom protocols that operate on the same port as the main Minecraft server. This means proxy servers like Velocity can interact with the game server regardless of whether players are online, without the need to run additional socket servers on different ports.
But ProtoWeaver's capabilities aren't limited to just proxies! Using the client module, any third-party Java application can directly communicate with your protocol.
Key Advantages
The library combines speed, security, and ease of use:
- All protocols run in the same Netty instance as Minecraft
- Built-in SSL encryption for data protection
- Intuitive API for quick start
- Automatic protocol authentication
- Support for various compression methods (Gzip, Snappy, LZ)
- Compatibility with all major mod loaders
- Packets represented as regular POJO objects
- Ability to configure custom serialization
Getting Started
Add to your build.gradle file:
Important: Do not bundle ProtoWeaver with your mod! This is a separate modification that should be installed alongside yours.
repositories {
maven { url "https://maven.mrnavastar.me/releases" }
}
dependencies {
// 'common' can be replaced with: client, fabric, forge, paper or proxy.
implementation "me.mrnavastar.protoweaver:common:1.3.11"
}
Creating a Protocol
Protocols in ProtoWeaver are easily configurable and feature-rich. Example of creating a simple protocol:
Protocol protocol = Protocol.create("my_mod_id", "cool_protocol")
.setCompression(CompressionType.GZIP)
.setServerHandler(MyCustomServerHandler.class)
.setClientHandler(MyCustomClientHandler.class)
.setMaxConnections(15)
.addPacket(String.class)
.build();
// Load the protocol before using
ProtoWeaver.load(protocol);
Sending Packets
Data transmission is maximally simplified. Any POJO object added to the protocol can be sent as a packet. All serialization is handled through the fast Kyro library.
// If you have a reference to 'ProtoConnection':
connection.send(myObject);
// Or through 'ProtoClient':
client.send(myObject);
Handling Incoming Data
Protocol functionality is implemented using handlers. Client and server can use either the same or different handlers.
public class MyCustomServerHandler implements ProtoConnectionHandler {
// All functions are optional to implement
@Override
public void void onReady(ProtoConnection connection) {
System.out.println("Great! New client connected from: " + connection.getRemoteAddress());
}
@Override
public void onDisconnect(ProtoConnection connection) {
System.out.println("Goodbye: " + connection.getRemoteAddress());
}
@Override
public void handlePacket(ProtoConnection connection, Object packet) {
System.out.println("Received packet: " + packet.toString() + " from: " + connection.getRemoteAddress());
}
}
public class MyCustomClientHandler implements ProtoConnectionHandler {
// All functions are optional to implement
@Override
public void void onReady(ProtoConnection connection) {
System.out.println("Successfully connected to: " + connection.getRemoteAddress());
}
@Override
public void onDisconnect(ProtoConnection connection) {
System.out.println("Disconnected from: " + connection.getRemoteAddress());
}
@Override
public void handlePacket(ProtoConnection connection, Object packet) {
System.out.println("Sending greeting!");
connection.send("Hello server!");
}
}
Custom Serialization
For working with Minecraft objects or other ready-made POJOs, you can register a custom serializer. Example for NBT tags:
public class NbtSerializer extends ProtoSerializer<CompoundTag> {
public NbtSerializer(Class<CompoundTag> type) {
super(type);
}
@Override
public void write(ByteArrayOutputStream buffer, CompoundTag value) {
try {
NbtIo.writeCompressed(value, buffer);
} catch (IOException e) {
Platform.throwException(e);
}
}
@Override
public CompoundTag read(ByteArrayInputStream buffer) {
try {
return NbtIo.readCompressed(buffer, NbtAccounter.unlimitedHeap());
} catch (IOException e) {
Platform.throwException(e);
throw new RuntimeException(e);
}
}
}
Serializer registration:
Protocol protocol = Protocol.create("my_mod_id", "cool_protocol")
.setCompression(CompressionType.GZIP)
.setServerHandler(MyCustomServerHandler.class)
.setClientHandler(MyCustomClientHandler.class)
.setMaxConnections(15)
.addPacket(CompoundTag.class, NbtSerializer.class)
.build();