From 3dc63160ade1b4a3feac971d88fb0b6ecbb5c28e Mon Sep 17 00:00:00 2001 From: Aikar Date: Sun, 19 Apr 2020 04:28:29 -0400 Subject: [PATCH] Load Chunks for Login Asynchronously diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java index 96a47dd1c2..96ebe0b226 100644 --- a/src/main/java/net/minecraft/server/Entity.java +++ b/src/main/java/net/minecraft/server/Entity.java @@ -1382,7 +1382,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke this.pitch = MathHelper.a(f1, -90.0F, 90.0F) % 360.0F; this.lastYaw = this.yaw; this.lastPitch = this.pitch; - world.getChunkAt((int) Math.floor(this.locX) >> 4, (int) Math.floor(this.locZ) >> 4); // CraftBukkit + if (valid) world.getChunkAt((int) Math.floor(this.locX) >> 4, (int) Math.floor(this.locZ) >> 4); // CraftBukkit // Paper } public void setPositionRotation(BlockPosition blockposition, float f, float f1) { diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java index 686fd4cbad..079ddc714e 100644 --- a/src/main/java/net/minecraft/server/EntityPlayer.java +++ b/src/main/java/net/minecraft/server/EntityPlayer.java @@ -43,6 +43,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { private static final Logger LOGGER = LogManager.getLogger(); public String locale = null; // CraftBukkit - lowercase // Paper - default to null public PlayerConnection playerConnection; + public NetworkManager networkManager; // Paper public final MinecraftServer server; public final PlayerInteractManager playerInteractManager; public final Deque removeQueue = new ArrayDeque<>(); // Paper @@ -105,6 +106,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { public boolean joining = true; public boolean sentListPacket = false; public boolean supressTrackerForLogin = false; // Paper + public boolean didPlayerJoinEvent = false; // Paper public Integer clientViewDistance; // CraftBukkit end public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper diff --git a/src/main/java/net/minecraft/server/LoginListener.java b/src/main/java/net/minecraft/server/LoginListener.java index f1222fcb2b..28f48f2252 100644 --- a/src/main/java/net/minecraft/server/LoginListener.java +++ b/src/main/java/net/minecraft/server/LoginListener.java @@ -66,7 +66,7 @@ public class LoginListener implements PacketLoginInListener { } // Paper end } else if (this.g == LoginListener.EnumProtocolState.DELAY_ACCEPT) { - EntityPlayer entityplayer = this.server.getPlayerList().a(this.i.getId()); + EntityPlayer entityplayer = this.server.getPlayerList().getActivePlayer(this.i.getId()); // Paper if (entityplayer == null) { this.g = LoginListener.EnumProtocolState.READY_TO_ACCEPT; @@ -165,7 +165,7 @@ public class LoginListener implements PacketLoginInListener { } this.networkManager.sendPacket(new PacketLoginOutSuccess(this.i)); - EntityPlayer entityplayer = this.server.getPlayerList().a(this.i.getId()); + EntityPlayer entityplayer = this.server.getPlayerList().getActivePlayer(this.i.getId()); // Paper if (entityplayer != null) { this.g = LoginListener.EnumProtocolState.DELAY_ACCEPT; diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java index 7929fcc800..c3710b73af 100644 --- a/src/main/java/net/minecraft/server/PlayerConnection.java +++ b/src/main/java/net/minecraft/server/PlayerConnection.java @@ -142,6 +142,7 @@ public class PlayerConnection implements PacketListenerPlayIn { // CraftBukkit end public void tick() { + if (!this.player.valid) return; // Paper this.syncPosition(); this.player.lastX = this.player.locX(); this.player.lastY = this.player.locY(); diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java index ec45c30dd3..eaba3cbf06 100644 --- a/src/main/java/net/minecraft/server/PlayerList.java +++ b/src/main/java/net/minecraft/server/PlayerList.java @@ -52,11 +52,12 @@ public abstract class PlayerList { private static final SimpleDateFormat g = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z"); private final MinecraftServer server; public final List players = new java.util.concurrent.CopyOnWriteArrayList(); // CraftBukkit - ArrayList -> CopyOnWriteArrayList: Iterator safety - private final Map j = Maps.newHashMap(); + private final Map j = Maps.newHashMap();Map getUUIDMap() { return j; } // Paper - OBFHELPER private final GameProfileBanList k; private final IpBanList l; private final OpList operators; private final WhiteList whitelist; + private final Map pendingPlayers = Maps.newHashMap(); // Paper // CraftBukkit start // private final Map o; // private final Map p; @@ -94,6 +95,11 @@ public abstract class PlayerList { } public void a(NetworkManager networkmanager, EntityPlayer entityplayer) { + EntityPlayer prev = pendingPlayers.put(entityplayer.getUniqueID(), entityplayer);// Paper + if (prev != null) { + disconnectPendingPlayer(prev); + } + entityplayer.networkManager = networkmanager; // Paper entityplayer.loginTime = System.currentTimeMillis(); // Paper GameProfile gameprofile = entityplayer.getProfile(); UserCache usercache = this.server.getUserCache(); @@ -107,7 +113,7 @@ public abstract class PlayerList { if (nbttagcompound != null && nbttagcompound.hasKey("bukkit")) { NBTTagCompound bukkit = nbttagcompound.getCompound("bukkit"); s = bukkit.hasKeyOfType("lastKnownName", 8) ? bukkit.getString("lastKnownName") : s; - } + }String lastKnownName = s; // Paper if (nbttagcompound == null) entityplayer.moveToSpawn(worldserver); // Paper - only move to spawn on first login, otherwise, stay where you are.... // CraftBukkit end @@ -158,6 +164,46 @@ public abstract class PlayerList { entityplayer.B().a(entityplayer); this.sendScoreboard(worldserver.getScoreboard(), entityplayer); this.server.invalidatePingSample(); + // Paper start - async load spawn in chunk + WorldServer finalWorldserver = worldserver; + int chunkX = loc.getBlockX() >> 4; + int chunkZ = loc.getBlockZ() >> 4; + worldserver.getChunkProvider().getTickingChunkAsync(chunkX, chunkZ, (chunk -> { // use ticking - as it has at least 1 neighbours loaded + postChunkLoadJoin(entityplayer, finalWorldserver, networkmanager, playerconnection, nbttagcompound, networkmanager.getSocketAddress().toString(), + lastKnownName); + })); + // boost the priorities + worldserver.asyncChunkTaskManager.raisePriority(chunkX, chunkZ, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY); + for (int cx = -1; cx <= 1; cx++) { + for (int cz = -1; cz <= 1; cz++) { + if (cx == 0 && cz == 0) continue; + // we have to directly request it otherwise the task won't be started yet to boost priority + worldserver.getChunkProvider().getFullChunkAsync(chunkX + cx, chunkZ + cz, null); + worldserver.asyncChunkTaskManager.raisePriority(chunkX + cx, chunkZ + cz, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY); + } + } + } + + EntityPlayer getActivePlayer(UUID uuid) { + EntityPlayer player = this.getUUIDMap().get(uuid); + return player != null ? player : pendingPlayers.get(uuid); + } + + void disconnectPendingPlayer(EntityPlayer entityplayer) { + ChatMessage msg = new ChatMessage("multiplayer.disconnect.duplicate_login", new Object[0]); + entityplayer.networkManager.sendPacket(new PacketPlayOutKickDisconnect(msg), (future) -> { + entityplayer.networkManager.close(msg); + entityplayer.networkManager = null; + }); + } + + private void postChunkLoadJoin(EntityPlayer entityplayer, WorldServer worldserver, NetworkManager networkmanager, PlayerConnection playerconnection, NBTTagCompound nbttagcompound, String s1, String s) { + pendingPlayers.remove(entityplayer.getUniqueID(), entityplayer); + if (!networkmanager.isConnected()) { + return; + } + entityplayer.didPlayerJoinEvent = true; + // Paper end ChatMessage chatmessage; if (entityplayer.getProfile().getName().equalsIgnoreCase(s)) { @@ -388,6 +434,7 @@ public abstract class PlayerList { protected void savePlayerFile(EntityPlayer entityplayer) { if (!entityplayer.getBukkitEntity().isPersistent()) return; // CraftBukkit + if (!entityplayer.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.playerFileData.save(entityplayer); ServerStatisticManager serverstatisticmanager = (ServerStatisticManager) entityplayer.getStatisticManager(); // CraftBukkit @@ -412,7 +459,7 @@ public abstract class PlayerList { org.bukkit.craftbukkit.event.CraftEventFactory.handleInventoryCloseEvent(entityplayer, org.bukkit.event.inventory.InventoryCloseEvent.Reason.DISCONNECT); // Paper PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(cserver.getPlayer(entityplayer), "\u00A7e" + entityplayer.getName() + " left the game"); - cserver.getPluginManager().callEvent(playerQuitEvent); + if (entityplayer.didPlayerJoinEvent) cserver.getPluginManager().callEvent(playerQuitEvent); // Paper - if we disconnected before join ever fired, don't fire quit entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage()); if (server.isMainThread()) entityplayer.playerTick();// SPIGOT-924 // Paper - don't tick during emergency shutdowns (Watchdog) @@ -464,6 +511,13 @@ public abstract class PlayerList { // this.p.remove(uuid); // CraftBukkit end } + // Paper start + entityplayer1 = pendingPlayers.get(uuid); + if (entityplayer1 == entityplayer) { + pendingPlayers.remove(uuid); + } + entityplayer.networkManager = null; + // Paper end // CraftBukkit start // this.sendAll(new PacketPlayOutPlayerInfo(EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer})); @@ -481,7 +535,7 @@ public abstract class PlayerList { cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity()); // CraftBukkit end - return playerQuitEvent.getQuitMessage(); // CraftBukkit + return entityplayer.didPlayerJoinEvent ? playerQuitEvent.getQuitMessage() : null; // CraftBukkit // Paper - don't print quit if we never printed join } // CraftBukkit start - Whole method, SocketAddress to LoginListener, added hostname to signature, return EntityPlayer @@ -500,6 +554,13 @@ public abstract class PlayerList { 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(); -- 2.25.1