From c6902445277d9828294c9062bdb3dc1c3152bc13 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sat, 4 Nov 2023 14:11:55 -0700 Subject: [PATCH] Fix a bunch of stuff with player spawn locations (#9887) If a playerdata doesn't contain a valid, loaded world, reset to the main world spawn point --- ...valid-world-is-found-on-legacy-Playe.patch | 22 ---- ...pawn-point-if-spawn-in-unloaded-worl.patch | 119 ++++++++++++++++-- ...awn-player-in-correct-world-on-login.patch | 30 ----- 3 files changed, 107 insertions(+), 64 deletions(-) delete mode 100644 patches/server/Fix-NPE-when-no-valid-world-is-found-on-legacy-Playe.patch delete mode 100644 patches/server/Spawn-player-in-correct-world-on-login.patch diff --git a/patches/server/Fix-NPE-when-no-valid-world-is-found-on-legacy-Playe.patch b/patches/server/Fix-NPE-when-no-valid-world-is-found-on-legacy-Playe.patch deleted file mode 100644 index 729f7edde5..0000000000 --- a/patches/server/Fix-NPE-when-no-valid-world-is-found-on-legacy-Playe.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jake Potrebic -Date: Sat, 28 Oct 2023 23:21:49 -0700 -Subject: [PATCH] Fix NPE when no valid world is found on legacy Players - - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -0,0 +0,0 @@ public abstract class PlayerList { - Logger logger = PlayerList.LOGGER; - - Objects.requireNonNull(logger); -- resourcekey = (ResourceKey) dataresult.resultOrPartial(logger::error).orElse(player.serverLevel().dimension()); // CraftBukkit - SPIGOT-7507: If no dimension, fall back to existing dimension loaded from "WorldUUID", which in turn defaults to World.OVERWORLD -+ resourcekey = (ResourceKey) dataresult.resultOrPartial(logger::error).orElse(player.serverLevel() != null ? player.serverLevel().dimension() : Level.OVERWORLD); // CraftBukkit - SPIGOT-7507: If no dimension, fall back to existing dimension loaded from "WorldUUID", which in turn defaults to World.OVERWORLD // Paper - account for null level - } else { -- resourcekey = player.serverLevel().dimension(); // CraftBukkit - SPIGOT-7507: If no dimension, fall back to existing dimension loaded from "WorldUUID", which in turn defaults to World.OVERWORLD -+ resourcekey = player.serverLevel() != null ? player.serverLevel().dimension() : Level.OVERWORLD; // CraftBukkit - SPIGOT-7507: If no dimension, fall back to existing dimension loaded from "WorldUUID", which in turn defaults to World.OVERWORLD // Paper - account for null level - } - - ResourceKey resourcekey1 = resourcekey; diff --git a/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch b/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch index 3a4b407a20..c4d743c75a 100644 --- a/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch +++ b/patches/server/Move-player-to-spawn-point-if-spawn-in-unloaded-worl.patch @@ -3,25 +3,120 @@ From: 2277 <38501234+2277@users.noreply.github.com> Date: Tue, 31 Mar 2020 10:33:55 +0100 Subject: [PATCH] Move player to spawn point if spawn in unloaded world -The code following this has better support for null worlds to move -them back to the world spawn. +If the playerdata contains an invalid world (missing, unloaded, invalid, +etc.), spawn the player at the spawn point of the main world. +Co-authored-by: Wyatt Childers +Co-authored-by: Jake Potrebic + +diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/players/PlayerList.java ++++ b/src/main/java/net/minecraft/server/players/PlayerList.java +@@ -0,0 +0,0 @@ public abstract class PlayerList { + } + + CompoundTag nbttagcompound = this.load(player); +- ResourceKey resourcekey; ++ ResourceKey resourcekey = null; // Paper + // CraftBukkit start - Better rename detection + if (nbttagcompound != null && nbttagcompound.contains("bukkit")) { + CompoundTag bukkit = nbttagcompound.getCompound("bukkit"); +@@ -0,0 +0,0 @@ public abstract class PlayerList { + } + // CraftBukkit end + ++ // Paper start - move logic in Entity to here, to use bukkit supplied world UUID & reset to main world spawn if no valid world is found ++ boolean invalidPlayerWorld = false; ++ bukkitData: if (nbttagcompound != null) { ++ // The main way for bukkit worlds to store the world is the world UUID despite mojang adding custom worlds ++ final org.bukkit.World bWorld; ++ if (nbttagcompound.contains("WorldUUIDMost") && nbttagcompound.contains("WorldUUIDLeast")) { ++ bWorld = org.bukkit.Bukkit.getServer().getWorld(new UUID(nbttagcompound.getLong("WorldUUIDMost"), nbttagcompound.getLong("WorldUUIDLeast"))); ++ } else if (nbttagcompound.contains("world", net.minecraft.nbt.Tag.TAG_STRING)) { // Paper - legacy bukkit world name ++ bWorld = org.bukkit.Bukkit.getServer().getWorld(nbttagcompound.getString("world")); ++ } else { ++ break bukkitData; // if neither of the bukkit data points exist, proceed to the vanilla migration section ++ } ++ if (bWorld != null) { ++ resourcekey = ((CraftWorld) bWorld).getHandle().dimension(); ++ } else { ++ resourcekey = Level.OVERWORLD; ++ invalidPlayerWorld = true; ++ } ++ } ++ if (resourcekey == null) { // only run the vanilla logic if we haven't found a world from the bukkit data ++ // Below is the vanilla way of getting the dimension, this is for migration from vanilla servers ++ // Paper end + if (nbttagcompound != null) { + DataResult> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, nbttagcompound.get("Dimension"))); // CraftBukkit - decompile error + Logger logger = PlayerList.LOGGER; + + Objects.requireNonNull(logger); +- resourcekey = (ResourceKey) dataresult.resultOrPartial(logger::error).orElse(player.serverLevel().dimension()); // CraftBukkit - SPIGOT-7507: If no dimension, fall back to existing dimension loaded from "WorldUUID", which in turn defaults to World.OVERWORLD ++ // Paper start - reset to main world spawn if no valid world is found ++ final Optional> result = dataresult.resultOrPartial(logger::error); ++ invalidPlayerWorld = result.isEmpty(); ++ resourcekey = result.orElse(Level.OVERWORLD); ++ // Paper end + } else { +- resourcekey = player.serverLevel().dimension(); // CraftBukkit - SPIGOT-7507: If no dimension, fall back to existing dimension loaded from "WorldUUID", which in turn defaults to World.OVERWORLD ++ resourcekey = Level.OVERWORLD; // Paper - revert to vanilla default main world, this isn't an "invalid world" since no player data existed + } ++ } // Paper + + ResourceKey resourcekey1 = resourcekey; + ServerLevel worldserver = this.server.getLevel(resourcekey1); +@@ -0,0 +0,0 @@ public abstract class PlayerList { + if (worldserver == null) { + PlayerList.LOGGER.warn("Unknown respawn dimension {}, defaulting to overworld", resourcekey1); + worldserver1 = this.server.overworld(); ++ invalidPlayerWorld = true; // Paper - reset to main world if no world with parsed value is found + } else { + worldserver1 = worldserver; + } +@@ -0,0 +0,0 @@ public abstract class PlayerList { + // Paper start + if (nbttagcompound == null) { + 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 ++ } ++ if (nbttagcompound == null || invalidPlayerWorld) { ++ // Paper end + player.fudgeSpawnLocation(worldserver1); // only move to spawn on first login, otherwise, stay where you are.... + } + // Paper end diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { - bworld = server.getWorld(worldName); - } + } + // CraftBukkit end +- // CraftBukkit start - Reset world +- if (this instanceof ServerPlayer) { +- Server server = Bukkit.getServer(); +- org.bukkit.World bworld = null; +- +- // TODO: Remove World related checks, replaced with WorldUID +- String worldName = nbt.getString("world"); +- +- if (nbt.contains("WorldUUIDMost") && nbt.contains("WorldUUIDLeast")) { +- UUID uid = new UUID(nbt.getLong("WorldUUIDMost"), nbt.getLong("WorldUUIDLeast")); +- bworld = server.getWorld(uid); +- } else { +- bworld = server.getWorld(worldName); +- } +- - if (bworld == null) { - bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getLevel(Level.OVERWORLD).getWorld(); - } -+ // Paper start - Move player to spawn point if spawn in unloaded world -+// if (bworld == null) { -+// bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getWorldServer(World.OVERWORLD).getWorld(); -+// } -+ // Paper end - Move player to spawn point if spawn in unloaded world - - ((ServerPlayer) this).setLevel(bworld == null ? null : ((CraftWorld) bworld).getHandle()); - } +- +- ((ServerPlayer) this).setLevel(bworld == null ? null : ((CraftWorld) bworld).getHandle()); +- } ++ // CraftBukkit start ++ // Paper - move world parsing/loading to PlayerList#placeNewPlayer + this.getBukkitEntity().readBukkitValues(nbt); + if (nbt.contains("Bukkit.invisible")) { + boolean bukkitInvisible = nbt.getBoolean("Bukkit.invisible"); diff --git a/patches/server/Spawn-player-in-correct-world-on-login.patch b/patches/server/Spawn-player-in-correct-world-on-login.patch deleted file mode 100644 index be4aaf209c..0000000000 --- a/patches/server/Spawn-player-in-correct-world-on-login.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Wyatt Childers -Date: Fri, 3 Jul 2020 14:57:05 -0400 -Subject: [PATCH] Spawn player in correct world on login - - -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -0,0 +0,0 @@ public abstract class PlayerList { - } - // CraftBukkit end - -- if (nbttagcompound != null) { -+ // Paper start - move logic in Entity to here, to use bukkit supplied world UUID. -+ if (nbttagcompound != null && nbttagcompound.contains("WorldUUIDMost") && nbttagcompound.contains("WorldUUIDLeast")) { -+ UUID uid = new UUID(nbttagcompound.getLong("WorldUUIDMost"), nbttagcompound.getLong("WorldUUIDLeast")); -+ org.bukkit.World bWorld = org.bukkit.Bukkit.getServer().getWorld(uid); -+ if (bWorld != null) { -+ resourcekey = ((CraftWorld) bWorld).getHandle().dimension(); -+ } else { -+ resourcekey = Level.OVERWORLD; -+ } -+ } else if (nbttagcompound != null) { -+ // Vanilla migration support -+ // Paper end - DataResult> dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, nbttagcompound.get("Dimension"))); // CraftBukkit - decompile error - Logger logger = PlayerList.LOGGER; -