diff --git a/shreddedpaper-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftWorld.java.patch b/shreddedpaper-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftWorld.java.patch index 0557dd4..9005680 100644 --- a/shreddedpaper-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftWorld.java.patch +++ b/shreddedpaper-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftWorld.java.patch @@ -23,6 +23,14 @@ import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; +@@ -182,6 +_,7 @@ + private final BlockMetadataStore blockMetadata = new BlockMetadataStore(this); + private final Object2IntOpenHashMap spawnCategoryLimit = new Object2IntOpenHashMap<>(); + private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftWorld.DATA_TYPE_REGISTRY); ++ private static final ThreadLocal isInsideIsChunkGenerated = ThreadLocal.withInitial(() -> Boolean.FALSE); // ShreddedPaper - track recursive isChunkGenerated calls + // Paper start - void damage configuration + private boolean voidDamageEnabled; + private float voidDamageAmount; @@ -240,7 +_,7 @@ @Override @@ -40,7 +48,7 @@ warnUnsafeChunk("getting a faraway chunk", x, z); // Paper net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) this.world.getChunk(x, z, ChunkStatus.FULL, true); return new CraftChunk(chunk); -@@ -413,10 +_,12 @@ +@@ -413,26 +_,37 @@ @Override public boolean isChunkGenerated(int x, int z) { // Paper start - Fix this method @@ -51,11 +59,47 @@ return CraftWorld.this.isChunkGenerated(x, z); - }, world.getChunkSource().mainThreadProcessor).join(); + }, world.getChunkSource().tickingRegions.executorFor(RegionPos.forChunk(x, z))); // ShreddedPaper - regions -+ if (TickThread.isTickThread()) this.getHandle().getChunkSource().mainThreadProcessor.managedBlock(future::isDone); // ShreddedPaper - run tick thread tasks (this might be one tick thread accessing a chunk in another tick thread) -+ return future.join(); // ShreddedPaper - regions ++ return future.join(); // ShreddedPaper - don't use managedBlock to avoid deadlocks in multi-threaded context } ChunkAccess chunk = world.getChunkSource().getChunkAtImmediately(x, z); if (chunk != null) { + return chunk instanceof ImposterProtoChunk || chunk instanceof net.minecraft.world.level.chunk.LevelChunk; + } +- final java.util.concurrent.CompletableFuture future = new java.util.concurrent.CompletableFuture<>(); +- ca.spottedleaf.moonrise.common.PlatformHooks.get().scheduleChunkLoad( +- this.world, x, z, false, ChunkStatus.EMPTY, true, ca.spottedleaf.concurrentutil.util.Priority.NORMAL, future::complete +- ); +- world.getChunkSource().mainThreadProcessor.managedBlock(future::isDone); +- return future.thenApply(c -> { +- if (c != null) { +- return c.getPersistedStatus() == ChunkStatus.FULL; +- } +- return false; +- }).join(); ++ // ShreddedPaper start - avoid recursive deadlock by returning false for recursive calls when chunk not in memory ++ if (isInsideIsChunkGenerated.get()) { ++ return false; // Conservative answer: assume not generated if we can't check without blocking ++ } ++ isInsideIsChunkGenerated.set(Boolean.TRUE); ++ try { ++ // ShreddedPaper end ++ final java.util.concurrent.CompletableFuture future = new java.util.concurrent.CompletableFuture<>(); ++ ca.spottedleaf.moonrise.common.PlatformHooks.get().scheduleChunkLoad( ++ this.world, x, z, false, ChunkStatus.EMPTY, true, ca.spottedleaf.concurrentutil.util.Priority.NORMAL, future::complete ++ ); ++ world.getChunkSource().mainThreadProcessor.managedBlock(future::isDone); ++ return future.thenApply(c -> { ++ if (c != null) { ++ return c.getPersistedStatus() == ChunkStatus.FULL; ++ } ++ return false; ++ }).join(); ++ } finally { ++ isInsideIsChunkGenerated.set(Boolean.FALSE); ++ } + // Paper end - Fix this method + } + @@ -751,13 +_,15 @@ @Override