Fix incorrect max player slot check

Using the total number of users in the connection set
is not correct since those users may not be logged in
yet. Instead, track separately the number of users
who have passed the slot check.

Fixes https://github.com/PaperMC/Folia/issues/205
This commit is contained in:
Spottedleaf 2024-03-24 14:01:03 -07:00
parent ad2ef004b9
commit b843a3512d
4 changed files with 44 additions and 37 deletions

View File

@ -15719,7 +15719,7 @@ index 45d4638d568ea2aee805aa1b0542533019e5870d..599feff33b43623d7c6bd22158afa730
date1 = fallback;
}
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d433ac7df25 100644
index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..08daa5ed0b4b599836b97eef1e53e630e7659443 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -132,10 +132,10 @@ public abstract class PlayerList {
@ -15735,7 +15735,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
private final UserBanList bans;
private final IpBanList ipBans;
private final ServerOpList ops;
@@ -156,9 +156,56 @@ public abstract class PlayerList {
@@ -156,9 +156,63 @@ public abstract class PlayerList {
// CraftBukkit start
private CraftServer cserver;
@ -15747,6 +15747,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
+ private final Object connectionsStateLock = new Object();
+ private final Map<String, Connection> connectionByName = new java.util.HashMap<>();
+ private final Map<UUID, Connection> connectionById = new java.util.HashMap<>();
+ private final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<Connection> usersCountedAgainstLimit = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>();
+
+ public boolean pushPendingJoin(String userName, UUID byId, Connection conn) {
+ userName = userName.toLowerCase(java.util.Locale.ROOT);
@ -15780,12 +15781,18 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
+ synchronized (this.connectionsStateLock) {
+ this.connectionByName.remove(userName, conn);
+ this.connectionById.remove(byId, conn);
+ this.usersCountedAgainstLimit.remove(conn);
+ }
+ }
+
+ private int getTotalConnections() {
+ private boolean countConnection(Connection conn, int limit) {
+ synchronized (this.connectionsStateLock) {
+ return this.connectionById.size();
+ int count = this.usersCountedAgainstLimit.size();
+ if (count >= limit) {
+ return false;
+ }
+ this.usersCountedAgainstLimit.add(conn);
+ return true;
+ }
+ }
+ // Folia end - region threading
@ -15793,7 +15800,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
public PlayerList(MinecraftServer server, LayeredRegistryAccess<RegistryLayer> registryManager, PlayerDataStorage saveHandler, int maxPlayers) {
this.cserver = server.server = new CraftServer((DedicatedServer) server, this);
server.console = new com.destroystokyo.paper.console.TerminalConsoleCommandSender(); // Paper
@@ -179,7 +226,7 @@ public abstract class PlayerList {
@@ -179,7 +233,7 @@ public abstract class PlayerList {
}
abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor
@ -15802,7 +15809,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
player.isRealPlayer = true; // Paper
player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed
GameProfile gameprofile = player.getGameProfile();
@@ -258,18 +305,42 @@ public abstract class PlayerList {
@@ -258,18 +312,42 @@ public abstract class PlayerList {
player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login
// Paper start - reset to main world spawn if first spawn or invalid world
}
@ -15847,7 +15854,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
Location loc = ev.getSpawnLocation();
worldserver1 = ((CraftWorld) loc.getWorld()).getHandle();
@@ -288,6 +359,10 @@ public abstract class PlayerList {
@@ -288,6 +366,10 @@ public abstract class PlayerList {
player.loadGameTypes(nbttagcompound);
ServerGamePacketListenerImpl playerconnection = new ServerGamePacketListenerImpl(this.server, connection, player, clientData);
@ -15858,7 +15865,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
GameRules gamerules = worldserver1.getGameRules();
boolean flag = gamerules.getBoolean(GameRules.RULE_DO_IMMEDIATE_RESPAWN);
boolean flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO);
@@ -303,7 +378,7 @@ public abstract class PlayerList {
@@ -303,7 +385,7 @@ public abstract class PlayerList {
this.sendPlayerPermissionLevel(player);
player.getStats().markAllDirty();
player.getRecipeBook().sendInitialRecipeBook(player);
@ -15867,7 +15874,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
this.server.invalidateStatus();
MutableComponent ichatmutablecomponent;
@@ -345,7 +420,7 @@ public abstract class PlayerList {
@@ -345,7 +427,7 @@ public abstract class PlayerList {
this.cserver.getPluginManager().callEvent(playerJoinEvent);
if (!player.connection.isAcceptingMessages()) {
@ -15876,7 +15883,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
}
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
@@ -360,8 +435,7 @@ public abstract class PlayerList {
@@ -360,8 +442,7 @@ public abstract class PlayerList {
ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player)); // Paper - Add Listing API for Player
final List<ServerPlayer> onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - Use single player info update packet on join
@ -15886,7 +15893,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
if (entityplayer1.getBukkitEntity().canSee(bukkitPlayer)) {
// Paper start - Add Listing API for Player
@@ -483,7 +557,7 @@ public abstract class PlayerList {
@@ -483,7 +564,7 @@ public abstract class PlayerList {
// Paper start - Configurable player collision; Add to collideRule team if needed
final net.minecraft.world.scores.Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard();
final PlayerTeam collideRuleTeam = scoreboard.getPlayerTeam(this.collideRuleTeamName);
@ -15895,7 +15902,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam);
}
// Paper end - Configurable player collision
@@ -577,7 +651,7 @@ public abstract class PlayerList {
@@ -577,7 +658,7 @@ public abstract class PlayerList {
protected void save(ServerPlayer player) {
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
@ -15904,7 +15911,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
this.playerIo.save(player);
ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit
@@ -617,7 +691,7 @@ public abstract class PlayerList {
@@ -617,7 +698,7 @@ public abstract class PlayerList {
// CraftBukkit end
// Paper start - Configurable player collision; Remove from collideRule team if needed
@ -15913,7 +15920,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
final net.minecraft.world.scores.Scoreboard scoreBoard = this.server.getLevel(Level.OVERWORLD).getScoreboard();
final PlayerTeam team = scoreBoard.getPlayersTeam(this.collideRuleTeamName);
if (entityplayer.getTeam() == team && team != null) {
@@ -657,7 +731,7 @@ public abstract class PlayerList {
@@ -657,7 +738,7 @@ public abstract class PlayerList {
entityplayer.unRide();
worldserver.removePlayerImmediately(entityplayer, Entity.RemovalReason.UNLOADED_WITH_PLAYER);
@ -15922,7 +15929,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
entityplayer.getAdvancements().stopListening();
this.players.remove(entityplayer);
this.playersByName.remove(entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot
@@ -676,8 +750,7 @@ public abstract class PlayerList {
@@ -676,8 +757,7 @@ public abstract class PlayerList {
// CraftBukkit start
// this.broadcastAll(new ClientboundPlayerInfoRemovePacket(List.of(entityplayer.getUUID())));
ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(entityplayer.getUUID()));
@ -15932,7 +15939,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
if (entityplayer2.getBukkitEntity().canSee(entityplayer.getBukkitEntity())) {
entityplayer2.connection.send(packet);
@@ -702,19 +775,12 @@ public abstract class PlayerList {
@@ -702,19 +782,12 @@ public abstract class PlayerList {
ServerPlayer entityplayer;
@ -15954,7 +15961,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
}
// Instead of kicking then returning, we need to store the kick reason
@@ -733,7 +799,7 @@ public abstract class PlayerList {
@@ -733,7 +806,7 @@ public abstract class PlayerList {
ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned.reason", gameprofilebanentry.getReason());
if (gameprofilebanentry.getExpires() != null) {
@ -15963,7 +15970,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
}
// return chatmessage;
@@ -746,14 +812,14 @@ public abstract class PlayerList {
@@ -746,14 +819,14 @@ public abstract class PlayerList {
ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned_ip.reason", ipbanentry.getReason());
if (ipbanentry.getExpires() != null) {
@ -15976,11 +15983,11 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
} else {
// return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile) ? IChatBaseComponent.translatable("multiplayer.disconnect.server_full") : null;
- if (this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile)) {
+ if (this.getTotalConnections() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile)) { // Folia - region threading - we control connection state here now async, not player list size
+ if (!this.countConnection(loginlistener.connection, this.maxPlayers) && !this.canBypassPlayerLimit(gameprofile)) { // Folia - region threading - we control connection state here now async, not player list size
event.disallow(PlayerLoginEvent.Result.KICK_FULL, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.serverFullMessage)); // Spigot // Paper - Adventure
}
}
@@ -819,6 +885,11 @@ public abstract class PlayerList {
@@ -819,6 +892,11 @@ public abstract class PlayerList {
public ServerPlayer respawn(ServerPlayer entityplayer, ServerLevel worldserver, boolean flag, Location location, boolean avoidSuffocation, RespawnReason reason, org.bukkit.event.player.PlayerRespawnEvent.RespawnFlag...respawnFlags) {
// Paper end - Expand PlayerRespawnEvent
@ -15992,7 +15999,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
entityplayer.stopRiding(); // CraftBukkit
this.players.remove(entityplayer);
this.playersByName.remove(entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot
@@ -1018,10 +1089,10 @@ public abstract class PlayerList {
@@ -1018,10 +1096,10 @@ public abstract class PlayerList {
public void tick() {
if (++this.sendAllPlayerInfoIn > 600) {
// CraftBukkit start
@ -16006,7 +16013,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
@Override
public boolean test(ServerPlayer input) {
return target.getBukkitEntity().canSee(input.getBukkitEntity());
@@ -1047,18 +1118,17 @@ public abstract class PlayerList {
@@ -1047,18 +1125,17 @@ public abstract class PlayerList {
// CraftBukkit start - add a world/entity limited version
public void broadcastAll(Packet packet, net.minecraft.world.entity.player.Player entityhuman) {
@ -16029,7 +16036,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
}
}
@@ -1102,8 +1172,7 @@ public abstract class PlayerList {
@@ -1102,8 +1179,7 @@ public abstract class PlayerList {
if (scoreboardteam == null) {
this.broadcastSystemMessage(message, false);
} else {
@ -16039,7 +16046,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
if (entityplayer.getTeam() != scoreboardteam) {
entityplayer.sendSystemMessage(message);
@@ -1114,10 +1183,12 @@ public abstract class PlayerList {
@@ -1114,10 +1190,12 @@ public abstract class PlayerList {
}
public String[] getPlayerNamesArray() {
@ -16055,7 +16062,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
}
return astring;
@@ -1136,7 +1207,9 @@ public abstract class PlayerList {
@@ -1136,7 +1214,9 @@ public abstract class PlayerList {
ServerPlayer entityplayer = this.getPlayer(profile.getId());
if (entityplayer != null) {
@ -16065,7 +16072,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
}
}
@@ -1146,7 +1219,10 @@ public abstract class PlayerList {
@@ -1146,7 +1226,10 @@ public abstract class PlayerList {
ServerPlayer entityplayer = this.getPlayer(profile.getId());
if (entityplayer != null) {
@ -16076,7 +16083,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
}
}
@@ -1207,8 +1283,7 @@ public abstract class PlayerList {
@@ -1207,8 +1290,7 @@ public abstract class PlayerList {
}
public void broadcast(@Nullable net.minecraft.world.entity.player.Player player, double x, double y, double z, double distance, ResourceKey<Level> worldKey, Packet<?> packet) {
@ -16086,7 +16093,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
// CraftBukkit start - Test if player receiving packet can see the source of the packet
if (player != null && !entityplayer.getBukkitEntity().canSee(player.getBukkitEntity())) {
@@ -1238,12 +1313,21 @@ public abstract class PlayerList {
@@ -1238,12 +1320,21 @@ public abstract class PlayerList {
io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main
MinecraftTimings.savePlayers.startTiming(); // Paper
int numSaved = 0;
@ -16113,7 +16120,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
}
// Paper end - Incremental chunk and player saving
}
@@ -1362,6 +1446,20 @@ public abstract class PlayerList {
@@ -1362,6 +1453,20 @@ public abstract class PlayerList {
}
public void removeAll(boolean isRestarting) {
@ -16134,7 +16141,7 @@ index 1e5f709115007ff19901c0a6c3cf884d9e4d3a6c..12502d9db5bae29ed642e179f3a19d43
// Paper end
// CraftBukkit start - disconnect safely
for (ServerPlayer player : this.players) {
@@ -1371,7 +1469,7 @@ public abstract class PlayerList {
@@ -1371,7 +1476,7 @@ public abstract class PlayerList {
// CraftBukkit end
// Paper start - Configurable player collision; Remove collideRule team if it exists

View File

@ -19,10 +19,10 @@ index 58cdb65083134680230d7070f9f6209f2d32873b..aa4b461bbb2c8c4753f7c9057bab1740
if (this.state == ServerLoginPacketListenerImpl.State.WAITING_FOR_DUPE_DISCONNECT && !this.isPlayerAlreadyInWorld((GameProfile) Objects.requireNonNull(this.authenticatedProfile))) {
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 12502d9db5bae29ed642e179f3a19d433ac7df25..ebbe5dda644a06bfd4769934e33402b2c009c7e2 100644
index 08daa5ed0b4b599836b97eef1e53e630e7659443..a390227e5af1232f2090d2be72f7789805025f76 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -172,6 +172,17 @@ public abstract class PlayerList {
@@ -173,6 +173,17 @@ public abstract class PlayerList {
conflictingId = this.connectionById.get(byId);
if (conflictingName == null && conflictingId == null) {

View File

@ -7,10 +7,10 @@ This allows the player to be re-positioned before logging into
the world without causing thread checks to trip on Folia.
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index ebbe5dda644a06bfd4769934e33402b2c009c7e2..754de3a79e1d8f9e8a5aabef78319958a1c37f72 100644
index a390227e5af1232f2090d2be72f7789805025f76..bbf43b5844a75a25c1757cfb1c3c9dbe9b1fadde 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -515,7 +515,13 @@ public abstract class PlayerList {
@@ -522,7 +522,13 @@ public abstract class PlayerList {
CompoundTag nbttagcompound1 = nbttagcompound.getCompound("RootVehicle");
// CraftBukkit start
ServerLevel finalWorldServer = worldserver1;

View File

@ -1779,10 +1779,10 @@ index f72e3d2decf8eb2a5a802bb1c6c8aa29e08912cf..81749b8da7182abd1bf35629f33388e8
} else {
passenger.stopRiding();
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 754de3a79e1d8f9e8a5aabef78319958a1c37f72..c8f8d41da92c08032ac3f78e002d081d6cd0b763 100644
index bbf43b5844a75a25c1757cfb1c3c9dbe9b1fadde..90be312057221a5a78066d89783c5e22008d797d 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -1328,6 +1328,7 @@ public abstract class PlayerList {
@@ -1335,6 +1335,7 @@ public abstract class PlayerList {
public void saveAll(int interval) {
io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main
@ -1790,7 +1790,7 @@ index 754de3a79e1d8f9e8a5aabef78319958a1c37f72..c8f8d41da92c08032ac3f78e002d081d
MinecraftTimings.savePlayers.startTiming(); // Paper
int numSaved = 0;
long now = System.nanoTime(); // Folia - region threading
@@ -1339,7 +1340,9 @@ public abstract class PlayerList {
@@ -1346,7 +1347,9 @@ public abstract class PlayerList {
}
// Folia end - region threading
if (interval == -1 || now - entityplayer.lastSave >= timeInterval) { // Folia - region threading