Paper/Spigot-Server-Patches/0486-Load-Chunks-for-Login-Asynchronously.patch
Aikar 8a91bfd240
Improvements to async login
Bump chunk priority to ensure chunks load fast
Handle case where client disconnects before they even fire PlayerJoinEvent
  - no longer call PlayerQuitEvent or print quit message.
  - don't save the player data file if never joined. Nothing has changed.
    CraftBukkit has a bug here that if you do save it, you will lose
    any horse that the player logged off on because the horse hasn't
    been resummoned yet.
2020-04-22 05:40:06 -04:00

109 lines
6.7 KiB
Diff

From 8a89997b6fd09a04f3085e265e205c0c1c2dcb58 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
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..84c6e5b614 100644
--- a/src/main/java/net/minecraft/server/EntityPlayer.java
+++ b/src/main/java/net/minecraft/server/EntityPlayer.java
@@ -105,6 +105,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/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..ddecbc0a28 100644
--- a/src/main/java/net/minecraft/server/PlayerList.java
+++ b/src/main/java/net/minecraft/server/PlayerList.java
@@ -173,6 +173,31 @@ public abstract class PlayerList {
this.players.add(entityplayer);
this.playersByName.put(entityplayer.getName().toLowerCase(java.util.Locale.ROOT), entityplayer); // Spigot
this.j.put(entityplayer.getUniqueID(), entityplayer);
+ // 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, playerconnection, nbttagcompound, networkmanager.getSocketAddress().toString(), joinMessage);
+ }));
+ // 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, (c) -> {});
+ worldserver.asyncChunkTaskManager.raisePriority(chunkX + cx, chunkZ + cz, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY);
+ }
+ }
+
+ }
+ private void postChunkLoadJoin(EntityPlayer entityplayer, WorldServer worldserver, PlayerConnection playerconnection, NBTTagCompound nbttagcompound, String s1, String joinMessage) {
+ if (!entityplayer.playerConnection.networkManager.isConnected()) {
+ return;
+ }
+ entityplayer.didPlayerJoinEvent = true;
+ // Paper end
// this.sendAll(new PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, new EntityPlayer[]{entityplayer})); // CraftBukkit - replaced with loop below
// Paper start - correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks
@@ -388,6 +413,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 +438,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)
@@ -481,7 +507,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
--
2.25.1