From 8d2efb30df31b4f1c947d9d20a7357cab5506519 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?=
Date: Sun, 22 Sep 2024 23:10:50 +0200
Subject: [PATCH 1/6] feat(api): add some basic api interfaces
---
.../dev/protocollib/api/BinaryPacket.java | 8 +++++
.../java/dev/protocollib/api/Connection.java | 30 +++++++++++++++++++
.../dev/protocollib/api/PacketContainer.java | 9 ++++++
.../dev/protocollib/api/PacketDirection.java | 7 +++++
.../java/dev/protocollib/api/PacketEvent.java | 11 +++++++
.../dev/protocollib/api/PacketListener.java | 8 +++++
.../api/PacketListenerBuilder.java | 16 ++++++++++
.../api/PacketListenerPriority.java | 7 +++++
.../api/PacketListenerRegistration.java | 6 ++++
.../java/dev/protocollib/api/PacketType.java | 13 ++++++++
.../java/dev/protocollib/api/PacketTypes.java | 7 +++++
.../java/dev/protocollib/api/ProtocolLib.java | 12 ++++++++
.../dev/protocollib/api/ProtocolPhase.java | 7 +++++
13 files changed, 141 insertions(+)
create mode 100644 src/main/java/dev/protocollib/api/BinaryPacket.java
create mode 100644 src/main/java/dev/protocollib/api/Connection.java
create mode 100644 src/main/java/dev/protocollib/api/PacketContainer.java
create mode 100644 src/main/java/dev/protocollib/api/PacketDirection.java
create mode 100644 src/main/java/dev/protocollib/api/PacketEvent.java
create mode 100644 src/main/java/dev/protocollib/api/PacketListener.java
create mode 100644 src/main/java/dev/protocollib/api/PacketListenerBuilder.java
create mode 100644 src/main/java/dev/protocollib/api/PacketListenerPriority.java
create mode 100644 src/main/java/dev/protocollib/api/PacketListenerRegistration.java
create mode 100644 src/main/java/dev/protocollib/api/PacketType.java
create mode 100644 src/main/java/dev/protocollib/api/PacketTypes.java
create mode 100644 src/main/java/dev/protocollib/api/ProtocolLib.java
create mode 100644 src/main/java/dev/protocollib/api/ProtocolPhase.java
diff --git a/src/main/java/dev/protocollib/api/BinaryPacket.java b/src/main/java/dev/protocollib/api/BinaryPacket.java
new file mode 100644
index 000000000..75da830c2
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/BinaryPacket.java
@@ -0,0 +1,8 @@
+package dev.protocollib.api;
+
+public interface BinaryPacket {
+
+ int id();
+
+ byte[] payload();
+}
diff --git a/src/main/java/dev/protocollib/api/Connection.java b/src/main/java/dev/protocollib/api/Connection.java
new file mode 100644
index 000000000..4ea34bde3
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/Connection.java
@@ -0,0 +1,30 @@
+package dev.protocollib.api;
+
+import java.net.InetSocketAddress;
+
+import javax.annotation.Nullable;
+
+import org.bukkit.entity.Player;
+
+public interface Connection {
+
+ @Nullable
+ Player player();
+
+ InetSocketAddress address();
+
+ int protocolVersion();
+
+ ProtocolPhase protocolPhase(PacketDirection packetDirection);
+
+ boolean isConnected();
+
+ void sendPacket(BinaryPacket packet);
+
+ void sendPacket(PacketContainer packet);
+
+ void receivePacket(PacketContainer packet);
+
+ void disconnect(String reason);
+
+}
diff --git a/src/main/java/dev/protocollib/api/PacketContainer.java b/src/main/java/dev/protocollib/api/PacketContainer.java
new file mode 100644
index 000000000..4a1af7cf8
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/PacketContainer.java
@@ -0,0 +1,9 @@
+package dev.protocollib.api;
+
+public interface PacketContainer {
+
+ PacketType packetType();
+
+ Object packet();
+
+}
diff --git a/src/main/java/dev/protocollib/api/PacketDirection.java b/src/main/java/dev/protocollib/api/PacketDirection.java
new file mode 100644
index 000000000..541c54cdc
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/PacketDirection.java
@@ -0,0 +1,7 @@
+package dev.protocollib.api;
+
+public enum PacketDirection {
+
+ SERVERBOUND, CLIENTBOUND;
+
+}
diff --git a/src/main/java/dev/protocollib/api/PacketEvent.java b/src/main/java/dev/protocollib/api/PacketEvent.java
new file mode 100644
index 000000000..7e93a5958
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/PacketEvent.java
@@ -0,0 +1,11 @@
+package dev.protocollib.api;
+
+import org.bukkit.event.Cancellable;
+
+public interface PacketEvent extends Cancellable {
+
+ Connection connection();
+
+ PacketContainer packet();
+
+}
diff --git a/src/main/java/dev/protocollib/api/PacketListener.java b/src/main/java/dev/protocollib/api/PacketListener.java
new file mode 100644
index 000000000..392b80d9c
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/PacketListener.java
@@ -0,0 +1,8 @@
+package dev.protocollib.api;
+
+@FunctionalInterface
+public interface PacketListener {
+
+ void handlePacket(PacketEvent event);
+
+}
diff --git a/src/main/java/dev/protocollib/api/PacketListenerBuilder.java b/src/main/java/dev/protocollib/api/PacketListenerBuilder.java
new file mode 100644
index 000000000..8a044643a
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/PacketListenerBuilder.java
@@ -0,0 +1,16 @@
+package dev.protocollib.api;
+
+import java.util.Collection;
+
+public interface PacketListenerBuilder {
+
+ PacketListenerBuilder types(PacketType...packetTypes);
+
+ PacketListenerBuilder types(Collection packetTypes);
+
+ PacketListenerBuilder priority(PacketListenerPriority priority);
+
+ PacketListenerBuilder listener(PacketListener listener);
+
+ PacketListenerRegistration register();
+}
diff --git a/src/main/java/dev/protocollib/api/PacketListenerPriority.java b/src/main/java/dev/protocollib/api/PacketListenerPriority.java
new file mode 100644
index 000000000..8c3bc8f89
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/PacketListenerPriority.java
@@ -0,0 +1,7 @@
+package dev.protocollib.api;
+
+public enum PacketListenerPriority {
+
+ LOWEST, LOW, NORMAL, HIGH, HIGHEST, MONITOR;
+
+}
diff --git a/src/main/java/dev/protocollib/api/PacketListenerRegistration.java b/src/main/java/dev/protocollib/api/PacketListenerRegistration.java
new file mode 100644
index 000000000..a26b32780
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/PacketListenerRegistration.java
@@ -0,0 +1,6 @@
+package dev.protocollib.api;
+
+public interface PacketListenerRegistration {
+
+ void unregister();
+}
diff --git a/src/main/java/dev/protocollib/api/PacketType.java b/src/main/java/dev/protocollib/api/PacketType.java
new file mode 100644
index 000000000..406046972
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/PacketType.java
@@ -0,0 +1,13 @@
+package dev.protocollib.api;
+
+public interface PacketType {
+
+ PacketDirection packetDirection();
+
+ Class> packetClass();
+
+ boolean isSupported();
+
+ boolean isDeprecated();
+
+}
diff --git a/src/main/java/dev/protocollib/api/PacketTypes.java b/src/main/java/dev/protocollib/api/PacketTypes.java
new file mode 100644
index 000000000..8a623ccf3
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/PacketTypes.java
@@ -0,0 +1,7 @@
+package dev.protocollib.api;
+
+public class PacketTypes {
+
+ // TODO should contain all packet types as public static final fields
+
+}
diff --git a/src/main/java/dev/protocollib/api/ProtocolLib.java b/src/main/java/dev/protocollib/api/ProtocolLib.java
new file mode 100644
index 000000000..ee10801af
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/ProtocolLib.java
@@ -0,0 +1,12 @@
+package dev.protocollib.api;
+
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+
+public interface ProtocolLib {
+
+ PacketListenerBuilder createListener(Plugin plugin);
+
+ Connection connection(Player player);
+
+}
diff --git a/src/main/java/dev/protocollib/api/ProtocolPhase.java b/src/main/java/dev/protocollib/api/ProtocolPhase.java
new file mode 100644
index 000000000..a01084656
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/ProtocolPhase.java
@@ -0,0 +1,7 @@
+package dev.protocollib.api;
+
+public enum ProtocolPhase {
+
+ HANDSHAKE, PLAY, STATUS, LOGIN, CONFIGURATION, UNKNOWN;
+
+}
From ba5f278419fb06c6e10802d79e1d7801e2c90675 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?=
Date: Mon, 21 Oct 2024 23:47:44 +0200
Subject: [PATCH 2/6] feat(api): add basic packet processing interfaces
---
.../dev/protocollib/api/BinaryPacket.java | 14 ++++
.../java/dev/protocollib/api/Connection.java | 75 +++++++++++++++++--
.../dev/protocollib/api/PacketContainer.java | 13 ++++
.../dev/protocollib/api/PacketDirection.java | 7 --
.../java/dev/protocollib/api/PacketEvent.java | 11 ---
.../dev/protocollib/api/PacketListener.java | 8 --
.../api/PacketListenerBuilder.java | 16 ----
.../api/PacketListenerPriority.java | 7 --
.../api/PacketListenerRegistration.java | 6 --
.../java/dev/protocollib/api/PacketType.java | 37 +++++++--
.../protocollib/api/ProtocolDirection.java | 14 ++++
.../java/dev/protocollib/api/ProtocolLib.java | 35 ++++++++-
.../dev/protocollib/api/ProtocolPhase.java | 3 +
.../api/listener/AsyncPacketListener.java | 32 ++++++++
.../listener/AsyncPacketListenerContext.java | 21 ++++++
.../api/listener/PacketListenerBuilder.java | 74 ++++++++++++++++++
.../api/listener/PacketListenerPriority.java | 22 ++++++
.../listener/PacketListenerRegistration.java | 14 ++++
.../api/listener/PacketSentListener.java | 16 ++++
.../api/listener/SyncPacketListener.java | 19 +++++
.../listener/SyncPacketListenerContext.java | 36 +++++++++
21 files changed, 414 insertions(+), 66 deletions(-)
delete mode 100644 src/main/java/dev/protocollib/api/PacketDirection.java
delete mode 100644 src/main/java/dev/protocollib/api/PacketEvent.java
delete mode 100644 src/main/java/dev/protocollib/api/PacketListener.java
delete mode 100644 src/main/java/dev/protocollib/api/PacketListenerBuilder.java
delete mode 100644 src/main/java/dev/protocollib/api/PacketListenerPriority.java
delete mode 100644 src/main/java/dev/protocollib/api/PacketListenerRegistration.java
create mode 100644 src/main/java/dev/protocollib/api/ProtocolDirection.java
create mode 100644 src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
create mode 100644 src/main/java/dev/protocollib/api/listener/AsyncPacketListenerContext.java
create mode 100644 src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
create mode 100644 src/main/java/dev/protocollib/api/listener/PacketListenerPriority.java
create mode 100644 src/main/java/dev/protocollib/api/listener/PacketListenerRegistration.java
create mode 100644 src/main/java/dev/protocollib/api/listener/PacketSentListener.java
create mode 100644 src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
create mode 100644 src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
diff --git a/src/main/java/dev/protocollib/api/BinaryPacket.java b/src/main/java/dev/protocollib/api/BinaryPacket.java
index 75da830c2..bdc14e2b9 100644
--- a/src/main/java/dev/protocollib/api/BinaryPacket.java
+++ b/src/main/java/dev/protocollib/api/BinaryPacket.java
@@ -1,8 +1,22 @@
package dev.protocollib.api;
+/**
+ * Representing a raw binary packet with a packet id and payload.
+ */
public interface BinaryPacket {
+ /**
+ * Retrieves the packet id.
+ *
+ * @return the packet ID
+ */
int id();
+ /**
+ * Retrieves the payload (data) of the packet.
+ *
+ * @return the packet payload as a byte array
+ */
byte[] payload();
}
+
diff --git a/src/main/java/dev/protocollib/api/Connection.java b/src/main/java/dev/protocollib/api/Connection.java
index 4ea34bde3..9e6825506 100644
--- a/src/main/java/dev/protocollib/api/Connection.java
+++ b/src/main/java/dev/protocollib/api/Connection.java
@@ -1,30 +1,95 @@
package dev.protocollib.api;
import java.net.InetSocketAddress;
-
-import javax.annotation.Nullable;
+import java.util.Optional;
import org.bukkit.entity.Player;
+import dev.protocollib.api.listener.PacketSentListener;
+
+/**
+ * Representing a connection of a player.
+ */
public interface Connection {
- @Nullable
- Player player();
+ /**
+ * Retrieves the player associated with the connection, if available.
+ *
+ * @return an optional containing the player, or empty if the player is not present
+ */
+ Optional player();
+ /**
+ * Retrieves the address of the connection.
+ *
+ * @return the remote address of the connection
+ */
InetSocketAddress address();
+ /**
+ * Retrieves the protocol version used by the connection.
+ *
+ * @return the protocol version
+ */
int protocolVersion();
- ProtocolPhase protocolPhase(PacketDirection packetDirection);
+ /**
+ * Retrieves the current protocol phase of the connection for a given direction.
+ *
+ * @param packetDirection the direction of the packet (clientbound or serverbound)
+ * @return the protocol phase of the connection
+ */
+ ProtocolPhase protocolPhase(ProtocolDirection packetDirection);
+ /**
+ * Checks if the connection is currently open.
+ *
+ * @return true if the connection is open, false otherwise
+ */
boolean isConnected();
+ /**
+ * Sends a binary packet over the connection.
+ *
+ * @param packet the binary packet to send
+ */
void sendPacket(BinaryPacket packet);
+ /**
+ * Sends a binary packet over the connection and registers a listener for when the packet is sent.
+ *
+ * @param packet the binary packet to send
+ * @param listener the listener to invoke once the packet is sent
+ */
+ void sendPacket(BinaryPacket packet, PacketSentListener listener);
+
+ /**
+ * Sends a packet container over the connection.
+ *
+ * @param packet the packet container to send
+ */
void sendPacket(PacketContainer packet);
+ /**
+ * Sends a packet container over the connection and registers a listener for when the packet is sent.
+ *
+ * @param packet the packet container to send
+ * @param listener the listener to invoke once the packet is sent
+ */
+ void sendPacket(PacketContainer packet, PacketSentListener listener);
+
+ /**
+ * Receives a packet container from the connection.
+ *
+ * @param packet the packet container received
+ */
void receivePacket(PacketContainer packet);
+ /**
+ * Disconnects the connection with the specified reason.
+ *
+ * @param reason the reason for disconnecting
+ */
void disconnect(String reason);
}
diff --git a/src/main/java/dev/protocollib/api/PacketContainer.java b/src/main/java/dev/protocollib/api/PacketContainer.java
index 4a1af7cf8..f23655c6e 100644
--- a/src/main/java/dev/protocollib/api/PacketContainer.java
+++ b/src/main/java/dev/protocollib/api/PacketContainer.java
@@ -1,9 +1,22 @@
package dev.protocollib.api;
+/**
+ * Representing a container for a packet.
+ */
public interface PacketContainer {
+ /**
+ * Retrieves the type of the packet.
+ *
+ * @return the packet type
+ */
PacketType packetType();
+ /**
+ * Retrieves the raw packet object.
+ *
+ * @return the packet object
+ */
Object packet();
}
diff --git a/src/main/java/dev/protocollib/api/PacketDirection.java b/src/main/java/dev/protocollib/api/PacketDirection.java
deleted file mode 100644
index 541c54cdc..000000000
--- a/src/main/java/dev/protocollib/api/PacketDirection.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package dev.protocollib.api;
-
-public enum PacketDirection {
-
- SERVERBOUND, CLIENTBOUND;
-
-}
diff --git a/src/main/java/dev/protocollib/api/PacketEvent.java b/src/main/java/dev/protocollib/api/PacketEvent.java
deleted file mode 100644
index 7e93a5958..000000000
--- a/src/main/java/dev/protocollib/api/PacketEvent.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package dev.protocollib.api;
-
-import org.bukkit.event.Cancellable;
-
-public interface PacketEvent extends Cancellable {
-
- Connection connection();
-
- PacketContainer packet();
-
-}
diff --git a/src/main/java/dev/protocollib/api/PacketListener.java b/src/main/java/dev/protocollib/api/PacketListener.java
deleted file mode 100644
index 392b80d9c..000000000
--- a/src/main/java/dev/protocollib/api/PacketListener.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package dev.protocollib.api;
-
-@FunctionalInterface
-public interface PacketListener {
-
- void handlePacket(PacketEvent event);
-
-}
diff --git a/src/main/java/dev/protocollib/api/PacketListenerBuilder.java b/src/main/java/dev/protocollib/api/PacketListenerBuilder.java
deleted file mode 100644
index 8a044643a..000000000
--- a/src/main/java/dev/protocollib/api/PacketListenerBuilder.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package dev.protocollib.api;
-
-import java.util.Collection;
-
-public interface PacketListenerBuilder {
-
- PacketListenerBuilder types(PacketType...packetTypes);
-
- PacketListenerBuilder types(Collection packetTypes);
-
- PacketListenerBuilder priority(PacketListenerPriority priority);
-
- PacketListenerBuilder listener(PacketListener listener);
-
- PacketListenerRegistration register();
-}
diff --git a/src/main/java/dev/protocollib/api/PacketListenerPriority.java b/src/main/java/dev/protocollib/api/PacketListenerPriority.java
deleted file mode 100644
index 8c3bc8f89..000000000
--- a/src/main/java/dev/protocollib/api/PacketListenerPriority.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package dev.protocollib.api;
-
-public enum PacketListenerPriority {
-
- LOWEST, LOW, NORMAL, HIGH, HIGHEST, MONITOR;
-
-}
diff --git a/src/main/java/dev/protocollib/api/PacketListenerRegistration.java b/src/main/java/dev/protocollib/api/PacketListenerRegistration.java
deleted file mode 100644
index a26b32780..000000000
--- a/src/main/java/dev/protocollib/api/PacketListenerRegistration.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package dev.protocollib.api;
-
-public interface PacketListenerRegistration {
-
- void unregister();
-}
diff --git a/src/main/java/dev/protocollib/api/PacketType.java b/src/main/java/dev/protocollib/api/PacketType.java
index 406046972..18290de30 100644
--- a/src/main/java/dev/protocollib/api/PacketType.java
+++ b/src/main/java/dev/protocollib/api/PacketType.java
@@ -1,13 +1,40 @@
package dev.protocollib.api;
-public interface PacketType {
+import java.util.Optional;
- PacketDirection packetDirection();
+import net.kyori.adventure.key.Keyed;
- Class> packetClass();
+/**
+ * Representing the type of a network packet.
+ *
+ *
A {@code PacketType} identifies a specific type of packet in the protocol,
+ * including information about its direction, associated class (if any), and
+ * whether the packet is currently supported.
+ */
+public interface PacketType extends Keyed {
- boolean isSupported();
+ /**
+ * Retrieves the direction in which the packet is being sent.
+ *
+ * @return the {@link ProtocolDirection} of the packet, either clientbound or serverbound
+ */
+ ProtocolDirection protocolDirection();
+
+ /**
+ * Retrieves the class associated with the packet type, if available.
+ *
+ *
Not all packet types have an associated class. If there is no class,
+ * an empty {@link Optional} is returned.
+ *
+ * @return an {@link Optional} containing the class of the packet, or empty if not applicable
+ */
+ Optional> packetClass();
- boolean isDeprecated();
+ /**
+ * Checks whether the packet type is supported by the current protocol version.
+ *
+ * @return {@code true} if the packet type is supported, {@code false} otherwise
+ */
+ boolean isSupported();
}
diff --git a/src/main/java/dev/protocollib/api/ProtocolDirection.java b/src/main/java/dev/protocollib/api/ProtocolDirection.java
new file mode 100644
index 000000000..f9e8b055d
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/ProtocolDirection.java
@@ -0,0 +1,14 @@
+package dev.protocollib.api;
+
+/**
+ * Representing the direction of a packet, either sent to or from the server.
+ */
+public enum ProtocolDirection {
+
+ /** Packet sent from the client to the server. */
+ SERVERBOUND,
+
+ /** Packet sent from the server to the client. */
+ CLIENTBOUND;
+
+}
diff --git a/src/main/java/dev/protocollib/api/ProtocolLib.java b/src/main/java/dev/protocollib/api/ProtocolLib.java
index ee10801af..859c7b441 100644
--- a/src/main/java/dev/protocollib/api/ProtocolLib.java
+++ b/src/main/java/dev/protocollib/api/ProtocolLib.java
@@ -3,10 +3,43 @@
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
+import dev.protocollib.api.listener.PacketListenerBuilder;
+
+/**
+ * Representing the main entry point for the ProtocolLib API.
+ */
public interface ProtocolLib {
+ /**
+ * Creates a packet listener for the provided plugin.
+ *
+ * @param plugin the plugin registering the packet listener
+ * @return a builder to configure and register the packet listener
+ */
PacketListenerBuilder createListener(Plugin plugin);
-
+
+ /**
+ * Retrieves the connection associated with a specific player.
+ *
+ * @param player the player whose connection is being retrieved
+ * @return the connection for the specified player
+ */
Connection connection(Player player);
+ /**
+ * Creates a new binary packet with the given type and payload.
+ *
+ * @param packetType the type of the packet to create
+ * @param payload the binary payload to include in the packet
+ * @return a new {@link BinaryPacket} instance
+ */
+ BinaryPacket createBinaryPacket(PacketType packetType, byte[] payload);
+
+ /**
+ * Creates a new packet container for the given packet type.
+ *
+ * @param packetType the type of the packet to create
+ * @return a new {@link PacketContainer} instance
+ */
+ PacketContainer createPacket(PacketType packetType);
}
diff --git a/src/main/java/dev/protocollib/api/ProtocolPhase.java b/src/main/java/dev/protocollib/api/ProtocolPhase.java
index a01084656..e3b92e02a 100644
--- a/src/main/java/dev/protocollib/api/ProtocolPhase.java
+++ b/src/main/java/dev/protocollib/api/ProtocolPhase.java
@@ -1,5 +1,8 @@
package dev.protocollib.api;
+/**
+ * Representing the different protocol phases of a minecraft.
+ */
public enum ProtocolPhase {
HANDSHAKE, PLAY, STATUS, LOGIN, CONFIGURATION, UNKNOWN;
diff --git a/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java b/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
new file mode 100644
index 000000000..e9196bd41
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
@@ -0,0 +1,32 @@
+package dev.protocollib.api.listener;
+
+import dev.protocollib.api.PacketContainer;
+
+/**
+ * Functional interface for handling packets asynchronously.
+ *
+ *
Once a packet is processed by the listener, the context's
+ * {@code resumeProcessing()} or {@code resumeProcessingWithException(Throwable)}
+ * methods must be called to signal that the listener is done with the packet.
+ * Failing to call one of these methods will cause the packet to remain in
+ * a waiting state until it times out, preventing further listeners from
+ * receiving the packet.
+ *
+ */
+@FunctionalInterface
+public interface AsyncPacketListener {
+
+ /**
+ * Handles a packet that was sent or received, asynchronously.
+ *
+ *
Once processing is complete, ensure that one of the {@code resumeProcessing}
+ * methods from the {@link AsyncPacketListenerContext} is called. This allows the
+ * packet to continue to the next listener. If not called, the packet will remain
+ * in a waiting state and will only proceed after a timeout occurs.
+ *
+ * @param packet the packet to handle
+ * @param context the context providing additional information about the packet and connection
+ */
+ void handlePacket(PacketContainer packet, AsyncPacketListenerContext context);
+
+}
diff --git a/src/main/java/dev/protocollib/api/listener/AsyncPacketListenerContext.java b/src/main/java/dev/protocollib/api/listener/AsyncPacketListenerContext.java
new file mode 100644
index 000000000..3676edcfa
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/listener/AsyncPacketListenerContext.java
@@ -0,0 +1,21 @@
+package dev.protocollib.api.listener;
+
+/**
+ * Representing the context of an asynchronous packet listener.
+ */
+public interface AsyncPacketListenerContext extends SyncPacketListenerContext {
+
+ /**
+ * Singles the listener is done with processing the packet.
+ */
+ void resumeProcessing();
+
+ /**
+ * Singles the listener is done with processing the packet and finished
+ * with an exception.
+ *
+ * @param throwable the processing exception
+ */
+ void resumeProcessingWithException(Throwable throwable);
+
+}
diff --git a/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java b/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
new file mode 100644
index 000000000..4cb9e4fba
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
@@ -0,0 +1,74 @@
+package dev.protocollib.api.listener;
+
+import java.util.Collection;
+
+import dev.protocollib.api.PacketType;
+
+/**
+ * Builder for creating and registering packet listeners.
+ */
+public interface PacketListenerBuilder {
+
+ /**
+ * Specifies the types of packets to listen for.
+ *
+ * @param packetTypes the packet types to listen for
+ * @return the same builder for further configuration
+ */
+ PacketListenerBuilder.WithType types(PacketType... packetTypes);
+
+ /**
+ * Specifies the types of packets to listen for.
+ *
+ * @param packetTypes the collection of packet types to listen for
+ * @return the same builder for further configuration
+ */
+ PacketListenerBuilder.WithType types(Collection packetTypes);
+
+ /**
+ * Interface for building a packet listener with specific packet types.
+ */
+ public interface WithType {
+
+ /**
+ * Specifies the priority of the packet listener.
+ *
+ * @param priority the priority to assign to the listener
+ * @return the same builder for further configuration
+ */
+ PacketListenerBuilder.WithType priority(PacketListenerPriority priority);
+
+ /**
+ * Marks the listener as immutable, preventing modifications of packets
+ * inside the listener.
+ *
+ * @return the same builder for further configuration
+ */
+ PacketListenerBuilder.WithType immutable();
+
+ /**
+ * Configures the listener to ignore packets that have been cancelled.
+ *
+ * @return the same builder for further configuration
+ */
+ PacketListenerBuilder.WithType ignoreCancelledPackets();
+
+ /**
+ * Registers the packet listener to operate synchronously. The listener
+ * will always get called on the main game thread.
+ *
+ * @param listener the synchronous packet listener to register
+ * @return the same builder for further configuration
+ */
+ PacketListenerRegistration registerSync(SyncPacketListener listener);
+
+ /**
+ * Registers the packet listener to operate asynchronously.
+ *
+ * @param listener the asynchronous packet listener to register
+ * @return the same builder for further configuration
+ */
+ PacketListenerRegistration registerAsync(AsyncPacketListener listener);
+ }
+}
+
diff --git a/src/main/java/dev/protocollib/api/listener/PacketListenerPriority.java b/src/main/java/dev/protocollib/api/listener/PacketListenerPriority.java
new file mode 100644
index 000000000..b7a912134
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/listener/PacketListenerPriority.java
@@ -0,0 +1,22 @@
+package dev.protocollib.api.listener;
+
+/**
+ * Representing the priority levels for packet listeners.
+ */
+public enum PacketListenerPriority {
+
+ /** Lowest priority, executed first. */
+ LOWEST,
+
+ /** Low priority, executed after lowest but before normal. */
+ LOW,
+
+ /** Normal priority, executed after low but before high. */
+ NORMAL,
+
+ /** High priority, executed after normal but before highest. */
+ HIGH,
+
+ /** Highest priority, executed last. */
+ HIGHEST;
+}
diff --git a/src/main/java/dev/protocollib/api/listener/PacketListenerRegistration.java b/src/main/java/dev/protocollib/api/listener/PacketListenerRegistration.java
new file mode 100644
index 000000000..e18a92c66
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/listener/PacketListenerRegistration.java
@@ -0,0 +1,14 @@
+package dev.protocollib.api.listener;
+
+/**
+ * Representing the registration of a packet listener.
+ * Allows unregistering the listener when no longer needed.
+ */
+public interface PacketListenerRegistration {
+
+ /**
+ * Unregisters the packet listener, stopping it from receiving further packets.
+ */
+ void unregister();
+}
+
diff --git a/src/main/java/dev/protocollib/api/listener/PacketSentListener.java b/src/main/java/dev/protocollib/api/listener/PacketSentListener.java
new file mode 100644
index 000000000..dc28b346f
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/listener/PacketSentListener.java
@@ -0,0 +1,16 @@
+package dev.protocollib.api.listener;
+
+/**
+ * Functional interface for a listener that is invoked when a packet has been sent.
+ *
+ * This method will get invoked on the underlying channel's event-loop.
+ */
+@FunctionalInterface
+public interface PacketSentListener {
+
+ /**
+ * Invoked when a packet has been successfully sent.
+ */
+ void invoke();
+}
+
diff --git a/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java b/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
new file mode 100644
index 000000000..1bc35b4ae
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
@@ -0,0 +1,19 @@
+package dev.protocollib.api.listener;
+
+import dev.protocollib.api.PacketContainer;
+
+/**
+ * Functional interface for handling packets synchronously.
+ */
+@FunctionalInterface
+public interface SyncPacketListener {
+
+ /**
+ * Synchronously handles a packet that was sent or received.
+ *
+ * @param packet the packet to handle
+ * @param context the context providing additional information about the packet and functions
+ */
+ void handlePacket(PacketContainer packet, SyncPacketListenerContext context);
+
+}
diff --git a/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java b/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
new file mode 100644
index 000000000..4afa166b1
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
@@ -0,0 +1,36 @@
+package dev.protocollib.api.listener;
+
+import dev.protocollib.api.Connection;
+
+/**
+ * Representing the context of a synchronous packet listener.
+ */
+public interface SyncPacketListenerContext {
+
+ /**
+ * Retrieves the connection associated with the packet.
+ *
+ * @return the connection handling the packet
+ */
+ Connection connection();
+
+ /**
+ * Checks if the packet handling has been cancelled.
+ *
+ * @return true if the packet is cancelled, false otherwise
+ */
+ boolean isCancelled();
+
+ /**
+ * Cancels the packet, preventing it from being processed further.
+ */
+ void cancel();
+
+ /**
+ * Adds a listener to be invoked after the packet is sent.
+ *
+ * @param listener the post-sent listener
+ */
+ void addPostSentListener(PacketSentListener listener);
+}
+
From 34ed976c624e37c44679b97e0598ea6d4ee9bb60 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?=
Date: Sat, 26 Oct 2024 03:05:37 +0200
Subject: [PATCH 3/6] feat(api): add send/receive packet methods
---
build.gradle | 4 +-
.../java/dev/protocollib/api/Connection.java | 53 ++++++++-----------
.../java/dev/protocollib/api/ProtocolLib.java | 22 ++++++++
.../api/listener/AsyncPacketListener.java | 2 +-
.../api/listener/PacketListenerBuilder.java | 2 +-
...r.java => PacketTransmissionListener.java} | 6 ++-
.../api/listener/SyncPacketListener.java | 2 +-
.../listener/SyncPacketListenerContext.java | 6 +--
.../api/{ => packet}/BinaryPacket.java | 5 +-
.../api/{ => packet}/PacketContainer.java | 11 +++-
.../protocollib/api/packet/PacketLike.java | 5 ++
.../api/packet/PacketOperationBuilder.java | 44 +++++++++++++++
.../api/{ => packet}/PacketType.java | 3 +-
.../api/{ => packet}/PacketTypes.java | 2 +-
14 files changed, 119 insertions(+), 48 deletions(-)
rename src/main/java/dev/protocollib/api/listener/{PacketSentListener.java => PacketTransmissionListener.java} (59%)
rename src/main/java/dev/protocollib/api/{ => packet}/BinaryPacket.java (76%)
rename src/main/java/dev/protocollib/api/{ => packet}/PacketContainer.java (53%)
create mode 100644 src/main/java/dev/protocollib/api/packet/PacketLike.java
create mode 100644 src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java
rename src/main/java/dev/protocollib/api/{ => packet}/PacketType.java (93%)
rename src/main/java/dev/protocollib/api/{ => packet}/PacketTypes.java (74%)
diff --git a/build.gradle b/build.gradle
index 058187d92..879cfc783 100644
--- a/build.gradle
+++ b/build.gradle
@@ -52,8 +52,8 @@ dependencies {
}
java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
withJavadocJar()
withSourcesJar()
diff --git a/src/main/java/dev/protocollib/api/Connection.java b/src/main/java/dev/protocollib/api/Connection.java
index 9e6825506..f789b1833 100644
--- a/src/main/java/dev/protocollib/api/Connection.java
+++ b/src/main/java/dev/protocollib/api/Connection.java
@@ -5,24 +5,31 @@
import org.bukkit.entity.Player;
-import dev.protocollib.api.listener.PacketSentListener;
+import dev.protocollib.api.packet.PacketLike;
+import dev.protocollib.api.packet.PacketOperationBuilder;
/**
- * Representing a connection of a player.
+ * Represents a connection associated with a player.
+ *
+ *
This interface provides methods to interact with the player's network connection,
+ * including retrieving the player's information, connection address, protocol version,
+ * and current connection state. It also allows for sending and receiving packets
+ * through the connection.
*/
public interface Connection {
+
/**
* Retrieves the player associated with the connection, if available.
*
- * @return an optional containing the player, or empty if the player is not present
+ * @return an {@link Optional} containing the player, or empty if the player is not present
*/
Optional player();
/**
* Retrieves the address of the connection.
*
- * @return the remote address of the connection
+ * @return the remote {@link InetSocketAddress} of the connection
*/
InetSocketAddress address();
@@ -37,53 +44,37 @@ public interface Connection {
* Retrieves the current protocol phase of the connection for a given direction.
*
* @param packetDirection the direction of the packet (clientbound or serverbound)
- * @return the protocol phase of the connection
+ * @return the {@link ProtocolPhase} representing the current phase of the connection
*/
ProtocolPhase protocolPhase(ProtocolDirection packetDirection);
/**
* Checks if the connection is currently open.
*
- * @return true if the connection is open, false otherwise
+ * @return {@code true} if the connection is open, {@code false} otherwise
*/
boolean isConnected();
/**
- * Sends a binary packet over the connection.
- *
- * @param packet the binary packet to send
- */
- void sendPacket(BinaryPacket packet);
-
- /**
- * Sends a binary packet over the connection and registers a listener for when the packet is sent.
- *
- * @param packet the binary packet to send
- * @param listener the listener to invoke once the packet is sent
- */
- void sendPacket(BinaryPacket packet, PacketSentListener listener);
-
- /**
- * Sends a packet container over the connection.
+ * Initiates a packet operation, which can involve sending or receiving a packet.
*
- * @param packet the packet container to send
+ * @return a {@link PacketOperationBuilder} to configure the packet operation
*/
- void sendPacket(PacketContainer packet);
+ PacketOperationBuilder packetOperation();
/**
- * Sends a packet container over the connection and registers a listener for when the packet is sent.
+ * Sends a packet to the client.
*
- * @param packet the packet container to send
- * @param listener the listener to invoke once the packet is sent
+ * @param packet the packet to send
*/
- void sendPacket(PacketContainer packet, PacketSentListener listener);
+ void sendPacket(PacketLike packet);
/**
- * Receives a packet container from the connection.
+ * Receives a packet as if the client had sent it.
*
- * @param packet the packet container received
+ * @param packet the received packet
*/
- void receivePacket(PacketContainer packet);
+ void receivePacket(PacketLike packet);
/**
* Disconnects the connection with the specified reason.
diff --git a/src/main/java/dev/protocollib/api/ProtocolLib.java b/src/main/java/dev/protocollib/api/ProtocolLib.java
index 859c7b441..dda0bf1ef 100644
--- a/src/main/java/dev/protocollib/api/ProtocolLib.java
+++ b/src/main/java/dev/protocollib/api/ProtocolLib.java
@@ -4,6 +4,10 @@
import org.bukkit.plugin.Plugin;
import dev.protocollib.api.listener.PacketListenerBuilder;
+import dev.protocollib.api.packet.BinaryPacket;
+import dev.protocollib.api.packet.PacketContainer;
+import dev.protocollib.api.packet.PacketLike;
+import dev.protocollib.api.packet.PacketType;
/**
* Representing the main entry point for the ProtocolLib API.
@@ -26,6 +30,24 @@ public interface ProtocolLib {
*/
Connection connection(Player player);
+ /**
+ * Sends a packet to the player.
+ *
+ * @param packet the packet to send
+ */
+ default void sendPacket(Player player, PacketLike packet) {
+ connection(player).sendPacket(packet);
+ }
+
+ /**
+ * Receives a packet as if the player had sent it.
+ *
+ * @param packet the received packet
+ */
+ default void receivePacket(Player player, PacketLike packet) {
+ connection(player).receivePacket(packet);
+ }
+
/**
* Creates a new binary packet with the given type and payload.
*
diff --git a/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java b/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
index e9196bd41..9c46ee300 100644
--- a/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
+++ b/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
@@ -1,6 +1,6 @@
package dev.protocollib.api.listener;
-import dev.protocollib.api.PacketContainer;
+import dev.protocollib.api.packet.PacketContainer;
/**
* Functional interface for handling packets asynchronously.
diff --git a/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java b/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
index 4cb9e4fba..1a9a6951d 100644
--- a/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
+++ b/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
@@ -2,7 +2,7 @@
import java.util.Collection;
-import dev.protocollib.api.PacketType;
+import dev.protocollib.api.packet.PacketType;
/**
* Builder for creating and registering packet listeners.
diff --git a/src/main/java/dev/protocollib/api/listener/PacketSentListener.java b/src/main/java/dev/protocollib/api/listener/PacketTransmissionListener.java
similarity index 59%
rename from src/main/java/dev/protocollib/api/listener/PacketSentListener.java
rename to src/main/java/dev/protocollib/api/listener/PacketTransmissionListener.java
index dc28b346f..0b030375d 100644
--- a/src/main/java/dev/protocollib/api/listener/PacketSentListener.java
+++ b/src/main/java/dev/protocollib/api/listener/PacketTransmissionListener.java
@@ -1,12 +1,14 @@
package dev.protocollib.api.listener;
/**
- * Functional interface for a listener that is invoked when a packet has been sent.
+ * Functional interface for a listener that is invoked when a packet has been sent
+ * (according to the underlying write's ChannelFuture) or received (just before the
+ * packet gets processed by mojangs packet handlers).
*
* This method will get invoked on the underlying channel's event-loop.
*/
@FunctionalInterface
-public interface PacketSentListener {
+public interface PacketTransmissionListener {
/**
* Invoked when a packet has been successfully sent.
diff --git a/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java b/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
index 1bc35b4ae..37b951a40 100644
--- a/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
+++ b/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
@@ -1,6 +1,6 @@
package dev.protocollib.api.listener;
-import dev.protocollib.api.PacketContainer;
+import dev.protocollib.api.packet.PacketContainer;
/**
* Functional interface for handling packets synchronously.
diff --git a/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java b/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
index 4afa166b1..32dd4a35c 100644
--- a/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
+++ b/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
@@ -27,10 +27,10 @@ public interface SyncPacketListenerContext {
void cancel();
/**
- * Adds a listener to be invoked after the packet is sent.
+ * Adds a listener to be invoked after the packet is sent or received.
*
- * @param listener the post-sent listener
+ * @param listener the transmission listener to invoke
*/
- void addPostSentListener(PacketSentListener listener);
+ void addTransmissionListener(PacketTransmissionListener listener);
}
diff --git a/src/main/java/dev/protocollib/api/BinaryPacket.java b/src/main/java/dev/protocollib/api/packet/BinaryPacket.java
similarity index 76%
rename from src/main/java/dev/protocollib/api/BinaryPacket.java
rename to src/main/java/dev/protocollib/api/packet/BinaryPacket.java
index bdc14e2b9..d845c0c80 100644
--- a/src/main/java/dev/protocollib/api/BinaryPacket.java
+++ b/src/main/java/dev/protocollib/api/packet/BinaryPacket.java
@@ -1,9 +1,9 @@
-package dev.protocollib.api;
+package dev.protocollib.api.packet;
/**
* Representing a raw binary packet with a packet id and payload.
*/
-public interface BinaryPacket {
+public non-sealed interface BinaryPacket extends PacketLike {
/**
* Retrieves the packet id.
@@ -19,4 +19,3 @@ public interface BinaryPacket {
*/
byte[] payload();
}
-
diff --git a/src/main/java/dev/protocollib/api/PacketContainer.java b/src/main/java/dev/protocollib/api/packet/PacketContainer.java
similarity index 53%
rename from src/main/java/dev/protocollib/api/PacketContainer.java
rename to src/main/java/dev/protocollib/api/packet/PacketContainer.java
index f23655c6e..5e1452b42 100644
--- a/src/main/java/dev/protocollib/api/PacketContainer.java
+++ b/src/main/java/dev/protocollib/api/packet/PacketContainer.java
@@ -1,9 +1,9 @@
-package dev.protocollib.api;
+package dev.protocollib.api.packet;
/**
* Representing a container for a packet.
*/
-public interface PacketContainer {
+public non-sealed interface PacketContainer extends PacketLike {
/**
* Retrieves the type of the packet.
@@ -19,4 +19,11 @@ public interface PacketContainer {
*/
Object packet();
+ /**
+ * Creates and returns a mutable copy of this packet.
+ *
+ * @return a clone of this instance.
+ */
+ PacketContainer clone();
+
}
diff --git a/src/main/java/dev/protocollib/api/packet/PacketLike.java b/src/main/java/dev/protocollib/api/packet/PacketLike.java
new file mode 100644
index 000000000..b9a2b4a66
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/packet/PacketLike.java
@@ -0,0 +1,5 @@
+package dev.protocollib.api.packet;
+
+public sealed interface PacketLike permits BinaryPacket, PacketContainer {
+
+}
diff --git a/src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java b/src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java
new file mode 100644
index 000000000..4c2e2622f
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java
@@ -0,0 +1,44 @@
+package dev.protocollib.api.packet;
+
+import dev.protocollib.api.listener.PacketTransmissionListener;
+
+/**
+ * Builder interface for constructing packet operations.
+ *
+ *
This interface provides methods to configure how packets are sent
+ * or received within ProtocolLib.
This method allows the caller to prevent further handling of the packet
+ * by other plugin listeners in the pipeline.
+ *
+ * @return the same builder for further configuration
+ */
+ PacketOperationBuilder skipProcessing();
+
+ /**
+ * Registers a listener to be called once the packet has been sent or received.
+ *
+ * @param listener the listener to be notified upon packet transmission
+ * @return the same builder for further configuration
+ */
+ PacketOperationBuilder postTransmission(PacketTransmissionListener listener);
+
+ /**
+ * Sends a packet to the client.
+ *
+ * @param packet the {@link PacketContainer} to send
+ */
+ void send(PacketLike packet);
+
+ /**
+ * Receives a packet as if the client had sent it.
+ *
+ * @param packet the {@link PacketContainer} to receive
+ */
+ void receive(PacketLike packet);
+}
diff --git a/src/main/java/dev/protocollib/api/PacketType.java b/src/main/java/dev/protocollib/api/packet/PacketType.java
similarity index 93%
rename from src/main/java/dev/protocollib/api/PacketType.java
rename to src/main/java/dev/protocollib/api/packet/PacketType.java
index 18290de30..4d874f53b 100644
--- a/src/main/java/dev/protocollib/api/PacketType.java
+++ b/src/main/java/dev/protocollib/api/packet/PacketType.java
@@ -1,7 +1,8 @@
-package dev.protocollib.api;
+package dev.protocollib.api.packet;
import java.util.Optional;
+import dev.protocollib.api.ProtocolDirection;
import net.kyori.adventure.key.Keyed;
/**
diff --git a/src/main/java/dev/protocollib/api/PacketTypes.java b/src/main/java/dev/protocollib/api/packet/PacketTypes.java
similarity index 74%
rename from src/main/java/dev/protocollib/api/PacketTypes.java
rename to src/main/java/dev/protocollib/api/packet/PacketTypes.java
index 8a623ccf3..92418b6b8 100644
--- a/src/main/java/dev/protocollib/api/PacketTypes.java
+++ b/src/main/java/dev/protocollib/api/packet/PacketTypes.java
@@ -1,4 +1,4 @@
-package dev.protocollib.api;
+package dev.protocollib.api.packet;
public class PacketTypes {
From fbc24f659ab41fa889a0a1fffa35db197d66706d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?=
Date: Sun, 23 Mar 2025 00:38:12 +0100
Subject: [PATCH 4/6] feat: add bundle behavior, terminal packets
---
src/main/java/dev/protocollib/Example.java | 102 ++++++++++++++++++
.../dev/protocollib/api/ProtocolPhase.java | 2 +-
.../api/listener/AsyncPacketListener.java | 4 +-
.../listener/AsyncPacketListenerContext.java | 4 +-
.../api/listener/PacketListenerBuilder.java | 42 ++++++--
.../PacketListenerBundleBehavior.java | 31 ++++++
.../listener/PacketListenerRegistration.java | 1 -
.../listener/PacketTransmissionListener.java | 1 -
.../api/listener/SyncPacketListener.java | 4 +-
.../listener/SyncPacketListenerContext.java | 13 ++-
.../api/packet/PacketContainer.java | 18 +++-
.../api/packet/PacketOperationBuilder.java | 11 +-
.../protocollib/api/packet/PacketType.java | 29 ++++-
.../protocollib/api/packet/PacketTypes.java | 5 +
14 files changed, 237 insertions(+), 30 deletions(-)
create mode 100644 src/main/java/dev/protocollib/Example.java
create mode 100644 src/main/java/dev/protocollib/api/listener/PacketListenerBundleBehavior.java
diff --git a/src/main/java/dev/protocollib/Example.java b/src/main/java/dev/protocollib/Example.java
new file mode 100644
index 000000000..75f1e4e84
--- /dev/null
+++ b/src/main/java/dev/protocollib/Example.java
@@ -0,0 +1,102 @@
+package dev.protocollib;
+
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+import dev.protocollib.api.ProtocolLib;
+import dev.protocollib.api.listener.*;
+import dev.protocollib.api.packet.*;
+import java.util.concurrent.*;
+
+public class Example {
+
+ private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool();
+ private static ProtocolLib protocolLib;
+ private static Plugin plugin;
+
+ // ========================
+ // Packet Listeners
+ // ========================
+
+ static void registerListeners() {
+ // sync read-only listener
+ protocolLib
+ .createListener(plugin)
+ .types(PacketTypes.Game.LEVEL_CHUNK)
+ .priority(PacketListenerPriority.LOW)
+ .includeCanceledPackets()
+ .bundleBehavior(PacketListenerBundleBehavior.SKIP_OUTSIDE_BUNDLE)
+ .registerSync((packet, context) -> {
+ Chunk chunk = Chunk.from(packet);
+ // Sync processing
+ });
+
+ // async modify packet on netty thread
+ protocolLib
+ .createListener(plugin)
+ .types(PacketTypes.Game.LEVEL_CHUNK)
+ .mutable()
+ .registerAsync((packet, context) -> {
+ Chunk chunk = Chunk.from(packet);
+
+ // do processing here ...
+ // write changes to packet ...
+
+ context.addTransmissionListener(chunk::markSent);
+ context.resumeProcessing();
+ });
+
+ // async modify packet on app thread-pool
+ protocolLib
+ .createListener(plugin)
+ .types(PacketTypes.Game.LEVEL_CHUNK)
+ .mutable()
+ .registerAsync((packet, context) -> {
+ Chunk chunk = Chunk.from(packet);
+
+ EXECUTOR.execute(() -> {
+
+ // do heavy processing here ...
+ // write changes to packet ...
+
+ context.addTransmissionListener(chunk::markSent);
+ context.resumeProcessing();
+ });
+ });
+ }
+
+ // ========================
+ // Packet Sending
+ // ========================
+
+ static void sendPackets(Player player, Chunk chunk) {
+ // full packet operation
+ protocolLib
+ .connection(player)
+ .packetOperation()
+ .skipProcessing()
+ .postTransmission(chunk::markSent)
+ .send(chunk.packet());
+
+ // connection shortcut
+ protocolLib
+ .connection(player)
+ .sendPacket(chunk.packet());
+
+ // direct API shortcut
+ protocolLib
+ .sendPacket(player, chunk.packet());
+ }
+
+ // ========================
+ // Chunk Implementation
+ // ========================
+
+ static class Chunk {
+ static Chunk from(PacketContainer packet) {
+ return new Chunk();
+ }
+
+ PacketContainer packet() { return null; }
+ void markSent() {}
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dev/protocollib/api/ProtocolPhase.java b/src/main/java/dev/protocollib/api/ProtocolPhase.java
index e3b92e02a..003596478 100644
--- a/src/main/java/dev/protocollib/api/ProtocolPhase.java
+++ b/src/main/java/dev/protocollib/api/ProtocolPhase.java
@@ -5,6 +5,6 @@
*/
public enum ProtocolPhase {
- HANDSHAKE, PLAY, STATUS, LOGIN, CONFIGURATION, UNKNOWN;
+ HANDSHAKE, GAME, STATUS, LOGIN, CONFIGURATION, UNKNOWN;
}
diff --git a/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java b/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
index 9c46ee300..1027a0ec1 100644
--- a/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
+++ b/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
@@ -1,5 +1,7 @@
package dev.protocollib.api.listener;
+import org.jetbrains.annotations.NotNull;
+
import dev.protocollib.api.packet.PacketContainer;
/**
@@ -27,6 +29,6 @@ public interface AsyncPacketListener {
* @param packet the packet to handle
* @param context the context providing additional information about the packet and connection
*/
- void handlePacket(PacketContainer packet, AsyncPacketListenerContext context);
+ void handlePacket(@NotNull PacketContainer packet, @NotNull AsyncPacketListenerContext context);
}
diff --git a/src/main/java/dev/protocollib/api/listener/AsyncPacketListenerContext.java b/src/main/java/dev/protocollib/api/listener/AsyncPacketListenerContext.java
index 3676edcfa..f014651b2 100644
--- a/src/main/java/dev/protocollib/api/listener/AsyncPacketListenerContext.java
+++ b/src/main/java/dev/protocollib/api/listener/AsyncPacketListenerContext.java
@@ -1,5 +1,7 @@
package dev.protocollib.api.listener;
+import org.jetbrains.annotations.NotNull;
+
/**
* Representing the context of an asynchronous packet listener.
*/
@@ -16,6 +18,6 @@ public interface AsyncPacketListenerContext extends SyncPacketListenerContext {
*
* @param throwable the processing exception
*/
- void resumeProcessingWithException(Throwable throwable);
+ void resumeProcessingWithException(@NotNull Throwable throwable);
}
diff --git a/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java b/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
index 1a9a6951d..f12bec871 100644
--- a/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
+++ b/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
@@ -2,6 +2,9 @@
import java.util.Collection;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+
import dev.protocollib.api.packet.PacketType;
/**
@@ -15,7 +18,8 @@ public interface PacketListenerBuilder {
* @param packetTypes the packet types to listen for
* @return the same builder for further configuration
*/
- PacketListenerBuilder.WithType types(PacketType... packetTypes);
+ @NotNull
+ PacketListenerBuilder.WithType types(@NotNull PacketType... packetTypes);
/**
* Specifies the types of packets to listen for.
@@ -23,7 +27,8 @@ public interface PacketListenerBuilder {
* @param packetTypes the collection of packet types to listen for
* @return the same builder for further configuration
*/
- PacketListenerBuilder.WithType types(Collection packetTypes);
+ @NotNull
+ PacketListenerBuilder.WithType types(@NotNull Collection packetTypes);
/**
* Interface for building a packet listener with specific packet types.
@@ -36,22 +41,36 @@ public interface WithType {
* @param priority the priority to assign to the listener
* @return the same builder for further configuration
*/
- PacketListenerBuilder.WithType priority(PacketListenerPriority priority);
+ @Contract("_ -> this")
+ PacketListenerBuilder.WithType priority(@NotNull PacketListenerPriority priority);
/**
- * Marks the listener as immutable, preventing modifications of packets
- * inside the listener.
+ * Allows the listener to modify packets. By default, listeners are read-only and
+ * cannot modify packets.
*
* @return the same builder for further configuration
*/
- PacketListenerBuilder.WithType immutable();
+ @Contract("_ -> this")
+ PacketListenerBuilder.WithType mutable();
/**
- * Configures the listener to ignore packets that have been cancelled.
+ * Configures the bundle behavior for the listener, determining how packets in bundles are handled.
*
+ * @param bundleBehavior the bundle behavior to apply
* @return the same builder for further configuration
+ * @see PacketListenerBundleBehavior
*/
- PacketListenerBuilder.WithType ignoreCancelledPackets();
+ @Contract("_ -> this")
+ PacketListenerBuilder.WithType bundleBehavior(@NotNull PacketListenerBundleBehavior bundleBehavior);
+
+ /**
+ * Configures the listener to include packets that have been canceled. By default,
+ * canceled packets are skipped.
+ *
+ * @return the same builder for further configuration
+ */
+ @Contract("_ -> this")
+ PacketListenerBuilder.WithType includeCanceledPackets();
/**
* Registers the packet listener to operate synchronously. The listener
@@ -60,7 +79,8 @@ public interface WithType {
* @param listener the synchronous packet listener to register
* @return the same builder for further configuration
*/
- PacketListenerRegistration registerSync(SyncPacketListener listener);
+ @NotNull
+ PacketListenerRegistration registerSync(@NotNull SyncPacketListener listener);
/**
* Registers the packet listener to operate asynchronously.
@@ -68,7 +88,7 @@ public interface WithType {
* @param listener the asynchronous packet listener to register
* @return the same builder for further configuration
*/
- PacketListenerRegistration registerAsync(AsyncPacketListener listener);
+ @NotNull
+ PacketListenerRegistration registerAsync(@NotNull AsyncPacketListener listener);
}
}
-
diff --git a/src/main/java/dev/protocollib/api/listener/PacketListenerBundleBehavior.java b/src/main/java/dev/protocollib/api/listener/PacketListenerBundleBehavior.java
new file mode 100644
index 000000000..e6eb9111e
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/listener/PacketListenerBundleBehavior.java
@@ -0,0 +1,31 @@
+package dev.protocollib.api.listener;
+
+/**
+ * Controls packet processing behavior relative to packet bundles (groups of
+ * packets processed atomically).
+ *
+ * Determines whether individual packets should be processed or ignored based on
+ * their membership in a packet bundle. Packet bundles typically represent
+ * groups of packets that are be processed together as an atomic unit.
+ *
+ */
+public enum PacketListenerBundleBehavior {
+
+ /**
+ * Processes all packets unconditionally, regardless of whether they are part of
+ * a packet bundle.
+ */
+ ALWAYS,
+
+ /**
+ * Processes only packets that exist outside of packet bundles, ignoring those
+ * inside bundles.
+ */
+ SKIP_INSIDE_BUNDLE,
+
+ /**
+ * Processes only packets that are part of packet bundles, ignoring standalone
+ * packets.
+ */
+ SKIP_OUTSIDE_BUNDLE;
+}
diff --git a/src/main/java/dev/protocollib/api/listener/PacketListenerRegistration.java b/src/main/java/dev/protocollib/api/listener/PacketListenerRegistration.java
index e18a92c66..cfcc71722 100644
--- a/src/main/java/dev/protocollib/api/listener/PacketListenerRegistration.java
+++ b/src/main/java/dev/protocollib/api/listener/PacketListenerRegistration.java
@@ -11,4 +11,3 @@ public interface PacketListenerRegistration {
*/
void unregister();
}
-
diff --git a/src/main/java/dev/protocollib/api/listener/PacketTransmissionListener.java b/src/main/java/dev/protocollib/api/listener/PacketTransmissionListener.java
index 0b030375d..0ea27c869 100644
--- a/src/main/java/dev/protocollib/api/listener/PacketTransmissionListener.java
+++ b/src/main/java/dev/protocollib/api/listener/PacketTransmissionListener.java
@@ -15,4 +15,3 @@ public interface PacketTransmissionListener {
*/
void invoke();
}
-
diff --git a/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java b/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
index 37b951a40..81e0caf77 100644
--- a/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
+++ b/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
@@ -1,5 +1,7 @@
package dev.protocollib.api.listener;
+import org.jetbrains.annotations.NotNull;
+
import dev.protocollib.api.packet.PacketContainer;
/**
@@ -14,6 +16,6 @@ public interface SyncPacketListener {
* @param packet the packet to handle
* @param context the context providing additional information about the packet and functions
*/
- void handlePacket(PacketContainer packet, SyncPacketListenerContext context);
+ void handlePacket(@NotNull PacketContainer packet, @NotNull SyncPacketListenerContext context);
}
diff --git a/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java b/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
index 32dd4a35c..7439d13d1 100644
--- a/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
+++ b/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
@@ -1,5 +1,7 @@
package dev.protocollib.api.listener;
+import org.jetbrains.annotations.NotNull;
+
import dev.protocollib.api.Connection;
/**
@@ -12,6 +14,7 @@ public interface SyncPacketListenerContext {
*
* @return the connection handling the packet
*/
+ @NotNull
Connection connection();
/**
@@ -22,15 +25,17 @@ public interface SyncPacketListenerContext {
boolean isCancelled();
/**
- * Cancels the packet, preventing it from being processed further.
+ * Sets whether the packet handling is cancelled. If cancelled, the packet
+ * will not be processed further.
+ *
+ * @param cancelled true to cancel the packet, false to allow processing
*/
- void cancel();
+ void setCancelled(boolean cancelled);
/**
* Adds a listener to be invoked after the packet is sent or received.
*
* @param listener the transmission listener to invoke
*/
- void addTransmissionListener(PacketTransmissionListener listener);
+ void addTransmissionListener(@NotNull PacketTransmissionListener listener);
}
-
diff --git a/src/main/java/dev/protocollib/api/packet/PacketContainer.java b/src/main/java/dev/protocollib/api/packet/PacketContainer.java
index 5e1452b42..b7f7f6626 100644
--- a/src/main/java/dev/protocollib/api/packet/PacketContainer.java
+++ b/src/main/java/dev/protocollib/api/packet/PacketContainer.java
@@ -1,5 +1,8 @@
package dev.protocollib.api.packet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
/**
* Representing a container for a packet.
*/
@@ -10,6 +13,7 @@ public non-sealed interface PacketContainer extends PacketLike {
*
* @return the packet type
*/
+ @NotNull
PacketType packetType();
/**
@@ -17,13 +21,23 @@ public non-sealed interface PacketContainer extends PacketLike {
*
* @return the packet object
*/
+ @NotNull
Object packet();
+ /**
+ * Retrieves the packet bundle that this packet is part of, if any.
+ * A packet bundle represents a collection of packets that are processed together.
+ *
+ * @return the packet bundle containing this packet, or {@code null} if not part of a bundle
+ */
+ @Nullable
+ PacketContainer bundle();
+
/**
* Creates and returns a mutable copy of this packet.
*
- * @return a clone of this instance.
+ * @return a clone of this instance
*/
+ @Nullable
PacketContainer clone();
-
}
diff --git a/src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java b/src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java
index 4c2e2622f..50fdb123b 100644
--- a/src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java
+++ b/src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java
@@ -1,5 +1,8 @@
package dev.protocollib.api.packet;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+
import dev.protocollib.api.listener.PacketTransmissionListener;
/**
@@ -18,6 +21,7 @@ public interface PacketOperationBuilder {
*
* @return the same builder for further configuration
*/
+ @Contract("_ -> this")
PacketOperationBuilder skipProcessing();
/**
@@ -26,19 +30,20 @@ public interface PacketOperationBuilder {
* @param listener the listener to be notified upon packet transmission
* @return the same builder for further configuration
*/
- PacketOperationBuilder postTransmission(PacketTransmissionListener listener);
+ @Contract("_ -> this")
+ PacketOperationBuilder postTransmission(@NotNull PacketTransmissionListener listener);
/**
* Sends a packet to the client.
*
* @param packet the {@link PacketContainer} to send
*/
- void send(PacketLike packet);
+ void send(@NotNull PacketLike packet);
/**
* Receives a packet as if the client had sent it.
*
* @param packet the {@link PacketContainer} to receive
*/
- void receive(PacketLike packet);
+ void receive(@NotNull PacketLike packet);
}
diff --git a/src/main/java/dev/protocollib/api/packet/PacketType.java b/src/main/java/dev/protocollib/api/packet/PacketType.java
index 4d874f53b..c3dd19f6e 100644
--- a/src/main/java/dev/protocollib/api/packet/PacketType.java
+++ b/src/main/java/dev/protocollib/api/packet/PacketType.java
@@ -3,14 +3,15 @@
import java.util.Optional;
import dev.protocollib.api.ProtocolDirection;
+import dev.protocollib.api.ProtocolPhase;
import net.kyori.adventure.key.Keyed;
/**
* Representing the type of a network packet.
*
*
A {@code PacketType} identifies a specific type of packet in the protocol,
- * including information about its direction, associated class (if any), and
- * whether the packet is currently supported.
+ * including information about its direction, phase in the protocol, associated class (if any),
+ * whether the packet is currently supported and if it terminates the current phase.
*/
public interface PacketType extends Keyed {
@@ -21,11 +22,23 @@ public interface PacketType extends Keyed {
*/
ProtocolDirection protocolDirection();
+ /**
+ * Retrieves the protocol phase during which this packet is used.
+ * This indicates which phase of the protocol (e.g., HANDSHAKE, LOGIN, GAME)
+ * the packet belongs to.
+ *
+ * @return the {@link ProtocolPhase} associated with this packet
+ */
+ ProtocolPhase protocolPhase();
+
/**
* Retrieves the class associated with the packet type, if available.
*
- *
Not all packet types have an associated class. If there is no class,
- * an empty {@link Optional} is returned.
+ *
If the packet is supported (i.e., {@link #isSupported()} returns {@code true}),
+ * this method will always return a non-empty {@link Optional} containing the packet class.
+ * Note that the same packet class may be reused across different protocol phases.
+ * The current protocol phase should be checked via {@link #protocolPhase()} to determine
+ * the correct context.
*
* @return an {@link Optional} containing the class of the packet, or empty if not applicable
*/
@@ -38,4 +51,12 @@ public interface PacketType extends Keyed {
*/
boolean isSupported();
+ /**
+ * Determines if processing this packet terminates the current protocol phase,
+ * potentially transitioning to a new phase. For example, a login success packet
+ * might terminate the LOGIN phase and transition to the CONFIGURATION phase.
+ *
+ * @return {@code true} if this packet ends the current protocol phase, {@code false} otherwise
+ */
+ boolean isTerminal();
}
diff --git a/src/main/java/dev/protocollib/api/packet/PacketTypes.java b/src/main/java/dev/protocollib/api/packet/PacketTypes.java
index 92418b6b8..703aaaec7 100644
--- a/src/main/java/dev/protocollib/api/packet/PacketTypes.java
+++ b/src/main/java/dev/protocollib/api/packet/PacketTypes.java
@@ -4,4 +4,9 @@ public class PacketTypes {
// TODO should contain all packet types as public static final fields
+ public static class Game {
+
+ public static final PacketType LEVEL_CHUNK = null;
+
+ }
}
From 30fe6465dbd65456f7f4afcf6090db3e62d4f209 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maurice=20Eisenbl=C3=A4tter?=
Date: Mon, 24 Mar 2025 22:30:53 +0100
Subject: [PATCH 5/6] feat(api): wip - add immutable packet listener
---
src/main/java/dev/protocollib/Example.java | 67 +++++++++++++++++--
.../java/dev/protocollib/api/ProtocolLib.java | 6 +-
.../api/listener/AsyncPacketListener.java | 4 +-
.../api/listener/ImmutablePacketListener.java | 12 ++++
.../ImmutablePacketListenerContext.java | 30 +++++++++
.../api/listener/PacketListenerBuilder.java | 27 +++++---
.../api/listener/SyncPacketListener.java | 4 +-
.../listener/SyncPacketListenerContext.java | 2 +-
.../api/packet/MutablePacketContainer.java | 26 +++++++
.../api/packet/PacketContainer.java | 9 +--
.../api/packet/PacketOperationBuilder.java | 4 +-
.../protocollib/api/reflect/Converter.java | 12 ++++
.../api/reflect/GenericAccessor.java | 31 +++++++++
.../api/reflect/GenericMutator.java | 46 +++++++++++++
.../api/reflect/MutableGenericAccessor.java | 12 ++++
15 files changed, 262 insertions(+), 30 deletions(-)
create mode 100644 src/main/java/dev/protocollib/api/listener/ImmutablePacketListener.java
create mode 100644 src/main/java/dev/protocollib/api/listener/ImmutablePacketListenerContext.java
create mode 100644 src/main/java/dev/protocollib/api/packet/MutablePacketContainer.java
create mode 100644 src/main/java/dev/protocollib/api/reflect/Converter.java
create mode 100644 src/main/java/dev/protocollib/api/reflect/GenericAccessor.java
create mode 100644 src/main/java/dev/protocollib/api/reflect/GenericMutator.java
create mode 100644 src/main/java/dev/protocollib/api/reflect/MutableGenericAccessor.java
diff --git a/src/main/java/dev/protocollib/Example.java b/src/main/java/dev/protocollib/Example.java
index 75f1e4e84..df840f650 100644
--- a/src/main/java/dev/protocollib/Example.java
+++ b/src/main/java/dev/protocollib/Example.java
@@ -1,11 +1,18 @@
package dev.protocollib;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
+
import dev.protocollib.api.ProtocolLib;
-import dev.protocollib.api.listener.*;
-import dev.protocollib.api.packet.*;
-import java.util.concurrent.*;
+import dev.protocollib.api.listener.PacketListenerBundleBehavior;
+import dev.protocollib.api.listener.PacketListenerPriority;
+import dev.protocollib.api.packet.MutablePacketContainer;
+import dev.protocollib.api.packet.PacketContainer;
+import dev.protocollib.api.packet.PacketTypes;
+import dev.protocollib.api.reflect.MutableGenericAccessor;
public class Example {
@@ -13,6 +20,56 @@ public class Example {
private static ProtocolLib protocolLib;
private static Plugin plugin;
+ public static class ParticleData {
+ public String s;
+ public int i;
+ }
+
+ public static class ParticlePacket {
+ public int duration;
+ public String name;
+ public ParticleData data;
+ }
+
+ static {
+ MutablePacketContainer packet = null;
+ Class> clazz = MutableGenericAccessor.class;
+
+ packet.accessor().update(a -> {
+ a.update(ParticleData.class, 0, b -> {
+
+ });
+ });
+
+ packet.accessor().getAccessor(ParticleData.class, 0).update(accessor -> {
+
+ });
+
+ packet.accessor().update(accessor -> {
+
+ accessor.setObject(clazz, 1, "");
+ accessor.set(Integer.class, 1, 1235);
+ accessor.set(String.class, 1, "world");
+
+ accessor.getAccessor(Object.class, 1).getAccessor(Object.class, 1).update(mutableAccessor -> {
+
+ });
+
+ accessor.update(Object.class, 1, mutableAccessor -> {
+ mutableAccessor.set(int.class, 1, -1);
+ });
+
+ accessor.update(ParticleData.class, 1, (pd) -> {
+ pd.i++;
+ return pd;
+ });
+
+ accessor.update(ParticleData.class, 1, (pd) -> {
+ pd.set(int.class, 1, pd.get(int.class, 1) + 1);
+ });
+ });
+ }
+
// ========================
// Packet Listeners
// ========================
@@ -41,7 +98,7 @@ static void registerListeners() {
// do processing here ...
// write changes to packet ...
- context.addTransmissionListener(chunk::markSent);
+ context.addAsyncTransmissionListener(chunk::markSent);
context.resumeProcessing();
});
@@ -58,7 +115,7 @@ static void registerListeners() {
// do heavy processing here ...
// write changes to packet ...
- context.addTransmissionListener(chunk::markSent);
+ context.addAsyncTransmissionListener(chunk::markSent);
context.resumeProcessing();
});
});
diff --git a/src/main/java/dev/protocollib/api/ProtocolLib.java b/src/main/java/dev/protocollib/api/ProtocolLib.java
index dda0bf1ef..2a86b11f6 100644
--- a/src/main/java/dev/protocollib/api/ProtocolLib.java
+++ b/src/main/java/dev/protocollib/api/ProtocolLib.java
@@ -5,7 +5,7 @@
import dev.protocollib.api.listener.PacketListenerBuilder;
import dev.protocollib.api.packet.BinaryPacket;
-import dev.protocollib.api.packet.PacketContainer;
+import dev.protocollib.api.packet.MutablePacketContainer;
import dev.protocollib.api.packet.PacketLike;
import dev.protocollib.api.packet.PacketType;
@@ -61,7 +61,7 @@ default void receivePacket(Player player, PacketLike packet) {
* Creates a new packet container for the given packet type.
*
* @param packetType the type of the packet to create
- * @return a new {@link PacketContainer} instance
+ * @return a new {@link MutablePacketContainer} instance
*/
- PacketContainer createPacket(PacketType packetType);
+ MutablePacketContainer createPacket(PacketType packetType);
}
diff --git a/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java b/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
index 1027a0ec1..324a7d811 100644
--- a/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
+++ b/src/main/java/dev/protocollib/api/listener/AsyncPacketListener.java
@@ -2,7 +2,7 @@
import org.jetbrains.annotations.NotNull;
-import dev.protocollib.api.packet.PacketContainer;
+import dev.protocollib.api.packet.MutablePacketContainer;
/**
* Functional interface for handling packets asynchronously.
@@ -29,6 +29,6 @@ public interface AsyncPacketListener {
* @param packet the packet to handle
* @param context the context providing additional information about the packet and connection
*/
- void handlePacket(@NotNull PacketContainer packet, @NotNull AsyncPacketListenerContext context);
+ void handlePacket(@NotNull MutablePacketContainer packet, @NotNull AsyncPacketListenerContext context);
}
diff --git a/src/main/java/dev/protocollib/api/listener/ImmutablePacketListener.java b/src/main/java/dev/protocollib/api/listener/ImmutablePacketListener.java
new file mode 100644
index 000000000..209443824
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/listener/ImmutablePacketListener.java
@@ -0,0 +1,12 @@
+package dev.protocollib.api.listener;
+
+import org.jetbrains.annotations.NotNull;
+
+import dev.protocollib.api.packet.PacketContainer;
+
+@FunctionalInterface
+public interface ImmutablePacketListener {
+
+ void handlePacket(@NotNull PacketContainer packet, @NotNull ImmutablePacketListenerContext context);
+
+}
diff --git a/src/main/java/dev/protocollib/api/listener/ImmutablePacketListenerContext.java b/src/main/java/dev/protocollib/api/listener/ImmutablePacketListenerContext.java
new file mode 100644
index 000000000..37354b718
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/listener/ImmutablePacketListenerContext.java
@@ -0,0 +1,30 @@
+package dev.protocollib.api.listener;
+
+import org.jetbrains.annotations.NotNull;
+
+import dev.protocollib.api.Connection;
+
+public interface ImmutablePacketListenerContext {
+
+ /**
+ * Retrieves the connection associated with the packet.
+ *
+ * @return the connection handling the packet
+ */
+ @NotNull
+ Connection connection();
+
+ /**
+ * Checks if the packet handling has been cancelled.
+ *
+ * @return true if the packet is cancelled, false otherwise
+ */
+ boolean isCancelledVolatile();
+
+ /**
+ * Adds a listener to be invoked after the packet is sent or received.
+ *
+ * @param listener the transmission listener to invoke
+ */
+ void addAsyncTransmissionListener(@NotNull PacketTransmissionListener listener);// TODO async via netty
+}
diff --git a/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java b/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
index f12bec871..8319717c3 100644
--- a/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
+++ b/src/main/java/dev/protocollib/api/listener/PacketListenerBuilder.java
@@ -44,15 +44,6 @@ public interface WithType {
@Contract("_ -> this")
PacketListenerBuilder.WithType priority(@NotNull PacketListenerPriority priority);
- /**
- * Allows the listener to modify packets. By default, listeners are read-only and
- * cannot modify packets.
- *
- * @return the same builder for further configuration
- */
- @Contract("_ -> this")
- PacketListenerBuilder.WithType mutable();
-
/**
* Configures the bundle behavior for the listener, determining how packets in bundles are handled.
*
@@ -72,6 +63,24 @@ public interface WithType {
@Contract("_ -> this")
PacketListenerBuilder.WithType includeCanceledPackets();
+ /**
+ * Allows the listener to modify packets. By default, listeners are read-only and
+ * cannot modify packets.
+ *
+ * @return the same builder for further configuration
+ */
+ @NotNull
+ PacketListenerBuilder.Mutable mutable();
+
+ @NotNull
+ PacketListenerRegistration registerSync(@NotNull ImmutablePacketListener listener);
+
+ @NotNull
+ PacketListenerRegistration registerAsync(@NotNull ImmutablePacketListener listener);
+ }
+
+ public interface Mutable {
+
/**
* Registers the packet listener to operate synchronously. The listener
* will always get called on the main game thread.
diff --git a/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java b/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
index 81e0caf77..1ee833cdf 100644
--- a/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
+++ b/src/main/java/dev/protocollib/api/listener/SyncPacketListener.java
@@ -2,7 +2,7 @@
import org.jetbrains.annotations.NotNull;
-import dev.protocollib.api.packet.PacketContainer;
+import dev.protocollib.api.packet.MutablePacketContainer;
/**
* Functional interface for handling packets synchronously.
@@ -16,6 +16,6 @@ public interface SyncPacketListener {
* @param packet the packet to handle
* @param context the context providing additional information about the packet and functions
*/
- void handlePacket(@NotNull PacketContainer packet, @NotNull SyncPacketListenerContext context);
+ void handlePacket(@NotNull MutablePacketContainer packet, @NotNull SyncPacketListenerContext context);
}
diff --git a/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java b/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
index 7439d13d1..bd4dab6e6 100644
--- a/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
+++ b/src/main/java/dev/protocollib/api/listener/SyncPacketListenerContext.java
@@ -37,5 +37,5 @@ public interface SyncPacketListenerContext {
*
* @param listener the transmission listener to invoke
*/
- void addTransmissionListener(@NotNull PacketTransmissionListener listener);
+ void addAsyncTransmissionListener(@NotNull PacketTransmissionListener listener);// TODO async via netty
}
diff --git a/src/main/java/dev/protocollib/api/packet/MutablePacketContainer.java b/src/main/java/dev/protocollib/api/packet/MutablePacketContainer.java
new file mode 100644
index 000000000..17df5a279
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/packet/MutablePacketContainer.java
@@ -0,0 +1,26 @@
+package dev.protocollib.api.packet;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import dev.protocollib.api.reflect.MutableGenericAccessor;
+
+public interface MutablePacketContainer extends PacketContainer {
+
+ /**
+ * Retrieves the raw packet object.
+ *
+ * @return the packet object
+ */
+ @NotNull
+ Object packet();
+
+ @NotNull
+ MutableGenericAccessor accessor();
+
+ @Nullable
+ MutablePacketContainer bundle();
+
+ @Nullable
+ MutablePacketContainer clone();
+}
diff --git a/src/main/java/dev/protocollib/api/packet/PacketContainer.java b/src/main/java/dev/protocollib/api/packet/PacketContainer.java
index b7f7f6626..c39c476d5 100644
--- a/src/main/java/dev/protocollib/api/packet/PacketContainer.java
+++ b/src/main/java/dev/protocollib/api/packet/PacketContainer.java
@@ -3,6 +3,8 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import dev.protocollib.api.reflect.GenericAccessor;
+
/**
* Representing a container for a packet.
*/
@@ -16,13 +18,8 @@ public non-sealed interface PacketContainer extends PacketLike {
@NotNull
PacketType packetType();
- /**
- * Retrieves the raw packet object.
- *
- * @return the packet object
- */
@NotNull
- Object packet();
+ GenericAccessor accessor();
/**
* Retrieves the packet bundle that this packet is part of, if any.
diff --git a/src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java b/src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java
index 50fdb123b..27cbc7dd6 100644
--- a/src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java
+++ b/src/main/java/dev/protocollib/api/packet/PacketOperationBuilder.java
@@ -36,14 +36,14 @@ public interface PacketOperationBuilder {
/**
* Sends a packet to the client.
*
- * @param packet the {@link PacketContainer} to send
+ * @param packet the packet to send
*/
void send(@NotNull PacketLike packet);
/**
* Receives a packet as if the client had sent it.
*
- * @param packet the {@link PacketContainer} to receive
+ * @param packet the packet to receive
*/
void receive(@NotNull PacketLike packet);
}
diff --git a/src/main/java/dev/protocollib/api/reflect/Converter.java b/src/main/java/dev/protocollib/api/reflect/Converter.java
new file mode 100644
index 000000000..0a71ae0cb
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/reflect/Converter.java
@@ -0,0 +1,12 @@
+package dev.protocollib.api.reflect;
+
+public interface Converter {
+
+ Object getGeneric(T specific);
+
+ Class> getGenericType();
+
+ T getSpecific(Object generic);
+
+ Class getSpecificType();
+}
diff --git a/src/main/java/dev/protocollib/api/reflect/GenericAccessor.java b/src/main/java/dev/protocollib/api/reflect/GenericAccessor.java
new file mode 100644
index 000000000..b573bf261
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/reflect/GenericAccessor.java
@@ -0,0 +1,31 @@
+package dev.protocollib.api.reflect;
+
+public interface GenericAccessor {
+
+ // ====================================================
+ // Value Retrieval Optional
+ // ====================================================
+
+ GenericAccessor getAccessor(Class> type, int ordinal);
+ GenericAccessor getAccessorOrThrow(Class> type, int ordinal);
+
+ Object getObject(Class> type, int ordinal);
+ Object getObjectOrThrow(Class> type, int ordinal);
+
+ T get(Class type, int ordinal);
+ T getOrThrow(Class type, int ordinal);
+
+ T get(Converter converter, int ordinal);
+ T getOrThrow(Converter converter, int ordinal);
+
+ // ====================================================
+ // Metadata
+ // ====================================================
+
+ boolean isSupported(Class> type, int ordinal);
+ boolean isSupported(Converter> type, int ordinal);
+
+ int count(Class> type);
+ int count(Converter> type);
+
+}
diff --git a/src/main/java/dev/protocollib/api/reflect/GenericMutator.java b/src/main/java/dev/protocollib/api/reflect/GenericMutator.java
new file mode 100644
index 000000000..4c9cc9bc9
--- /dev/null
+++ b/src/main/java/dev/protocollib/api/reflect/GenericMutator.java
@@ -0,0 +1,46 @@
+package dev.protocollib.api.reflect;
+
+import java.util.function.Consumer;
+import java.util.function.UnaryOperator;
+
+public interface GenericMutator extends GenericAccessor {
+
+ MutableGenericAccessor getAccessor(Class> type, int ordinal);
+ MutableGenericAccessor getAccessorOrThrow(Class> type, int ordinal);
+
+ // ====================================================
+ // Value Modification
+ // ====================================================
+
+ Object updateObject(Class> type, int ordinal, UnaryOperator