diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/DimensionDataStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/DimensionDataStorage.java.patch new file mode 100644 index 0000000000..41f17dad54 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/DimensionDataStorage.java.patch @@ -0,0 +1,20 @@ +--- a/net/minecraft/world/level/storage/DimensionDataStorage.java ++++ b/net/minecraft/world/level/storage/DimensionDataStorage.java +@@ -139,7 +_,7 @@ + } else { + int i = Util.maxAllowedExecutorThreads(); + int size = map.size(); +- if (size > i) { ++ if (false && size > i) { // Paper - Separate dimension data IO pool; just throw them into the fixed pool queue + this.pendingWriteFuture = this.pendingWriteFuture.thenCompose(object -> { + List> list = new ArrayList<>(i); + int i1 = Mth.positiveCeilDiv(size, i); +@@ -160,7 +_,7 @@ + object -> CompletableFuture.allOf( + map.entrySet() + .stream() +- .map(entry -> CompletableFuture.runAsync(() -> tryWrite(entry.getKey(), entry.getValue()), Util.ioPool())) ++ .map(entry -> CompletableFuture.runAsync(() -> tryWrite(entry.getKey(), entry.getValue()), Util.DIMENSION_DATA_IO_POOL)) // Paper - Separate dimension data IO pool + .toArray(CompletableFuture[]::new) + ) + ); diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/LevelStorageSource.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/LevelStorageSource.java.patch new file mode 100644 index 0000000000..d6448bf4b9 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/LevelStorageSource.java.patch @@ -0,0 +1,86 @@ +--- a/net/minecraft/world/level/storage/LevelStorageSource.java ++++ b/net/minecraft/world/level/storage/LevelStorageSource.java +@@ -66,7 +_,6 @@ + import net.minecraft.world.level.Level; + import net.minecraft.world.level.LevelSettings; + import net.minecraft.world.level.WorldDataConfiguration; +-import net.minecraft.world.level.dimension.DimensionType; + import net.minecraft.world.level.dimension.LevelStem; + import net.minecraft.world.level.levelgen.WorldDimensions; + import net.minecraft.world.level.levelgen.WorldGenSettings; +@@ -145,6 +_,7 @@ + PrimaryLevelData primaryLevelData = PrimaryLevelData.parse( + dynamic, levelSettings, complete.specialWorldProperty(), worldGenSettings.options(), lifecycle + ); ++ primaryLevelData.pdc = dynamic.castTyped(NbtOps.INSTANCE).getElement("BukkitValues", null); // CraftBukkit - Add PDC to world + return new LevelDataAndDimensions(primaryLevelData, complete); + } + +@@ -340,25 +_,39 @@ + return this.backupDir; + } + +- public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(String saveName) throws IOException, ContentValidationException { ++ public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(String saveName, ResourceKey dimensionType) throws IOException, ContentValidationException { // CraftBukkit + Path levelPath = this.getLevelPath(saveName); +- List list = this.worldDirValidator.validateDirectory(levelPath, true); ++ List list = Boolean.getBoolean("paper.disableWorldSymlinkValidation") ? List.of() : this.worldDirValidator.validateDirectory(levelPath, true); // Paper - add skipping of symlinks scan + if (!list.isEmpty()) { + throw new ContentValidationException(levelPath, list); + } else { +- return new LevelStorageSource.LevelStorageAccess(saveName, levelPath); ++ return new LevelStorageSource.LevelStorageAccess(saveName, levelPath, dimensionType); // CraftBukkit + } + } + +- public LevelStorageSource.LevelStorageAccess createAccess(String saveName) throws IOException { ++ public LevelStorageSource.LevelStorageAccess createAccess(String saveName, ResourceKey dimensionType) throws IOException { // CraftBukkit + Path levelPath = this.getLevelPath(saveName); +- return new LevelStorageSource.LevelStorageAccess(saveName, levelPath); ++ return new LevelStorageSource.LevelStorageAccess(saveName, levelPath, dimensionType); // CraftBukkit + } + + public DirectoryValidator getWorldDirValidator() { + return this.worldDirValidator; + } + ++ // CraftBukkit start ++ public static Path getStorageFolder(Path path, ResourceKey dimensionType) { ++ if (dimensionType == LevelStem.OVERWORLD) { ++ return path; ++ } else if (dimensionType == LevelStem.NETHER) { ++ return path.resolve("DIM-1"); ++ } else if (dimensionType == LevelStem.END) { ++ return path.resolve("DIM1"); ++ } else { ++ return path.resolve("dimensions").resolve(dimensionType.location().getNamespace()).resolve(dimensionType.location().getPath()); ++ } ++ } ++ // CraftBukkit end ++ + public record LevelCandidates(List levels) implements Iterable { + public boolean isEmpty() { + return this.levels.isEmpty(); +@@ -409,8 +_,12 @@ + public final LevelStorageSource.LevelDirectory levelDirectory; + private final String levelId; + private final Map resources = Maps.newHashMap(); ++ // CraftBukkit start ++ public final ResourceKey dimensionType; + +- LevelStorageAccess(final String levelId, final Path levelDir) throws IOException { ++ LevelStorageAccess(final String levelId, final Path levelDir, final ResourceKey dimensionType) throws IOException { ++ this.dimensionType = dimensionType; ++ // CraftBukkit end + this.levelId = levelId; + this.levelDirectory = new LevelStorageSource.LevelDirectory(levelDir); + this.lock = DirectoryLock.create(levelDir); +@@ -453,7 +_,7 @@ + } + + public Path getDimensionPath(ResourceKey dimensionPath) { +- return DimensionType.getStorageFolder(dimensionPath, this.levelDirectory.path()); ++ return getStorageFolder(this.levelDirectory.path(), this.dimensionType); // CraftBukkit + } + + private void checkLock() { diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/PlayerDataStorage.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/PlayerDataStorage.java.patch new file mode 100644 index 0000000000..f531362c07 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/PlayerDataStorage.java.patch @@ -0,0 +1,122 @@ +--- a/net/minecraft/world/level/storage/PlayerDataStorage.java ++++ b/net/minecraft/world/level/storage/PlayerDataStorage.java +@@ -14,8 +_,10 @@ + import net.minecraft.nbt.NbtAccounter; + import net.minecraft.nbt.NbtIo; + import net.minecraft.nbt.NbtUtils; ++import net.minecraft.server.level.ServerPlayer; + import net.minecraft.util.datafix.DataFixTypes; + import net.minecraft.world.entity.player.Player; ++import org.bukkit.craftbukkit.entity.CraftPlayer; + import org.slf4j.Logger; + + public class PlayerDataStorage { +@@ -31,6 +_,7 @@ + } + + public void save(Player player) { ++ if (org.spigotmc.SpigotConfig.disablePlayerDataSaving) return; // Spigot + try { + CompoundTag compoundTag = player.saveWithoutId(new CompoundTag()); + Path path = this.playerDir.toPath(); +@@ -40,30 +_,46 @@ + Path path3 = path.resolve(player.getStringUUID() + ".dat_old"); + Util.safeReplaceFile(path2, path1, path3); + } catch (Exception var7) { +- LOGGER.warn("Failed to save player data for {}", player.getName().getString()); ++ LOGGER.warn("Failed to save player data for {}", player.getScoreboardName(), var7); // Paper - Print exception + } + } + +- private void backup(Player player, String suffix) { ++ private void backup(String name, String stringUuid, String suffix) { // CraftBukkit + Path path = this.playerDir.toPath(); +- Path path1 = path.resolve(player.getStringUUID() + suffix); +- Path path2 = path.resolve(player.getStringUUID() + "_corrupted_" + LocalDateTime.now().format(FORMATTER) + suffix); ++ Path path1 = path.resolve(stringUuid + suffix); // CraftBukkit ++ Path path2 = path.resolve(stringUuid + "_corrupted_" + LocalDateTime.now().format(FORMATTER) + suffix); // CraftBukkit + if (Files.isRegularFile(path1)) { + try { + Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); + } catch (Exception var7) { +- LOGGER.warn("Failed to copy the player.dat file for {}", player.getName().getString(), var7); ++ LOGGER.warn("Failed to copy the player.dat file for {}", name, var7); // CraftBukkit + } + } + } + +- private Optional load(Player player, String suffix) { +- File file = new File(this.playerDir, player.getStringUUID() + suffix); ++ private Optional load(String name, String stringUuid, String suffix) { // CraftBukkit ++ File file = new File(this.playerDir, stringUuid + suffix); // CraftBukkit ++ // Spigot Start ++ boolean usingWrongFile = false; ++ if (org.bukkit.Bukkit.getOnlineMode() && !file.exists()) { // Paper - Check online mode first ++ file = new File(file, java.util.UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(java.nio.charset.StandardCharsets.UTF_8)).toString() + suffix); ++ if (file.exists()) { ++ usingWrongFile = true; ++ org.bukkit.Bukkit.getServer().getLogger().warning("Using offline mode UUID file for player " + name + " as it is the only copy we can find."); ++ } ++ } ++ // Spigot End + if (file.exists() && file.isFile()) { + try { +- return Optional.of(NbtIo.readCompressed(file.toPath(), NbtAccounter.unlimitedHeap())); ++ // Spigot Start ++ Optional optional = Optional.of(NbtIo.readCompressed(file.toPath(), NbtAccounter.unlimitedHeap())); ++ if (usingWrongFile) { ++ file.renameTo(new File(file.getPath() + ".offline-read")); ++ } ++ return optional; ++ // Spigot End + } catch (Exception var5) { +- LOGGER.warn("Failed to load player data for {}", player.getName().getString()); ++ LOGGER.warn("Failed to load player data for {}", name); // CraftBukkit + } + } + +@@ -71,16 +_,40 @@ + } + + public Optional load(Player player) { +- Optional optional = this.load(player, ".dat"); ++ // CraftBukkit start ++ return this.load(player.getName().getString(), player.getStringUUID()).map((tag) -> { ++ if (player instanceof ServerPlayer) { ++ CraftPlayer player1 = (CraftPlayer) player.getBukkitEntity(); ++ // Only update first played if it is older than the one we have ++ long modified = new File(this.playerDir, player.getStringUUID() + ".dat").lastModified(); ++ if (modified < player1.getFirstPlayed()) { ++ player1.setFirstPlayed(modified); ++ } ++ } ++ ++ player.load(tag); // From below ++ return tag; ++ }); ++ } ++ ++ public Optional load(String name, String uuid) { ++ // CraftBukkit end ++ Optional optional = this.load(name, uuid, ".dat"); // CraftBukkit + if (optional.isEmpty()) { +- this.backup(player, ".dat"); ++ this.backup(name, uuid, ".dat"); // CraftBukkit + } + +- return optional.or(() -> this.load(player, ".dat_old")).map(compoundTag -> { ++ return optional.or(() -> this.load(name, uuid, ".dat_old")).map(compoundTag -> { // CraftBukkit + int dataVersion = NbtUtils.getDataVersion(compoundTag, -1); + compoundTag = DataFixTypes.PLAYER.updateToCurrentVersion(this.fixerUpper, compoundTag, dataVersion); +- player.load(compoundTag); ++ // player.load(compoundTag); // CraftBukkit - handled above + return compoundTag; + }); + } ++ ++ // CraftBukkit start ++ public File getPlayerDir() { ++ return this.playerDir; ++ } ++ // CraftBukkit end + } diff --git a/paper-server/patches/sources/net/minecraft/world/level/storage/PrimaryLevelData.java.patch b/paper-server/patches/sources/net/minecraft/world/level/storage/PrimaryLevelData.java.patch new file mode 100644 index 0000000000..8cd7249f86 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/level/storage/PrimaryLevelData.java.patch @@ -0,0 +1,123 @@ +--- a/net/minecraft/world/level/storage/PrimaryLevelData.java ++++ b/net/minecraft/world/level/storage/PrimaryLevelData.java +@@ -74,6 +_,21 @@ + private final Set removedFeatureFlags; + private final TimerQueue scheduledEvents; + ++ // CraftBukkit start - Add world and pdc ++ public net.minecraft.core.Registry customDimensions; ++ private net.minecraft.server.level.ServerLevel world; ++ protected net.minecraft.nbt.Tag pdc; ++ ++ public void setWorld(net.minecraft.server.level.ServerLevel world) { ++ if (this.world != null) { ++ return; ++ } ++ this.world = world; ++ world.getWorld().readBukkitValues(this.pdc); ++ this.pdc = null; ++ } ++ // CraftBukkit end ++ + private PrimaryLevelData( + @Nullable CompoundTag loadedPlayerTag, + boolean wasModded, +@@ -237,7 +_,7 @@ + nbt.put("Version", compoundTag); + NbtUtils.addCurrentDataVersion(nbt); + DynamicOps dynamicOps = registry.createSerializationContext(NbtOps.INSTANCE); +- WorldGenSettings.encode(dynamicOps, this.worldOptions, registry) ++ WorldGenSettings.encode(dynamicOps, this.worldOptions, new net.minecraft.world.level.levelgen.WorldDimensions(this.customDimensions != null ? this.customDimensions : registry.lookupOrThrow(net.minecraft.core.registries.Registries.LEVEL_STEM))) // CraftBukkit + .resultOrPartial(Util.prefix("WorldGenSettings: ", LOGGER::error)) + .ifPresent(worldOptionsTag -> nbt.put("WorldGenSettings", worldOptionsTag)); + nbt.putInt("GameType", this.settings.gameType().getId()); +@@ -281,6 +_,8 @@ + if (this.wanderingTraderId != null) { + nbt.putUUID("WanderingTraderId", this.wanderingTraderId); + } ++ nbt.putString("Bukkit.Version", org.bukkit.Bukkit.getName() + "/" + org.bukkit.Bukkit.getVersion() + "/" + org.bukkit.Bukkit.getBukkitVersion()); // CraftBukkit ++ this.world.getWorld().storeBukkitValues(nbt); // CraftBukkit - add pdc + } + + private static ListTag stringCollectionToTag(Set stringCollection) { +@@ -358,6 +_,25 @@ + + @Override + public void setThundering(boolean thundering) { ++ // Paper start - Add cause to Weather/ThunderChangeEvents ++ this.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.UNKNOWN); ++ } ++ public void setThundering(boolean thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause cause) { ++ // Paper end - Add cause to Weather/ThunderChangeEvents ++ // CraftBukkit start ++ if (this.thundering == thundering) { ++ return; ++ } ++ ++ org.bukkit.World world = org.bukkit.Bukkit.getWorld(this.getLevelName()); ++ if (world != null) { ++ org.bukkit.event.weather.ThunderChangeEvent thunder = new org.bukkit.event.weather.ThunderChangeEvent(world, thundering, cause); // Paper - Add cause to Weather/ThunderChangeEvents ++ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(thunder); ++ if (thunder.isCancelled()) { ++ return; ++ } ++ } ++ // CraftBukkit end + this.thundering = thundering; + } + +@@ -378,6 +_,26 @@ + + @Override + public void setRaining(boolean isRaining) { ++ // Paper start - Add cause to Weather/ThunderChangeEvents ++ this.setRaining(isRaining, org.bukkit.event.weather.WeatherChangeEvent.Cause.UNKNOWN); ++ } ++ ++ public void setRaining(boolean isRaining, org.bukkit.event.weather.WeatherChangeEvent.Cause cause) { ++ // Paper end - Add cause to Weather/ThunderChangeEvents ++ // CraftBukkit start ++ if (this.raining == isRaining) { ++ return; ++ } ++ ++ org.bukkit.World world = org.bukkit.Bukkit.getWorld(this.getLevelName()); ++ if (world != null) { ++ org.bukkit.event.weather.WeatherChangeEvent weather = new org.bukkit.event.weather.WeatherChangeEvent(world, isRaining, cause); // Paper - Add cause to Weather/ThunderChangeEvents ++ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(weather); ++ if (weather.isCancelled()) { ++ return; ++ } ++ } ++ // CraftBukkit end + this.raining = isRaining; + } + +@@ -444,6 +_,12 @@ + @Override + public void setDifficulty(Difficulty difficulty) { + this.settings = this.settings.withDifficulty(difficulty); ++ // CraftBukkit start ++ net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket packet = new net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket(this.getDifficulty(), this.isDifficultyLocked()); ++ for (net.minecraft.server.level.ServerPlayer player : (java.util.List) (java.util.List) this.world.players()) { ++ player.connection.send(packet); ++ } ++ // CraftBukkit end + } + + @Override +@@ -579,6 +_,14 @@ + public LevelSettings getLevelSettings() { + return this.settings.copy(); + } ++ ++ // CraftBukkit start - Check if the name stored in NBT is the correct one ++ public void checkName(String name) { ++ if (!this.settings.levelName.equals(name)) { ++ this.settings.levelName = name; ++ } ++ } ++ // CraftBukkit end + + @Deprecated + public static enum SpecialWorldProperty { diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/storage/DimensionDataStorage.java.patch b/paper-server/patches/unapplied/net/minecraft/world/level/storage/DimensionDataStorage.java.patch deleted file mode 100644 index 0a22aaf58b..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/level/storage/DimensionDataStorage.java.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/net/minecraft/world/level/storage/DimensionDataStorage.java -+++ b/net/minecraft/world/level/storage/DimensionDataStorage.java -@@ -139,7 +139,7 @@ - } else { - int i = Util.maxAllowedExecutorThreads(); - int j = map.size(); -- if (j > i) { -+ if (false && j > i) { // Paper - Separate dimension data IO pool; just throw them into the fixed pool queue - this.pendingWriteFuture = this.pendingWriteFuture.thenCompose(object -> { - List> list = new ArrayList<>(i); - int k = Mth.positiveCeilDiv(j, i); -@@ -160,7 +160,7 @@ - v -> CompletableFuture.allOf( - map.entrySet() - .stream() -- .map(entry -> CompletableFuture.runAsync(() -> tryWrite(entry.getKey(), entry.getValue()), Util.ioPool())) -+ .map(entry -> CompletableFuture.runAsync(() -> tryWrite(entry.getKey(), entry.getValue()), Util.DIMENSION_DATA_IO_POOL)) // Paper - Separate dimension data IO pool - .toArray(CompletableFuture[]::new) - ) - ); diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/storage/LevelStorageSource.java.patch b/paper-server/patches/unapplied/net/minecraft/world/level/storage/LevelStorageSource.java.patch deleted file mode 100644 index e0a1e52b18..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/level/storage/LevelStorageSource.java.patch +++ /dev/null @@ -1,107 +0,0 @@ ---- a/net/minecraft/world/level/storage/LevelStorageSource.java -+++ b/net/minecraft/world/level/storage/LevelStorageSource.java -@@ -68,7 +68,6 @@ - import net.minecraft.world.level.Level; - import net.minecraft.world.level.LevelSettings; - import net.minecraft.world.level.WorldDataConfiguration; --import net.minecraft.world.level.dimension.DimensionType; - import net.minecraft.world.level.dimension.LevelStem; - import net.minecraft.world.level.levelgen.WorldDimensions; - import net.minecraft.world.level.levelgen.WorldGenSettings; -@@ -149,7 +148,7 @@ - } - - public static WorldDataConfiguration readDataConfig(Dynamic dynamic) { -- DataResult dataresult = WorldDataConfiguration.CODEC.parse(dynamic); -+ DataResult dataresult = WorldDataConfiguration.CODEC.parse(dynamic); // CraftBukkit - decompile error - Logger logger = LevelStorageSource.LOGGER; - - Objects.requireNonNull(logger); -@@ -168,6 +167,7 @@ - WorldDimensions.Complete worlddimensions_b = generatorsettings.dimensions().bake(dimensionsRegistry); - Lifecycle lifecycle = worlddimensions_b.lifecycle().add(registries.allRegistriesLifecycle()); - PrimaryLevelData worlddataserver = PrimaryLevelData.parse(dynamic1, worldsettings, worlddimensions_b.specialWorldProperty(), generatorsettings.options(), lifecycle); -+ worlddataserver.pdc = ((Dynamic) dynamic1).getElement("BukkitValues", null); // CraftBukkit - Add PDC to world - - return new LevelDataAndDimensions(worlddataserver, worlddimensions_b); - } -@@ -409,26 +409,40 @@ - return this.backupDir; - } - -- public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(String directoryName) throws IOException, ContentValidationException { -- Path path = this.getLevelPath(directoryName); -- List list = this.worldDirValidator.validateDirectory(path, true); -+ public LevelStorageSource.LevelStorageAccess validateAndCreateAccess(String s, ResourceKey dimensionType) throws IOException, ContentValidationException { // CraftBukkit -+ Path path = this.getLevelPath(s); -+ List list = Boolean.getBoolean("paper.disableWorldSymlinkValidation") ? List.of() : this.worldDirValidator.validateDirectory(path, true); // Paper - add skipping of symlinks scan - - if (!list.isEmpty()) { - throw new ContentValidationException(path, list); - } else { -- return new LevelStorageSource.LevelStorageAccess(directoryName, path); -+ return new LevelStorageSource.LevelStorageAccess(s, path, dimensionType); // CraftBukkit - } - } - -- public LevelStorageSource.LevelStorageAccess createAccess(String directoryName) throws IOException { -- Path path = this.getLevelPath(directoryName); -+ public LevelStorageSource.LevelStorageAccess createAccess(String s, ResourceKey dimensionType) throws IOException { // CraftBukkit -+ Path path = this.getLevelPath(s); - -- return new LevelStorageSource.LevelStorageAccess(directoryName, path); -+ return new LevelStorageSource.LevelStorageAccess(s, path, dimensionType); // CraftBukkit - } - - public DirectoryValidator getWorldDirValidator() { - return this.worldDirValidator; -+ } -+ -+ // CraftBukkit start -+ public static Path getStorageFolder(Path path, ResourceKey dimensionType) { -+ if (dimensionType == LevelStem.OVERWORLD) { -+ return path; -+ } else if (dimensionType == LevelStem.NETHER) { -+ return path.resolve("DIM-1"); -+ } else if (dimensionType == LevelStem.END) { -+ return path.resolve("DIM1"); -+ } else { -+ return path.resolve("dimensions").resolve(dimensionType.location().getNamespace()).resolve(dimensionType.location().getPath()); -+ } - } -+ // CraftBukkit end - - public static record LevelCandidates(List levels) implements Iterable { - -@@ -488,8 +502,12 @@ - public final LevelStorageSource.LevelDirectory levelDirectory; - private final String levelId; - private final Map resources = Maps.newHashMap(); -+ // CraftBukkit start -+ public final ResourceKey dimensionType; - -- LevelStorageAccess(final String s, final Path path) throws IOException { -+ LevelStorageAccess(final String s, final Path path, final ResourceKey dimensionType) throws IOException { -+ this.dimensionType = dimensionType; -+ // CraftBukkit end - this.levelId = s; - this.levelDirectory = new LevelStorageSource.LevelDirectory(path); - this.lock = DirectoryLock.create(path); -@@ -529,7 +547,7 @@ - } - - public Path getLevelPath(LevelResource savePath) { -- Map map = this.resources; -+ Map map = this.resources; // CraftBukkit - decompile error - LevelStorageSource.LevelDirectory convertable_b = this.levelDirectory; - - Objects.requireNonNull(this.levelDirectory); -@@ -537,7 +555,7 @@ - } - - public Path getDimensionPath(ResourceKey key) { -- return DimensionType.getStorageFolder(key, this.levelDirectory.path()); -+ return LevelStorageSource.getStorageFolder(this.levelDirectory.path(), this.dimensionType); // CraftBukkit - } - - private void checkLock() { diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/storage/PlayerDataStorage.java.patch b/paper-server/patches/unapplied/net/minecraft/world/level/storage/PlayerDataStorage.java.patch deleted file mode 100644 index 6ed0222e60..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/level/storage/PlayerDataStorage.java.patch +++ /dev/null @@ -1,143 +0,0 @@ ---- a/net/minecraft/world/level/storage/PlayerDataStorage.java -+++ b/net/minecraft/world/level/storage/PlayerDataStorage.java -@@ -15,8 +15,10 @@ - import net.minecraft.nbt.NbtAccounter; - import net.minecraft.nbt.NbtIo; - import net.minecraft.nbt.NbtUtils; -+import net.minecraft.server.level.ServerPlayer; - import net.minecraft.util.datafix.DataFixTypes; - import net.minecraft.world.entity.player.Player; -+import org.bukkit.craftbukkit.entity.CraftPlayer; - import org.slf4j.Logger; - - public class PlayerDataStorage { -@@ -33,6 +35,7 @@ - } - - public void save(Player player) { -+ if (org.spigotmc.SpigotConfig.disablePlayerDataSaving) return; // Spigot - try { - CompoundTag nbttagcompound = player.saveWithoutId(new CompoundTag()); - Path path = this.playerDir.toPath(); -@@ -44,39 +47,60 @@ - - Util.safeReplaceFile(path2, path1, path3); - } catch (Exception exception) { -- PlayerDataStorage.LOGGER.warn("Failed to save player data for {}", player.getName().getString()); -+ PlayerDataStorage.LOGGER.warn("Failed to save player data for {}", player.getScoreboardName(), exception); // Paper - Print exception - } - - } - -- private void backup(Player player, String extension) { -+ private void backup(String name, String s1, String s) { // name, uuid, extension - Path path = this.playerDir.toPath(); -- String s1 = player.getStringUUID(); -- Path path1 = path.resolve(s1 + extension); -+ // String s1 = entityhuman.getStringUUID(); // CraftBukkit - used above -+ Path path1 = path.resolve(s1 + s); - -- s1 = player.getStringUUID(); -- Path path2 = path.resolve(s1 + "_corrupted_" + LocalDateTime.now().format(PlayerDataStorage.FORMATTER) + extension); -+ // s1 = entityhuman.getStringUUID(); // CraftBukkit - used above -+ Path path2 = path.resolve(s1 + "_corrupted_" + LocalDateTime.now().format(PlayerDataStorage.FORMATTER) + s); - - if (Files.isRegularFile(path1, new LinkOption[0])) { - try { - Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); - } catch (Exception exception) { -- PlayerDataStorage.LOGGER.warn("Failed to copy the player.dat file for {}", player.getName().getString(), exception); -+ PlayerDataStorage.LOGGER.warn("Failed to copy the player.dat file for {}", name, exception); // CraftBukkit - } - - } - } - -- private Optional load(Player player, String extension) { -+ // CraftBukkit start -+ private Optional load(String name, String s1, String s) { // name, uuid, extension -+ // CraftBukkit end - File file = this.playerDir; -- String s1 = player.getStringUUID(); -- File file1 = new File(file, s1 + extension); -+ // String s1 = entityhuman.getStringUUID(); // CraftBukkit - used above -+ File file1 = new File(file, s1 + s); -+ // Spigot Start -+ boolean usingWrongFile = false; -+ if ( org.bukkit.Bukkit.getOnlineMode() && !file1.exists() ) // Paper - Check online mode first -+ { -+ file1 = new File( file, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + name ).getBytes( java.nio.charset.StandardCharsets.UTF_8 ) ).toString() + s ); -+ if ( file1.exists() ) -+ { -+ usingWrongFile = true; -+ org.bukkit.Bukkit.getServer().getLogger().warning( "Using offline mode UUID file for player " + name + " as it is the only copy we can find." ); -+ } -+ } -+ // Spigot End - - if (file1.exists() && file1.isFile()) { - try { -- return Optional.of(NbtIo.readCompressed(file1.toPath(), NbtAccounter.unlimitedHeap())); -+ // Spigot Start -+ Optional optional = Optional.of(NbtIo.readCompressed(file1.toPath(), NbtAccounter.unlimitedHeap())); -+ if ( usingWrongFile ) -+ { -+ file1.renameTo( new File( file1.getPath() + ".offline-read" ) ); -+ } -+ return optional; -+ // Spigot End - } catch (Exception exception) { -- PlayerDataStorage.LOGGER.warn("Failed to load player data for {}", player.getName().getString()); -+ PlayerDataStorage.LOGGER.warn("Failed to load player data for {}", name); // CraftBukkit - } - } - -@@ -84,20 +108,44 @@ - } - - public Optional load(Player player) { -- Optional optional = this.load(player, ".dat"); -+ // CraftBukkit start -+ return this.load(player.getName().getString(), player.getStringUUID()).map((nbttagcompound) -> { -+ if (player instanceof ServerPlayer) { -+ CraftPlayer player1 = (CraftPlayer) player.getBukkitEntity(); -+ // Only update first played if it is older than the one we have -+ long modified = new File(this.playerDir, player.getStringUUID() + ".dat").lastModified(); -+ if (modified < player1.getFirstPlayed()) { -+ player1.setFirstPlayed(modified); -+ } -+ } - -+ player.load(nbttagcompound); // From below -+ return nbttagcompound; -+ }); -+ } -+ -+ public Optional load(String name, String uuid) { -+ // CraftBukkit end -+ Optional optional = this.load(name, uuid, ".dat"); // CraftBukkit -+ - if (optional.isEmpty()) { -- this.backup(player, ".dat"); -+ this.backup(name, uuid, ".dat"); // CraftBukkit - } - - return optional.or(() -> { -- return this.load(player, ".dat_old"); -+ return this.load(name, uuid, ".dat_old"); // CraftBukkit - }).map((nbttagcompound) -> { - int i = NbtUtils.getDataVersion(nbttagcompound, -1); - - nbttagcompound = DataFixTypes.PLAYER.updateToCurrentVersion(this.fixerUpper, nbttagcompound, i); -- player.load(nbttagcompound); -+ // entityhuman.load(nbttagcompound); // CraftBukkit - handled above - return nbttagcompound; - }); - } -+ -+ // CraftBukkit start -+ public File getPlayerDir() { -+ return this.playerDir; -+ } -+ // CraftBukkit end - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/level/storage/PrimaryLevelData.java.patch b/paper-server/patches/unapplied/net/minecraft/world/level/storage/PrimaryLevelData.java.patch deleted file mode 100644 index 131a7c275b..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/level/storage/PrimaryLevelData.java.patch +++ /dev/null @@ -1,203 +0,0 @@ ---- a/net/minecraft/world/level/storage/PrimaryLevelData.java -+++ b/net/minecraft/world/level/storage/PrimaryLevelData.java -@@ -20,15 +20,12 @@ - import net.minecraft.SharedConstants; - import net.minecraft.Util; - import net.minecraft.core.BlockPos; -+import net.minecraft.core.Registry; - import net.minecraft.core.RegistryAccess; - import net.minecraft.core.UUIDUtil; --import net.minecraft.nbt.CompoundTag; --import net.minecraft.nbt.ListTag; --import net.minecraft.nbt.NbtOps; --import net.minecraft.nbt.NbtUtils; --import net.minecraft.nbt.StringTag; --import net.minecraft.nbt.Tag; - import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; - import net.minecraft.world.Difficulty; - import net.minecraft.world.level.GameRules; - import net.minecraft.world.level.GameType; -@@ -36,12 +33,26 @@ - import net.minecraft.world.level.LevelSettings; - import net.minecraft.world.level.WorldDataConfiguration; - import net.minecraft.world.level.border.WorldBorder; -+import net.minecraft.world.level.dimension.LevelStem; - import net.minecraft.world.level.dimension.end.EndDragonFight; --import net.minecraft.world.level.levelgen.WorldGenSettings; - import net.minecraft.world.level.levelgen.WorldOptions; - import net.minecraft.world.level.timers.TimerCallbacks; - import net.minecraft.world.level.timers.TimerQueue; - import org.slf4j.Logger; -+import net.minecraft.core.registries.Registries; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.ListTag; -+import net.minecraft.nbt.NbtOps; -+import net.minecraft.nbt.NbtUtils; -+import net.minecraft.nbt.StringTag; -+import net.minecraft.nbt.Tag; -+import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket; -+import net.minecraft.world.level.levelgen.WorldDimensions; -+import net.minecraft.world.level.levelgen.WorldGenSettings; -+import org.bukkit.Bukkit; -+import org.bukkit.event.weather.ThunderChangeEvent; -+import org.bukkit.event.weather.WeatherChangeEvent; -+// CraftBukkit end - - public class PrimaryLevelData implements ServerLevelData, WorldData { - -@@ -79,7 +90,21 @@ - private boolean wasModded; - private final Set removedFeatureFlags; - private final TimerQueue scheduledEvents; -+ // CraftBukkit start - Add world and pdc -+ public Registry customDimensions; -+ private ServerLevel world; -+ protected Tag pdc; - -+ public void setWorld(ServerLevel world) { -+ if (this.world != null) { -+ return; -+ } -+ this.world = world; -+ world.getWorld().readBukkitValues(this.pdc); -+ this.pdc = null; -+ } -+ // CraftBukkit end -+ - private PrimaryLevelData(@Nullable CompoundTag playerData, boolean modded, BlockPos spawnPos, float spawnAngle, long time, long timeOfDay, int version, int clearWeatherTime, int rainTime, boolean raining, int thunderTime, boolean thundering, boolean initialized, boolean difficultyLocked, WorldBorder.Settings worldBorder, int wanderingTraderSpawnDelay, int wanderingTraderSpawnChance, @Nullable UUID wanderingTraderId, Set serverBrands, Set removedFeatures, TimerQueue scheduledEvents, @Nullable CompoundTag customBossEvents, EndDragonFight.Data dragonFight, LevelSettings levelInfo, WorldOptions generatorOptions, PrimaryLevelData.SpecialWorldProperty specialProperty, Lifecycle lifecycle) { - this.wasModded = modded; - this.spawnPos = spawnPos; -@@ -116,7 +141,7 @@ - - public static PrimaryLevelData parse(Dynamic dynamic, LevelSettings info, PrimaryLevelData.SpecialWorldProperty specialProperty, WorldOptions generatorOptions, Lifecycle lifecycle) { - long i = dynamic.get("Time").asLong(0L); -- OptionalDynamic optionaldynamic = dynamic.get("Player"); -+ OptionalDynamic optionaldynamic = dynamic.get("Player"); // CraftBukkit - decompile error - Codec codec = CompoundTag.CODEC; - - Objects.requireNonNull(codec); -@@ -136,7 +161,7 @@ - WorldBorder.Settings worldborder_c = WorldBorder.Settings.read(dynamic, WorldBorder.DEFAULT_SETTINGS); - int k1 = dynamic.get("WanderingTraderSpawnDelay").asInt(0); - int l1 = dynamic.get("WanderingTraderSpawnChance").asInt(0); -- UUID uuid = (UUID) dynamic.get("WanderingTraderId").read(UUIDUtil.CODEC).result().orElse((Object) null); -+ UUID uuid = (UUID) dynamic.get("WanderingTraderId").read(UUIDUtil.CODEC).result().orElse(null); // CraftBukkit - decompile error - Set set = (Set) dynamic.get("ServerBrands").asStream().flatMap((dynamic1) -> { - return dynamic1.asString().result().stream(); - }).collect(Collectors.toCollection(Sets::newLinkedHashSet)); -@@ -145,7 +170,7 @@ - }).collect(Collectors.toSet()); - TimerQueue customfunctioncallbacktimerqueue = new TimerQueue<>(TimerCallbacks.SERVER_CALLBACKS, dynamic.get("ScheduledEvents").asStream()); - CompoundTag nbttagcompound1 = (CompoundTag) dynamic.get("CustomBossEvents").orElseEmptyMap().getValue(); -- DataResult dataresult = dynamic.get("DragonFight").read(EndDragonFight.Data.CODEC); -+ DataResult dataresult = dynamic.get("DragonFight").read(EndDragonFight.Data.CODEC); // CraftBukkit - decompile error - Logger logger = PrimaryLevelData.LOGGER; - - Objects.requireNonNull(logger); -@@ -180,7 +205,7 @@ - levelNbt.put("Version", nbttagcompound2); - NbtUtils.addCurrentDataVersion(levelNbt); - DynamicOps dynamicops = registryManager.createSerializationContext(NbtOps.INSTANCE); -- DataResult dataresult = WorldGenSettings.encode(dynamicops, this.worldOptions, registryManager); -+ DataResult dataresult = WorldGenSettings.encode(dynamicops, this.worldOptions, new WorldDimensions(this.customDimensions != null ? this.customDimensions : registryManager.lookupOrThrow(Registries.LEVEL_STEM))); // CraftBukkit - Logger logger = PrimaryLevelData.LOGGER; - - Objects.requireNonNull(logger); -@@ -230,11 +255,13 @@ - levelNbt.putUUID("WanderingTraderId", this.wanderingTraderId); - } - -+ levelNbt.putString("Bukkit.Version", Bukkit.getName() + "/" + Bukkit.getVersion() + "/" + Bukkit.getBukkitVersion()); // CraftBukkit -+ this.world.getWorld().storeBukkitValues(levelNbt); // CraftBukkit - add pdc - } - - private static ListTag stringCollectionToTag(Set strings) { - ListTag nbttaglist = new ListTag(); -- Stream stream = strings.stream().map(StringTag::valueOf); -+ Stream stream = strings.stream().map(StringTag::valueOf); // CraftBukkit - decompile error - - Objects.requireNonNull(nbttaglist); - stream.forEach(nbttaglist::add); -@@ -310,6 +337,25 @@ - - @Override - public void setThundering(boolean thundering) { -+ // Paper start - Add cause to Weather/ThunderChangeEvents -+ this.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.UNKNOWN); -+ } -+ public void setThundering(boolean thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause cause) { -+ // Paper end - Add cause to Weather/ThunderChangeEvents -+ // CraftBukkit start -+ if (this.thundering == thundering) { -+ return; -+ } -+ -+ org.bukkit.World world = Bukkit.getWorld(this.getLevelName()); -+ if (world != null) { -+ ThunderChangeEvent thunder = new ThunderChangeEvent(world, thundering, cause); // Paper - Add cause to Weather/ThunderChangeEvents -+ Bukkit.getServer().getPluginManager().callEvent(thunder); -+ if (thunder.isCancelled()) { -+ return; -+ } -+ } -+ // CraftBukkit end - this.thundering = thundering; - } - -@@ -330,6 +376,26 @@ - - @Override - public void setRaining(boolean raining) { -+ // Paper start - Add cause to Weather/ThunderChangeEvents -+ this.setRaining(raining, org.bukkit.event.weather.WeatherChangeEvent.Cause.UNKNOWN); -+ } -+ -+ public void setRaining(boolean raining, org.bukkit.event.weather.WeatherChangeEvent.Cause cause) { -+ // Paper end - Add cause to Weather/ThunderChangeEvents -+ // CraftBukkit start -+ if (this.raining == raining) { -+ return; -+ } -+ -+ org.bukkit.World world = Bukkit.getWorld(this.getLevelName()); -+ if (world != null) { -+ WeatherChangeEvent weather = new WeatherChangeEvent(world, raining, cause); // Paper - Add cause to Weather/ThunderChangeEvents -+ Bukkit.getServer().getPluginManager().callEvent(weather); -+ if (weather.isCancelled()) { -+ return; -+ } -+ } -+ // CraftBukkit end - this.raining = raining; - } - -@@ -396,6 +462,12 @@ - @Override - public void setDifficulty(Difficulty difficulty) { - this.settings = this.settings.withDifficulty(difficulty); -+ // CraftBukkit start -+ ClientboundChangeDifficultyPacket packet = new ClientboundChangeDifficultyPacket(this.getDifficulty(), this.isDifficultyLocked()); -+ for (ServerPlayer player : (java.util.List) (java.util.List) this.world.players()) { -+ player.connection.send(packet); -+ } -+ // CraftBukkit end - } - - @Override -@@ -532,6 +604,14 @@ - return this.settings.copy(); - } - -+ // CraftBukkit start - Check if the name stored in NBT is the correct one -+ public void checkName(String name) { -+ if (!this.settings.levelName.equals(name)) { -+ this.settings.levelName = name; -+ } -+ } -+ // CraftBukkit end -+ - /** @deprecated */ - @Deprecated - public static enum SpecialWorldProperty {