fix: re-merge connection states, remove OptifineSupport

(cherry picked from commit a0ca4895b1)
This commit is contained in:
mworzala 2024-01-16 09:47:38 -05:00 committed by Matt Worzala
parent 69aeb8e2ea
commit f4cb5272f9
30 changed files with 115 additions and 243 deletions

View File

@ -13,8 +13,6 @@ import net.minestom.server.command.CommandManager;
import net.minestom.server.event.server.ServerListPingEvent; import net.minestom.server.event.server.ServerListPingEvent;
import net.minestom.server.extras.lan.OpenToLAN; import net.minestom.server.extras.lan.OpenToLAN;
import net.minestom.server.extras.lan.OpenToLANConfig; import net.minestom.server.extras.lan.OpenToLANConfig;
import net.minestom.server.extras.optifine.OptifineSupport;
import net.minestom.server.extras.velocity.VelocityProxy;
import net.minestom.server.instance.block.BlockManager; import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.ping.ResponseData; import net.minestom.server.ping.ResponseData;
import net.minestom.server.utils.identity.NamedAndIdentified; import net.minestom.server.utils.identity.NamedAndIdentified;
@ -108,9 +106,7 @@ public class Main {
PlayerInit.init(); PlayerInit.init();
OptifineSupport.enable(); // VelocityProxy.enable("abcdef");
// VelocityProxy.enable("abc");
//BungeeCordProxy.enable(); //BungeeCordProxy.enable();
//MojangAuth.init(); //MojangAuth.init();

View File

@ -1,7 +1,5 @@
package net.minestom.demo; package net.minestom.demo;
import net.kyori.adventure.resource.ResourcePackInfo;
import net.kyori.adventure.resource.ResourcePackRequest;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.advancements.FrameType; import net.minestom.server.advancements.FrameType;
@ -40,7 +38,6 @@ import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.time.TimeUnit; import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.world.DimensionType; import net.minestom.server.world.DimensionType;
import java.net.URI;
import java.time.Duration; import java.time.Duration;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
@ -92,6 +89,12 @@ public class PlayerInit {
.addListener(AsyncPlayerConfigurationEvent.class, event -> { .addListener(AsyncPlayerConfigurationEvent.class, event -> {
final Player player = event.getPlayer(); final Player player = event.getPlayer();
try {
Thread.sleep(60 * 1000);
} catch (Exception e) {
throw new RuntimeException(e);
}
var instances = MinecraftServer.getInstanceManager().getInstances(); var instances = MinecraftServer.getInstanceManager().getInstances();
Instance instance = instances.stream().skip(new Random().nextInt(instances.size())).findFirst().orElse(null); Instance instance = instances.stream().skip(new Random().nextInt(instances.size())).findFirst().orElse(null);
event.setSpawningInstance(instance); event.setSpawningInstance(instance);

View File

@ -29,6 +29,7 @@ import net.minestom.server.thread.Acquirable;
import net.minestom.server.thread.ThreadDispatcher; import net.minestom.server.thread.ThreadDispatcher;
import net.minestom.server.timer.SchedulerManager; import net.minestom.server.timer.SchedulerManager;
import net.minestom.server.utils.PacketUtils; import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.PropertyUtils;
import net.minestom.server.utils.collection.MappedCollection; import net.minestom.server.utils.collection.MappedCollection;
import net.minestom.server.world.DimensionTypeManager; import net.minestom.server.world.DimensionTypeManager;
import net.minestom.server.world.biomes.BiomeManager; import net.minestom.server.world.biomes.BiomeManager;
@ -45,7 +46,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
final class ServerProcessImpl implements ServerProcess { final class ServerProcessImpl implements ServerProcess {
private final static Logger LOGGER = LoggerFactory.getLogger(ServerProcessImpl.class); private static final Logger LOGGER = LoggerFactory.getLogger(ServerProcessImpl.class);
private static final Boolean SHUTDOWN_ON_SIGNAL = PropertyUtils.getBoolean("minestom.shutdown-on-signal", true);
private final ExceptionManager exception; private final ExceptionManager exception;
private final ExtensionManager extension; private final ExtensionManager extension;
@ -241,7 +243,7 @@ final class ServerProcessImpl implements ServerProcess {
MinestomTerminal.start(); MinestomTerminal.start();
} }
// Stop the server on SIGINT // Stop the server on SIGINT
Runtime.getRuntime().addShutdownHook(new Thread(this::stop)); if (SHUTDOWN_ON_SIGNAL) Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
} }
@Override @Override

View File

@ -457,7 +457,7 @@ public class LivingEntity extends Entity implements EquipmentHandler {
if (this instanceof Player player) { if (this instanceof Player player) {
PlayerConnection playerConnection = player.playerConnection; PlayerConnection playerConnection = player.playerConnection;
// connection null during Player initialization (due to #super call) // connection null during Player initialization (due to #super call)
self = playerConnection != null && playerConnection.getServerState() == ConnectionState.PLAY; self = playerConnection != null && playerConnection.getConnectionState() == ConnectionState.PLAY;
} }
EntityPropertiesPacket propertiesPacket = new EntityPropertiesPacket(getEntityId(), List.of(attributeInstance)); EntityPropertiesPacket propertiesPacket = new EntityPropertiesPacket(getEntityId(), List.of(attributeInstance));
if (self) { if (self) {

View File

@ -168,10 +168,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
private final AtomicInteger teleportId = new AtomicInteger(); private final AtomicInteger teleportId = new AtomicInteger();
private int receivedTeleportId; private int receivedTeleportId;
private record PacketInState(ConnectionState state, ClientPacket packet) { private final MessagePassingQueue<ClientPacket> packets = new MpscUnboundedXaddArrayQueue<>(32);
}
private final MessagePassingQueue<PacketInState> packets = new MpscUnboundedXaddArrayQueue<>(32);
private final boolean levelFlat; private final boolean levelFlat;
private final PlayerSettings settings; private final PlayerSettings settings;
private float exp; private float exp;
@ -379,7 +376,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
* <p>This will result in them being removed from the current instance, player list, etc.</p> * <p>This will result in them being removed from the current instance, player list, etc.</p>
*/ */
public void startConfigurationPhase() { public void startConfigurationPhase() {
Check.stateCondition(playerConnection.getClientState() != ConnectionState.PLAY, Check.stateCondition(playerConnection.getConnectionState() != ConnectionState.PLAY,
"Player must be in the play state for reconfiguration."); "Player must be in the play state for reconfiguration.");
// Remove the player, then send them back to configuration // Remove the player, then send them back to configuration
@ -745,12 +742,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
sendPacket(new TimeUpdatePacket(instance.getWorldAge(), instance.getTime())); sendPacket(new TimeUpdatePacket(instance.getWorldAge(), instance.getTime()));
} }
if (dimensionChange) {
sendPacket(new SpawnPositionPacket(spawnPosition, 0)); // Without this the client gets stuck on loading terrain for a while
instance.getWorldBorder().init(this);
sendPacket(new TimeUpdatePacket(instance.getWorldAge(), instance.getTime()));
}
if (dimensionChange || firstSpawn) { if (dimensionChange || firstSpawn) {
this.inventory.update(); this.inventory.update();
sendPacket(new HeldItemChangePacket(heldSlot)); sendPacket(new HeldItemChangePacket(heldSlot));
@ -1631,10 +1622,9 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
* @param component the reason * @param component the reason
*/ */
public void kick(@NotNull Component component) { public void kick(@NotNull Component component) {
final ConnectionState connectionState = playerConnection.getServerState();
// Packet type depends on the current player connection state // Packet type depends on the current player connection state
final ServerPacket disconnectPacket; final ServerPacket disconnectPacket;
if (connectionState == ConnectionState.LOGIN) { if (playerConnection.getConnectionState() == ConnectionState.LOGIN) {
disconnectPacket = new LoginDisconnectPacket(component); disconnectPacket = new LoginDisconnectPacket(component);
} else { } else {
disconnectPacket = new DisconnectPacket(component); disconnectPacket = new DisconnectPacket(component);
@ -2042,8 +2032,8 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
* *
* @param packet the packet to add in the queue * @param packet the packet to add in the queue
*/ */
public void addPacketToQueue(@NotNull ConnectionState state, @NotNull ClientPacket packet) { public void addPacketToQueue(@NotNull ClientPacket packet) {
this.packets.offer(new PacketInState(state, packet)); this.packets.offer(packet);
} }
@ApiStatus.Internal @ApiStatus.Internal
@ -2055,7 +2045,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
} }
final PacketListenerManager manager = MinecraftServer.getPacketListenerManager(); final PacketListenerManager manager = MinecraftServer.getPacketListenerManager();
// This method is NOT thread-safe // This method is NOT thread-safe
this.packets.drain(packet -> manager.processClientPacket(packet.state, packet.packet, playerConnection), ServerFlag.PACKET_PER_TICK); this.packets.drain(packet -> manager.processClientPacket(packet, playerConnection), ServerFlag.PACKET_PER_TICK);
} }
/** /**
@ -2065,7 +2055,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
*/ */
public void refreshLatency(int latency) { public void refreshLatency(int latency) {
this.latency = latency; this.latency = latency;
if (getPlayerConnection().getServerState() == ConnectionState.PLAY) { if (getPlayerConnection().getConnectionState() == ConnectionState.PLAY) {
PacketUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LATENCY, infoEntry())); PacketUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LATENCY, infoEntry()));
} }
} }
@ -2482,7 +2472,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
this.allowServerListings = allowServerListings; this.allowServerListings = allowServerListings;
// TODO: Use the metadata object here // TODO: Use the metadata object here
boolean isInPlayState = getPlayerConnection().getServerState() == ConnectionState.PLAY; boolean isInPlayState = getPlayerConnection().getConnectionState() == ConnectionState.PLAY;
if (isInPlayState) metadata.setNotifyAboutChanges(false); if (isInPlayState) metadata.setNotifyAboutChanges(false);
metadata.setIndex((byte) 17, Metadata.Byte(displayedSkinParts)); metadata.setIndex((byte) 17, Metadata.Byte(displayedSkinParts));
metadata.setIndex((byte) 18, Metadata.Byte((byte) (this.mainHand == MainHand.RIGHT ? 1 : 0))); metadata.setIndex((byte) 18, Metadata.Byte((byte) (this.mainHand == MainHand.RIGHT ? 1 : 0)));

View File

@ -1,36 +0,0 @@
package net.minestom.server.extras.optifine;
import net.minestom.server.MinecraftServer;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.validate.Check;
import net.minestom.server.world.biomes.Biome;
import net.minestom.server.world.biomes.BiomeManager;
/**
* Hacky class for Optifine because of an issue making the client crash if biomes 'swamp' and 'swamp_hills'
* are not registered.
* <p>
* Can be removed anytime, hope that it will be fixed.
*/
public final class OptifineSupport {
private static volatile boolean enabled;
/**
* Enables optifine support by registering the required biomes.
*
* @throws IllegalStateException if optifine support is already enabled
*/
public static void enable() {
Check.stateCondition(enabled, "Optifine support is already enabled!");
OptifineSupport.enabled = true;
BiomeManager biomeManager = MinecraftServer.getBiomeManager();
biomeManager.addBiome(Biome.builder().name(NamespaceID.from("minecraft:swamp")).build());
biomeManager.addBiome(Biome.builder().name(NamespaceID.from("minecraft:swamp_hills")).build());
}
public static boolean isEnabled() {
return enabled;
}
}

View File

@ -100,13 +100,12 @@ public final class PacketListenerManager {
/** /**
* Processes a packet by getting its {@link PacketPlayListenerConsumer} and calling all the packet listeners. * Processes a packet by getting its {@link PacketPlayListenerConsumer} and calling all the packet listeners.
* *
* @param state the current connection state
* @param packet the received packet * @param packet the received packet
* @param connection the connection of the player who sent the packet * @param connection the connection of the player who sent the packet
* @param <T> the packet type * @param <T> the packet type
*/ */
public <T extends ClientPacket> void processClientPacket(@NotNull ConnectionState state, @NotNull T packet, @NotNull PlayerConnection connection) { public <T extends ClientPacket> void processClientPacket(@NotNull T packet, @NotNull PlayerConnection connection) {
final ConnectionState state = connection.getConnectionState();
final Class clazz = packet.getClass(); final Class clazz = packet.getClass();
PacketPrePlayListenerConsumer<T> packetListenerConsumer = listeners[state.ordinal()].get(clazz); PacketPrePlayListenerConsumer<T> packetListenerConsumer = listeners[state.ordinal()].get(clazz);

View File

@ -4,7 +4,6 @@ import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket; import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket;
import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public final class ConfigListener { public final class ConfigListener {

View File

@ -40,13 +40,9 @@ public final class HandshakeListener {
public static void listener(@NotNull ClientHandshakePacket packet, @NotNull PlayerConnection connection) { public static void listener(@NotNull ClientHandshakePacket packet, @NotNull PlayerConnection connection) {
String address = packet.serverAddress(); String address = packet.serverAddress();
switch (packet.intent()) { switch (packet.intent()) {
case 1 -> { case 1 -> connection.setConnectionState(ConnectionState.STATUS);
connection.setClientState(ConnectionState.STATUS);
connection.setServerState(ConnectionState.STATUS);
}
case 2 -> { case 2 -> {
connection.setClientState(ConnectionState.LOGIN); connection.setConnectionState(ConnectionState.LOGIN);
connection.setServerState(ConnectionState.LOGIN);
if (packet.protocolVersion() != MinecraftServer.PROTOCOL_VERSION) { if (packet.protocolVersion() != MinecraftServer.PROTOCOL_VERSION) {
// Incorrect client version // Incorrect client version
disconnect(connection, INVALID_VERSION_TEXT); disconnect(connection, INVALID_VERSION_TEXT);

View File

@ -59,6 +59,12 @@ public final class ConnectionManager {
// Players in play state // Players in play state
private final Set<Player> playPlayers = new CopyOnWriteArraySet<>(); private final Set<Player> playPlayers = new CopyOnWriteArraySet<>();
// The players who need keep alive ticks. This was added because we may not send a keep alive in
// the time after sending finish configuration but before receiving configuration end (to swap to play).
// I(mattw) could not come up with a better way to express this besides completely splitting client/server
// states. Perhaps there will be an improvement in the future.
private final Set<Player> keepAlivePlayers = new CopyOnWriteArraySet<>();
private final Set<Player> unmodifiableConfigurationPlayers = Collections.unmodifiableSet(configurationPlayers); private final Set<Player> unmodifiableConfigurationPlayers = Collections.unmodifiableSet(configurationPlayers);
private final Set<Player> unmodifiablePlayPlayers = Collections.unmodifiableSet(playPlayers); private final Set<Player> unmodifiablePlayPlayers = Collections.unmodifiableSet(playPlayers);
@ -238,7 +244,6 @@ public final class ConnectionManager {
// Send login success packet (and switch to configuration phase) // Send login success packet (and switch to configuration phase)
LoginSuccessPacket loginSuccessPacket = new LoginSuccessPacket(player.getUuid(), player.getUsername(), 0); LoginSuccessPacket loginSuccessPacket = new LoginSuccessPacket(player.getUuid(), player.getUsername(), 0);
playerConnection.sendPacket(loginSuccessPacket); playerConnection.sendPacket(loginSuccessPacket);
configurationPlayers.add(player);
}); });
if (DebugUtils.INSIDE_TEST) configFuture.join(); if (DebugUtils.INSIDE_TEST) configFuture.join();
} }
@ -251,6 +256,12 @@ public final class ConnectionManager {
@ApiStatus.Internal @ApiStatus.Internal
public void doConfiguration(@NotNull Player player, boolean isFirstConfig) { public void doConfiguration(@NotNull Player player, boolean isFirstConfig) {
if (isFirstConfig) {
configurationPlayers.add(player);
keepAlivePlayers.add(player);
}
player.getPlayerConnection().setConnectionState(ConnectionState.CONFIGURATION);
CompletableFuture<Void> configFuture = AsyncUtils.runAsync(() -> { CompletableFuture<Void> configFuture = AsyncUtils.runAsync(() -> {
player.sendPacket(PluginMessagePacket.getBrandPacket()); player.sendPacket(PluginMessagePacket.getBrandPacket());
@ -276,6 +287,7 @@ public final class ConnectionManager {
var packFuture = player.getResourcePackFuture(); var packFuture = player.getResourcePackFuture();
if (packFuture != null) packFuture.join(); if (packFuture != null) packFuture.join();
keepAlivePlayers.remove(player);
player.setPendingInstance(spawningInstance); player.setPendingInstance(spawningInstance);
player.sendPacket(new FinishConfigurationPacket()); player.sendPacket(new FinishConfigurationPacket());
}); });
@ -301,6 +313,7 @@ public final class ConnectionManager {
if (player == null) return; if (player == null) return;
this.configurationPlayers.remove(player); this.configurationPlayers.remove(player);
this.playPlayers.remove(player); this.playPlayers.remove(player);
this.keepAlivePlayers.remove(player);
} }
/** /**
@ -309,6 +322,7 @@ public final class ConnectionManager {
public synchronized void shutdown() { public synchronized void shutdown() {
this.configurationPlayers.clear(); this.configurationPlayers.clear();
this.playPlayers.clear(); this.playPlayers.clear();
this.keepAlivePlayers.clear();
this.connectionPlayerMap.clear(); this.connectionPlayerMap.clear();
} }
@ -317,8 +331,7 @@ public final class ConnectionManager {
updateWaitingPlayers(); updateWaitingPlayers();
// Send keep alive packets // Send keep alive packets
handleKeepAlive(configurationPlayers, tickStart); handleKeepAlive(keepAlivePlayers, tickStart);
handleKeepAlive(playPlayers, tickStart);
// Interpret packets for configuration players // Interpret packets for configuration players
configurationPlayers.forEach(Player::interpretPacketQueue); configurationPlayers.forEach(Player::interpretPacketQueue);
@ -330,8 +343,9 @@ public final class ConnectionManager {
@ApiStatus.Internal @ApiStatus.Internal
public void updateWaitingPlayers() { public void updateWaitingPlayers() {
this.waitingPlayers.drain(player -> { this.waitingPlayers.drain(player -> {
configurationPlayers.remove(player); player.getPlayerConnection().setConnectionState(ConnectionState.PLAY);
playPlayers.add(player); playPlayers.add(player);
keepAlivePlayers.add(player);
// Spawn the player at Player#getRespawnPoint // Spawn the player at Player#getRespawnPoint
CompletableFuture<Void> spawnFuture = player.UNSAFE_init(); CompletableFuture<Void> spawnFuture = player.UNSAFE_init();

View File

@ -5,9 +5,6 @@ import net.minestom.server.listener.manager.PacketListenerManager;
import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.client.ClientPacketsHandler; import net.minestom.server.network.packet.client.ClientPacketsHandler;
import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket; import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket;
import net.minestom.server.network.packet.client.play.ClientPlayerPositionAndRotationPacket;
import net.minestom.server.network.packet.client.play.ClientPlayerPositionPacket;
import net.minestom.server.network.packet.client.play.ClientPlayerRotationPacket;
import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerConnection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -53,25 +50,16 @@ public class PacketProcessor {
} }
public ClientPacket process(@NotNull PlayerConnection connection, int packetId, ByteBuffer body) { public ClientPacket process(@NotNull PlayerConnection connection, int packetId, ByteBuffer body) {
final ClientPacket packet = create(connection.getClientState(), packetId, body); final ClientPacket packet = create(connection.getConnectionState(), packetId, body);
final ConnectionState state = connection.getClientState();
// If the packet intends to switch state, do it now. switch (connection.getConnectionState()) {
// Since packets are processed next tick for players, we have to switch immediately.
// TODO HOWEVER THIS WILL NOT ACTUALLY WORK BECAUSE WHEN WE QUEUE THE PACKET IT HAS THE WRONG LISTENER.
var nextState = packet.nextState();
if (nextState != null && state != nextState) {
connection.setClientState(nextState);
}
switch (state) {
// Process all pre-config packets immediately // Process all pre-config packets immediately
case HANDSHAKE, STATUS, LOGIN -> packetListenerManager.processClientPacket(state, packet, connection); case HANDSHAKE, STATUS, LOGIN -> packetListenerManager.processClientPacket(packet, connection);
// Process config and play packets on the next tick // Process config and play packets on the next tick
case CONFIGURATION, PLAY -> { case CONFIGURATION, PLAY -> {
final Player player = connection.getPlayer(); final Player player = connection.getPlayer();
assert player != null; assert player != null;
player.addPacketToQueue(state, packet); player.addPacketToQueue(packet);
} }
} }
return packet; return packet;

View File

@ -1,10 +1,8 @@
package net.minestom.server.network.packet.client.configuration; package net.minestom.server.network.packet.client.configuration;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public record ClientFinishConfigurationPacket() implements ClientPacket { public record ClientFinishConfigurationPacket() implements ClientPacket {
@ -16,8 +14,4 @@ public record ClientFinishConfigurationPacket() implements ClientPacket {
public void write(@NotNull NetworkBuffer writer) { public void write(@NotNull NetworkBuffer writer) {
} }
@Override
public @NotNull ConnectionState nextState() {
return ConnectionState.PLAY;
}
} }

View File

@ -1,10 +1,8 @@
package net.minestom.server.network.packet.client.login; package net.minestom.server.network.packet.client.login;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer; import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public record ClientLoginAcknowledgedPacket() implements ClientPacket { public record ClientLoginAcknowledgedPacket() implements ClientPacket {
@ -16,8 +14,4 @@ public record ClientLoginAcknowledgedPacket() implements ClientPacket {
public void write(@NotNull NetworkBuffer writer) { public void write(@NotNull NetworkBuffer writer) {
} }
@Override
public @NotNull ConnectionState nextState() {
return ConnectionState.CONFIGURATION;
}
} }

View File

@ -22,15 +22,4 @@ public non-sealed interface ServerPacket extends NetworkBuffer.Writer, SendableP
*/ */
int getId(@NotNull ConnectionState state); int getId(@NotNull ConnectionState state);
/**
* If not null, the server will switch state immediately after sending this packet
*
* <p>WARNING: A cached or framed packet will currently never go through writeServerPacketSync,
* so a state change inside one of them will never actually be triggered. Currently, cached
* packets are never used for packets that change state, so this is not a problem.</p>
*/
default @Nullable ConnectionState nextState() {
return null;
}
} }

View File

@ -6,7 +6,6 @@ import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.PacketUtils; import net.minestom.server.utils.PacketUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public record FinishConfigurationPacket() implements ServerPacket { public record FinishConfigurationPacket() implements ServerPacket {
@ -25,9 +24,4 @@ public record FinishConfigurationPacket() implements ServerPacket {
default -> PacketUtils.invalidPacketState(getClass(), state, ConnectionState.CONFIGURATION); default -> PacketUtils.invalidPacketState(getClass(), state, ConnectionState.CONFIGURATION);
}; };
} }
@Override
public @NotNull ConnectionState nextState() {
return ConnectionState.PLAY;
}
} }

View File

@ -6,7 +6,6 @@ import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.utils.PacketUtils; import net.minestom.server.utils.PacketUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID; import java.util.UUID;
@ -32,9 +31,4 @@ public record LoginSuccessPacket(@NotNull UUID uuid, @NotNull String username, i
default -> PacketUtils.invalidPacketState(getClass(), state, ConnectionState.LOGIN); default -> PacketUtils.invalidPacketState(getClass(), state, ConnectionState.LOGIN);
}; };
} }
@Override
public @NotNull ConnectionState nextState() {
return ConnectionState.CONFIGURATION;
}
} }

View File

@ -22,8 +22,4 @@ public record StartConfigurationPacket() implements ServerPacket {
}; };
} }
@Override
public @NotNull ConnectionState nextState() {
return ConnectionState.CONFIGURATION;
}
} }

View File

@ -16,7 +16,7 @@ public class FakePlayerConnection extends PlayerConnection {
@Override @Override
public void sendPacket(@NotNull SendablePacket packet) { public void sendPacket(@NotNull SendablePacket packet) {
FakePlayerController controller = getFakePlayer().getController(); FakePlayerController controller = getFakePlayer().getController();
final ServerPacket serverPacket = SendablePacket.extractServerPacket(getServerState(), packet); final ServerPacket serverPacket = SendablePacket.extractServerPacket(getConnectionState(), packet);
controller.consumePacket(serverPacket); controller.consumePacket(serverPacket);
} }

View File

@ -20,15 +20,13 @@ import java.util.List;
*/ */
public abstract class PlayerConnection { public abstract class PlayerConnection {
private Player player; private Player player;
private volatile ConnectionState clientState; private volatile ConnectionState connectionState;
private volatile ConnectionState serverState;
private PlayerPublicKey playerPublicKey; private PlayerPublicKey playerPublicKey;
volatile boolean online; volatile boolean online;
public PlayerConnection() { public PlayerConnection() {
this.online = true; this.online = true;
this.clientState = ConnectionState.HANDSHAKE; this.connectionState = ConnectionState.HANDSHAKE;
this.serverState = ConnectionState.HANDSHAKE;
} }
/** /**
@ -141,14 +139,8 @@ public abstract class PlayerConnection {
return online; return online;
} }
@ApiStatus.Internal public void setConnectionState(@NotNull ConnectionState connectionState) {
public void setClientState(@NotNull ConnectionState state) { this.connectionState = connectionState;
this.clientState = state;
}
@ApiStatus.Internal
public void setServerState(@NotNull ConnectionState state) {
this.serverState = state;
} }
/** /**
@ -156,17 +148,8 @@ public abstract class PlayerConnection {
* *
* @return the client connection state * @return the client connection state
*/ */
public @NotNull ConnectionState getClientState() { public @NotNull ConnectionState getConnectionState() {
return clientState; return connectionState;
}
/**
* Gets the server connection state.
*
* @return the server connection state
*/
public @NotNull ConnectionState getServerState() {
return serverState;
} }
public PlayerPublicKey playerPublicKey() { public PlayerPublicKey playerPublicKey() {
@ -180,8 +163,7 @@ public abstract class PlayerConnection {
@Override @Override
public String toString() { public String toString() {
return "PlayerConnection{" + return "PlayerConnection{" +
"clientState=" + clientState + "connectionState=" + connectionState +
", serverState=" + serverState +
", identifier=" + getIdentifier() + ", identifier=" + getIdentifier() +
'}'; '}';
} }

View File

@ -112,7 +112,7 @@ public class PlayerSocketConnection extends PlayerConnection {
MinecraftServer.getExceptionManager().handleException(e); MinecraftServer.getExceptionManager().handleException(e);
} finally { } finally {
if (payload.position() != payload.limit()) { if (payload.position() != payload.limit()) {
LOGGER.warn("WARNING: Packet ({}) 0x{} not fully read ({}) {}", getClientState(), Integer.toHexString(id), payload, packet); LOGGER.warn("WARNING: Packet ({}) 0x{} not fully read ({}) {}", getConnectionState(), Integer.toHexString(id), payload, packet);
} }
} }
}); });
@ -290,14 +290,14 @@ public class PlayerSocketConnection extends PlayerConnection {
/** /**
* Adds an entry to the plugin request map. * Adds an entry to the plugin request map.
* <p> * <p>
* Only working if {@link #getServerState()} ()} is {@link net.minestom.server.network.ConnectionState#LOGIN}. * Only working if {@link #getConnectionState()} is {@link net.minestom.server.network.ConnectionState#LOGIN}.
* *
* @param messageId the message id * @param messageId the message id
* @param channel the packet channel * @param channel the packet channel
* @throws IllegalStateException if a messageId with the value {@code messageId} already exists for this connection * @throws IllegalStateException if a messageId with the value {@code messageId} already exists for this connection
*/ */
public void addPluginRequestEntry(int messageId, @NotNull String channel) { public void addPluginRequestEntry(int messageId, @NotNull String channel) {
if (getServerState() != ConnectionState.LOGIN) { if (!getConnectionState().equals(ConnectionState.LOGIN)) {
return; return;
} }
Check.stateCondition(pluginRequestMap.containsKey(messageId), "You cannot have two messageId with the same value"); Check.stateCondition(pluginRequestMap.containsKey(messageId), "You cannot have two messageId with the same value");
@ -317,10 +317,10 @@ public class PlayerSocketConnection extends PlayerConnection {
} }
@Override @Override
public void setClientState(@NotNull ConnectionState state) { public void setConnectionState(@NotNull ConnectionState connectionState) {
super.setClientState(state); super.setConnectionState(connectionState);
// Clear the plugin request map (since it is not used anymore) // Clear the plugin request map (since it is not used anymore)
if (state == ConnectionState.PLAY) { if (connectionState.equals(ConnectionState.PLAY)) {
this.pluginRequestMap.clear(); this.pluginRequestMap.clear();
} }
} }
@ -338,24 +338,21 @@ public class PlayerSocketConnection extends PlayerConnection {
final Player player = getPlayer(); final Player player = getPlayer();
// Outgoing event // Outgoing event
if (player != null && outgoing.hasListener()) { if (player != null && outgoing.hasListener()) {
final ServerPacket serverPacket = SendablePacket.extractServerPacket(getServerState(), packet); final ServerPacket serverPacket = SendablePacket.extractServerPacket(getConnectionState(), packet);
PlayerPacketOutEvent event = new PlayerPacketOutEvent(player, serverPacket); PlayerPacketOutEvent event = new PlayerPacketOutEvent(player, serverPacket);
outgoing.call(event); outgoing.call(event);
if (event.isCancelled()) return; if (event.isCancelled()) return;
} }
// Write packet // Write packet
// WARNING: A cached or framed packet will currently never go through writeServerPacketSync,
// so a state change inside one of them will never actually be triggered. Currently, cached
// packets are never used for packets that change state, so this is not a problem.
if (packet instanceof ServerPacket serverPacket) { if (packet instanceof ServerPacket serverPacket) {
writeServerPacketSync(serverPacket, compressed); writeServerPacketSync(serverPacket, compressed);
} else if (packet instanceof FramedPacket framedPacket) { } else if (packet instanceof FramedPacket framedPacket) {
var buffer = framedPacket.body(); var buffer = framedPacket.body();
writeBufferSync(buffer, 0, buffer.limit()); writeBufferSync(buffer, 0, buffer.limit());
} else if (packet instanceof CachedPacket cachedPacket) { } else if (packet instanceof CachedPacket cachedPacket) {
var buffer = cachedPacket.body(getServerState()); var buffer = cachedPacket.body(getConnectionState());
if (buffer != null) writeBufferSync(buffer, buffer.position(), buffer.remaining()); if (buffer != null) writeBufferSync(buffer, buffer.position(), buffer.remaining());
else writeServerPacketSync(cachedPacket.packet(getServerState()), compressed); else writeServerPacketSync(cachedPacket.packet(getConnectionState()), compressed);
} else if (packet instanceof LazyPacket lazyPacket) { } else if (packet instanceof LazyPacket lazyPacket) {
writeServerPacketSync(lazyPacket.packet(), compressed); writeServerPacketSync(lazyPacket.packet(), compressed);
} else { } else {
@ -372,15 +369,8 @@ public class PlayerSocketConnection extends PlayerConnection {
} }
} }
try (var hold = ObjectPool.PACKET_POOL.hold()) { try (var hold = ObjectPool.PACKET_POOL.hold()) {
var state = getServerState(); var buffer = PacketUtils.createFramedPacket(getConnectionState(), hold.get(), serverPacket, compressed);
var buffer = PacketUtils.createFramedPacket(state, hold.get(), serverPacket, compressed);
writeBufferSync(buffer, 0, buffer.limit()); writeBufferSync(buffer, 0, buffer.limit());
// If this packet has a state change, apply it.
var nextState = serverPacket.nextState();
if (nextState != null && state != nextState) {
setServerState(nextState);
}
} }
} }

View File

@ -1,20 +1,17 @@
package net.minestom.server.command; package net.minestom.server.command;
import net.minestom.server.network.ConnectionState;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.suggestion.SuggestionEntry; import net.minestom.server.command.builder.suggestion.SuggestionEntry;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.network.packet.client.play.ClientTabCompletePacket; import net.minestom.server.network.packet.client.play.ClientTabCompletePacket;
import net.minestom.server.network.packet.server.play.TabCompletePacket; import net.minestom.server.network.packet.server.play.TabCompletePacket;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.List; import java.util.List;
import static net.minestom.server.command.builder.arguments.ArgumentType.Literal; import static net.minestom.server.command.builder.arguments.ArgumentType.*;
import static net.minestom.server.command.builder.arguments.ArgumentType.Word;
import static net.minestom.server.command.builder.arguments.ArgumentType.Integer;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
@ -41,7 +38,7 @@ public class CommandSuggestionIntegrationTest {
env.process().command().register(command); env.process().command().register(command);
var listener = connection.trackIncoming(TabCompletePacket.class); var listener = connection.trackIncoming(TabCompletePacket.class);
player.addPacketToQueue(ConnectionState.PLAY, new ClientTabCompletePacket(3, "test te")); player.addPacketToQueue(new ClientTabCompletePacket(3, "test te"));
player.interpretPacketQueue(); player.interpretPacketQueue();
listener.assertSingle(tabCompletePacket -> { listener.assertSingle(tabCompletePacket -> {
@ -69,7 +66,7 @@ public class CommandSuggestionIntegrationTest {
env.process().command().register(command); env.process().command().register(command);
var listener = connection.trackIncoming(TabCompletePacket.class); var listener = connection.trackIncoming(TabCompletePacket.class);
player.addPacketToQueue(ConnectionState.PLAY, new ClientTabCompletePacket(1, "foo 1")); player.addPacketToQueue(new ClientTabCompletePacket(1, "foo 1"));
player.interpretPacketQueue(); player.interpretPacketQueue();
listener.assertSingle(tabCompletePacket -> { listener.assertSingle(tabCompletePacket -> {

View File

@ -1,13 +1,12 @@
package net.minestom.server.entity; package net.minestom.server.entity;
import net.minestom.server.network.ConnectionState;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.event.player.PlayerChangeHeldSlotEvent; import net.minestom.server.event.player.PlayerChangeHeldSlotEvent;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.network.packet.client.play.ClientHeldItemChangePacket; import net.minestom.server.network.packet.client.play.ClientHeldItemChangePacket;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -25,7 +24,7 @@ public class PlayerHeldIntegrationTest {
assertEquals(ItemStack.AIR, player.getItemInMainHand()); assertEquals(ItemStack.AIR, player.getItemInMainHand());
assertEquals(0, player.getHeldSlot()); assertEquals(0, player.getHeldSlot());
player.addPacketToQueue(ConnectionState.PLAY, new ClientHeldItemChangePacket((short) 1)); player.addPacketToQueue(new ClientHeldItemChangePacket((short) 1));
player.interpretPacketQueue(); player.interpretPacketQueue();
assertEquals(ItemStack.of(Material.STONE), player.getItemInMainHand()); assertEquals(ItemStack.of(Material.STONE), player.getItemInMainHand());
@ -42,7 +41,7 @@ public class PlayerHeldIntegrationTest {
assertEquals(ItemStack.AIR, player.getItemInMainHand()); assertEquals(ItemStack.AIR, player.getItemInMainHand());
assertEquals(0, player.getHeldSlot()); assertEquals(0, player.getHeldSlot());
player.addPacketToQueue(ConnectionState.PLAY, new ClientHeldItemChangePacket((short) 1)); player.addPacketToQueue(new ClientHeldItemChangePacket((short) 1));
var listener = env.listen(PlayerChangeHeldSlotEvent.class); var listener = env.listen(PlayerChangeHeldSlotEvent.class);
listener.followup(event -> { listener.followup(event -> {
assertEquals(player, event.getPlayer()); assertEquals(player, event.getPlayer());

View File

@ -1,8 +1,5 @@
package net.minestom.server.entity.player; package net.minestom.server.entity.player;
import net.minestom.server.network.ConnectionState;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode; import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
@ -11,6 +8,8 @@ import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.network.packet.client.play.ClientPlayerBlockPlacementPacket; import net.minestom.server.network.packet.client.play.ClientPlayerBlockPlacementPacket;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
@ -39,7 +38,7 @@ public class PlayerBlockPlacementIntegrationTest {
1f, 1f, 1f, 1f, 1f, 1f,
false, 0 false, 0
); );
player.addPacketToQueue(ConnectionState.PLAY, packet); player.addPacketToQueue(packet);
player.interpretPacketQueue(); player.interpretPacketQueue();
var placedBlock = instance.getBlock(1, 41, 0); var placedBlock = instance.getBlock(1, 41, 0);

View File

@ -1,21 +1,20 @@
package net.minestom.server.entity.player; package net.minestom.server.entity.player;
import net.minestom.server.event.player.PlayerGameModeChangeEvent;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.message.ChatMessageType;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.client.common.ClientSettingsPacket;
import net.minestom.testing.Collector;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode; import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.event.player.PlayerGameModeChangeEvent;
import net.minestom.server.message.ChatMessageType;
import net.minestom.server.network.packet.client.common.ClientSettingsPacket;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.packet.server.play.*;
import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.NamespaceID;
import net.minestom.server.world.DimensionType; import net.minestom.server.world.DimensionType;
import net.minestom.testing.Collector;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -85,7 +84,7 @@ public class PlayerIntegrationTest {
env.tick(); env.tick();
env.tick(); env.tick();
player.addPacketToQueue(ConnectionState.PLAY, packet); player.addPacketToQueue(packet);
var collector = connection.trackIncoming(); var collector = connection.trackIncoming();
env.tick(); env.tick();
env.tick(); env.tick();

View File

@ -1,11 +1,6 @@
package net.minestom.server.entity.player; package net.minestom.server.entity.player;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.network.ConnectionState;
import net.minestom.testing.Collector;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import net.minestom.testing.TestConnection;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
@ -17,6 +12,10 @@ import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.network.packet.server.play.EntityPositionPacket; import net.minestom.server.network.packet.server.play.EntityPositionPacket;
import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.testing.Collector;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import net.minestom.testing.TestConnection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -34,12 +33,12 @@ public class PlayerMovementIntegrationTest {
var instance = env.createFlatInstance(); var instance = env.createFlatInstance();
var p1 = env.createPlayer(instance, new Pos(0, 40, 0)); var p1 = env.createPlayer(instance, new Pos(0, 40, 0));
// No confirmation // No confirmation
p1.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
p1.interpretPacketQueue(); p1.interpretPacketQueue();
assertEquals(new Pos(0, 40, 0), p1.getPosition()); assertEquals(new Pos(0, 40, 0), p1.getPosition());
// Confirmation // Confirmation
p1.addPacketToQueue(ConnectionState.PLAY, new ClientTeleportConfirmPacket(p1.getLastSentTeleportId())); p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId()));
p1.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
p1.interpretPacketQueue(); p1.interpretPacketQueue();
assertEquals(new Pos(0.2, 40, 0), p1.getPosition()); assertEquals(new Pos(0.2, 40, 0), p1.getPosition());
} }
@ -52,9 +51,9 @@ public class PlayerMovementIntegrationTest {
var p1 = env.createPlayer(instance, new Pos(0, 40, 0)); var p1 = env.createPlayer(instance, new Pos(0, 40, 0));
connection.connect(instance, new Pos(0, 40, 0)).join(); connection.connect(instance, new Pos(0, 40, 0)).join();
p1.addPacketToQueue(ConnectionState.PLAY, new ClientTeleportConfirmPacket(p1.getLastSentTeleportId())); p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId()));
p1.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true)); p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
p1.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Pos(0.4, 40, 0), true)); p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.4, 40, 0), true));
var tracker = connection.trackIncoming(EntityPositionPacket.class); var tracker = connection.trackIncoming(EntityPositionPacket.class);
p1.interpretPacketQueue(); p1.interpretPacketQueue();
@ -76,42 +75,42 @@ public class PlayerMovementIntegrationTest {
final Player player = future.join(); final Player player = future.join();
// Initial join // Initial join
chunkDataPacketCollector.assertCount(MathUtils.square(viewDiameter)); chunkDataPacketCollector.assertCount(MathUtils.square(viewDiameter));
player.addPacketToQueue(ConnectionState.PLAY, new ClientTeleportConfirmPacket(player.getLastSentTeleportId())); player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId()));
// Move to next chunk // Move to next chunk
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(-0.5, 40, 0.5), true)); player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, 0.5), true));
player.interpretPacketQueue(); player.interpretPacketQueue();
chunkDataPacketCollector.assertCount(viewDiameter); chunkDataPacketCollector.assertCount(viewDiameter);
// Move to next chunk // Move to next chunk
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(-0.5, 40, -0.5), true)); player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(-0.5, 40, -0.5), true));
player.interpretPacketQueue(); player.interpretPacketQueue();
chunkDataPacketCollector.assertCount(viewDiameter); chunkDataPacketCollector.assertCount(viewDiameter);
// Move to next chunk // Move to next chunk
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true)); player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true));
player.interpretPacketQueue(); player.interpretPacketQueue();
chunkDataPacketCollector.assertCount(viewDiameter); chunkDataPacketCollector.assertCount(viewDiameter);
// Move to next chunk // Move to next chunk
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(0.5, 40, 0.5), true)); player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, 0.5), true));
player.interpretPacketQueue(); player.interpretPacketQueue();
chunkDataPacketCollector.assertEmpty(); chunkDataPacketCollector.assertEmpty();
// Move to next chunk // Move to next chunk
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true)); player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(0.5, 40, -0.5), true));
player.interpretPacketQueue(); player.interpretPacketQueue();
chunkDataPacketCollector.assertEmpty(); chunkDataPacketCollector.assertEmpty();
// Move to next chunk // Move to next chunk
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class); chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
// Abuse the fact that there is no delta check // Abuse the fact that there is no delta check
player.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Vec(16.5, 40, -16.5), true)); player.addPacketToQueue(new ClientPlayerPositionPacket(new Vec(16.5, 40, -16.5), true));
player.interpretPacketQueue(); player.interpretPacketQueue();
chunkDataPacketCollector.assertCount(viewDiameter * 2 - 1); chunkDataPacketCollector.assertCount(viewDiameter * 2 - 1);
} }

View File

@ -3,7 +3,6 @@ package net.minestom.server.entity.player;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.client.play.ClientStatusPacket; import net.minestom.server.network.packet.client.play.ClientStatusPacket;
import net.minestom.server.network.packet.server.play.ChunkDataPacket; import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.network.packet.server.play.UnloadChunkPacket; import net.minestom.server.network.packet.server.play.UnloadChunkPacket;
@ -16,7 +15,8 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@EnvTest @EnvTest
@ -58,7 +58,7 @@ public class PlayerRespawnChunkIntegrationTest {
var loadChunkTracker = connection.trackIncoming(ChunkDataPacket.class); var loadChunkTracker = connection.trackIncoming(ChunkDataPacket.class);
player.setHealth(0); player.setHealth(0);
player.addPacketToQueue(ConnectionState.PLAY, new ClientStatusPacket(ClientStatusPacket.Action.PERFORM_RESPAWN)); player.addPacketToQueue(new ClientStatusPacket(ClientStatusPacket.Action.PERFORM_RESPAWN));
player.interpretPacketQueue(); player.interpretPacketQueue();
List<ChunkDataPacket> dataPacketList = loadChunkTracker.collect(); List<ChunkDataPacket> dataPacketList = loadChunkTracker.collect();
Set<ChunkDataPacket> duplicateCheck = new HashSet<>(); Set<ChunkDataPacket> duplicateCheck = new HashSet<>();

View File

@ -1,8 +1,5 @@
package net.minestom.server.inventory.click.integration; package net.minestom.server.inventory.click.integration;
import net.minestom.server.network.ConnectionState;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.event.inventory.InventoryPreClickEvent;
@ -13,6 +10,8 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.network.packet.client.play.ClientClickWindowPacket; import net.minestom.server.network.packet.client.play.ClientClickWindowPacket;
import net.minestom.server.utils.inventory.PlayerInventoryUtils; import net.minestom.server.utils.inventory.PlayerInventoryUtils;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.List; import java.util.List;
@ -184,7 +183,7 @@ public class HeldClickIntegrationTest {
slot = slot - 9 + offset; slot = slot - 9 + offset;
} }
} }
player.addPacketToQueue(ConnectionState.PLAY, new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) target, player.addPacketToQueue(new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) target,
ClientClickWindowPacket.ClickType.SWAP, List.of(), ItemStack.AIR)); ClientClickWindowPacket.ClickType.SWAP, List.of(), ItemStack.AIR));
player.interpretPacketQueue(); player.interpretPacketQueue();
} }

View File

@ -1,9 +1,6 @@
package net.minestom.server.inventory.click.integration; package net.minestom.server.inventory.click.integration;
import net.minestom.server.network.ConnectionState;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.event.inventory.InventoryPreClickEvent;
@ -14,6 +11,8 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.network.packet.client.play.ClientClickWindowPacket; import net.minestom.server.network.packet.client.play.ClientClickWindowPacket;
import net.minestom.server.utils.inventory.PlayerInventoryUtils; import net.minestom.server.utils.inventory.PlayerInventoryUtils;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.List; import java.util.List;
@ -167,7 +166,7 @@ public class LeftClickIntegrationTest {
slot = slot - 9 + offset; slot = slot - 9 + offset;
} }
} }
player.addPacketToQueue(ConnectionState.PLAY, new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) 0, player.addPacketToQueue(new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) 0,
ClientClickWindowPacket.ClickType.PICKUP, List.of(), ItemStack.AIR)); ClientClickWindowPacket.ClickType.PICKUP, List.of(), ItemStack.AIR));
player.interpretPacketQueue(); player.interpretPacketQueue();
} }

View File

@ -1,8 +1,5 @@
package net.minestom.server.inventory.click.integration; package net.minestom.server.inventory.click.integration;
import net.minestom.server.network.ConnectionState;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.inventory.InventoryPreClickEvent; import net.minestom.server.event.inventory.InventoryPreClickEvent;
@ -13,6 +10,8 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.network.packet.client.play.ClientClickWindowPacket; import net.minestom.server.network.packet.client.play.ClientClickWindowPacket;
import net.minestom.server.utils.inventory.PlayerInventoryUtils; import net.minestom.server.utils.inventory.PlayerInventoryUtils;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.List; import java.util.List;
@ -188,7 +187,7 @@ public class RightClickIntegrationTest {
slot = slot - 9 + offset; slot = slot - 9 + offset;
} }
} }
player.addPacketToQueue(ConnectionState.PLAY, new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) 1, player.addPacketToQueue(new ClientClickWindowPacket(windowId, 0, (short) slot, (byte) 1,
ClientClickWindowPacket.ClickType.PICKUP, List.of(), ItemStack.AIR)); ClientClickWindowPacket.ClickType.PICKUP, List.of(), ItemStack.AIR));
player.interpretPacketQueue(); player.interpretPacketQueue();
} }

View File

@ -39,7 +39,7 @@ final class TestConnectionImpl implements TestConnection {
// Use player provider to disable queued chunk sending // Use player provider to disable queued chunk sending
process.connection().setPlayerProvider(TestPlayerImpl::new); process.connection().setPlayerProvider(TestPlayerImpl::new);
playerConnection.setServerState(ConnectionState.LOGIN); playerConnection.setConnectionState(ConnectionState.LOGIN);
var player = process.connection().createPlayer(playerConnection, UUID.randomUUID(), "RandName"); var player = process.connection().createPlayer(playerConnection, UUID.randomUUID(), "RandName");
player.eventNode().addListener(AsyncPlayerConfigurationEvent.class, event -> { player.eventNode().addListener(AsyncPlayerConfigurationEvent.class, event -> {
event.setSpawningInstance(instance); event.setSpawningInstance(instance);
@ -47,10 +47,8 @@ final class TestConnectionImpl implements TestConnection {
}); });
// Force the player through the entirety of the login process manually // Force the player through the entirety of the login process manually
playerConnection.setServerState(ConnectionState.CONFIGURATION);
process.connection().doConfiguration(player, true); process.connection().doConfiguration(player, true);
process.connection().transitionConfigToPlay(player); process.connection().transitionConfigToPlay(player);
playerConnection.setServerState(ConnectionState.PLAY);
process.connection().updateWaitingPlayers(); process.connection().updateWaitingPlayers();
return CompletableFuture.completedFuture(player); return CompletableFuture.completedFuture(player);
} }
@ -72,7 +70,7 @@ final class TestConnectionImpl implements TestConnection {
} }
private ServerPacket extractPacket(final SendablePacket packet) { private ServerPacket extractPacket(final SendablePacket packet) {
if (!(packet instanceof ServerPacket serverPacket)) return SendablePacket.extractServerPacket(getServerState(), packet); if (!(packet instanceof ServerPacket serverPacket)) return SendablePacket.extractServerPacket(getConnectionState(), packet);
final Player player = getPlayer(); final Player player = getPlayer();
if (player == null) return serverPacket; if (player == null) return serverPacket;