From 8a75e9e986fcdb56b6065d92f42609661e60ee67 Mon Sep 17 00:00:00 2001 From: mworzala Date: Tue, 28 Nov 2023 18:48:00 +0200 Subject: [PATCH] feat: cleanup, remove ConnectionManager#getOnlinePlayers --- .../java/net/minestom/demo/PlayerInit.java | 3 +- .../minestom/demo/commands/ConfigCommand.java | 2 +- .../demo/commands/PlayersCommand.java | 22 +- .../net/minestom/server/MinecraftServer.java | 4 +- .../server/adventure/audience/Audiences.java | 10 +- .../audience/IterableAudienceProvider.java | 5 +- .../audience/SingleAudienceProvider.java | 12 +- .../net/minestom/server/entity/Player.java | 96 +++------ .../server/entity/fakeplayer/FakePlayer.java | 3 +- .../query/response/BasicQueryResponse.java | 2 +- .../query/response/FullQueryResponse.java | 6 +- .../extras/query/response/QueryKey.java | 5 +- .../server/listener/ChatMessageListener.java | 3 +- .../server/listener/PlayConfigListener.java | 14 +- .../listener/common/KeepAliveListener.java | 1 - .../listener/preplay/LoginListener.java | 9 +- .../server/network/ConnectionManager.java | 199 ++++++++++-------- .../server/network/PacketProcessor.java | 4 +- .../minestom/server/ping/ResponseData.java | 4 +- .../net/minestom/server/scoreboard/Team.java | 6 +- .../server/scoreboard/TeamManager.java | 4 +- .../minestom/server/utils/PacketUtils.java | 6 +- .../server/utils/entity/EntityFinder.java | 6 +- .../minestom/testing/TestConnectionImpl.java | 2 +- 24 files changed, 206 insertions(+), 222 deletions(-) diff --git a/demo/src/main/java/net/minestom/demo/PlayerInit.java b/demo/src/main/java/net/minestom/demo/PlayerInit.java index 6419a7de7..9f9bcd07c 100644 --- a/demo/src/main/java/net/minestom/demo/PlayerInit.java +++ b/demo/src/main/java/net/minestom/demo/PlayerInit.java @@ -177,8 +177,7 @@ public class PlayerInit { BenchmarkManager benchmarkManager = MinecraftServer.getBenchmarkManager(); MinecraftServer.getSchedulerManager().buildTask(() -> { - Collection players = MinecraftServer.getConnectionManager().getOnlinePlayers(); - if (players.isEmpty()) + if (MinecraftServer.getConnectionManager().getOnlinePlayerCount() != 0) return; long ramUsage = benchmarkManager.getUsedMemory(); diff --git a/demo/src/main/java/net/minestom/demo/commands/ConfigCommand.java b/demo/src/main/java/net/minestom/demo/commands/ConfigCommand.java index 4be2adece..9d9f691ea 100644 --- a/demo/src/main/java/net/minestom/demo/commands/ConfigCommand.java +++ b/demo/src/main/java/net/minestom/demo/commands/ConfigCommand.java @@ -9,7 +9,7 @@ public class ConfigCommand extends Command { setDefaultExecutor((sender, context) -> { if (!(sender instanceof Player player)) return; - player.startConfigurationPhase2(); + player.startConfigurationPhase(); }); } } diff --git a/demo/src/main/java/net/minestom/demo/commands/PlayersCommand.java b/demo/src/main/java/net/minestom/demo/commands/PlayersCommand.java index 899dd4fea..1879dcc0d 100644 --- a/demo/src/main/java/net/minestom/demo/commands/PlayersCommand.java +++ b/demo/src/main/java/net/minestom/demo/commands/PlayersCommand.java @@ -6,8 +6,10 @@ import net.minestom.server.command.CommandSender; import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.CommandContext; import net.minestom.server.entity.Player; +import net.minestom.server.network.ConnectionState; import java.util.Collection; +import java.util.List; public class PlayersCommand extends Command { @@ -17,20 +19,20 @@ public class PlayersCommand extends Command { } private void usage(CommandSender sender, CommandContext context) { - final Collection players = MinecraftServer.getConnectionManager().getOnlinePlayers(); + final var players = List.copyOf(MinecraftServer.getConnectionManager().getPlayers()); final int playerCount = players.size(); sender.sendMessage(Component.text("Total players: " + playerCount)); + final int limit = 15; - if (playerCount <= limit) { - for (final Player player : players) { - sender.sendMessage(Component.text(player.getUsername())); - } - } else { - for (final Player player : players.stream().limit(limit).toList()) { - sender.sendMessage(Component.text(player.getUsername())); - } - sender.sendMessage(Component.text("...")); + for (int i = 0; i < Math.min(limit, playerCount); i++) { + final var player = players.get(i); + var msg = Component.text(player.getUsername()); + if (player.getPlayerConnection().getServerState() == ConnectionState.CONFIGURATION) + msg = msg.append(Component.text(" (config)")); + sender.sendMessage(msg); } + + if (playerCount > limit) sender.sendMessage(Component.text("...")); } } diff --git a/src/main/java/net/minestom/server/MinecraftServer.java b/src/main/java/net/minestom/server/MinecraftServer.java index 17d46e250..21ecf40ce 100644 --- a/src/main/java/net/minestom/server/MinecraftServer.java +++ b/src/main/java/net/minestom/server/MinecraftServer.java @@ -103,7 +103,7 @@ public final class MinecraftServer { */ public static void setBrandName(@NotNull String brandName) { MinecraftServer.brandName = brandName; - PacketUtils.broadcastPacket(PluginMessagePacket.getBrandPacket()); + PacketUtils.broadcastPlayPacket(PluginMessagePacket.getBrandPacket()); } /** @@ -123,7 +123,7 @@ public final class MinecraftServer { */ public static void setDifficulty(@NotNull Difficulty difficulty) { MinecraftServer.difficulty = difficulty; - PacketUtils.broadcastPacket(new ServerDifficultyPacket(difficulty, true)); + PacketUtils.broadcastPlayPacket(new ServerDifficultyPacket(difficulty, true)); } @ApiStatus.Experimental diff --git a/src/main/java/net/minestom/server/adventure/audience/Audiences.java b/src/main/java/net/minestom/server/adventure/audience/Audiences.java index 764b38645..e37dfb1c7 100644 --- a/src/main/java/net/minestom/server/adventure/audience/Audiences.java +++ b/src/main/java/net/minestom/server/adventure/audience/Audiences.java @@ -5,6 +5,7 @@ import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Keyed; import net.minestom.server.MinecraftServer; import net.minestom.server.entity.Player; +import net.minestom.server.network.ConnectionState; import org.jetbrains.annotations.NotNull; import java.util.function.Predicate; @@ -41,7 +42,7 @@ public class Audiences { * @return all audience members */ public static @NotNull Audience all() { - return Audience.audience(audience.server, audience.customs()); + return Audience.audience(audience.server(), audience.customs()); } /** @@ -50,7 +51,7 @@ public class Audiences { * @return all players */ public static @NotNull Audience players() { - return audience.players; + return audience.players(); } /** @@ -60,7 +61,8 @@ public class Audiences { * @return all players matching the predicate */ public static @NotNull Audience players(@NotNull Predicate filter) { - return PacketGroupingAudience.of(MinecraftServer.getConnectionManager().getOnlinePlayers().stream().filter(filter).toList()); + return PacketGroupingAudience.of(MinecraftServer.getConnectionManager().getPlayers(ConnectionState.PLAY) + .stream().filter(filter).toList()); } /** @@ -78,7 +80,7 @@ public class Audiences { * @return the audience of all players and the console */ public static @NotNull Audience server() { - return audience.server; + return audience.server(); } /** diff --git a/src/main/java/net/minestom/server/adventure/audience/IterableAudienceProvider.java b/src/main/java/net/minestom/server/adventure/audience/IterableAudienceProvider.java index f2f3ff0ff..c675ae7ff 100644 --- a/src/main/java/net/minestom/server/adventure/audience/IterableAudienceProvider.java +++ b/src/main/java/net/minestom/server/adventure/audience/IterableAudienceProvider.java @@ -5,6 +5,7 @@ import net.kyori.adventure.key.Key; import net.minestom.server.MinecraftServer; import net.minestom.server.command.ConsoleSender; import net.minestom.server.entity.Player; +import net.minestom.server.network.ConnectionState; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -35,12 +36,12 @@ class IterableAudienceProvider implements AudienceProvider players() { - return MinecraftServer.getConnectionManager().getOnlinePlayers(); + return MinecraftServer.getConnectionManager().getPlayers(ConnectionState.PLAY); } @Override public @NotNull Iterable players(@NotNull Predicate filter) { - return MinecraftServer.getConnectionManager().getOnlinePlayers().stream().filter(filter).toList(); + return MinecraftServer.getConnectionManager().getPlayers(ConnectionState.PLAY).stream().filter(filter).toList(); } @Override diff --git a/src/main/java/net/minestom/server/adventure/audience/SingleAudienceProvider.java b/src/main/java/net/minestom/server/adventure/audience/SingleAudienceProvider.java index 262dfb9a1..8ad86b2da 100644 --- a/src/main/java/net/minestom/server/adventure/audience/SingleAudienceProvider.java +++ b/src/main/java/net/minestom/server/adventure/audience/SingleAudienceProvider.java @@ -4,6 +4,7 @@ import net.kyori.adventure.audience.Audience; import net.kyori.adventure.key.Key; import net.minestom.server.MinecraftServer; import net.minestom.server.entity.Player; +import net.minestom.server.network.ConnectionState; import org.jetbrains.annotations.NotNull; import java.util.function.Predicate; @@ -15,8 +16,6 @@ import java.util.function.Predicate; class SingleAudienceProvider implements AudienceProvider { protected final IterableAudienceProvider collection = new IterableAudienceProvider(); - protected final Audience players = PacketGroupingAudience.of(MinecraftServer.getConnectionManager().getOnlinePlayers()); - protected final Audience server = Audience.audience(this.players, MinecraftServer.getCommandManager().getConsoleSender()); protected SingleAudienceProvider() { } @@ -32,17 +31,18 @@ class SingleAudienceProvider implements AudienceProvider { @Override public @NotNull Audience all() { - return Audience.audience(this.server, this.customs()); + return Audience.audience(this.server(), this.customs()); } @Override public @NotNull Audience players() { - return this.players; + return PacketGroupingAudience.of(MinecraftServer.getConnectionManager().getPlayers(ConnectionState.PLAY)); } @Override public @NotNull Audience players(@NotNull Predicate filter) { - return PacketGroupingAudience.of(MinecraftServer.getConnectionManager().getOnlinePlayers().stream().filter(filter).toList()); + return PacketGroupingAudience.of(MinecraftServer.getConnectionManager().getPlayers(ConnectionState.PLAY) + .stream().filter(filter).toList()); } @Override @@ -52,7 +52,7 @@ class SingleAudienceProvider implements AudienceProvider { @Override public @NotNull Audience server() { - return this.server; + return Audience.audience(players(), MinecraftServer.getCommandManager().getConsoleSender()); } @Override diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index b04be8b9f..02f18bfcb 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -57,12 +57,9 @@ import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.PlayerProvider; import net.minestom.server.network.packet.client.ClientPacket; -import net.minestom.server.network.packet.server.CachedPacket; import net.minestom.server.network.packet.server.SendablePacket; 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.configuration.FinishConfigurationPacket; import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.packet.server.play.data.DeathLocation; @@ -134,6 +131,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, private Component displayName; private PlayerSkin skin; + private Instance pendingInstance = null; private DimensionType dimensionType; private GameMode gameMode; private DeathLocation deathLocation; @@ -254,17 +252,25 @@ public class Player extends LivingEntity implements CommandSender, Localizable, metadata.setNotifyAboutChanges(false); } + @ApiStatus.Internal + public void setPendingInstance(@NotNull Instance pendingInstance) { + // I(mattw) am not a big fan of this function, but somehow we need to store + // the instance and i didn't like a record in ConnectionManager either. + this.pendingInstance = pendingInstance; + } + /** * Used when the player is created. * Init the player and spawn him. *

* WARNING: executed in the main update thread * UNSAFE: Only meant to be used when a socket player connects through the server. - * - * @param spawnInstance the player spawn instance (defined in {@link AsyncPlayerConfigurationEvent}) */ @ApiStatus.Internal - public CompletableFuture UNSAFE_init(@NotNull Instance spawnInstance) { + public CompletableFuture UNSAFE_init() { + final Instance spawnInstance = this.pendingInstance; + this.pendingInstance = null; + this.removed = false; this.dimensionType = spawnInstance.getDimensionType(); @@ -297,9 +303,10 @@ public class Player extends LivingEntity implements CommandSender, Localizable, EventDispatcher.call(skinInitEvent); this.skin = skinInitEvent.getSkin(); // FIXME: when using Geyser, this line remove the skin of the client - PacketUtils.broadcastPacket(getAddPlayerToList()); + PacketUtils.broadcastPlayPacket(getAddPlayerToList()); - for (var player : MinecraftServer.getConnectionManager().getOnlinePlayers()) { + var connectionManager = MinecraftServer.getConnectionManager(); + for (var player : connectionManager.getPlayers(ConnectionState.PLAY)) { if (player != this) { sendPacket(player.getAddPlayerToList()); if (player.displayName != null) { @@ -356,63 +363,15 @@ public class Player extends LivingEntity implements CommandSender, Localizable, *

This will result in them being removed from the current instance, player list, etc.

*/ public void startConfigurationPhase() { - boolean isFirstConfig = true; + Check.stateCondition(playerConnection.getClientState() != ConnectionState.PLAY, + "Player must be in the play state for reconfiguration."); - // 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; - } + // Remove the player, then send them back to configuration + remove(false); - // Call the event and spawn the player. - AsyncUtils.runAsync(() -> { - System.out.println("CALL EVENT"); - var event = new AsyncPlayerConfigurationEvent(this, isFirstConfig); - EventDispatcher.call(event); + var connectionManager = MinecraftServer.getConnectionManager(); + connectionManager.transitionPlayToConfig(this); - 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); - System.out.println("SEND REENTER"); - MinecraftServer.getConnectionManager().transitionPlayToConfig(this); - 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"); -// }); } /** @@ -427,6 +386,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, public void update(long time) { // Process received packets interpretPacketQueue(); + // It is possible to be removed during packet processing, if thats the case exit immediately. if (isRemoved()) return; super.update(time); // Super update (item pickup/fire management) @@ -626,7 +586,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, // Clear all viewable chunks ChunkUtils.forChunksInRange(chunkX, chunkZ, MinecraftServer.getChunkViewDistance(), chunkRemover); // Remove from the tab-list - PacketUtils.broadcastPacket(getRemovePlayerToList()); + PacketUtils.broadcastPlayPacket(getRemovePlayerToList()); // 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. @@ -1126,7 +1086,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, */ public void setDisplayName(@Nullable Component displayName) { this.displayName = displayName; - PacketUtils.broadcastPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME, infoEntry())); + PacketUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME, infoEntry())); } /** @@ -1168,11 +1128,11 @@ public class Player extends LivingEntity implements CommandSender, Localizable, { // Remove player - PacketUtils.broadcastPacket(removePlayerPacket); + PacketUtils.broadcastPlayPacket(removePlayerPacket); sendPacketToViewers(destroyEntitiesPacket); // Show player again - PacketUtils.broadcastPacket(addPlayerPacket); + PacketUtils.broadcastPlayPacket(addPlayerPacket); getViewers().forEach(player -> showPlayer(player.getPlayerConnection())); } @@ -1507,7 +1467,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, // Condition to prevent sending the packets before spawning the player if (isActive()) { sendPacket(new ChangeGameStatePacket(ChangeGameStatePacket.Reason.CHANGE_GAMEMODE, gameMode.id())); - PacketUtils.broadcastPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, infoEntry())); + PacketUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, infoEntry())); } // The client updates their abilities based on the GameMode as follows @@ -2004,7 +1964,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable, public void refreshLatency(int latency) { this.latency = latency; if (getPlayerConnection().getServerState() == ConnectionState.PLAY) { - PacketUtils.broadcastPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LATENCY, infoEntry())); + PacketUtils.broadcastPlayPacket(new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.UPDATE_LATENCY, infoEntry())); } } diff --git a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java index 451559d4b..f5447af85 100644 --- a/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java +++ b/src/main/java/net/minestom/server/entity/fakeplayer/FakePlayer.java @@ -67,7 +67,8 @@ public class FakePlayer extends Player implements NavigableEntity { }).build(); MinecraftServer.getGlobalEventHandler().addListener(spawnListener); } - CONNECTION_MANAGER.startConfigurationState(this); + + CONNECTION_MANAGER.transitionLoginToConfig(this); } /** diff --git a/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java b/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java index fd4e2d512..f18780397 100644 --- a/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java +++ b/src/main/java/net/minestom/server/extras/query/response/BasicQueryResponse.java @@ -21,7 +21,7 @@ public class BasicQueryResponse implements Writeable { this.motd = "A Minestom Server"; this.gametype = "SMP"; this.map = "world"; - this.numPlayers = String.valueOf(MinecraftServer.getConnectionManager().getOnlinePlayers().size()); + this.numPlayers = String.valueOf(MinecraftServer.getConnectionManager().getOnlinePlayerCount()); this.maxPlayers = String.valueOf(Integer.parseInt(this.numPlayers) + 1); } diff --git a/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java b/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java index ee62e17e4..46cb2e6c2 100644 --- a/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java +++ b/src/main/java/net/minestom/server/extras/query/response/FullQueryResponse.java @@ -1,8 +1,10 @@ package net.minestom.server.extras.query.response; import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.minestom.server.MinecraftServer; import net.minestom.server.extras.query.Query; +import net.minestom.server.network.ConnectionState; import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.binary.Writeable; import org.jetbrains.annotations.NotNull; @@ -13,7 +15,7 @@ import java.util.*; * A full query response containing a dynamic set of responses. */ public class FullQueryResponse implements Writeable { - private static final PlainComponentSerializer PLAIN = PlainComponentSerializer.plain(); + private static final PlainTextComponentSerializer PLAIN = PlainTextComponentSerializer.plainText(); private static final byte[] PADDING_10 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, PADDING_11 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -31,7 +33,7 @@ public class FullQueryResponse implements Writeable { this.kv.put(key.getKey(), key.getValue()); } - this.players = MinecraftServer.getConnectionManager().getOnlinePlayers() + this.players = MinecraftServer.getConnectionManager().getPlayers(ConnectionState.PLAY) .stream() .map(player -> PLAIN.serialize(player.getName())) .toList(); diff --git a/src/main/java/net/minestom/server/extras/query/response/QueryKey.java b/src/main/java/net/minestom/server/extras/query/response/QueryKey.java index 0b5762e3b..f5d1ed409 100644 --- a/src/main/java/net/minestom/server/extras/query/response/QueryKey.java +++ b/src/main/java/net/minestom/server/extras/query/response/QueryKey.java @@ -1,6 +1,7 @@ package net.minestom.server.extras.query.response; import net.minestom.server.MinecraftServer; +import net.minestom.server.network.ConnectionState; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -18,8 +19,8 @@ public enum QueryKey { VERSION(() -> MinecraftServer.VERSION_NAME), PLUGINS(FullQueryResponse::generatePluginsValue), MAP(() -> "world"), - NUM_PLAYERS("numplayers", () -> String.valueOf(MinecraftServer.getConnectionManager().getOnlinePlayers().size())), - MAX_PLAYERS("maxplayers", () -> String.valueOf(MinecraftServer.getConnectionManager().getOnlinePlayers().size() + 1)), + NUM_PLAYERS("numplayers", () -> String.valueOf(MinecraftServer.getConnectionManager().getOnlinePlayerCount())), + MAX_PLAYERS("maxplayers", () -> String.valueOf(MinecraftServer.getConnectionManager().getOnlinePlayerCount() + 1)), HOST_PORT("hostport", () -> String.valueOf(MinecraftServer.getServer().getPort())), HOST_IP("hostip", () -> Objects.requireNonNullElse(MinecraftServer.getServer().getAddress(), "localhost")); diff --git a/src/main/java/net/minestom/server/listener/ChatMessageListener.java b/src/main/java/net/minestom/server/listener/ChatMessageListener.java index f82ca0e91..f3630483a 100644 --- a/src/main/java/net/minestom/server/listener/ChatMessageListener.java +++ b/src/main/java/net/minestom/server/listener/ChatMessageListener.java @@ -10,6 +10,7 @@ import net.minestom.server.event.player.PlayerChatEvent; import net.minestom.server.message.ChatPosition; import net.minestom.server.message.Messenger; import net.minestom.server.network.ConnectionManager; +import net.minestom.server.network.ConnectionState; import net.minestom.server.network.packet.client.play.ClientChatMessagePacket; import net.minestom.server.network.packet.client.play.ClientCommandChatPacket; import org.jetbrains.annotations.NotNull; @@ -38,7 +39,7 @@ public class ChatMessageListener { return; } - final Collection players = CONNECTION_MANAGER.getOnlinePlayers(); + final Collection players = CONNECTION_MANAGER.getPlayers(ConnectionState.PLAY); PlayerChatEvent playerChatEvent = new PlayerChatEvent(player, players, () -> buildDefaultChatMessage(player, message), message); // Call the event diff --git a/src/main/java/net/minestom/server/listener/PlayConfigListener.java b/src/main/java/net/minestom/server/listener/PlayConfigListener.java index 257711c5c..6561146b6 100644 --- a/src/main/java/net/minestom/server/listener/PlayConfigListener.java +++ b/src/main/java/net/minestom/server/listener/PlayConfigListener.java @@ -1,23 +1,17 @@ package net.minestom.server.listener; +import net.minestom.server.MinecraftServer; import net.minestom.server.entity.Player; +import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.packet.client.play.ClientConfigurationAckPacket; import org.jetbrains.annotations.NotNull; import java.util.concurrent.ForkJoinPool; public class PlayConfigListener { + private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager(); public static void configAckListener(@NotNull ClientConfigurationAckPacket packet, @NotNull Player player) { -// player.startConfigurationPhase(); - System.out.println("PLAYER HAS REENTERED CONFIGURATION PHASE!!!!!" + player.getUsername()); - ForkJoinPool.commonPool().execute(() -> { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - player.startConfigurationPhase(); - }); + CONNECTION_MANAGER.transitionConfigToPlay(player, false); } } diff --git a/src/main/java/net/minestom/server/listener/common/KeepAliveListener.java b/src/main/java/net/minestom/server/listener/common/KeepAliveListener.java index 3a1627ecd..3173e8a95 100644 --- a/src/main/java/net/minestom/server/listener/common/KeepAliveListener.java +++ b/src/main/java/net/minestom/server/listener/common/KeepAliveListener.java @@ -9,7 +9,6 @@ public final class KeepAliveListener { private static final Component KICK_MESSAGE = Component.text("Bad Keep Alive packet", NamedTextColor.RED); public static void listener(ClientKeepAlivePacket packet, Player player) { - System.out.println("KEEP ALIVE LISTENER"); final long packetId = packet.id(); if (packetId != player.getLastKeepAlive()) { player.kick(KICK_MESSAGE); diff --git a/src/main/java/net/minestom/server/listener/preplay/LoginListener.java b/src/main/java/net/minestom/server/listener/preplay/LoginListener.java index 3f407f117..6c3314f77 100644 --- a/src/main/java/net/minestom/server/listener/preplay/LoginListener.java +++ b/src/main/java/net/minestom/server/listener/preplay/LoginListener.java @@ -89,7 +89,7 @@ public final class LoginListener { final UUID playerUuid = bungee && isSocketConnection ? ((PlayerSocketConnection) connection).gameProfile().uuid() : CONNECTION_MANAGER.getPlayerConnectionUuid(connection, packet.username()); - CONNECTION_MANAGER.startConfigurationState(connection, playerUuid, packet.username()); + CONNECTION_MANAGER.createPlayer(connection, playerUuid, packet.username()); } } @@ -155,7 +155,7 @@ public final class LoginListener { final String profileName = gameProfile.get("name").getAsString(); MinecraftServer.LOGGER.info("UUID of player {} is {}", loginUsername, profileUUID); - CONNECTION_MANAGER.startConfigurationState(connection, profileUUID, profileName); + CONNECTION_MANAGER.createPlayer(connection, profileUUID, profileName); List propertyList = new ArrayList<>(); for (JsonElement element : gameProfile.get("properties").getAsJsonArray()) { JsonObject object = element.getAsJsonObject(); @@ -208,7 +208,7 @@ public final class LoginListener { if (success) { socketConnection.setRemoteAddress(socketAddress); socketConnection.UNSAFE_setProfile(gameProfile); - CONNECTION_MANAGER.startConfigurationState(connection, gameProfile.uuid(), gameProfile.name()); + CONNECTION_MANAGER.createPlayer(connection, gameProfile.uuid(), gameProfile.name()); } else { LoginDisconnectPacket disconnectPacket = new LoginDisconnectPacket(INVALID_PROXY_RESPONSE); socketConnection.sendPacket(disconnectPacket); @@ -219,7 +219,6 @@ public final class LoginListener { public static void loginAckListener(@NotNull ClientLoginAcknowledgedPacket ignored, @NotNull PlayerConnection connection) { final Player player = Objects.requireNonNull(connection.getPlayer()); - CONNECTION_MANAGER.registerPlayer(player); // Registry data var registry = new HashMap(); @@ -236,7 +235,7 @@ public final class LoginListener { connection.sendPacket(PluginMessagePacket.getBrandPacket()); // Enter configuration phase (for the first time) - player.startConfigurationPhase(); + CONNECTION_MANAGER.transitionConfigToPlay(player, true); } } diff --git a/src/main/java/net/minestom/server/network/ConnectionManager.java b/src/main/java/net/minestom/server/network/ConnectionManager.java index 0b7929da6..6ad280801 100644 --- a/src/main/java/net/minestom/server/network/ConnectionManager.java +++ b/src/main/java/net/minestom/server/network/ConnectionManager.java @@ -5,16 +5,20 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.minestom.server.MinecraftServer; import net.minestom.server.entity.Player; import net.minestom.server.event.EventDispatcher; +import net.minestom.server.event.player.AsyncPlayerConfigurationEvent; import net.minestom.server.event.player.AsyncPlayerPreLoginEvent; import net.minestom.server.instance.Instance; import net.minestom.server.network.packet.client.login.ClientLoginStartPacket; import net.minestom.server.network.packet.server.common.KeepAlivePacket; +import net.minestom.server.network.packet.server.configuration.FinishConfigurationPacket; import net.minestom.server.network.packet.server.login.LoginSuccessPacket; +import net.minestom.server.network.packet.server.play.StartConfigurationPacket; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.network.player.PlayerSocketConnection; import net.minestom.server.utils.StringUtils; import net.minestom.server.utils.async.AsyncUtils; import net.minestom.server.utils.debug.DebugUtils; +import net.minestom.server.utils.validate.Check; import org.jctools.queues.MessagePassingQueue; import org.jctools.queues.MpscUnboundedArrayQueue; import org.jetbrains.annotations.ApiStatus; @@ -35,16 +39,16 @@ public final class ConnectionManager { private static final long KEEP_ALIVE_KICK = 30_000; private static final Component TIMEOUT_TEXT = Component.text("Timeout", NamedTextColor.RED); - private record PendingPlayer(@NotNull Player player, @NotNull Instance instance) { - } - - private final MessagePassingQueue waitingPlayers = new MpscUnboundedArrayQueue<>(64); - private final Set configurationPlayers = new CopyOnWriteArraySet<>(); - private final Set players = new CopyOnWriteArraySet<>(); - private final Set unmodifiablePlayers = Collections.unmodifiableSet(players); // All players once their Player object has been instantiated. private final Map connectionPlayerMap = new ConcurrentHashMap<>(); + // Players waiting to be spawned (post configuration state) + private final MessagePassingQueue waitingPlayers = new MpscUnboundedArrayQueue<>(64); + // Players in configuration state + private final Set configurationPlayers = new CopyOnWriteArraySet<>(); + // Players in play state + private final Set playPlayers = new CopyOnWriteArraySet<>(); + // The uuid provider once a player login private volatile UuidProvider uuidProvider = (playerConnection, username) -> UUID.randomUUID(); @@ -52,27 +56,44 @@ public final class ConnectionManager { private volatile PlayerProvider playerProvider = Player::new; /** - * Gets all online players. + * Gets the number of "online" players, eg for the query response. * - * @return an unmodifiable collection containing all the online players + * @apiNote Only includes players in the play state, not players in configuration. */ - public @NotNull Collection<@NotNull Player> getOnlinePlayers() { - return unmodifiablePlayers; + public int getOnlinePlayerCount() { + return playPlayers.size(); } /** - * Gets online players filtered by state. + * Gets players filtered by state. * - *

States before login are not considered online, and will result in nothing being returned.

+ * @param states The state(s) to return players, if empty all players (play and config) are returned. + * Only {@link ConnectionState#CONFIGURATION} and {@link ConnectionState#PLAY} are valid. * * @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 @NotNull Collection<@NotNull Player> getPlayers(@NotNull ConnectionState... state) { -// connectionPlayerMap.values().stream() -// .filter() - return List.of(); + public @NotNull Collection<@NotNull Player> getPlayers(@NotNull ConnectionState... states) { + boolean play = false, config = false; + for (var state : states) { + switch (state) { + case PLAY -> play = true; + case CONFIGURATION -> config = true; + default -> throw new IllegalArgumentException("Cannot fetch players in " + state + "!"); + } + } + + if (config && !play) { // Only play + return Collections.unmodifiableCollection(configurationPlayers); + } else if (!config && play) { // Only configuration + return Collections.unmodifiableCollection(playPlayers); + } else { // Both or neither was specified + final var players = new ArrayList(playPlayers.size() + configurationPlayers.size()); + players.addAll(configurationPlayers); + players.addAll(playPlayers); + return Collections.unmodifiableCollection(players); + } } /** @@ -90,11 +111,13 @@ public final class ConnectionManager { *

* This can cause issue if two or more players have the same username. * - * @param username the player username (ignoreCase) + * @param username the player username (case-insensitive) + * @param states The state(s) to return players, if empty all players (play and config) are returned. + * Only {@link ConnectionState#CONFIGURATION} and {@link ConnectionState#PLAY} are valid. * @return the first player who validate the username condition, null if none was found */ - public @Nullable Player getPlayer(@NotNull String username) { - for (Player player : getOnlinePlayers()) { + public @Nullable Player getPlayer(@NotNull String username, @NotNull ConnectionState... states) { + for (Player player : getPlayers(states)) { if (player.getUsername().equalsIgnoreCase(username)) return player; } @@ -107,10 +130,12 @@ public final class ConnectionManager { * This can cause issue if two or more players have the same UUID. * * @param uuid the player UUID + * @param states The state(s) to return players, if empty all players (play and config) are returned. + * Only {@link ConnectionState#CONFIGURATION} and {@link ConnectionState#PLAY} are valid. * @return the first player who validate the UUID condition, null if none was found */ - public @Nullable Player getPlayer(@NotNull UUID uuid) { - for (Player player : getOnlinePlayers()) { + public @Nullable Player getPlayer(@NotNull UUID uuid, @NotNull ConnectionState... states) { + for (Player player : getPlayers(states)) { if (player.getUuid().equals(uuid)) return player; } @@ -121,9 +146,11 @@ public final class ConnectionManager { * Finds the closest player matching a given username. * * @param username the player username (can be partial) + * @param states The state(s) to return players, if empty all players (play and config) are returned. + * Only {@link ConnectionState#CONFIGURATION} and {@link ConnectionState#PLAY} are valid. * @return the closest match, null if no players are online */ - public @Nullable Player findPlayer(@NotNull String username) { + public @Nullable Player findPlayer(@NotNull String username, @NotNull ConnectionState... states) { Player exact = getPlayer(username); if (exact != null) return exact; final String username1 = username.toLowerCase(Locale.ROOT); @@ -132,8 +159,7 @@ public final class ConnectionManager { final String username2 = player.getUsername().toLowerCase(Locale.ROOT); return StringUtils.jaroWinklerScore(username1, username2); }; - return getOnlinePlayers() - .stream() + return getPlayers(states).stream() .min(Comparator.comparingDouble(distanceFunction::apply)) .filter(player -> distanceFunction.apply(player) > 0) .orElse(null); @@ -186,73 +212,35 @@ public final class ConnectionManager { return playerProvider; } - //todo REDONE TRANSITIONS - - @ApiStatus.Internal - public void transitionLoginToConfig(@NotNull Player player) { - configurationPlayers.add(player); - } - - @ApiStatus.Internal - public void transitionConfigToPlay(@NotNull Player player) { - - } - - @ApiStatus.Internal - public void transitionPlayToConfig(@NotNull Player player) { - configurationPlayers.add(player); - } /** - * Adds a {@link Player} to the players list. - *

- * Used during connection, you shouldn't have to do it manually. - * - * @param player the player + * Creates a player object and begins the transition from the login state to the config state. */ @ApiStatus.Internal - public synchronized void registerPlayer(@NotNull Player player) { - this.players.add(player); - this.connectionPlayerMap.put(player.getPlayerConnection(), player); - } - - /** - * Removes a {@link Player} from the players list. - *

- * Used during disconnection, you shouldn't have to do it manually. - * - * @param connection the player connection - * @see PlayerConnection#disconnect() to properly disconnect a player - */ - @ApiStatus.Internal - public synchronized void removePlayer(@NotNull PlayerConnection connection) { - final Player player = this.connectionPlayerMap.remove(connection); - if (player == null) return; - this.players.remove(player); - } - - @ApiStatus.Internal - public @NotNull Player startConfigurationState(@NotNull PlayerConnection connection, - @NotNull UUID uuid, @NotNull String username) { + public @NotNull Player createPlayer(@NotNull PlayerConnection connection, @NotNull UUID uuid, @NotNull String username) { final Player player = playerProvider.createPlayer(uuid, username, connection); - startConfigurationState(player); + this.connectionPlayerMap.put(connection, player); + transitionLoginToConfig(player); return player; } @ApiStatus.Internal - public CompletableFuture startConfigurationState(@NotNull Player player) { - return AsyncUtils.runAsync(() -> { + public void transitionLoginToConfig(@NotNull Player player) { + AsyncUtils.runAsync(() -> { final PlayerConnection playerConnection = player.getPlayerConnection(); + // Compression if (playerConnection instanceof PlayerSocketConnection socketConnection) { final int threshold = MinecraftServer.getCompressionThreshold(); if (threshold > 0) socketConnection.startCompression(); } + // Call pre login event AsyncPlayerPreLoginEvent asyncPlayerPreLoginEvent = new AsyncPlayerPreLoginEvent(player); EventDispatcher.call(asyncPlayerPreLoginEvent); if (!player.isOnline()) return; // Player has been kicked + // Change UUID/Username based on the event { final String eventUsername = asyncPlayerPreLoginEvent.getUsername(); @@ -273,42 +261,74 @@ public final class ConnectionManager { } @ApiStatus.Internal - public void startPlayState(@NotNull Player player, @NotNull Instance instance) { - this.waitingPlayers.relaxedOffer(new PendingPlayer(player, instance)); + public void transitionPlayToConfig(@NotNull Player player) { + player.sendPacket(new StartConfigurationPacket()); + configurationPlayers.add(player); + } + + @ApiStatus.Internal + public void transitionConfigToPlay(@NotNull Player player, boolean isFirstConfig) { + // Call the event and spawn the player. + AsyncUtils.runAsync(() -> { + var event = new AsyncPlayerConfigurationEvent(player, isFirstConfig); + EventDispatcher.call(event); + + final Instance spawningInstance = event.getSpawningInstance(); + Check.notNull(spawningInstance, "You need to specify a spawning instance in the AsyncPlayerConfigurationEvent"); + + player.setPendingInstance(spawningInstance); + this.waitingPlayers.relaxedOffer(player); + player.sendPacket(new FinishConfigurationPacket()); + }); + } + + /** + * Removes a {@link Player} from the players list. + *

+ * Used during disconnection, you shouldn't have to do it manually. + * + * @param connection the player connection + * @see PlayerConnection#disconnect() to properly disconnect a player + */ + @ApiStatus.Internal + public synchronized void removePlayer(@NotNull PlayerConnection connection) { + final Player player = this.connectionPlayerMap.remove(connection); + if (player == null) return; + this.configurationPlayers.remove(player); + this.playPlayers.remove(player); } /** * Shutdowns the connection manager by kicking all the currently connected players. */ public synchronized void shutdown() { - this.players.clear(); + this.configurationPlayers.clear(); + this.playPlayers.clear(); this.connectionPlayerMap.clear(); } public void tick(long tickStart) { + // Let waiting players into their instances updateWaitingPlayers(); - handleKeepAlive(tickStart); + + // Send keep alive packets + handleKeepAlive(configurationPlayers, tickStart); + handleKeepAlive(playPlayers, tickStart); // Interpret packets for configuration players - for (var player : configurationPlayers) { -// System.out.println("CONFIG INTERPRET: " + player.getUsername()); - - //todo we are required to do this because when we wait for the config ack packet we are not in an instance so not ticking. - // but then once we switch to config the packets must be eval-ed immediately because we are in an instance. What if we change - // the protocol state swap to happen immediately when the packet is read, not when its processed? - player.interpretPacketQueue(); - } + configurationPlayers.forEach(Player::interpretPacketQueue); } /** * Connects waiting players. */ private void updateWaitingPlayers() { - this.waitingPlayers.drain(pp -> { - configurationPlayers.remove(pp.player); + this.waitingPlayers.drain(player -> { + configurationPlayers.remove(player); + playPlayers.add(player); // Spawn the player at Player#getRespawnPoint - CompletableFuture spawnFuture = pp.player.UNSAFE_init(pp.instance); + CompletableFuture spawnFuture = player.UNSAFE_init(); // Required to get the exact moment the player spawns if (DebugUtils.INSIDE_TEST) spawnFuture.join(); @@ -320,10 +340,9 @@ public final class ConnectionManager { * * @param tickStart the time of the update in milliseconds, forwarded to the packet */ - private void handleKeepAlive(long tickStart) { - //todo need to send keep alives for config players also!! + private void handleKeepAlive(@NotNull Collection playerGroup, long tickStart) { final KeepAlivePacket keepAlivePacket = new KeepAlivePacket(tickStart); - for (Player player : getOnlinePlayers()) { + for (Player player : playerGroup) { final long lastKeepAlive = tickStart - player.getLastKeepAlive(); if (lastKeepAlive > KEEP_ALIVE_DELAY && player.didAnswerKeepAlive()) { player.refreshKeepAlive(tickStart); diff --git a/src/main/java/net/minestom/server/network/PacketProcessor.java b/src/main/java/net/minestom/server/network/PacketProcessor.java index 595ace1f1..ddf7276b8 100644 --- a/src/main/java/net/minestom/server/network/PacketProcessor.java +++ b/src/main/java/net/minestom/server/network/PacketProcessor.java @@ -53,10 +53,8 @@ public class PacketProcessor { } public ClientPacket process(@NotNull PlayerConnection connection, int packetId, ByteBuffer body) { -// System.out.println("READ: " + connection.getClientState() + " " + packetId); final ClientPacket packet = create(connection.getClientState(), packetId, body); final ConnectionState state = connection.getClientState(); -// System.out.println("READ2: " + state + " " + packet.getClass().getSimpleName()); // If the packet intends to switch state, do it now. // Since packets are processed next tick for players, we have to switch immediately. @@ -67,7 +65,9 @@ public class PacketProcessor { } switch (state) { + // Process all pre-config packets immediately case HANDSHAKE, STATUS, LOGIN -> packetListenerManager.processClientPacket(state, packet, connection); + // Process config and play packets on the next tick case CONFIGURATION, PLAY -> { final Player player = connection.getPlayer(); assert player != null; diff --git a/src/main/java/net/minestom/server/ping/ResponseData.java b/src/main/java/net/minestom/server/ping/ResponseData.java index 706d9a757..885d850b0 100644 --- a/src/main/java/net/minestom/server/ping/ResponseData.java +++ b/src/main/java/net/minestom/server/ping/ResponseData.java @@ -7,6 +7,8 @@ import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; import net.minestom.server.MinecraftServer; import net.minestom.server.entity.Player; import net.minestom.server.event.server.ServerListPingEvent; +import net.minestom.server.network.ConnectionManager; +import net.minestom.server.network.ConnectionState; import net.minestom.server.utils.identity.NamedAndIdentified; import org.jetbrains.annotations.NotNull; @@ -37,7 +39,7 @@ public class ResponseData { this.entries = new ArrayList<>(); this.version = MinecraftServer.VERSION_NAME; this.protocol = MinecraftServer.PROTOCOL_VERSION; - this.online = MinecraftServer.getConnectionManager().getOnlinePlayers().size(); + this.online = MinecraftServer.getConnectionManager().getOnlinePlayerCount(); this.maxPlayer = this.online + 1; this.description = DEFAULT_DESCRIPTION; this.favicon = ""; diff --git a/src/main/java/net/minestom/server/scoreboard/Team.java b/src/main/java/net/minestom/server/scoreboard/Team.java index 02d35e692..b058d468e 100644 --- a/src/main/java/net/minestom/server/scoreboard/Team.java +++ b/src/main/java/net/minestom/server/scoreboard/Team.java @@ -128,7 +128,7 @@ public class Team implements PacketGroupingAudience { final TeamsPacket addPlayerPacket = new TeamsPacket(teamName, new TeamsPacket.AddEntitiesToTeamAction(toAdd)); // Sends to all online players the add player packet - PacketUtils.broadcastPacket(addPlayerPacket); + PacketUtils.broadcastPlayPacket(addPlayerPacket); // invalidate player members this.isPlayerMembersUpToDate = false; @@ -159,7 +159,7 @@ public class Team implements PacketGroupingAudience { final TeamsPacket removePlayerPacket = new TeamsPacket(teamName, new TeamsPacket.RemoveEntitiesToTeamAction(toRemove)); // Sends to all online player the remove player packet - PacketUtils.broadcastPacket(removePlayerPacket); + PacketUtils.broadcastPlayPacket(removePlayerPacket); // Removes the member from the team this.members.removeAll(toRemove); @@ -463,7 +463,7 @@ public class Team implements PacketGroupingAudience { public void sendUpdatePacket() { final var info = new TeamsPacket.UpdateTeamAction(teamDisplayName, friendlyFlags, nameTagVisibility, collisionRule, teamColor, prefix, suffix); - PacketUtils.broadcastPacket(new TeamsPacket(teamName, info)); + PacketUtils.broadcastPlayPacket(new TeamsPacket(teamName, info)); } @Override diff --git a/src/main/java/net/minestom/server/scoreboard/TeamManager.java b/src/main/java/net/minestom/server/scoreboard/TeamManager.java index dd0b9d9ef..8eb2a2399 100644 --- a/src/main/java/net/minestom/server/scoreboard/TeamManager.java +++ b/src/main/java/net/minestom/server/scoreboard/TeamManager.java @@ -37,7 +37,7 @@ public final class TeamManager { */ protected void registerNewTeam(@NotNull Team team) { this.teams.add(team); - PacketUtils.broadcastPacket(team.createTeamsCreationPacket()); + PacketUtils.broadcastPlayPacket(team.createTeamsCreationPacket()); } /** @@ -60,7 +60,7 @@ public final class TeamManager { */ public boolean deleteTeam(@NotNull Team team) { // Sends to all online players a team destroy packet - PacketUtils.broadcastPacket(team.createTeamDestructionPacket()); + PacketUtils.broadcastPlayPacket(team.createTeamDestructionPacket()); return this.teams.remove(team); } diff --git a/src/main/java/net/minestom/server/utils/PacketUtils.java b/src/main/java/net/minestom/server/utils/PacketUtils.java index b009d7de5..31f33a620 100644 --- a/src/main/java/net/minestom/server/utils/PacketUtils.java +++ b/src/main/java/net/minestom/server/utils/PacketUtils.java @@ -113,7 +113,7 @@ public final class PacketUtils { * Checks if the {@link ServerPacket} is suitable to be wrapped into a {@link CachedPacket}. * Note: {@link ComponentHoldingServerPacket}s are not translated inside a {@link CachedPacket}. * - * @see CachedPacket#body() + * @see CachedPacket#body(ConnectionState) * @see PlayerSocketConnection#writePacketSync(SendablePacket, boolean) */ static boolean shouldUseCachePacket(final @NotNull ServerPacket packet) { @@ -153,8 +153,8 @@ public final class PacketUtils { sendGroupedPacket(players, packet, player -> true); } - public static void broadcastPacket(@NotNull ServerPacket packet) { - sendGroupedPacket(MinecraftServer.getConnectionManager().getOnlinePlayers(), packet); + public static void broadcastPlayPacket(@NotNull ServerPacket packet) { + sendGroupedPacket(MinecraftServer.getConnectionManager().getPlayers(ConnectionState.PLAY), packet); } @ApiStatus.Experimental diff --git a/src/main/java/net/minestom/server/utils/entity/EntityFinder.java b/src/main/java/net/minestom/server/utils/entity/EntityFinder.java index 577928232..7043e8e9c 100644 --- a/src/main/java/net/minestom/server/utils/entity/EntityFinder.java +++ b/src/main/java/net/minestom/server/utils/entity/EntityFinder.java @@ -11,6 +11,8 @@ import net.minestom.server.entity.EntityType; import net.minestom.server.entity.GameMode; import net.minestom.server.entity.Player; import net.minestom.server.instance.Instance; +import net.minestom.server.network.ConnectionManager; +import net.minestom.server.network.ConnectionState; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.math.IntRange; import net.minestom.server.utils.validate.Check; @@ -27,6 +29,7 @@ import java.util.concurrent.ThreadLocalRandom; * It is based on the target selectors used in commands. */ public class EntityFinder { + private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager(); private TargetSelector targetSelector; @@ -307,8 +310,7 @@ public class EntityFinder { private static @NotNull List<@NotNull Entity> findTarget(@Nullable Instance instance, @NotNull TargetSelector targetSelector, @NotNull Point startPosition, @Nullable Entity self) { - final var players = instance != null ? - instance.getPlayers() : MinecraftServer.getConnectionManager().getOnlinePlayers(); + final var players = instance != null ? instance.getPlayers() : CONNECTION_MANAGER.getPlayers(ConnectionState.PLAY); if (targetSelector == TargetSelector.NEAREST_PLAYER) { return players.stream() .min(Comparator.comparingDouble(p -> p.getPosition().distanceSquared(startPosition))) diff --git a/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java b/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java index e32afcf5a..6fe1846f8 100644 --- a/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java +++ b/testing/src/main/java/net/minestom/testing/TestConnectionImpl.java @@ -40,7 +40,7 @@ final class TestConnectionImpl implements TestConnection { event.getPlayer().setRespawnPoint(pos); }); - return process.connection().startConfigurationState(player, true) + return process.connection().createPlayer(player, true) .thenApply(unused -> { process.connection().updateWaitingPlayers(); return player;