diff --git a/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch b/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch index 2ca59ca1c..68119bc33 100644 --- a/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch +++ b/Spigot-Server-Patches/Async-Chunk-Loading-and-Generation.patch @@ -43,7 +43,7 @@ reading or writing to the chunk will be safe, so plugins still should not be touching chunks asynchronously! diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java -index da710cc6fe..6b65364e22 100644 +index 912c990404..2f6d7f2976 100644 --- a/src/main/java/com/destroystokyo/paper/PaperConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java @@ -0,0 +0,0 @@ public class PaperConfig { @@ -51,14 +51,56 @@ index da710cc6fe..6b65364e22 100644 } } + -+ // Temporary opt out, will be removed later + public static boolean asyncChunks = false; -+ private static void disableAsyncChunks() { -+ asyncChunks = config.getBoolean("settings.async-chunks", true); ++ public static boolean asyncChunkGeneration = true; ++ public static boolean asyncChunkGenThreadPerWorld = true; ++ public static int asyncChunkLoadThreads = -1; ++ private static void asyncChunks() { ++ if (version < 15) { ++ boolean enabled = config.getBoolean("settings.async-chunks", true); ++ ConfigurationSection section = config.createSection("settings.async-chunks"); ++ section.set("enable", enabled); ++ section.set("load-threads", -1); ++ section.set("generation", true); ++ section.set("thread-per-world-generation", true); ++ } ++ ++ asyncChunks = getBoolean("settings.async-chunks.enable", true); ++ asyncChunkGeneration = getBoolean("settings.async-chunks.generation", true); ++ asyncChunkGenThreadPerWorld = getBoolean("settings.async-chunks.thread-per-world-generation", true); ++ asyncChunkLoadThreads = getInt("settings.async-chunks.load-threads", -1); ++ if (asyncChunkLoadThreads <= 0) { ++ asyncChunkLoadThreads = (int) Math.min(Integer.getInteger("paper.maxchunkthreads", 8), Runtime.getRuntime().availableProcessors() * 1.5); ++ } ++ ++ // Let Shared Host set some limits ++ String sharedHostEnvGen = System.getenv("PAPER_ASYNC_CHUNKS_SHARED_HOST_GEN"); ++ String sharedHostEnvLoad = System.getenv("PAPER_ASYNC_CHUNKS_SHARED_HOST_LOAD"); ++ if ("1".equals(sharedHostEnvGen)) { ++ log("Async Chunks - Generation: Your host has requested to use a single thread world generation"); ++ asyncChunkGenThreadPerWorld = false; ++ } else if ("2".equals(sharedHostEnvGen)) { ++ log("Async Chunks - Generation: Your host has disabled async world generation - You will experience lag from world generation"); ++ asyncChunkGeneration = false; ++ } ++ ++ if (sharedHostEnvLoad != null) { ++ try { ++ asyncChunkLoadThreads = Math.max(1, Math.min(asyncChunkLoadThreads, Integer.parseInt(sharedHostEnvLoad))); ++ } catch (NumberFormatException ignored) {} ++ } ++ + if (!asyncChunks) { + log("Async Chunks: Disabled - Chunks will be managed synchronosuly, and will cause tremendous lag."); + } else { -+ log("Async Chunks: Enabled - Chunks will be loaded and generated much faster, without lag."); ++ log("Async Chunks: Enabled - Chunks will be loaded much faster, without lag."); ++ if (!asyncChunkGeneration) { ++ log("Async Chunks - Generation: Disabled - Chunks will be generated synchronosuly, and will cause tremendous lag."); ++ } else if (asyncChunkGenThreadPerWorld) { ++ log("Async Chunks - Generation: Enabled - Chunks will be generated much faster, without lag."); ++ } else { ++ log("Async Chunks - Generation: Enabled (Single Thread) - Chunks will be generated much faster, without lag."); ++ } + } + } } @@ -794,7 +836,7 @@ index 98d182fdb8..487d98eb1b 100644 diff --git a/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java b/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java new file mode 100644 -index 0000000000..a3fc989832 +index 0000000000..1c592c7956 --- /dev/null +++ b/src/main/java/net/minecraft/server/PaperAsyncChunkProvider.java @@ -0,0 +0,0 @@ @@ -846,8 +888,8 @@ index 0000000000..a3fc989832 +public class PaperAsyncChunkProvider extends ChunkProviderServer { + + private static final PriorityQueuedExecutor.RejectionHandler IGNORE_HANDLER = (run, executor) -> {}; -+ private static final int CHUNK_THREADS = (int) Math.min(Integer.getInteger("paper.maxchunkthreads", 8), Runtime.getRuntime().availableProcessors() * 1.5); -+ private static final PriorityQueuedExecutor EXECUTOR = new PriorityQueuedExecutor("PaperChunkLoader", PaperConfig.asyncChunks ? CHUNK_THREADS : 0, IGNORE_HANDLER); ++ private static final PriorityQueuedExecutor EXECUTOR = new PriorityQueuedExecutor("PaperChunkLoader", PaperConfig.asyncChunks ? PaperConfig.asyncChunkLoadThreads : 0, IGNORE_HANDLER); ++ private static final PriorityQueuedExecutor SINGLE_GEN_EXECUTOR = new PriorityQueuedExecutor("PaperChunkGenerator", PaperConfig.asyncChunks && PaperConfig.asyncChunkGeneration && !PaperConfig.asyncChunkGenThreadPerWorld ? 1 : 0, IGNORE_HANDLER); + + private final PriorityQueuedExecutor generationExecutor; + //private static final PriorityQueuedExecutor generationExecutor = new PriorityQueuedExecutor("PaperChunkGen", 1); @@ -868,8 +910,8 @@ index 0000000000..a3fc989832 + this.asyncHandler = server; + this.chunkLoader = chunkLoader; + String worldName = this.world.getWorld().getName(); -+ this.shouldGenSync = generator instanceof CustomChunkGenerator && !(((CustomChunkGenerator) generator).asyncSupported); -+ this.generationExecutor = new PriorityQueuedExecutor("PaperChunkGen-" + worldName, shouldGenSync ? 0 : 1, IGNORE_HANDLER); ++ this.shouldGenSync = generator instanceof CustomChunkGenerator && !(((CustomChunkGenerator) generator).asyncSupported) || !PaperConfig.asyncChunkGeneration; ++ this.generationExecutor = PaperConfig.asyncChunkGenThreadPerWorld ? new PriorityQueuedExecutor("PaperChunkGen-" + worldName, shouldGenSync ? 0 : 1, IGNORE_HANDLER) : SINGLE_GEN_EXECUTOR; + } + + static void processChunkLoads(MinecraftServer server) { @@ -1176,13 +1218,12 @@ index 0000000000..a3fc989832 + this.chunk = chunk; + this.hasFinished = true; + } -+ if (Bukkit.isPrimaryThread()) { -+ postChunk(); -+ } else { -+ synchronized (mainThreadQueue) { -+ mainThreadQueue.add(this::postChunk); -+ mainThreadQueue.notify(); -+ } ++ ++ // Don't post here, even if on main, it must enter the queue so we can exit any open batch ++ // schedulers, as post stage may trigger a new generation and cause errors ++ synchronized (mainThreadQueue) { ++ mainThreadQueue.add(this::postChunk); ++ mainThreadQueue.notify(); + } + } + @@ -1410,7 +1451,7 @@ index 3c35c0f481..187ca2813a 100644 this.m = world.getChunkProvider().getChunkGenerator().getSettings(); this.i = world.getSeaLevel(); diff --git a/src/main/java/net/minecraft/server/SchedulerBatch.java b/src/main/java/net/minecraft/server/SchedulerBatch.java -index d868149d1a..0d94b262ac 100644 +index d868149d1a..0d45d933ee 100644 --- a/src/main/java/net/minecraft/server/SchedulerBatch.java +++ b/src/main/java/net/minecraft/server/SchedulerBatch.java @@ -0,0 +0,0 @@ public class SchedulerBatch, R> { @@ -1427,10 +1468,12 @@ index d868149d1a..0d94b262ac 100644 + public void startBatch() { b(); } // Paper - OBFHELPER public void b() { +- if (this.c) { + lock.lock(); // Paper - if (this.c) { ++ if (false && this.c) { // Paper throw new RuntimeException("Batch already started."); } else { + this.d = 1000; @@ -0,0 +0,0 @@ public class SchedulerBatch, R> { } } @@ -1445,14 +1488,16 @@ index d868149d1a..0d94b262ac 100644 + public CompletableFuture executeBatch() { return c(); } // Paper - OBFHELPER public CompletableFuture c() { +- if (!this.c) { + // Paper start + if (!lock.isHeldByCurrentThread()) { + throw new IllegalStateException("Current thread does not hold the write lock"); + } + try {// Paper end - if (!this.c) { ++ if (false && !this.c) { // Paper throw new RuntimeException("Batch not properly started. Please use startBatch to create a new batch."); } else { + if (this.d != 1000) { @@ -0,0 +0,0 @@ public class SchedulerBatch, R> { this.c = false; return this.b.c(); diff --git a/Spigot-Server-Patches/Paper-config-files.patch b/Spigot-Server-Patches/Paper-config-files.patch index f4a4d33e8..6f93017b9 100644 --- a/Spigot-Server-Patches/Paper-config-files.patch +++ b/Spigot-Server-Patches/Paper-config-files.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Paper config files diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java new file mode 100644 -index 000000000..961966e16 +index 0000000000..961966e169 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java @@ -0,0 +0,0 @@ @@ -249,7 +249,7 @@ index 000000000..961966e16 +} diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java new file mode 100644 -index 000000000..104abab84 +index 0000000000..92e44befe0 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java @@ -0,0 +0,0 @@ @@ -313,7 +313,7 @@ index 000000000..104abab84 + commands.put("paper", new PaperCommand("paper")); + + version = getInt("config-version", 14); -+ set("config-version", 14); ++ set("config-version", 15); + readConfig(PaperConfig.class, null); + } + @@ -432,7 +432,7 @@ index 000000000..104abab84 +} diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java new file mode 100644 -index 000000000..a73865739 +index 0000000000..a738657394 --- /dev/null +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -0,0 +0,0 @@ @@ -504,7 +504,7 @@ index 000000000..a73865739 + } +} diff --git a/src/main/java/net/minecraft/server/DedicatedServer.java b/src/main/java/net/minecraft/server/DedicatedServer.java -index 8b3988fc0..d8535fdd9 100644 +index 8b3988fc0a..d8535fdd9e 100644 --- a/src/main/java/net/minecraft/server/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/DedicatedServer.java @@ -0,0 +0,0 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer @@ -519,7 +519,7 @@ index 8b3988fc0..d8535fdd9 100644 DedicatedServer.LOGGER.info("Generating keypair"); this.a(MinecraftEncryption.b()); diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java -index 709b28d78..4ba748ae2 100644 +index 3c7537d013..ffaa425ec8 100644 --- a/src/main/java/net/minecraft/server/Entity.java +++ b/src/main/java/net/minecraft/server/Entity.java @@ -0,0 +0,0 @@ public abstract class Entity implements INamableTileEntity, ICommandListener { @@ -536,7 +536,7 @@ index 709b28d78..4ba748ae2 100644 public boolean impulse; public int portalCooldown; diff --git a/src/main/java/net/minecraft/server/EntityTypes.java b/src/main/java/net/minecraft/server/EntityTypes.java -index c6434ec37..17bfa356f 100644 +index c6434ec371..17bfa356f1 100644 --- a/src/main/java/net/minecraft/server/EntityTypes.java +++ b/src/main/java/net/minecraft/server/EntityTypes.java @@ -0,0 +0,0 @@ package net.minecraft.server; @@ -560,7 +560,7 @@ index c6434ec37..17bfa356f 100644 + // Paper end } diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index ed77641e4..f381e23be 100644 +index ed77641e46..f381e23beb 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -0,0 +0,0 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc @@ -581,7 +581,7 @@ index ed77641e4..f381e23be 100644 this.world = new CraftWorld((WorldServer) this, gen, env); this.ticksPerAnimalSpawns = this.getServer().getTicksPerAnimalSpawns(); // CraftBukkit diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index e28ce05fb..e659f3f33 100644 +index e28ce05fb9..e659f3f339 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -0,0 +0,0 @@ public final class CraftServer implements Server { @@ -636,7 +636,7 @@ index e28ce05fb..e659f3f33 100644 + // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java -index 4a998593b..e354245f7 100644 +index 4a998593bd..e354245f73 100644 --- a/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java @@ -0,0 +0,0 @@ public class Main { @@ -655,7 +655,7 @@ index 4a998593b..e354245f7 100644 }; diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java -index 95f7a9587..87bc8e2d9 100644 +index 95f7a9587a..87bc8e2d9c 100644 --- a/src/main/java/org/spigotmc/SpigotWorldConfig.java +++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java @@ -0,0 +0,0 @@ public class SpigotWorldConfig