stable configuration state join

This commit is contained in:
mworzala 2023-09-30 13:17:44 -04:00 committed by Matt Worzala
parent 78cb62fa72
commit 465af0e051
173 changed files with 1131 additions and 760 deletions

View File

@ -13,7 +13,7 @@ import net.minestom.server.listener.manager.PacketListenerManager;
import net.minestom.server.monitoring.BenchmarkManager;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.PacketProcessor;
import net.minestom.server.network.packet.server.play.PluginMessagePacket;
import net.minestom.server.network.packet.server.common.PluginMessagePacket;
import net.minestom.server.network.packet.server.play.ServerDifficultyPacket;
import net.minestom.server.network.socket.Server;
import net.minestom.server.recipe.RecipeManager;
@ -44,8 +44,8 @@ public final class MinecraftServer {
public static final ComponentLogger LOGGER = ComponentLogger.logger(MinecraftServer.class);
public static final String VERSION_NAME = "1.20.1";
public static final int PROTOCOL_VERSION = 763;
public static final String VERSION_NAME = "1.20.2";
public static final int PROTOCOL_VERSION = 764;
// Threads
public static final String THREAD_NAME_BENCHMARK = "Ms-Benchmark";

View File

@ -46,8 +46,8 @@ final class ServerProcessImpl implements ServerProcess {
private final ExceptionManager exception;
private final ConnectionManager connection;
private final PacketProcessor packetProcessor;
private final PacketListenerManager packetListener;
private final PacketProcessor packetProcessor;
private final InstanceManager instance;
private final BlockManager block;
private final CommandManager command;
@ -72,8 +72,8 @@ final class ServerProcessImpl implements ServerProcess {
public ServerProcessImpl() throws IOException {
this.exception = new ExceptionManager();
this.connection = new ConnectionManager();
this.packetProcessor = new PacketProcessor();
this.packetListener = new PacketListenerManager(this);
this.packetListener = new PacketListenerManager();
this.packetProcessor = new PacketProcessor(packetListener);
this.instance = new InstanceManager();
this.block = new BlockManager();
this.command = new CommandManager();

View File

@ -59,6 +59,7 @@ import net.minestom.server.network.PlayerProvider;
import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.server.SendablePacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.common.*;
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
import net.minestom.server.network.packet.server.play.*;
import net.minestom.server.network.packet.server.play.data.DeathLocation;
@ -246,6 +247,9 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
.withDynamic(Identity.NAME, this::getUsername)
.withDynamic(Identity.DISPLAY_NAME, this::getDisplayName)
.build();
// When in configuration state no metadata updates can be sent.
metadata.setNotifyAboutChanges(false);
}
/**
@ -1947,7 +1951,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
}
final PacketListenerManager manager = MinecraftServer.getPacketListenerManager();
// This method is NOT thread-safe
this.packets.drain(packet -> manager.processClientPacket(packet, this), PACKET_PER_TICK);
this.packets.drain(packet -> manager.processClientPacket(playerConnection.getConnectionState(), packet, playerConnection), PACKET_PER_TICK);
}
/**
@ -1957,7 +1961,9 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
*/
public void refreshLatency(int latency) {
this.latency = latency;
PacketUtils.broadcastPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LATENCY, infoEntry()));
if (getPlayerConnection().getConnectionState() == ConnectionState.PLAY) {
PacketUtils.broadcastPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LATENCY, infoEntry()));
}
}
public void refreshOnGround(boolean onGround) {
@ -2368,10 +2374,11 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
this.allowServerListings = allowServerListings;
// TODO: Use the metadata object here
metadata.setNotifyAboutChanges(false);
boolean isInPlayState = getPlayerConnection().getConnectionState() == ConnectionState.PLAY;
if (isInPlayState) metadata.setNotifyAboutChanges(false);
metadata.setIndex((byte) 17, Metadata.Byte(displayedSkinParts));
metadata.setIndex((byte) 18, Metadata.Byte((byte) (this.mainHand == MainHand.RIGHT ? 1 : 0)));
metadata.setNotifyAboutChanges(true);
if (isInPlayState) metadata.setNotifyAboutChanges(true);
}
}

View File

@ -67,7 +67,7 @@ public class FakePlayer extends Player implements NavigableEntity {
}).build();
MinecraftServer.getGlobalEventHandler().addListener(spawnListener);
}
CONNECTION_MANAGER.startPlayState(this, option.isRegistered());
CONNECTION_MANAGER.startConfigurationState(this, option.isRegistered());
}
/**

View File

@ -9,10 +9,12 @@ import net.minestom.server.inventory.Inventory;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.client.common.ClientKeepAlivePacket;
import net.minestom.server.network.packet.client.common.ClientPluginMessagePacket;
import net.minestom.server.network.packet.client.play.*;
import net.minestom.server.network.packet.server.SendablePacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.play.KeepAlivePacket;
import net.minestom.server.network.packet.server.common.KeepAlivePacket;
import net.minestom.server.network.packet.server.play.PlayerPositionAndLookPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.MathUtils;

View File

@ -2,10 +2,11 @@ package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.trait.PlayerInstanceEvent;
import net.minestom.server.network.packet.client.common.ClientPluginMessagePacket;
import org.jetbrains.annotations.NotNull;
/**
* Called when a player send {@link net.minestom.server.network.packet.client.play.ClientPluginMessagePacket}.
* Called when a player send {@link ClientPluginMessagePacket}.
*/
public class PlayerPluginMessageEvent implements PlayerInstanceEvent {

View File

@ -1,7 +1,7 @@
package net.minestom.server.event.player;
import net.minestom.server.event.Event;
import net.minestom.server.network.packet.server.play.TagsPacket;
import net.minestom.server.network.packet.server.common.TagsPacket;
import org.jetbrains.annotations.NotNull;
@Deprecated

View File

@ -78,7 +78,6 @@ public class AnvilLoader implements IChunkLoader {
@Override
public @NotNull CompletableFuture<@Nullable Chunk> loadChunk(@NotNull Instance instance, int chunkX, int chunkZ) {
LOGGER.debug("Attempt loading at {} {}", chunkX, chunkZ);
if (!Files.exists(path)) {
// No world folder
return CompletableFuture.completedFuture(null);

View File

@ -10,6 +10,7 @@ import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.instance.light.Light;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.server.CachedPacket;
import net.minestom.server.network.packet.server.play.data.LightData;
import net.minestom.server.timer.ExecutionType;
@ -281,7 +282,7 @@ public class LightingChunk extends DynamicChunk {
// Load all the lighting
for (LightingChunk f : copy) {
if (f.isLoaded()) {
f.lightCache.body();
f.lightCache.body(ConnectionState.PLAY);
}
}

View File

@ -9,7 +9,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class StatusListener {
public class PlayStatusListener {
public static void listener(ClientStatusPacket packet, Player player) {
switch (packet.action()) {

View File

@ -9,8 +9,8 @@ import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.packet.client.play.ClientClickWindowPacket;
import net.minestom.server.network.packet.client.play.ClientCloseWindowPacket;
import net.minestom.server.network.packet.client.play.ClientPongPacket;
import net.minestom.server.network.packet.server.play.PingPacket;
import net.minestom.server.network.packet.client.common.ClientPongPacket;
import net.minestom.server.network.packet.server.common.PingPacket;
import net.minestom.server.network.packet.server.play.SetSlotPacket;
public class WindowListener {

View File

@ -1,9 +1,9 @@
package net.minestom.server.listener;
package net.minestom.server.listener.common;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.play.ClientKeepAlivePacket;
import net.minestom.server.network.packet.client.common.ClientKeepAlivePacket;
public final class KeepAliveListener {
private static final Component KICK_MESSAGE = Component.text("Bad Keep Alive packet", NamedTextColor.RED);

View File

@ -1,9 +1,9 @@
package net.minestom.server.listener;
package net.minestom.server.listener.common;
import net.minestom.server.entity.Player;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.PlayerPluginMessageEvent;
import net.minestom.server.network.packet.client.play.ClientPluginMessagePacket;
import net.minestom.server.network.packet.client.common.ClientPluginMessagePacket;
public class PluginMessageListener {

View File

@ -1,9 +1,9 @@
package net.minestom.server.listener;
package net.minestom.server.listener.common;
import net.minestom.server.entity.Player;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.PlayerResourcePackStatusEvent;
import net.minestom.server.network.packet.client.play.ClientResourcePackStatusPacket;
import net.minestom.server.network.packet.client.common.ClientResourcePackStatusPacket;
public class ResourcePackListener {

View File

@ -1,9 +1,9 @@
package net.minestom.server.listener;
package net.minestom.server.listener.common;
import net.minestom.server.entity.Player;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.PlayerSettingsChangeEvent;
import net.minestom.server.network.packet.client.play.ClientSettingsPacket;
import net.minestom.server.network.packet.client.common.ClientSettingsPacket;
public final class SettingsListener {
public static void listener(ClientSettingsPacket packet, Player player) {

View File

@ -1,13 +1,30 @@
package net.minestom.server.listener.manager;
import net.minestom.server.MinecraftServer;
import net.minestom.server.ServerProcess;
import net.minestom.server.entity.Player;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.PlayerPacketEvent;
import net.minestom.server.listener.*;
import net.minestom.server.listener.common.KeepAliveListener;
import net.minestom.server.listener.common.PluginMessageListener;
import net.minestom.server.listener.common.ResourcePackListener;
import net.minestom.server.listener.common.SettingsListener;
import net.minestom.server.listener.preplay.ConfigurationListener;
import net.minestom.server.listener.preplay.HandshakeListener;
import net.minestom.server.listener.preplay.LoginListener;
import net.minestom.server.listener.preplay.StatusListener;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.client.common.*;
import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket;
import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket;
import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket;
import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket;
import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket;
import net.minestom.server.network.packet.client.login.ClientLoginStartPacket;
import net.minestom.server.network.packet.client.play.*;
import net.minestom.server.network.packet.client.status.PingPacket;
import net.minestom.server.network.packet.client.status.StatusRequestPacket;
import net.minestom.server.network.player.PlayerConnection;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -18,81 +35,113 @@ import java.util.concurrent.ConcurrentHashMap;
public final class PacketListenerManager {
private final static Logger LOGGER = LoggerFactory.getLogger(PacketListenerManager.class);
private final ServerProcess serverProcess;
private final Map<Class<? extends ClientPacket>, PacketListenerConsumer> listeners = new ConcurrentHashMap<>();
private final Map<Class<? extends ClientPacket>, PacketPrePlayListenerConsumer>[] listeners = new Map[ConnectionState.values().length];
public PacketListenerManager(ServerProcess serverProcess) {
this.serverProcess = serverProcess;
public PacketListenerManager() {
for (int i = 0; i < listeners.length; i++) {
listeners[i] = new ConcurrentHashMap<>();
}
setListener(ClientKeepAlivePacket.class, KeepAliveListener::listener);
setListener(ClientCommandChatPacket.class, ChatMessageListener::commandChatListener);
setListener(ClientChatMessagePacket.class, ChatMessageListener::chatMessageListener);
setListener(ClientClickWindowPacket.class, WindowListener::clickWindowListener);
setListener(ClientCloseWindowPacket.class, WindowListener::closeWindowListener);
setListener(ClientPongPacket.class, WindowListener::pong);
setListener(ClientEntityActionPacket.class, EntityActionListener::listener);
setListener(ClientHeldItemChangePacket.class, PlayerHeldListener::heldListener);
setListener(ClientPlayerBlockPlacementPacket.class, BlockPlacementListener::listener);
setListener(ClientSteerVehiclePacket.class, PlayerVehicleListener::steerVehicleListener);
setListener(ClientVehicleMovePacket.class, PlayerVehicleListener::vehicleMoveListener);
setListener(ClientSteerBoatPacket.class, PlayerVehicleListener::boatSteerListener);
setListener(ClientPlayerPacket.class, PlayerPositionListener::playerPacketListener);
setListener(ClientPlayerRotationPacket.class, PlayerPositionListener::playerLookListener);
setListener(ClientPlayerPositionPacket.class, PlayerPositionListener::playerPositionListener);
setListener(ClientPlayerPositionAndRotationPacket.class, PlayerPositionListener::playerPositionAndLookListener);
setListener(ClientTeleportConfirmPacket.class, PlayerPositionListener::teleportConfirmListener);
setListener(ClientPlayerDiggingPacket.class, PlayerDiggingListener::playerDiggingListener);
setListener(ClientAnimationPacket.class, AnimationListener::animationListener);
setListener(ClientInteractEntityPacket.class, UseEntityListener::useEntityListener);
setListener(ClientUseItemPacket.class, UseItemListener::useItemListener);
setListener(ClientStatusPacket.class, StatusListener::listener);
setListener(ClientSettingsPacket.class, SettingsListener::listener);
setListener(ClientCreativeInventoryActionPacket.class, CreativeInventoryActionListener::listener);
setListener(ClientCraftRecipeRequest.class, RecipeListener::listener);
setListener(ClientTabCompletePacket.class, TabCompleteListener::listener);
setListener(ClientPluginMessagePacket.class, PluginMessageListener::listener);
setListener(ClientPlayerAbilitiesPacket.class, AbilitiesListener::listener);
setListener(ClientResourcePackStatusPacket.class, ResourcePackListener::listener);
setListener(ClientAdvancementTabPacket.class, AdvancementTabListener::listener);
setListener(ClientSpectatePacket.class, SpectateListener::listener);
setListener(ClientEditBookPacket.class, BookListener::listener);
setListener(ConnectionState.HANDSHAKE, ClientHandshakePacket.class, HandshakeListener::listener);
setListener(ConnectionState.STATUS, StatusRequestPacket.class, StatusListener::requestListener);
setListener(ConnectionState.STATUS, PingPacket.class, StatusListener::pingListener);
setListener(ConnectionState.LOGIN, ClientLoginStartPacket.class, LoginListener::loginStartListener);
setListener(ConnectionState.LOGIN, ClientEncryptionResponsePacket.class, LoginListener::loginEncryptionResponseListener);
setListener(ConnectionState.LOGIN, ClientLoginPluginResponsePacket.class, LoginListener::loginPluginResponseListener);
setListener(ConnectionState.LOGIN, ClientLoginAcknowledgedPacket.class, LoginListener::loginAckListener);
setConfigurationListener(ClientSettingsPacket.class, SettingsListener::listener);
setConfigurationListener(ClientPluginMessagePacket.class, PluginMessageListener::listener);
setConfigurationListener(ClientFinishConfigurationPacket.class, ConfigurationListener::finishListener);
setConfigurationListener(ClientKeepAlivePacket.class, KeepAliveListener::listener);
setConfigurationListener(ClientPongPacket.class, (packet, player) -> {/* empty */});
setConfigurationListener(ClientResourcePackStatusPacket.class, ResourcePackListener::listener);
setPlayListener(ClientKeepAlivePacket.class, KeepAliveListener::listener);
setPlayListener(ClientCommandChatPacket.class, ChatMessageListener::commandChatListener);
setPlayListener(ClientChatMessagePacket.class, ChatMessageListener::chatMessageListener);
setPlayListener(ClientClickWindowPacket.class, WindowListener::clickWindowListener);
setPlayListener(ClientCloseWindowPacket.class, WindowListener::closeWindowListener);
setPlayListener(ClientPongPacket.class, WindowListener::pong);
setPlayListener(ClientEntityActionPacket.class, EntityActionListener::listener);
setPlayListener(ClientHeldItemChangePacket.class, PlayerHeldListener::heldListener);
setPlayListener(ClientPlayerBlockPlacementPacket.class, BlockPlacementListener::listener);
setPlayListener(ClientSteerVehiclePacket.class, PlayerVehicleListener::steerVehicleListener);
setPlayListener(ClientVehicleMovePacket.class, PlayerVehicleListener::vehicleMoveListener);
setPlayListener(ClientSteerBoatPacket.class, PlayerVehicleListener::boatSteerListener);
setPlayListener(ClientPlayerPacket.class, PlayerPositionListener::playerPacketListener);
setPlayListener(ClientPlayerRotationPacket.class, PlayerPositionListener::playerLookListener);
setPlayListener(ClientPlayerPositionPacket.class, PlayerPositionListener::playerPositionListener);
setPlayListener(ClientPlayerPositionAndRotationPacket.class, PlayerPositionListener::playerPositionAndLookListener);
setPlayListener(ClientTeleportConfirmPacket.class, PlayerPositionListener::teleportConfirmListener);
setPlayListener(ClientPlayerDiggingPacket.class, PlayerDiggingListener::playerDiggingListener);
setPlayListener(ClientAnimationPacket.class, AnimationListener::animationListener);
setPlayListener(ClientInteractEntityPacket.class, UseEntityListener::useEntityListener);
setPlayListener(ClientUseItemPacket.class, UseItemListener::useItemListener);
setPlayListener(ClientStatusPacket.class, PlayStatusListener::listener);
setPlayListener(ClientSettingsPacket.class, SettingsListener::listener);
setPlayListener(ClientCreativeInventoryActionPacket.class, CreativeInventoryActionListener::listener);
setPlayListener(ClientCraftRecipeRequest.class, RecipeListener::listener);
setPlayListener(ClientTabCompletePacket.class, TabCompleteListener::listener);
setPlayListener(ClientPluginMessagePacket.class, PluginMessageListener::listener);
setPlayListener(ClientPlayerAbilitiesPacket.class, AbilitiesListener::listener);
setPlayListener(ClientResourcePackStatusPacket.class, ResourcePackListener::listener);
setPlayListener(ClientAdvancementTabPacket.class, AdvancementTabListener::listener);
setPlayListener(ClientSpectatePacket.class, SpectateListener::listener);
setPlayListener(ClientEditBookPacket.class, BookListener::listener);
}
/**
* Processes a packet by getting its {@link PacketListenerConsumer} and calling all the packet listeners.
* Processes a packet by getting its {@link PacketPlayListenerConsumer} and calling all the packet listeners.
*
* @param packet the received packet
* @param player the player who sent the packet
* @param <T> the packet type
*/
public <T extends ClientPacket> void processClientPacket(@NotNull T packet, @NotNull Player player) {
public <T extends ClientPacket> void processClientPacket(@NotNull ConnectionState state, @NotNull T packet, @NotNull PlayerConnection connection) {
final Class clazz = packet.getClass();
PacketListenerConsumer<T> packetListenerConsumer = listeners.get(clazz);
PacketPrePlayListenerConsumer<T> packetListenerConsumer = listeners[state.ordinal()].get(clazz);
// Listener can be null if none has been set before, call PacketConsumer anyway
if (packetListenerConsumer == null) {
LOGGER.warn("Packet " + clazz + " does not have any default listener! (The issue comes from Minestom)");
}
// Event
PlayerPacketEvent playerPacketEvent = new PlayerPacketEvent(player, packet);
EventDispatcher.call(playerPacketEvent);
if (playerPacketEvent.isCancelled()) {
return;
}
// Finally execute the listener
if (packetListenerConsumer != null) {
try {
packetListenerConsumer.accept(packet, player);
} catch (Exception e) {
// Packet is likely invalid
MinecraftServer.getExceptionManager().handleException(e);
// Event
if (state == ConnectionState.PLAY) {
PlayerPacketEvent playerPacketEvent = new PlayerPacketEvent(connection.getPlayer(), packet);
EventDispatcher.call(playerPacketEvent);
if (playerPacketEvent.isCancelled()) {
return;
}
}
// Finally execute the listener
try {
packetListenerConsumer.accept(packet, connection);
} catch (Exception e) {
// Packet is likely invalid
MinecraftServer.getExceptionManager().handleException(e);
}
}
/**
* Sets the listener of a packet.
* <p>
* WARNING: this will overwrite the default minestom listener, this is not reversible.
*
* @param state the state of the packet
* @param packetClass the class of the packet
* @param consumer the new packet's listener
* @param <T> the type of the packet
*/
public <T extends ClientPacket> void setListener(@NotNull ConnectionState state, @NotNull Class<T> packetClass, @NotNull PacketPrePlayListenerConsumer<T> consumer) {
this.listeners[state.ordinal()].put(packetClass, consumer);
}
/**
@ -104,8 +153,26 @@ public final class PacketListenerManager {
* @param consumer the new packet's listener
* @param <T> the type of the packet
*/
public <T extends ClientPacket> void setListener(@NotNull Class<T> packetClass, @NotNull PacketListenerConsumer<T> consumer) {
this.listeners.put(packetClass, consumer);
public <T extends ClientPacket> void setPlayListener(@NotNull Class<T> packetClass, @NotNull PacketPlayListenerConsumer<T> consumer) {
setListener(ConnectionState.PLAY, packetClass, (packet, playerConnection) -> consumer.accept(packet, playerConnection.getPlayer()));
}
public <T extends ClientPacket> void setConfigurationListener(@NotNull Class<T> packetClass, @NotNull PacketPlayListenerConsumer<T> consumer) {
setListener(ConnectionState.CONFIGURATION, packetClass, (packet, playerConnection) -> consumer.accept(packet, playerConnection.getPlayer()));
}
/**
* Sets the listener of a packet.
* <p>
* WARNING: this will overwrite the default minestom listener, this is not reversible.
*
* @param packetClass the class of the packet
* @param consumer the new packet's listener
* @param <T> the type of the packet
*/
@Deprecated
public <T extends ClientPacket> void setListener(@NotNull Class<T> packetClass, @NotNull PacketPlayListenerConsumer<T> consumer) {
setPlayListener(packetClass, consumer);
}
}

View File

@ -4,11 +4,11 @@ import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.ClientPacket;
/**
* Small convenient interface to use method references with {@link PacketListenerManager#setListener(Class, PacketListenerConsumer)}.
* Small convenient interface to use method references with {@link PacketListenerManager#setListener(Class, PacketPlayListenerConsumer)}.
*
* @param <T> the packet type
*/
@FunctionalInterface
public interface PacketListenerConsumer<T extends ClientPacket> {
public interface PacketPlayListenerConsumer<T extends ClientPacket> {
void accept(T packet, Player player);
}

View File

@ -0,0 +1,16 @@
package net.minestom.server.listener.manager;
import net.minestom.server.entity.Player;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.player.PlayerConnection;
/**
* Small convenient interface to use method references with {@link PacketListenerManager#setListener(ConnectionState, Class, PacketPrePlayListenerConsumer)}.
*
* @param <T> the packet type
*/
@FunctionalInterface
public interface PacketPrePlayListenerConsumer<T extends ClientPacket> {
void accept(T packet, PlayerConnection connection);
}

View File

@ -0,0 +1,13 @@
package net.minestom.server.listener.preplay;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket;
import org.jetbrains.annotations.NotNull;
public final class ConfigurationListener {
public static void finishListener(@NotNull ClientFinishConfigurationPacket packet, @NotNull Player player) {
//todo move to play state
System.out.println("Finished configuration for " + player.getUsername() );
}
}

View File

@ -1,4 +1,4 @@
package net.minestom.server.network.packet.client.handshake;
package net.minestom.server.listener.preplay;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@ -9,8 +9,7 @@ import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.extras.bungee.BungeeCordProxy;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket;
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
import net.minestom.server.network.player.GameProfile;
import net.minestom.server.network.player.PlayerConnection;
@ -24,12 +23,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static net.minestom.server.network.NetworkBuffer.*;
public final class HandshakeListener {
public record HandshakePacket(int protocolVersion, @NotNull String serverAddress,
int serverPort, int nextState) implements ClientPreplayPacket {
private final static Logger LOGGER = LoggerFactory.getLogger(HandshakePacket.class);
private final static Logger LOGGER = LoggerFactory.getLogger(HandshakeListener.class);
/**
* Text sent if a player tries to connect with an invalid version of the client
@ -41,34 +37,10 @@ public record HandshakePacket(int protocolVersion, @NotNull String serverAddress
*/
private static final Component INVALID_BUNGEE_FORWARDING = Component.text("Invalid connection, please connect through the BungeeCord proxy. If you believe this is an error, contact a server administrator.", NamedTextColor.RED);
public HandshakePacket {
if (serverAddress.length() > getMaxHandshakeLength()) {
throw new IllegalArgumentException("Server address too long: " + serverAddress.length());
}
}
public HandshakePacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), reader.read(STRING),
reader.read(UNSIGNED_SHORT), reader.read(VAR_INT));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(VAR_INT, protocolVersion);
int maxLength = getMaxHandshakeLength();
if (serverAddress.length() > maxLength) {
throw new IllegalArgumentException("serverAddress is " + serverAddress.length() + " characters long, maximum allowed is " + maxLength);
}
writer.write(STRING, serverAddress);
writer.write(UNSIGNED_SHORT, serverPort);
writer.write(VAR_INT, nextState);
}
@Override
public void process(@NotNull PlayerConnection connection) {
String address = serverAddress;
public static void listener(@NotNull ClientHandshakePacket packet, @NotNull PlayerConnection connection) {
String address = packet.serverAddress();
// Bungee support (IP forwarding)
if (BungeeCordProxy.isEnabled() && connection instanceof PlayerSocketConnection socketConnection && nextState == 2) {
if (BungeeCordProxy.isEnabled() && connection instanceof PlayerSocketConnection socketConnection && packet.nextState() == 2) {
final String[] split = address.split("\00");
if (split.length == 3 || split.length == 4) {
@ -135,13 +107,13 @@ public record HandshakePacket(int protocolVersion, @NotNull String serverAddress
if (connection instanceof PlayerSocketConnection) {
// Give to the connection the server info that the client used
((PlayerSocketConnection) connection).refreshServerInformation(address, serverPort, protocolVersion);
((PlayerSocketConnection) connection).refreshServerInformation(address, packet.serverPort(), packet.protocolVersion());
}
switch (nextState) {
switch (packet.nextState()) {
case 1 -> connection.setConnectionState(ConnectionState.STATUS);
case 2 -> {
if (protocolVersion == MinecraftServer.PROTOCOL_VERSION) {
if (packet.protocolVersion() == MinecraftServer.PROTOCOL_VERSION) {
connection.setConnectionState(ConnectionState.LOGIN);
} else {
// Incorrect client version
@ -154,17 +126,12 @@ public record HandshakePacket(int protocolVersion, @NotNull String serverAddress
}
}
private static int getMaxHandshakeLength() {
// BungeeGuard limits handshake length to 2500 characters, while vanilla limits it to 255
return BungeeCordProxy.isEnabled() ? (BungeeCordProxy.isBungeeGuardEnabled() ? 2500 : Short.MAX_VALUE) : 255;
}
private void disconnect(@NotNull PlayerConnection connection, @NotNull Component reason) {
private static void disconnect(@NotNull PlayerConnection connection, @NotNull Component reason) {
connection.sendPacket(new LoginDisconnectPacket(reason));
connection.disconnect();
}
private void bungeeDisconnect(@NotNull PlayerConnection connection) {
private static void bungeeDisconnect(@NotNull PlayerConnection connection) {
LOGGER.warn("{} tried to log in without valid BungeeGuard forwarding information.", connection.getIdentifier());
disconnect(connection, INVALID_BUNGEE_FORWARDING);
}

View File

@ -0,0 +1,225 @@
package net.minestom.server.listener.preplay;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.extras.MojangAuth;
import net.minestom.server.extras.bungee.BungeeCordProxy;
import net.minestom.server.extras.mojangAuth.MojangCrypt;
import net.minestom.server.extras.velocity.VelocityProxy;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket;
import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket;
import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket;
import net.minestom.server.network.packet.client.login.ClientLoginStartPacket;
import net.minestom.server.network.packet.server.configuration.FinishConfigurationPacket;
import net.minestom.server.network.packet.server.login.EncryptionRequestPacket;
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
import net.minestom.server.network.packet.server.login.LoginPluginRequestPacket;
import net.minestom.server.network.player.GameProfile;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection;
import net.minestom.server.utils.async.AsyncUtils;
import org.jetbrains.annotations.NotNull;
import javax.crypto.SecretKey;
import java.math.BigInteger;
import java.net.*;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import static net.minestom.server.network.NetworkBuffer.STRING;
public final class LoginListener {
private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
private static final Gson GSON = new Gson();
private static final Component ALREADY_CONNECTED = Component.text("You are already on this server", NamedTextColor.RED);
public static final Component INVALID_PROXY_RESPONSE = Component.text("Invalid proxy response!", NamedTextColor.RED);
public static void loginStartListener(@NotNull ClientLoginStartPacket packet, @NotNull PlayerConnection connection) {
final boolean isSocketConnection = connection instanceof PlayerSocketConnection;
// Proxy support (only for socket clients) and cache the login username
if (isSocketConnection) {
PlayerSocketConnection socketConnection = (PlayerSocketConnection) connection;
socketConnection.UNSAFE_setLoginUsername(packet.username());
// Velocity support
if (VelocityProxy.isEnabled()) {
final int messageId = ThreadLocalRandom.current().nextInt();
final String channel = VelocityProxy.PLAYER_INFO_CHANNEL;
// Important in order to retrieve the channel in the response packet
socketConnection.addPluginRequestEntry(messageId, channel);
connection.sendPacket(new LoginPluginRequestPacket(messageId, channel, null));
return;
}
}
if (MojangAuth.isEnabled() && isSocketConnection) {
// Mojang auth
if (CONNECTION_MANAGER.getPlayer(packet.username()) != null) {
connection.sendPacket(new LoginDisconnectPacket(ALREADY_CONNECTED));
connection.disconnect();
return;
}
final PlayerSocketConnection socketConnection = (PlayerSocketConnection) connection;
socketConnection.setConnectionState(ConnectionState.LOGIN);
final byte[] publicKey = MojangAuth.getKeyPair().getPublic().getEncoded();
byte[] nonce = new byte[4];
ThreadLocalRandom.current().nextBytes(nonce);
socketConnection.setNonce(nonce);
socketConnection.sendPacket(new EncryptionRequestPacket("", publicKey, nonce));
} else {
final boolean bungee = BungeeCordProxy.isEnabled();
// Offline
final UUID playerUuid = bungee && isSocketConnection ?
((PlayerSocketConnection) connection).gameProfile().uuid() :
CONNECTION_MANAGER.getPlayerConnectionUuid(connection, packet.username());
CONNECTION_MANAGER.startConfigurationState(connection, playerUuid, packet.username(), true);
}
}
public static void loginEncryptionResponseListener(@NotNull ClientEncryptionResponsePacket packet, @NotNull PlayerConnection connection) {
// Encryption is only support for socket connection
if (!(connection instanceof PlayerSocketConnection socketConnection)) return;
AsyncUtils.runAsync(() -> {
final String loginUsername = socketConnection.getLoginUsername();
if (loginUsername == null || loginUsername.isEmpty()) {
// Shouldn't happen
return;
}
final boolean hasPublicKey = connection.playerPublicKey() != null;
final boolean verificationFailed = hasPublicKey || !Arrays.equals(socketConnection.getNonce(),
MojangCrypt.decryptUsingKey(MojangAuth.getKeyPair().getPrivate(), packet.encryptedVerifyToken()));
if (verificationFailed) {
MinecraftServer.LOGGER.error("Encryption failed for {}", loginUsername);
return;
}
final byte[] digestedData = MojangCrypt.digestData("", MojangAuth.getKeyPair().getPublic(), getSecretKey(packet.sharedSecret()));
if (digestedData == null) {
// Incorrect key, probably because of the client
MinecraftServer.LOGGER.error("Connection {} failed initializing encryption.", socketConnection.getRemoteAddress());
connection.disconnect();
return;
}
// Query Mojang's session server.
final String serverId = new BigInteger(digestedData).toString(16);
final String username = URLEncoder.encode(loginUsername, StandardCharsets.UTF_8);
final String url = String.format(MojangAuth.AUTH_URL, username, serverId);
// TODO: Add ability to add ip query tag. See: https://wiki.vg/Protocol_Encryption#Authentication
final HttpClient client = HttpClient.newHttpClient();
final HttpRequest request = HttpRequest.newBuilder(URI.create(url)).GET().build();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).whenComplete((response, throwable) -> {
if (throwable != null) {
MinecraftServer.getExceptionManager().handleException(throwable);
if (socketConnection.getPlayer() != null) {
socketConnection.getPlayer().kick(Component.text("Failed to contact Mojang's Session Servers (Are they down?)"));
} else {
socketConnection.disconnect();
}
return;
}
try {
final JsonObject gameProfile = GSON.fromJson(response.body(), JsonObject.class);
if (gameProfile == null) {
// Invalid response
if (socketConnection.getPlayer() != null) {
socketConnection.getPlayer().kick(Component.text("Failed to get data from Mojang's Session Servers (Are they down?)"));
} else {
socketConnection.disconnect();
}
return;
}
socketConnection.setEncryptionKey(getSecretKey(packet.sharedSecret()));
UUID profileUUID = java.util.UUID.fromString(gameProfile.get("id").getAsString()
.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
final String profileName = gameProfile.get("name").getAsString();
MinecraftServer.LOGGER.info("UUID of player {} is {}", loginUsername, profileUUID);
CONNECTION_MANAGER.startConfigurationState(connection, profileUUID, profileName, true);
List<GameProfile.Property> propertyList = new ArrayList<>();
for (JsonElement element : gameProfile.get("properties").getAsJsonArray()) {
JsonObject object = element.getAsJsonObject();
propertyList.add(new GameProfile.Property(object.get("name").getAsString(), object.get("value").getAsString(), object.get("signature").getAsString()));
}
socketConnection.UNSAFE_setProfile(new GameProfile(profileUUID, profileName, propertyList));
} catch (Exception e) {
MinecraftServer.getExceptionManager().handleException(e);
}
});
});
}
private static SecretKey getSecretKey(byte[] sharedSecret) {
return MojangCrypt.decryptByteToSecretKey(MojangAuth.getKeyPair().getPrivate(), sharedSecret);
}
public static void loginPluginResponseListener(@NotNull ClientLoginPluginResponsePacket packet, @NotNull PlayerConnection connection) {
// Proxy support
if (connection instanceof PlayerSocketConnection socketConnection) {
final String channel = socketConnection.getPluginRequestChannel(packet.messageId());
if (channel != null) {
boolean success = false;
SocketAddress socketAddress = null;
GameProfile gameProfile = null;
// Velocity
if (VelocityProxy.isEnabled() && channel.equals(VelocityProxy.PLAYER_INFO_CHANNEL)) {
byte[] data = packet.data();
if (data != null && data.length > 0) {
NetworkBuffer buffer = new NetworkBuffer(ByteBuffer.wrap(data));
success = VelocityProxy.checkIntegrity(buffer);
if (success) {
// Get the real connection address
final InetAddress address;
try {
address = InetAddress.getByName(buffer.read(STRING));
} catch (UnknownHostException e) {
MinecraftServer.getExceptionManager().handleException(e);
return;
}
final int port = ((java.net.InetSocketAddress) connection.getRemoteAddress()).getPort();
socketAddress = new InetSocketAddress(address, port);
gameProfile = new GameProfile(buffer);
}
}
}
if (success) {
socketConnection.setRemoteAddress(socketAddress);
socketConnection.UNSAFE_setProfile(gameProfile);
CONNECTION_MANAGER.startConfigurationState(connection, gameProfile.uuid(), gameProfile.name(), true);
} else {
LoginDisconnectPacket disconnectPacket = new LoginDisconnectPacket(INVALID_PROXY_RESPONSE);
socketConnection.sendPacket(disconnectPacket);
}
}
}
}
public static void loginAckListener(@NotNull ClientLoginAcknowledgedPacket packet, @NotNull PlayerConnection connection) {
connection.setConnectionState(ConnectionState.CONFIGURATION);
connection.sendPacket(new FinishConfigurationPacket());
}
}

View File

@ -0,0 +1,43 @@
package net.minestom.server.listener.preplay;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.server.ClientPingServerEvent;
import net.minestom.server.event.server.ServerListPingEvent;
import net.minestom.server.network.packet.client.status.PingPacket;
import net.minestom.server.network.packet.client.status.StatusRequestPacket;
import net.minestom.server.network.packet.server.status.PongPacket;
import net.minestom.server.network.packet.server.status.ResponsePacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.ping.ServerListPingType;
import org.jetbrains.annotations.NotNull;
public final class StatusListener {
public static void requestListener(@NotNull StatusRequestPacket packet, @NotNull PlayerConnection connection) {
final ServerListPingType pingVersion = ServerListPingType.fromModernProtocolVersion(connection.getProtocolVersion());
final ServerListPingEvent statusRequestEvent = new ServerListPingEvent(connection, pingVersion);
EventDispatcher.callCancellable(statusRequestEvent, () ->
connection.sendPacket(new ResponsePacket(pingVersion.getPingResponse(statusRequestEvent.getResponseData()))));
}
public static void pingListener(@NotNull PingPacket packet, @NotNull PlayerConnection connection) {
final ClientPingServerEvent clientPingEvent = new ClientPingServerEvent(connection, packet.number());
EventDispatcher.call(clientPingEvent);
if (clientPingEvent.isCancelled()) {
connection.disconnect();
} else {
if (clientPingEvent.getDelay().isZero()) {
connection.sendPacket(new PongPacket(clientPingEvent.getPayload()));
connection.disconnect();
} else {
MinecraftServer.getSchedulerManager().buildTask(() -> {
connection.sendPacket(new PongPacket(clientPingEvent.getPayload()));
connection.disconnect();
}).delay(clientPingEvent.getDelay()).schedule();
}
}
}
}

View File

@ -8,8 +8,9 @@ import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.AsyncPlayerPreLoginEvent;
import net.minestom.server.event.player.PlayerLoginEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.network.packet.client.login.ClientLoginStartPacket;
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
import net.minestom.server.network.packet.server.play.KeepAlivePacket;
import net.minestom.server.network.packet.server.common.KeepAlivePacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection;
import net.minestom.server.utils.StringUtils;
@ -135,7 +136,7 @@ public final class ConnectionManager {
/**
* Computes the UUID of the specified connection.
* Used in {@link net.minestom.server.network.packet.client.login.LoginStartPacket} in order
* Used in {@link ClientLoginStartPacket} in order
* to give the player the right {@link UUID}.
*
* @param playerConnection the player connection
@ -184,6 +185,47 @@ public final class ConnectionManager {
this.players.remove(player);
}
public @NotNull Player startConfigurationState(@NotNull PlayerConnection connection,
@NotNull UUID uuid, @NotNull String username,
boolean register) {
final Player player = playerProvider.createPlayer(uuid, username, connection);
startConfigurationState(player, register);
return player;
}
public CompletableFuture<Void> startConfigurationState(@NotNull Player player, boolean register) {
return AsyncUtils.runAsync(() -> {
final PlayerConnection playerConnection = player.getPlayerConnection();
// Compression
if (playerConnection instanceof PlayerSocketConnection socketConnection) {
final int threshold = MinecraftServer.getCompressionThreshold();
if (threshold > 0) socketConnection.startCompression();
}
// Call pre login event
AsyncPlayerPreLoginEvent asyncPlayerPreLoginEvent = new AsyncPlayerPreLoginEvent(player);
EventDispatcher.call(asyncPlayerPreLoginEvent);
if (!player.isOnline())
return; // Player has been kicked
// Change UUID/Username based on the event
{
final String eventUsername = asyncPlayerPreLoginEvent.getUsername();
final UUID eventUuid = asyncPlayerPreLoginEvent.getPlayerUuid();
if (!player.getUsername().equals(eventUsername)) {
player.setUsernameField(eventUsername);
}
if (!player.getUuid().equals(eventUuid)) {
player.setUuid(eventUuid);
}
}
// Send login success packet
LoginSuccessPacket loginSuccessPacket = new LoginSuccessPacket(player.getUuid(), player.getUsername(), 0);
playerConnection.sendPacket(loginSuccessPacket);
// playerConnection.setConnectionState(ConnectionState.CONFIGURATION);
// if (register) registerPlayer(player); // WHEN ENTERING CONFIGURATION THIS SHOULD BE SET
// this.waitingPlayers.relaxedOffer(player);
});
}
/**
* Calls the player initialization callbacks and the event {@link AsyncPlayerPreLoginEvent}.
* <p>
@ -193,7 +235,7 @@ public final class ConnectionManager {
* @param player the player
* @param register true to register the newly created player in {@link ConnectionManager} lists
*/
public CompletableFuture<Void> startPlayState(@NotNull Player player, boolean register) {
public CompletableFuture<Void> startPlayStateOLD(@NotNull Player player, boolean register) {
return AsyncUtils.runAsync(() -> {
final PlayerConnection playerConnection = player.getPlayerConnection();
// Compression
@ -233,11 +275,11 @@ public final class ConnectionManager {
* @return the newly created player object
* @see #startPlayState(Player, boolean)
*/
public @NotNull Player startPlayState(@NotNull PlayerConnection connection,
public @NotNull Player startPlayStateOLD(@NotNull PlayerConnection connection,
@NotNull UUID uuid, @NotNull String username,
boolean register) {
final Player player = playerProvider.createPlayer(uuid, username, connection);
startPlayState(player, register);
startPlayStateOLD(player, register);
return player;
}

View File

@ -4,5 +4,5 @@ package net.minestom.server.network;
* Represents the current connection state of a {@link net.minestom.server.network.player.PlayerConnection}.
*/
public enum ConnectionState {
UNKNOWN, STATUS, LOGIN, PLAY
HANDSHAKE, STATUS, LOGIN, CONFIGURATION, PLAY
}

View File

@ -1,12 +1,11 @@
package net.minestom.server.network;
import net.minestom.server.entity.Player;
import net.minestom.server.listener.manager.PacketListenerManager;
import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.client.ClientPacketsHandler;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.client.handshake.HandshakePacket;
import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.binary.BinaryReader;
import org.jetbrains.annotations.NotNull;
import java.nio.ByteBuffer;
@ -17,25 +16,34 @@ import java.nio.ByteBuffer;
* You can retrieve the different packet handlers per state (status/login/play)
* from the {@link ClientPacketsHandler} classes.
*/
public record PacketProcessor(@NotNull ClientPacketsHandler statusHandler,
@NotNull ClientPacketsHandler loginHandler,
@NotNull ClientPacketsHandler playHandler) {
public PacketProcessor() {
this(new ClientPacketsHandler.Status(),
new ClientPacketsHandler.Login(),
new ClientPacketsHandler.Play());
public class PacketProcessor {
private final ClientPacketsHandler statusHandler;
private final ClientPacketsHandler loginHandler;
private final ClientPacketsHandler configurationHandler;
private final ClientPacketsHandler playHandler;
private final PacketListenerManager packetListenerManager;
public PacketProcessor(@NotNull PacketListenerManager packetListenerManager) {
statusHandler = new ClientPacketsHandler.Status();
loginHandler = new ClientPacketsHandler.Login();
configurationHandler = new ClientPacketsHandler.Configuration();
playHandler = new ClientPacketsHandler.Play();
this.packetListenerManager = packetListenerManager;
}
public @NotNull ClientPacket create(@NotNull ConnectionState connectionState, int packetId, ByteBuffer body) {
NetworkBuffer buffer = new NetworkBuffer(body);
final ClientPacket clientPacket = switch (connectionState) {
case PLAY -> playHandler.create(packetId, buffer);
case LOGIN -> loginHandler.create(packetId, buffer);
case STATUS -> statusHandler.create(packetId, buffer);
case UNKNOWN -> {
case HANDSHAKE -> {
assert packetId == 0;
yield new HandshakePacket(buffer);
yield new ClientHandshakePacket(buffer);
}
case STATUS -> statusHandler.create(packetId, buffer);
case LOGIN -> loginHandler.create(packetId, buffer);
case CONFIGURATION -> configurationHandler.create(packetId, buffer);
case PLAY -> playHandler.create(packetId, buffer);
};
body.position(buffer.readIndex());
return clientPacket;
@ -43,12 +51,15 @@ public record PacketProcessor(@NotNull ClientPacketsHandler statusHandler,
public ClientPacket process(@NotNull PlayerConnection connection, int packetId, ByteBuffer body) {
final ClientPacket packet = create(connection.getConnectionState(), packetId, body);
if (packet instanceof ClientPreplayPacket prePlayPacket) {
prePlayPacket.process(connection);
} else {
final Player player = connection.getPlayer();
assert player != null;
player.addPacketToQueue(packet);
final ConnectionState state = connection.getConnectionState();
switch (state) {
case HANDSHAKE, STATUS, LOGIN, CONFIGURATION -> packetListenerManager.processClientPacket(connection.getConnectionState(), packet, connection);
case PLAY -> {
final Player player = connection.getPlayer();
assert player != null;
player.addPacketToQueue(packet);
}
}
return packet;
}

View File

@ -1,9 +1,12 @@
package net.minestom.server.network.packet.client;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.login.EncryptionResponsePacket;
import net.minestom.server.network.packet.client.login.LoginPluginResponsePacket;
import net.minestom.server.network.packet.client.login.LoginStartPacket;
import net.minestom.server.network.packet.client.common.*;
import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket;
import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket;
import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket;
import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket;
import net.minestom.server.network.packet.client.login.ClientLoginStartPacket;
import net.minestom.server.network.packet.client.play.*;
import net.minestom.server.network.packet.client.status.PingPacket;
import net.minestom.server.network.packet.client.status.StatusRequestPacket;
@ -18,7 +21,7 @@ import java.util.function.Function;
* <p>
* Packets are registered using {@link #register(int, Function)} and created using {@link #create(int, NetworkBuffer)}.
*/
public sealed class ClientPacketsHandler permits ClientPacketsHandler.Status, ClientPacketsHandler.Login, ClientPacketsHandler.Play {
public sealed class ClientPacketsHandler permits ClientPacketsHandler.Status, ClientPacketsHandler.Login, ClientPacketsHandler.Configuration, ClientPacketsHandler.Play {
private final ObjectArray<Function<NetworkBuffer, ClientPacket>> suppliers = ObjectArray.singleThread(0x10);
private ClientPacketsHandler() {
@ -36,79 +39,109 @@ public sealed class ClientPacketsHandler permits ClientPacketsHandler.Status, Cl
}
public static final class Status extends ClientPacketsHandler {
private static int nextId = 0;
private static int nextId() {
return nextId++;
}
public Status() {
register(0x00, StatusRequestPacket::new);
register(0x01, PingPacket::new);
register(nextId(), StatusRequestPacket::new);
register(nextId(), PingPacket::new);
}
}
public static final class Login extends ClientPacketsHandler {
public Login() {
register(0x00, LoginStartPacket::new);
register(0x01, EncryptionResponsePacket::new);
register(0x02, LoginPluginResponsePacket::new);
private static int nextId = 0;
private static int nextId() {
return nextId++;
}
public Login() {
register(nextId(), ClientLoginStartPacket::new);
register(nextId(), ClientEncryptionResponsePacket::new);
register(nextId(), ClientLoginPluginResponsePacket::new);
register(nextId(), ClientLoginAcknowledgedPacket::new);
}
}
public static final class Configuration extends ClientPacketsHandler {
private static int nextId = 0;
private static int nextId() {
return nextId++;
}
public Configuration() {
register(nextId(), ClientSettingsPacket::new);
register(nextId(), ClientPluginMessagePacket::new);
register(nextId(), ClientFinishConfigurationPacket::new);
register(nextId(), ClientKeepAlivePacket::new);
register(nextId(), ClientPongPacket::new);
register(nextId(), ClientResourcePackStatusPacket::new);
}
}
public static final class Play extends ClientPacketsHandler {
private static int nextId = 0;
private static int nextPlayId() {
private static int nextId() {
return nextId++;
}
public Play() {
register(nextPlayId(), ClientTeleportConfirmPacket::new);
register(nextPlayId(), ClientQueryBlockNbtPacket::new);
nextPlayId(); // difficulty packet
register(nextPlayId(), ClientChatAckPacket::new);
register(nextPlayId(), ClientCommandChatPacket::new);
register(nextPlayId(), ClientChatMessagePacket::new);
register(nextPlayId(), ClientChatSessionUpdatePacket::new);
register(nextPlayId(), ClientStatusPacket::new);
register(nextPlayId(), ClientSettingsPacket::new);
register(nextPlayId(), ClientTabCompletePacket::new);
register(nextPlayId(), ClientClickWindowButtonPacket::new);
register(nextPlayId(), ClientClickWindowPacket::new);
register(nextPlayId(), ClientCloseWindowPacket::new);
register(nextPlayId(), ClientPluginMessagePacket::new);
register(nextPlayId(), ClientEditBookPacket::new);
register(nextPlayId(), ClientQueryEntityNbtPacket::new);
register(nextPlayId(), ClientInteractEntityPacket::new);
register(nextPlayId(), ClientGenerateStructurePacket::new);
register(nextPlayId(), ClientKeepAlivePacket::new);
nextPlayId(); // lock difficulty
register(nextPlayId(), ClientPlayerPositionPacket::new);
register(nextPlayId(), ClientPlayerPositionAndRotationPacket::new);
register(nextPlayId(), ClientPlayerRotationPacket::new);
register(nextPlayId(), ClientPlayerPacket::new);
register(nextPlayId(), ClientVehicleMovePacket::new);
register(nextPlayId(), ClientSteerBoatPacket::new);
register(nextPlayId(), ClientPickItemPacket::new);
register(nextPlayId(), ClientCraftRecipeRequest::new);
register(nextPlayId(), ClientPlayerAbilitiesPacket::new);
register(nextPlayId(), ClientPlayerDiggingPacket::new);
register(nextPlayId(), ClientEntityActionPacket::new);
register(nextPlayId(), ClientSteerVehiclePacket::new);
register(nextPlayId(), ClientPongPacket::new);
register(nextPlayId(), ClientSetRecipeBookStatePacket::new);
register(nextPlayId(), ClientSetDisplayedRecipePacket::new);
register(nextPlayId(), ClientNameItemPacket::new);
register(nextPlayId(), ClientResourcePackStatusPacket::new);
register(nextPlayId(), ClientAdvancementTabPacket::new);
register(nextPlayId(), ClientSelectTradePacket::new);
register(nextPlayId(), ClientSetBeaconEffectPacket::new);
register(nextPlayId(), ClientHeldItemChangePacket::new);
register(nextPlayId(), ClientUpdateCommandBlockPacket::new);
register(nextPlayId(), ClientUpdateCommandBlockMinecartPacket::new);
register(nextPlayId(), ClientCreativeInventoryActionPacket::new);
nextPlayId(); // Update Jigsaw Block
register(nextPlayId(), ClientUpdateStructureBlockPacket::new);
register(nextPlayId(), ClientUpdateSignPacket::new);
register(nextPlayId(), ClientAnimationPacket::new);
register(nextPlayId(), ClientSpectatePacket::new);
register(nextPlayId(), ClientPlayerBlockPlacementPacket::new);
register(nextPlayId(), ClientUseItemPacket::new);
register(nextId(), ClientTeleportConfirmPacket::new);
register(nextId(), ClientQueryBlockNbtPacket::new);
nextId(); // difficulty packet
register(nextId(), ClientChatAckPacket::new);
register(nextId(), ClientCommandChatPacket::new);
register(nextId(), ClientChatMessagePacket::new);
register(nextId(), ClientChatSessionUpdatePacket::new);
nextId(); // chunk batch received
register(nextId(), ClientStatusPacket::new);
register(nextId(), ClientSettingsPacket::new);
register(nextId(), ClientTabCompletePacket::new);
nextId(); // configuration acknowledged
register(nextId(), ClientClickWindowButtonPacket::new);
register(nextId(), ClientClickWindowPacket::new);
register(nextId(), ClientCloseWindowPacket::new);
register(nextId(), ClientPluginMessagePacket::new);
register(nextId(), ClientEditBookPacket::new);
register(nextId(), ClientQueryEntityNbtPacket::new);
register(nextId(), ClientInteractEntityPacket::new);
register(nextId(), ClientGenerateStructurePacket::new);
register(nextId(), ClientKeepAlivePacket::new);
nextId(); // lock difficulty
register(nextId(), ClientPlayerPositionPacket::new);
register(nextId(), ClientPlayerPositionAndRotationPacket::new);
register(nextId(), ClientPlayerRotationPacket::new);
register(nextId(), ClientPlayerPacket::new);
register(nextId(), ClientVehicleMovePacket::new);
register(nextId(), ClientSteerBoatPacket::new);
register(nextId(), ClientPickItemPacket::new);
register(nextId(), ClientCraftRecipeRequest::new);
register(nextId(), ClientPlayerAbilitiesPacket::new);
register(nextId(), ClientPlayerDiggingPacket::new);
register(nextId(), ClientEntityActionPacket::new);
register(nextId(), ClientSteerVehiclePacket::new);
register(nextId(), ClientPongPacket::new);
register(nextId(), ClientSetRecipeBookStatePacket::new);
register(nextId(), ClientSetDisplayedRecipePacket::new);
register(nextId(), ClientNameItemPacket::new);
register(nextId(), ClientResourcePackStatusPacket::new);
register(nextId(), ClientAdvancementTabPacket::new);
register(nextId(), ClientSelectTradePacket::new);
register(nextId(), ClientSetBeaconEffectPacket::new);
register(nextId(), ClientHeldItemChangePacket::new);
register(nextId(), ClientUpdateCommandBlockPacket::new);
register(nextId(), ClientUpdateCommandBlockMinecartPacket::new);
register(nextId(), ClientCreativeInventoryActionPacket::new);
nextId(); // Update Jigsaw Block
register(nextId(), ClientUpdateStructureBlockPacket::new);
register(nextId(), ClientUpdateSignPacket::new);
register(nextId(), ClientAnimationPacket::new);
register(nextId(), ClientSpectatePacket::new);
register(nextId(), ClientPlayerBlockPlacementPacket::new);
register(nextId(), ClientUseItemPacket::new);
}
}
}

View File

@ -1,18 +0,0 @@
package net.minestom.server.network.packet.client;
import net.minestom.server.MinecraftServer;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.player.PlayerConnection;
import org.jetbrains.annotations.NotNull;
public interface ClientPreplayPacket extends ClientPacket {
ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
/**
* Called when the packet is received.
*
* @param connection the connection who sent the packet
*/
void process(@NotNull PlayerConnection connection);
}

View File

@ -1,4 +1,4 @@
package net.minestom.server.network.packet.client.play;
package net.minestom.server.network.packet.client.common;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;

View File

@ -1,4 +1,4 @@
package net.minestom.server.network.packet.client.play;
package net.minestom.server.network.packet.client.common;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;

View File

@ -1,4 +1,4 @@
package net.minestom.server.network.packet.client.play;
package net.minestom.server.network.packet.client.common;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;

View File

@ -1,4 +1,4 @@
package net.minestom.server.network.packet.client.play;
package net.minestom.server.network.packet.client.common;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;

View File

@ -1,4 +1,4 @@
package net.minestom.server.network.packet.client.play;
package net.minestom.server.network.packet.client.common;
import net.minestom.server.entity.Player;
import net.minestom.server.message.ChatMessageType;

View File

@ -0,0 +1,17 @@
package net.minestom.server.network.packet.client.configuration;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
public record ClientFinishConfigurationPacket() implements ClientPacket {
public ClientFinishConfigurationPacket(@NotNull NetworkBuffer buffer) {
this();
}
@Override
public void write(@NotNull NetworkBuffer writer) {
}
}

View File

@ -0,0 +1,41 @@
package net.minestom.server.network.packet.client.handshake;
import net.minestom.server.extras.bungee.BungeeCordProxy;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
import static net.minestom.server.network.NetworkBuffer.*;
public record ClientHandshakePacket(int protocolVersion, @NotNull String serverAddress,
int serverPort, int nextState) implements ClientPacket {
public ClientHandshakePacket {
if (serverAddress.length() > getMaxHandshakeLength()) {
throw new IllegalArgumentException("Server address too long: " + serverAddress.length());
}
}
public ClientHandshakePacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), reader.read(STRING),
reader.read(UNSIGNED_SHORT), reader.read(VAR_INT));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(VAR_INT, protocolVersion);
int maxLength = getMaxHandshakeLength();
if (serverAddress.length() > maxLength) {
throw new IllegalArgumentException("serverAddress is " + serverAddress.length() + " characters long, maximum allowed is " + maxLength);
}
writer.write(STRING, serverAddress);
writer.write(UNSIGNED_SHORT, serverPort);
writer.write(VAR_INT, nextState);
}
private static int getMaxHandshakeLength() {
// BungeeGuard limits handshake length to 2500 characters, while vanilla limits it to 255
return BungeeCordProxy.isEnabled() ? (BungeeCordProxy.isBungeeGuardEnabled() ? 2500 : Short.MAX_VALUE) : 255;
}
}

View File

@ -0,0 +1,21 @@
package net.minestom.server.network.packet.client.login;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY;
public record ClientEncryptionResponsePacket(byte[] sharedSecret,
byte[] encryptedVerifyToken) implements ClientPacket {
public ClientEncryptionResponsePacket(@NotNull NetworkBuffer reader) {
this(reader.read(BYTE_ARRAY), reader.read(BYTE_ARRAY));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(BYTE_ARRAY, sharedSecret);
writer.write(BYTE_ARRAY, encryptedVerifyToken);
}
}

View File

@ -0,0 +1,17 @@
package net.minestom.server.network.packet.client.login;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
public record ClientLoginAcknowledgedPacket() implements ClientPacket {
public ClientLoginAcknowledgedPacket(@NotNull NetworkBuffer buffer) {
this();
}
@Override
public void write(@NotNull NetworkBuffer writer) {
}
}

View File

@ -0,0 +1,22 @@
package net.minestom.server.network.packet.client.login;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static net.minestom.server.network.NetworkBuffer.*;
public record ClientLoginPluginResponsePacket(int messageId, byte @Nullable [] data) implements ClientPacket {
public ClientLoginPluginResponsePacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), reader.readOptional(RAW_BYTES));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(VAR_INT, messageId);
writer.writeOptional(RAW_BYTES, data);
}
}

View File

@ -0,0 +1,27 @@
package net.minestom.server.network.packet.client.login;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
import static net.minestom.server.network.NetworkBuffer.STRING;
import static net.minestom.server.network.NetworkBuffer.UUID;
public record ClientLoginStartPacket(@NotNull String username,
@NotNull UUID profileId) implements ClientPacket {
public ClientLoginStartPacket(@NotNull NetworkBuffer reader) {
this(reader.read(STRING), reader.read(UUID));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
if (username.length() > 16)
throw new IllegalArgumentException("Username is not allowed to be longer than 16 characters");
writer.write(STRING, username);
writer.write(UUID, profileId);
}
}

View File

@ -1,127 +0,0 @@
package net.minestom.server.network.packet.client.login;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.extras.MojangAuth;
import net.minestom.server.extras.mojangAuth.MojangCrypt;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.player.GameProfile;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection;
import net.minestom.server.utils.async.AsyncUtils;
import org.jetbrains.annotations.NotNull;
import javax.crypto.SecretKey;
import java.math.BigInteger;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import static net.minestom.server.network.NetworkBuffer.BYTE_ARRAY;
public record EncryptionResponsePacket(byte[] sharedSecret,
byte[] encryptedVerifyToken) implements ClientPreplayPacket {
private static final Gson GSON = new Gson();
public EncryptionResponsePacket(@NotNull NetworkBuffer reader) {
this(reader.read(BYTE_ARRAY), reader.read(BYTE_ARRAY));
}
@Override
public void process(@NotNull PlayerConnection connection) {
// Encryption is only support for socket connection
if (!(connection instanceof PlayerSocketConnection socketConnection)) return;
AsyncUtils.runAsync(() -> {
final String loginUsername = socketConnection.getLoginUsername();
if (loginUsername == null || loginUsername.isEmpty()) {
// Shouldn't happen
return;
}
final boolean hasPublicKey = connection.playerPublicKey() != null;
final boolean verificationFailed = hasPublicKey || !Arrays.equals(socketConnection.getNonce(),
MojangCrypt.decryptUsingKey(MojangAuth.getKeyPair().getPrivate(), encryptedVerifyToken));
if (verificationFailed) {
MinecraftServer.LOGGER.error("Encryption failed for {}", loginUsername);
return;
}
final byte[] digestedData = MojangCrypt.digestData("", MojangAuth.getKeyPair().getPublic(), getSecretKey());
if (digestedData == null) {
// Incorrect key, probably because of the client
MinecraftServer.LOGGER.error("Connection {} failed initializing encryption.", socketConnection.getRemoteAddress());
connection.disconnect();
return;
}
// Query Mojang's session server.
final String serverId = new BigInteger(digestedData).toString(16);
final String username = URLEncoder.encode(loginUsername, StandardCharsets.UTF_8);
final String url = String.format(MojangAuth.AUTH_URL, username, serverId);
// TODO: Add ability to add ip query tag. See: https://wiki.vg/Protocol_Encryption#Authentication
final HttpClient client = HttpClient.newHttpClient();
final HttpRequest request = HttpRequest.newBuilder(URI.create(url)).GET().build();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).whenComplete((response, throwable) -> {
if (throwable != null) {
MinecraftServer.getExceptionManager().handleException(throwable);
if (socketConnection.getPlayer() != null) {
socketConnection.getPlayer().kick(Component.text("Failed to contact Mojang's Session Servers (Are they down?)"));
} else {
socketConnection.disconnect();
}
return;
}
try {
final JsonObject gameProfile = GSON.fromJson(response.body(), JsonObject.class);
if (gameProfile == null) {
// Invalid response
if (socketConnection.getPlayer() != null) {
socketConnection.getPlayer().kick(Component.text("Failed to get data from Mojang's Session Servers (Are they down?)"));
} else {
socketConnection.disconnect();
}
return;
}
socketConnection.setEncryptionKey(getSecretKey());
UUID profileUUID = java.util.UUID.fromString(gameProfile.get("id").getAsString()
.replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
final String profileName = gameProfile.get("name").getAsString();
MinecraftServer.LOGGER.info("UUID of player {} is {}", loginUsername, profileUUID);
CONNECTION_MANAGER.startPlayState(connection, profileUUID, profileName, true);
List<GameProfile.Property> propertyList = new ArrayList<>();
for (JsonElement element : gameProfile.get("properties").getAsJsonArray()) {
JsonObject object = element.getAsJsonObject();
propertyList.add(new GameProfile.Property(object.get("name").getAsString(), object.get("value").getAsString(), object.get("signature").getAsString()));
}
socketConnection.UNSAFE_setProfile(new GameProfile(profileUUID, profileName, propertyList));
} catch (Exception e) {
MinecraftServer.getExceptionManager().handleException(e);
}
});
});
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(BYTE_ARRAY, sharedSecret);
writer.write(BYTE_ARRAY, encryptedVerifyToken);
}
private SecretKey getSecretKey() {
return MojangCrypt.decryptByteToSecretKey(MojangAuth.getKeyPair().getPrivate(), sharedSecret);
}
}

View File

@ -1,82 +0,0 @@
package net.minestom.server.network.packet.client.login;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.extras.velocity.VelocityProxy;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
import net.minestom.server.network.player.GameProfile;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import static net.minestom.server.network.NetworkBuffer.*;
public record LoginPluginResponsePacket(int messageId, byte @Nullable [] data) implements ClientPreplayPacket {
private final static ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
public static final Component INVALID_PROXY_RESPONSE = Component.text("Invalid proxy response!", NamedTextColor.RED);
public LoginPluginResponsePacket(@NotNull NetworkBuffer reader) {
this(reader.read(VAR_INT), reader.readOptional(RAW_BYTES));
}
@Override
public void process(@NotNull PlayerConnection connection) {
// Proxy support
if (connection instanceof PlayerSocketConnection socketConnection) {
final String channel = socketConnection.getPluginRequestChannel(messageId);
if (channel != null) {
boolean success = false;
SocketAddress socketAddress = null;
GameProfile gameProfile = null;
// Velocity
if (VelocityProxy.isEnabled() && channel.equals(VelocityProxy.PLAYER_INFO_CHANNEL)) {
if (data != null && data.length > 0) {
NetworkBuffer buffer = new NetworkBuffer(ByteBuffer.wrap(data));
success = VelocityProxy.checkIntegrity(buffer);
if (success) {
// Get the real connection address
final InetAddress address;
try {
address = InetAddress.getByName(buffer.read(STRING));
} catch (UnknownHostException e) {
MinecraftServer.getExceptionManager().handleException(e);
return;
}
final int port = ((java.net.InetSocketAddress) connection.getRemoteAddress()).getPort();
socketAddress = new InetSocketAddress(address, port);
gameProfile = new GameProfile(buffer);
}
}
}
if (success) {
socketConnection.setRemoteAddress(socketAddress);
socketConnection.UNSAFE_setProfile(gameProfile);
CONNECTION_MANAGER.startPlayState(connection, gameProfile.uuid(), gameProfile.name(), true);
} else {
LoginDisconnectPacket disconnectPacket = new LoginDisconnectPacket(INVALID_PROXY_RESPONSE);
socketConnection.sendPacket(disconnectPacket);
}
}
}
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(VAR_INT, messageId);
writer.writeOptional(RAW_BYTES, data);
}
}

View File

@ -1,82 +0,0 @@
package net.minestom.server.network.packet.client.login;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.extras.MojangAuth;
import net.minestom.server.extras.bungee.BungeeCordProxy;
import net.minestom.server.extras.velocity.VelocityProxy;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.server.login.EncryptionRequestPacket;
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
import net.minestom.server.network.packet.server.login.LoginPluginRequestPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import static net.minestom.server.network.NetworkBuffer.STRING;
import static net.minestom.server.network.NetworkBuffer.UUID;
public record LoginStartPacket(@NotNull String username,
@Nullable UUID profileId) implements ClientPreplayPacket {
private static final Component ALREADY_CONNECTED = Component.text("You are already on this server", NamedTextColor.RED);
public LoginStartPacket(@NotNull NetworkBuffer reader) {
this(reader.read(STRING), reader.readOptional(UUID));
}
@Override
public void process(@NotNull PlayerConnection connection) {
final boolean isSocketConnection = connection instanceof PlayerSocketConnection;
// Proxy support (only for socket clients) and cache the login username
if (isSocketConnection) {
PlayerSocketConnection socketConnection = (PlayerSocketConnection) connection;
socketConnection.UNSAFE_setLoginUsername(username);
// Velocity support
if (VelocityProxy.isEnabled()) {
final int messageId = ThreadLocalRandom.current().nextInt();
final String channel = VelocityProxy.PLAYER_INFO_CHANNEL;
// Important in order to retrieve the channel in the response packet
socketConnection.addPluginRequestEntry(messageId, channel);
connection.sendPacket(new LoginPluginRequestPacket(messageId, channel, null));
return;
}
}
if (MojangAuth.isEnabled() && isSocketConnection) {
// Mojang auth
if (CONNECTION_MANAGER.getPlayer(username) != null) {
connection.sendPacket(new LoginDisconnectPacket(ALREADY_CONNECTED));
connection.disconnect();
return;
}
final PlayerSocketConnection socketConnection = (PlayerSocketConnection) connection;
socketConnection.setConnectionState(ConnectionState.LOGIN);
final byte[] publicKey = MojangAuth.getKeyPair().getPublic().getEncoded();
byte[] nonce = new byte[4];
ThreadLocalRandom.current().nextBytes(nonce);
socketConnection.setNonce(nonce);
socketConnection.sendPacket(new EncryptionRequestPacket("", publicKey, nonce));
} else {
final boolean bungee = BungeeCordProxy.isEnabled();
// Offline
final UUID playerUuid = bungee && isSocketConnection ?
((PlayerSocketConnection) connection).gameProfile().uuid() :
CONNECTION_MANAGER.getPlayerConnectionUuid(connection, username);
CONNECTION_MANAGER.startPlayState(connection, playerUuid, username, true);
}
}
@Override
public void write(@NotNull NetworkBuffer writer) {
if (username.length() > 16)
throw new IllegalArgumentException("Username is not allowed to be longer than 16 characters");
writer.write(STRING, username);
}
}

View File

@ -1,22 +1,16 @@
package net.minestom.server.network.packet.client.status;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
import static net.minestom.server.network.NetworkBuffer.BYTE;
public record LegacyServerListPingPacket(byte payload) implements ClientPreplayPacket {
public record LegacyServerListPingPacket(byte payload) implements ClientPacket {
public LegacyServerListPingPacket(@NotNull NetworkBuffer reader) {
this(reader.read(BYTE));
}
@Override
public void process(@NotNull PlayerConnection connection) {
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(BYTE, payload);

View File

@ -1,41 +1,16 @@
package net.minestom.server.network.packet.client.status;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.server.ClientPingServerEvent;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.server.status.PongPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
import static net.minestom.server.network.NetworkBuffer.LONG;
public record PingPacket(long number) implements ClientPreplayPacket {
public record PingPacket(long number) implements ClientPacket {
public PingPacket(@NotNull NetworkBuffer reader) {
this(reader.read(LONG));
}
@Override
public void process(@NotNull PlayerConnection connection) {
final ClientPingServerEvent clientPingEvent = new ClientPingServerEvent(connection, number);
EventDispatcher.call(clientPingEvent);
if (clientPingEvent.isCancelled()) {
connection.disconnect();
} else {
if (clientPingEvent.getDelay().isZero()) {
connection.sendPacket(new PongPacket(clientPingEvent.getPayload()));
connection.disconnect();
} else {
MinecraftServer.getSchedulerManager().buildTask(() -> {
connection.sendPacket(new PongPacket(clientPingEvent.getPayload()));
connection.disconnect();
}).delay(clientPingEvent.getDelay()).schedule();
}
}
}
@Override
public void write(@NotNull NetworkBuffer writer) {
writer.write(LONG, number);

View File

@ -1,27 +1,14 @@
package net.minestom.server.network.packet.client.status;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.server.ServerListPingEvent;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.server.handshake.ResponsePacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.ping.ServerListPingType;
import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
public record StatusRequestPacket() implements ClientPreplayPacket {
public record StatusRequestPacket() implements ClientPacket {
public StatusRequestPacket(@NotNull NetworkBuffer reader) {
this();
}
@Override
public void process(@NotNull PlayerConnection connection) {
final ServerListPingType pingVersion = ServerListPingType.fromModernProtocolVersion(connection.getProtocolVersion());
final ServerListPingEvent statusRequestEvent = new ServerListPingEvent(connection, pingVersion);
EventDispatcher.callCancellable(statusRequestEvent, () ->
connection.sendPacket(new ResponsePacket(pingVersion.getPingResponse(statusRequestEvent.getResponseData()))));
}
@Override
public void write(@NotNull NetworkBuffer writer) {
// Empty

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.utils.PacketUtils;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@ -33,23 +34,23 @@ public final class CachedPacket implements SendablePacket {
this.packet = null;
}
public @NotNull ServerPacket packet() {
FramedPacket cache = updatedCache();
public @NotNull ServerPacket packet(@NotNull ConnectionState state) {
FramedPacket cache = updatedCache(state);
return cache != null ? cache.packet() : packetSupplier.get();
}
public @Nullable ByteBuffer body() {
FramedPacket cache = updatedCache();
public @Nullable ByteBuffer body(@NotNull ConnectionState state) {
FramedPacket cache = updatedCache(state);
return cache != null ? cache.body() : null;
}
private @Nullable FramedPacket updatedCache() {
private @Nullable FramedPacket updatedCache(@NotNull ConnectionState state) {
if (!PacketUtils.CACHED_PACKET)
return null;
SoftReference<FramedPacket> ref = packet;
FramedPacket cache;
if (ref == null || (cache = ref.get()) == null) {
cache = PacketUtils.allocateTrimmedPacket(packetSupplier.get());
cache = PacketUtils.allocateTrimmedPacket(state, packetSupplier.get());
this.packet = new SoftReference<>(cache);
}
return cache;

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.player.PlayerConnection;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@ -12,11 +13,11 @@ public sealed interface SendablePacket
permits CachedPacket, FramedPacket, LazyPacket, ServerPacket {
@ApiStatus.Experimental
static @NotNull ServerPacket extractServerPacket(@NotNull SendablePacket packet) {
static @NotNull ServerPacket extractServerPacket(@NotNull ConnectionState state, @NotNull SendablePacket packet) {
if (packet instanceof ServerPacket serverPacket) {
return serverPacket;
} else if (packet instanceof CachedPacket cachedPacket) {
return cachedPacket.packet();
return cachedPacket.packet(state);
} else if (packet instanceof FramedPacket framedPacket) {
return framedPacket.packet();
} else if (packet instanceof LazyPacket lazyPacket) {

View File

@ -1,7 +1,9 @@
package net.minestom.server.network.packet.server;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.player.PlayerConnection;
import org.jetbrains.annotations.NotNull;
/**
* Represents a packet which can be sent to a player using {@link PlayerConnection#sendPacket(SendablePacket)}.
@ -17,5 +19,6 @@ public non-sealed interface ServerPacket extends NetworkBuffer.Writer, SendableP
*
* @return the id of this packet
*/
int getId();
int getId(@NotNull ConnectionState state);
}

View File

@ -11,6 +11,16 @@ public final class ServerPacketIdentifier {
public static final int LOGIN_SET_COMPRESSION = 0x03;
public static final int LOGIN_PLUGIN_REQUEST = 0x04;
public static final int CONFIGURATION_PLUGIN_MESSAGE = 0x00;
public static final int CONFIGURATION_DISCONNECT = 0x01;
public static final int CONFIGURATION_FINISH_CONFIGURATION = 0x02;
public static final int CONFIGURATION_KEEP_ALIVE = 0x03;
public static final int CONFIGURATION_PING = 0x04;
public static final int CONFIGURATION_REGISTRY_DATA = 0x05;
public static final int CONFIGURATION_RESOURCE_PACK_SEND = 0x06;
public static final int CONFIGURATION_UPDATE_ENABLED_FEATURES = 0x07;
public static final int CONFIGURATION_TAGS = 0x08;
public static final int BUNDLE = nextPlayId();
public static final int SPAWN_ENTITY = nextPlayId();
public static final int SPAWN_EXPERIENCE_ORB = nextPlayId();
@ -24,6 +34,8 @@ public final class ServerPacketIdentifier {
public static final int BLOCK_CHANGE = nextPlayId();
public static final int BOSS_BAR = nextPlayId();
public static final int SERVER_DIFFICULTY = nextPlayId();
public static final int CHUNK_BATCH_FINISHED = nextPlayId();
public static final int CHUNK_BATCH_START = nextPlayId();
public static final int CHUNK_BIOMES = nextPlayId();
public static final int CLEAR_TITLES = nextPlayId();
public static final int TAB_COMPLETE = nextPlayId();
@ -62,6 +74,7 @@ public final class ServerPacketIdentifier {
public static final int OPEN_WINDOW = nextPlayId();
public static final int OPEN_SIGN_EDITOR = nextPlayId();
public static final int PING = nextPlayId();
public static final int PONG_RESPONSE = nextPlayId();
public static final int CRAFT_RECIPE_RESPONSE = nextPlayId();
public static final int PLAYER_ABILITIES = nextPlayId();
public static final int PLAYER_CHAT = nextPlayId();
@ -110,6 +123,7 @@ public final class ServerPacketIdentifier {
public static final int SET_TITLE_TIME = nextPlayId();
public static final int ENTITY_SOUND_EFFECT = nextPlayId();
public static final int SOUND_EFFECT = nextPlayId();
public static final int START_CONFIGURATION_PACKET = nextPlayId();
public static final int STOP_SOUND = nextPlayId();
public static final int SYSTEM_CHAT = nextPlayId();
public static final int PLAYER_LIST_HEADER_AND_FOOTER = nextPlayId();
@ -118,7 +132,6 @@ public final class ServerPacketIdentifier {
public static final int ENTITY_TELEPORT = nextPlayId();
public static final int ADVANCEMENTS = nextPlayId();
public static final int ENTITY_PROPERTIES = nextPlayId();
public static final int UPDATE_ENABLED_FEATURES = nextPlayId();
public static final int ENTITY_EFFECT = nextPlayId();
public static final int DECLARE_RECIPES = nextPlayId();
public static final int TAGS = nextPlayId();

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
package net.minestom.server.network.packet.server.common;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
@ -24,8 +25,8 @@ public record DisconnectPacket(@NotNull Component message) implements ComponentH
}
@Override
public int getId() {
return ServerPacketIdentifier.DISCONNECT;
public int getId(@NotNull ConnectionState state) {
return state == ConnectionState.PLAY ? ServerPacketIdentifier.DISCONNECT : ServerPacketIdentifier.CONFIGURATION_DISCONNECT;
}
@Override

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
package net.minestom.server.network.packet.server.common;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -18,7 +19,7 @@ public record KeepAlivePacket(long id) implements ServerPacket {
}
@Override
public int getId() {
return ServerPacketIdentifier.KEEP_ALIVE;
public int getId(@NotNull ConnectionState state) {
return state == ConnectionState.PLAY ? ServerPacketIdentifier.KEEP_ALIVE : ServerPacketIdentifier.CONFIGURATION_KEEP_ALIVE;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
package net.minestom.server.network.packet.server.common;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -18,7 +19,7 @@ public record PingPacket(int id) implements ServerPacket {
}
@Override
public int getId() {
return ServerPacketIdentifier.PING;
public int getId(@NotNull ConnectionState state) {
return state == ConnectionState.PLAY ? ServerPacketIdentifier.PING : ServerPacketIdentifier.CONFIGURATION_PING;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
package net.minestom.server.network.packet.server.common;
import net.minestom.server.MinecraftServer;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -21,8 +22,8 @@ public record PluginMessagePacket(String channel, byte[] data) implements Server
}
@Override
public int getId() {
return ServerPacketIdentifier.PLUGIN_MESSAGE;
public int getId(@NotNull ConnectionState state) {
return state == ConnectionState.PLAY ? ServerPacketIdentifier.PLUGIN_MESSAGE : ServerPacketIdentifier.CONFIGURATION_PLUGIN_MESSAGE;
}
/**

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
package net.minestom.server.network.packet.server.common;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
@ -40,8 +41,8 @@ public record ResourcePackSendPacket(String url, String hash, boolean forced,
}
@Override
public int getId() {
return ServerPacketIdentifier.RESOURCE_PACK_SEND;
public int getId(@NotNull ConnectionState state) {
return state == ConnectionState.PLAY ? ServerPacketIdentifier.RESOURCE_PACK_SEND : ServerPacketIdentifier.CONFIGURATION_RESOURCE_PACK_SEND;
}
@Override

View File

@ -1,7 +1,8 @@
package net.minestom.server.network.packet.server.play;
package net.minestom.server.network.packet.server.common;
import net.minestom.server.MinecraftServer;
import net.minestom.server.gamedata.tags.Tag;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.CachedPacket;
import net.minestom.server.network.packet.server.ServerPacket;
@ -47,8 +48,8 @@ public record TagsPacket(@NotNull Map<Tag.BasicType, List<Tag>> tagsMap) impleme
}
@Override
public int getId() {
return ServerPacketIdentifier.TAGS;
public int getId(@NotNull ConnectionState state) {
return state == ConnectionState.PLAY ? ServerPacketIdentifier.TAGS : ServerPacketIdentifier.CONFIGURATION_TAGS;
}
private static Map<Tag.BasicType, List<Tag>> readTagsMap(@NotNull NetworkBuffer reader) {

View File

@ -0,0 +1,22 @@
package net.minestom.server.network.packet.server.configuration;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import org.jetbrains.annotations.NotNull;
public record FinishConfigurationPacket() implements ServerPacket {
public FinishConfigurationPacket(@NotNull NetworkBuffer buffer) {
this();
}
@Override
public void write(@NotNull NetworkBuffer writer) {
}
@Override
public int getId(@NotNull ConnectionState state) {
return 2;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.login;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -25,7 +26,7 @@ public record EncryptionRequestPacket(@NotNull String serverId,
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.LOGIN_ENCRYPTION_REQUEST;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.login;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -23,7 +24,7 @@ public record LoginDisconnectPacket(@NotNull Component kickMessage) implements C
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.LOGIN_DISCONNECT;
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.login;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -25,7 +26,7 @@ public record LoginPluginRequestPacket(int messageId, @NotNull String channel,
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.LOGIN_PLUGIN_REQUEST;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.login;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -23,7 +24,7 @@ public record LoginSuccessPacket(@NotNull UUID uuid, @NotNull String username, i
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.LOGIN_SUCCESS;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.login;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -18,7 +19,7 @@ public record SetCompressionPacket(int threshold) implements ServerPacket {
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.LOGIN_SET_COMPRESSION;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -18,7 +19,7 @@ public record AcknowledgeBlockChangePacket(int sequence) implements ServerPacket
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ACKNOWLEDGE_BLOCK_CHANGE;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
@ -24,7 +25,7 @@ public record ActionBarPacket(@NotNull Component text) implements ComponentHoldi
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ACTION_BAR;
}

View File

@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component;
import net.minestom.server.advancements.FrameType;
import net.minestom.server.adventure.ComponentHolder;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
@ -43,7 +44,7 @@ public record AdvancementsPacket(boolean reset, @NotNull List<AdvancementMapping
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ADVANCEMENTS;
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.entity.Entity;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -25,7 +26,7 @@ public record AttachEntityPacket(int attachedEntityId, int holdingEntityId) impl
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ATTACH_ENTITY;
}
}

View File

@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Point;
import net.minestom.server.instance.block.Block;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -29,7 +30,7 @@ public record BlockActionPacket(@NotNull Point blockPosition, byte actionId,
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.BLOCK_ACTION;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Point;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -22,7 +23,7 @@ public record BlockBreakAnimationPacket(int entityId, @NotNull Point blockPositi
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.BLOCK_BREAK_ANIMATION;
}
}

View File

@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Point;
import net.minestom.server.instance.block.Block;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -26,7 +27,7 @@ public record BlockChangePacket(@NotNull Point blockPosition, int blockStateId)
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.BLOCK_CHANGE;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Point;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -29,7 +30,7 @@ public record BlockEntityDataPacket(@NotNull Point blockPosition, int action,
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.BLOCK_ENTITY_DATA;
}
}

View File

@ -4,6 +4,7 @@ import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.text.Component;
import net.minestom.server.adventure.AdventurePacketConvertor;
import net.minestom.server.adventure.ComponentHolder;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
@ -199,7 +200,7 @@ public record BossBarPacket(@NotNull UUID uuid, @NotNull Action action) implemen
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.BOSS_BAR;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.entity.Entity;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -23,7 +24,7 @@ public record CameraPacket(int cameraId) implements ServerPacket {
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.CAMERA;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -20,7 +21,7 @@ public record ChangeGameStatePacket(@NotNull Reason reason, float value) impleme
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.CHANGE_GAME_STATE;
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -27,7 +28,7 @@ public record ChunkDataPacket(int chunkX, int chunkZ,
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.CHUNK_DATA;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -18,7 +19,7 @@ public record ClearTitlesPacket(boolean reset) implements ServerPacket {
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.CLEAR_TITLES;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -18,7 +19,7 @@ public record CloseWindowPacket(byte windowId) implements ServerPacket {
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.CLOSE_WINDOW;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -21,7 +22,7 @@ public record CollectItemPacket(int collectedEntityId, int collectorEntityId, in
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.COLLECT_ITEM;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -20,7 +21,7 @@ public record CraftRecipeResponse(byte windowId, String recipe) implements Serve
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.CRAFT_RECIPE_RESPONSE;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -26,7 +27,7 @@ public record CustomChatCompletionPacket(@NotNull Action action,
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.CUSTOM_CHAT_COMPLETIONS;
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Point;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -19,7 +20,7 @@ public record DamageEventPacket(int targetEntityId, int damageTypeId, int source
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.DAMAGE_EVENT;
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
@ -25,7 +26,7 @@ public record DeathCombatEventPacket(int playerId, @NotNull Component message) i
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.DEATH_COMBAT_EVENT;
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -33,7 +34,7 @@ public record DeclareCommandsPacket(@NotNull List<Node> nodes,
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.DECLARE_COMMANDS;
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -46,7 +47,7 @@ public record DeclareRecipesPacket(@NotNull List<DeclaredRecipe> recipes) implem
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.DECLARE_RECIPES;
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.crypto.MessageSignature;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -17,7 +18,7 @@ public record DeleteChatPacket(@NotNull MessageSignature signature) implements S
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.DELETE_CHAT_MESSAGE;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -28,7 +29,7 @@ public record DestroyEntitiesPacket(@NotNull List<Integer> entityIds) implements
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.DESTROY_ENTITIES;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -20,7 +21,7 @@ public record DisplayScoreboardPacket(byte position, String scoreName) implement
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.DISPLAY_SCOREBOARD;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Point;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -23,7 +24,7 @@ public record EffectPacket(int effectId, Point position, int data,
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.EFFECT;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -18,7 +19,7 @@ public record EndCombatEventPacket(int duration) implements ServerPacket {
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.END_COMBAT_EVENT;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -16,7 +17,7 @@ public record EnterCombatEventPacket() implements ServerPacket {
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTER_COMBAT_EVENT;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -20,7 +21,7 @@ public record EntityAnimationPacket(int entityId, @NotNull Animation animation)
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_ANIMATION;
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -25,7 +26,7 @@ public record EntityEffectPacket(int entityId, @NotNull Potion potion,
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_EFFECT;
}
}

View File

@ -3,6 +3,7 @@ package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.entity.EquipmentSlot;
import net.minestom.server.item.ItemStack;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
@ -44,7 +45,7 @@ public record EntityEquipmentPacket(int entityId,
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_EQUIPMENT;
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -20,7 +21,7 @@ public record EntityHeadLookPacket(int entityId, float yaw) implements ServerPac
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_HEAD_LOOK;
}
}

View File

@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.entity.Metadata;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
@ -49,7 +50,7 @@ public record EntityMetaDataPacket(int entityId,
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_METADATA;
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -27,7 +28,7 @@ public record EntityPositionAndRotationPacket(int entityId, short deltaX, short
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_POSITION_AND_ROTATION;
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -25,7 +26,7 @@ public record EntityPositionPacket(int entityId, short deltaX, short deltaY, sho
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_POSITION;
}

View File

@ -4,6 +4,7 @@ import net.minestom.server.attribute.Attribute;
import net.minestom.server.attribute.AttributeInstance;
import net.minestom.server.attribute.AttributeModifier;
import net.minestom.server.attribute.AttributeOperation;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -57,7 +58,7 @@ public record EntityPropertiesPacket(int entityId, List<AttributeInstance> prope
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_PROPERTIES;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -21,7 +22,7 @@ public record EntityRotationPacket(int entityId, float yaw, float pitch, boolean
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_ROTATION;
}
}

View File

@ -2,6 +2,7 @@ package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.sound.Sound;
import net.minestom.server.adventure.AdventurePacketConvertor;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -89,7 +90,7 @@ public record EntitySoundEffectPacket(
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_SOUND_EFFECT;
}
}

View File

@ -1,5 +1,6 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -20,7 +21,7 @@ public record EntityStatusPacket(int entityId, byte status) implements ServerPac
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_STATUS;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -27,7 +28,7 @@ public record EntityTeleportPacket(int entityId, Pos position, boolean onGround)
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_TELEPORT;
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.coordinate.Point;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -34,7 +35,7 @@ public record EntityVelocityPacket(int entityId, short velocityX, short velocity
}
@Override
public int getId() {
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.ENTITY_VELOCITY;
}
}

Some files were not shown because too many files have changed in this diff Show More