feat(api): add basic packet processing interfaces

This commit is contained in:
Maurice Eisenblätter 2024-10-21 23:47:44 +02:00
parent 8d2efb30df
commit ba5f278419
No known key found for this signature in database
GPG Key ID: 2E553EFBAE92FB3A
21 changed files with 414 additions and 66 deletions

View File

@ -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();
}

View File

@ -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> 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);
}

View File

@ -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();
}

View File

@ -1,7 +0,0 @@
package dev.protocollib.api;
public enum PacketDirection {
SERVERBOUND, CLIENTBOUND;
}

View File

@ -1,11 +0,0 @@
package dev.protocollib.api;
import org.bukkit.event.Cancellable;
public interface PacketEvent extends Cancellable {
Connection connection();
PacketContainer packet();
}

View File

@ -1,8 +0,0 @@
package dev.protocollib.api;
@FunctionalInterface
public interface PacketListener {
void handlePacket(PacketEvent event);
}

View File

@ -1,16 +0,0 @@
package dev.protocollib.api;
import java.util.Collection;
public interface PacketListenerBuilder {
PacketListenerBuilder types(PacketType...packetTypes);
PacketListenerBuilder types(Collection<PacketType> packetTypes);
PacketListenerBuilder priority(PacketListenerPriority priority);
PacketListenerBuilder listener(PacketListener listener);
PacketListenerRegistration register();
}

View File

@ -1,7 +0,0 @@
package dev.protocollib.api;
public enum PacketListenerPriority {
LOWEST, LOW, NORMAL, HIGH, HIGHEST, MONITOR;
}

View File

@ -1,6 +0,0 @@
package dev.protocollib.api;
public interface PacketListenerRegistration {
void unregister();
}

View File

@ -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.
*
* <p>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.</p>
*/
public interface PacketType extends Keyed {
/**
* 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.
*
* <p>Not all packet types have an associated class. If there is no class,
* an empty {@link Optional} is returned.</p>
*
* @return an {@link Optional} containing the class of the packet, or empty if not applicable
*/
Optional<Class<?>> packetClass();
/**
* 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();
boolean isDeprecated();
}

View File

@ -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;
}

View File

@ -3,10 +3,43 @@ package dev.protocollib.api;
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);
}

View File

@ -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;

View File

@ -0,0 +1,32 @@
package dev.protocollib.api.listener;
import dev.protocollib.api.PacketContainer;
/**
* Functional interface for handling packets asynchronously.
*
* <p>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.
* </p>
*/
@FunctionalInterface
public interface AsyncPacketListener {
/**
* Handles a packet that was sent or received, asynchronously.
*
* <p>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.</p>
*
* @param packet the packet to handle
* @param context the context providing additional information about the packet and connection
*/
void handlePacket(PacketContainer packet, AsyncPacketListenerContext context);
}

View File

@ -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);
}

View File

@ -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<PacketType> 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);
}
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);
}