Skip to content

Geyser Networking API#5685

Open
Redned235 wants to merge 27 commits into
masterfrom
feature/networking-api
Open

Geyser Networking API#5685
Redned235 wants to merge 27 commits into
masterfrom
feature/networking-api

Conversation

@Redned235

@Redned235 Redned235 commented Jul 13, 2025

Copy link
Copy Markdown
Member

Introduces a networking API to Geyser which can be used in extensions. This supports both sending and listening for plugin messages, and allows Geyser to intercept these, as well as intercepting and sending packets.

Plugin Messages

In order to start sending and listening for plugin messages, you need to tell Geyser which channels to listen for. This can be done by listening on the SessionDefineNetworkChannelsEvent and registering the channel for the connection. Firstly, we will go over how to send a custom message.

Registering the channel

Example:

public class NetworkExtension implements Extension {
    private final NetworkChannel myChannel = NetworkChannel.of(this, "my_channel", MyMessage.class);

    @Subscribe
    public void onDefineChannels(SessionDefineNetworkChannelsEvent event) {
        event.define(this.myChannel, MyMessage::new).register();
    }
}

In the define method, you also need to define the creator of the message that will be sent. This effectively turns the content from a MessageBuffer into your type. Then calling register will actually register it into the network manager.

As a recommended principle, this should be a record with two constructors: one creating the object just using its values (an all-args constructor), then one for the MessageBuffer. It should also extend Message.Simple.

Example:

public record MyMessage(String name, int entityId) implements Message.Simple {

    public MyMessage(MessageBuffer buffer) {
        this(buffer.read(DataType.STRING), buffer.read(DataType.INT));
    }

    @Override
    public void encode(MessageBuffer buffer) {
        buffer.write(DataType.STRING, this.name);
        buffer.write(DataType.INT, this.entityId);
    }
}

A MessageBuffer supports both reading and writing, with built-in DataTypes for common values (int, string, long, varint, etc.). Custom DataTypes can easily be added with DataType#of.

Sending the message

Now that your channel and its corresponding message creator is registered, it can now be either listened for, or sent out. This can easily be sent out by fetching the Network from a GeyserConnection, and running the #send method.

Example:

@Subscribe
public void onSessionJoin(SessionJoinEvent event) {
    GeyserConnection connection = event.connection();
    connection.network().send(this.myChannel, new MyMessage(connection.name(), connection.entities().playerEntity().javaId()), MessageDirection.SERVERBOUND);
}

Note: When sending a message to the server, ensure the direction is SERVERBOUND as that will specify that the server should receive the message. If you were to use CLIENTBOUND for example, that would send it to the client.

Now on your server, you can listen for this message! Here is an example using Bukkit:

this.getServer().getMessenger().registerIncomingPluginChannel(this, "network_extension:my_channel", new PluginMessageListener() {

    @Override
    public void onPluginMessageReceived(@NotNull String s, @NotNull Player player, @NotNull byte[] bytes) {
        System.out.println("Received over channel " + s);
        System.out.println("Content: " + new String(bytes, StandardCharsets.UTF_8));
    }
});

Listening for messages

In some cases, it may be more desirable to do the opposite of what was shown above - sending information to your Geyser extension from a server. This too is supported! In that case, when registering the channel, you will need to register a clientbound handler inside your channel definition.

As an example:

@Subscribe
public void onDefineChannels(SessionDefineNetworkChannelsEvent event) {
    event.define(this.myChannel, MyMessage::new)
            .clientbound(message -> {
                String name = message.name()
                // ...
                return MessageHandler.State.HANDLED; // Indicates this handler handled the message
            })
            .register();
}

And for plugin messages, that is about it!

Packets

This API also supports listening for packets. This works alongside the plugin messaging component to it. There are two methods: defining the packet structure using API, or using the Cloudburst API. Both are explained in more detail below.

Packet Structure Using API

When constructing your NetworkChannel, a special method (and class) needs to be used: PacketChannel#java, orPacketChannel#bedrock. This creates a NetworkChannel that is capable of handling packets for either of the two platforms.

Example:

private final NetworkChannel animateChannel = PacketChannel.bedrock(this, 44, AnimateMessage.class);

It is important to understand that these only work in Extensions. The this seen in the example represents an Extension instance, assuming the NetworkChannel is constructed in the extension.

The following two parameters are also quite important: the packet ID and the actual message. These should correspond to real packets in the corresponding platform. Like above, this should be registered in the SessionDefineNetworkChannelsEvent in the same way.

The AnimateMessage on the other hand from the example, is the actual implementation of the animate packet in Bedrock. Here is how that looks:

public record AnimateMessage(int type, long entityId, float rowingTime) implements Message.Packet {

    @Override
    public void encode(@NotNull MessageBuffer buffer) {
        buffer.write(DataType.VAR_INT, this.type);
        buffer.write(DataType.UNSIGNED_VAR_LONG, this.entityId);
        buffer.write(DataType.FLOAT, this.rowingTime);
    }

    public static AnimateMessage decode(@NonNull MessageBuffer buffer) {
        int type = buffer.read(DataType.VAR_INT);
        long entityId = buffer.read(DataType.UNSIGNED_VAR_LONG);
        float rowingTime = (type == 128 || type == 129) ? buffer.read(DataType.FLOAT) : 0.0f;
        return new AnimateMessage(type, entityId, rowingTime);
    }
}

Now that the AnimateMessage has been created, we can now send it:

@Subscribe
public void onSessionJoin(SessionJoinEvent event) {
    event.connection().network().send(this.animateChannel, new AnimateMessage(1, -1, 0f), MessageDirection.SERVERBOUND); // Swing main hand
}

Or if you wanted to listen for other players swinging their arms:

@Subscribe
public void onDefineChannels(SessionDefineNetworkChannelsEvent event) {
    event.define(this.animateChannel, AnimateMessage::decode)
            .clientbound(message -> {
                if (message.type() == 1) { // Swing arm
                    System.out.println("Entity " + message.entityId() + " swung their arm!");
                }
                    
                return MessageHandler.State.UNHANDLED;
            })
            .register();
}

It is also worth noting that the MessageHandler.State controls the behavior of the packet once intercepted, meaning if you return UNHANDLED, the message will still make it back to the client. Additionally, returning HANDLED will cause the client to never receive the packet.

Important Note for Registering Java Packets

When registering packets for Java, it is a hard requirement that the ProtocolState also be specified. This is because in Java Edition, there are multiple protocol states in which packet IDs differ, or don't exist at all (i.e. login packets do not exist in the game state).

To specify the protocol state, simply call protocolState after defining the packet in SessionDefineNetworkChannelsEvent and set the state it belongs to. An example is provided below:

@Subscribe
public void onDefineChannels(SessionDefineNetworkChannelsEvent event) {
    event.define(this.animateChannel, ClientboundAnimateMessage::decode)
            .protocolState(ProtocolState.GAME)
            .clientbound(message -> ...)
            .register();
}

Packet Structure Using Cloudburst Protocol Library

While the first example required a bit more manual work, in some cases that may be more desired for fine-turning the entire process. However, it is also possible to simply just use the raw packet objects themselves as provided by the Cloudburst Protocol Library.

In addition to depending on the Geyser API, depending on Cloudburst Protocol too is all that is required here - no need to rely on any Geyser internals!

Creating the channel is nearly identical as above, except rather than a custom AnimateMessage, just use the packet directly like so:

private static final NetworkChannel animateChannel = PacketChannel.bedrock(this, 44, AnimatePacket.class);

When registering the channel though, it's a tad different. This can be done like so:

event.define(this.animateChannel, Message.Packet.of(AnimatePacket::new)).register();

And sending can be done like so:

AnimatePacket packet = new AnimatePacket();
packet.setAction(AnimatePacket.Action.SWING_ARM);
packet.setRowingTime(0.0f);

event.connection().network().send(this.animateChannel, Message.Packet.of(packet), MessageDirection.CLIENTBOUND);

However, if you want to listen for one of these, the process is very similar as earlier, except you need to obtain the packet from the message (as opposed to it being the message), like so:

@Subscribe
public void onDefineChannels(SessionDefineNetworkChannelsEvent event) {
    event.define(this.animateChannel, Message.Packet.of(AnimatePacket::new))
            .clientbound(message -> {
                AnimatePacket packet = message.packet();
                if (packet.getAction() == AnimatePacket.Action.SWING_ARM) {
                    System.out.println("Entity " + packet.getRuntimeEntityId() + " swung their arm!");
                }
                return MessageHandler.State.HANDLED;
            })
            .register();
}

Note that this is only an initial draft and subject to change! Testing and feedback are more than welcome.

A gist of what was covered above with slightly more can be found here: https://gist.github.com/Redned235/3cf05b62290fa9eec70d8b4f3fa22f67

@onebeastchris onebeastchris left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks very promising! Left some notes. A few more things that don't fit anywhere:

  • it might be worth to separate listening / receiving packet listeners? This could be used to avoid extra processing for packets that are sent both ways (where one is only interested in one direction)
  • Currently; some bedrock packet (de)serializers are modified by Geyser. This would result in incorrect values for some packets... do we want to note that / have a mechanism to disable that?

Comment thread api/src/main/java/org/geysermc/geyser/api/network/ExtensionNetworkChannel.java Outdated
Comment thread api/src/main/java/org/geysermc/geyser/api/network/message/MessageFactory.java Outdated
Comment thread api/src/main/java/org/geysermc/geyser/api/network/PacketChannel.java Outdated
Comment thread api/src/main/java/org/geysermc/geyser/api/network/message/Message.java Outdated
Comment thread core/src/main/java/org/geysermc/geyser/network/GeyserNetwork.java
Comment thread core/src/main/java/org/geysermc/geyser/network/GeyserNetworkManager.java Outdated
@onebeastchris onebeastchris mentioned this pull request Jul 22, 2025
@onebeastchris

Copy link
Copy Markdown
Member

Another thing that came up recently is whether we'd allow forwarding packets to a backend server - even without an extension present. This could be combined with this PR, assuming we'd want to do that.. thoughts?

@dima-dencep

Copy link
Copy Markdown
Contributor

😢😢😢😢

Copilot AI review requested due to automatic review settings November 9, 2025 18:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a comprehensive networking API for Geyser that enables extensions to send and listen for plugin messages, as well as intercept and send packets. The API provides a flexible event-driven architecture with support for message priorities, pipeline tags, and both custom and Cloudburst protocol-based packet handling.

Key Changes

  • Adds networking API interfaces and implementations for plugin messages and packet handling
  • Introduces event system for registering network channels with configurable handlers and priorities
  • Provides message encoding/decoding infrastructure with built-in and custom data types

Reviewed Changes

Copilot reviewed 44 out of 44 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionDefineNetworkChannelsEvent.java Defines event for registering network channels with builder pattern for handlers
api/src/main/java/org/geysermc/geyser/api/network/*.java Core networking API interfaces (NetworkChannel, NetworkManager, MessageDirection)
api/src/main/java/org/geysermc/geyser/api/network/message/*.java Message handling infrastructure (Message, MessageBuffer, MessageCodec, DataType, handlers)
core/src/main/java/org/geysermc/geyser/network/*.java Implementation of network channels and manager with packet/message handling
core/src/main/java/org/geysermc/geyser/network/message/*.java ByteBuf-based message buffer and codec implementations
core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java Integration of network manager into packet sending flow
core/src/main/java/org/geysermc/geyser/translator/protocol/java/*.java Plugin message registration and handling for custom payloads
core/src/test/java/org/geysermc/geyser/network/MessageRegistrationOrderTest.java Tests for message handler priority and pipeline ordering
core/src/test/java/org/geysermc/geyser/util/*.java Refactored test utilities to common util package

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread api/src/main/java/org/geysermc/geyser/api/network/message/MessagePriority.java Outdated
Comment thread core/src/main/resources/mappings
Comment thread core/src/main/resources/languages
try {
serializer.deserialize(buffer.buffer(), session.getUpstream().getCodecHelper(), this.packet);
} catch (Exception e) {
throw new PacketSerializeException("Error whilst deserializing " + this.packet, e);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be neat to have our own exception type in the API?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would the usecase be?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Being able to catch specific exceptions to e.g. display a warning :p
We have custom exception types for other api things too; like the ResourcePackRegistrationException

Comment thread core/src/main/java/org/geysermc/geyser/network/GeyserNetwork.java
this.session.sendUpstreamPacket(packetMessage.packet());
} else if (packetBase instanceof JavaPacketMessage<?> packetMessage) {
this.session.sendDownstreamPacket(packetMessage.packet());
} else if (packetBase instanceof Message.Packet packet) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Continuing from #5685 (comment) - we could split Message.Packet into Message.BedrockPacket (and therefore leave a spot open for Message.JavaPacket if we desire to add it in the future?)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a huge fan of that from the API side. Message.BedrockPacket.of(AnimatePacket::new)) for instance just doesn't seem great. If we are to introduce a Java packet system, it's probably best to define in the NetworkChannel#packet method.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO introducing a Java packet system that isn't a Message.Packet would be more confusing :p
Can we add a field / enum or something to Message.Packet to indicate whether it is Bedrock or Java?

@dima-dencep

dima-dencep commented Nov 9, 2025

Copy link
Copy Markdown
Contributor

I haven't really looked into what's going on here yet, but for emotecraft it's very important to get byte[] from the packet (or at least ByteBuffer)

And, of course, sending packets during the configuration state

Copilot AI review requested due to automatic review settings November 9, 2025 19:51
@Redned235

Copy link
Copy Markdown
Member Author

I haven't really looked into what's going on here yet, but for emotecraft it's very important to get byte[] from the packet (or at least ByteBuffer)

And, of course, sending packets during the configuration state

At what point during the config stage? During login or switching into the state while previously in the game state?

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 42 out of 42 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread api/src/main/java/org/geysermc/geyser/api/network/message/MessagePriority.java Outdated
Comment thread api/src/main/java/org/geysermc/geyser/api/network/NetworkChannel.java Outdated
Comment thread api/src/main/java/org/geysermc/geyser/api/network/NetworkChannel.java Outdated
Comment thread api/src/main/java/org/geysermc/geyser/api/network/message/Message.java Outdated
Copilot AI review requested due to automatic review settings November 9, 2025 20:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Copilot reviewed 42 out of 42 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@dima-dencep

Copy link
Copy Markdown
Contributor

At what point during the config stage? During login or switching into the state while previously in the game state?

At the state where fabric/neoforge mods are configured

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 51 out of 51 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

core/src/main/java/org/geysermc/geyser/registry/loader/ProviderRegistryLoader.java:1

  • Corrected spelling of 'Cloud' to 'Could'.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread api/src/main/java/org/geysermc/geyser/api/network/PacketChannel.java Outdated
Comment thread api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java Outdated
Comment on lines +191 to +192
* However, it should be noted that if the specified tag does not exist at the time of registration,
* the handler will be added to the end of the pipeline without throwing an error.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally this would be configurable... maybe with optionallyBefore (or alternatively e.g. requiredBefore) to forcibly throw if the specified handler isn't found?
Pipeline order can be a tricky thing, detecting breaks would be difficult if it'll fall back silently

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems quite niche IMO - what would the usecase here be?

Copilot AI review requested due to automatic review settings December 25, 2025 17:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 51 out of 51 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread api/src/main/java/org/geysermc/geyser/api/network/message/Message.java Outdated
Comment thread core/src/main/java/org/geysermc/geyser/network/PacketChannelImpl.java Outdated
@Novampr Novampr linked an issue Jan 13, 2026 that may be closed by this pull request
Copilot AI review requested due to automatic review settings February 7, 2026 15:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 51 out of 51 changed files in this pull request and generated 9 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread core/src/main/java/org/geysermc/geyser/network/GeyserNetwork.java

@NonNull
public <T extends MessageBuffer> List<Message<T>> createMessages(@NonNull NetworkChannel channel, @NonNull T buffer) {
return this.createMessages0(channel, def -> buffer);

Copilot AI Feb 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createMessages(channel, buffer) passes the same buffer instance to every registered definition. If more than one definition exists for a channel, the first message factory will advance the reader index and later factories will decode from the wrong position (often producing invalid messages). Consider creating a fresh buffer per definition (e.g., from the original byte[]), or resetting/copying the buffer before each decode.

Suggested change
return this.createMessages0(channel, def -> buffer);
byte[] data = buffer.toByteArray();
return (List<Message<T>>) (List<?>) this.createMessages(channel, data);

Copilot uses AI. Check for mistakes.
Comment thread core/src/main/java/org/geysermc/geyser/network/GeyserNetwork.java
Comment thread core/src/main/java/org/geysermc/geyser/network/GeyserNetwork.java
Comment thread api/src/main/java/org/geysermc/geyser/api/network/message/Message.java Outdated
Comment on lines +241 to +245
ServerboundCustomPayloadPacket packet = new ServerboundCustomPayloadPacket(
Key.key(channel.identifier().toString()),
buffer.serialize()
);

Copilot AI Feb 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Network#send ignores the direction parameter for non-packet (custom payload) channels and always sends a ServerboundCustomPayloadPacket downstream. This contradicts the API contract/docs that imply direction affects where the message is delivered; either enforce direction == SERVERBOUND here (e.g., throw/return) or implement clientbound injection behavior explicitly.

Copilot uses AI. Check for mistakes.
Comment thread core/src/main/java/org/geysermc/geyser/network/GeyserNetwork.java
@GeyserMC GeyserMC deleted a comment from Copilot AI Feb 7, 2026
Copilot AI review requested due to automatic review settings June 27, 2026 11:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 52 out of 52 changed files in this pull request and generated 6 comments.

Comment on lines +321 to +339
List<Message<ByteBufMessageBuffer>> messages = new ArrayList<>();
for (PacketChannel channel : channels) {
if (((PacketChannelImpl) channel).messageType().isInstance(packet)) {
messages.add(new BedrockPacketMessage<>(packet));
} else {
ByteBuf buffer = Unpooled.buffer();
definition.getSerializer().serialize(buffer, this.session.getUpstream().getCodecHelper(), packet);
messages.addAll(this.createMessages(channel, new ByteBufMessageBuffer(ByteBufCodec.INSTANCE_LE, buffer), direction));
}
}

for (NetworkChannel channel : channels) {
boolean handled = this.handleMessages(channel, messages, direction);
if (!handled) {
return false;
}
}

return true;
Comment on lines +360 to +379
List<Message<ByteBufMessageBuffer>> messages = new ArrayList<>();
for (PacketChannel channel : channels) {
if (((PacketChannelImpl) channel).messageType().isInstance(packet)) {
messages.add(new JavaPacketMessage<>(packet));
} else {
ByteBuf buffer = Unpooled.buffer();
packet.serialize(buffer);
messages.addAll(this.createMessages(channel, new ByteBufMessageBuffer(ByteBufCodec.INSTANCE, buffer), direction));
}
}

for (NetworkChannel channel : channels) {
boolean handled = this.handleMessages(channel, messages, direction);
if (!handled) {
return false;
}
}

return true;
}
Comment on lines +309 to +313
public boolean handleBedrockPacket(BedrockPacket packet, MessageDirection direction) {
if (this.packetChannels.isEmpty()) {
return true; // Avoid processing anything if we have nothing to handle
}

Comment on lines +239 to +250
MessageDefinition<T, Message<T>> definition = this.findMessageDefinition(channel, message);

T buffer = definition.codec.createBuffer();
message.encode(buffer);

ServerboundCustomPayloadPacket packet = new ServerboundCustomPayloadPacket(
Key.key(channel.identifier().toString()),
buffer.serialize()
);

this.session.sendDownstreamPacket(packet);
}
Copilot AI review requested due to automatic review settings June 27, 2026 13:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 54 out of 54 changed files in this pull request and generated 3 comments.


@Override
public <T extends MessageBuffer> void send(@NonNull NetworkChannel channel, @NonNull Message<T> message, @NonNull MessageDirection direction, @NonNull MessageFlag... flags) {
Set<MessageFlag> flagSet = Set.of(flags);
Comment on lines +239 to +250
MessageDefinition<T, Message<T>> definition = this.findMessageDefinition(channel, message);

T buffer = definition.codec.createBuffer();
message.encode(buffer);

ServerboundCustomPayloadPacket packet = new ServerboundCustomPayloadPacket(
Key.key(channel.identifier().toString()),
buffer.serialize()
);

this.session.sendDownstreamPacket(packet);
}
Comment thread core/src/main/java/org/geysermc/geyser/network/GeyserNetwork.java
Copilot AI review requested due to automatic review settings June 27, 2026 20:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 61 out of 61 changed files in this pull request and generated 3 comments.

Comment on lines +28 to +49
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.network.PacketChannel;
import org.geysermc.geyser.api.util.Identifier;

public class PacketChannelImpl extends ExternalNetworkChannel implements PacketChannel {
private final boolean java;

public PacketChannelImpl(@NonNull Identifier identifier, boolean java, @NonNull Class<?> packetType) {
super(identifier, packetType);

this.java = java;
}

public boolean isJava() {
return this.java;
}

@Override
public boolean isPacket() {
return true;
}
}
Comment on lines +28 to +47
import org.checkerframework.checker.index.qual.NonNegative;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.network.RawPacketChannel;
import org.geysermc.geyser.api.util.Identifier;

public class RawPacketChannelImpl extends PacketChannelImpl implements RawPacketChannel {
private final int packetId;

public RawPacketChannelImpl(@NonNull Identifier identifier, boolean java, @NonNegative int packetId, @NonNull Class<?> messageType) {
super(identifier, java, messageType);

this.packetId = packetId;
}

@Override
@NonNegative
public int packetId() {
return this.packetId;
}
}
Comment on lines +275 to +284
MessageDefinition<T, Message<T>> definition = this.findMessageDefinition(channel, message);

T buffer = definition.codec.createBuffer();
message.encode(buffer);

Key channelKey = Key.key(channel.identifier().toString());
byte[] data = buffer.serialize();

ServerboundCustomPayloadPacket packet = new ServerboundCustomPayloadPacket(channelKey, data);
this.session.sendDownstreamPacket(packet);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API] ServerboundDiagnosticsPacket data Packet intercepting and sending API

4 participants