diff --git a/patches/unapplied/api/Expose-the-internal-current-tick.patch b/patches/api/Expose-the-internal-current-tick.patch similarity index 100% rename from patches/unapplied/api/Expose-the-internal-current-tick.patch rename to patches/api/Expose-the-internal-current-tick.patch diff --git a/patches/unapplied/api/Increase-custom-payload-channel-message-size.patch b/patches/api/Increase-custom-payload-channel-message-size.patch similarity index 100% rename from patches/unapplied/api/Increase-custom-payload-channel-message-size.patch rename to patches/api/Increase-custom-payload-channel-message-size.patch diff --git a/patches/unapplied/server/Allow-Saving-of-Oversized-Chunks.patch b/patches/server/Allow-Saving-of-Oversized-Chunks.patch similarity index 86% rename from patches/unapplied/server/Allow-Saving-of-Oversized-Chunks.patch rename to patches/server/Allow-Saving-of-Oversized-Chunks.patch index a0dbbc59cb..8c3a6f20e9 100644 --- a/patches/unapplied/server/Allow-Saving-of-Oversized-Chunks.patch +++ b/patches/server/Allow-Saving-of-Oversized-Chunks.patch @@ -53,15 +53,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @VisibleForTesting protected final RegionBitmap usedSectors; public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper -+ public final File regionFile; // Paper ++ public final Path regionFile; // Paper - public RegionFile(File file, File directory, boolean dsync) throws IOException { - this(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync); + public RegionFile(Path path, Path path1, boolean dsync) throws IOException { + this(path, path1, RegionFileVersion.VERSION_DEFLATE, dsync); @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { public RegionFile(Path file, Path directory, RegionFileVersion outputChunkStreamVersion, boolean dsync) throws IOException { this.header = ByteBuffer.allocateDirect(8192); -+ this.regionFile = file.toFile(); // Paper ++ this.regionFile = file; // Paper + initOversizedState(); // Paper this.usedSectors = new RegionBitmap(); this.version = outputChunkStreamVersion; @@ -75,9 +75,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + private int oversizedCount = 0; + + private synchronized void initOversizedState() throws IOException { -+ File metaFile = getOversizedMetaFile(); -+ if (metaFile.exists()) { -+ final byte[] read = java.nio.file.Files.readAllBytes(metaFile.toPath()); ++ Path metaFile = getOversizedMetaFile(); ++ if (Files.exists(metaFile)) { ++ final byte[] read = java.nio.file.Files.readAllBytes(metaFile); + System.arraycopy(read, 0, oversized, 0, oversized.length); + for (byte temp : oversized) { + oversizedCount += temp; @@ -101,9 +101,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + oversizedCount--; + } + if (previous && !oversized) { -+ File oversizedFile = getOversizedFile(x, z); -+ if (oversizedFile.exists()) { -+ oversizedFile.delete(); ++ Path oversizedFile = getOversizedFile(x, z); ++ if (Files.exists(oversizedFile)) { ++ Files.delete(oversizedFile); + } + } + if (oversizedCount > 0) { @@ -111,28 +111,28 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + writeOversizedMeta(); + } + } else if (previous) { -+ File oversizedMetaFile = getOversizedMetaFile(); -+ if (oversizedMetaFile.exists()) { -+ oversizedMetaFile.delete(); ++ Path oversizedMetaFile = getOversizedMetaFile(); ++ if (Files.exists(oversizedMetaFile)) { ++ Files.delete(oversizedMetaFile); + } + } + } + + private void writeOversizedMeta() throws IOException { -+ java.nio.file.Files.write(getOversizedMetaFile().toPath(), oversized); ++ java.nio.file.Files.write(getOversizedMetaFile(), oversized); + } + -+ private File getOversizedMetaFile() { -+ return new File(this.regionFile.getParentFile(), this.regionFile.getName().replaceAll("\\.mca$", "") + ".oversized.nbt"); ++ private Path getOversizedMetaFile() { ++ return this.regionFile.getParent().resolve(this.regionFile.getFileName().toString().replaceAll("\\.mca$", "") + ".oversized.nbt"); + } + -+ private File getOversizedFile(int x, int z) { -+ return new File(this.regionFile.getParentFile(), this.regionFile.getName().replaceAll("\\.mca$", "") + "_oversized_" + x + "_" + z + ".nbt"); ++ private Path getOversizedFile(int x, int z) { ++ return this.regionFile.getParent().resolve(this.regionFile.getFileName().toString().replaceAll("\\.mca$", "") + "_oversized_" + x + "_" + z + ".nbt"); + } + + synchronized CompoundTag getOversizedData(int x, int z) throws IOException { -+ File file = getOversizedFile(x, z); -+ try (DataInputStream out = new DataInputStream(new BufferedInputStream(new InflaterInputStream(new java.io.FileInputStream(file))))) { ++ Path file = getOversizedFile(x, z); ++ try (DataInputStream out = new DataInputStream(new java.io.BufferedInputStream(new InflaterInputStream(Files.newInputStream(file))))) { + return NbtIo.read((java.io.DataInput) out); + } + @@ -145,22 +145,23 @@ diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSto index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -0,0 +0,0 @@ import java.io.File; - import java.io.IOException; +@@ -0,0 +0,0 @@ import java.nio.file.Files; + import java.nio.file.Path; import javax.annotation.Nullable; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtIo; + import net.minecraft.nbt.StreamTagVisitor; +import net.minecraft.nbt.Tag; - import net.minecraft.server.MinecraftServer; import net.minecraft.util.ExceptionCollector; import net.minecraft.world.level.ChunkPos; + @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { } } + // Paper start -+ private static void printOversizedLog(String msg, File file, int x, int z) { ++ private static void printOversizedLog(String msg, Path file, int x, int z) { + org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); + } + diff --git a/patches/unapplied/server/Chunk-debug-command.patch b/patches/server/Chunk-debug-command.patch similarity index 100% rename from patches/unapplied/server/Chunk-debug-command.patch rename to patches/server/Chunk-debug-command.patch diff --git a/patches/unapplied/server/ChunkMapDistance-CME.patch b/patches/server/ChunkMapDistance-CME.patch similarity index 93% rename from patches/unapplied/server/ChunkMapDistance-CME.patch rename to patches/server/ChunkMapDistance-CME.patch index 8e14449633..8087fce876 100644 --- a/patches/unapplied/server/ChunkMapDistance-CME.patch +++ b/patches/server/ChunkMapDistance-CME.patch @@ -21,8 +21,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java @@ -0,0 +0,0 @@ public abstract class DistanceManager { - private final DistanceManager.ChunkTicketTracker ticketTracker = new DistanceManager.ChunkTicketTracker(); private final DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter = new DistanceManager.FixedPlayerDistanceChunkTracker(8); + private final TickingTracker tickingTicketsTracker = new TickingTracker(); private final DistanceManager.PlayerTicketTracker playerTicketManager = new DistanceManager.PlayerTicketTracker(33); - final Set<ChunkHolder> chunksToUpdateFutures = Sets.newHashSet(); + // Paper start use a queue, but still keep unique requirement @@ -52,7 +52,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - iter.remove(); - expectedSize--; - -- playerchunk.updateFutures(playerchunkmap, this.mainThreadExecutor); +- playerchunk.updateFutures(chunkStorage, this.mainThreadExecutor); - - // Reset iterator if set was modified using add() - if (this.chunksToUpdateFutures.size() != expectedSize) { @@ -67,7 +67,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + while(!this.pendingChunkUpdates.isEmpty()) { + ChunkHolder remove = this.pendingChunkUpdates.remove(); + remove.isUpdateQueued = false; -+ remove.updateFutures(playerchunkmap, this.mainThreadExecutor); ++ remove.updateFutures(chunkStorage, this.mainThreadExecutor); + } + // Paper end return true; diff --git a/patches/unapplied/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch similarity index 96% rename from patches/unapplied/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch rename to patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch index 3db0ed6ee0..e5f6873116 100644 --- a/patches/unapplied/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch +++ b/patches/server/Configurable-Keep-Spawn-Loaded-range-per-world.patch @@ -29,13 +29,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa // CraftBukkit start - public void loadSpawn(ChunkProgressListener worldloadlistener, ServerLevel worldserver) { + public void prepareLevels(ChunkProgressListener worldloadlistener, ServerLevel worldserver) { - if (!worldserver.getWorld().getKeepSpawnInMemory()) { - return; - } + ServerChunkCache chunkproviderserver = worldserver.getChunkSource(); // Paper - // WorldServer worldserver = this.E(); + // WorldServer worldserver = this.overworld(); this.forceTicks = true; // CraftBukkit end + if (worldserver.getWorld().getKeepSpawnInMemory()) { // Paper @@ -53,7 +53,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - - while (chunkproviderserver.getTickingGenerated() != 441) { - // CraftBukkit start -- // this.nextTickTime = SystemUtils.getMonotonicMillis() + 10L; +- // this.nextTickTime = SystemUtils.getMillis() + 10L; - this.executeModerately(); - // CraftBukkit end - } @@ -68,22 +68,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end // CraftBukkit start - // this.nextTickTime = SystemUtils.getMonotonicMillis() + 10L; + // this.nextTickTime = SystemUtils.getMillis() + 10L; this.executeModerately(); - // Iterator iterator = this.worldServer.values().iterator(); + // Iterator iterator = this.levels.values().iterator(); + } if (true) { ServerLevel worldserver1 = worldserver; @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa - // this.nextTick = SystemUtils.getMonotonicMillis() + 10L; + // this.nextTickTime = SystemUtils.getMillis() + 10L; this.executeModerately(); // CraftBukkit end - worldloadlistener.stop(); + if (worldserver.getWorld().getKeepSpawnInMemory()) worldloadlistener.stop(); // Paper chunkproviderserver.getLightEngine().setTaskPerBatch(5); // CraftBukkit start - // this.updateSpawnFlags(); + // this.updateMobSpawningFlags(); diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java diff --git a/patches/unapplied/server/Expose-the-internal-current-tick.patch b/patches/server/Expose-the-internal-current-tick.patch similarity index 100% rename from patches/unapplied/server/Expose-the-internal-current-tick.patch rename to patches/server/Expose-the-internal-current-tick.patch diff --git a/patches/unapplied/server/Fix-World-isChunkGenerated-calls.patch b/patches/server/Fix-World-isChunkGenerated-calls.patch similarity index 80% rename from patches/unapplied/server/Fix-World-isChunkGenerated-calls.patch rename to patches/server/Fix-World-isChunkGenerated-calls.patch index e0d6709554..18388b3cfb 100644 --- a/patches/unapplied/server/Fix-World-isChunkGenerated-calls.patch +++ b/patches/server/Fix-World-isChunkGenerated-calls.patch @@ -7,30 +7,6 @@ Optimize World#loadChunk() too This patch also adds a chunk status cache on region files (note that its only purpose is to cache the status on DISK) -diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkHolder.java -+++ b/src/main/java/net/minecraft/server/level/ChunkHolder.java -@@ -0,0 +0,0 @@ public class ChunkHolder { - Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = (Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>) statusFuture.getNow(null); - return (either == null) ? null : (LevelChunk) either.left().orElse(null); - } -+ -+ public ChunkAccess getAvailableChunkNow() { -+ // TODO can we just getStatusFuture(EMPTY)? -+ for (ChunkStatus curr = ChunkStatus.FULL, next = curr.getParent(); curr != next; curr = next, next = next.getParent()) { -+ CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = this.getFutureIfPresentUnchecked(curr); -+ Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = future.getNow(null); -+ if (either == null || !either.left().isPresent()) { -+ continue; -+ } -+ return either.left().get(); -+ } -+ return null; -+ } - // CraftBukkit end - - public CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getFutureIfPresentUnchecked(ChunkStatus leastStatus) { diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -41,8 +17,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import net.minecraft.world.level.chunk.storage.ChunkStorage; +import net.minecraft.world.level.chunk.storage.RegionFile; import net.minecraft.world.level.entity.ChunkStatusUpdateListener; + import net.minecraft.world.level.levelgen.blending.BlendingData; import net.minecraft.world.level.levelgen.structure.StructureStart; - import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager; @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Nullable public CompoundTag readChunk(ChunkPos pos) throws IOException { @@ -52,7 +28,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return null; + } + -+ nbttagcompound = this.getChunkData(this.level.getTypeKey(), this.overworldDataStorage, nbttagcompound, pos, level); // CraftBukkit ++ nbttagcompound = this.upgradeChunkTag(this.level.getTypeKey(), this.overworldDataStorage, nbttagcompound, this.generator.getTypeNameForDataFixer(), pos, level); // CraftBukkit + if (nbttagcompound == null) { + return null; + } @@ -67,12 +43,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public ChunkStatus getChunkStatusOnDiskIfCached(ChunkPos chunkPos) { + RegionFile regionFile = regionFileCache.getRegionFileIfLoaded(chunkPos); -- return nbttagcompound == null ? null : this.getChunkData(this.level.getTypeKey(), this.overworldDataStorage, nbttagcompound, pos, level); // CraftBukkit +- return nbttagcompound == null ? null : this.upgradeChunkTag(this.level.getTypeKey(), this.overworldDataStorage, nbttagcompound, this.generator.getTypeNameForDataFixer(), pos, level); // CraftBukkit + return regionFile == null ? null : regionFile.getStatusIfCached(chunkPos.x, chunkPos.z); } + public ChunkStatus getChunkStatusOnDisk(ChunkPos chunkPos) throws IOException { -+ RegionFile regionFile = regionFileCache.getFile(chunkPos, true); ++ RegionFile regionFile = regionFileCache.getRegionFile(chunkPos, true); + + if (regionFile == null || !regionFileCache.chunkExists(chunkPos)) { + return null; @@ -90,7 +66,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + public void updateChunkStatusOnDisk(ChunkPos chunkPos, @Nullable CompoundTag compound) throws IOException { -+ RegionFile regionFile = regionFileCache.getFile(chunkPos, false); ++ RegionFile regionFile = regionFileCache.getRegionFile(chunkPos, false); + + regionFile.setStatus(chunkPos.x, chunkPos.z, ChunkSerializer.getStatus(compound)); + } @@ -101,21 +77,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end + - boolean noPlayersCloseForSpawning(ChunkPos chunkPos) { + boolean anyPlayerCloseEnoughForSpawning(ChunkPos pos) { // Spigot start - return this.isOutsideOfRange(chunkPos, false); -diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java -+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - } - // Paper end - // Paper start - async chunk io -+ @Nullable - public ChunkAccess getChunkAtImmediately(int x, int z) { - ChunkHolder holder = this.chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); - if (holder == null) { + return this.anyPlayerCloseEnoughForSpawning(pos, false); diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java @@ -143,11 +107,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java @@ -0,0 +0,0 @@ public class ChunkSerializer { - return nbttagcompound; + })); } + // Paper start -+ public static ChunkStatus getStatus(CompoundTag compound) { ++ public static @Nullable ChunkStatus getStatus(@Nullable CompoundTag compound) { + if (compound == null) { + return null; + } @@ -158,8 +122,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end + public static ChunkStatus.ChunkType getChunkTypeFromTag(@Nullable CompoundTag nbt) { - if (nbt != null) { - ChunkStatus chunkstatus = ChunkStatus.byName(nbt.getCompound("Level").getString("Status")); + return nbt != null ? ChunkStatus.byName(nbt.getString("Status")).getChunkType() : ChunkStatus.ChunkType.PROTOCHUNK; + } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java @@ -174,7 +138,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper - public final File regionFile; // Paper + public final Path regionFile; // Paper + // Paper start - Cache chunk status + private final ChunkStatus[] statuses = new ChunkStatus[32 * 32]; @@ -200,8 +164,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end + - public RegionFile(File file, File directory, boolean dsync) throws IOException { - this(file.toPath(), directory.toPath(), RegionFileVersion.VERSION_DEFLATE, dsync); + public RegionFile(Path path, Path path1, boolean dsync) throws IOException { + this(path, path1, RegionFileVersion.VERSION_DEFLATE, dsync); } @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { return this.getOffset(pos) != 0; @@ -299,7 +263,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - return true; + net.minecraft.world.level.chunk.storage.RegionFile file; + try { -+ file = world.getChunkSource().chunkMap.regionFileCache.getFile(chunkPos, false); ++ file = world.getChunkSource().chunkMap.regionFileCache.getRegionFile(chunkPos, false); + } catch (IOException ex) { + throw new RuntimeException(ex); + }