2021-06-14 03:06:38 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 19 Apr 2020 04:28:29 -0400
Subject: [PATCH] Load Chunks for Login Asynchronously
2022-08-27 06:56:55 +02:00
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
2022-10-02 09:56:36 +02:00
index 5a2797104d43d5981fe0d4599c0abbbf8658f153..c0e17bbf04723da76ea6952d9558dd4d34b00f6c 100644
2022-08-27 06:56:55 +02:00
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -170,6 +170,7 @@ import org.bukkit.event.world.GenericGameEvent;
import org.bukkit.event.world.TimeSkipEvent;
// CraftBukkit end
import it.unimi.dsi.fastutil.ints.IntArrayList; // Paper
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
public class ServerLevel extends Level implements WorldGenLevel {
2022-09-26 10:02:51 +02:00
@@ -435,6 +436,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
2022-08-27 06:56:55 +02:00
return this.getServer().getPlayerList().getPlayer(uuid);
}
// Paper end
+ public final ReferenceOpenHashSet<ServerPlayer> pendingLogin = new ReferenceOpenHashSet<>(); // Paper
// Add env and gen to constructor, IWorldDataServer -> WorldDataServer
public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
2021-06-14 03:06:38 +02:00
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
2022-09-26 10:02:51 +02:00
index 3008e1cce4df86150dec87cca0433676033d4f73..fdc1d1d5840ee7f12e4a72656698924c51fea05c 100644
2021-06-14 03:06:38 +02:00
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
2022-07-27 22:17:18 +02:00
@@ -182,6 +182,7 @@ public class ServerPlayer extends Player {
2021-06-14 03:06:38 +02:00
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
public ServerGamePacketListenerImpl connection;
+ public net.minecraft.network.Connection networkManager; // Paper
public final MinecraftServer server;
public final ServerPlayerGameMode gameMode;
private final PlayerAdvancements advancements;
2022-09-26 10:02:51 +02:00
@@ -255,6 +256,7 @@ public class ServerPlayer extends Player {
2021-06-14 03:06:38 +02:00
public boolean joining = true;
public boolean sentListPacket = false;
public boolean supressTrackerForLogin = false; // Paper
+ public boolean didPlayerJoinEvent = false; // Paper
public Integer clientViewDistance;
2022-03-16 16:57:51 +01:00
public String kickLeaveMessage = null; // SPIGOT-3034: Forward leave message to PlayerQuitEvent
2021-06-14 03:06:38 +02:00
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java
2022-09-26 10:02:51 +02:00
index 97d1ff2af23bac14e67bca5896843325aaa5bfc1..e9bc61590d33dc341074371859ceec54599e6c47 100644
2021-06-14 03:06:38 +02:00
--- a/src/main/java/net/minecraft/server/level/TicketType.java
+++ b/src/main/java/net/minecraft/server/level/TicketType.java
2022-09-26 10:02:51 +02:00
@@ -23,6 +23,7 @@ public class TicketType<T> {
2021-06-14 03:06:38 +02:00
public static final TicketType<ChunkPos> FORCED = TicketType.create("forced", Comparator.comparingLong(ChunkPos::toLong));
public static final TicketType<ChunkPos> LIGHT = TicketType.create("light", Comparator.comparingLong(ChunkPos::toLong));
public static final TicketType<BlockPos> PORTAL = TicketType.create("portal", Vec3i::compareTo, 300);
+ public static final TicketType<Long> LOGIN = create("login", Long::compareTo, 100); // Paper
public static final TicketType<Integer> POST_TELEPORT = TicketType.create("post_teleport", Integer::compareTo, 5);
public static final TicketType<ChunkPos> UNKNOWN = TicketType.create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1);
public static final TicketType<Unit> PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
2022-09-12 13:31:45 +02:00
index 3af9f2d86cf2a9566e22865689101245647d05a5..fe722106e20e199eb914a09f8dbc1409e27f1d69 100644
2021-06-14 03:06:38 +02:00
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
2022-08-29 15:21:45 +02:00
@@ -346,6 +346,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
2021-06-14 03:06:38 +02:00
2022-07-27 22:17:18 +02:00
@Override
2021-06-14 03:06:38 +02:00
public void tick() {
+ // Paper start - login async
+ // Don't tick if not valid (dead), otherwise we load chunks below
+ if (this.player.valid) {
+ // Paper end
2022-06-08 06:39:43 +02:00
if (this.ackBlockChangesUpTo > -1) {
this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo));
this.ackBlockChangesUpTo = -1;
2022-08-29 15:21:45 +02:00
@@ -392,7 +396,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic
2021-06-14 03:06:38 +02:00
this.lastVehicle = null;
this.clientVehicleIsFloating = false;
this.aboveGroundVehicleTickCount = 0;
- }
+ }} // Paper - end if (valid)
this.server.getProfiler().push("keepAlive");
// Paper Start - give clients a longer time to respond to pings as per pre 1.12.2 timings
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
2022-10-02 09:56:36 +02:00
index 6fd0e5a97d0ed9155b12dac94c075e1225a22e93..c16cb8ebe28987f1630fe659dfa437264bd236e1 100644
2021-06-14 03:06:38 +02:00
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
2022-08-08 17:25:41 +02:00
@@ -90,7 +90,7 @@ public class ServerLoginPacketListenerImpl implements TickablePacketListener, Se
2021-06-14 03:06:38 +02:00
}
// Paper end
} else if (this.state == ServerLoginPacketListenerImpl.State.DELAY_ACCEPT) {
- ServerPlayer entityplayer = this.server.getPlayerList().getPlayer(this.gameProfile.getId());
+ ServerPlayer entityplayer = this.server.getPlayerList().getActivePlayer(this.gameProfile.getId()); // Paper
if (entityplayer == null) {
this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
2022-09-17 23:58:51 +02:00
@@ -189,7 +189,7 @@ public class ServerLoginPacketListenerImpl implements TickablePacketListener, Se
2021-06-14 03:06:38 +02:00
}
this.connection.send(new ClientboundGameProfilePacket(this.gameProfile));
- ServerPlayer entityplayer = this.server.getPlayerList().getPlayer(this.gameProfile.getId());
+ ServerPlayer entityplayer = this.server.getPlayerList().getActivePlayer(this.gameProfile.getId()); // Paper
try {
2021-11-24 12:38:00 +01:00
ServerPlayer entityplayer1 = this.server.getPlayerList().getPlayerForLogin(this.gameProfile, s); // CraftBukkit - add player reference
2021-06-14 03:06:38 +02:00
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
2022-09-26 10:02:51 +02:00
index 1096e24835194f20425f75228cafe62adebc2282..f37787b9d018a624b509612729f18ca077b55f55 100644
2021-06-14 03:06:38 +02:00
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
2022-07-27 22:17:18 +02:00
@@ -139,6 +139,7 @@ public abstract class PlayerList {
2021-06-14 03:06:38 +02:00
private final IpBanList ipBans;
private final ServerOpList ops;
private final UserWhiteList whitelist;
+ private final Map<UUID, ServerPlayer> pendingPlayers = Maps.newHashMap(); // Paper
// CraftBukkit start
2021-06-20 21:25:59 +02:00
// private final Map<UUID, ServerStatisticManager> stats;
// private final Map<UUID, AdvancementDataPlayer> advancements;
2022-09-01 18:51:59 +02:00
@@ -180,6 +181,13 @@ public abstract class PlayerList {
2021-06-14 03:06:38 +02:00
public void placeNewPlayer(Connection connection, ServerPlayer player) {
2022-09-26 10:02:51 +02:00
player.isRealPlayer = true; // Paper
2022-09-01 18:51:59 +02:00
player.loginTime = System.currentTimeMillis(); // Paper
+ // Paper start
+ ServerPlayer prev = pendingPlayers.put(player.getUUID(), player);
2021-06-14 03:06:38 +02:00
+ if (prev != null) {
+ disconnectPendingPlayer(prev);
+ }
2022-09-01 18:51:59 +02:00
+ player.networkManager = connection;
+ // Paper end
2021-06-14 03:06:38 +02:00
GameProfile gameprofile = player.getGameProfile();
GameProfileCache usercache = this.server.getProfileCache();
2022-09-01 18:51:59 +02:00
Optional<GameProfile> optional = usercache.get(gameprofile.getId());
@@ -192,7 +200,7 @@ public abstract class PlayerList {
2021-06-14 03:06:38 +02:00
if (nbttagcompound != null && nbttagcompound.contains("bukkit")) {
CompoundTag bukkit = nbttagcompound.getCompound("bukkit");
s = bukkit.contains("lastKnownName", 8) ? bukkit.getString("lastKnownName") : s;
- }
+ }String lastKnownName = s; // Paper
// CraftBukkit end
if (nbttagcompound != null) {
2022-09-01 18:51:59 +02:00
@@ -219,11 +227,15 @@ public abstract class PlayerList {
2022-01-14 04:56:45 +01:00
if (nbttagcompound == null) player.fudgeSpawnLocation(worldserver1); // Paper - only move to spawn on first login, otherwise, stay where you are....
player.setLevel(worldserver1);
- String s1 = "local";
+ // Paper start - make s1 final
+ final String s1;
if (connection.getRemoteAddress() != null) {
s1 = connection.getRemoteAddress().toString();
+ } else {
+ s1 = "local";
}
+ // Paper end
// Spigot start - spawn location event
Player spawnPlayer = player.getBukkitEntity();
2022-09-01 18:51:59 +02:00
@@ -265,6 +277,56 @@ public abstract class PlayerList {
2021-06-14 03:06:38 +02:00
player.getRecipeBook().sendInitialRecipeBook(player);
this.updateEntireScoreboard(worldserver1.getScoreboard(), player);
this.server.invalidateStatus();
+ // Paper start - async load spawn in chunk
+ ServerLevel finalWorldserver = worldserver1;
2022-08-27 06:56:55 +02:00
+ finalWorldserver.pendingLogin.add(player);
2021-06-14 03:06:38 +02:00
+ int chunkX = loc.getBlockX() >> 4;
+ int chunkZ = loc.getBlockZ() >> 4;
+ final net.minecraft.world.level.ChunkPos pos = new net.minecraft.world.level.ChunkPos(chunkX, chunkZ);
+ net.minecraft.server.level.ChunkMap playerChunkMap = worldserver1.getChunkSource().chunkMap;
+ net.minecraft.server.level.DistanceManager distanceManager = playerChunkMap.distanceManager;
2022-09-01 18:51:59 +02:00
+ net.minecraft.server.ChunkSystem.scheduleTickingState(
+ worldserver1, chunkX, chunkZ, net.minecraft.server.level.ChunkHolder.FullChunkStatus.ENTITY_TICKING, true,
+ ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHEST,
+ (chunk) -> {
+ MinecraftServer.getServer().scheduleOnMain(() -> {
+ try {
+ if (!playerconnection.connection.isConnected()) {
+ return;
+ }
+ PlayerList.this.postChunkLoadJoin(
+ player, finalWorldserver, connection, playerconnection,
+ nbttagcompound, s1, lastKnownName
+ );
+ distanceManager.addTicket(net.minecraft.server.level.TicketType.LOGIN, pos, 31, pos.toLong());
+ } finally {
+ finalWorldserver.pendingLogin.remove(player);
2022-08-29 15:21:45 +02:00
+ }
2022-09-01 18:51:59 +02:00
+ });
+ }
+ );
2021-06-14 03:06:38 +02:00
+ }
+
+ public ServerPlayer getActivePlayer(UUID uuid) {
2021-06-17 19:11:00 +02:00
+ ServerPlayer player = this.playersByUUID.get(uuid);
2021-06-14 03:06:38 +02:00
+ return player != null ? player : pendingPlayers.get(uuid);
+ }
+
+ void disconnectPendingPlayer(ServerPlayer entityplayer) {
2022-06-08 06:39:43 +02:00
+ Component msg = Component.translatable("multiplayer.disconnect.duplicate_login");
2022-07-28 00:20:14 +02:00
+ entityplayer.networkManager.send(new net.minecraft.network.protocol.game.ClientboundDisconnectPacket(msg), net.minecraft.network.PacketSendListener.thenRun(() -> {
2021-06-14 03:06:38 +02:00
+ entityplayer.networkManager.disconnect(msg);
+ entityplayer.networkManager = null;
2022-07-28 00:20:14 +02:00
+ }));
2021-06-14 03:06:38 +02:00
+ }
+
+ private void postChunkLoadJoin(ServerPlayer player, ServerLevel worldserver1, Connection networkmanager, ServerGamePacketListenerImpl playerconnection, CompoundTag nbttagcompound, String s1, String s) {
+ pendingPlayers.remove(player.getUUID(), player);
+ if (!networkmanager.isConnected()) {
+ return;
+ }
+ player.didPlayerJoinEvent = true;
+ // Paper end
2022-06-08 06:39:43 +02:00
MutableComponent ichatmutablecomponent;
2021-06-14 03:06:38 +02:00
if (player.getGameProfile().getName().equalsIgnoreCase(s)) {
2022-09-01 18:51:59 +02:00
@@ -506,6 +568,7 @@ public abstract class PlayerList {
2021-06-14 03:06:38 +02:00
protected void save(ServerPlayer player) {
if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
+ if (!player.didPlayerJoinEvent) return; // Paper - If we never fired PJE, we disconnected during login. Data has not changed, and additionally, our saved vehicle is not loaded! If we save now, we will lose our vehicle (CraftBukkit bug)
this.playerIo.save(player);
ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit
2022-09-01 18:51:59 +02:00
@@ -533,7 +596,7 @@ public abstract class PlayerList {
2021-06-14 03:06:38 +02:00
}
2022-06-09 10:51:45 +02:00
PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName())));
2021-06-14 03:06:38 +02:00
- this.cserver.getPluginManager().callEvent(playerQuitEvent);
+ if (entityplayer.didPlayerJoinEvent) this.cserver.getPluginManager().callEvent(playerQuitEvent); // Paper - if we disconnected before join ever fired, don't fire quit
entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
if (server.isSameThread()) entityplayer.doTick(); // SPIGOT-924 // Paper - don't tick during emergency shutdowns (Watchdog)
2022-09-01 18:51:59 +02:00
@@ -578,6 +641,13 @@ public abstract class PlayerList {
2021-06-20 21:25:59 +02:00
// this.advancements.remove(uuid);
2021-06-14 03:06:38 +02:00
// CraftBukkit end
}
+ // Paper start
+ entityplayer1 = pendingPlayers.get(uuid);
+ if (entityplayer1 == entityplayer) {
+ pendingPlayers.remove(uuid);
+ }
+ entityplayer.networkManager = null;
+ // Paper end
// CraftBukkit start
2021-11-24 12:38:00 +01:00
// this.broadcastAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer}));
2022-09-01 18:51:59 +02:00
@@ -595,7 +665,7 @@ public abstract class PlayerList {
2021-06-14 03:06:38 +02:00
this.cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity());
// CraftBukkit end
- return playerQuitEvent.quitMessage(); // Paper - Adventure
+ return entityplayer.didPlayerJoinEvent ? playerQuitEvent.quitMessage() : null; // CraftBukkit // Paper - Adventure // Paper - don't print quit if we never printed join
}
// CraftBukkit start - Whole method, SocketAddress to LoginListener, added hostname to signature, return EntityPlayer
2022-09-01 18:51:59 +02:00
@@ -614,6 +684,13 @@ public abstract class PlayerList {
2021-06-14 03:06:38 +02:00
list.add(entityplayer);
}
}
+ // Paper start - check pending players too
+ entityplayer = pendingPlayers.get(uuid);
+ if (entityplayer != null) {
+ this.pendingPlayers.remove(uuid);
+ disconnectPendingPlayer(entityplayer);
+ }
+ // Paper end
Iterator iterator = list.iterator();
2022-08-27 06:56:55 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
2022-09-26 10:02:51 +02:00
index b92dff790cfe699c3e6a036f1377c3052373fe05..237127907c3c8ddcd16bdc9645e84a2d0b922440 100644
2022-08-27 06:56:55 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1219,7 +1219,7 @@ public final class CraftServer implements Server {
return false;
}
- if (handle.players().size() > 0) {
+ if (handle.players().size() > 0 || handle.pendingLogin.size() > 0) { // Paper
return false;
}