Skip to content

Networking

MehVahdJukaar edited this page Jul 25, 2026 · 1 revision

Networking

One packet API for both loaders. Write a record, register it, send it.

Getting Started

A packet is a record implementing Message, with a type built by Message.makeType:

public record TestMessage(int data) implements Message {

    public static final TypeAndCodec<RegistryFriendlyByteBuf, TestMessage> TYPE =
            Message.makeType(MyMod.res("test"), TestMessage::new);

    public TestMessage(FriendlyByteBuf buffer) {
        this(buffer.readVarInt());
    }

    @Override
    public void write(RegistryFriendlyByteBuf buf) {
        buf.writeVarInt(this.data);
    }

    @Override
    public void handle(Context context) {
        // runs on the receiving side, on the main thread
    }

    @Override
    public Type<? extends CustomPacketPayload> type() {
        return TYPE.type();
    }
}

Register on init, with a protocol version:

NetworkHelper.addNetworkRegistration(event -> event.registerClientBound(TestMessage.TYPE), 1);

registerClientBound, registerServerBound or registerBidirectional.

Then send:

NetworkHelper.sendToAllClientPlayersInRange(level, pos, 32, new TestMessage(5));

There's a send method for each target you'd expect: one player, all players, players in range, players tracking an entity or a chunk, and to the server. Plus presets for the ranges that keep coming up (InDefaultRange 64, InParticleRange 32, InDistantParticleRange 512).

Context gives you the player, the direction, reply(...) and disconnect(...).

Example: ChannelHandlerExample

Warning

handle lives in a common class, so watch classloading. Don't touch client only classes in it directly, put those behind a separate client class.

Clone this wiki locally