mirror of
https://github.com/PaperMC/Paper.git
synced 2024-10-30 23:39:58 +01:00
ccbb51078a
Fixes #5189
259 lines
15 KiB
Diff
259 lines
15 KiB
Diff
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
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
index 73dc7394a7209a8cd1eec40115cb6e7828f1dbd6..30f8f4a8314c849a66143a545c1af3440965c6aa 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
|
@@ -178,6 +178,7 @@ public class ServerPlayer extends Player {
|
|
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;
|
|
@@ -244,6 +245,7 @@ public class ServerPlayer extends Player {
|
|
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/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java
|
|
index be677d437d17b74c6188ce1bd5fc6fdc228fd92f..78fbb4c3e52e900956ae0811aaf934c81ee5ea48 100644
|
|
--- a/src/main/java/net/minecraft/server/level/TicketType.java
|
|
+++ b/src/main/java/net/minecraft/server/level/TicketType.java
|
|
@@ -23,6 +23,7 @@ public class TicketType<T> {
|
|
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
|
|
index 67ede93bed3fafcb548c394397bcc2ca7a86c39f..36815e17d521e420fb04db108a12c2b9d1a9dce8 100644
|
|
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
@@ -220,6 +220,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
|
private static final int LATENCY_CHECK_INTERVAL = 15000;
|
|
public final Connection connection;
|
|
private final MinecraftServer server;
|
|
+ public Runnable playerJoinReady; // Paper
|
|
public ServerPlayer player;
|
|
private int tickCount;
|
|
private long keepAliveTime = Util.getMillis();
|
|
@@ -294,6 +295,15 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
|
// CraftBukkit end
|
|
|
|
public void tick() {
|
|
+ // Paper start - login async
|
|
+ Runnable playerJoinReady = this.playerJoinReady;
|
|
+ if (playerJoinReady != null) {
|
|
+ this.playerJoinReady = null;
|
|
+ playerJoinReady.run();
|
|
+ }
|
|
+ // Don't tick if not valid (dead), otherwise we load chunks below
|
|
+ if (this.player.valid) {
|
|
+ // Paper end
|
|
this.resetPosition();
|
|
this.player.xo = this.player.getX();
|
|
this.player.yo = this.player.getY();
|
|
@@ -335,7 +345,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
|
|
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
|
|
index b5d8987d2903086d69bbd6ba8092e568c94be63f..bd1203a5b58bac7cccf1f81337fa2967a0e9eb40 100644
|
|
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
|
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
|
@@ -88,7 +88,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
|
|
}
|
|
// 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;
|
|
@@ -194,7 +194,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
|
|
}
|
|
|
|
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 {
|
|
ServerPlayer entityplayer1 = this.server.getPlayerList().processLogin(this.gameProfile, s); // CraftBukkit - add player reference
|
|
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
|
index 9609579e6d61c3975740d07a394680aeef952516..6b23b9389ff92ae8016d4adb289ac2a097670be5 100644
|
|
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
|
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
|
@@ -40,6 +40,7 @@ import net.minecraft.network.protocol.Packet;
|
|
import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundChatPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
|
|
+import net.minecraft.network.protocol.game.ClientboundDisconnectPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
|
|
import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket;
|
|
@@ -135,6 +136,7 @@ public abstract class PlayerList {
|
|
private final IpBanList ipBans;
|
|
private final ServerOpList ops;
|
|
private final UserWhiteList whitelist;
|
|
+ private final Map<UUID, ServerPlayer> pendingPlayers = Maps.newHashMap(); // Paper
|
|
// CraftBukkit start
|
|
// private final Map<UUID, ServerStatisticManager> stats;
|
|
// private final Map<UUID, AdvancementDataPlayer> advancements;
|
|
@@ -173,6 +175,11 @@ public abstract class PlayerList {
|
|
}
|
|
|
|
public void placeNewPlayer(Connection connection, ServerPlayer player) {
|
|
+ ServerPlayer prev = pendingPlayers.put(player.getUUID(), player);// Paper
|
|
+ if (prev != null) {
|
|
+ disconnectPendingPlayer(prev);
|
|
+ }
|
|
+ player.networkManager = connection; // Paper
|
|
player.loginTime = System.currentTimeMillis(); // Paper
|
|
GameProfile gameprofile = player.getGameProfile();
|
|
GameProfileCache usercache = this.server.getProfileCache();
|
|
@@ -186,7 +193,7 @@ public abstract class PlayerList {
|
|
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) {
|
|
@@ -260,6 +267,52 @@ public abstract class PlayerList {
|
|
player.getRecipeBook().sendInitialRecipeBook(player);
|
|
this.updateEntireScoreboard(worldserver1.getScoreboard(), player);
|
|
this.server.invalidateStatus();
|
|
+ // Paper start - async load spawn in chunk
|
|
+ ServerLevel finalWorldserver = worldserver1;
|
|
+ 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;
|
|
+ distanceManager.addTicketAtLevel(net.minecraft.server.level.TicketType.LOGIN, pos, 31, pos.toLong());
|
|
+ worldserver1.getChunkSource().runDistanceManagerUpdates();
|
|
+ worldserver1.getChunkSource().getChunkAtAsynchronously(chunkX, chunkZ, true, true).thenApply(chunk -> {
|
|
+ net.minecraft.server.level.ChunkHolder updatingChunk = playerChunkMap.getUpdatingChunkIfPresent(pos.toLong());
|
|
+ if (updatingChunk != null) {
|
|
+ return updatingChunk.getEntityTickingChunkFuture();
|
|
+ } else {
|
|
+ return java.util.concurrent.CompletableFuture.completedFuture(chunk);
|
|
+ }
|
|
+ }).thenAccept(chunk -> {
|
|
+ playerconnection.playerJoinReady = () -> {
|
|
+ postChunkLoadJoin(
|
|
+ player, finalWorldserver, connection, playerconnection,
|
|
+ nbttagcompound, connection.getRemoteAddress().toString(), lastKnownName
|
|
+ );
|
|
+ };
|
|
+ });
|
|
+ }
|
|
+
|
|
+ public ServerPlayer getActivePlayer(UUID uuid) {
|
|
+ ServerPlayer player = this.playersByUUID.get(uuid);
|
|
+ return player != null ? player : pendingPlayers.get(uuid);
|
|
+ }
|
|
+
|
|
+ void disconnectPendingPlayer(ServerPlayer entityplayer) {
|
|
+ TranslatableComponent msg = new TranslatableComponent("multiplayer.disconnect.duplicate_login", new Object[0]);
|
|
+ entityplayer.networkManager.send(new ClientboundDisconnectPacket(msg), (future) -> {
|
|
+ entityplayer.networkManager.disconnect(msg);
|
|
+ entityplayer.networkManager = null;
|
|
+ });
|
|
+ }
|
|
+
|
|
+ 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
|
|
TranslatableComponent chatmessage;
|
|
|
|
if (player.getGameProfile().getName().equalsIgnoreCase(s)) {
|
|
@@ -503,6 +556,7 @@ public abstract class PlayerList {
|
|
|
|
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
|
|
|
|
@@ -530,7 +584,7 @@ public abstract class PlayerList {
|
|
}
|
|
|
|
PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, com.destroystokyo.paper.PaperConfig.useDisplayNameInQuit ? entityplayer.getBukkitEntity().displayName() : net.kyori.adventure.text.Component.text(entityplayer.getScoreboardName())));
|
|
- 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)
|
|
@@ -575,6 +629,13 @@ public abstract class PlayerList {
|
|
// this.advancements.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(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.REMOVE_PLAYER, new EntityPlayer[]{entityplayer}));
|
|
@@ -592,7 +653,7 @@ public abstract class PlayerList {
|
|
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
|
|
@@ -611,6 +672,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();
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
index 079e8f0f7ec5c3566b6778f5d518061a08699872..ebf7a58c6af5f5573d97c730c50c69a9f8140a6d 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
@@ -1513,7 +1513,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
|
|
this.yo = y;
|
|
this.zo = d4;
|
|
this.setPos(d3, y, d4);
|
|
- this.level.getChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4); // CraftBukkit
|
|
+ if (valid) this.level.getChunk((int) Math.floor(this.getX()) >> 4, (int) Math.floor(this.getZ()) >> 4); // CraftBukkit // Paper
|
|
}
|
|
|
|
public void moveTo(Vec3 pos) {
|