diff --git a/patches/server/Add-API-for-quit-reason.patch b/patches/server/Add-API-for-quit-reason.patch index 661ca6d00f..45e505229f 100644 --- a/patches/server/Add-API-for-quit-reason.patch +++ b/patches/server/Add-API-for-quit-reason.patch @@ -34,8 +34,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper + public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - there are a lot of changes to do if we change all methods leading to the event - public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) { - super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); + // Paper start - replace player chunk loader + private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java diff --git a/patches/server/Add-Alternate-Current-redstone-implementation.patch b/patches/server/Add-Alternate-Current-redstone-implementation.patch index 2be3491e46..e25055c3ef 100644 --- a/patches/server/Add-Alternate-Current-redstone-implementation.patch +++ b/patches/server/Add-Alternate-Current-redstone-implementation.patch @@ -2038,10 +2038,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - - private ExplosionInteraction() {} + return ret; } -+ + // Paper end + // Paper start - optimize redstone (Alternate Current) + public alternate.current.wire.WireHandler getWireHandler() { + // This method is overridden in ServerLevel. @@ -2051,7 +2050,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // an instance of Level to ServerLevel. + return null; + } -+ // Paper end ++ // Paper end - optimize redstone (Alternate Current) } diff --git a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 diff --git a/patches/server/Add-Early-Warning-Feature-to-WatchDog.patch b/patches/server/Add-Early-Warning-Feature-to-WatchDog.patch index 9ee27bb80b..3ab1e65665 100644 --- a/patches/server/Add-Early-Warning-Feature-to-WatchDog.patch +++ b/patches/server/Add-Early-Warning-Feature-to-WatchDog.patch @@ -69,7 +69,7 @@ diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/ index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread +@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa private static WatchdogThread instance; private long timeoutTime; private boolean restart; @@ -80,7 +80,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private volatile long lastTick; private volatile boolean stopping; -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread +@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa super( "Paper Watchdog Thread" ); this.timeoutTime = timeoutTime; this.restart = restart; @@ -89,7 +89,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } private static long monotonicMillis() -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread +@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa while ( !this.stopping ) { // @@ -110,7 +110,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 log.log( Level.SEVERE, "------------------------------" ); log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug." ); // Paper log.log( Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author" ); -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread +@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa } } // Paper end @@ -122,6 +122,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - Different message for short timeout log.log( Level.SEVERE, "------------------------------" ); log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper + io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log ); log.log( Level.SEVERE, "------------------------------" ); // diff --git a/patches/server/Add-PlayerKickEvent-causes.patch b/patches/server/Add-PlayerKickEvent-causes.patch index e1244f5c83..31de64309e 100644 --- a/patches/server/Add-PlayerKickEvent-causes.patch +++ b/patches/server/Add-PlayerKickEvent-causes.patch @@ -244,7 +244,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM)); // Paper - kick event cause return; } - // CraftBukkit end + // Paper start @@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl // Paper start - validate pick item position if (!(packet.getSlot() >= 0 && packet.getSlot() < this.player.getInventory().items.size())) { diff --git a/patches/server/Add-debug-for-sync-chunk-loads.patch b/patches/server/Add-debug-for-sync-chunk-loads.patch index 1f8bfaab7a..2c78c67e54 100644 --- a/patches/server/Add-debug-for-sync-chunk-loads.patch +++ b/patches/server/Add-debug-for-sync-chunk-loads.patch @@ -198,9 +198,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/io/papermc/paper/command/PaperCommand.java +++ b/src/main/java/io/papermc/paper/command/PaperCommand.java @@ -0,0 +0,0 @@ public final class PaperCommand extends Command { - commands.put(Set.of("version"), new VersionCommand()); commands.put(Set.of("dumpplugins"), new DumpPluginsCommand()); commands.put(Set.of("fixlight"), new FixLightCommand()); + commands.put(Set.of("debug", "chunkinfo", "holderinfo"), new ChunkDebugCommand()); + commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand()); return commands.entrySet().stream() @@ -304,27 +304,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- 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 { - @Nullable - @Override - public ChunkAccess getChunk(int x, int z, ChunkStatus leastStatus, boolean create) { -+ final int x1 = x; final int z1 = z; // Paper - conflict on variable change - if (Thread.currentThread() != this.mainThread) { - return (ChunkAccess) CompletableFuture.supplyAsync(() -> { - return this.getChunk(x, z, leastStatus, create); -@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - - Objects.requireNonNull(completablefuture); - if (!completablefuture.isDone()) { // Paper + // Paper start - async chunk io/loading + io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.pushChunkWait(this.level, x1, z1); // Paper - rewrite chunk system + // Paper end + com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x1, z1); // Paper - sync load info this.level.timings.syncChunkLoad.startTiming(); // Paper chunkproviderserver_b.managedBlock(completablefuture::isDone); - this.level.timings.syncChunkLoad.stopTiming(); // Paper + io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.popChunkWait(); // Paper - async chunk debug // Paper - rewrite chunk system 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 +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { - this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit + this.entityLookup = new io.papermc.paper.chunk.system.entity.EntityLookup(this, new EntityCallbacks()); // Paper - rewrite chunk system } + // Paper start diff --git a/patches/server/Add-missing-important-BlockStateListPopulator-method.patch b/patches/server/Add-missing-important-BlockStateListPopulator-method.patch index b8c250b136..d88ae4415a 100644 --- a/patches/server/Add-missing-important-BlockStateListPopulator-method.patch +++ b/patches/server/Add-missing-important-BlockStateListPopulator-method.patch @@ -57,21 +57,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java +++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java @@ -0,0 +0,0 @@ public class DummyGeneratorAccess implements WorldGenLevel { - public boolean destroyBlock(BlockPos pos, boolean drop, Entity breakingEntity, int maxUpdateDepth) { - return false; // SPIGOT-6515 - } -+ -+ // Paper start -+ @Override -+ public void scheduleTick(BlockPos pos, Fluid fluid, int delay) { -+ } + @Override + public void getEntitiesByClass(Class clazz, Entity except, AABB box, List into, Predicate predicate) {} + // Paper end ++ // Paper start - add more methods ++ public void scheduleTick(BlockPos pos, Fluid fluid, int delay) {} + + @Override -+ public void scheduleTick(BlockPos pos, Block block, int delay, net.minecraft.world.ticks.TickPriority priority) { -+ } ++ public void scheduleTick(BlockPos pos, Block block, int delay, net.minecraft.world.ticks.TickPriority priority) {} + + @Override -+ public void scheduleTick(BlockPos pos, Fluid fluid, int delay, net.minecraft.world.ticks.TickPriority priority) { -+ } -+ // Paper end ++ public void scheduleTick(BlockPos pos, Fluid fluid, int delay, net.minecraft.world.ticks.TickPriority priority) {} ++ // Paper end - add more methods } diff --git a/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch b/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch index f267756a38..d3446f38ad 100644 --- a/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch +++ b/patches/server/Add-paper-mobcaps-and-paper-playermobcaps.patch @@ -14,7 +14,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/io/papermc/paper/command/PaperCommand.java +++ b/src/main/java/io/papermc/paper/command/PaperCommand.java @@ -0,0 +0,0 @@ public final class PaperCommand extends Command { - commands.put(Set.of("fixlight"), new FixLightCommand()); + commands.put(Set.of("debug", "chunkinfo", "holderinfo"), new ChunkDebugCommand()); commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand()); commands.put(Set.of("dumpitem"), new DumpItemCommand()); + commands.put(Set.of("mobcaps", "playermobcaps"), new MobcapsCommand()); diff --git a/patches/server/Add-velocity-warnings.patch b/patches/server/Add-velocity-warnings.patch index f7fa993bbd..814b5c62d6 100644 --- a/patches/server/Add-velocity-warnings.patch +++ b/patches/server/Add-velocity-warnings.patch @@ -65,7 +65,7 @@ diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/ index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread +@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa log.log( Level.SEVERE, "During the run of the server, a physics stackoverflow was supressed" ); log.log( Level.SEVERE, "near " + net.minecraft.world.level.Level.lastPhysicsProblem ); } @@ -85,4 +85,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end log.log( Level.SEVERE, "------------------------------" ); log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper - WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log ); + io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system diff --git a/patches/server/Allow-Saving-of-Oversized-Chunks.patch b/patches/server/Allow-Saving-of-Oversized-Chunks.patch index 55354892a5..ecf972be96 100644 --- a/patches/server/Allow-Saving-of-Oversized-Chunks.patch +++ b/patches/server/Allow-Saving-of-Oversized-Chunks.patch @@ -41,18 +41,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; +import java.util.zip.InflaterInputStream; // Paper -+ import javax.annotation.Nullable; import net.minecraft.Util; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.NbtIo; ++import net.minecraft.nbt.CompoundTag; // Paper ++import net.minecraft.nbt.NbtIo; // Paper import net.minecraft.world.level.ChunkPos; import org.slf4j.Logger; @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { - private final IntBuffer timestamps; @VisibleForTesting protected final RegionBitmap usedSectors; + public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper + public final Path regionFile; // Paper public RegionFile(Path file, Path directory, boolean dsync) throws IOException { @@ -218,7 +217,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public CompoundTag read(ChunkPos pos) throws IOException { // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing @@ -0,0 +0,0 @@ public class RegionFileStorage implements AutoCloseable { - // CraftBukkit end + try { // Paper DataInputStream datainputstream = regionfile.getChunkDataInputStream(pos); + // Paper start diff --git a/patches/server/Async-GameProfileCache-saving.patch b/patches/server/Async-GameProfileCache-saving.patch index 97a7b667a3..6c9a19c7ca 100644 --- a/patches/server/Async-GameProfileCache-saving.patch +++ b/patches/server/Async-GameProfileCache-saving.patch @@ -16,7 +16,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.getProfileCache().save(false); // Paper } // Spigot end - + io.papermc.paper.chunk.system.io.RegionFileIOThread.close(true); // Paper // Paper - rewrite chunk system diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java diff --git a/patches/server/AsyncTabCompleteEvent.patch b/patches/server/AsyncTabCompleteEvent.patch index 5920aca062..349bbdae77 100644 --- a/patches/server/AsyncTabCompleteEvent.patch +++ b/patches/server/AsyncTabCompleteEvent.patch @@ -37,6 +37,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + server.scheduleOnMain(() -> this.disconnect(Component.translatable("disconnect.spam", new Object[0]))); // Paper return; } + // Paper start +@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + } + // Paper end // CraftBukkit end + // Paper start - async tab completion + TAB_COMPLETE_EXECUTOR.execute(() -> { diff --git a/patches/server/Basic-PlayerProfile-API.patch b/patches/server/Basic-PlayerProfile-API.patch index 184c9f61f0..cbae66a61c 100644 --- a/patches/server/Basic-PlayerProfile-API.patch +++ b/patches/server/Basic-PlayerProfile-API.patch @@ -559,8 +559,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.papermc.paper.math.BlockPosition; import io.papermc.paper.math.FinePosition; -@@ -0,0 +0,0 @@ import net.minecraft.world.level.ClipContext; - import net.minecraft.world.level.Level; +@@ -0,0 +0,0 @@ import net.minecraft.world.level.chunk.ChunkAccess; + import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.phys.Vec3; import org.apache.commons.lang.exception.ExceptionUtils; +import com.mojang.authlib.GameProfile; diff --git a/patches/server/Buffer-joins-to-world.patch b/patches/server/Buffer-joins-to-world.patch index 186dce05a4..30c714d791 100644 --- a/patches/server/Buffer-joins-to-world.patch +++ b/patches/server/Buffer-joins-to-world.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java @@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler> { - } + } // Paper end - add pending task queue } + private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper diff --git a/patches/server/Chunk-Save-Reattempt.patch b/patches/server/Chunk-Save-Reattempt.patch index ec5a4e51e9..6d260baab6 100644 --- a/patches/server/Chunk-Save-Reattempt.patch +++ b/patches/server/Chunk-Save-Reattempt.patch @@ -23,9 +23,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- 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 @@ public class RegionFileStorage implements AutoCloseable { - - protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { - RegionFile regionfile = this.getRegionFile(pos, false); // CraftBukkit + } + // Paper end - rewrite chunk system + try { // Paper + int attempts = 0; Exception laste = null; while (attempts++ < 5) { try { // Paper if (nbt == null) { @@ -46,6 +46,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + net.minecraft.server.MinecraftServer.LOGGER.error("Failed to save chunk " + pos, laste); + } + // Paper end - } - - public void close() throws IOException { + } finally { // Paper start + regionfile.fileLock.unlock(); + } // Paper end diff --git a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch index 57275490cc..bfddc2eb73 100644 --- a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch +++ b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch @@ -644,7 +644,7 @@ diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/ index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread +@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa log.log( Level.SEVERE, "During the run of the server, a plugin set an excessive velocity on an entity" ); log.log( Level.SEVERE, "This may be the cause of the issue, or it may be entirely unrelated" ); log.log( Level.SEVERE, org.bukkit.craftbukkit.CraftServer.excessiveVelEx.getMessage()); @@ -653,7 +653,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 { log.log( Level.SEVERE, "\t\t" + stack ); } -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread +@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa } log.log( Level.SEVERE, "\tStack:" ); // diff --git a/patches/server/Do-not-read-tile-entities-in-chunks-that-are-positio.patch b/patches/server/Do-not-read-tile-entities-in-chunks-that-are-positio.patch new file mode 100644 index 0000000000..a30d948b1f --- /dev/null +++ b/patches/server/Do-not-read-tile-entities-in-chunks-that-are-positio.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 18 Jun 2023 23:04:46 -0700 +Subject: [PATCH] Do not read tile entities in chunks that are positioned + outside of the chunk + +The tile entities are not accessible and so should not be loaded. +This can happen as a result of users moving regionfiles around, +which would cause a crash on Folia but would appear to function +fine on Paper. + +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- 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 { + for (int k1 = 0; k1 < nbttaglist3.size(); ++k1) { + CompoundTag nbttagcompound4 = nbttaglist3.getCompound(k1); + ++ // Paper start - do not read tile entities positioned outside the chunk ++ BlockPos blockposition = BlockEntity.getPosFromTag(nbttagcompound4); ++ if ((blockposition.getX() >> 4) != chunkPos.x || (blockposition.getZ() >> 4) != chunkPos.z) { ++ LOGGER.warn("Tile entity serialized in chunk " + chunkPos + " in world '" + world.getWorld().getName() + "' positioned at " + blockposition + " is located outside of the chunk"); ++ continue; ++ } ++ // Paper end - do not read tile entities positioned outside the chunk + ((ChunkAccess) object1).setBlockEntityNbt(nbttagcompound4); + } + +@@ -0,0 +0,0 @@ public class ChunkSerializer { + CompoundTag nbttagcompound1 = nbttaglist1.getCompound(i); + boolean flag = nbttagcompound1.getBoolean("keepPacked"); + ++ // Paper start - do not read tile entities positioned outside the chunk ++ BlockPos blockposition = BlockEntity.getPosFromTag(nbttagcompound1); // moved up ++ ChunkPos chunkPos = chunk.getPos(); ++ if ((blockposition.getX() >> 4) != chunkPos.x || (blockposition.getZ() >> 4) != chunkPos.z) { ++ LOGGER.warn("Tile entity serialized in chunk " + chunkPos + " in world '" + world.getWorld().getName() + "' positioned at " + blockposition + " is located outside of the chunk"); ++ continue; ++ } ++ // Paper end - do not read tile entities positioned outside the chunk ++ + if (flag) { + chunk.setBlockEntityNbt(nbttagcompound1); + } else { +- BlockPos blockposition = BlockEntity.getPosFromTag(nbttagcompound1); ++ // Paper - do not read tile entities positioned outside the chunk - move up + BlockEntity tileentity = BlockEntity.loadStatic(blockposition, chunk.getBlockState(blockposition), nbttagcompound1); + + if (tileentity != null) { diff --git a/patches/server/Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch b/patches/server/Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch index c143fab0de..ff04083261 100644 --- a/patches/server/Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch +++ b/patches/server/Don-t-crash-if-player-is-attempted-to-be-removed-fro.patch @@ -20,4 +20,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (objectset == null || objectset.isEmpty()) { // Paper this.playersPerChunk.remove(i); this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); - this.playerTicketManager.update(i, Integer.MAX_VALUE, false); + //this.playerTicketManager.update(i, Integer.MAX_VALUE, false); // Paper - no longer used diff --git a/patches/server/Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch b/patches/server/Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch index 21a3c1061d..f01e20cd03 100644 --- a/patches/server/Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch +++ b/patches/server/Don-t-read-neighbour-chunk-data-off-disk-when-conver.patch @@ -18,4 +18,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (true) return true; // Paper - this isn't even needed anymore, light is purged updating to 1.14+, why are we holding up the conversion process reading chunk data off disk - return true, we need to set light populated to true so the converter recognizes the chunk as being "full" ChunkPos pos = new ChunkPos(x, z); if (cps != null) { - com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread"); + //com.google.common.base.Preconditions.checkState(org.bukkit.Bukkit.isPrimaryThread(), "primary thread"); // Paper - this function is now MT-Safe diff --git a/patches/server/Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch b/patches/server/Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch index 950603bec1..b865a5b70f 100644 --- a/patches/server/Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch +++ b/patches/server/Don-t-respond-to-ServerboundCommandSuggestionPacket-.patch @@ -10,8 +10,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - return; } + // Paper end // CraftBukkit end + // Paper start - Don't suggest if tab-complete is disabled + if (org.spigotmc.SpigotConfig.tabComplete < 0) { diff --git a/patches/server/Don-t-tick-markers.patch b/patches/server/Don-t-tick-markers.patch index 8f503111a6..192694b840 100644 --- a/patches/server/Don-t-tick-markers.patch +++ b/patches/server/Don-t-tick-markers.patch @@ -39,11 +39,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java @@ -0,0 +0,0 @@ public class ActivationRange - ActivationType.VILLAGER.boundingBox = player.getBoundingBox().inflate( villagerActivationRange, worldHeight, villagerActivationRange ); - // Paper end -- world.getEntities().get(maxBB, ActivationRange::activateEntity); -+ world.getEntities().get(world.paperConfig().entities.markers.tick ? null : (e) -> !(e instanceof net.minecraft.world.entity.Marker), maxBB, ActivationRange::activateEntity); // Paper - configurable marker ticking - } - MinecraftTimings.entityActivationCheckTimer.stopTiming(); - } + // Paper start + java.util.List entities = world.getEntities((Entity)null, maxBB, null); ++ boolean tickMarkers = world.paperConfig().entities.markers.tick; // Paper - configurable marker ticking + for (int i = 0; i < entities.size(); i++) { + Entity entity = entities.get(i); ++ // Paper start - configurable marker ticking ++ if (!tickMarkers && entity instanceof net.minecraft.world.entity.Marker) { ++ continue; ++ } ++ // Paper end - configurable marker ticking + ActivationRange.activateEntity(entity); + } + // Paper end diff --git a/patches/server/Duplicate-UUID-Resolve-Option.patch b/patches/server/Duplicate-UUID-Resolve-Option.patch index 4706d45d62..b941148f60 100644 --- a/patches/server/Duplicate-UUID-Resolve-Option.patch +++ b/patches/server/Duplicate-UUID-Resolve-Option.patch @@ -65,10 +65,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + checkDupeUUID(world, entity); // Paper return !needsRemoval; - })); + }), position); // Paper - rewrite chunk system // CraftBukkit end @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - }); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } + // Paper start @@ -115,5 +115,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + // Paper end public CompletableFuture> prepareTickingChunk(ChunkHolder holder) { - CompletableFuture, ChunkHolder.ChunkLoadingFailure>> completablefuture = this.getChunkRangeFuture(holder, 1, (i) -> { - return ChunkStatus.FULL; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system + } diff --git a/patches/server/Ensure-Entity-AABB-s-are-never-invalid.patch b/patches/server/Ensure-Entity-AABB-s-are-never-invalid.patch index d76f58368c..9242d2a605 100644 --- a/patches/server/Ensure-Entity-AABB-s-are-never-invalid.patch +++ b/patches/server/Ensure-Entity-AABB-s-are-never-invalid.patch @@ -28,9 +28,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) { + // Paper end - if (this.position.x != x || this.position.y != y || this.position.z != z) { - this.position = new Vec3(x, y, z); - int i = Mth.floor(x); + // Paper start - rewrite chunk system + if (this.updatingSectionStatus) { + LOGGER.error("Refusing to update position for entity " + this + " to position " + new Vec3(x, y, z) + " since it is processing a section status update", new Throwable()); @@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { this.levelCallback.onMove(); } diff --git a/patches/server/Entity-Activation-Range-2.0.patch b/patches/server/Entity-Activation-Range-2.0.patch index 4143dee12a..d24b803a52 100644 --- a/patches/server/Entity-Activation-Range-2.0.patch +++ b/patches/server/Entity-Activation-Range-2.0.patch @@ -564,8 +564,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + ActivationType.VILLAGER.boundingBox = player.getBoundingBox().inflate( villagerActivationRange, worldHeight, villagerActivationRange ); + // Paper end - world.getEntities().get(maxBB, ActivationRange::activateEntity); - } + // Paper start + java.util.List entities = world.getEntities((Entity)null, maxBB, null); @@ -0,0 +0,0 @@ public class ActivationRange * @param entity * @return @@ -628,8 +628,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 { - return true; + return 20; // Paper - } -- if ( entity instanceof Villager && ( (Villager) entity ).canBreed() ) ++ } + // Paper start + if (entity instanceof Bee) { + Bee bee = (Bee)entity; @@ -657,7 +656,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return config.villagersWorkImmunityFor; + } + } -+ } + } +- if ( entity instanceof Villager && ( (Villager) entity ).canBreed() ) + if ( entity instanceof Llama && ( (Llama) entity ).inCaravan() ) { - return true; @@ -685,11 +685,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper start + if (entity instanceof Mob && ((Mob) entity).targetSelector.hasTasks() ) { + return 0; -+ } + } + if (entity instanceof Pillager) { + Pillager pillager = (Pillager) entity; + // TODO:? - } ++ } + // Paper end } // SPIGOT-6644: Otherwise the target refresh tick will be missed diff --git a/patches/server/Expose-client-protocol-version-and-virtual-host.patch b/patches/server/Expose-client-protocol-version-and-virtual-host.patch index 63fdacbbfb..6025949f3a 100644 --- a/patches/server/Expose-client-protocol-version-and-virtual-host.patch +++ b/patches/server/Expose-client-protocol-version-and-virtual-host.patch @@ -64,9 +64,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/network/Connection.java +++ b/src/main/java/net/minecraft/network/Connection.java @@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler> { - @Nullable - BandwidthDebugMonitor bandwidthDebugMonitor; - public String hostname = ""; // CraftBukkit - add field + } + } + // Paper end - add pending task queue + // Paper start - NetworkClient implementation + public int protocolVersion; + public java.net.InetSocketAddress virtualHost; diff --git a/patches/server/Fix-World-isChunkGenerated-calls.patch b/patches/server/Fix-World-isChunkGenerated-calls.patch index b72a9bad68..87217f196a 100644 --- a/patches/server/Fix-World-isChunkGenerated-calls.patch +++ b/patches/server/Fix-World-isChunkGenerated-calls.patch @@ -12,7 +12,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } + // Paper end private CompletableFuture> readChunk(ChunkPos chunkPos) { - return this.read(chunkPos).thenApplyAsync((optional) -> { @@ -97,7 +97,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java @@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { - protected final RegionBitmap usedSectors; + public final java.util.concurrent.locks.ReentrantLock fileLock = new java.util.concurrent.locks.ReentrantLock(true); // Paper public final Path regionFile; // Paper + // Paper start - Cache chunk status @@ -135,8 +135,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private static int getOffsetIndex(ChunkPos pos) { return pos.getRegionLocalX() + pos.getRegionLocalZ() * 32; } - - public void close() throws IOException { +@@ -0,0 +0,0 @@ public class RegionFile implements AutoCloseable { + synchronized (this) { + try { + // Paper end + this.closed = true; // Paper try { this.padToFullSector(); diff --git a/patches/server/Fix-and-optimise-world-force-upgrading.patch b/patches/server/Fix-and-optimise-world-force-upgrading.patch index 92b72f5794..d5fb1171c2 100644 --- a/patches/server/Fix-and-optimise-world-force-upgrading.patch +++ b/patches/server/Fix-and-optimise-world-force-upgrading.patch @@ -330,10 +330,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- 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 @@ public class RegionFileStorage implements AutoCloseable { - this.sync = dsync; } -+ // Paper start + // Paper start + @Nullable + public static ChunkPos getRegionFileCoordinates(Path file) { + String fileName = file.getFileName().toString(); @@ -356,11 +355,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return null; + } + } -+ // Paper end -+ - private RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit - long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); - RegionFile regionfile = (RegionFile) this.regionCache.getAndMoveToFirst(i); ++ + public synchronized RegionFile getRegionFileIfLoaded(ChunkPos chunkcoordintpair) { + return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ())); + } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java diff --git a/patches/server/Fix-dangerous-end-portal-logic.patch b/patches/server/Fix-dangerous-end-portal-logic.patch index 1eafeba01a..f4db15ac0b 100644 --- a/patches/server/Fix-dangerous-end-portal-logic.patch +++ b/patches/server/Fix-dangerous-end-portal-logic.patch @@ -15,9 +15,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- 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 { - } - // Paper end + public boolean updatingSectionStatus = false; + // Paper end + // Paper start - make end portalling safe + public BlockPos portalBlock; + public ServerLevel portalWorld; @@ -48,10 +48,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.teleportTo(worldserver, null); + } + // Paper end - make end portalling safe -+ + public Entity(EntityType type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); - this.passengers = ImmutableList.of(); @@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { } diff --git a/patches/server/Fix-plugin-loggers-on-server-shutdown.patch b/patches/server/Fix-plugin-loggers-on-server-shutdown.patch index b0fa9154a7..4fab2ddf6c 100644 --- a/patches/server/Fix-plugin-loggers-on-server-shutdown.patch +++ b/patches/server/Fix-plugin-loggers-on-server-shutdown.patch @@ -46,7 +46,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + io.papermc.paper.log.CustomLogManager.forceReset(); // Paper - Reset loggers after shutdown this.onServerExit(); - // Paper end + // Paper end - move final shutdown items here } diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 diff --git a/patches/server/Fix-silent-equipment-change-for-mobs.patch b/patches/server/Fix-silent-equipment-change-for-mobs.patch index 6e194f7935..9ffcfc332e 100644 --- a/patches/server/Fix-silent-equipment-change-for-mobs.patch +++ b/patches/server/Fix-silent-equipment-change-for-mobs.patch @@ -51,8 +51,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -0,0 +0,0 @@ public abstract class Level implements LevelAccessor, AutoCloseable { - - // Paper start + // Paper end - optimize redstone (Alternate Current) + // Paper start - notify observers even if grow failed public void checkCapturedTreeStateForObserverNotify(final BlockPos pos, final CraftBlockState craftBlockState) { - if (craftBlockState.getPosition().getY() == pos.getY() && this.getBlockState(craftBlockState.getPosition()) == craftBlockState.getHandle()) { // notify observers if the block state is the same and the Y level equals the original y level (for mega trees) + // notify observers if the block state is the same and the Y level equals the original y level (for mega trees) diff --git a/patches/server/Further-improve-server-tick-loop.patch b/patches/server/Further-improve-server-tick-loop.patch index 82a18711c8..debf0da413 100644 --- a/patches/server/Further-improve-server-tick-loop.patch +++ b/patches/server/Further-improve-server-tick-loop.patch @@ -90,7 +90,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper End // Spigot End - protected void runServer() { + public static volatile RuntimeException chunkSystemCrash; // Paper - rewrite chunk system @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { AtomicReference atomicreference = new AtomicReference(); - Thread thread = new Thread(() -> { + Thread thread = new io.papermc.paper.util.TickThread(() -> { // Paper - rewrite chunk system @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop, Set> byType = Maps.newHashMap(); public final Map, Set> getData() { return this.byType; } // Paper - public accessor private final Runnable setDirty; private boolean isValid; - + public final Optional noAllocateOptional = Optional.of(this); // Paper - rewrite chunk system diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java -@@ -0,0 +0,0 @@ public class SectionStorage implements AutoCloseable { +@@ -0,0 +0,0 @@ public class SectionStorage extends RegionFileStorage implements AutoCloseabl } @Nullable diff --git a/patches/server/Optimise-getChunkAt-calls-for-loaded-chunks.patch b/patches/server/Optimise-getChunkAt-calls-for-loaded-chunks.patch index 28344e744c..3bd61b6429 100644 --- a/patches/server/Optimise-getChunkAt-calls-for-loaded-chunks.patch +++ b/patches/server/Optimise-getChunkAt-calls-for-loaded-chunks.patch @@ -24,7 +24,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 gameprofilerfiller.incrementCounter("getChunk"); @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - if (Thread.currentThread() != this.mainThread) { + if (!io.papermc.paper.util.TickThread.isTickThread()) { // Paper - rewrite chunk system return null; } else { - this.level.getProfiler().incrementCounter("getChunkNow"); diff --git a/patches/server/Optimize-Captured-TileEntity-Lookup.patch b/patches/server/Optimize-Captured-TileEntity-Lookup.patch index 1925711d6f..d169847e04 100644 --- a/patches/server/Optimize-Captured-TileEntity-Lookup.patch +++ b/patches/server/Optimize-Captured-TileEntity-Lookup.patch @@ -26,5 +26,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } + // Paper end // CraftBukkit end - return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && Thread.currentThread() != this.thread ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); + return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && !io.papermc.paper.util.TickThread.isTickThread() ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); // Paper - rewrite chunk system } diff --git a/patches/server/Optimize-indirect-passenger-iteration.patch b/patches/server/Optimize-indirect-passenger-iteration.patch index c6ac7d02d0..280f61edfd 100644 --- a/patches/server/Optimize-indirect-passenger-iteration.patch +++ b/patches/server/Optimize-indirect-passenger-iteration.patch @@ -43,7 +43,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return () -> { return this.getIndirectPassengersStream().iterator(); }; - } +@@ -0,0 +0,0 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource { + // Paper end - rewrite chunk system public boolean hasExactlyOnePlayerPassenger() { + if (this.passengers.isEmpty()) { return false; } // Paper diff --git a/patches/server/Paper-dumpitem-command.patch b/patches/server/Paper-dumpitem-command.patch index 4d5fc71282..8608deff59 100644 --- a/patches/server/Paper-dumpitem-command.patch +++ b/patches/server/Paper-dumpitem-command.patch @@ -10,8 +10,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/io/papermc/paper/command/PaperCommand.java +++ b/src/main/java/io/papermc/paper/command/PaperCommand.java @@ -0,0 +0,0 @@ public final class PaperCommand extends Command { - commands.put(Set.of("dumpplugins"), new DumpPluginsCommand()); commands.put(Set.of("fixlight"), new FixLightCommand()); + commands.put(Set.of("debug", "chunkinfo", "holderinfo"), new ChunkDebugCommand()); commands.put(Set.of("syncloadinfo"), new SyncLoadInfoCommand()); + commands.put(Set.of("dumpitem"), new DumpItemCommand()); diff --git a/patches/server/Player-Chunk-Load-Unload-Events.patch b/patches/server/Player-Chunk-Load-Unload-Events.patch index b4693fb687..6d63186310 100644 --- a/patches/server/Player-Chunk-Load-Unload-Events.patch +++ b/patches/server/Player-Chunk-Load-Unload-Events.patch @@ -9,23 +9,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/network/PlayerChunkSender.java +++ b/src/main/java/net/minecraft/server/network/PlayerChunkSender.java @@ -0,0 +0,0 @@ public class PlayerChunkSender { - public void dropChunk(ServerPlayer player, ChunkPos pos) { - if (!this.pendingChunks.remove(pos.toLong()) && player.isAlive()) { - player.connection.send(new ClientboundForgetLevelChunkPacket(pos)); -+ // Paper start -+ if(io.papermc.paper.event.packet.PlayerChunkUnloadEvent.getHandlerList().getRegisteredListeners().length > 0){ -+ new io.papermc.paper.event.packet.PlayerChunkUnloadEvent(player.getBukkitEntity().getWorld().getChunkAt(pos.longKey), player.getBukkitEntity()).callEvent(); -+ } -+ // Paper end - } - + // Paper start - rewrite player chunk loader + public static void dropChunkStatic(ServerPlayer player, ChunkPos pos) { + player.connection.send(new ClientboundForgetLevelChunkPacket(pos)); ++ // Paper start ++ if (io.papermc.paper.event.packet.PlayerChunkUnloadEvent.getHandlerList().getRegisteredListeners().length > 0) { ++ new io.papermc.paper.event.packet.PlayerChunkUnloadEvent(player.getBukkitEntity().getWorld().getChunkAt(pos.longKey), player.getBukkitEntity()).callEvent(); ++ } ++ // Paper end } + // Paper end - rewrite player chunk loader + @@ -0,0 +0,0 @@ public class PlayerChunkSender { - private static void sendChunk(ServerGamePacketListenerImpl handler, ServerLevel world, LevelChunk chunk) { + public static void sendChunk(ServerGamePacketListenerImpl handler, ServerLevel world, LevelChunk chunk) { // Paper - rewrite chunk loader - public handler.send(new ClientboundLevelChunkWithLightPacket(chunk, world.getLightEngine(), (BitSet)null, (BitSet)null)); + // Paper start -+ if(io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0){ ++ if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) { + new io.papermc.paper.event.packet.PlayerChunkLoadEvent(new org.bukkit.craftbukkit.CraftChunk(chunk), handler.getPlayer().getBukkitEntity()).callEvent(); + } + // Paper end diff --git a/patches/server/PlayerNaturallySpawnCreaturesEvent.patch b/patches/server/PlayerNaturallySpawnCreaturesEvent.patch index a3012a5726..c85410ff9f 100644 --- a/patches/server/PlayerNaturallySpawnCreaturesEvent.patch +++ b/patches/server/PlayerNaturallySpawnCreaturesEvent.patch @@ -76,5 +76,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet cachedSingleHashSet; // Paper + public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper - public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) { - super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); + // Paper start - replace player chunk loader + private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); diff --git a/patches/server/Put-world-into-worldlist-before-initing-the-world.patch b/patches/server/Put-world-into-worldlist-before-initing-the-world.patch index bd59668813..cf12637cc8 100644 --- a/patches/server/Put-world-into-worldlist-before-initing-the-world.patch +++ b/patches/server/Put-world-into-worldlist-before-initing-the-world.patch @@ -38,4 +38,4 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper - move up this.getServer().prepareLevels(internal.getChunkSource().chunkMap.progressListener, internal); - internal.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API + //internal.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API // Paper - rewrite chunk system diff --git a/patches/unapplied/server/Rewrite-chunk-system.patch b/patches/server/Rewrite-chunk-system.patch similarity index 98% rename from patches/unapplied/server/Rewrite-chunk-system.patch rename to patches/server/Rewrite-chunk-system.patch index f44dbd1b53..ff66fbbbeb 100644 --- a/patches/unapplied/server/Rewrite-chunk-system.patch +++ b/patches/server/Rewrite-chunk-system.patch @@ -2354,9 +2354,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import net.minecraft.network.protocol.game.ClientboundSetChunkCacheRadiusPacket; +import net.minecraft.network.protocol.game.ClientboundSetSimulationDistancePacket; +import net.minecraft.server.level.ChunkMap; ++import net.minecraft.server.level.ChunkTrackingView; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.TicketType; ++import net.minecraft.server.network.PlayerChunkSender; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.chunk.ChunkAccess; @@ -2815,8 +2817,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + private void sendChunk(final int chunkX, final int chunkZ) { + if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) { -+ this.world.getChunkSource().chunkMap.updateChunkTracking(this.player, -+ new ChunkPos(chunkX, chunkZ), new MutableObject<>(), false, true); // unloaded, loaded ++ PlayerChunkSender.sendChunk(this.player.connection, this.world, this.world.getChunkIfLoaded(chunkX, chunkZ)); + return; + } + throw new IllegalStateException(); @@ -2830,8 +2831,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + + private void sendUnloadChunkRaw(final int chunkX, final int chunkZ) { -+ this.player.serverLevel().getChunkSource().chunkMap.updateChunkTracking(this.player, -+ new ChunkPos(chunkX, chunkZ), null, true, false); // unloaded, loaded ++ PlayerChunkSender.dropChunkStatic(this.player, new ChunkPos(chunkX, chunkZ)); + } + + private final SingleUserAreaMap broadcastMap = new SingleUserAreaMap<>(this) { @@ -2900,11 +2900,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + private static boolean wantChunkLoaded(final int centerX, final int centerZ, final int chunkX, final int chunkZ, + final int sendRadius) { + // expect sendRadius to be = 1 + target viewable radius -+ return ChunkMap.isChunkInRange(chunkX, chunkZ, centerX, centerZ, sendRadius); ++ return ChunkTrackingView.isWithinDistance(centerX, centerZ, sendRadius, chunkX, chunkZ, true); + } + + private static int getClientViewDistance(final ServerPlayer player) { -+ final Integer vd = player.clientViewDistance; ++ final Integer vd = player.requestedViewDistance(); + return vd == null ? -1 : Math.max(0, vd.intValue()); + } + @@ -3122,20 +3122,34 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // try to push more chunk generations + final long maxGens = Math.max(0L, Math.min(MAX_RATE, Math.min(this.genQueue.size(), this.getMaxChunkGenerates()))); + final int maxGensThisTick = (int)this.chunkGenerateTicketLimiter.takeAllocation(time, genRate, maxGens); -+ for (int i = 0; i < maxGensThisTick; ++i) { -+ final long chunk = this.genQueue.dequeueLong(); -+ final byte prev = this.chunkTicketStage.put(chunk, CHUNK_TICKET_STAGE_GENERATING); ++ int ratedGensThisTick = 0; ++ while (!this.genQueue.isEmpty()) { ++ final long chunkKey = this.genQueue.firstLong(); ++ final int chunkX = CoordinateUtils.getChunkX(chunkKey); ++ final int chunkZ = CoordinateUtils.getChunkZ(chunkKey); ++ final ChunkAccess chunk = this.world.chunkSource.getChunkAtImmediately(chunkX, chunkZ); ++ if (chunk.getStatus() != ChunkStatus.FULL) { ++ // only rate limit actual generations ++ if ((ratedGensThisTick + 1) > maxGensThisTick) { ++ break; ++ } ++ ++ratedGensThisTick; ++ } ++ ++ this.genQueue.dequeueLong(); ++ ++ final byte prev = this.chunkTicketStage.put(chunkKey, CHUNK_TICKET_STAGE_GENERATING); + if (prev != CHUNK_TICKET_STAGE_LOADED) { + throw new IllegalStateException("Previous state should be " + CHUNK_TICKET_STAGE_LOADED + ", not " + prev); + } + this.pushDelayedTicketOp( + ChunkHolderManager.TicketOperation.addAndRemove( -+ chunk, ++ chunkKey, + REGION_PLAYER_TICKET, GENERATED_TICKET_LEVEL, this.idBoxed, + REGION_PLAYER_TICKET, LOADED_TICKET_LEVEL, this.idBoxed + ) + ); -+ this.generatingQueue.enqueue(chunk); ++ this.generatingQueue.enqueue(chunkKey); + } + + // try to pull ticking chunks @@ -3783,6 +3797,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; ++import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.entity.EntityInLevelCallback; +import net.minecraft.world.level.entity.EntityTypeTest; +import net.minecraft.world.level.entity.LevelCallback; @@ -3790,6 +3805,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +import net.minecraft.world.level.entity.LevelEntityGetter; +import net.minecraft.world.level.entity.Visibility; +import net.minecraft.world.phys.AABB; ++import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; @@ -4076,22 +4092,55 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + this.getChunk(x, z).updateStatus(newStatus, this); + } + -+ public void addLegacyChunkEntities(final List entities) { -+ for (int i = 0, len = entities.size(); i < len; ++i) { -+ this.addEntity(entities.get(i), true); ++ public void addLegacyChunkEntities(final List entities, final ChunkPos forChunk) { ++ this.addEntityChunk(entities, forChunk, true); ++ } ++ ++ public void addEntityChunkEntities(final List entities, final ChunkPos forChunk) { ++ this.addEntityChunk(entities, forChunk, true); ++ } ++ ++ public void addWorldGenChunkEntities(final List entities, final ChunkPos forChunk) { ++ this.addEntityChunk(entities, forChunk, false); ++ } ++ ++ private void addRecursivelySafe(final Entity root, final boolean fromDisk) { ++ if (!this.addEntity(root, fromDisk)) { ++ // possible we are a passenger, and so should dismount from any valid entity in the world ++ root.stopRiding(true); ++ return; ++ } ++ for (final Entity passenger : root.getPassengers()) { ++ this.addRecursivelySafe(passenger, fromDisk); + } + } + -+ public void addEntityChunkEntities(final List entities) { ++ private void addEntityChunk(final List entities, final ChunkPos forChunk, final boolean fromDisk) { + for (int i = 0, len = entities.size(); i < len; ++i) { -+ this.addEntity(entities.get(i), true); -+ } -+ } ++ final Entity entity = entities.get(i); ++ if (entity.isPassenger()) { ++ continue; ++ } + -+ public void addWorldGenChunkEntities(final List entities) { -+ for (int i = 0, len = entities.size(); i < len; ++i) { -+ this.addEntity(entities.get(i), false); -+ } ++ if (!entity.chunkPosition().equals(forChunk)) { ++ LOGGER.warn("Root entity " + entity + " is outside of serialized chunk " + forChunk); ++ // can't set removed here, as we may not own the chunk position ++ // skip the entity ++ continue; ++ } ++ ++ final Vec3 rootPosition = entity.position(); ++ ++ // always adjust positions before adding passengers in case plugins access the entity, and so that ++ // they are added to the right entity chunk ++ for (final Entity passenger : entity.getIndirectPassengers()) { ++ if (!passenger.chunkPosition().equals(forChunk)) { ++ passenger.setPosRaw(rootPosition.x, rootPosition.y, rootPosition.z, true); ++ } ++ } ++ ++ this.addRecursivelySafe(entity, fromDisk); ++ } + } + + public boolean addNewEntity(final Entity entity) { @@ -6538,7 +6587,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + final ServerLevel world = this.world; + final ProtoChunk protoChunk = (ProtoChunk)this.fromChunk; + chunk = new LevelChunk(this.world, protoChunk, (final LevelChunk unused) -> { -+ ChunkMap.postLoadProtoChunk(world, protoChunk.getEntities()); ++ ChunkMap.postLoadProtoChunk(world, protoChunk.getEntities(), protoChunk.getPos()); // Paper - rewrite chunk system + }); + } + @@ -11054,7 +11103,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + if (entityChunk != null) { + final List entities = EntityStorage.readEntities(this.world, entityChunk); + -+ this.world.getEntityLookup().addEntityChunkEntities(entities); ++ this.world.getEntityLookup().addEntityChunkEntities(entities, new ChunkPos(this.chunkX, this.chunkZ)); + } + } + @@ -16775,7 +16824,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 +++ b/src/main/java/net/minecraft/network/Connection.java @@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler> { @Nullable - private volatile Component delayedDisconnect; + BandwidthDebugMonitor bandwidthDebugMonitor; public String hostname = ""; // CraftBukkit - add field + // Paper start - add pending task queue + private final Queue pendingTasks = new java.util.concurrent.ConcurrentLinkedQueue<>(); @@ -16808,7 +16857,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private void flushQueue() { + try { // Paper - add pending task queue if (this.channel != null && this.channel.isOpen()) { - Queue queue = this.queue; + Queue queue = this.pendingActions; @@ -0,0 +0,0 @@ public class Connection extends SimpleChannelInboundHandler> { @@ -17067,6 +17116,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public final ChunkHolder.PlayerProvider playerProvider; - private boolean wasAccessibleSinceLastSave; - private CompletableFuture pendingFullStateConfirmation; +- private CompletableFuture sendSync; + // Paper - rewrite chunk system private final ChunkMap chunkMap; // Paper @@ -17114,6 +17164,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public boolean hasChunkBeenSent() { + return this.playersSentChunkTo.size() != 0; + } ++ ++ public boolean hasBeenSent(ServerPlayer to) { ++ return this.playersSentChunkTo.contains(to); ++ } + // Paper end - replace player chunk loader + public ChunkHolder(ChunkPos pos, LevelHeightAccessor world, LevelLightEngine lightingProvider, ChunkHolder.PlayerProvider playersWatchingChunkProvider, io.papermc.paper.chunk.system.scheduling.NewChunkHolder newChunkHolder) { // Paper - rewrite chunk system + this.newChunkHolder = newChunkHolder; // Paper - rewrite chunk system @@ -17121,6 +17175,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.blockChangedLightSectionFilter = new BitSet(); this.skyChangedLightSectionFilter = new BitSet(); - this.pendingFullStateConfirmation = CompletableFuture.completedFuture(null); // CraftBukkit - decompile error +- this.sendSync = CompletableFuture.completedFuture(null); // CraftBukkit - decompile error + // Paper - rewrite chunk system this.pos = pos; this.levelHeightAccessor = world; @@ -17216,6 +17271,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end - rewrite chunk system } + public CompletableFuture getChunkSendSyncFuture() { +- return this.sendSync; ++ throw new UnsupportedOperationException(); // Paper - rewrite chunk system + } + + @Nullable + public LevelChunk getChunkToSend() { +- return !this.sendSync.isDone() ? null : this.getTickingChunk(); ++ return this.getSendingChunk(); // Paper - rewrite chunk system + } + @Nullable public final LevelChunk getFullChunk() { // Paper - final for inline - CompletableFuture> completablefuture = this.getFullChunkFuture(); @@ -17415,8 +17481,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 }); } +- public void addSendDependency(CompletableFuture postProcessingFuture) { +- if (this.sendSync.isDone()) { +- this.sendSync = postProcessingFuture; +- } else { +- this.sendSync = this.sendSync.thenCombine(postProcessingFuture, (object, object1) -> { +- return null; +- }); +- } +- +- } + // Paper - rewrite chunk system -+ + public FullChunkStatus getFullStatus() { - return ChunkLevel.fullStatus(this.ticketLevel); + return this.newChunkHolder.getChunkStatus(); // Paper - rewrite chunk system) { @@ -17692,7 +17768,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - private static final int MIN_VIEW_DISTANCE = 2; + public static final int MIN_VIEW_DISTANCE = 2; public static final int MAX_VIEW_DISTANCE = 32; public static final int FORCED_TICKET_LEVEL = ChunkLevel.byStatus(FullChunkStatus.ENTITY_TICKING); - public final Long2ObjectLinkedOpenHashMap updatingChunkMap = new Long2ObjectLinkedOpenHashMap(); @@ -17725,7 +17801,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public final Int2ObjectMap entityMap; @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider private final Queue unloadQueue; - int viewDistance; + private int serverViewDistance; - // CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback() - public final CallbackExecutor callbackExecutor = new CallbackExecutor(); @@ -17754,8 +17830,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 void addPlayerToDistanceMaps(ServerPlayer player) { + this.level.playerChunkLoader.addPlayer(player); // Paper - replace chunk loader - int chunkX = MCUtil.getChunkCoordinate(player.getX()); - int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); + int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX()); + int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ()); // Note: players need to be explicitly added to distance maps before they can be updated } @@ -17765,8 +17841,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - int chunkX = MCUtil.getChunkCoordinate(player.getX()); - int chunkZ = MCUtil.getChunkCoordinate(player.getZ()); + int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX()); + int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ()); // Note: players need to be explicitly added to distance maps before they can be updated + this.level.playerChunkLoader.updatePlayer(player); // Paper - replace chunk loader } @@ -17817,6 +17893,36 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.overworldDataStorage = persistentStateManagerFactory; this.poiManager = new PoiManager(path.resolve("poi"), dataFixer, dsync, iregistrycustom, world); @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + boolean isChunkTracked(ServerPlayer player, int chunkX, int chunkZ) { +- return player.getChunkTrackingView().contains(chunkX, chunkZ) && !player.connection.chunkSender.isPending(ChunkPos.asLong(chunkX, chunkZ)); ++ // Paper start - rewrite player chunk loader ++ return this.level.playerChunkLoader.isChunkSent(player, chunkX, chunkZ); ++ // Paper end - rewrite player chunk loader + } + + private boolean isChunkOnTrackedBorder(ServerPlayer player, int chunkX, int chunkZ) { +- if (!this.isChunkTracked(player, chunkX, chunkZ)) { +- return false; +- } else { +- for (int k = -1; k <= 1; ++k) { +- for (int l = -1; l <= 1; ++l) { +- if ((k != 0 || l != 0) && !this.isChunkTracked(player, chunkX + k, chunkZ + l)) { +- return true; +- } +- } +- } +- +- return false; +- } ++ // Paper start - rewrite player chunk loader ++ return this.level.playerChunkLoader.isChunkSent(player, chunkX, chunkZ, true); ++ // Paper end - rewrite player chunk loader + } + + protected ThreadedLevelLightEngine getLightEngine() { +@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Nullable protected ChunkHolder getUpdatingChunkIfPresent(long pos) { @@ -17847,6 +17953,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public String getChunkDebugData(ChunkPos chunkPos) { @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + // Paper start + public final int getEffectiveViewDistance() { +- // TODO this needs to be checked on update +- // Mojang currently sets it to +1 of the configured view distance. So subtract one to get the one we really want. +- //TODO check if +0 is correct now +- return this.viewDistance; ++ return this.serverViewDistance; + } // Paper end private CompletableFuture, ChunkHolder.ChunkLoadingFailure>> getChunkRangeFuture(ChunkHolder centerChunk, int margin, IntFunction distanceToStatus) { @@ -17903,7 +18018,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - - Optional optional = either.left(); - -- if (!optional.isPresent()) { +- if (optional.isEmpty()) { - return Either.right(new ChunkHolder.ChunkLoadingFailure() { - public String toString() { - ChunkPos chunkcoordintpair2 = new ChunkPos(j + l1 % (margin * 2 + 1), k + l1 / (margin * 2 + 1)); @@ -18005,7 +18120,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected void saveAllChunks(boolean flush) { - if (flush) { -- List list = (List) io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).collect(Collectors.toList()); // Paper +- List list = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).stream().filter(ChunkHolder::wasAccessibleSinceLastSave).peek(ChunkHolder::refreshAccessibility).toList(); // Paper - MutableBoolean mutableboolean = new MutableBoolean(); - - do { @@ -18286,11 +18401,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } - private static void postLoadProtoChunk(ServerLevel world, List nbt) { -+ public static void postLoadProtoChunk(ServerLevel world, List nbt) { // Paper - public ++ public static void postLoadProtoChunk(ServerLevel world, List nbt, ChunkPos position) { // Paper - public and add chunk position parameter if (!nbt.isEmpty()) { // CraftBukkit start - these are spawned serialized (DefinedStructure) and we don't call an add event below at the moment due to ordering complexities world.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(nbt, world).filter((entity) -> { @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + needsRemoval = true; + } + return !needsRemoval; +- })); ++ }), position); // Paper - rewrite chunk system + // CraftBukkit end + } + } private CompletableFuture> protoChunkToFullChunk(ChunkHolder chunkHolder) { @@ -18351,6 +18474,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - return either.ifLeft((chunk) -> { - chunk.postProcessGeneration(); - this.level.startTickingChunk(chunk); +- CompletableFuture completablefuture2 = holder.getChunkSendSyncFuture(); +- +- if (completablefuture2.isDone()) { +- this.onChunkReadyToSend(chunk); +- } else { +- completablefuture2.thenAcceptAsync((object) -> { +- this.onChunkReadyToSend(chunk); +- }, this.mainThreadExecutor); +- } +- - }); - }, this.mainThreadExecutor); - @@ -18358,27 +18491,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.tickingGenerated.getAndIncrement(); - return null; - }); -- completablefuture1.thenAcceptAsync((either) -> { -- either.ifLeft((chunk) -> { -- MutableObject mutableobject = new MutableObject(); -- -- this.getPlayers(holder.getPos(), false).forEach((entityplayer) -> { -- this.playerLoadedChunk(entityplayer, mutableobject, chunk); -- }); -- }); -- }, (runnable) -> { -- this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable)); -- }); - return completablefuture1; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } + private void onChunkReadyToSend(LevelChunk chunk) { +- ChunkPos chunkcoordintpair = chunk.getPos(); +- Iterator iterator = this.playerMap.getAllPlayers().iterator(); +- +- while (iterator.hasNext()) { +- ServerPlayer entityplayer = (ServerPlayer) iterator.next(); +- +- if (entityplayer.getChunkTrackingView().contains(chunkcoordintpair)) { +- ChunkMap.markChunkPendingToSend(entityplayer, chunk); +- } +- } ++ throw new UnsupportedOperationException(); // Paper - rewrite player chunk loader + + } + public CompletableFuture> prepareAccessibleChunk(ChunkHolder holder) { - return this.getChunkRangeFuture(holder, 1, ChunkStatus::getStatusAroundFullChunk).thenApplyAsync((either) -> { - return either.mapLeft((list) -> { -- LevelChunk chunk = (LevelChunk) list.get(list.size() / 2); -- -- return chunk; +- return (LevelChunk) list.get(list.size() / 2); - }); - }, (runnable) -> { - this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable)); @@ -18474,88 +18609,67 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.markPositionReplaceable(pos); - return false; - } -- -- ChunkStatus.ChunkType chunkstatus_type = ChunkSerializer.getChunkTypeFromTag(nbttagcompound); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system + } +- ChunkStatus.ChunkType chunkstatus_type = ChunkSerializer.getChunkTypeFromTag(nbttagcompound); ++ // Paper start - replace player loader system ++ public void setTickViewDistance(int distance) { ++ this.level.playerChunkLoader.setTickDistance(distance); ++ } + - return this.markPosition(pos, chunkstatus_type) == 1; - } -+ // Paper start - replace player loader system -+ public void setTickViewDistance(int distance) { -+ this.level.playerChunkLoader.setTickDistance(distance); - } - + public void setSendViewDistance(int distance) { + this.level.playerChunkLoader.setSendDistance(distance); -+ } + } + // Paper end - replace player loader system - public void setViewDistance(int watchDistance) { + +- protected void setServerViewDistance(int watchDistance) { ++ public void setServerViewDistance(int watchDistance) { // Paper - replace player loader system int j = Mth.clamp(watchDistance, 2, 32); -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - int k = this.viewDistance; - - this.viewDistance = j; -- this.distanceManager.updatePlayerTickets(this.viewDistance); -- Iterator objectiterator = io.papermc.paper.chunk.system.ChunkSystem.getUpdatingChunkHolders(this.level).iterator(); // Paper + if (j != this.serverViewDistance) { + this.serverViewDistance = j; +- this.distanceManager.updatePlayerTickets(this.serverViewDistance); +- Iterator iterator = this.playerMap.getAllPlayers().iterator(); - -- while (objectiterator.hasNext()) { -- ChunkHolder playerchunk = (ChunkHolder) objectiterator.next(); -- ChunkPos chunkcoordintpair = playerchunk.getPos(); -- MutableObject mutableobject = new MutableObject(); +- while (iterator.hasNext()) { +- ServerPlayer entityplayer = (ServerPlayer) iterator.next(); - -- this.getPlayers(chunkcoordintpair, false).forEach((entityplayer) -> { -- SectionPos sectionposition = entityplayer.getLastSectionPos(); -- boolean flag = ChunkMap.isChunkInRange(chunkcoordintpair.x, chunkcoordintpair.z, sectionposition.x(), sectionposition.z(), k); -- boolean flag1 = ChunkMap.isChunkInRange(chunkcoordintpair.x, chunkcoordintpair.z, sectionposition.x(), sectionposition.z(), this.viewDistance); -- -- this.updateChunkTracking(entityplayer, chunkcoordintpair, mutableobject, flag, flag1); -- }); +- this.updateChunkTracking(entityplayer); - } -+ this.level.playerChunkLoader.setLoadDistance(this.viewDistance + 1); // Paper - replace player loader system ++ this.level.playerChunkLoader.setLoadDistance(this.serverViewDistance + 1); // Paper - replace player loader system } } -- protected void updateChunkTracking(ServerPlayer player, ChunkPos pos, MutableObject packet, boolean oldWithinViewDistance, boolean newWithinViewDistance) { -+ public void updateChunkTracking(ServerPlayer player, ChunkPos pos, MutableObject packet, boolean oldWithinViewDistance, boolean newWithinViewDistance) { // Paper - public -+ io.papermc.paper.util.TickThread.ensureTickThread(this.level, pos, "May not update chunk tracking for chunk async"); // Paper - replace chunk loader system -+ io.papermc.paper.util.TickThread.ensureTickThread(player, "May not update chunk tracking for player async"); // Paper - replace chunk loader system - if (player.level() == this.level) { -+ ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong()); // Paper - replace chunk loader system - move up - if (newWithinViewDistance && !oldWithinViewDistance) { -- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.toLong()); -+ // Paper - replace chunk loader system - move up - - if (playerchunk != null) { -- LevelChunk chunk = playerchunk.getTickingChunk(); -+ LevelChunk chunk = playerchunk.getSendingChunk(); // Paper - replace chunk loader system - - if (chunk != null) { -+ playerchunk.addPlayer(player); // Paper - replace chunk loader system - this.playerLoadedChunk(player, packet, chunk); - } - -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - if (!newWithinViewDistance && oldWithinViewDistance) { -+ // Paper start - replace chunk loader system -+ if (playerchunk != null) { -+ playerchunk.removePlayer(player); -+ } else { -+ LOGGER.warn("ChunkHolder at " + pos + " in world '" + this.level.getWorld().getName() + "' does not exist to untrack chunk for " + player, new Throwable()); -+ } -+ // Paper end - replace chunk loader system - player.untrackChunk(pos); - } - -- } -+ } else { LOGGER.warn("Mismatch in world for chunk " + pos + " in world '" + this.level.getWorld().getName() + "' for player " + player, new Throwable()); } // Paper - replace chunk loader system + int getPlayerViewDistance(ServerPlayer player) { +- return Mth.clamp(player.requestedViewDistance(), 2, this.serverViewDistance); ++ return io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player); // Paper - per player view distance } - public int size() { + private void markChunkPendingToSend(ServerPlayer player, ChunkPos pos) { +- LevelChunk chunk = this.getChunkToSend(pos.toLong()); +- +- if (chunk != null) { +- ChunkMap.markChunkPendingToSend(player, chunk); +- } ++ throw new UnsupportedOperationException(); // Paper - per player view distance + + } + + private static void markChunkPendingToSend(ServerPlayer player, LevelChunk chunk) { +- player.connection.chunkSender.markChunkPendingToSend(chunk); ++ throw new UnsupportedOperationException(); // Paper - rewrite player chunk loader + } + + private static void dropChunk(ServerPlayer player, ChunkPos pos) { +- player.connection.chunkSender.dropChunk(player, pos); ++ // Paper - rewrite player chunk loader + } + + @Nullable @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } @@ -18625,90 +18739,93 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return this.read(chunkPos).thenApplyAsync((optional) -> { return optional.map((nbttagcompound) -> this.upgradeChunkTag(nbttagcompound, chunkPos)); // CraftBukkit @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + this.distanceManager.addPlayer(SectionPos.of((EntityAccess) player), player); + } + +- player.setChunkTrackingView(ChunkTrackingView.EMPTY); +- this.updateChunkTracking(player); ++ // Paper - handled by player chunk loader + this.addPlayerToDistanceMaps(player); // Paper - distance maps + } else { + SectionPos sectionposition = player.getLastSectionPos(); +@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + this.removePlayerFromDistanceMaps(player); // Paper - distance maps +- this.applyChunkTrackingView(player, ChunkTrackingView.EMPTY); ++ // Paper - handled by player chunk loader } -- for (int k = i - this.viewDistance - 1; k <= i + this.viewDistance + 1; ++k) { -- for (int l = j - this.viewDistance - 1; l <= j + this.viewDistance + 1; ++l) { -- if (ChunkMap.isChunkInRange(k, l, i, j, this.viewDistance)) { -- ChunkPos chunkcoordintpair = new ChunkPos(k, l); -- -- this.updateChunkTracking(player, chunkcoordintpair, new MutableObject(), !added, added); -- } -- } -- } -+ // Paper - handled by player chunk loader - } - @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - SectionPos sectionposition = SectionPos.of((EntityAccess) player); + this.playerMap.unIgnorePlayer(player); + } - player.setLastSectionPos(sectionposition); -- player.connection.send(new ClientboundSetChunkCacheCenterPacket(sectionposition.x(), sectionposition.z())); -+ //player.connection.send(new ClientboundSetChunkCacheCenterPacket(sectionposition.x(), sectionposition.z())); // Paper - handled by player chunk loader - return sectionposition; - } - -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - int l1; - int i2; - -- if (Math.abs(i1 - i) <= k1 * 2 && Math.abs(j1 - j) <= k1 * 2) { -- l1 = Math.min(i, i1) - k1; -- i2 = Math.min(j, j1) - k1; -- int j2 = Math.max(i, i1) + k1; -- int k2 = Math.max(j, j1) + k1; -- -- for (int l2 = l1; l2 <= j2; ++l2) { -- for (int i3 = i2; i3 <= k2; ++i3) { -- boolean flag3 = ChunkMap.isChunkInRange(l2, i3, i1, j1, this.viewDistance); -- boolean flag4 = ChunkMap.isChunkInRange(l2, i3, i, j, this.viewDistance); -- -- this.updateChunkTracking(player, new ChunkPos(l2, i3), new MutableObject(), flag3, flag4); -- } -- } -- } else { -- boolean flag5; -- boolean flag6; -- -- for (l1 = i1 - k1; l1 <= i1 + k1; ++l1) { -- for (i2 = j1 - k1; i2 <= j1 + k1; ++i2) { -- if (ChunkMap.isChunkInRange(l1, i2, i1, j1, this.viewDistance)) { -- flag5 = true; -- flag6 = false; -- this.updateChunkTracking(player, new ChunkPos(l1, i2), new MutableObject(), true, false); -- } -- } -- } -- -- for (l1 = i - k1; l1 <= i + k1; ++l1) { -- for (i2 = j - k1; i2 <= j + k1; ++i2) { -- if (ChunkMap.isChunkInRange(l1, i2, i, j, this.viewDistance)) { -- flag5 = false; -- flag6 = true; -- this.updateChunkTracking(player, new ChunkPos(l1, i2), new MutableObject(), false, true); -- } -- } -- } -- } -+ // Paper - replaced by PlayerChunkLoader +- this.updateChunkTracking(player); ++ // Paper - replaced by PlayerChunkLoader + } this.updateMaps(player); // Paper - distance maps + } -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + private void updateChunkTracking(ServerPlayer player) { +- ChunkPos chunkcoordintpair = player.chunkPosition(); +- int i = this.getPlayerViewDistance(player); +- ChunkTrackingView chunktrackingview = player.getChunkTrackingView(); +- +- if (chunktrackingview instanceof ChunkTrackingView.Positioned) { +- ChunkTrackingView.Positioned chunktrackingview_a = (ChunkTrackingView.Positioned) chunktrackingview; +- +- if (chunktrackingview_a.center().equals(chunkcoordintpair) && chunktrackingview_a.viewDistance() == i) { +- return; +- } +- } +- +- this.applyChunkTrackingView(player, ChunkTrackingView.of(chunkcoordintpair, i)); ++ throw new UnsupportedOperationException(); // Paper - replaced by PlayerChunkLoader + } + + private void applyChunkTrackingView(ServerPlayer player, ChunkTrackingView chunkFilter) { +- if (player.level() == this.level) { +- ChunkTrackingView chunktrackingview1 = player.getChunkTrackingView(); +- +- if (chunkFilter instanceof ChunkTrackingView.Positioned) { +- label15: +- { +- ChunkTrackingView.Positioned chunktrackingview_a = (ChunkTrackingView.Positioned) chunkFilter; +- +- if (chunktrackingview1 instanceof ChunkTrackingView.Positioned) { +- ChunkTrackingView.Positioned chunktrackingview_a1 = (ChunkTrackingView.Positioned) chunktrackingview1; +- +- if (chunktrackingview_a1.center().equals(chunktrackingview_a.center())) { +- break label15; +- } +- } +- +- player.connection.send(new ClientboundSetChunkCacheCenterPacket(chunktrackingview_a.center().x, chunktrackingview_a.center().z)); +- } +- } +- +- ChunkTrackingView.difference(chunktrackingview1, chunkFilter, (chunkcoordintpair) -> { +- this.markChunkPendingToSend(player, chunkcoordintpair); +- }, (chunkcoordintpair) -> { +- ChunkMap.dropChunk(player, chunkcoordintpair); +- }); +- player.setChunkTrackingView(chunkFilter); +- } ++ throw new UnsupportedOperationException(); // Paper - replaced by PlayerChunkLoader + } @Override public List getPlayers(ChunkPos chunkPos, boolean onlyOnWatchDistanceEdge) { -- Set set = this.playerMap.getPlayers(chunkPos.toLong()); +- Set set = this.playerMap.getAllPlayers(); - Builder builder = ImmutableList.builder(); - Iterator iterator = set.iterator(); - - while (iterator.hasNext()) { - ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -- SectionPos sectionposition = entityplayer.getLastSectionPos(); - -- if (onlyOnWatchDistanceEdge && ChunkMap.isChunkOnRangeBorder(chunkPos.x, chunkPos.z, sectionposition.x(), sectionposition.z(), this.viewDistance) || !onlyOnWatchDistanceEdge && ChunkMap.isChunkInRange(chunkPos.x, chunkPos.z, sectionposition.x(), sectionposition.z(), this.viewDistance)) { +- if (onlyOnWatchDistanceEdge && this.isChunkOnTrackedBorder(entityplayer, chunkPos.x, chunkPos.z) || !onlyOnWatchDistanceEdge && this.isChunkTracked(entityplayer, chunkPos.x, chunkPos.z)) { - builder.add(entityplayer); - } + // Paper start - per player view distance @@ -18725,6 +18842,39 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public void addEntity(Entity entity) { @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + protected void tick() { +- Iterator iterator = this.playerMap.getAllPlayers().iterator(); +- +- while (iterator.hasNext()) { +- ServerPlayer entityplayer = (ServerPlayer) iterator.next(); +- +- this.updateChunkTracking(entityplayer); +- } ++ // Paper - replaced by PlayerChunkLoader + + List list = Lists.newArrayList(); + List list1 = this.level.players(); +@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + public void waitForLightBeforeSending(ChunkPos centerPos, int radius) { +- int j = radius + 1; +- +- ChunkPos.rangeClosed(centerPos, j).forEach((chunkcoordintpair1) -> { +- ChunkHolder playerchunk = this.getVisibleChunkIfPresent(chunkcoordintpair1.toLong()); +- +- if (playerchunk != null) { +- playerchunk.addSendDependency(this.lightEngine.waitForPendingTasks(chunkcoordintpair1.x, chunkcoordintpair1.z)); +- } +- +- }); ++ // Paper - rewrite player chunk loader + } + + private class ChunkDistanceManager extends DistanceManager { +@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Override protected boolean isChunkToRemove(long pos) { @@ -18733,15 +18883,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } @Nullable -@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot - if (player != this.entity) { - Vec3 vec3d = player.position().subtract(this.entity.position()); -- double d0 = (double) Math.min(this.getEffectiveRange(), ChunkMap.this.viewDistance * 16); -+ double d0 = (double) Math.min(this.getEffectiveRange(), io.papermc.paper.chunk.system.ChunkSystem.getSendViewDistance(player) * 16); // Paper - per player view distance - double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z; - double d2 = d0 * d0; - boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player); diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java @@ -19048,7 +19189,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 protected void updatePlayerTickets(int viewDistance) { - this.playerTicketManager.updateViewDistance(viewDistance); -+ this.chunkMap.setViewDistance(viewDistance);// Paper - route to player chunk manager ++ this.chunkMap.setServerViewDistance(viewDistance);// Paper - route to player chunk manager } // Paper start @@ -19721,8 +19862,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 java.util.function.Consumer consumer = (net.minecraft.world.level.chunk.ChunkAccess chunk) -> { if (chunk != null) { - int ticketLevel = Math.max(33, chunkProvider.chunkMap.getUpdatingChunkIfPresent(chunk.getPos().toLong()).getTicketLevel()); ++ synchronized (ret) { // Folia - region threading - make callback thread-safe TODO rebase ret.add(chunk); - ticketLevels.add(ticketLevel); ++ } // Folia - region threading - make callback thread-safe TODO rebase chunkProvider.addTicketAtLevel(TicketType.FUTURE_AWAIT, chunk.getPos(), ticketLevel, holderIdentifier); } - if (++loadedChunks[0] == requiredChunks) { @@ -19985,7 +20128,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 }); this.chunkSource.getGeneratorState().ensureStructuresGenerated(); @@ -0,0 +0,0 @@ public class ServerLevel extends Level implements WorldGenLevel { - }, "random_sequences"); + return (RandomSequences) this.getDataStorage().computeIfAbsent(RandomSequences.factory(l), "random_sequences"); }); this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit + @@ -20131,14 +20274,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return this.entityLookup; // Paper - rewrite chunk system } - public void addLegacyChunkEntities(Stream entities) { +- public void addLegacyChunkEntities(Stream entities) { - this.entityManager.addLegacyChunkEntities(entities); -+ this.entityLookup.addLegacyChunkEntities(entities.toList()); // Paper - rewrite chunk system ++ public void addLegacyChunkEntities(Stream entities, ChunkPos forChunk) { // Paper - rewrite chunk system ++ this.entityLookup.addLegacyChunkEntities(entities.toList(), forChunk); // Paper - rewrite chunk system } - public void addWorldGenChunkEntities(Stream entities) { +- public void addWorldGenChunkEntities(Stream entities) { - this.entityManager.addWorldGenChunkEntities(entities); -+ this.entityLookup.addWorldGenChunkEntities(entities.toList()); // Paper - rewrite chunk system ++ public void addWorldGenChunkEntities(Stream entities, ChunkPos forChunk) { // Paper - rewrite chunk system ++ this.entityLookup.addWorldGenChunkEntities(entities.toList(), forChunk); // Paper - rewrite chunk system } public void startTickingChunk(LevelChunk chunk) { @@ -20207,6 +20352,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public boolean isRealPlayer; // Paper public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet cachedSingleHashSet; // Paper ++ // Paper start - replace player chunk loader + private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); + public io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader; + @@ -20248,8 +20394,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return input.setSendViewDistance(distance); + }); + } ++ // Paper end - replace player chunk loader + - public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile) { + public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) { super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); this.chatVisibility = ChatVisiblity.FULL; diff --git a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java @@ -20425,7 +20572,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - static enum TaskType { + public CompletableFuture waitForPendingTasks(int x, int z) { diff --git a/src/main/java/net/minecraft/server/level/Ticket.java b/src/main/java/net/minecraft/server/level/Ticket.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/Ticket.java @@ -20522,11 +20669,55 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + public void getEntitiesByClass(Class clazz, Entity except, AABB box, List into, Predicate predicate) {} + // Paper end } +diff --git a/src/main/java/net/minecraft/server/network/PlayerChunkSender.java b/src/main/java/net/minecraft/server/network/PlayerChunkSender.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/network/PlayerChunkSender.java ++++ b/src/main/java/net/minecraft/server/network/PlayerChunkSender.java +@@ -0,0 +0,0 @@ public class PlayerChunkSender { + this.pendingChunks.add(chunk.getPos().toLong()); + } + ++ // Paper start - rewrite player chunk loader ++ public static void dropChunkStatic(ServerPlayer player, ChunkPos pos) { ++ player.connection.send(new ClientboundForgetLevelChunkPacket(pos)); ++ } ++ // Paper end - rewrite player chunk loader ++ + public void dropChunk(ServerPlayer player, ChunkPos pos) { + if (!this.pendingChunks.remove(pos.toLong()) && player.isAlive()) { +- player.connection.send(new ClientboundForgetLevelChunkPacket(pos)); ++ dropChunkStatic(player, pos); // Paper - rewrite player chunk loader - move into own method + } + + } + + public void sendNextChunks(ServerPlayer player) { ++ if (true) return; // Paper - rewrite player chunk loader + if (this.unacknowledgedBatches < this.maxUnacknowledgedBatches) { + float f = Math.max(1.0F, this.desiredChunksPerTick); + this.batchQuota = Math.min(this.batchQuota + this.desiredChunksPerTick, f); +@@ -0,0 +0,0 @@ public class PlayerChunkSender { + } + } + +- private static void sendChunk(ServerGamePacketListenerImpl handler, ServerLevel world, LevelChunk chunk) { ++ public static void sendChunk(ServerGamePacketListenerImpl handler, ServerLevel world, LevelChunk chunk) { // Paper - rewrite chunk loader - public + handler.send(new ClientboundLevelChunkWithLightPacket(chunk, world.getLightEngine(), (BitSet)null, (BitSet)null)); + ChunkPos chunkPos = chunk.getPos(); + DebugPackets.sendPoiPacketsForChunk(world, chunkPos); +@@ -0,0 +0,0 @@ public class PlayerChunkSender { + } + + public void onChunkBatchReceivedByClient(float desiredBatchSize) { ++ if (true) return; // Paper - rewrite player chunk loader + --this.unacknowledgedBatches; + this.desiredChunksPerTick = Double.isNaN((double)desiredBatchSize) ? 0.01F : Mth.clamp(desiredBatchSize, 0.01F, 64.0F); + if (this.unacknowledgedBatches == 0) { diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Tic +@@ -0,0 +0,0 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl this.disconnect(Component.translatable("disconnect.spam")); return; } @@ -20545,25 +20736,25 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- 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 { - boolean flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO); + boolean flag2 = gamerules.getBoolean(GameRules.RULE_LIMITED_CRAFTING); // Spigot - view distance -- playerconnection.send(new ClientboundLoginPacket(player.getId(), worlddata.isHardcore(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), this.server.levelKeys(), this.synchronizedRegistries, worldserver1.dimensionTypeId(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), this.getMaxPlayers(), worldserver1.spigotConfig.viewDistance, worldserver1.spigotConfig.simulationDistance, flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat(), player.getLastDeathLocation(), player.getPortalCooldown())); -+ playerconnection.send(new ClientboundLoginPacket(player.getId(), worlddata.isHardcore(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), this.server.levelKeys(), this.synchronizedRegistries, worldserver1.dimensionTypeId(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), this.getMaxPlayers(), worldserver1.getWorld().getSendViewDistance(), worldserver1.getWorld().getSimulationDistance(), flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat(), player.getLastDeathLocation(), player.getPortalCooldown())); // Paper - replace old player chunk management +- playerconnection.send(new ClientboundLoginPacket(player.getId(), worlddata.isHardcore(), this.server.levelKeys(), this.getMaxPlayers(), worldserver1.spigotConfig.viewDistance, worldserver1.spigotConfig.simulationDistance, flag1, !flag, flag2, player.createCommonSpawnInfo(worldserver1))); ++ playerconnection.send(new ClientboundLoginPacket(player.getId(), worlddata.isHardcore(), this.server.levelKeys(), this.getMaxPlayers(), worldserver1.getWorld().getSendViewDistance(), worldserver1.getWorld().getSimulationDistance(), flag1, !flag, flag2, player.createCommonSpawnInfo(worldserver1))); // Paper - replace old player chunk management player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit - playerconnection.send(new ClientboundUpdateEnabledFeaturesPacket(FeatureFlags.REGISTRY.toNames(worldserver1.enabledFeatures()))); - playerconnection.send(new ClientboundCustomPayloadPacket(ClientboundCustomPayloadPacket.BRAND, (new FriendlyByteBuf(Unpooled.buffer())).writeUtf(this.getServer().getServerModName()))); + playerconnection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked())); + playerconnection.send(new ClientboundPlayerAbilitiesPacket(player.getAbilities())); @@ -0,0 +0,0 @@ public abstract class PlayerList { - // CraftBukkit start - LevelData worlddata = worldserver1.getLevelData(); - entityplayer1.connection.send(new ClientboundRespawnPacket(worldserver1.dimensionTypeId(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), entityplayer1.gameMode.getGameModeForPlayer(), entityplayer1.gameMode.getPreviousGameModeForPlayer(), worldserver1.isDebug(), worldserver1.isFlat(), (byte) i, entityplayer1.getLastDeathLocation(), entityplayer1.getPortalCooldown())); + LevelData worlddata = worldserver2.getLevelData(); + + entityplayer1.connection.send(new ClientboundRespawnPacket(entityplayer1.createCommonSpawnInfo(worldserver2), (byte) i)); - entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.spigotConfig.viewDistance)); // Spigot - entityplayer1.connection.send(new ClientboundSetSimulationDistancePacket(worldserver1.spigotConfig.simulationDistance)); // Spigot + entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.getWorld().getSendViewDistance())); // Spigot // Paper - replace old player chunk management + entityplayer1.connection.send(new ClientboundSetSimulationDistancePacket(worldserver1.getWorld().getSimulationDistance())); // Spigot // Paper - replace old player chunk management - entityplayer1.spawnIn(worldserver1); - entityplayer1.unsetRemoved(); - entityplayer1.connection.teleport(CraftLocation.toBukkit(entityplayer1.position(), worldserver1.getWorld(), entityplayer1.getYRot(), entityplayer1.getXRot())); + entityplayer1.connection.teleport(CraftLocation.toBukkit(entityplayer1.position(), worldserver2.getWorld(), entityplayer1.getYRot(), entityplayer1.getXRot())); // CraftBukkit + entityplayer1.connection.send(new ClientboundSetDefaultSpawnPositionPacket(worldserver1.getSharedSpawnPos(), worldserver1.getSharedSpawnAngle())); + entityplayer1.connection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked())); @@ -0,0 +0,0 @@ public abstract class PlayerList { public void setViewDistance(int viewDistance) { @@ -21689,6 +21880,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 nbttagcompound.put("PostProcessing", ChunkSerializer.packOffsets(chunk.getPostProcessing())); CompoundTag nbttagcompound3 = new CompoundTag(); Iterator iterator1 = chunk.getHeightmaps().iterator(); +@@ -0,0 +0,0 @@ public class ChunkSerializer { + + return nbttaglist == null && nbttaglist1 == null ? null : (chunk) -> { + if (nbttaglist != null) { +- world.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(nbttaglist, world)); ++ world.addLegacyChunkEntities(EntityType.loadEntitiesRecursive(nbttaglist, world), chunk.getPos()); // Paper - rewrite chunk system + } + + if (nbttaglist1 != null) { diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java @@ -22798,7 +22998,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + throw new IllegalArgumentException("View distance " + viewDistance + " is out of range of [2, 32]"); + } + net.minecraft.server.level.ChunkMap chunkMap = getHandle().getChunkSource().chunkMap; -+ chunkMap.setViewDistance(viewDistance); ++ chunkMap.setServerViewDistance(viewDistance); + } + + @Override diff --git a/patches/server/Sanitise-RegionFileCache-and-make-configurable.patch b/patches/server/Sanitise-RegionFileCache-and-make-configurable.patch index 6dc02058ac..1d713471f4 100644 --- a/patches/server/Sanitise-RegionFileCache-and-make-configurable.patch +++ b/patches/server/Sanitise-RegionFileCache-and-make-configurable.patch @@ -15,9 +15,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- 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 @@ public class RegionFileStorage implements AutoCloseable { - if (regionfile != null) { - return regionfile; - } else { + return null; + } + // Paper end - cache regionfile does not exist state - if (this.regionCache.size() >= 256) { + if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper - configurable ((RegionFile) this.regionCache.removeLast()).close(); diff --git a/patches/server/Show-Paper-in-client-crashes-server-lists-and-Mojang.patch b/patches/server/Show-Paper-in-client-crashes-server-lists-and-Mojang.patch index 3bd592f65c..c1093120a8 100644 --- a/patches/server/Show-Paper-in-client-crashes-server-lists-and-Mojang.patch +++ b/patches/server/Show-Paper-in-client-crashes-server-lists-and-Mojang.patch @@ -66,7 +66,7 @@ diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/ index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread +@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa private WatchdogThread(long timeoutTime, boolean restart) { @@ -75,7 +75,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.timeoutTime = timeoutTime; this.restart = restart; } -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread +@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa { Logger log = Bukkit.getServer().getLogger(); log.log( Level.SEVERE, "------------------------------" ); @@ -93,12 +93,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // if ( net.minecraft.world.level.Level.lastPhysicsProblem != null ) { -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread +@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa } // log.log( Level.SEVERE, "------------------------------" ); - log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Spigot!):" ); + log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper + io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(isLongTimeout); // Paper // Paper - rewrite chunk system WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log ); log.log( Level.SEVERE, "------------------------------" ); - // diff --git a/patches/server/System-property-for-disabling-watchdoge.patch b/patches/server/System-property-for-disabling-watchdoge.patch index c5213c8c5a..8b145e16e3 100644 --- a/patches/server/System-property-for-disabling-watchdoge.patch +++ b/patches/server/System-property-for-disabling-watchdoge.patch @@ -8,7 +8,7 @@ diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/ index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java -@@ -0,0 +0,0 @@ public class WatchdogThread extends Thread +@@ -0,0 +0,0 @@ public final class WatchdogThread extends io.papermc.paper.util.TickThread // Pa while ( !this.stopping ) { // diff --git a/patches/server/Use-a-Queue-for-Queueing-Commands.patch b/patches/server/Use-a-Queue-for-Queueing-Commands.patch index bb951685c9..c40fb2d526 100644 --- a/patches/server/Use-a-Queue-for-Queueing-Commands.patch +++ b/patches/server/Use-a-Queue-for-Queueing-Commands.patch @@ -19,9 +19,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private QueryThreadGs4 queryThreadGs4; // private final RemoteControlCommandListener rconConsoleSource; // CraftBukkit - remove field @@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - } - - public void handleConsoleInput(String command, CommandSourceStack commandSource) { + return; + } + // Paper end - rewrite chunk system - this.consoleInput.add(new ConsoleInput(command, commandSource)); + this.serverCommandQueue.add(new ConsoleInput(command, commandSource)); // Paper - use proper queue } diff --git a/patches/server/WorldCreator-keepSpawnLoaded.patch b/patches/server/WorldCreator-keepSpawnLoaded.patch index 779f2b3d4d..506033c048 100644 --- a/patches/server/WorldCreator-keepSpawnLoaded.patch +++ b/patches/server/WorldCreator-keepSpawnLoaded.patch @@ -14,5 +14,5 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + internal.keepSpawnInMemory = creator.keepSpawnLoaded().toBooleanOrElse(internal.getWorld().getKeepSpawnInMemory()); // Paper this.getServer().prepareLevels(internal.getChunkSource().chunkMap.progressListener, internal); - internal.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API + //internal.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API // Paper - rewrite chunk system diff --git a/patches/server/implement-optional-per-player-mob-spawns.patch b/patches/server/implement-optional-per-player-mob-spawns.patch index 61809e5b52..ca984c35a5 100644 --- a/patches/server/implement-optional-per-player-mob-spawns.patch +++ b/patches/server/implement-optional-per-player-mob-spawns.patch @@ -261,8 +261,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 private int serverViewDistance; + public final com.destroystokyo.paper.util.misc.PlayerAreaMap playerMobDistanceMap; // Paper - // CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback() - public final CallbackExecutor callbackExecutor = new CallbackExecutor(); + // Paper - rewrite chunk system + @@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX()); int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ()); @@ -275,6 +275,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } void removePlayerFromDistanceMaps(ServerPlayer player) { + this.level.playerChunkLoader.removePlayer(player); // Paper - replace chunk loader + // Paper start - per player mob spawning + if (this.playerMobDistanceMap != null) { @@ -284,9 +285,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 } void updateMaps(ServerPlayer player) { - int chunkX = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getX()); +@@ -0,0 +0,0 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider int chunkZ = io.papermc.paper.util.MCUtil.getChunkCoordinate(player.getZ()); // Note: players need to be explicitly added to distance maps before they can be updated + this.level.playerChunkLoader.updatePlayer(player); // Paper - replace chunk loader + + // Paper start - per player mob spawning + if (this.playerMobDistanceMap != null) { diff --git a/patches/server/incremental-chunk-and-player-saving.patch b/patches/server/incremental-chunk-and-player-saving.patch index f6c1779d91..07ce138b95 100644 --- a/patches/server/incremental-chunk-and-player-saving.patch +++ b/patches/server/incremental-chunk-and-player-saving.patch @@ -112,8 +112,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + // Paper end + public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) { - ServerChunkCache chunkproviderserver = this.getChunkSource(); - + // Paper start - rewrite chunk system - add close param + this.save(progressListener, flush, savingDisabled, false); diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java