feat: start reentry of config phase

(cherry picked from commit e702c09f06)
This commit is contained in:
mworzala 2023-11-25 21:43:28 +02:00 committed by Matt Worzala
parent fb0c8c5405
commit b9c2d42696
11 changed files with 247 additions and 68 deletions

View File

@ -64,6 +64,7 @@ public class Main {
commandManager.register(new DisplayCommand()); commandManager.register(new DisplayCommand());
commandManager.register(new NotificationCommand()); commandManager.register(new NotificationCommand());
commandManager.register(new TestCommand2()); commandManager.register(new TestCommand2());
commandManager.register(new ConfigCommand());
commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage(Component.text("Unknown command", NamedTextColor.RED))); commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage(Component.text("Unknown command", NamedTextColor.RED)));
@ -109,10 +110,10 @@ public class Main {
OptifineSupport.enable(); OptifineSupport.enable();
VelocityProxy.enable("abc"); // VelocityProxy.enable("abc");
//BungeeCordProxy.enable(); //BungeeCordProxy.enable();
//MojangAuth.init();c //MojangAuth.init();
// useful for testing - we don't need to worry about event calls so just set this to a long time // useful for testing - we don't need to worry about event calls so just set this to a long time
OpenToLAN.open(new OpenToLANConfig().eventCallDelay(Duration.of(1, TimeUnit.DAY))); OpenToLAN.open(new OpenToLANConfig().eventCallDelay(Duration.of(1, TimeUnit.DAY)));

View File

@ -0,0 +1,15 @@
package net.minestom.demo.commands;
import net.minestom.server.command.builder.Command;
import net.minestom.server.entity.Player;
public class ConfigCommand extends Command {
public ConfigCommand() {
super("config");
setDefaultExecutor((sender, context) -> {
if (!(sender instanceof Player player)) return;
player.startConfigurationPhase2();
});
}
}

View File

@ -1524,8 +1524,11 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev
* WARNING: this does not trigger {@link EntityDeathEvent}. * WARNING: this does not trigger {@link EntityDeathEvent}.
*/ */
public void remove() { public void remove() {
if (isRemoved()) return; remove(true);
}
protected void remove(boolean permanent) {
if (isRemoved()) return;
EventDispatcher.call(new EntityDespawnEvent(this)); EventDispatcher.call(new EntityDespawnEvent(this));
try { try {
despawn(); despawn();
@ -1541,10 +1544,21 @@ public class Entity implements Viewable, Tickable, Schedulable, Snapshotable, Ev
MinecraftServer.process().dispatcher().removeElement(this); MinecraftServer.process().dispatcher().removeElement(this);
this.removed = true; this.removed = true;
Entity.ENTITY_BY_ID.remove(id); if (permanent) {
Entity.ENTITY_BY_UUID.remove(uuid); Entity.ENTITY_BY_ID.remove(id);
Entity.ENTITY_BY_UUID.remove(uuid);
} else {
// Reset some other state
this.position = Pos.ZERO;
this.previousPosition = Pos.ZERO;
this.lastSyncedPosition = Pos.ZERO;
}
Instance currentInstance = this.instance; Instance currentInstance = this.instance;
if (currentInstance != null) removeFromInstance(currentInstance); if (currentInstance != null) {
removeFromInstance(currentInstance);
this.instance = null;
}
} }
/** /**

View File

@ -60,6 +60,7 @@ import net.minestom.server.network.PlayerProvider;
import net.minestom.server.network.packet.client.ClientPacket; import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.server.SendablePacket; import net.minestom.server.network.packet.server.SendablePacket;
import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.network.packet.server.common.*; import net.minestom.server.network.packet.server.common.*;
import net.minestom.server.network.packet.server.configuration.FinishConfigurationPacket; import net.minestom.server.network.packet.server.configuration.FinishConfigurationPacket;
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
@ -249,19 +250,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
metadata.setNotifyAboutChanges(false); metadata.setNotifyAboutChanges(false);
} }
public void UNSAFE_enterConfiguration(boolean isFirstConfig) {
AsyncUtils.runAsync(() -> {
var event = new AsyncPlayerConfigurationEvent(this, isFirstConfig);
EventDispatcher.call(event);
final Instance spawningInstance = event.getSpawningInstance();
Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent");
MinecraftServer.getConnectionManager().startPlayState(this, event.getSpawningInstance());
sendPacket(new FinishConfigurationPacket());
});
}
/** /**
* Used when the player is created. * Used when the player is created.
* Init the player and spawn him. * Init the player and spawn him.
@ -271,9 +259,12 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
* *
* @param spawnInstance the player spawn instance (defined in {@link AsyncPlayerConfigurationEvent}) * @param spawnInstance the player spawn instance (defined in {@link AsyncPlayerConfigurationEvent})
*/ */
@ApiStatus.Internal
public CompletableFuture<Void> UNSAFE_init(@NotNull Instance spawnInstance) { public CompletableFuture<Void> UNSAFE_init(@NotNull Instance spawnInstance) {
this.dimensionType = spawnInstance.getDimensionType(); this.dimensionType = spawnInstance.getDimensionType();
System.out.println("INIT PLAYER");
final JoinGamePacket joinGamePacket = new JoinGamePacket( final JoinGamePacket joinGamePacket = new JoinGamePacket(
getEntityId(), false, List.of(), 0, getEntityId(), false, List.of(), 0,
MinecraftServer.getChunkViewDistance(), MinecraftServer.getChunkViewDistance(), MinecraftServer.getChunkViewDistance(), MinecraftServer.getChunkViewDistance(),
@ -281,8 +272,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
0, gameMode, null, false, levelFlat, deathLocation, portalCooldown); 0, gameMode, null, false, levelFlat, deathLocation, portalCooldown);
sendPacket(joinGamePacket); sendPacket(joinGamePacket);
// Server brand name
sendPacket(PluginMessagePacket.getBrandPacket());
// Difficulty // Difficulty
sendPacket(new ServerDifficultyPacket(MinecraftServer.getDifficulty(), true)); sendPacket(new ServerDifficultyPacket(MinecraftServer.getDifficulty(), true));
@ -356,6 +345,71 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
return setInstance(spawnInstance); return setInstance(spawnInstance);
} }
/**
* Moves the player immediately to the configuration state. The player is automatically moved
* to configuration upon finishing login, this method can be used to move them back to configuration
* after entering the play state.
*
* <p>This will result in them being removed from the current instance, player list, etc.</p>
*/
public void startConfigurationPhase() {
boolean isFirstConfig = true;
// If the player is currently in the play state, we need to put them back in configuration.
if (playerConnection.getClientState() == ConnectionState.PLAY) {
remove(false);
sendPacket(new StartConfigurationPacket());
} else {
// Sanity check that they are already in configuration.
// On first join, they will already be in the config state when this is called.
assert playerConnection.getClientState() == ConnectionState.CONFIGURATION;
}
// Call the event and spawn the player.
AsyncUtils.runAsync(() -> {
System.out.println("CALL EVENT");
var event = new AsyncPlayerConfigurationEvent(this, isFirstConfig);
EventDispatcher.call(event);
System.out.println("FINISHED EVENT");
final Instance spawningInstance = event.getSpawningInstance();
Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent");
MinecraftServer.getConnectionManager().startPlayState(this, event.getSpawningInstance());
sendPacket(new FinishConfigurationPacket());
System.out.println("SENT CHANGE PACKET");
});
}
public void startConfigurationPhase2() {
boolean isFirstConfig = true;
// If the player is currently in the play state, we need to put them back in configuration.
if (playerConnection.getClientState() == ConnectionState.PLAY) {
remove(false);
sendPacket(new StartConfigurationPacket());
} else {
// Sanity check that they are already in configuration.
// On first join, they will already be in the config state when this is called.
assert playerConnection.getClientState() == ConnectionState.CONFIGURATION;
}
// Call the event and spawn the player.
// AsyncUtils.runAsync(() -> {
// System.out.println("CALL EVENT");
// var event = new AsyncPlayerConfigurationEvent(this, isFirstConfig);
// EventDispatcher.call(event);
//
// System.out.println("FINISHED EVENT");
// final Instance spawningInstance = event.getSpawningInstance();
// Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent");
//
// MinecraftServer.getConnectionManager().startPlayState(this, event.getSpawningInstance());
// sendPacket(new FinishConfigurationPacket());
// System.out.println("SENT CHANGE PACKET");
// });
}
/** /**
* Used to initialize the player connection * Used to initialize the player connection
*/ */
@ -538,11 +592,16 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
} }
@Override @Override
public void remove() { public void remove(boolean permanent) {
if (isRemoved()) return; if (isRemoved()) return;
EventDispatcher.call(new PlayerDisconnectEvent(this));
super.remove(); if (permanent) {
this.packets.clear(); this.packets.clear();
EventDispatcher.call(new PlayerDisconnectEvent(this));
}
super.remove(permanent);
final Inventory currentInventory = getOpenInventory(); final Inventory currentInventory = getOpenInventory();
if (currentInventory != null) currentInventory.removeViewer(this); if (currentInventory != null) currentInventory.removeViewer(this);
MinecraftServer.getBossBarManager().removeAllBossBars(this); MinecraftServer.getBossBarManager().removeAllBossBars(this);
@ -565,7 +624,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
// Prevent the player from being stuck in loading screen, or just unable to interact with the server // Prevent the player from being stuck in loading screen, or just unable to interact with the server
// This should be considered as a bug, since the player will ultimately time out anyway. // This should be considered as a bug, since the player will ultimately time out anyway.
if (playerConnection.isOnline()) kick(REMOVE_MESSAGE); if (permanent && playerConnection.isOnline()) kick(REMOVE_MESSAGE);
} }
@Override @Override

View File

@ -0,0 +1,12 @@
package net.minestom.server.listener;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket;
import org.jetbrains.annotations.NotNull;
public class PlayConfigListener {
public static void configAckListener(@NotNull ClientConfigurationAckPacket packet, @NotNull Player player) {
player.startConfigurationPhase();
}
}

View File

@ -65,6 +65,7 @@ public final class PacketListenerManager {
setPlayListener(ClientChatMessagePacket.class, ChatMessageListener::chatMessageListener); setPlayListener(ClientChatMessagePacket.class, ChatMessageListener::chatMessageListener);
setPlayListener(ClientClickWindowPacket.class, WindowListener::clickWindowListener); setPlayListener(ClientClickWindowPacket.class, WindowListener::clickWindowListener);
setPlayListener(ClientCloseWindowPacket.class, WindowListener::closeWindowListener); setPlayListener(ClientCloseWindowPacket.class, WindowListener::closeWindowListener);
setPlayListener(ClientConfigurationAckPacket.class, PlayConfigListener::configAckListener);
setPlayListener(ClientPongPacket.class, WindowListener::pong); setPlayListener(ClientPongPacket.class, WindowListener::pong);
setPlayListener(ClientEntityActionPacket.class, EntityActionListener::listener); setPlayListener(ClientEntityActionPacket.class, EntityActionListener::listener);
setPlayListener(ClientHeldItemChangePacket.class, PlayerHeldListener::heldListener); setPlayListener(ClientHeldItemChangePacket.class, PlayerHeldListener::heldListener);

View File

@ -8,24 +8,19 @@ import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.entity.damage.DamageType; import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
import net.minestom.server.extras.MojangAuth; import net.minestom.server.extras.MojangAuth;
import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.extras.bungee.BungeeCordProxy;
import net.minestom.server.extras.mojangAuth.MojangCrypt; import net.minestom.server.extras.mojangAuth.MojangCrypt;
import net.minestom.server.extras.velocity.VelocityProxy; import net.minestom.server.extras.velocity.VelocityProxy;
import net.minestom.server.instance.Instance;
import net.minestom.server.message.Messenger; import net.minestom.server.message.Messenger;
import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.ConnectionManager;
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.login.ClientEncryptionResponsePacket; import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket;
import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket; import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket;
import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket; import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket;
import net.minestom.server.network.packet.client.login.ClientLoginStartPacket; import net.minestom.server.network.packet.client.login.ClientLoginStartPacket;
import net.minestom.server.network.packet.server.common.ResourcePackSendPacket; import net.minestom.server.network.packet.server.common.PluginMessagePacket;
import net.minestom.server.network.packet.server.common.TagsPacket; import net.minestom.server.network.packet.server.common.TagsPacket;
import net.minestom.server.network.packet.server.configuration.FinishConfigurationPacket;
import net.minestom.server.network.packet.server.configuration.RegistryDataPacket; import net.minestom.server.network.packet.server.configuration.RegistryDataPacket;
import net.minestom.server.network.packet.server.login.EncryptionRequestPacket; import net.minestom.server.network.packet.server.login.EncryptionRequestPacket;
import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; import net.minestom.server.network.packet.server.login.LoginDisconnectPacket;
@ -33,12 +28,9 @@ import net.minestom.server.network.packet.server.login.LoginPluginRequestPacket;
import net.minestom.server.network.player.GameProfile; import net.minestom.server.network.player.GameProfile;
import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection; import net.minestom.server.network.player.PlayerSocketConnection;
import net.minestom.server.registry.Registry;
import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.async.AsyncUtils;
import net.minestom.server.utils.validate.Check;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jglrxavpok.hephaistos.nbt.NBT; import org.jglrxavpok.hephaistos.nbt.NBT;
import org.jglrxavpok.hephaistos.nbt.NBTType;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import java.math.BigInteger; import java.math.BigInteger;
@ -49,7 +41,6 @@ import java.net.http.HttpResponse;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import static net.minestom.server.network.NetworkBuffer.STRING; import static net.minestom.server.network.NetworkBuffer.STRING;
@ -241,8 +232,11 @@ public final class LoginListener {
// Tags // Tags
connection.sendPacket(TagsPacket.DEFAULT_TAGS); connection.sendPacket(TagsPacket.DEFAULT_TAGS);
// Server Brand
connection.sendPacket(PluginMessagePacket.getBrandPacket());
// Enter configuration phase (for the first time) // Enter configuration phase (for the first time)
player.UNSAFE_enterConfiguration(true); player.startConfigurationPhase();
} }
} }

View File

@ -8,14 +8,13 @@ import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.AsyncPlayerPreLoginEvent; import net.minestom.server.event.player.AsyncPlayerPreLoginEvent;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
import net.minestom.server.network.packet.client.login.ClientLoginStartPacket; import net.minestom.server.network.packet.client.login.ClientLoginStartPacket;
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
import net.minestom.server.network.packet.server.common.KeepAlivePacket; import net.minestom.server.network.packet.server.common.KeepAlivePacket;
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.network.player.PlayerSocketConnection; import net.minestom.server.network.player.PlayerSocketConnection;
import net.minestom.server.utils.StringUtils; import net.minestom.server.utils.StringUtils;
import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.async.AsyncUtils;
import net.minestom.server.utils.debug.DebugUtils; import net.minestom.server.utils.debug.DebugUtils;
import net.minestom.server.utils.validate.Check;
import org.jctools.queues.MessagePassingQueue; import org.jctools.queues.MessagePassingQueue;
import org.jctools.queues.MpscUnboundedArrayQueue; import org.jctools.queues.MpscUnboundedArrayQueue;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
@ -36,11 +35,14 @@ public final class ConnectionManager {
private static final long KEEP_ALIVE_KICK = 30_000; private static final long KEEP_ALIVE_KICK = 30_000;
private static final Component TIMEOUT_TEXT = Component.text("Timeout", NamedTextColor.RED); private static final Component TIMEOUT_TEXT = Component.text("Timeout", NamedTextColor.RED);
private record PendingPlayer(@NotNull Player player, @NotNull Instance instance) {} private record PendingPlayer(@NotNull Player player, @NotNull Instance instance) {
}
private final MessagePassingQueue<PendingPlayer> waitingPlayers = new MpscUnboundedArrayQueue<>(64); private final MessagePassingQueue<PendingPlayer> waitingPlayers = new MpscUnboundedArrayQueue<>(64);
private final Set<Player> players = new CopyOnWriteArraySet<>(); private final Set<Player> players = new CopyOnWriteArraySet<>();
private final Set<Player> unmodifiablePlayers = Collections.unmodifiableSet(players); private final Set<Player> unmodifiablePlayers = Collections.unmodifiableSet(players);
// All players once their Player object has been instantiated.
private final Map<PlayerConnection, Player> connectionPlayerMap = new ConcurrentHashMap<>(); private final Map<PlayerConnection, Player> connectionPlayerMap = new ConcurrentHashMap<>();
// The uuid provider once a player login // The uuid provider once a player login
@ -48,16 +50,6 @@ public final class ConnectionManager {
// The player provider to have your own Player implementation // The player provider to have your own Player implementation
private volatile PlayerProvider playerProvider = Player::new; private volatile PlayerProvider playerProvider = Player::new;
/**
* Gets the {@link Player} linked to a {@link PlayerConnection}.
*
* @param connection the player connection
* @return the player linked to the connection
*/
public Player getPlayer(@NotNull PlayerConnection connection) {
return connectionPlayerMap.get(connection);
}
/** /**
* Gets all online players. * Gets all online players.
* *
@ -68,25 +60,28 @@ public final class ConnectionManager {
} }
/** /**
* Finds the closest player matching a given username. * Gets online players filtered by state.
* *
* @param username the player username (can be partial) * <p>States before login are not considered online, and will result in nothing being returned.</p>
* @return the closest match, null if no players are online *
* @return An unmodifiable collection containing the filtered players.
* @apiNote The returned collection has no defined update behavior relative to the state of the server,
* so it should be refetched whenever used, rather than kept and reused.
*/ */
public @Nullable Player findPlayer(@NotNull String username) { public @NotNull Collection<@NotNull Player> getPlayers(@NotNull ConnectionState... state) {
Player exact = getPlayer(username); // connectionPlayerMap.values().stream()
if (exact != null) return exact; // .filter()
final String username1 = username.toLowerCase(Locale.ROOT); return List.of();
}
Function<Player, Double> distanceFunction = player -> { /**
final String username2 = player.getUsername().toLowerCase(Locale.ROOT); * Gets the {@link Player} linked to a {@link PlayerConnection}.
return StringUtils.jaroWinklerScore(username1, username2); *
}; * @param connection the player connection
return getOnlinePlayers() * @return the player linked to the connection
.stream() */
.min(Comparator.comparingDouble(distanceFunction::apply)) public Player getPlayer(@NotNull PlayerConnection connection) {
.filter(player -> distanceFunction.apply(player) > 0) return connectionPlayerMap.get(connection);
.orElse(null);
} }
/** /**
@ -121,6 +116,28 @@ public final class ConnectionManager {
return null; return null;
} }
/**
* Finds the closest player matching a given username.
*
* @param username the player username (can be partial)
* @return the closest match, null if no players are online
*/
public @Nullable Player findPlayer(@NotNull String username) {
Player exact = getPlayer(username);
if (exact != null) return exact;
final String username1 = username.toLowerCase(Locale.ROOT);
Function<Player, Double> distanceFunction = player -> {
final String username2 = player.getUsername().toLowerCase(Locale.ROOT);
return StringUtils.jaroWinklerScore(username1, username2);
};
return getOnlinePlayers()
.stream()
.min(Comparator.comparingDouble(distanceFunction::apply))
.filter(player -> distanceFunction.apply(player) > 0)
.orElse(null);
}
/** /**
* Changes how {@link UUID} are attributed to players. * Changes how {@link UUID} are attributed to players.
* <p> * <p>
@ -168,6 +185,23 @@ public final class ConnectionManager {
return playerProvider; return playerProvider;
} }
//todo REDONE TRANSITIONS
@ApiStatus.Internal
public void transitionLoginToConfig(@NotNull Player player) {
}
@ApiStatus.Internal
public void transitionConfigToPlay(@NotNull Player player) {
}
@ApiStatus.Internal
public void transitionPlayToConfig(@NotNull Player player) {
}
/** /**
* Adds a {@link Player} to the players list. * Adds a {@link Player} to the players list.
* <p> * <p>
@ -198,7 +232,7 @@ public final class ConnectionManager {
@ApiStatus.Internal @ApiStatus.Internal
public @NotNull Player startConfigurationState(@NotNull PlayerConnection connection, public @NotNull Player startConfigurationState(@NotNull PlayerConnection connection,
@NotNull UUID uuid, @NotNull String username) { @NotNull UUID uuid, @NotNull String username) {
final Player player = playerProvider.createPlayer(uuid, username, connection); final Player player = playerProvider.createPlayer(uuid, username, connection);
startConfigurationState(player); startConfigurationState(player);
return player; return player;
@ -255,6 +289,8 @@ public final class ConnectionManager {
public void updateWaitingPlayers() { public void updateWaitingPlayers() {
this.waitingPlayers.drain(pp -> { this.waitingPlayers.drain(pp -> {
System.out.println("DRAIN PP " + pp);
// Spawn the player at Player#getRespawnPoint // Spawn the player at Player#getRespawnPoint
CompletableFuture<Void> spawnFuture = pp.player.UNSAFE_init(pp.instance); CompletableFuture<Void> spawnFuture = pp.player.UNSAFE_init(pp.instance);

View File

@ -100,7 +100,7 @@ public sealed class ClientPacketsHandler permits ClientPacketsHandler.Status, Cl
register(nextId(), ClientStatusPacket::new); register(nextId(), ClientStatusPacket::new);
register(nextId(), ClientSettingsPacket::new); register(nextId(), ClientSettingsPacket::new);
register(nextId(), ClientTabCompletePacket::new); register(nextId(), ClientTabCompletePacket::new);
nextId(); // configuration acknowledged register(nextId(), ClientConfigurationAckPacket::new);
register(nextId(), ClientClickWindowButtonPacket::new); register(nextId(), ClientClickWindowButtonPacket::new);
register(nextId(), ClientClickWindowPacket::new); register(nextId(), ClientClickWindowPacket::new);
register(nextId(), ClientCloseWindowPacket::new); register(nextId(), ClientCloseWindowPacket::new);

View File

@ -0,0 +1,22 @@
package net.minestom.server.network.packet.client.play;
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;
public record ClientConfigurationAckPacket() implements ClientPacket {
public ClientConfigurationAckPacket(@NotNull NetworkBuffer buffer) {
this();
}
@Override
public void write(@NotNull NetworkBuffer writer) {
}
@Override
public @NotNull ConnectionState nextState() {
return ConnectionState.CONFIGURATION;
}
}

View File

@ -0,0 +1,25 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.NetworkBuffer;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public record StartConfigurationPacket() implements ServerPacket {
@Override
public void write(@NotNull NetworkBuffer writer) {
}
@Override
public int getId(@NotNull ConnectionState state) {
return ServerPacketIdentifier.START_CONFIGURATION_PACKET;
}
@Override
public @NotNull ConnectionState nextState() {
return ConnectionState.CONFIGURATION;
}
}