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
parent de3e8cc523
commit 40b641ffb1
No known key found for this signature in database
GPG Key ID: B148F922E64797C7
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.extras.lan.OpenToLAN;
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.ping.ResponseData;
import net.minestom.server.utils.identity.NamedAndIdentified;
@ -108,9 +106,7 @@ public class Main {
PlayerInit.init();
OptifineSupport.enable();
// VelocityProxy.enable("abc");
// VelocityProxy.enable("abcdef");
//BungeeCordProxy.enable();
//MojangAuth.init();

View File

@ -1,7 +1,5 @@
package net.minestom.demo;
import net.kyori.adventure.resource.ResourcePackInfo;
import net.kyori.adventure.resource.ResourcePackRequest;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
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.world.DimensionType;
import java.net.URI;
import java.time.Duration;
import java.util.Random;
import java.util.Set;
@ -92,6 +89,12 @@ public class PlayerInit {
.addListener(AsyncPlayerConfigurationEvent.class, event -> {
final Player player = event.getPlayer();
try {
Thread.sleep(60 * 1000);
} catch (Exception e) {
throw new RuntimeException(e);
}
var instances = MinecraftServer.getInstanceManager().getInstances();
Instance instance = instances.stream().skip(new Random().nextInt(instances.size())).findFirst().orElse(null);
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.timer.SchedulerManager;
import net.minestom.server.utils.PacketUtils;
import net.minestom.server.utils.PropertyUtils;
import net.minestom.server.utils.collection.MappedCollection;
import net.minestom.server.world.DimensionTypeManager;
import net.minestom.server.world.biomes.BiomeManager;
@ -45,7 +46,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
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 ExtensionManager extension;
@ -241,7 +243,7 @@ final class ServerProcessImpl implements ServerProcess {
MinestomTerminal.start();
}
// Stop the server on SIGINT
Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
if (SHUTDOWN_ON_SIGNAL) Runtime.getRuntime().addShutdownHook(new Thread(this::stop));
}
@Override

View File

@ -457,7 +457,7 @@ public class LivingEntity extends Entity implements EquipmentHandler {
if (this instanceof Player player) {
PlayerConnection playerConnection = player.playerConnection;
// 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));
if (self) {

View File

@ -168,10 +168,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
private final AtomicInteger teleportId = new AtomicInteger();
private int receivedTeleportId;
private record PacketInState(ConnectionState state, ClientPacket packet) {
}
private final MessagePassingQueue<PacketInState> packets = new MpscUnboundedXaddArrayQueue<>(32);
private final MessagePassingQueue<ClientPacket> packets = new MpscUnboundedXaddArrayQueue<>(32);
private final boolean levelFlat;
private final PlayerSettings settings;
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>
*/
public void startConfigurationPhase() {
Check.stateCondition(playerConnection.getClientState() != ConnectionState.PLAY,
Check.stateCondition(playerConnection.getConnectionState() != ConnectionState.PLAY,
"Player must be in the play state for reconfiguration.");
// 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()));
}
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) {
this.inventory.update();
sendPacket(new HeldItemChangePacket(heldSlot));
@ -1631,10 +1622,9 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
* @param component the reason
*/
public void kick(@NotNull Component component) {
final ConnectionState connectionState = playerConnection.getServerState();
// Packet type depends on the current player connection state
final ServerPacket disconnectPacket;
if (connectionState == ConnectionState.LOGIN) {
if (playerConnection.getConnectionState() == ConnectionState.LOGIN) {
disconnectPacket = new LoginDisconnectPacket(component);
} else {
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
*/
public void addPacketToQueue(@NotNull ConnectionState state, @NotNull ClientPacket packet) {
this.packets.offer(new PacketInState(state, packet));
public void addPacketToQueue(@NotNull ClientPacket packet) {
this.packets.offer(packet);
}
@ApiStatus.Internal
@ -2055,7 +2045,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.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) {
this.latency = latency;
if (getPlayerConnection().getServerState() == ConnectionState.PLAY) {
if (getPlayerConnection().getConnectionState() == ConnectionState.PLAY) {
PacketUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LATENCY, infoEntry()));
}
}
@ -2482,7 +2472,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
this.allowServerListings = allowServerListings;
// TODO: Use the metadata object here
boolean isInPlayState = getPlayerConnection().getServerState() == ConnectionState.PLAY;
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)));

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.
*
* @param state the current connection state
* @param packet the received packet
* @param connection the connection of the player who sent the packet
* @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();
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.network.ConnectionManager;
import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket;
import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket;
import org.jetbrains.annotations.NotNull;
public final class ConfigListener {

View File

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

View File

@ -59,6 +59,12 @@ public final class ConnectionManager {
// Players in play state
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> unmodifiablePlayPlayers = Collections.unmodifiableSet(playPlayers);
@ -238,7 +244,6 @@ public final class ConnectionManager {
// Send login success packet (and switch to configuration phase)
LoginSuccessPacket loginSuccessPacket = new LoginSuccessPacket(player.getUuid(), player.getUsername(), 0);
playerConnection.sendPacket(loginSuccessPacket);
configurationPlayers.add(player);
});
if (DebugUtils.INSIDE_TEST) configFuture.join();
}
@ -251,6 +256,12 @@ public final class ConnectionManager {
@ApiStatus.Internal
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(() -> {
player.sendPacket(PluginMessagePacket.getBrandPacket());
@ -276,6 +287,7 @@ public final class ConnectionManager {
var packFuture = player.getResourcePackFuture();
if (packFuture != null) packFuture.join();
keepAlivePlayers.remove(player);
player.setPendingInstance(spawningInstance);
player.sendPacket(new FinishConfigurationPacket());
});
@ -301,6 +313,7 @@ public final class ConnectionManager {
if (player == null) return;
this.configurationPlayers.remove(player);
this.playPlayers.remove(player);
this.keepAlivePlayers.remove(player);
}
/**
@ -309,6 +322,7 @@ public final class ConnectionManager {
public synchronized void shutdown() {
this.configurationPlayers.clear();
this.playPlayers.clear();
this.keepAlivePlayers.clear();
this.connectionPlayerMap.clear();
}
@ -317,8 +331,7 @@ public final class ConnectionManager {
updateWaitingPlayers();
// Send keep alive packets
handleKeepAlive(configurationPlayers, tickStart);
handleKeepAlive(playPlayers, tickStart);
handleKeepAlive(keepAlivePlayers, tickStart);
// Interpret packets for configuration players
configurationPlayers.forEach(Player::interpretPacketQueue);
@ -330,8 +343,9 @@ public final class ConnectionManager {
@ApiStatus.Internal
public void updateWaitingPlayers() {
this.waitingPlayers.drain(player -> {
configurationPlayers.remove(player);
player.getPlayerConnection().setConnectionState(ConnectionState.PLAY);
playPlayers.add(player);
keepAlivePlayers.add(player);
// Spawn the player at Player#getRespawnPoint
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.ClientPacketsHandler;
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 org.jetbrains.annotations.NotNull;
@ -53,25 +50,16 @@ public class PacketProcessor {
}
public ClientPacket process(@NotNull PlayerConnection connection, int packetId, ByteBuffer body) {
final ClientPacket packet = create(connection.getClientState(), packetId, body);
final ConnectionState state = connection.getClientState();
final ClientPacket packet = create(connection.getConnectionState(), packetId, body);
// If the packet intends to switch state, do it now.
// 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) {
switch (connection.getConnectionState()) {
// 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
case CONFIGURATION, PLAY -> {
final Player player = connection.getPlayer();
assert player != null;
player.addPacketToQueue(state, packet);
player.addPacketToQueue(packet);
}
}
return packet;

View File

@ -1,10 +1,8 @@
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.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public record ClientFinishConfigurationPacket() implements ClientPacket {
@ -16,8 +14,4 @@ public record ClientFinishConfigurationPacket() implements ClientPacket {
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;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.client.ClientPacket;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public record ClientLoginAcknowledgedPacket() implements ClientPacket {
@ -16,8 +14,4 @@ public record ClientLoginAcknowledgedPacket() implements ClientPacket {
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);
/**
* 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.utils.PacketUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public record FinishConfigurationPacket() implements ServerPacket {
@ -25,9 +24,4 @@ public record FinishConfigurationPacket() implements ServerPacket {
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.utils.PacketUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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);
};
}
@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
public void sendPacket(@NotNull SendablePacket packet) {
FakePlayerController controller = getFakePlayer().getController();
final ServerPacket serverPacket = SendablePacket.extractServerPacket(getServerState(), packet);
final ServerPacket serverPacket = SendablePacket.extractServerPacket(getConnectionState(), packet);
controller.consumePacket(serverPacket);
}

View File

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

View File

@ -112,7 +112,7 @@ public class PlayerSocketConnection extends PlayerConnection {
MinecraftServer.getExceptionManager().handleException(e);
} finally {
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.
* <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 channel the packet channel
* @throws IllegalStateException if a messageId with the value {@code messageId} already exists for this connection
*/
public void addPluginRequestEntry(int messageId, @NotNull String channel) {
if (getServerState() != ConnectionState.LOGIN) {
if (!getConnectionState().equals(ConnectionState.LOGIN)) {
return;
}
Check.stateCondition(pluginRequestMap.containsKey(messageId), "You cannot have two messageId with the same value");
@ -317,10 +317,10 @@ public class PlayerSocketConnection extends PlayerConnection {
}
@Override
public void setClientState(@NotNull ConnectionState state) {
super.setClientState(state);
public void setConnectionState(@NotNull ConnectionState connectionState) {
super.setConnectionState(connectionState);
// Clear the plugin request map (since it is not used anymore)
if (state == ConnectionState.PLAY) {
if (connectionState.equals(ConnectionState.PLAY)) {
this.pluginRequestMap.clear();
}
}
@ -338,24 +338,21 @@ public class PlayerSocketConnection extends PlayerConnection {
final Player player = getPlayer();
// Outgoing event
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);
outgoing.call(event);
if (event.isCancelled()) return;
}
// 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) {
writeServerPacketSync(serverPacket, compressed);
} else if (packet instanceof FramedPacket framedPacket) {
var buffer = framedPacket.body();
writeBufferSync(buffer, 0, buffer.limit());
} 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());
else writeServerPacketSync(cachedPacket.packet(getServerState()), compressed);
else writeServerPacketSync(cachedPacket.packet(getConnectionState()), compressed);
} else if (packet instanceof LazyPacket lazyPacket) {
writeServerPacketSync(lazyPacket.packet(), compressed);
} else {
@ -372,15 +369,8 @@ public class PlayerSocketConnection extends PlayerConnection {
}
}
try (var hold = ObjectPool.PACKET_POOL.hold()) {
var state = getServerState();
var buffer = PacketUtils.createFramedPacket(state, hold.get(), serverPacket, compressed);
var buffer = PacketUtils.createFramedPacket(getConnectionState(), hold.get(), serverPacket, compressed);
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;
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.suggestion.SuggestionEntry;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.network.packet.client.play.ClientTabCompletePacket;
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 java.util.List;
import static net.minestom.server.command.builder.arguments.ArgumentType.Literal;
import static net.minestom.server.command.builder.arguments.ArgumentType.Word;
import static net.minestom.server.command.builder.arguments.ArgumentType.Integer;
import static net.minestom.server.command.builder.arguments.ArgumentType.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
@ -41,7 +38,7 @@ public class CommandSuggestionIntegrationTest {
env.process().command().register(command);
var listener = connection.trackIncoming(TabCompletePacket.class);
player.addPacketToQueue(ConnectionState.PLAY, new ClientTabCompletePacket(3, "test te"));
player.addPacketToQueue(new ClientTabCompletePacket(3, "test te"));
player.interpretPacketQueue();
listener.assertSingle(tabCompletePacket -> {
@ -69,7 +66,7 @@ public class CommandSuggestionIntegrationTest {
env.process().command().register(command);
var listener = connection.trackIncoming(TabCompletePacket.class);
player.addPacketToQueue(ConnectionState.PLAY, new ClientTabCompletePacket(1, "foo 1"));
player.addPacketToQueue(new ClientTabCompletePacket(1, "foo 1"));
player.interpretPacketQueue();
listener.assertSingle(tabCompletePacket -> {

View File

@ -1,13 +1,12 @@
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.event.player.PlayerChangeHeldSlotEvent;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
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 static org.junit.jupiter.api.Assertions.assertEquals;
@ -25,7 +24,7 @@ public class PlayerHeldIntegrationTest {
assertEquals(ItemStack.AIR, player.getItemInMainHand());
assertEquals(0, player.getHeldSlot());
player.addPacketToQueue(ConnectionState.PLAY, new ClientHeldItemChangePacket((short) 1));
player.addPacketToQueue(new ClientHeldItemChangePacket((short) 1));
player.interpretPacketQueue();
assertEquals(ItemStack.of(Material.STONE), player.getItemInMainHand());
@ -42,7 +41,7 @@ public class PlayerHeldIntegrationTest {
assertEquals(ItemStack.AIR, player.getItemInMainHand());
assertEquals(0, player.getHeldSlot());
player.addPacketToQueue(ConnectionState.PLAY, new ClientHeldItemChangePacket((short) 1));
player.addPacketToQueue(new ClientHeldItemChangePacket((short) 1));
var listener = env.listen(PlayerChangeHeldSlotEvent.class);
listener.followup(event -> {
assertEquals(player, event.getPlayer());

View File

@ -1,8 +1,5 @@
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.entity.GameMode;
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.Material;
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.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@ -39,7 +38,7 @@ public class PlayerBlockPlacementIntegrationTest {
1f, 1f, 1f,
false, 0
);
player.addPacketToQueue(ConnectionState.PLAY, packet);
player.addPacketToQueue(packet);
player.interpretPacketQueue();
var placedBlock = instance.getBlock(1, 41, 0);

View File

@ -1,21 +1,20 @@
package net.minestom.server.entity.player;
import net.minestom.server.event.player.PlayerGameModeChangeEvent;
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.entity.GameMode;
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.play.*;
import net.minestom.server.utils.NamespaceID;
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.Test;
@ -85,7 +84,7 @@ public class PlayerIntegrationTest {
env.tick();
env.tick();
player.addPacketToQueue(ConnectionState.PLAY, packet);
player.addPacketToQueue(packet);
var collector = connection.trackIncoming();
env.tick();
env.tick();

View File

@ -1,11 +1,6 @@
package net.minestom.server.entity.player;
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.Vec;
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.utils.MathUtils;
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.junit.jupiter.api.Test;
@ -34,12 +33,12 @@ public class PlayerMovementIntegrationTest {
var instance = env.createFlatInstance();
var p1 = env.createPlayer(instance, new Pos(0, 40, 0));
// 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();
assertEquals(new Pos(0, 40, 0), p1.getPosition());
// Confirmation
p1.addPacketToQueue(ConnectionState.PLAY, new ClientTeleportConfirmPacket(p1.getLastSentTeleportId()));
p1.addPacketToQueue(ConnectionState.PLAY, new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
p1.addPacketToQueue(new ClientTeleportConfirmPacket(p1.getLastSentTeleportId()));
p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
p1.interpretPacketQueue();
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));
connection.connect(instance, new Pos(0, 40, 0)).join();
p1.addPacketToQueue(ConnectionState.PLAY, new ClientTeleportConfirmPacket(p1.getLastSentTeleportId()));
p1.addPacketToQueue(ConnectionState.PLAY, 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 ClientTeleportConfirmPacket(p1.getLastSentTeleportId()));
p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.2, 40, 0), true));
p1.addPacketToQueue(new ClientPlayerPositionPacket(new Pos(0.4, 40, 0), true));
var tracker = connection.trackIncoming(EntityPositionPacket.class);
p1.interpretPacketQueue();
@ -76,42 +75,42 @@ public class PlayerMovementIntegrationTest {
final Player player = future.join();
// Initial join
chunkDataPacketCollector.assertCount(MathUtils.square(viewDiameter));
player.addPacketToQueue(ConnectionState.PLAY, new ClientTeleportConfirmPacket(player.getLastSentTeleportId()));
player.addPacketToQueue(new ClientTeleportConfirmPacket(player.getLastSentTeleportId()));
// Move to next chunk
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();
chunkDataPacketCollector.assertCount(viewDiameter);
// Move to next chunk
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();
chunkDataPacketCollector.assertCount(viewDiameter);
// Move to next chunk
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();
chunkDataPacketCollector.assertCount(viewDiameter);
// Move to next chunk
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();
chunkDataPacketCollector.assertEmpty();
// Move to next chunk
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();
chunkDataPacketCollector.assertEmpty();
// Move to next chunk
chunkDataPacketCollector = connection.trackIncoming(ChunkDataPacket.class);
// 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();
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.coordinate.Pos;
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.server.play.ChunkDataPacket;
import net.minestom.server.network.packet.server.play.UnloadChunkPacket;
@ -16,7 +15,8 @@ import java.util.HashSet;
import java.util.List;
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
@ -58,7 +58,7 @@ public class PlayerRespawnChunkIntegrationTest {
var loadChunkTracker = connection.trackIncoming(ChunkDataPacket.class);
player.setHealth(0);
player.addPacketToQueue(ConnectionState.PLAY, new ClientStatusPacket(ClientStatusPacket.Action.PERFORM_RESPAWN));
player.addPacketToQueue(new ClientStatusPacket(ClientStatusPacket.Action.PERFORM_RESPAWN));
player.interpretPacketQueue();
List<ChunkDataPacket> dataPacketList = loadChunkTracker.collect();
Set<ChunkDataPacket> duplicateCheck = new HashSet<>();

View File

@ -1,8 +1,5 @@
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.entity.Player;
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.network.packet.client.play.ClientClickWindowPacket;
import net.minestom.server.utils.inventory.PlayerInventoryUtils;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import org.junit.jupiter.api.Test;
import java.util.List;
@ -184,7 +183,7 @@ public class HeldClickIntegrationTest {
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));
player.interpretPacketQueue();
}

View File

@ -1,9 +1,6 @@
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.entity.Player;
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.network.packet.client.play.ClientClickWindowPacket;
import net.minestom.server.utils.inventory.PlayerInventoryUtils;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import org.junit.jupiter.api.Test;
import java.util.List;
@ -167,7 +166,7 @@ public class LeftClickIntegrationTest {
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));
player.interpretPacketQueue();
}

View File

@ -1,8 +1,5 @@
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.entity.Player;
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.network.packet.client.play.ClientClickWindowPacket;
import net.minestom.server.utils.inventory.PlayerInventoryUtils;
import net.minestom.testing.Env;
import net.minestom.testing.EnvTest;
import org.junit.jupiter.api.Test;
import java.util.List;
@ -188,7 +187,7 @@ public class RightClickIntegrationTest {
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));
player.interpretPacketQueue();
}

View File

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