diff --git a/patches/unapplied/server/0991-Rewrite-chunk-system.patch b/patches/server/0972-Rewrite-chunk-system.patch similarity index 94% rename from patches/unapplied/server/0991-Rewrite-chunk-system.patch rename to patches/server/0972-Rewrite-chunk-system.patch index 541f2b8723..6ad2b98718 100644 --- a/patches/unapplied/server/0991-Rewrite-chunk-system.patch +++ b/patches/server/0972-Rewrite-chunk-system.patch @@ -779,7 +779,7 @@ index 0000000000000000000000000000000000000000..64b5803d002b2968841a5ddee987f98b + } +} diff --git a/src/main/java/ca/spottedleaf/starlight/common/light/StarLightInterface.java b/src/main/java/ca/spottedleaf/starlight/common/light/StarLightInterface.java -index 499c069d64692872924963d3a7ac39664b20468d..ef8ea36b2acefb935afda01396d2699e2921f396 100644 +index e0338db4d6fa359029ed5edeacc3646aa98701f5..c03dbb4a74d00d794be4139f0f7c4b5ff1b01d38 100644 --- a/src/main/java/ca/spottedleaf/starlight/common/light/StarLightInterface.java +++ b/src/main/java/ca/spottedleaf/starlight/common/light/StarLightInterface.java @@ -41,14 +41,14 @@ public final class StarLightInterface { @@ -962,7 +962,7 @@ index 2f0d9b953802dee821cfde82d22b0567cce8ee91..22687667ec69a954261e55e59261286a public static Timing getTickList(ServerLevel worldserver, String timingsType) { diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java -index 05bddc0697faa8d9d9955d89d76930c84ef7df0d..cbeaadaecf816070b3a37938c8e683180939afc4 100644 +index cff2f04409fab9abca87ceec85a551e1d59f9e7d..b1400f8bb661b13834c4176f94433435500113ba 100644 --- a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java @@ -32,192 +32,41 @@ public final class ChunkSystem { @@ -1229,10 +1229,10 @@ index 05bddc0697faa8d9d9955d89d76930c84ef7df0d..cbeaadaecf816070b3a37938c8e68318 private ChunkSystem() { diff --git a/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java new file mode 100644 -index 0000000000000000000000000000000000000000..1b090f1e79b996e52097afc49c1cec85936653e6 +index 0000000000000000000000000000000000000000..ee58c67cb2bd78159cce19ec75f13dc6168a0e7a --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/RegionizedPlayerChunkLoader.java -@@ -0,0 +1,1208 @@ +@@ -0,0 +1,1375 @@ +package io.papermc.paper.chunk.system; + +import ca.spottedleaf.concurrentutil.collection.SRSWLinkedQueue; @@ -1244,10 +1244,11 @@ index 0000000000000000000000000000000000000000..1b090f1e79b996e52097afc49c1cec85 +import io.papermc.paper.util.TickThread; +import io.papermc.paper.util.player.SingleUserAreaMap; +import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -+import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; +import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.longs.LongComparator; +import it.unimi.dsi.fastutil.longs.LongHeapPriorityQueue; ++import it.unimi.dsi.fastutil.longs.LongIterator; ++import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundSetChunkCacheCenterPacket; @@ -1261,18 +1262,97 @@ index 0000000000000000000000000000000000000000..1b090f1e79b996e52097afc49c1cec85 +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.levelgen.BelowZeroRetrogen; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import java.lang.invoke.VarHandle; +import java.util.ArrayDeque; ++import java.util.Arrays; ++import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +public class RegionizedPlayerChunkLoader { + ++ // expected that this list returns for a given radius, the set of chunks ordered ++ // by manhattan distance ++ private static final long[][] SEARCH_RADIUS_ITERATION_LIST = new long[64+2+1][]; ++ static { ++ for (int i = 0; i < SEARCH_RADIUS_ITERATION_LIST.length; ++i) { ++ // a BFS around -x, -z, +x, +z will give increasing manhatten distance ++ SEARCH_RADIUS_ITERATION_LIST[i] = generateBFSOrder(i); ++ } ++ } ++ ++ private static void expandQuadrants(final CustomLongArray input, final int size) { ++ final int len = input.size(); ++ final long[] array = input.elements(); ++ ++ int writeIndex = size - 1; ++ for (int i = len - 1; i >= 0; --i) { ++ final long key = array[i]; ++ final int chunkX = CoordinateUtils.getChunkX(key); ++ final int chunkZ = CoordinateUtils.getChunkZ(key); ++ ++ if ((chunkX | chunkZ) < 0 || (i != 0 && chunkX == 0 && chunkZ == 0)) { ++ throw new IllegalStateException(); ++ } ++ ++ // Q4 ++ if (chunkZ != 0) { ++ array[writeIndex--] = CoordinateUtils.getChunkKey(chunkX, -chunkZ); ++ } ++ // Q3 ++ if (chunkX != 0 && chunkZ != 0) { ++ array[writeIndex--] = CoordinateUtils.getChunkKey(-chunkX, -chunkZ); ++ } ++ // Q2 ++ if (chunkX != 0) { ++ array[writeIndex--] = CoordinateUtils.getChunkKey(-chunkX, chunkZ); ++ } ++ ++ array[writeIndex--] = key; ++ } ++ ++ input.forceSize(size); ++ ++ if (writeIndex != -1) { ++ throw new IllegalStateException(); ++ } ++ } ++ ++ private static long[] generateBFSOrder(final int radius) { ++ // by using only the first quadrant, we can reduce the total element size by 4 when spreading ++ final CustomLongArray[] byDistance = makeQ1BFS(radius); ++ ++ // to increase generation parallelism, we want to space the chunks out so that they are not nearby when generating ++ // this also means we are minimising locality ++ // but, we need to maintain sorted order by manhatten distance ++ ++ // per manhatten distance we transform the chunk list so that each element is maximally spaced out from each other ++ for (int i = 0, len = byDistance.length; i < len; ++i) { ++ final CustomLongArray points = byDistance[i]; ++ final int expectedSize = getDistanceSize(i, radius); ++ ++ final CustomLongArray spread = spread(points, expectedSize); ++ // add in Q2, Q3, Q4 ++ expandQuadrants(spread, expectedSize); ++ ++ byDistance[i] = spread; ++ } ++ ++ // now, rebuild the list so that it still maintains manhatten distance order ++ final CustomLongArray ret = new CustomLongArray((2 * radius + 1) * (2 * radius + 1)); ++ ++ for (final CustomLongArray dist : byDistance) { ++ ret.addAll(dist); ++ } ++ ++ return ret.elements(); ++ } ++ + public static final TicketType REGION_PLAYER_TICKET = TicketType.create("region_player_ticket", Long::compareTo); + + public static final int MIN_VIEW_DISTANCE = 2; @@ -1479,151 +1559,12 @@ index 0000000000000000000000000000000000000000..1b090f1e79b996e52097afc49c1cec85 + } + } + -+ private static long[] generateBFSOrder(final int radius) { -+ final LongArrayList chunks = new LongArrayList(); -+ final LongArrayFIFOQueue queue = new LongArrayFIFOQueue(); -+ final LongOpenHashSet seen = new LongOpenHashSet(); -+ -+ seen.add(CoordinateUtils.getChunkKey(0, 0)); -+ queue.enqueue(CoordinateUtils.getChunkKey(0, 0)); -+ while (!queue.isEmpty()) { -+ final long chunk = queue.dequeueLong(); -+ final int chunkX = CoordinateUtils.getChunkX(chunk); -+ final int chunkZ = CoordinateUtils.getChunkZ(chunk); -+ -+ // important that the addition to the list is here, rather than when enqueueing neighbours -+ // ensures the order is actually kept -+ chunks.add(chunk); -+ -+ // -x -+ final long n1 = CoordinateUtils.getChunkKey(chunkX - 1, chunkZ); -+ // -z -+ final long n2 = CoordinateUtils.getChunkKey(chunkX, chunkZ - 1); -+ // +x -+ final long n3 = CoordinateUtils.getChunkKey(chunkX + 1, chunkZ); -+ // +z -+ final long n4 = CoordinateUtils.getChunkKey(chunkX, chunkZ + 1); -+ -+ final long[] list = new long[] {n1, n2, n3, n4}; -+ -+ for (final long neighbour : list) { -+ final int neighbourX = CoordinateUtils.getChunkX(neighbour); -+ final int neighbourZ = CoordinateUtils.getChunkZ(neighbour); -+ if (Math.max(Math.abs(neighbourX), Math.abs(neighbourZ)) > radius) { -+ // don't enqueue out of range -+ continue; -+ } -+ if (!seen.add(neighbour)) { -+ continue; -+ } -+ queue.enqueue(neighbour); -+ } -+ } -+ -+ // to increase generation parallelism, we want to space the chunks out so that they are not nearby when generating -+ // this also means we are minimising locality -+ // but, we need to maintain sorted order by manhatten distance -+ -+ // first, build a map of manhatten distance -> chunks -+ final java.util.List byDistance = new java.util.ArrayList<>(); -+ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator = chunks.iterator(); iterator.hasNext();) { -+ final long chunkKey = iterator.nextLong(); -+ -+ final int chunkX = CoordinateUtils.getChunkX(chunkKey); -+ final int chunkZ = CoordinateUtils.getChunkZ(chunkKey); -+ -+ final int dist = Math.abs(chunkX) + Math.abs(chunkZ); -+ if (dist == byDistance.size()) { -+ final LongArrayList list = new LongArrayList(); -+ list.add(chunkKey); -+ byDistance.add(list); -+ continue; -+ } -+ -+ byDistance.get(dist).add(chunkKey); -+ } -+ -+ // per distance we transform the chunk list so that each element is maximally spaced out from each other -+ for (int i = 0, len = byDistance.size(); i < len; ++i) { -+ final LongArrayList notAdded = byDistance.get(i).clone(); -+ final LongArrayList added = new LongArrayList(); -+ -+ while (!notAdded.isEmpty()) { -+ if (added.isEmpty()) { -+ added.add(notAdded.removeLong(notAdded.size() - 1)); -+ continue; -+ } -+ -+ long maxChunk = -1L; -+ int maxDist = 0; -+ -+ // select the chunk from the not yet added set that has the largest minimum distance from -+ // the current set of added chunks -+ -+ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator = notAdded.iterator(); iterator.hasNext();) { -+ final long chunkKey = iterator.nextLong(); -+ final int chunkX = CoordinateUtils.getChunkX(chunkKey); -+ final int chunkZ = CoordinateUtils.getChunkZ(chunkKey); -+ -+ int minDist = Integer.MAX_VALUE; -+ -+ for (final it.unimi.dsi.fastutil.longs.LongIterator iterator2 = added.iterator(); iterator2.hasNext();) { -+ final long addedKey = iterator2.nextLong(); -+ final int addedX = CoordinateUtils.getChunkX(addedKey); -+ final int addedZ = CoordinateUtils.getChunkZ(addedKey); -+ -+ // here we use square distance because chunk generation uses neighbours in a square radius -+ final int dist = Math.max(Math.abs(addedX - chunkX), Math.abs(addedZ - chunkZ)); -+ -+ if (dist < minDist) { -+ minDist = dist; -+ } -+ } -+ -+ if (minDist > maxDist) { -+ maxDist = minDist; -+ maxChunk = chunkKey; -+ } -+ } -+ -+ // move the selected chunk from the not added set to the added set -+ -+ if (!notAdded.rem(maxChunk)) { -+ throw new IllegalStateException(); -+ } -+ -+ added.add(maxChunk); -+ } -+ -+ byDistance.set(i, added); -+ } -+ -+ // now, rebuild the list so that it still maintains manhatten distance order -+ final LongArrayList ret = new LongArrayList(chunks.size()); -+ -+ for (final LongArrayList dist : byDistance) { -+ ret.addAll(dist); -+ } -+ -+ return ret.toLongArray(); -+ } -+ + public static final class PlayerChunkLoaderData { + + private static final AtomicLong ID_GENERATOR = new AtomicLong(); + private final long id = ID_GENERATOR.incrementAndGet(); + private final Long idBoxed = Long.valueOf(this.id); + -+ // expected that this list returns for a given radius, the set of chunks ordered -+ // by manhattan distance -+ private static final long[][] SEARCH_RADIUS_ITERATION_LIST = new long[65][]; -+ static { -+ for (int i = 0; i < SEARCH_RADIUS_ITERATION_LIST.length; ++i) { -+ // a BFS around -x, -z, +x, +z will give increasing manhatten distance -+ SEARCH_RADIUS_ITERATION_LIST[i] = generateBFSOrder(i); -+ } -+ } -+ + private static final long MAX_RATE = 10_000L; + + private final ServerPlayer player; @@ -2440,6 +2381,232 @@ index 0000000000000000000000000000000000000000..1b090f1e79b996e52097afc49c1cec85 + return added - removed; + } + } ++ ++ private static class CustomLongArray extends LongArrayList { ++ ++ public CustomLongArray() { ++ super(); ++ } ++ ++ public CustomLongArray(final int expected) { ++ super(expected); ++ } ++ ++ public boolean addAll(final CustomLongArray list) { ++ this.addElements(this.size, list.a, 0, list.size); ++ return list.size != 0; ++ } ++ ++ public void addUnchecked(final long value) { ++ this.a[this.size++] = value; ++ } ++ ++ public void forceSize(final int to) { ++ this.size = to; ++ } ++ ++ @Override ++ public int hashCode() { ++ long h = 1L; ++ ++ Objects.checkFromToIndex(0, this.size, this.a.length); ++ ++ for (int i = 0; i < this.size; ++i) { ++ h = it.unimi.dsi.fastutil.HashCommon.mix(h + this.a[i]); ++ } ++ ++ return (int)h; ++ } ++ ++ @Override ++ public boolean equals(final Object o) { ++ if (o == this) { ++ return true; ++ } ++ ++ if (!(o instanceof CustomLongArray other)) { ++ return false; ++ } ++ ++ return this.size == other.size && Arrays.equals(this.a, 0, this.size, other.a, 0, this.size); ++ } ++ } ++ ++ private static int getDistanceSize(final int radius, final int max) { ++ if (radius == 0) { ++ return 1; ++ } ++ final int diff = radius - max; ++ if (diff <= 0) { ++ return 4*radius; ++ } ++ return 4*(max - Math.max(0, diff - 1)); ++ } ++ ++ private static int getQ1DistanceSize(final int radius, final int max) { ++ if (radius == 0) { ++ return 1; ++ } ++ final int diff = radius - max; ++ if (diff <= 0) { ++ return radius+1; ++ } ++ return max - diff + 1; ++ } ++ ++ private static final class BasicFIFOLQueue { ++ ++ private final long[] values; ++ private int head, tail; ++ ++ public BasicFIFOLQueue(final int cap) { ++ if (cap <= 1) { ++ throw new IllegalArgumentException(); ++ } ++ this.values = new long[cap]; ++ } ++ ++ public boolean isEmpty() { ++ return this.head == this.tail; ++ } ++ ++ public long removeFirst() { ++ final long ret = this.values[this.head]; ++ ++ if (this.head == this.tail) { ++ throw new IllegalStateException(); ++ } ++ ++ ++this.head; ++ if (this.head == this.values.length) { ++ this.head = 0; ++ } ++ ++ return ret; ++ } ++ ++ public void addLast(final long value) { ++ this.values[this.tail++] = value; ++ ++ if (this.tail == this.head) { ++ throw new IllegalStateException(); ++ } ++ ++ if (this.tail == this.values.length) { ++ this.tail = 0; ++ } ++ } ++ } ++ ++ private static CustomLongArray[] makeQ1BFS(final int radius) { ++ final CustomLongArray[] ret = new CustomLongArray[2 * radius + 1]; ++ final BasicFIFOLQueue queue = new BasicFIFOLQueue(Math.max(1, 4 * radius) + 1); ++ final LongOpenHashSet seen = new LongOpenHashSet((radius + 1) * (radius + 1)); ++ ++ seen.add(CoordinateUtils.getChunkKey(0, 0)); ++ queue.addLast(CoordinateUtils.getChunkKey(0, 0)); ++ while (!queue.isEmpty()) { ++ final long chunk = queue.removeFirst(); ++ final int chunkX = CoordinateUtils.getChunkX(chunk); ++ final int chunkZ = CoordinateUtils.getChunkZ(chunk); ++ ++ final int index = Math.abs(chunkX) + Math.abs(chunkZ); ++ final CustomLongArray list = ret[index]; ++ if (list != null) { ++ list.addUnchecked(chunk); ++ } else { ++ (ret[index] = new CustomLongArray(getQ1DistanceSize(index, radius))).addUnchecked(chunk); ++ } ++ ++ for (int i = 0; i < 4; ++i) { ++ // 0 -> -1, 0 ++ // 1 -> 0, -1 ++ // 2 -> 1, 0 ++ // 3 -> 0, 1 ++ ++ final int signInv = -(i >>> 1); // 2/3 -> -(1), 0/1 -> -(0) ++ // note: -n = (~n) + 1 ++ // (n ^ signInv) - signInv = signInv == 0 ? ((n ^ 0) - 0 = n) : ((n ^ -1) - (-1) = ~n + 1) ++ ++ final int axis = i & 1; // 0/2 -> 0, 1/3 -> 1 ++ final int dx = ((axis - 1) ^ signInv) - signInv; // 0 -> -1, 1 -> 0 ++ final int dz = (-axis ^ signInv) - signInv; // 0 -> 0, 1 -> -1 ++ ++ final int neighbourX = chunkX + dx; ++ final int neighbourZ = chunkZ + dz; ++ final long neighbour = CoordinateUtils.getChunkKey(neighbourX, neighbourZ); ++ ++ if ((neighbourX | neighbourZ) < 0 || Math.max(Math.abs(neighbourX), Math.abs(neighbourZ)) > radius) { ++ // don't enqueue out of range ++ continue; ++ } ++ ++ if (!seen.add(neighbour)) { ++ continue; ++ } ++ ++ queue.addLast(neighbour); ++ } ++ } ++ ++ return ret; ++ } ++ ++ // doesn't appear worth optimising this function now, even though it's 70% of the call ++ private static CustomLongArray spread(final CustomLongArray input, final int size) { ++ final LongLinkedOpenHashSet notAdded = new LongLinkedOpenHashSet(input); ++ final CustomLongArray added = new CustomLongArray(size); ++ ++ while (!notAdded.isEmpty()) { ++ if (added.isEmpty()) { ++ added.addUnchecked(notAdded.removeLastLong()); ++ continue; ++ } ++ ++ long maxChunk = -1L; ++ int maxDist = 0; ++ ++ // select the chunk from the not yet added set that has the largest minimum distance from ++ // the current set of added chunks ++ ++ for (final LongIterator iterator = notAdded.iterator(); iterator.hasNext();) { ++ final long chunkKey = iterator.nextLong(); ++ final int chunkX = CoordinateUtils.getChunkX(chunkKey); ++ final int chunkZ = CoordinateUtils.getChunkZ(chunkKey); ++ ++ int minDist = Integer.MAX_VALUE; ++ ++ final int len = added.size(); ++ final long[] addedArr = added.elements(); ++ Objects.checkFromToIndex(0, len, addedArr.length); ++ for (int i = 0; i < len; ++i) { ++ final long addedKey = addedArr[i]; ++ final int addedX = CoordinateUtils.getChunkX(addedKey); ++ final int addedZ = CoordinateUtils.getChunkZ(addedKey); ++ ++ // here we use square distance because chunk generation uses neighbours in a square radius ++ final int dist = Math.max(Math.abs(addedX - chunkX), Math.abs(addedZ - chunkZ)); ++ ++ minDist = Math.min(dist, minDist); ++ } ++ ++ if (minDist > maxDist) { ++ maxDist = minDist; ++ maxChunk = chunkKey; ++ } ++ } ++ ++ // move the selected chunk from the not added set to the added set ++ ++ if (!notAdded.remove(maxChunk)) { ++ throw new IllegalStateException(); ++ } ++ ++ added.addUnchecked(maxChunk); ++ } ++ ++ return added; ++ } +} diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java new file mode 100644 @@ -4700,7 +4867,7 @@ index 0000000000000000000000000000000000000000..2934f0cf0ef09c84739312b00186c2ef +} diff --git a/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java b/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java new file mode 100644 -index 0000000000000000000000000000000000000000..de28d6ee71990da74d9deb360fac8bde5adbc918 +index 0000000000000000000000000000000000000000..69e9944358951bd69ff5e8b3482da1a5e4476209 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/light/LightQueue.java @@ -0,0 +1,283 @@ @@ -4718,7 +4885,7 @@ index 0000000000000000000000000000000000000000..de28d6ee71990da74d9deb360fac8bde +import net.minecraft.core.SectionPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; -+import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.status.ChunkStatus; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; @@ -5208,10 +5375,10 @@ index 0000000000000000000000000000000000000000..d72041aa814ff179e6e29a45dcd359a9 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java new file mode 100644 -index 0000000000000000000000000000000000000000..679ed4d53269e1113035b462cf74ab16a231e22e +index 0000000000000000000000000000000000000000..c307b084f59f7bb94dc02f25bbcd3e01e01d2306 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkFullTask.java -@@ -0,0 +1,135 @@ +@@ -0,0 +1,131 @@ +package io.papermc.paper.chunk.system.scheduling; + +import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; @@ -5221,7 +5388,7 @@ index 0000000000000000000000000000000000000000..679ed4d53269e1113035b462cf74ab16 +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.ImposterProtoChunk; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.ProtoChunk; @@ -5286,10 +5453,6 @@ index 0000000000000000000000000000000000000000..679ed4d53269e1113035b462cf74ab16 + chunk.registerTickContainerInLevel(this.world); + } catch (final Throwable throwable) { + this.complete(null, throwable); -+ -+ if (throwable instanceof ThreadDeath) { -+ throw (ThreadDeath)throwable; -+ } + return; + } + this.complete(chunk, null); @@ -6855,7 +7018,7 @@ index 0000000000000000000000000000000000000000..5b446e6ac151f99f64f0c442d0b40b5e +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLightTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLightTask.java new file mode 100644 -index 0000000000000000000000000000000000000000..53ddd7e9ac05e6a9eb809f329796e6d4f6bb2ab1 +index 0000000000000000000000000000000000000000..86e618586d2ad9d843ad761b7336bb3073ed4c23 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLightTask.java @@ -0,0 +1,181 @@ @@ -6868,7 +7031,7 @@ index 0000000000000000000000000000000000000000..53ddd7e9ac05e6a9eb809f329796e6d4 +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.ProtoChunk; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; @@ -7042,7 +7205,7 @@ index 0000000000000000000000000000000000000000..53ddd7e9ac05e6a9eb809f329796e6d4 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java new file mode 100644 -index 0000000000000000000000000000000000000000..f0b03a05387e38ca6933b1ea6fe59b537d5535b9 +index 0000000000000000000000000000000000000000..5ff994d5af24b0bdd7b3a16e245b2c4100bef3f0 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkLoadTask.java @@ -0,0 +1,484 @@ @@ -7064,7 +7227,7 @@ index 0000000000000000000000000000000000000000..f0b03a05387e38ca6933b1ea6fe59b53 +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.storage.ChunkSerializer; @@ -7532,7 +7695,7 @@ index 0000000000000000000000000000000000000000..f0b03a05387e38ca6933b1ea6fe59b53 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkProgressionTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkProgressionTask.java new file mode 100644 -index 0000000000000000000000000000000000000000..322675a470eacbf0e5452f4009c643f2d0b4ce24 +index 0000000000000000000000000000000000000000..b2341328bb22f08836ef18785dc27393a36ce8d6 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkProgressionTask.java @@ -0,0 +1,105 @@ @@ -7543,7 +7706,7 @@ index 0000000000000000000000000000000000000000..322675a470eacbf0e5452f4009c643f2 +import ca.spottedleaf.concurrentutil.util.ConcurrentUtil; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.status.ChunkStatus; +import java.lang.invoke.VarHandle; +import java.util.Map; +import java.util.function.BiConsumer; @@ -7809,7 +7972,7 @@ index 0000000000000000000000000000000000000000..4cc1b3ba6d093a9683dbd8b7fe76106a +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java new file mode 100644 -index 0000000000000000000000000000000000000000..17ce14f2dcbf900890efbc2351782bc6f8867068 +index 0000000000000000000000000000000000000000..049e20407033073b06fcdeb46c38485f4926d778 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkTaskScheduler.java @@ -0,0 +1,883 @@ @@ -7838,7 +8001,7 @@ index 0000000000000000000000000000000000000000..17ce14f2dcbf900890efbc2351782bc6 +import net.minecraft.server.level.TicketType; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.Bukkit; +import org.slf4j.Logger; @@ -8698,7 +8861,7 @@ index 0000000000000000000000000000000000000000..17ce14f2dcbf900890efbc2351782bc6 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java new file mode 100644 -index 0000000000000000000000000000000000000000..e929d55fdb6fad6587af058dff6cadb6bc2a156b +index 0000000000000000000000000000000000000000..5024aafbe607b1fa884fcab42fc05da30a54e185 --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/ChunkUpgradeGenericStatusTask.java @@ -0,0 +1,212 @@ @@ -8713,7 +8876,7 @@ index 0000000000000000000000000000000000000000..e929d55fdb6fad6587af058dff6cadb6 +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.ProtoChunk; +import org.slf4j.Logger; +import java.lang.invoke.VarHandle; @@ -9668,7 +9831,7 @@ index 0000000000000000000000000000000000000000..396d72c00e47cf1669ae20dc839c1c96 +} diff --git a/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java new file mode 100644 -index 0000000000000000000000000000000000000000..b66a7d4aab887309579154815a0d4abf9de506b0 +index 0000000000000000000000000000000000000000..56b07a3306e5735816c8d89601b519cb0db6379a --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/scheduling/NewChunkHolder.java @@ -0,0 +1,2106 @@ @@ -9704,7 +9867,7 @@ index 0000000000000000000000000000000000000000..b66a7d4aab887309579154815a0d4abf +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.ImposterProtoChunk; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.storage.ChunkSerializer; @@ -14610,7 +14773,7 @@ index cea9c098ade00ee87b8efc8164ab72f5279758f0..197224e31175252d8438a8df585bbb65 + } } diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java -index 83c7b47e189a934345f6548df9b101cc8c501910..e028353e0261310afc42ca0454b723d9f1ffc131 100644 +index 5c401c7e30ed5f6f32b1ad6523537aa46173cff5..e5c2e53388ff61e4aeae22a74b525d9a26ea0200 100644 --- a/src/main/java/io/papermc/paper/util/MCUtil.java +++ b/src/main/java/io/papermc/paper/util/MCUtil.java @@ -7,17 +7,30 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; @@ -14640,7 +14803,7 @@ index 83c7b47e189a934345f6548df9b101cc8c501910..e028353e0261310afc42ca0454b723d9 import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; +import net.minecraft.world.level.chunk.ChunkAccess; -+import net.minecraft.world.level.chunk.ChunkStatus; ++import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.phys.Vec3; import org.apache.commons.lang.exception.ExceptionUtils; import com.mojang.authlib.GameProfile; @@ -14656,7 +14819,7 @@ index 83c7b47e189a934345f6548df9b101cc8c501910..e028353e0261310afc42ca0454b723d9 import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.LinkedBlockingQueue; -@@ -532,6 +548,100 @@ public final class MCUtil { +@@ -532,6 +548,98 @@ public final class MCUtil { } } @@ -14718,8 +14881,6 @@ index 83c7b47e189a934345f6548df9b101cc8c501910..e028353e0261310afc42ca0454b723d9 + worldData.addProperty("name", world.getWorld().getName()); + worldData.addProperty("view-distance", world.getWorld().getViewDistance()); // Paper - replace chunk loader system + worldData.addProperty("tick-view-distance", world.getWorld().getSimulationDistance()); // Paper - replace chunk loader system -+ worldData.addProperty("keep-spawn-loaded", world.keepSpawnInMemory); -+ worldData.addProperty("keep-spawn-loaded-range", world.paperConfig().spawn.keepSpawnLoadedRange * 16); + + JsonArray playersData = new JsonArray(); + @@ -14754,8 +14915,8 @@ index 83c7b47e189a934345f6548df9b101cc8c501910..e028353e0261310afc42ca0454b723d9 + } + } + - public static int getTicketLevelFor(net.minecraft.world.level.chunk.ChunkStatus status) { - return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); + public static int getTicketLevelFor(net.minecraft.world.level.chunk.status.ChunkStatus status) { + return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + net.minecraft.world.level.chunk.status.ChunkStatus.getDistance(status); } diff --git a/src/main/java/io/papermc/paper/util/TickThread.java b/src/main/java/io/papermc/paper/util/TickThread.java index 73e83d56a340f0c7dcb8ff737d621003e72c6de4..bdaf062f9b66ceab303a0807eca301342886a8ea 100644 @@ -15508,22 +15669,22 @@ index 0000000000000000000000000000000000000000..c78cbec447032de9fe69748591bef6be + } +} diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java -index 2906cb10461b5334a7555046384c28848eec149f..329471af4f40e0a74612707cce96bb00819e6cf2 100644 +index c33f85b570f159ab465b5a10a8044a81f2797f43..244a19ecd0234fa1d7a6ecfea20751595688605d 100644 --- a/src/main/java/net/minecraft/server/Main.java +++ b/src/main/java/net/minecraft/server/Main.java -@@ -316,6 +316,7 @@ public class Main { +@@ -320,6 +320,7 @@ public class Main { convertable_conversionsession.saveDataTag(iregistrycustom_dimension, savedata); */ + Class.forName(net.minecraft.world.entity.npc.VillagerTrades.class.getName()); // Paper - load this sync so it won't fail later async final DedicatedServer dedicatedserver = (DedicatedServer) MinecraftServer.spin((thread) -> { - DedicatedServer dedicatedserver1 = new DedicatedServer(optionset, worldLoader.get(), thread, convertable_conversionsession, resourcepackrepository, worldstem, dedicatedserversettings, DataFixers.getDataFixer(), services, LoggerChunkProgressListener::new); + DedicatedServer dedicatedserver1 = new DedicatedServer(optionset, worldLoader.get(), thread, convertable_conversionsession, resourcepackrepository, worldstem, dedicatedserversettings, DataFixers.getDataFixer(), services, LoggerChunkProgressListener::createFromGameruleRadius); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 882b6effa39b62172914b41af54e54c2890480fb..03d566c3e6d7541487ea79ed868aa7334793df3b 100644 +index 1d8c63a5a0b05340396a9f7ba079eb7fceda03e2..d7699ac1c627f265c403b9e00121f5f55e982341 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -311,7 +311,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function serverFactory) { AtomicReference atomicreference = new AtomicReference(); @@ -15532,7 +15693,7 @@ index 882b6effa39b62172914b41af54e54c2890480fb..03d566c3e6d7541487ea79ed868aa733 ((MinecraftServer) atomicreference.get()).runServer(); }, "Server thread"); -@@ -643,7 +643,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { @@ -15667,7 +15828,7 @@ index 882b6effa39b62172914b41af54e54c2890480fb..03d566c3e6d7541487ea79ed868aa733 if (entity.isRemoved()) { continue; } -@@ -2517,6 +2512,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop NOT_DONE_YET = Either.right(ChunkHolder.ChunkLoadingFailure.UNLOADED); - private static final CompletableFuture> UNLOADED_LEVEL_CHUNK_FUTURE = CompletableFuture.completedFuture(ChunkHolder.UNLOADED_LEVEL_CHUNK); +@@ -46,17 +46,12 @@ public class ChunkHolder { + public static final ChunkResult NOT_DONE_YET = ChunkResult.error("Not done yet"); + private static final CompletableFuture> UNLOADED_LEVEL_CHUNK_FUTURE = CompletableFuture.completedFuture(ChunkHolder.UNLOADED_LEVEL_CHUNK); private static final List CHUNK_STATUSES = ChunkStatus.getStatusList(); -- private final AtomicReferenceArray>> futures; +- private final AtomicReferenceArray>> futures; + // Paper - rewrite chunk system private final LevelHeightAccessor levelHeightAccessor; -- private volatile CompletableFuture> fullChunkFuture; private int fullChunkCreateCount; private volatile boolean isFullChunkReady; // Paper - cache chunk ticking stage -- private volatile CompletableFuture> tickingChunkFuture; private volatile boolean isTickingReady; // Paper - cache chunk ticking stage -- private volatile CompletableFuture> entityTickingChunkFuture; private volatile boolean isEntityTickingReady; // Paper - cache chunk ticking stage +- private volatile CompletableFuture> fullChunkFuture; private int fullChunkCreateCount; private volatile boolean isFullChunkReady; // Paper - cache chunk ticking stage +- private volatile CompletableFuture> tickingChunkFuture; private volatile boolean isTickingReady; // Paper - cache chunk ticking stage +- private volatile CompletableFuture> entityTickingChunkFuture; private volatile boolean isEntityTickingReady; // Paper - cache chunk ticking stage - public CompletableFuture chunkToSave; // Paper - public + // Paper - rewrite chunk system @Nullable @@ -15745,7 +15906,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 public final ChunkPos pos; private boolean hasChangedSections; private final ShortSet[] changedBlocksPerSection; -@@ -67,11 +62,20 @@ public class ChunkHolder { +@@ -65,11 +60,20 @@ public class ChunkHolder { private final LevelLightEngine lightEngine; private final ChunkHolder.LevelChangeListener onLevelChange; public final ChunkHolder.PlayerProvider playerProvider; @@ -15769,7 +15930,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 // Paper start public void onChunkAdd() { -@@ -83,158 +87,143 @@ public class ChunkHolder { +@@ -81,147 +85,131 @@ public class ChunkHolder { } // Paper end @@ -15831,12 +15992,12 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 public @Nullable ChunkAccess getAvailableChunkNow() { - // TODO can we just getStatusFuture(EMPTY)? - for (ChunkStatus curr = ChunkStatus.FULL, next = curr.getParent(); curr != next; curr = next, next = next.getParent()) { -- CompletableFuture> future = this.getFutureIfPresentUnchecked(curr); -- Either either = future.getNow(null); -- if (either == null || either.left().isEmpty()) { +- CompletableFuture> future = this.getFutureIfPresentUnchecked(curr); +- ChunkResult either = future.getNow(null); +- if (either == null || either.isSuccess()) { - continue; - } -- return either.left().get(); +- return either.orElseThrow(IllegalStateException::new); - } - return null; + return this.newChunkHolder.getCurrentChunk(); // Paper - rewrite chunk system @@ -15848,56 +16009,51 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - if (!ChunkLevel.fullStatus(this.oldTicketLevel).isOrAfter(FullChunkStatus.FULL)) return null; - return this.getFullChunkNowUnchecked(); + // Paper start - rewrite chunk system -+ ChunkAccess chunk = this.getAvailableChunkNow(); -+ if (!this.isFullChunkReady() || !(chunk instanceof LevelChunk)) return null; // instanceof to avoid a race condition on off-main threads -+ return (LevelChunk)chunk; ++ if (!this.isFullChunkReady() || !(this.getAvailableChunkNow() instanceof LevelChunk chunk)) return null; // instanceof to avoid a race condition on off-main threads ++ return chunk; + // Paper end - rewrite chunk system } public LevelChunk getFullChunkNowUnchecked() { -- CompletableFuture> statusFuture = this.getFutureIfPresentUnchecked(ChunkStatus.FULL); -- Either either = (Either) statusFuture.getNow(null); -- return (either == null) ? null : (LevelChunk) either.left().orElse(null); +- CompletableFuture> statusFuture = this.getFutureIfPresentUnchecked(ChunkStatus.FULL); +- ChunkResult either = statusFuture.getNow(null); +- return (either == null) ? null : (LevelChunk) either.orElse(null); + // Paper start - rewrite chunk system -+ ChunkAccess chunk = this.getAvailableChunkNow(); -+ return chunk instanceof LevelChunk ? (LevelChunk)chunk : null; ++ return this.getAvailableChunkNow() instanceof LevelChunk chunk ? chunk : null; + // Paper end - rewrite chunk system } // CraftBukkit end - public CompletableFuture> getFutureIfPresentUnchecked(ChunkStatus leastStatus) { -- CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(leastStatus.getIndex()); + public CompletableFuture> getFutureIfPresentUnchecked(ChunkStatus leastStatus) { +- CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(leastStatus.getIndex()); - - return completablefuture == null ? ChunkHolder.UNLOADED_CHUNK_FUTURE : completablefuture; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public CompletableFuture> getFutureIfPresent(ChunkStatus leastStatus) { + public CompletableFuture> getFutureIfPresent(ChunkStatus leastStatus) { - return ChunkLevel.generationStatus(this.ticketLevel).isOrAfter(leastStatus) ? this.getFutureIfPresentUnchecked(leastStatus) : ChunkHolder.UNLOADED_CHUNK_FUTURE; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public final CompletableFuture> getTickingChunkFuture() { // Paper - final for inline + public final CompletableFuture> getTickingChunkFuture() { // Paper - final for inline - return this.tickingChunkFuture; + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public final CompletableFuture> getEntityTickingChunkFuture() { // Paper - final for inline + public final CompletableFuture> getEntityTickingChunkFuture() { // Paper - final for inline - return this.entityTickingChunkFuture; -+ throw new UnsupportedOperationException(); // Paper - rewrite chunk system ++ throw new UnsupportedOperationException(); // Paper - rewrite chunk systemv } - public final CompletableFuture> getFullChunkFuture() { // Paper - final for inline + public final CompletableFuture> getFullChunkFuture() { // Paper - final for inline - return this.fullChunkFuture; -+ throw new UnsupportedOperationException(); // Paper - rewrite chunk system ++ throw new UnsupportedOperationException(); // Paper - rewrite chunk systemv } @Nullable public final LevelChunk getTickingChunk() { // Paper - final for inline -- CompletableFuture> completablefuture = this.getTickingChunkFuture(); -- Either either = (Either) completablefuture.getNow(null); // CraftBukkit - decompile error -- -- return either == null ? null : (LevelChunk) either.left().orElse(null); // CraftBukkit - decompile error +- return (LevelChunk) ((ChunkResult) this.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).orElse(null); // CraftBukkit - decompile error + // Paper start - rewrite chunk system + if (!this.isTickingReady()) { + return null; @@ -15917,27 +16073,13 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 + return this.getSendingChunk(); // Paper - rewrite chunk system } - @Nullable - public final LevelChunk getFullChunk() { // Paper - final for inline -- CompletableFuture> completablefuture = this.getFullChunkFuture(); -- Either either = (Either) completablefuture.getNow(null); // CraftBukkit - decompile error -- -- return either == null ? null : (LevelChunk) either.left().orElse(null); // CraftBukkit - decompile error -+ // Paper start - rewrite chunk system -+ if (!this.isFullChunkReady()) { -+ return null; -+ } -+ return (LevelChunk)this.getAvailableChunkNow(); -+ // Paper end - rewrite chunk system - } - @Nullable public ChunkStatus getLastAvailableStatus() { - for (int i = ChunkHolder.CHUNK_STATUSES.size() - 1; i >= 0; --i) { - ChunkStatus chunkstatus = (ChunkStatus) ChunkHolder.CHUNK_STATUSES.get(i); -- CompletableFuture> completablefuture = this.getFutureIfPresentUnchecked(chunkstatus); +- CompletableFuture> completablefuture = this.getFutureIfPresentUnchecked(chunkstatus); - -- if (((Either) completablefuture.getNow(ChunkHolder.UNLOADED_CHUNK)).left().isPresent()) { +- if (((ChunkResult) completablefuture.getNow(ChunkHolder.UNLOADED_CHUNK)).isSuccess()) { - return chunkstatus; - } - } @@ -15947,11 +16089,11 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 } // Paper start - public ChunkStatus getChunkHolderStatus() { + public @Nullable ChunkStatus getChunkHolderStatus() { - for (ChunkStatus curr = ChunkStatus.FULL, next = curr.getParent(); curr != next; curr = next, next = next.getParent()) { -- CompletableFuture> future = this.getFutureIfPresentUnchecked(curr); -- Either either = future.getNow(null); -- if (either == null || !either.left().isPresent()) { +- CompletableFuture> future = this.getFutureIfPresentUnchecked(curr); +- ChunkResult either = future.getNow(null); +- if (either == null || !either.isSuccess()) { - continue; - } - return curr; @@ -15966,13 +16108,13 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 public ChunkAccess getLastAvailable() { - for (int i = ChunkHolder.CHUNK_STATUSES.size() - 1; i >= 0; --i) { - ChunkStatus chunkstatus = (ChunkStatus) ChunkHolder.CHUNK_STATUSES.get(i); -- CompletableFuture> completablefuture = this.getFutureIfPresentUnchecked(chunkstatus); +- CompletableFuture> completablefuture = this.getFutureIfPresentUnchecked(chunkstatus); - - if (!completablefuture.isCompletedExceptionally()) { -- Optional optional = ((Either) completablefuture.getNow(ChunkHolder.UNLOADED_CHUNK)).left(); +- ChunkAccess ichunkaccess = (ChunkAccess) ((ChunkResult) completablefuture.getNow(ChunkHolder.UNLOADED_CHUNK)).orElse((Object) null); - -- if (optional.isPresent()) { -- return (ChunkAccess) optional.get(); +- if (ichunkaccess != null) { +- return ichunkaccess; - } - } - } @@ -15997,30 +16139,33 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 if (chunk != null) { int i = this.levelHeightAccessor.getSectionIndex(pos.getY()); -@@ -250,16 +239,17 @@ public class ChunkHolder { +@@ -237,13 +225,13 @@ public class ChunkHolder { } public void sectionLightChanged(LightLayer lightType, int y) { -- Either either = (Either) this.getFutureIfPresent(ChunkStatus.INITIALIZE_LIGHT).getNow(null); // CraftBukkit - decompile error -+ // Paper start - no-tick view distance +- ChunkAccess ichunkaccess = (ChunkAccess) ((ChunkResult) this.getFutureIfPresent(ChunkStatus.INITIALIZE_LIGHT).getNow(ChunkHolder.UNLOADED_CHUNK)).orElse(null); // CraftBukkit - decompile error ++ ChunkAccess ichunkaccess = this.getAvailableChunkNow(); // Paper - rewrite chunk system -- if (either != null) { -- ChunkAccess ichunkaccess = (ChunkAccess) either.left().orElse(null); // CraftBukkit - decompile error -+ if (true) { -+ ChunkAccess ichunkaccess = this.getAvailableChunkNow(); + if (ichunkaccess != null) { + ichunkaccess.setUnsaved(true); +- LevelChunk chunk = this.getTickingChunk(); ++ LevelChunk chunk = this.getSendingChunk(); // Paper - rewrite chunk system - if (ichunkaccess != null) { - ichunkaccess.setUnsaved(true); -- LevelChunk chunk = this.getTickingChunk(); -+ LevelChunk chunk = this.getSendingChunk(); -+ // Paper end - no-tick view distance +- if (chunk != null) { ++ if (this.playersSentChunkTo.size() != 0 && chunk != null) { // Paper - replace player chunk loader + int j = this.lightEngine.getMinLightSection(); + int k = this.lightEngine.getMaxLightSection(); -- if (chunk != null) { -+ if (this.playersSentChunkTo.size() != 0 && chunk != null) { // Paper - replace player chunk loader - int j = this.lightEngine.getMinLightSection(); - int k = this.lightEngine.getMaxLightSection(); +@@ -263,7 +251,7 @@ public class ChunkHolder { -@@ -284,7 +274,7 @@ public class ChunkHolder { + // Paper start - starlight + public void broadcast(Packet packet, boolean onChunkViewEdge) { +- this.broadcast(this.playerProvider.getPlayers(this.pos, onChunkViewEdge), packet); ++ this.broadcast(this.getPlayers(onChunkViewEdge), packet); // Paper - rewrite chunk system + } + // Paper end - starlight + +@@ -273,7 +261,7 @@ public class ChunkHolder { List list; if (!this.skyChangedLightSectionFilter.isEmpty() || !this.blockChangedLightSectionFilter.isEmpty()) { @@ -16029,7 +16174,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 if (!list.isEmpty()) { ClientboundLightUpdatePacket packetplayoutlightupdate = new ClientboundLightUpdatePacket(chunk.getPos(), this.lightEngine, this.skyChangedLightSectionFilter, this.blockChangedLightSectionFilter); -@@ -296,7 +286,7 @@ public class ChunkHolder { +@@ -285,7 +273,7 @@ public class ChunkHolder { } if (this.hasChangedSections) { @@ -16038,7 +16183,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 for (int i = 0; i < this.changedBlocksPerSection.length; ++i) { ShortSet shortset = this.changedBlocksPerSection[i]; -@@ -354,78 +344,35 @@ public class ChunkHolder { +@@ -343,75 +331,33 @@ public class ChunkHolder { } @@ -16048,24 +16193,25 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - }); - } - -- public CompletableFuture> getOrScheduleFuture(ChunkStatus targetStatus, ChunkMap chunkStorage) { +- public CompletableFuture> getOrScheduleFuture(ChunkStatus targetStatus, ChunkMap chunkStorage) { - int i = targetStatus.getIndex(); -- CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(i); -- +- CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(i); ++ // Paper start - rewrite chunk system ++ public List getPlayers(boolean onlyOnWatchDistanceEdge) { ++ List ret = new java.util.ArrayList<>(); + - if (completablefuture != null) { -- Either either = (Either) completablefuture.getNow(ChunkHolder.NOT_DONE_YET); +- ChunkResult chunkresult = (ChunkResult) completablefuture.getNow(ChunkHolder.NOT_DONE_YET); - -- if (either == null) { -- String s = "value in future for status: " + targetStatus + " was incorrectly set to null at chunk: " + this.pos; +- if (chunkresult == null) { +- String s = String.valueOf(targetStatus); +- String s1 = "value in future for status: " + s + " was incorrectly set to null at chunk: " + String.valueOf(this.pos); - -- throw chunkStorage.debugFuturesAndCreateReportedException(new IllegalStateException("null value previously set for chunk status"), s); +- throw chunkStorage.debugFuturesAndCreateReportedException(new IllegalStateException("null value previously set for chunk status"), s1); - } - -- if (either == ChunkHolder.NOT_DONE_YET || either.right().isEmpty()) { +- if (chunkresult == ChunkHolder.NOT_DONE_YET || chunkresult.isSuccess()) { - return completablefuture; -+ // Paper start - rewrite chunk system -+ public List getPlayers(boolean onlyOnWatchDistanceEdge){ -+ List ret = new java.util.ArrayList<>(); + for (int i = 0, len = this.playersSentChunkTo.size(); i < len; ++i) { + ServerPlayer player = this.playersSentChunkTo.getUnchecked(i); + if (onlyOnWatchDistanceEdge && !this.chunkMap.level.playerChunkLoader.isChunkSent(player, this.pos.x, this.pos.z, onlyOnWatchDistanceEdge)) { @@ -16075,9 +16221,9 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 } - if (ChunkLevel.generationStatus(this.ticketLevel).isOrAfter(targetStatus)) { -- CompletableFuture> completablefuture1 = chunkStorage.schedule(this, targetStatus); +- CompletableFuture> completablefuture1 = chunkStorage.schedule(this, targetStatus); - -- this.updateChunkToSave(completablefuture1, "schedule " + targetStatus); +- this.updateChunkToSave(completablefuture1, "schedule " + String.valueOf(targetStatus)); - this.futures.set(i, completablefuture1); - return completablefuture1; - } else { @@ -16085,31 +16231,25 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - } + return ret; } ++ // Paper end - rewrite chunk system - protected void addSaveDependency(String thenDesc, CompletableFuture then) { - if (this.chunkToSaveHistory != null) { - this.chunkToSaveHistory.push(new ChunkHolder.ChunkSaveDebug(Thread.currentThread(), then, thenDesc)); - } -- + - this.chunkToSave = this.chunkToSave.thenCombine(then, (ichunkaccess, object) -> { - return ichunkaccess; - }); -+ public void broadcast(Packet packet, boolean onlyOnWatchDistanceEdge) { -+ this.broadcast(this.getPlayers(onlyOnWatchDistanceEdge), packet); - } -+ // Paper end - rewrite chunk system - -- private void updateChunkToSave(CompletableFuture> then, String thenDesc) { +- } +- +- private void updateChunkToSave(CompletableFuture> then, String thenDesc) { - if (this.chunkToSaveHistory != null) { - this.chunkToSaveHistory.push(new ChunkHolder.ChunkSaveDebug(Thread.currentThread(), then, thenDesc)); - } - -- this.chunkToSave = this.chunkToSave.thenCombine(then, (ichunkaccess, either) -> { -- return (ChunkAccess) either.map((ichunkaccess1) -> { -- return ichunkaccess1; -- }, (playerchunk_failure) -> { -- return ichunkaccess; -- }); +- this.chunkToSave = this.chunkToSave.thenCombine(then, (ichunkaccess, chunkresult) -> { +- return (ChunkAccess) ChunkResult.orElse(chunkresult, ichunkaccess); + private void broadcast(List players, Packet packet) { + players.forEach((entityplayer) -> { + entityplayer.connection.send(packet); @@ -16130,11 +16270,11 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 public FullChunkStatus getFullStatus() { - return ChunkLevel.fullStatus(this.ticketLevel); -+ return this.newChunkHolder.getChunkStatus(); // Paper - rewrite chunk system) { ++ return this.newChunkHolder.getChunkStatus(); // Paper - rewrite chunk system } public final ChunkPos getPos() { // Paper - final for inline -@@ -433,240 +380,17 @@ public class ChunkHolder { +@@ -419,238 +365,17 @@ public class ChunkHolder { } public final int getTicketLevel() { // Paper - final for inline @@ -16153,7 +16293,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - this.ticketLevel = level; - } - -- private void scheduleFullChunkPromotion(ChunkMap playerchunkmap, CompletableFuture> completablefuture, Executor executor, FullChunkStatus fullchunkstatus) { +- private void scheduleFullChunkPromotion(ChunkMap playerchunkmap, CompletableFuture> completablefuture, Executor executor, FullChunkStatus fullchunkstatus) { - this.pendingFullStateConfirmation.cancel(false); - CompletableFuture completablefuture1 = new CompletableFuture(); - @@ -16161,8 +16301,8 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - playerchunkmap.onFullChunkStatusChange(this.pos, fullchunkstatus); - }, executor); - this.pendingFullStateConfirmation = completablefuture1; -- completablefuture.thenAccept((either) -> { -- either.ifLeft((chunk) -> { +- completablefuture.thenAccept((chunkresult) -> { +- chunkresult.ifSuccess((chunk) -> { - completablefuture1.complete(null); // CraftBukkit - decompile error - }); - }); @@ -16184,7 +16324,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - // ChunkUnloadEvent: Called before the chunk is unloaded: isChunkLoaded is still true and chunk can still be modified by plugins. - if (fullchunkstatus.isOrAfter(FullChunkStatus.FULL) && !fullchunkstatus1.isOrAfter(FullChunkStatus.FULL)) { - this.getFutureIfPresentUnchecked(ChunkStatus.FULL).thenAccept((either) -> { -- LevelChunk chunk = (LevelChunk)either.left().orElse(null); +- LevelChunk chunk = (LevelChunk) either.orElse(null); - if (chunk != null) { - chunkStorage.callbackExecutor.execute(() -> { - // Minecraft will apply the chunks tick lists to the world once the chunk got loaded, and then store the tick @@ -16206,17 +16346,15 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - // CraftBukkit end - - if (flag) { -- Either either = Either.right(new ChunkHolder.ChunkLoadingFailure() { -- public String toString() { -- return "Unloaded ticket level " + ChunkHolder.this.pos; -- } +- ChunkResult chunkresult = ChunkResult.error(() -> { +- return "Unloaded ticket level " + String.valueOf(this.pos); - }); - - for (int i = flag1 ? chunkstatus1.getIndex() + 1 : 0; i <= chunkstatus.getIndex(); ++i) { -- CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(i); +- CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(i); - - if (completablefuture == null) { -- this.futures.set(i, CompletableFuture.completedFuture(either)); +- this.futures.set(i, CompletableFuture.completedFuture(chunkresult)); - } - } - } @@ -16230,13 +16368,13 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - this.fullChunkFuture = chunkStorage.prepareAccessibleChunk(this); - this.scheduleFullChunkPromotion(chunkStorage, this.fullChunkFuture, executor, FullChunkStatus.FULL); - // Paper start - cache ticking ready status -- this.fullChunkFuture.thenAccept(either -> { -- final Optional left = either.left(); -- if (left.isPresent() && ChunkHolder.this.fullChunkCreateCount == expectCreateCount) { -- LevelChunk fullChunk = either.left().get(); -- ChunkHolder.this.isFullChunkReady = true; -- io.papermc.paper.chunk.system.ChunkSystem.onChunkBorder(fullChunk, this); -- } +- this.fullChunkFuture.thenAccept(chunkResult -> { +- chunkResult.ifSuccess(chunk -> { +- if (ChunkHolder.this.fullChunkCreateCount == expectCreateCount) { +- ChunkHolder.this.isFullChunkReady = true; +- io.papermc.paper.chunk.system.ChunkSystem.onChunkBorder(chunk, this); +- } +- }); - }); - this.updateChunkToSave(this.fullChunkFuture, "full"); - } @@ -16244,7 +16382,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - if (flag2 && !flag3) { - // Paper start - if (this.isFullChunkReady) { -- io.papermc.paper.chunk.system.ChunkSystem.onChunkNotBorder(this.fullChunkFuture.join().left().get(), this); // Paper +- io.papermc.paper.chunk.system.ChunkSystem.onChunkNotBorder(this.fullChunkFuture.join().orElseThrow(IllegalStateException::new), this); // Paper - } - // Paper end - this.fullChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); @@ -16260,8 +16398,8 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - this.tickingChunkFuture = chunkStorage.prepareTickingChunk(this); - this.scheduleFullChunkPromotion(chunkStorage, this.tickingChunkFuture, executor, FullChunkStatus.BLOCK_TICKING); - // Paper start - cache ticking ready status -- this.tickingChunkFuture.thenAccept(either -> { -- either.ifLeft(chunk -> { +- this.tickingChunkFuture.thenAccept(chunkResult -> { +- chunkResult.ifSuccess(chunk -> { - // note: Here is a very good place to add callbacks to logic waiting on this. - ChunkHolder.this.isTickingReady = true; - io.papermc.paper.chunk.system.ChunkSystem.onChunkTicking(chunk, this); @@ -16274,7 +16412,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - if (flag4 && !flag5) { - // Paper start - if (this.isTickingReady) { -- io.papermc.paper.chunk.system.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().left().get(), this); // Paper +- io.papermc.paper.chunk.system.ChunkSystem.onChunkNotTicking(this.tickingChunkFuture.join().orElseThrow(IllegalStateException::new), this); // Paper - } - // Paper end - this.tickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isTickingReady = false; // Paper - cache chunk ticking stage @@ -16292,8 +16430,8 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - this.entityTickingChunkFuture = chunkStorage.prepareEntityTickingChunk(this); - this.scheduleFullChunkPromotion(chunkStorage, this.entityTickingChunkFuture, executor, FullChunkStatus.ENTITY_TICKING); - // Paper start - cache ticking ready status -- this.entityTickingChunkFuture.thenAccept(either -> { -- either.ifLeft(chunk -> { +- this.entityTickingChunkFuture.thenAccept(chunkResult -> { +- chunkResult.ifSuccess(chunk -> { - ChunkHolder.this.isEntityTickingReady = true; - io.papermc.paper.chunk.system.ChunkSystem.onChunkEntityTicking(chunk, this); - }); @@ -16305,7 +16443,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - if (flag6 && !flag7) { - // Paper start - if (this.isEntityTickingReady) { -- io.papermc.paper.chunk.system.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().left().get(), this); +- io.papermc.paper.chunk.system.ChunkSystem.onChunkNotEntityTicking(this.entityTickingChunkFuture.join().orElseThrow(IllegalStateException::new), this); - } - // Paper end - this.entityTickingChunkFuture.complete(ChunkHolder.UNLOADED_LEVEL_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage @@ -16322,7 +16460,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 - // ChunkLoadEvent: Called after the chunk is loaded: isChunkLoaded returns true and chunk is ready to be modified by plugins. - if (!fullchunkstatus.isOrAfter(FullChunkStatus.FULL) && fullchunkstatus1.isOrAfter(FullChunkStatus.FULL)) { - this.getFutureIfPresentUnchecked(ChunkStatus.FULL).thenAccept((either) -> { -- LevelChunk chunk = (LevelChunk)either.left().orElse(null); +- LevelChunk chunk = (LevelChunk) either.orElse(null); - if (chunk != null) { - chunkStorage.callbackExecutor.execute(() -> { - chunk.loadCallback(); @@ -16352,23 +16490,23 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 public void replaceProtoChunk(ImposterProtoChunk chunk) { - for (int i = 0; i < this.futures.length(); ++i) { -- CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(i); +- CompletableFuture> completablefuture = (CompletableFuture) this.futures.get(i); - - if (completablefuture != null) { -- Optional optional = ((Either) completablefuture.getNow(ChunkHolder.UNLOADED_CHUNK)).left(); +- ChunkAccess ichunkaccess = (ChunkAccess) ((ChunkResult) completablefuture.getNow(ChunkHolder.UNLOADED_CHUNK)).orElse((Object) null); - -- if (!optional.isEmpty() && optional.get() instanceof ProtoChunk) { -- this.futures.set(i, CompletableFuture.completedFuture(Either.left(chunk))); +- if (ichunkaccess instanceof ProtoChunk) { +- this.futures.set(i, CompletableFuture.completedFuture(ChunkResult.of(chunk))); - } - } - } - -- this.updateChunkToSave(CompletableFuture.completedFuture(Either.left(chunk.getWrapped())), "replaceProto"); +- this.updateChunkToSave(CompletableFuture.completedFuture(ChunkResult.of(chunk.getWrapped())), "replaceProto"); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public List>>> getAllFutures() { -- List>>> list = new ArrayList(); + public List>>> getAllFutures() { +- List>>> list = new ArrayList(); - - for (int i = 0; i < ChunkHolder.CHUNK_STATUSES.size(); ++i) { - list.add(Pair.of((ChunkStatus) ChunkHolder.CHUNK_STATUSES.get(i), (CompletableFuture) this.futures.get(i))); @@ -16379,7 +16517,7 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 } @FunctionalInterface -@@ -704,15 +428,15 @@ public class ChunkHolder { +@@ -670,15 +395,15 @@ public class ChunkHolder { // Paper start public final boolean isEntityTickingReady() { @@ -16399,10 +16537,10 @@ index 807a6bb1026dac2c4cd0a50afe06fd62ce23558b..2b998bdbe49bf8211b755e0eb7c1bf13 // Paper end } diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b883fe621 100644 +index d3f63185edd1db9fab3887ea3f08982435b3a23c..721b63f7471ace33ae22f4205f554ee3be0e033d 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -119,10 +119,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -122,10 +122,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider 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); @@ -16414,7 +16552,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b public final ServerLevel level; private final ThreadedLevelLightEngine lightEngine; public final BlockableEventLoop mainThreadExecutor; // Paper - public -@@ -131,16 +128,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -134,11 +131,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider private final ChunkGeneratorStructureState chunkGeneratorState; public final Supplier overworldDataStorage; private final PoiManager poiManager; @@ -16428,16 +16566,12 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b public final ChunkProgressListener progressListener; private final ChunkStatusUpdateListener chunkStatusListener; public final ChunkMap.ChunkDistanceManager distanceManager; - private final AtomicInteger tickingGenerated; -- private final StructureTemplateManager structureTemplateManager; -+ public final StructureTemplateManager structureTemplateManager; // Paper - rewrite chunk system - private final String storageName; - private final PlayerMap playerMap; - public final Int2ObjectMap entityMap; -@@ -149,27 +144,6 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -150,28 +145,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + private final Long2LongMap chunkSaveCooldowns; private final Queue unloadQueue; public int serverViewDistance; - +- private WorldGenContext worldGenContext; +- - // CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback() - public final CallbackExecutor callbackExecutor = new CallbackExecutor(); - public static final class CallbackExecutor implements java.util.concurrent.Executor, Runnable { @@ -16458,11 +16592,11 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b - } - }; - // CraftBukkit end -- ++ private WorldGenContext worldGenContext; public final WorldGenContext getWorldGenContext() { return this.worldGenContext; } // Paper - rewrite chunk system + // Paper start - distance maps private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>(); - -@@ -178,6 +152,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -181,6 +155,7 @@ 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.nearbyPlayers.addPlayer(player); @@ -16470,7 +16604,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } void removePlayerFromDistanceMaps(ServerPlayer player) { -@@ -185,6 +160,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -188,6 +163,7 @@ 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.nearbyPlayers.removePlayer(player); @@ -16478,7 +16612,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } void updateMaps(ServerPlayer player) { -@@ -192,6 +168,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -195,6 +171,7 @@ 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.nearbyPlayers.tickPlayer(player); @@ -16486,7 +16620,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } // Paper end // Paper start -@@ -221,17 +198,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -224,17 +201,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public final ChunkHolder getUnloadingChunkHolder(int chunkX, int chunkZ) { @@ -16497,7 +16631,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b // Paper end public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory, int viewDistance, boolean dsync) { - super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); + super(new RegionStorageInfo(session.getLevelId(), world.dimension(), "chunk"), session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); - this.visibleChunkMap = this.updatingChunkMap.clone(); - this.pendingUnloads = new Long2ObjectLinkedOpenHashMap(); - this.entitiesInLevel = new LongOpenHashSet(); @@ -16506,7 +16640,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b this.tickingGenerated = new AtomicInteger(); this.playerMap = new PlayerMap(); this.entityMap = new Int2ObjectOpenHashMap(); -@@ -262,19 +236,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -263,19 +237,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.chunkGeneratorState = chunkGenerator.createState(iregistrycustom.lookupOrThrow(Registries.STRUCTURE_SET), this.randomState, j, world.spigotConfig); // Spigot this.mainThreadExecutor = mainThreadExecutor; @@ -16530,8 +16664,8 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b + this.lightEngine = new ThreadedLevelLightEngine(chunkProvider, this, this.level.dimensionType().hasSkyLight(), null, null); // Paper - rewrite chunk system this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor); this.overworldDataStorage = persistentStateManagerFactory; - this.poiManager = new PoiManager(path.resolve("poi"), dataFixer, dsync, iregistrycustom, world); -@@ -330,23 +302,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + this.poiManager = new PoiManager(new RegionStorageInfo(session.getLevelId(), world.dimension(), "poi"), path.resolve("poi"), dataFixer, dsync, iregistrycustom, world); +@@ -333,23 +305,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } boolean isChunkTracked(ServerPlayer player, int chunkX, int chunkZ) { @@ -16561,7 +16695,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } protected ThreadedLevelLightEngine getLightEngine() { -@@ -355,20 +319,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -358,20 +322,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Nullable protected ChunkHolder getUpdatingChunkIfPresent(long pos) { @@ -16591,18 +16725,18 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } public String getChunkDebugData(ChunkPos chunkPos) { -@@ -397,84 +363,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -400,80 +366,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - private CompletableFuture, ChunkHolder.ChunkLoadingFailure>> getChunkRangeFuture(ChunkHolder centerChunk, int margin, IntFunction distanceToStatus) { + private CompletableFuture>> getChunkRangeFuture(ChunkHolder centerChunk, int margin, IntFunction distanceToStatus) { - if (margin == 0) { - ChunkStatus chunkstatus = (ChunkStatus) distanceToStatus.apply(0); - -- return centerChunk.getOrScheduleFuture(chunkstatus, this).thenApply((either) -> { -- return either.mapLeft(List::of); +- return centerChunk.getOrScheduleFuture(chunkstatus, this).thenApply((chunkresult) -> { +- return chunkresult.map(List::of); - }); - } else { -- List>> list = new ArrayList(); +- List>> list = new ArrayList(); - List list1 = new ArrayList(); - ChunkPos chunkcoordintpair = centerChunk.getPos(); - int j = chunkcoordintpair.x; @@ -16611,28 +16745,26 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b - for (int l = -margin; l <= margin; ++l) { - for (int i1 = -margin; i1 <= margin; ++i1) { - int j1 = Math.max(Math.abs(i1), Math.abs(l)); -- final ChunkPos chunkcoordintpair1 = new ChunkPos(j + i1, k + l); +- ChunkPos chunkcoordintpair1 = new ChunkPos(j + i1, k + l); - long k1 = chunkcoordintpair1.toLong(); - ChunkHolder playerchunk1 = this.getUpdatingChunkIfPresent(k1); - - if (playerchunk1 == null) { -- return CompletableFuture.completedFuture(Either.right(new ChunkHolder.ChunkLoadingFailure() { -- public String toString() { -- return "Unloaded " + chunkcoordintpair1; -- } +- return CompletableFuture.completedFuture(ChunkResult.error(() -> { +- return "Unloaded " + String.valueOf(chunkcoordintpair1); - })); - } - - ChunkStatus chunkstatus1 = (ChunkStatus) distanceToStatus.apply(j1); -- CompletableFuture> completablefuture = playerchunk1.getOrScheduleFuture(chunkstatus1, this); +- CompletableFuture> completablefuture = playerchunk1.getOrScheduleFuture(chunkstatus1, this); - - list1.add(playerchunk1); - list.add(completablefuture); - } - } - -- CompletableFuture>> completablefuture1 = Util.sequence(list); -- CompletableFuture, ChunkHolder.ChunkLoadingFailure>> completablefuture2 = completablefuture1.thenApply((list2) -> { +- CompletableFuture>> completablefuture1 = Util.sequence(list); +- CompletableFuture>> completablefuture2 = completablefuture1.thenApply((list2) -> { - List list3 = Lists.newArrayList(); - // CraftBukkit start - decompile error - int cnt = 0; @@ -16640,35 +16772,33 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b - for (Iterator iterator = list2.iterator(); iterator.hasNext(); ++cnt) { - final int l1 = cnt; - // CraftBukkit end -- final Either either = (Either) iterator.next(); +- ChunkResult chunkresult = (ChunkResult) iterator.next(); - -- if (either == null) { +- if (chunkresult == null) { - throw this.debugFuturesAndCreateReportedException(new IllegalStateException("At least one of the chunk futures were null"), "n/a"); - } - -- Optional optional = either.left(); +- ChunkAccess ichunkaccess = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error - -- 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)); +- if (ichunkaccess == null) { +- return ChunkResult.error(() -> { +- String s = String.valueOf(new ChunkPos(j + l1 % (margin * 2 + 1), k + l1 / (margin * 2 + 1))); - -- return "Unloaded " + chunkcoordintpair2 + " " + either.right().get(); -- } +- return "Unloaded " + s + " " + chunkresult.getError(); - }); - } - -- list3.add((ChunkAccess) optional.get()); +- list3.add(ichunkaccess); - } - -- return Either.left(list3); +- return ChunkResult.of(list3); - }); - Iterator iterator = list1.iterator(); - - while (iterator.hasNext()) { - ChunkHolder playerchunk2 = (ChunkHolder) iterator.next(); - -- playerchunk2.addSaveDependency("getChunkRangeFuture " + chunkcoordintpair + " " + margin, completablefuture2); +- playerchunk2.addSaveDependency("getChunkRangeFuture " + String.valueOf(chunkcoordintpair) + " " + margin, completablefuture2); - } - - return completablefuture2; @@ -16677,14 +16807,14 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } public ReportedException debugFuturesAndCreateReportedException(IllegalStateException exception, String details) { -@@ -504,263 +393,72 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -503,263 +396,72 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - public CompletableFuture> prepareEntityTickingChunk(ChunkHolder chunk) { + public CompletableFuture> prepareEntityTickingChunk(ChunkHolder chunk) { - return this.getChunkRangeFuture(chunk, 2, (i) -> { - return ChunkStatus.FULL; -- }).thenApplyAsync((either) -> { -- return either.mapLeft((list) -> { +- }).thenApplyAsync((chunkresult) -> { +- return chunkresult.map((list) -> { - return (LevelChunk) list.get(list.size() / 2); - }); - }, this.mainThreadExecutor); @@ -16833,7 +16963,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b - } - - int l = 0; -- Iterator objectiterator = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper +- Iterator objectiterator = io.papermc.paper.chunk.system.ChunkSystem.getVisibleChunkHolders(this.level).iterator(); // Paper - - while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) { - if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) { @@ -16901,26 +17031,26 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - public CompletableFuture> schedule(ChunkHolder holder, ChunkStatus requiredStatus) { + public CompletableFuture> schedule(ChunkHolder holder, ChunkStatus requiredStatus) { - ChunkPos chunkcoordintpair = holder.getPos(); - - if (requiredStatus == ChunkStatus.EMPTY) { -- return this.scheduleChunkLoad(chunkcoordintpair); +- return this.scheduleChunkLoad(chunkcoordintpair).thenApply(ChunkResult::of); - } else { - if (requiredStatus == ChunkStatus.LIGHT) { - this.distanceManager.addTicket(TicketType.LIGHT, chunkcoordintpair, ChunkLevel.byStatus(ChunkStatus.LIGHT), chunkcoordintpair); - } - - if (!requiredStatus.hasLoadDependencies()) { -- Optional optional = ((Either) holder.getOrScheduleFuture(requiredStatus.getParent(), this).getNow(ChunkHolder.UNLOADED_CHUNK)).left(); +- ChunkAccess ichunkaccess = (ChunkAccess) ((ChunkResult) holder.getOrScheduleFuture(requiredStatus.getParent(), this).getNow(ChunkHolder.UNLOADED_CHUNK)).orElse((Object) null); - -- if (optional.isPresent() && ((ChunkAccess) optional.get()).getStatus().isOrAfter(requiredStatus)) { -- CompletableFuture> completablefuture = requiredStatus.load(this.level, this.structureTemplateManager, this.lightEngine, (ichunkaccess) -> { -- return this.protoChunkToFullChunk(holder); -- }, (ChunkAccess) optional.get()); +- if (ichunkaccess != null && ichunkaccess.getStatus().isOrAfter(requiredStatus)) { +- CompletableFuture completablefuture = requiredStatus.load(this.worldGenContext, (ichunkaccess1) -> { +- return this.protoChunkToFullChunk(holder, ichunkaccess1); +- }, ichunkaccess); - - this.progressListener.onStatusChange(chunkcoordintpair, requiredStatus); -- return completablefuture; +- return completablefuture.thenApply(ChunkResult::of); - } - } - @@ -16929,7 +17059,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private CompletableFuture> scheduleChunkLoad(ChunkPos pos) { + private CompletableFuture scheduleChunkLoad(ChunkPos pos) { - return this.readChunk(pos).thenApply((optional) -> { - return optional.filter((nbttagcompound) -> { - boolean flag = ChunkMap.isChunkDataValid(nbttagcompound); @@ -16946,9 +17076,9 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b - ProtoChunk protochunk = ChunkSerializer.read(this.level, this.poiManager, pos, (CompoundTag) optional.get()); - - this.markPosition(pos, protochunk.getStatus().getChunkType()); -- return Either.left(protochunk); // CraftBukkit - decompile error +- return protochunk; - } else { -- return Either.left(this.createEmptyChunk(pos)); // CraftBukkit - decompile error +- return this.createEmptyChunk(pos); - } - }, this.mainThreadExecutor).exceptionallyAsync((throwable) -> { - return this.handleChunkLoadFailure(throwable, pos); @@ -16961,45 +17091,54 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b return nbt.contains("Status", 8); } -@@ -796,54 +494,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -816,60 +518,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } - private CompletableFuture> scheduleChunkGeneration(ChunkHolder holder, ChunkStatus requiredStatus) { + private CompletableFuture> scheduleChunkGeneration(ChunkHolder holder, ChunkStatus requiredStatus) { - ChunkPos chunkcoordintpair = holder.getPos(); -- CompletableFuture, ChunkHolder.ChunkLoadingFailure>> completablefuture = this.getChunkRangeFuture(holder, requiredStatus.getRange(), (i) -> { +- CompletableFuture>> completablefuture = this.getChunkRangeFuture(holder, requiredStatus.getRange(), (i) -> { - return this.getDependencyStatus(requiredStatus, i); - }); - - this.level.getProfiler().incrementCounter(() -> { -- return "chunkGenerate " + requiredStatus; +- return "chunkGenerate " + String.valueOf(requiredStatus); - }); - Executor executor = (runnable) -> { - this.worldgenMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable)); - }; - -- return completablefuture.thenComposeAsync((either) -> { -- return (CompletionStage) either.map((list) -> { +- return completablefuture.thenComposeAsync((chunkresult) -> { +- List list = (List) chunkresult.orElse(null); // CraftBukkit - decompile error +- +- if (list == null) { +- this.releaseLightTicket(chunkcoordintpair); +- Objects.requireNonNull(chunkresult); +- return CompletableFuture.completedFuture(ChunkResult.error(chunkresult::getError)); +- } else { - try { - ChunkAccess ichunkaccess = (ChunkAccess) list.get(list.size() / 2); - CompletableFuture completablefuture1; - - if (ichunkaccess.getStatus().isOrAfter(requiredStatus)) { -- completablefuture1 = requiredStatus.load(this.level, this.structureTemplateManager, this.lightEngine, (ichunkaccess1) -> { -- return this.protoChunkToFullChunk(holder); +- completablefuture1 = requiredStatus.load(this.worldGenContext, (ichunkaccess1) -> { +- return this.protoChunkToFullChunk(holder, ichunkaccess1); - }, ichunkaccess); - } else { -- completablefuture1 = requiredStatus.generate(executor, this.level, this.generator, this.structureTemplateManager, this.lightEngine, (ichunkaccess1) -> { -- return this.protoChunkToFullChunk(holder); +- completablefuture1 = requiredStatus.generate(this.worldGenContext, executor, (ichunkaccess1) -> { +- return this.protoChunkToFullChunk(holder, ichunkaccess1); - }, list); - } - - this.progressListener.onStatusChange(chunkcoordintpair, requiredStatus); -- return completablefuture1; +- return completablefuture1.thenApply(ChunkResult::of); - } catch (Exception exception) { - exception.getStackTrace(); - CrashReport crashreport = CrashReport.forThrowable(exception, "Exception generating new chunk"); - CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk to be generated"); - +- crashreportsystemdetails.setDetail("Status being generated", () -> { +- return BuiltInRegistries.CHUNK_STATUS.getKey(requiredStatus).toString(); +- }); - crashreportsystemdetails.setDetail("Location", (Object) String.format(Locale.ROOT, "%d,%d", chunkcoordintpair.x, chunkcoordintpair.z)); - crashreportsystemdetails.setDetail("Position hash", (Object) ChunkPos.asLong(chunkcoordintpair.x, chunkcoordintpair.z)); - crashreportsystemdetails.setDetail("Generator", (Object) this.generator); @@ -17008,16 +17147,13 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b - }); - throw new ReportedException(crashreport); - } -- }, (playerchunk_failure) -> { -- this.releaseLightTicket(chunkcoordintpair); -- return CompletableFuture.completedFuture(Either.right(playerchunk_failure)); -- }); +- } - }, executor); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } protected void releaseLightTicket(ChunkPos pos) { -@@ -854,7 +505,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -880,7 +529,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider })); } @@ -17026,7 +17162,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b ChunkStatus chunkstatus1; if (distance == 0) { -@@ -866,7 +517,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -892,7 +541,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return chunkstatus1; } @@ -17035,7 +17171,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b 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) -> { -@@ -882,53 +533,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -908,45 +557,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } checkDupeUUID(world, entity); // Paper - duplicate uuid resolving return !needsRemoval; @@ -17046,66 +17182,58 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } - private CompletableFuture> protoChunkToFullChunk(ChunkHolder chunkHolder) { -- CompletableFuture> completablefuture = chunkHolder.getFutureIfPresentUnchecked(ChunkStatus.FULL.getParent()); + private CompletableFuture protoChunkToFullChunk(ChunkHolder playerchunk, ChunkAccess ichunkaccess) { +- return CompletableFuture.supplyAsync(() -> { +- ChunkPos chunkcoordintpair = playerchunk.getPos(); +- ProtoChunk protochunk = (ProtoChunk) ichunkaccess; +- LevelChunk chunk; - -- return completablefuture.thenApplyAsync((either) -> { -- ChunkStatus chunkstatus = ChunkLevel.generationStatus(chunkHolder.getTicketLevel()); -- -- return !chunkstatus.isOrAfter(ChunkStatus.FULL) ? ChunkHolder.UNLOADED_CHUNK : either.mapLeft((ichunkaccess) -> { -- try (Timing ignored = level.timings.chunkPostLoad.startTimingIfSync()) { // Paper -- ChunkPos chunkcoordintpair = chunkHolder.getPos(); -- ProtoChunk protochunk = (ProtoChunk) ichunkaccess; -- LevelChunk chunk; -- -- if (protochunk instanceof ImposterProtoChunk) { -- chunk = ((ImposterProtoChunk) protochunk).getWrapped(); -- } else { -- chunk = new LevelChunk(this.level, protochunk, (chunk1) -> { -- ChunkMap.postLoadProtoChunk(this.level, protochunk.getEntities()); -- }); -- chunkHolder.replaceProtoChunk(new ImposterProtoChunk(chunk, false)); -- } -- -- chunk.setFullStatus(() -> { -- return ChunkLevel.fullStatus(chunkHolder.getTicketLevel()); +- if (protochunk instanceof ImposterProtoChunk) { +- chunk = ((ImposterProtoChunk) protochunk).getWrapped(); +- } else { +- chunk = new LevelChunk(this.level, protochunk, (chunk1) -> { +- ChunkMap.postLoadProtoChunk(this.level, protochunk.getEntities()); - }); -- chunk.runPostLoad(); -- if (this.entitiesInLevel.add(chunkcoordintpair.toLong())) { -- chunk.setLoaded(true); -- chunk.registerAllBlockEntitiesAfterLevelLoad(); -- chunk.registerTickContainerInLevel(this.level); -- } +- playerchunk.replaceProtoChunk(new ImposterProtoChunk(chunk, false)); +- } - -- return chunk; -- } // Paper +- chunk.setFullStatus(() -> { +- return ChunkLevel.fullStatus(playerchunk.getTicketLevel()); - }); +- chunk.runPostLoad(); +- if (this.entitiesInLevel.add(chunkcoordintpair.toLong())) { +- chunk.setLoaded(true); +- chunk.registerAllBlockEntitiesAfterLevelLoad(); +- chunk.registerTickContainerInLevel(this.level); +- } +- +- return chunk; - }, (runnable) -> { - ProcessorHandle mailbox = this.mainThreadMailbox; -- long i = chunkHolder.getPos().toLong(); +- long i = playerchunk.getPos().toLong(); - -- Objects.requireNonNull(chunkHolder); -- mailbox.tell(ChunkTaskPriorityQueueSorter.message(runnable, i, chunkHolder::getTicketLevel)); +- Objects.requireNonNull(playerchunk); +- mailbox.tell(ChunkTaskPriorityQueueSorter.message(runnable, i, playerchunk::getTicketLevel)); - }); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } // Paper start - duplicate uuid resolving -@@ -971,61 +583,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } +@@ -990,61 +608,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper end - duplicate uuid resolving - public CompletableFuture> prepareTickingChunk(ChunkHolder holder) { -- CompletableFuture, ChunkHolder.ChunkLoadingFailure>> completablefuture = this.getChunkRangeFuture(holder, 1, (i) -> { + + public CompletableFuture> prepareTickingChunk(ChunkHolder holder) { +- CompletableFuture>> completablefuture = this.getChunkRangeFuture(holder, 1, (i) -> { - return ChunkStatus.FULL; - }); -- CompletableFuture> completablefuture1 = completablefuture.thenApplyAsync((either) -> { -- return either.mapLeft((list) -> { +- CompletableFuture> completablefuture1 = completablefuture.thenApplyAsync((chunkresult) -> { +- return chunkresult.map((list) -> { - return (LevelChunk) list.get(list.size() / 2); - }); - }, (runnable) -> { - this.mainThreadMailbox.tell(ChunkTaskPriorityQueueSorter.message(holder, runnable)); -- }).thenApplyAsync((either) -> { -- return either.ifLeft((chunk) -> { +- }).thenApplyAsync((chunkresult) -> { +- return chunkresult.ifSuccess((chunk) -> { - chunk.postProcessGeneration(); - this.level.startTickingChunk(chunk); - CompletableFuture completablefuture2 = holder.getChunkSendSyncFuture(); @@ -17121,7 +17249,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b - }); - }, this.mainThreadExecutor); - -- completablefuture1.handle((either, throwable) -> { +- completablefuture1.handle((chunkresult, throwable) -> { - this.tickingGenerated.getAndIncrement(); - return null; - }); @@ -17144,9 +17272,9 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } - public CompletableFuture> prepareAccessibleChunk(ChunkHolder holder) { -- return this.getChunkRangeFuture(holder, 1, ChunkStatus::getStatusAroundFullChunk).thenApplyAsync((either) -> { -- return either.mapLeft((list) -> { + public CompletableFuture> prepareAccessibleChunk(ChunkHolder holder) { +- return this.getChunkRangeFuture(holder, 1, ChunkStatus::getStatusAroundFullChunk).thenApplyAsync((chunkresult) -> { +- return chunkresult.map((list) -> { - return (LevelChunk) list.get(list.size() / 2); - }); - }, (runnable) -> { @@ -17156,7 +17284,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } public int getTickingGenerated() { -@@ -1033,130 +600,52 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1052,96 +625,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } private boolean saveChunkIfNeeded(ChunkHolder chunkHolder) { @@ -17200,7 +17328,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b - try { - ChunkStatus chunkstatus = chunk.getStatus(); - -- if (chunkstatus.getChunkType() != ChunkStatus.ChunkType.LEVELCHUNK) { +- if (chunkstatus.getChunkType() != ChunkType.LEVELCHUNK) { - if (this.isExistingChunkFull(chunkcoordintpair)) { - return false; - } @@ -17213,11 +17341,15 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b - this.level.getProfiler().incrementCounter("chunkSave"); - CompoundTag nbttagcompound = ChunkSerializer.write(this.level, chunk); - -- this.write(chunkcoordintpair, nbttagcompound); +- this.write(chunkcoordintpair, nbttagcompound).exceptionallyAsync((throwable) -> { +- this.level.getServer().reportChunkSaveFailure(chunkcoordintpair); +- return null; +- }, this.mainThreadExecutor); - this.markPosition(chunkcoordintpair, chunkstatus.getChunkType()); - return true; - } catch (Exception exception) { - ChunkMap.LOGGER.error("Failed to save chunk {},{}", new Object[]{chunkcoordintpair.x, chunkcoordintpair.z, exception}); +- this.level.getServer().reportChunkSaveFailure(chunkcoordintpair); - return false; - } - } @@ -17243,39 +17375,40 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b - this.markPositionReplaceable(pos); - return false; - } -+ 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; +- +- ChunkType chunktype = ChunkSerializer.getChunkTypeFromTag(nbttagcompound); +- +- return this.markPosition(pos, chunktype) == 1; - } -+ public void setSendViewDistance(int distance) { -+ this.level.playerChunkLoader.setSendDistance(distance); ++ throw new UnsupportedOperationException(); // Paper - rewrite chunk system } -+ // Paper end - replace player loader system public void setServerViewDistance(int watchDistance) { // Paper - public - int j = Mth.clamp(watchDistance, 2, 32); +@@ -1149,37 +641,36 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider if (j != this.serverViewDistance) { this.serverViewDistance = j; - this.distanceManager.updatePlayerTickets(this.serverViewDistance); - Iterator iterator = this.playerMap.getAllPlayers().iterator(); -- ++ this.level.playerChunkLoader.setLoadDistance(this.serverViewDistance + 1); // Paper - replace player loader system ++ } + - while (iterator.hasNext()) { - ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -- ++ } + - this.updateChunkTracking(entityplayer); - } -+ this.level.playerChunkLoader.setLoadDistance(this.serverViewDistance + 1); // Paper - replace player loader system - } +- } ++ // 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 int getPlayerViewDistance(ServerPlayer player) { // Paper - public - return Mth.clamp(player.requestedViewDistance(), 2, this.serverViewDistance); @@ -17303,7 +17436,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } @Nullable -@@ -1179,30 +668,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1202,30 +693,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } void dumpChunks(Writer writer) throws IOException { @@ -17334,8 +17467,8 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } - private static String printFuture(CompletableFuture> future) { -@@ -1221,6 +687,35 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + private static String printFuture(CompletableFuture> future) { +@@ -1240,6 +708,32 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } @@ -17343,35 +17476,32 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b + @Nullable + @Override + public CompoundTag readSync(ChunkPos chunkcoordintpair) throws IOException { -+ // Paper start - rewrite chunk system + if (!io.papermc.paper.chunk.system.io.RegionFileIOThread.isRegionFileThread()) { + return io.papermc.paper.chunk.system.io.RegionFileIOThread.loadData( + this.level, chunkcoordintpair.x, chunkcoordintpair.z, io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.CHUNK_DATA, + io.papermc.paper.chunk.system.io.RegionFileIOThread.getIOBlockingPriorityForCurrentThread() + ); + } -+ // Paper end - rewrite chunk system + return super.readSync(chunkcoordintpair); + } + + @Override -+ public void write(ChunkPos chunkcoordintpair, CompoundTag nbttagcompound) throws IOException { -+ // Paper start - rewrite chunk system ++ public CompletableFuture write(ChunkPos chunkcoordintpair, CompoundTag nbttagcompound) throws IOException { + if (!io.papermc.paper.chunk.system.io.RegionFileIOThread.isRegionFileThread()) { + io.papermc.paper.chunk.system.io.RegionFileIOThread.scheduleSave( + this.level, chunkcoordintpair.x, chunkcoordintpair.z, nbttagcompound, + io.papermc.paper.chunk.system.io.RegionFileIOThread.RegionFileType.CHUNK_DATA); -+ return; ++ return null; + } -+ // Paper end - rewrite chunk system + super.write(chunkcoordintpair, nbttagcompound); ++ return null; + } + // Paper end + private CompletableFuture> readChunk(ChunkPos chunkPos) { return this.read(chunkPos).thenApplyAsync((optional) -> { return optional.map((nbttagcompound) -> this.upgradeChunkTag(nbttagcompound, chunkPos)); // CraftBukkit -@@ -1321,8 +816,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1340,8 +834,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.distanceManager.addPlayer(SectionPos.of((EntityAccess) player), player); } @@ -17381,7 +17511,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b this.addPlayerToDistanceMaps(player); // Paper - distance maps } else { SectionPos sectionposition = player.getLastSectionPos(); -@@ -1333,7 +827,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1352,7 +845,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } this.removePlayerFromDistanceMaps(player); // Paper - distance maps @@ -17390,7 +17520,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } } -@@ -1381,73 +875,30 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1400,71 +893,30 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.playerMap.unIgnorePlayer(player); } @@ -17406,9 +17536,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b - int i = this.getPlayerViewDistance(player); - ChunkTrackingView chunktrackingview = player.getChunkTrackingView(); - -- if (chunktrackingview instanceof ChunkTrackingView.Positioned) { -- ChunkTrackingView.Positioned chunktrackingview_a = (ChunkTrackingView.Positioned) chunktrackingview; -- +- if (chunktrackingview instanceof ChunkTrackingView.Positioned chunktrackingview_a) { - if (chunktrackingview_a.center().equals(chunkcoordintpair) && chunktrackingview_a.viewDistance() == i) { - return; - } @@ -17474,7 +17602,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } public void addEntity(Entity entity) { -@@ -1520,13 +971,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1535,13 +987,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } protected void tick() { @@ -17489,7 +17617,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b List list = Lists.newArrayList(); List list1 = this.level.players(); -@@ -1635,16 +1080,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1648,16 +1094,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public void waitForLightBeforeSending(ChunkPos centerPos, int radius) { @@ -17507,7 +17635,7 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b } public class ChunkDistanceManager extends DistanceManager { // Paper - public -@@ -1655,7 +1091,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1668,7 +1105,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Override protected boolean isChunkToRemove(long pos) { @@ -17517,10 +17645,10 @@ index ee16a8ef86705dc89b1cc300c06cf683431c7ef3..4549b32a3d848e4e84334e889dbc9c6b @Nullable diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e153ca1fb 100644 +index 7a48ae2ba962ff56d0abff581b51f28b48bd9aae..ed5154e41ca858f4d6b4d1c276c66831c038d2a6 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -39,67 +39,29 @@ import org.slf4j.Logger; +@@ -38,65 +38,28 @@ import org.slf4j.Logger; public abstract class DistanceManager { @@ -17566,7 +17694,7 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e protected void purgeStaleTickets() { - ++this.ticketTickCounter; -- ObjectIterator objectiterator = this.tickets.long2ObjectEntrySet().fastIterator(); +- ObjectIterator>>> objectiterator = this.tickets.long2ObjectEntrySet().fastIterator(); - - while (objectiterator.hasNext()) { - Entry>> entry = (Entry) objectiterator.next(); @@ -17594,11 +17722,9 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e - + this.getChunkHolderManager().tick(); // Paper - rewrite chunk system } -- + private static int getTicketLevelAt(SortedArraySet> tickets) { - return !tickets.isEmpty() ? ((Ticket) tickets.first()).getTicketLevel() : ChunkLevel.MAX_LEVEL + 1; - } -@@ -113,108 +75,25 @@ public abstract class DistanceManager { +@@ -112,108 +75,25 @@ public abstract class DistanceManager { protected abstract ChunkHolder updateChunkScheduling(long pos, int level, @Nullable ChunkHolder holder, int k); public boolean runAllUpdates(ChunkMap chunkStorage) { @@ -17649,9 +17775,9 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e - throw new IllegalStateException(); - } - -- CompletableFuture> completablefuture = playerchunk.getEntityTickingChunkFuture(); +- CompletableFuture> completablefuture = playerchunk.getEntityTickingChunkFuture(); - -- completablefuture.thenAccept((either) -> { +- completablefuture.thenAccept((chunkresult) -> { - this.mainThreadExecutor.execute(() -> { - this.ticketThrottlerReleaser.tell(ChunkTaskPriorityQueueSorter.release(() -> { - }, j, false)); @@ -17714,7 +17840,7 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e } public void addRegionTicket(TicketType type, ChunkPos pos, int radius, T argument) { -@@ -223,13 +102,7 @@ public abstract class DistanceManager { +@@ -222,13 +102,7 @@ public abstract class DistanceManager { } public boolean addRegionTicketAtDistance(TicketType tickettype, ChunkPos chunkcoordintpair, int i, T t0) { @@ -17729,7 +17855,7 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e } public void removeRegionTicket(TicketType type, ChunkPos pos, int radius, T argument) { -@@ -238,31 +111,21 @@ public abstract class DistanceManager { +@@ -237,31 +111,21 @@ public abstract class DistanceManager { } public boolean removeRegionTicketAtDistance(TicketType tickettype, ChunkPos chunkcoordintpair, int i, T t0) { @@ -17766,7 +17892,7 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e } } -@@ -271,12 +134,10 @@ public abstract class DistanceManager { +@@ -270,12 +134,10 @@ public abstract class DistanceManager { ChunkPos chunkcoordintpair = pos.chunk(); long i = chunkcoordintpair.toLong(); @@ -17782,7 +17908,7 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e } public void removePlayer(SectionPos pos, ServerPlayer player) { -@@ -289,40 +150,44 @@ public abstract class DistanceManager { +@@ -288,40 +150,44 @@ public abstract class DistanceManager { if (objectset == null || objectset.isEmpty()) { // Paper this.playersPerChunk.remove(i); this.naturalSpawnChunkCounter.update(i, Integer.MAX_VALUE, false); @@ -17843,7 +17969,7 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e } public int getNaturalSpawnChunkCount() { -@@ -336,103 +201,28 @@ public abstract class DistanceManager { +@@ -335,103 +201,26 @@ public abstract class DistanceManager { } public String getDebugStatus() { @@ -17854,8 +17980,7 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e - private void dumpTickets(String path) { - try { - FileOutputStream fileoutputstream = new FileOutputStream(new File(path)); -+ // Paper - rewrite chunk system - +- - try { - ObjectIterator objectiterator = this.tickets.long2ObjectEntrySet().iterator(); - @@ -17867,7 +17992,7 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e - while (iterator.hasNext()) { - Ticket ticket = (Ticket) iterator.next(); - -- fileoutputstream.write((chunkcoordintpair.x + "\t" + chunkcoordintpair.z + "\t" + ticket.getType() + "\t" + ticket.getTicketLevel() + "\t\n").getBytes(StandardCharsets.UTF_8)); +- fileoutputstream.write((chunkcoordintpair.x + "\t" + chunkcoordintpair.z + "\t" + String.valueOf(ticket.getType()) + "\t" + ticket.getTicketLevel() + "\t\n").getBytes(StandardCharsets.UTF_8)); - } - } - } catch (Throwable throwable) { @@ -17891,11 +18016,11 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e - TickingTracker tickingTracker() { - return this.tickingTicketsTracker; - } -+ // Paper - replace player chunk loader ++ // Paper - rewrite chunk system public void removeTicketsOnClosing() { - ImmutableSet> immutableset = ImmutableSet.of(TicketType.UNKNOWN, TicketType.POST_TELEPORT, TicketType.LIGHT, TicketType.FUTURE_AWAIT, TicketType.CHUNK_RELIGHT, ca.spottedleaf.starlight.common.light.StarLightInterface.CHUNK_WORK_TICKET); // Paper - add additional tickets to preserve -- ObjectIterator objectiterator = this.tickets.long2ObjectEntrySet().fastIterator(); +- ObjectIterator>>> objectiterator = this.tickets.long2ObjectEntrySet().fastIterator(); - - while (objectiterator.hasNext()) { - Entry>> entry = (Entry) objectiterator.next(); @@ -17954,7 +18079,7 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e private class ChunkTicketTracker extends ChunkTracker { private static final int MAX_LEVEL = ChunkLevel.MAX_LEVEL + 1; -@@ -479,6 +269,7 @@ public abstract class DistanceManager { +@@ -478,6 +267,7 @@ public abstract class DistanceManager { return this.runUpdates(distance); } } @@ -17962,7 +18087,7 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e private class FixedPlayerDistanceChunkTracker extends ChunkTracker { -@@ -558,6 +349,7 @@ public abstract class DistanceManager { +@@ -557,6 +347,7 @@ public abstract class DistanceManager { } } @@ -17970,17 +18095,17 @@ index 8e8e3896040241bba8fd15f4d6d046567847f741..c80a625f7289e3bb33c6851d2072957e private class PlayerTicketTracker extends DistanceManager.FixedPlayerDistanceChunkTracker { private int viewDistance = 0; -@@ -653,4 +445,5 @@ public abstract class DistanceManager { +@@ -652,4 +443,5 @@ public abstract class DistanceManager { return distance <= this.viewDistance; } } + */ // Paper - rewrite chunk system } diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7a92cd5dd 100644 +index 2d9d4d06b75873f888ef4d8f5779a52706f821a8..f74efe41cd0da2f9749fc96fb9e0f7cf237ad1c6 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -73,7 +73,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -71,7 +71,7 @@ public class ServerChunkCache extends ChunkSource { public final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet entityTickingChunks = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true); final com.destroystokyo.paper.util.concurrent.WeakSeqLock loadedChunkMapSeqLock = new com.destroystokyo.paper.util.concurrent.WeakSeqLock(); final it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap loadedChunkMap = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>(8192, 0.5f); @@ -17989,7 +18114,7 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 private final LevelChunk[] lastLoadedChunks = new LevelChunk[4 * 4]; // Paper end -@@ -197,7 +197,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -195,7 +195,7 @@ public class ServerChunkCache extends ChunkSource { public LevelChunk getChunkAtIfLoadedImmediately(int x, int z) { long k = ChunkPos.asLong(x, z); @@ -17998,7 +18123,7 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 return this.getChunkAtIfLoadedMainThread(x, z); } -@@ -249,7 +249,8 @@ public class ServerChunkCache extends ChunkSource { +@@ -247,7 +247,8 @@ public class ServerChunkCache extends ChunkSource { @Nullable @Override public ChunkAccess getChunk(int x, int z, ChunkStatus leastStatus, boolean create) { @@ -18008,13 +18133,14 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 return (ChunkAccess) CompletableFuture.supplyAsync(() -> { return this.getChunk(x, z, leastStatus, create); }, this.mainThreadProcessor).join(); -@@ -267,24 +268,19 @@ public class ServerChunkCache extends ChunkSource { - - ChunkAccess ichunkaccess; +@@ -263,15 +264,7 @@ public class ServerChunkCache extends ChunkSource { + gameprofilerfiller.incrementCounter("getChunk"); + long k = ChunkPos.asLong(x, z); - for (int l = 0; l < 4; ++l) { - if (k == this.lastChunkPos[l] && leastStatus == this.lastChunkStatus[l]) { -- ichunkaccess = this.lastChunk[l]; +- ChunkAccess ichunkaccess = this.lastChunk[l]; +- - if (ichunkaccess != null) { // CraftBukkit - the chunk can become accessible in the meantime TODO for non-null chunks it might also make sense to check that the chunk's state hasn't changed in the meantime - return ichunkaccess; - } @@ -18023,9 +18149,8 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 + // Paper - rewrite chunk system - there are no correct callbacks to remove items from cache in the new chunk system gameprofilerfiller.incrementCounter("getChunkCacheMiss"); -- CompletableFuture> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create); -+ CompletableFuture> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create, true); // Paper - ServerChunkCache.MainThreadExecutor chunkproviderserver_b = this.mainThreadProcessor; + CompletableFuture> completablefuture = this.getChunkFutureMainThread(x, z, leastStatus, create); +@@ -279,9 +272,11 @@ public class ServerChunkCache extends ChunkSource { Objects.requireNonNull(completablefuture); if (!completablefuture.isDone()) { // Paper @@ -18036,8 +18161,8 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 + io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.popChunkWait(); // Paper - rewrite chunk system this.level.timings.syncChunkLoad.stopTiming(); // Paper } // Paper - ichunkaccess = (ChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> { -@@ -304,7 +300,7 @@ public class ServerChunkCache extends ChunkSource { + ChunkResult chunkresult = (ChunkResult) completablefuture.join(); +@@ -299,7 +294,7 @@ public class ServerChunkCache extends ChunkSource { @Nullable @Override public LevelChunk getChunkNow(int chunkX, int chunkZ) { @@ -18046,19 +18171,21 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 return null; } else { return this.getChunkAtIfLoadedMainThread(chunkX, chunkZ); // Paper - Perf: Optimise getChunkAt calls for loaded chunks -@@ -318,7 +314,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -313,7 +308,7 @@ public class ServerChunkCache extends ChunkSource { } - public CompletableFuture> getChunkFuture(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { + public CompletableFuture> getChunkFuture(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { - boolean flag1 = Thread.currentThread() == this.mainThread; + boolean flag1 = io.papermc.paper.util.TickThread.isTickThread(); // Paper - rewrite chunk system CompletableFuture completablefuture; if (flag1) { -@@ -339,47 +335,52 @@ public class ServerChunkCache extends ChunkSource { +@@ -333,48 +328,54 @@ public class ServerChunkCache extends ChunkSource { + return completablefuture; } - private CompletableFuture> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { ++ + private CompletableFuture> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { - ChunkPos chunkcoordintpair = new ChunkPos(chunkX, chunkZ); - long k = chunkcoordintpair.toLong(); - int l = ChunkLevel.byStatus(leastStatus); @@ -18066,7 +18193,7 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 + // Paper start - add isUrgent - old sig left in place for dirty nms plugins + return getChunkFutureMainThread(chunkX, chunkZ, leastStatus, create, false); + } -+ private CompletableFuture> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create, boolean isUrgent) { ++ private CompletableFuture> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create, boolean isUrgent) { + // Paper start - rewrite chunk system + io.papermc.paper.util.TickThread.ensureTickThread(this.level, chunkX, chunkZ, "Scheduling chunk load off-main"); + int minLevel = ChunkLevel.byStatus(leastStatus); @@ -18099,12 +18226,12 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 + io.papermc.paper.chunk.system.scheduling.NewChunkHolder.ChunkCompletion chunkCompletion = chunkHolder == null ? null : chunkHolder.getLastChunkCompletion(); + if (needsFullScheduling || chunkCompletion == null || !chunkCompletion.genStatus().isOrAfter(leastStatus)) { + // schedule -+ CompletableFuture> ret = new CompletableFuture<>(); ++ CompletableFuture> ret = new CompletableFuture<>(); + Consumer complete = (ChunkAccess chunk) -> { + if (chunk == null) { -+ ret.complete(Either.right(ChunkHolder.ChunkLoadingFailure.UNLOADED)); ++ ret.complete(ChunkResult.error("Unexpected chunk unload")); + } else { -+ ret.complete(Either.left(chunk)); ++ ret.complete(ChunkResult.of(chunk)); } - } - } @@ -18123,7 +18250,7 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 + return ret; + } else { + // can return now -+ return CompletableFuture.completedFuture(Either.left(chunkCompletion.chunk())); ++ return CompletableFuture.completedFuture(ChunkResult.of(chunkCompletion.chunk())); + } + // Paper end - rewrite chunk system } @@ -18140,7 +18267,7 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 } @Nullable -@@ -391,22 +392,13 @@ public class ServerChunkCache extends ChunkSource { +@@ -386,22 +387,13 @@ public class ServerChunkCache extends ChunkSource { if (playerchunk == null) { return null; } else { @@ -18148,10 +18275,10 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 - - while (true) { - ChunkStatus chunkstatus = (ChunkStatus) ServerChunkCache.CHUNK_STATUSES.get(l); -- Optional optional = ((Either) playerchunk.getFutureIfPresentUnchecked(chunkstatus).getNow(ChunkHolder.UNLOADED_CHUNK)).left(); +- ChunkAccess ichunkaccess = (ChunkAccess) ((ChunkResult) playerchunk.getFutureIfPresentUnchecked(chunkstatus).getNow(ChunkHolder.UNLOADED_CHUNK)).orElse((Object) null); - -- if (optional.isPresent()) { -- return (LightChunk) optional.get(); +- if (ichunkaccess != null) { +- return ichunkaccess; - } - - if (chunkstatus == ChunkStatus.INITIALIZE_LIGHT.getParent()) { @@ -18169,7 +18296,7 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 } } -@@ -420,15 +412,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -415,15 +407,7 @@ public class ServerChunkCache extends ChunkSource { } public boolean runDistanceManagerUpdates() { // Paper - public @@ -18186,21 +18313,13 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 } // Paper start -@@ -438,17 +422,10 @@ public class ServerChunkCache extends ChunkSource { +@@ -433,9 +417,10 @@ public class ServerChunkCache extends ChunkSource { // Paper end public boolean isPositionTicking(long pos) { - ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); - -- if (playerchunk == null) { -- return false; -- } else if (!this.level.shouldTickBlocksAt(pos)) { -- return false; -- } else { -- Either either = (Either) playerchunk.getTickingChunkFuture().getNow(null); // CraftBukkit - decompile error -- -- return either != null && either.left().isPresent(); -- } +- return playerchunk == null ? false : (!this.level.shouldTickBlocksAt(pos) ? false : ((ChunkResult) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).isSuccess()); + // Paper start - replace player chunk loader system + ChunkHolder holder = this.chunkMap.getVisibleChunkIfPresent(pos); + return holder != null && holder.isTickingReady(); @@ -18208,7 +18327,7 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 } public void save(boolean flush) { -@@ -464,17 +441,13 @@ public class ServerChunkCache extends ChunkSource { +@@ -451,17 +436,13 @@ public class ServerChunkCache extends ChunkSource { this.close(true); } @@ -18229,7 +18348,7 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 this.level.getProfiler().push("purge"); this.distanceManager.purgeStaleTickets(); this.runDistanceManagerUpdates(); -@@ -495,6 +468,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -485,6 +466,7 @@ public class ServerChunkCache extends ChunkSource { this.level.getProfiler().popPush("chunks"); if (tickChunks) { this.level.timings.chunks.startTiming(); // Paper - timings @@ -18237,13 +18356,13 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 this.tickChunks(); this.level.timings.chunks.stopTiming(); // Paper - timings this.chunkMap.tick(); -@@ -597,7 +571,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -587,7 +569,12 @@ public class ServerChunkCache extends ChunkSource { ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); if (playerchunk != null) { -- ((Either) playerchunk.getFullChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left().ifPresent(chunkConsumer); +- ((ChunkResult) playerchunk.getFullChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).ifSuccess(chunkConsumer); + // Paper start - rewrite chunk system -+ LevelChunk chunk = playerchunk.getFullChunk(); ++ LevelChunk chunk = playerchunk.getFullChunkNow(); + if (chunk != null) { + chunkConsumer.accept(chunk); + } @@ -18251,7 +18370,7 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 } } -@@ -763,17 +742,10 @@ public class ServerChunkCache extends ChunkSource { +@@ -753,17 +740,10 @@ public class ServerChunkCache extends ChunkSource { @Override // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task public boolean pollTask() { @@ -18271,19 +18390,19 @@ index 8a118a7b2878d3c99dadfa97e2ae58fda2b3f93b..9bb4223fbb665211df11dc89fcd13cb7 } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73dfbf7bb0 100644 +index 06c185eae0063ff1b1714be0a5c7b0cdd538816b..e517037047013d0d55771fc08af9e03c4d334823 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -195,7 +195,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - private final MinecraftServer server; +@@ -199,7 +199,7 @@ public class ServerLevel extends Level implements WorldGenLevel { public final PrimaryLevelData serverLevelData; // CraftBukkit - type + private int lastSpawnChunkRadius; final EntityTickList entityTickList; - public final PersistentEntitySectionManager entityManager; + //public final PersistentEntitySectionManager entityManager; // Paper - rewrite chunk system private final GameEventDispatcher gameEventDispatcher; public boolean noSave; private final SleepStatus sleepStatus; -@@ -263,50 +263,65 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -268,50 +268,65 @@ public class ServerLevel extends Level implements WorldGenLevel { return true; } @@ -18308,7 +18427,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 + } + + public final void loadChunksAsync(BlockPos pos, int radiusBlocks, -+ net.minecraft.world.level.chunk.ChunkStatus chunkStatus, ++ net.minecraft.world.level.chunk.status.ChunkStatus chunkStatus, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority priority, + java.util.function.Consumer> onLoad) { + loadChunksAsync( @@ -18323,11 +18442,11 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 + public final void loadChunksAsync(int minChunkX, int maxChunkX, int minChunkZ, int maxChunkZ, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority priority, + java.util.function.Consumer> onLoad) { -+ this.loadChunksAsync(minChunkX, maxChunkX, minChunkZ, maxChunkZ, net.minecraft.world.level.chunk.ChunkStatus.FULL, priority, onLoad); ++ this.loadChunksAsync(minChunkX, maxChunkX, minChunkZ, maxChunkZ, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, priority, onLoad); + } + + public final void loadChunksAsync(int minChunkX, int maxChunkX, int minChunkZ, int maxChunkZ, -+ net.minecraft.world.level.chunk.ChunkStatus chunkStatus, ++ net.minecraft.world.level.chunk.status.ChunkStatus chunkStatus, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority priority, + java.util.function.Consumer> onLoad) { List ret = new java.util.ArrayList<>(); @@ -18354,15 +18473,15 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 - Long holderIdentifier = Long.valueOf(chunkProvider.chunkFutureAwaitCounter++); + Long holderIdentifier = Long.valueOf(chunkProvider.chunkFutureAwaitCounter.getAndIncrement()); + -+ int ticketLevel = 33 + net.minecraft.world.level.chunk.ChunkStatus.getDistance(chunkStatus); ++ int ticketLevel = 33 + net.minecraft.world.level.chunk.status.ChunkStatus.getDistance(chunkStatus); 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 ++ synchronized (ret) { 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) { @@ -18376,11 +18495,11 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 chunkProvider.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, ticketLevel, chunkPos); chunkProvider.removeTicketAtLevel(TicketType.FUTURE_AWAIT, chunkPos, ticketLevel, holderIdentifier); -@@ -318,12 +333,228 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -323,12 +338,228 @@ public class ServerLevel extends Level implements WorldGenLevel { for (int cx = minChunkX; cx <= maxChunkX; ++cx) { for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) { io.papermc.paper.chunk.system.ChunkSystem.scheduleChunkLoad( -- this, cx, cz, net.minecraft.world.level.chunk.ChunkStatus.FULL, true, priority, consumer +- this, cx, cz, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, true, priority, consumer + this, cx, cz, chunkStatus, true, priority, consumer ); } @@ -18509,7 +18628,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 + + private final java.util.concurrent.atomic.AtomicLong nonFullSyncLoadIdGenerator = new java.util.concurrent.atomic.AtomicLong(); + -+ private ChunkAccess getIfAboveStatus(int chunkX, int chunkZ, net.minecraft.world.level.chunk.ChunkStatus status) { ++ private ChunkAccess getIfAboveStatus(int chunkX, int chunkZ, net.minecraft.world.level.chunk.status.ChunkStatus status) { + io.papermc.paper.chunk.system.scheduling.NewChunkHolder loaded = + this.chunkTaskScheduler.chunkHolderManager.getChunkHolder(chunkX, chunkZ); + io.papermc.paper.chunk.system.scheduling.NewChunkHolder.ChunkCompletion loadedCompletion; @@ -18521,8 +18640,8 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 + } + + @Override -+ public ChunkAccess syncLoadNonFull(int chunkX, int chunkZ, net.minecraft.world.level.chunk.ChunkStatus status) { -+ if (status == null || status.isOrAfter(net.minecraft.world.level.chunk.ChunkStatus.FULL)) { ++ public ChunkAccess syncLoadNonFull(int chunkX, int chunkZ, net.minecraft.world.level.chunk.status.ChunkStatus status) { ++ if (status == null || status.isOrAfter(net.minecraft.world.level.chunk.status.ChunkStatus.FULL)) { + throw new IllegalArgumentException("Status: " + status); + } + ChunkAccess loaded = this.getIfAboveStatus(chunkX, chunkZ, status); @@ -18531,7 +18650,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 + } + + Long ticketId = Long.valueOf(this.nonFullSyncLoadIdGenerator.getAndIncrement()); -+ int ticketLevel = 33 + net.minecraft.world.level.chunk.ChunkStatus.getDistance(status); ++ int ticketLevel = 33 + net.minecraft.world.level.chunk.status.ChunkStatus.getDistance(status); + this.chunkTaskScheduler.chunkHolderManager.addTicketAtLevel( + TicketType.NON_FULL_SYNC_LOAD, chunkX, chunkZ, ticketLevel, ticketId + ); @@ -18607,12 +18726,12 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 // Paper start - optimise getPlayerByUUID @Nullable -@@ -376,16 +607,16 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -382,16 +613,16 @@ public class ServerLevel extends Level implements WorldGenLevel { // CraftBukkit end boolean flag2 = minecraftserver.forceSynchronousWrites(); DataFixer datafixer = minecraftserver.getFixerUpper(); -- EntityPersistentStorage entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver); -+ this.entityStorage = new EntityRegionFileStorage(convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), flag2); // Paper - rewrite chunk system //EntityPersistentStorage entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver); +- EntityPersistentStorage entitypersistentstorage = new EntityStorage(new SimpleRegionStorage(new RegionStorageInfo(convertable_conversionsession.getLevelId(), resourcekey, "entities"), convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, DataFixTypes.ENTITY_CHUNK), this, minecraftserver); ++ this.entityStorage = new EntityRegionFileStorage(convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), flag2); // Paper - rewrite chunk system // EntityPersistentStorage entitypersistentstorage = new EntityStorage(new SimpleRegionStorage(new RegionStorageInfo(convertable_conversionsession.getLevelId(), resourcekey, "entities"), convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, DataFixTypes.ENTITY_CHUNK), this, minecraftserver); - this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage); + // this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage, this.entitySliceManager); // Paper // Paper - rewrite chunk system @@ -18629,7 +18748,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 return minecraftserver.overworld().getDataStorage(); }); this.chunkSource.getGeneratorState().ensureStructuresGenerated(); -@@ -414,6 +645,9 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -420,6 +651,9 @@ public class ServerLevel extends Level implements WorldGenLevel { return (RandomSequences) this.getDataStorage().computeIfAbsent(RandomSequences.factory(l), "random_sequences"); }); this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit @@ -18639,7 +18758,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 } // Paper start -@@ -546,7 +780,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -552,7 +786,7 @@ public class ServerLevel extends Level implements WorldGenLevel { gameprofilerfiller.push("checkDespawn"); entity.checkDespawn(); gameprofilerfiller.pop(); @@ -18648,7 +18767,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 Entity entity1 = entity.getVehicle(); if (entity1 != null) { -@@ -571,13 +805,16 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -577,13 +811,16 @@ public class ServerLevel extends Level implements WorldGenLevel { } gameprofilerfiller.push("entityManagement"); @@ -18667,7 +18786,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 } protected void tickTime() { -@@ -1054,6 +1291,11 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1060,6 +1297,11 @@ public class ServerLevel extends Level implements WorldGenLevel { } public void save(@Nullable ProgressListener progressListener, boolean flush, boolean savingDisabled) { @@ -18679,7 +18798,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 ServerChunkCache chunkproviderserver = this.getChunkSource(); if (!savingDisabled) { -@@ -1069,16 +1311,13 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1075,16 +1317,13 @@ public class ServerLevel extends Level implements WorldGenLevel { } timings.worldSaveChunks.startTiming(); // Paper @@ -18700,7 +18819,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 // CraftBukkit start - moved from MinecraftServer.saveChunks ServerLevel worldserver1 = this; -@@ -1214,7 +1453,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1220,7 +1459,7 @@ public class ServerLevel extends Level implements WorldGenLevel { this.removePlayerImmediately((ServerPlayer) entity, Entity.RemovalReason.DISCARDED); } @@ -18709,7 +18828,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 } // CraftBukkit start -@@ -1245,7 +1484,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1251,7 +1490,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } // CraftBukkit end @@ -18718,7 +18837,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 } } -@@ -1257,10 +1496,10 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1263,10 +1502,10 @@ public class ServerLevel extends Level implements WorldGenLevel { public boolean tryAddFreshEntityWithPassengers(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { // CraftBukkit end Stream stream = entity.getSelfAndPassengers().map(Entity::getUUID); // CraftBukkit - decompile error @@ -18732,7 +18851,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 return false; } else { this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit -@@ -1894,7 +2133,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1852,7 +2091,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } } @@ -18741,7 +18860,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 bufferedwriter.write(String.format(Locale.ROOT, "block_entity_tickers: %d\n", this.blockEntityTickers.size())); bufferedwriter.write(String.format(Locale.ROOT, "block_ticks: %d\n", this.getBlockTicks().count())); bufferedwriter.write(String.format(Locale.ROOT, "fluid_ticks: %d\n", this.getFluidTicks().count())); -@@ -1943,7 +2182,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1901,7 +2140,7 @@ public class ServerLevel extends Level implements WorldGenLevel { BufferedWriter bufferedwriter2 = Files.newBufferedWriter(path1); try { @@ -18750,7 +18869,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 } catch (Throwable throwable4) { if (bufferedwriter2 != null) { try { -@@ -1964,7 +2203,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -1922,7 +2161,7 @@ public class ServerLevel extends Level implements WorldGenLevel { BufferedWriter bufferedwriter3 = Files.newBufferedWriter(path2); try { @@ -18759,7 +18878,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 } catch (Throwable throwable6) { if (bufferedwriter3 != null) { try { -@@ -2106,7 +2345,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2064,7 +2303,7 @@ public class ServerLevel extends Level implements WorldGenLevel { @VisibleForTesting public String getWatchdogStats() { @@ -18768,7 +18887,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 return BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString(); }), this.blockEntityTickers.size(), ServerLevel.getTypeCount(this.blockEntityTickers, TickingBlockEntity::getType), this.getBlockTicks().count(), this.getFluidTicks().count(), this.gatherChunkSourceStats()); } -@@ -2166,15 +2405,15 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2124,15 +2363,15 @@ public class ServerLevel extends Level implements WorldGenLevel { @Override public LevelEntityGetter getEntities() { org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot @@ -18789,7 +18908,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 } public void startTickingChunk(LevelChunk chunk) { -@@ -2190,34 +2429,49 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2152,34 +2391,49 @@ public class ServerLevel extends Level implements WorldGenLevel { @Override public void close() throws IOException { super.close(); @@ -18846,7 +18965,7 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 } @Override -@@ -2238,7 +2492,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -2205,7 +2459,7 @@ public class ServerLevel extends Level implements WorldGenLevel { CrashReportCategory crashreportsystemdetails = super.fillReportDetails(report); crashreportsystemdetails.setDetail("Loaded entity count", () -> { @@ -18856,10 +18975,10 @@ index 9816913ad729fd39c173364b92e5db06a733bc55..a3881964bad0cab8f480eda634216d73 return crashreportsystemdetails; } diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index bd6c60ebfc76d19313bf01048268f8ce7e6603c5..18356db5d998dccb9e645a9ee0bebc5cbbfa5f7a 100644 +index bee8cc19d7912d2ab1b731c47cf7e31d21d61866..65e6623c2d1a6cf48729f78948fc48e82057114c 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -276,6 +276,50 @@ public class ServerPlayer extends Player { +@@ -292,6 +292,50 @@ public class ServerPlayer extends Player { public @Nullable String clientBrandName = null; // Paper - Brand support public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event @@ -18911,10 +19030,10 @@ index bd6c60ebfc76d19313bf01048268f8ce7e6603c5..18356db5d998dccb9e645a9ee0bebc5c 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 -index 3229bb8dfb9f39e5fa1c8d91cb58057764cd4abb..17b624294fc0cab2976e3804e6c9a24b91a0e3aa 100644 +index f206df06a7d8895175db31d4a840d7467ffe826f..8ef22f8f0d6da49247a90152e5cfa9ffc7f596a4 100644 --- a/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java +++ b/src/main/java/net/minecraft/server/level/ThreadedLevelLightEngine.java -@@ -37,15 +37,12 @@ import net.minecraft.world.level.chunk.ChunkStatus; +@@ -37,15 +37,12 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; public class ThreadedLevelLightEngine extends LevelLightEngine implements AutoCloseable { public static final int DEFAULT_BATCH_SIZE = 1000; private static final Logger LOGGER = LogUtils.getLogger(); @@ -19147,10 +19266,10 @@ index 6051e5f272838ef23276a90e21c2fc821ca155d1..658e63ebde81dc14c8ab5850fb246dc0 public static TicketType create(String name, Comparator argumentComparator) { return new TicketType<>(name, argumentComparator, 0L); diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -index c3e7bd8865cc8990fc59f1ff0dfc1697cbb5ca49..5ece375eaf6bcc61864997a389bb5e24625e4505 100644 +index b17eb5c228264715bdf58895e4e7a3910a13c6e9..9c066b1dda5912d7aaf50df381cc4809bedf0604 100644 --- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java +++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -@@ -535,4 +535,21 @@ public class WorldGenRegion implements WorldGenLevel { +@@ -543,4 +543,21 @@ public class WorldGenRegion implements WorldGenLevel { public long nextSubTickCount() { return this.subTickCount.getAndIncrement(); } @@ -19173,7 +19292,7 @@ index c3e7bd8865cc8990fc59f1ff0dfc1697cbb5ca49..5ece375eaf6bcc61864997a389bb5e24 + // 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 e890162e1cea3538ed7dea7b78ee2e5346a8ce7b..9baae5af750b46ededbd660d15934da71befde72 100644 +index c502d9b85eb68b277ae17dfea34e0475f0156647..27d0f1ed58948039004f8f1eba2f7f9609fdeec0 100644 --- a/src/main/java/net/minecraft/server/network/PlayerChunkSender.java +++ b/src/main/java/net/minecraft/server/network/PlayerChunkSender.java @@ -43,16 +43,23 @@ public class PlayerChunkSender { @@ -19220,19 +19339,19 @@ index e890162e1cea3538ed7dea7b78ee2e5346a8ce7b..9baae5af750b46ededbd660d15934da7 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/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index d38fe02af4cc35ed5b22acec41bedb76151f8af5..4a569bf782bfdd870f32fe0ab5c3b8b86a07f218 100644 +index db1279f780e905e5b29fd4db0440d29f52596be0..7bf4884940c6414000a8ac661c1ff64427f53789 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -294,7 +294,7 @@ public abstract class PlayerList { +@@ -296,7 +296,7 @@ public abstract class PlayerList { boolean flag2 = gamerules.getBoolean(GameRules.RULE_LIMITED_CRAFTING); // Spigot - view distance -- 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 +- 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), this.server.enforceSecureProfile())); ++ 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), this.server.enforceSecureProfile())); // Paper - replace old player chunk management player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit playerconnection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked())); playerconnection.send(new ClientboundPlayerAbilitiesPacket(player.getAbilities())); -@@ -944,8 +944,8 @@ public abstract class PlayerList { +@@ -943,8 +943,8 @@ public abstract class PlayerList { LevelData worlddata = worldserver2.getLevelData(); entityplayer1.connection.send(new ClientboundRespawnPacket(entityplayer1.createCommonSpawnInfo(worldserver2), (byte) i)); @@ -19243,7 +19362,7 @@ index d38fe02af4cc35ed5b22acec41bedb76151f8af5..4a569bf782bfdd870f32fe0ab5c3b8b8 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())); -@@ -1497,7 +1497,7 @@ public abstract class PlayerList { +@@ -1496,7 +1496,7 @@ public abstract class PlayerList { public void setViewDistance(int viewDistance) { this.viewDistance = viewDistance; @@ -19252,7 +19371,7 @@ index d38fe02af4cc35ed5b22acec41bedb76151f8af5..4a569bf782bfdd870f32fe0ab5c3b8b8 Iterator iterator = this.server.getAllLevels().iterator(); while (iterator.hasNext()) { -@@ -1512,7 +1512,7 @@ public abstract class PlayerList { +@@ -1511,7 +1511,7 @@ public abstract class PlayerList { public void setSimulationDistance(int simulationDistance) { this.simulationDistance = simulationDistance; @@ -19354,27 +19473,11 @@ index ea72dcb064a35bc6245bc5c94d592efedd8faf41..0793dfe47e68a2b48b010aad5b12dcfa @Override public boolean remove(Object object) { int i = this.findIndex((T)object); -diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java -index 640db9f71608310a64e09f1e3e677c01e6ccd98a..f2a7cb6ebed7a4b4019a09af2a025f624f6fe9c9 100644 ---- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java -+++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java -@@ -186,7 +186,11 @@ public class WorldUpgrader { - } - - WorldUpgrader.LOGGER.error("Error upgrading chunk {}", chunkcoordintpair, throwable); -+ // Paper start -+ } catch (IOException e) { -+ WorldUpgrader.LOGGER.error("Error upgrading chunk {}", chunkcoordintpair, e); - } -+ // Paper end - - if (flag1) { - ++this.converted; diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 5275e7a34f86830d43edcab3a0e94f8d8e9cfae5..b108f779abe3d9798c0bcbc983f41d48b33aa153 100644 +index 4e96b6c05bf8b8235e91bdd26e5615c5299fd9aa..64ba2b3f8e0d5176dc24432ceb4a51eea1f24098 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -480,6 +480,58 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -482,6 +482,58 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } // Paper end @@ -19433,7 +19536,7 @@ index 5275e7a34f86830d43edcab3a0e94f8d8e9cfae5..b108f779abe3d9798c0bcbc983f41d48 public Entity(EntityType type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); this.passengers = ImmutableList.of(); -@@ -2580,11 +2632,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -2608,11 +2660,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return InteractionResult.PASS; } @@ -19447,7 +19550,7 @@ index 5275e7a34f86830d43edcab3a0e94f8d8e9cfae5..b108f779abe3d9798c0bcbc983f41d48 return false; } -@@ -4009,6 +4061,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4037,6 +4089,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess }).count(); } @@ -19461,7 +19564,7 @@ index 5275e7a34f86830d43edcab3a0e94f8d8e9cfae5..b108f779abe3d9798c0bcbc983f41d48 public boolean hasExactlyOnePlayerPassenger() { if (this.passengers.isEmpty()) { return false; } // Paper - Optimize indirect passenger iteration return this.countPlayerPassengers() == 1; -@@ -4361,6 +4420,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4387,6 +4446,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return; } // Paper end - Block invalid positions and bounding box @@ -19474,7 +19577,7 @@ index 5275e7a34f86830d43edcab3a0e94f8d8e9cfae5..b108f779abe3d9798c0bcbc983f41d48 // Paper start - Fix MC-4 if (this instanceof ItemEntity) { if (io.papermc.paper.configuration.GlobalConfiguration.get().misc.fixEntityPositionDesync) { -@@ -4490,6 +4555,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4514,6 +4579,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @Override public final void setRemoved(Entity.RemovalReason entity_removalreason, EntityRemoveEvent.Cause cause) { @@ -19488,7 +19591,7 @@ index 5275e7a34f86830d43edcab3a0e94f8d8e9cfae5..b108f779abe3d9798c0bcbc983f41d48 CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit end final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers -@@ -4501,7 +4573,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4525,7 +4597,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.stopRiding(); } @@ -19497,7 +19600,7 @@ index 5275e7a34f86830d43edcab3a0e94f8d8e9cfae5..b108f779abe3d9798c0bcbc983f41d48 this.levelCallback.onRemove(entity_removalreason); // Paper start - Folia schedulers if (!(this instanceof ServerPlayer) && entity_removalreason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { -@@ -4532,7 +4604,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4556,7 +4628,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @Override public boolean shouldBeSaved() { @@ -19507,10 +19610,10 @@ index 5275e7a34f86830d43edcab3a0e94f8d8e9cfae5..b108f779abe3d9798c0bcbc983f41d48 @Override diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -index ed008e1a9573ea3c75de94680b91c8ee598ee44a..c07cc1bf3b98525d72924edee4233364fd8174d0 100644 +index 71d8909f35a22256406a2232d21adfd7d94dc3a5..51564dc963e39018e1572d3429c70eb9f8094e72 100644 --- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java +++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -@@ -38,12 +38,28 @@ import net.minecraft.world.level.chunk.storage.SectionStorage; +@@ -40,8 +40,23 @@ import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; public class PoiManager extends SectionStorage { public static final int MAX_VILLAGE_DISTANCE = 6; public static final int VILLAGE_SECTION_SIZE = 1; @@ -19533,16 +19636,19 @@ index ed008e1a9573ea3c75de94680b91c8ee598ee44a..c07cc1bf3b98525d72924edee4233364 + } + } + // Paper end - rewrite chunk system -+ - public PoiManager(Path path, DataFixer dataFixer, boolean dsync, RegistryAccess registryManager, LevelHeightAccessor world) { - super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, registryManager, world); + public PoiManager( + RegionStorageInfo storageKey, Path directory, DataFixer dataFixer, boolean dsync, RegistryAccess registryManager, LevelHeightAccessor world +@@ -53,7 +68,7 @@ public class PoiManager extends SectionStorage { + registryManager, + world + ); - this.distanceTracker = new PoiManager.DistanceTracker(); + this.world = (net.minecraft.server.level.ServerLevel)world; // Paper - rewrite chunk system } public void add(BlockPos pos, Holder type) { -@@ -177,8 +193,8 @@ public class PoiManager extends SectionStorage { +@@ -187,8 +202,8 @@ public class PoiManager extends SectionStorage { } public int sectionsToVillage(SectionPos pos) { @@ -19553,7 +19659,7 @@ index ed008e1a9573ea3c75de94680b91c8ee598ee44a..c07cc1bf3b98525d72924edee4233364 } boolean isVillageCenter(long pos) { -@@ -192,21 +208,118 @@ public class PoiManager extends SectionStorage { +@@ -202,20 +217,117 @@ public class PoiManager extends SectionStorage { @Override public void tick(BooleanSupplier shouldKeepTicking) { @@ -19598,8 +19704,8 @@ index ed008e1a9573ea3c75de94680b91c8ee598ee44a..c07cc1bf3b98525d72924edee4233364 + io.papermc.paper.chunk.system.poi.PoiChunk ret = manager.getPoiChunkIfLoaded(chunkX, chunkZ, true); + + return ret == null ? Optional.empty() : ret.getSectionForVanilla(chunkY); - } - ++ } ++ + @Override + public Optional getOrLoad(long pos) { + int chunkX = io.papermc.paper.util.CoordinateUtils.getChunkSectionX(pos); @@ -19672,13 +19778,12 @@ index ed008e1a9573ea3c75de94680b91c8ee598ee44a..c07cc1bf3b98525d72924edee4233364 + for (int section = minY; section <= maxY; ++section) { + this.checkConsistencyWithBlocks(SectionPos.of(chunkX, section, chunkZ), sections[section - minY]); + } -+ } + } + // Paper end - rewrite chunk system -+ + public void checkConsistencyWithBlocks(SectionPos sectionPos, LevelChunkSection chunkSection) { Util.ifElse(this.getOrLoad(sectionPos.asLong()), poiSet -> poiSet.refresh(populator -> { - if (mayHavePoi(chunkSection)) { -@@ -241,7 +354,7 @@ public class PoiManager extends SectionStorage { +@@ -251,7 +363,7 @@ public class PoiManager extends SectionStorage { .map(sectionPos -> Pair.of(sectionPos, this.getOrLoad(sectionPos.asLong()))) .filter(pair -> !pair.getSecond().map(PoiSection::isValid).orElse(false)) .map(pair -> pair.getFirst().chunk()) @@ -19687,7 +19792,7 @@ index ed008e1a9573ea3c75de94680b91c8ee598ee44a..c07cc1bf3b98525d72924edee4233364 .forEach(chunkPos -> world.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.EMPTY)); } -@@ -255,7 +368,7 @@ public class PoiManager extends SectionStorage { +@@ -265,7 +377,7 @@ public class PoiManager extends SectionStorage { @Override protected int getLevelFromSource(long id) { @@ -19696,7 +19801,7 @@ index ed008e1a9573ea3c75de94680b91c8ee598ee44a..c07cc1bf3b98525d72924edee4233364 } @Override -@@ -277,6 +390,35 @@ public class PoiManager extends SectionStorage { +@@ -287,6 +399,35 @@ public class PoiManager extends SectionStorage { } } @@ -19733,7 +19838,7 @@ index ed008e1a9573ea3c75de94680b91c8ee598ee44a..c07cc1bf3b98525d72924edee4233364 HAS_SPACE(PoiRecord::hasSpace), IS_OCCUPIED(PoiRecord::isOccupied), diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java -index beb0ff150fdd8ca6c44139ccb2d0eb77a4431e0c..f7d69dd83aad8e0ec1497441c61188bcf230865f 100644 +index 971fb29a2c3dc713cb8ab1d2eed054cc16f9c93c..5b7deae326228e482b218aeebd857a59b7434eaf 100644 --- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java +++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiSection.java @@ -29,6 +29,7 @@ public class PoiSection { @@ -19781,10 +19886,10 @@ index bd20bea7f76a7307f1698fb2dfef37125032d166..9a28912f52824acdc80a62243b136e6f List getEntities(EntityTypeTest filter, AABB box, Predicate predicate); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index cedde2235227eb5820beefb98549994e1cca1198..9c743c980697a14d7348554fb77f242d5eaa152e 100644 +index 6ef8b68ceaf710e37ceb63040db95ca47b103ac3..143ab00a079c0bb2af8717567f7069e82cddd9a6 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -545,6 +545,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -539,6 +539,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable { if ((i & 2) != 0 && (!this.isClientSide || (i & 4) == 0) && (this.isClientSide || chunk == null || (chunk.getFullStatus() != null && chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING)))) { // allow chunk to be null here as chunk.isReady() is false when we send our notification during block placement this.sendBlockUpdated(blockposition, iblockdata1, iblockdata, i); @@ -19796,7 +19901,7 @@ index cedde2235227eb5820beefb98549994e1cca1198..9c743c980697a14d7348554fb77f242d } if ((i & 1) != 0) { -@@ -936,7 +941,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -933,7 +938,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } // Paper end - Perf: Optimize capturedTileEntities lookup // CraftBukkit end @@ -19805,7 +19910,7 @@ index cedde2235227eb5820beefb98549994e1cca1198..9c743c980697a14d7348554fb77f242d } public void setBlockEntity(BlockEntity blockEntity) { -@@ -1027,26 +1032,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1024,26 +1029,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public List getEntities(@Nullable Entity except, AABB box, Predicate predicate) { this.getProfiler().incrementCounter("getEntities"); List list = Lists.newArrayList(); @@ -19833,7 +19938,7 @@ index cedde2235227eb5820beefb98549994e1cca1198..9c743c980697a14d7348554fb77f242d return list; } -@@ -1064,34 +1050,23 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1061,33 +1047,23 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public void getEntities(EntityTypeTest filter, AABB box, Predicate predicate, List result, int limit) { this.getProfiler().incrementCounter("getEntities"); @@ -19845,8 +19950,7 @@ index cedde2235227eb5820beefb98549994e1cca1198..9c743c980697a14d7348554fb77f242d - } - } - -- if (entity instanceof EnderDragon) { -- EnderDragon entityenderdragon = (EnderDragon) entity; +- if (entity instanceof EnderDragon entityenderdragon) { - EnderDragonPart[] aentitycomplexpart = entityenderdragon.getSubEntities(); - int j = aentitycomplexpart.length; - @@ -19884,7 +19988,7 @@ index cedde2235227eb5820beefb98549994e1cca1198..9c743c980697a14d7348554fb77f242d } @Nullable -@@ -1383,4 +1358,45 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1377,4 +1353,45 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } } // Paper end - notify observers even if grow failed @@ -19931,7 +20035,7 @@ index cedde2235227eb5820beefb98549994e1cca1198..9c743c980697a14d7348554fb77f242d + // Paper end } diff --git a/src/main/java/net/minecraft/world/level/LevelReader.java b/src/main/java/net/minecraft/world/level/LevelReader.java -index ced67cf88c91c5270a0060a7307f36739237cbb2..dab86988686cf7c926b7432b8a4afffd7a23327a 100644 +index a0ae26d6197e1069ca09982b4f8b706c55ae8491..32bfeb9aa87b43a9d2ce46dcc99dbd0ff355b412 100644 --- a/src/main/java/net/minecraft/world/level/LevelReader.java +++ b/src/main/java/net/minecraft/world/level/LevelReader.java @@ -26,6 +26,15 @@ public interface LevelReader extends BlockAndTintGetter, CollisionGetter, Signal @@ -19951,10 +20055,10 @@ index ced67cf88c91c5270a0060a7307f36739237cbb2..dab86988686cf7c926b7432b8a4afffd @Nullable default ChunkAccess getChunkIfLoadedImmediately(BlockPos pos) { return this.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4);} diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -index 84a2a5384a8a31eff5363e6391c9a5187212ff36..4c03297fb523ef59cd9d11edbed437398e562a00 100644 +index c9cd18ce79a6ee7297a8fd14f4dbe712570b3ced..927bdebdb8ae01613f0cea074b3367bd7ffe9ab1 100644 --- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -114,7 +114,7 @@ public abstract class ChunkGenerator { +@@ -120,7 +120,7 @@ public abstract class ChunkGenerator { return CompletableFuture.supplyAsync(Util.wrapThreadWithTaskName("init_biomes", () -> { chunk.fillBiomesFromNoise(this.biomeSource, noiseConfig.sampler()); return chunk; @@ -19963,7 +20067,7 @@ index 84a2a5384a8a31eff5363e6391c9a5187212ff36..4c03297fb523ef59cd9d11edbed43739 } public abstract void applyCarvers(WorldGenRegion chunkRegion, long seed, RandomState noiseConfig, BiomeManager biomeAccess, StructureManager structureAccessor, ChunkAccess chunk, GenerationStep.Carving carverStep); -@@ -309,7 +309,7 @@ public abstract class ChunkGenerator { +@@ -315,7 +315,7 @@ public abstract class ChunkGenerator { return Pair.of(placement.getLocatePos(pos), holder); } @@ -19972,76 +20076,11 @@ index 84a2a5384a8a31eff5363e6391c9a5187212ff36..4c03297fb523ef59cd9d11edbed43739 structurestart = structureAccessor.getStartForStructure(SectionPos.bottomOf(ichunkaccess), (Structure) holder.value(), ichunkaccess); } while (structurestart == null); -diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java -index 846ae3fd184a1d63b743aa25e045604576697c96..a907b79fd8291a0e92db138f37239d17424188a1 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java -@@ -30,6 +30,30 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp - - public class ChunkStatus { - -+ // Paper start - rewrite chunk system -+ public boolean isParallelCapable; // Paper -+ public int writeRadius = -1; -+ public int loadRange = 0; -+ -+ protected static final java.util.List statuses = new java.util.ArrayList<>(); -+ -+ private ChunkStatus nextStatus; -+ -+ public final ChunkStatus getNextStatus() { -+ return this.nextStatus; -+ } -+ -+ public final boolean isEmptyLoadStatus() { -+ return this.loadingTask == PASSTHROUGH_LOAD_TASK; -+ } -+ -+ public final boolean isEmptyGenStatus() { -+ return this == ChunkStatus.EMPTY; -+ } -+ -+ public final java.util.concurrent.atomic.AtomicBoolean warnedAboutNoImmediateComplete = new java.util.concurrent.atomic.AtomicBoolean(); -+ // Paper end - rewrite chunk system -+ - public static final int MAX_STRUCTURE_DISTANCE = 8; - private static final EnumSet PRE_FEATURES = EnumSet.of(Heightmap.Types.OCEAN_FLOOR_WG, Heightmap.Types.WORLD_SURFACE_WG); - public static final EnumSet POST_FEATURES = EnumSet.of(Heightmap.Types.OCEAN_FLOOR, Heightmap.Types.WORLD_SURFACE, Heightmap.Types.MOTION_BLOCKING, Heightmap.Types.MOTION_BLOCKING_NO_LEAVES); -@@ -151,13 +175,13 @@ public class ChunkStatus { - ((ProtoChunk) chunk).setLightEngine(lightingProvider); - boolean flag = ChunkStatus.isLighted(chunk); - -- return lightingProvider.initializeLight(chunk, flag).thenApply(Either::left); -+ return CompletableFuture.completedFuture(Either.left(chunk)); // Paper - rewrite chunk system - } - - private static CompletableFuture> lightChunk(ThreadedLevelLightEngine lightingProvider, ChunkAccess chunk) { - boolean flag = ChunkStatus.isLighted(chunk); - -- return lightingProvider.lightChunk(chunk, flag).thenApply(Either::left); -+ return CompletableFuture.completedFuture(Either.left(chunk)); // Paper - rewrite chunk system - } - - private static ChunkStatus registerSimple(String id, @Nullable ChunkStatus previous, int taskMargin, EnumSet heightMapTypes, ChunkStatus.ChunkType chunkType, ChunkStatus.SimpleGenerationTask task) { -@@ -211,6 +235,13 @@ public class ChunkStatus { - this.chunkType = chunkType; - this.heightmapsAfter = heightMapTypes; - this.index = previous == null ? 0 : previous.getIndex() + 1; -+ // Paper start -+ this.nextStatus = this; -+ if (statuses.size() > 0) { -+ statuses.get(statuses.size() - 1).nextStatus = this; -+ } -+ statuses.add(this); -+ // Paper end - } - - public int getIndex() { diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 73e682bb3ef3b2e450ec8c594b5365c7a340615e..6a5756bd333d9b221e7770842e5114d295cb7f1d 100644 +index fca31bc427847141e7317b85a10da9e34e9e2bf6..50e86fd70aeb798daf3685e7f7dc780516dd76b4 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -84,6 +84,7 @@ public class LevelChunk extends ChunkAccess { +@@ -86,6 +86,7 @@ public class LevelChunk extends ChunkAccess { private final Int2ObjectMap gameEventListenerRegistrySections; private final LevelChunkTicks blockTicks; private final LevelChunkTicks fluidTicks; @@ -20224,11 +20263,77 @@ index 73e682bb3ef3b2e450ec8c594b5365c7a340615e..6a5756bd333d9b221e7770842e5114d2 } public void setFullStatus(Supplier levelTypeProvider) { +diff --git a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatus.java b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatus.java +index 95318092f8281d98132d1d3ceb4a5c36cf32eb05..68e1e3d525ee6cec23971eea431f22a535207b2b 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatus.java ++++ b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatus.java +@@ -128,6 +128,29 @@ public class ChunkStatus { + } + } + // Paper end - starlight ++ // Paper start - rewrite chunk system ++ public boolean isParallelCapable; // Paper ++ public int writeRadius = -1; ++ public int loadRange = 0; ++ ++ protected static final java.util.List statuses = new java.util.ArrayList<>(); ++ ++ private ChunkStatus nextStatus; ++ ++ public final ChunkStatus getNextStatus() { ++ return this.nextStatus; ++ } ++ ++ public final boolean isEmptyLoadStatus() { ++ return this.loadingTask == PASSTHROUGH_LOAD_TASK; // TODO fix this ++ } ++ ++ public final boolean isEmptyGenStatus() { ++ return this == ChunkStatus.EMPTY; ++ } ++ ++ public final java.util.concurrent.atomic.AtomicBoolean warnedAboutNoImmediateComplete = new java.util.concurrent.atomic.AtomicBoolean(); ++ // Paper end - rewrite chunk system + + private static ChunkStatus register( + String id, +@@ -190,6 +213,13 @@ public class ChunkStatus { + this.chunkType = chunkType; + this.heightmapsAfter = heightMapTypes; + this.index = previous == null ? 0 : previous.getIndex() + 1; ++ // Paper start ++ this.nextStatus = this; ++ if (statuses.size() > 0) { ++ statuses.get(statuses.size() - 1).nextStatus = this; ++ } ++ statuses.add(this); ++ // Paper end + } + + public int getIndex() { +diff --git a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java +index ce7f154b9dad4e78ee0189405cf57dcb3d5301b8..f095704157653f30615c92a8d6f2900fe1721360 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java ++++ b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStatusTasks.java +@@ -113,11 +113,11 @@ public class ChunkStatusTasks { + } + + static CompletableFuture generateInitializeLight(WorldGenContext context, ChunkStatus status, Executor executor, ToFullChunk fullChunkConverter, List chunks, ChunkAccess chunk) { +- return ChunkStatusTasks.initializeLight(context.lightEngine(), chunk); ++ return CompletableFuture.completedFuture(chunk); // Paper - rewrite chunk system + } + + static CompletableFuture loadInitializeLight(WorldGenContext context, ChunkStatus status, ToFullChunk fullChunkConverter, ChunkAccess chunk) { +- return ChunkStatusTasks.initializeLight(context.lightEngine(), chunk); ++ return CompletableFuture.completedFuture(chunk); // Paper - rewrite chunk system + } + + private static CompletableFuture initializeLight(ThreadedLevelLightEngine lightingProvider, ChunkAccess chunk) { 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 c6115477cc94bf47a5f459418a232412b7c358ba..e67ebc8517a1afb0c7fe23f19a781942dded3241 100644 +index 01d6b8683a9fa30d05b03ebfef8ee2dca4e83a56..b2e8082dda0d0ca32bfc32cbf9d8ae9822febc30 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 -@@ -110,6 +110,17 @@ public class ChunkSerializer { +@@ -112,6 +112,17 @@ public class ChunkSerializer { } } // Paper end - guard against serializing mismatching coordinates @@ -20246,7 +20351,7 @@ index c6115477cc94bf47a5f459418a232412b7c358ba..e67ebc8517a1afb0c7fe23f19a781942 public static ProtoChunk read(ServerLevel world, PoiManager poiStorage, ChunkPos chunkPos, CompoundTag nbt) { // Paper start - Do not let the server load chunks from newer versions if (nbt.contains("DataVersion", net.minecraft.nbt.Tag.TAG_ANY_NUMERIC)) { -@@ -120,6 +131,12 @@ public class ChunkSerializer { +@@ -122,6 +133,12 @@ public class ChunkSerializer { } } // Paper end - Do not let the server load chunks from newer versions @@ -20259,7 +20364,7 @@ index c6115477cc94bf47a5f459418a232412b7c358ba..e67ebc8517a1afb0c7fe23f19a781942 ChunkPos chunkcoordintpair1 = new ChunkPos(nbt.getInt("xPos"), nbt.getInt("zPos")); // Paper - guard against serializing mismatching coordinates; diff on change, see ChunkSerializer#getChunkCoordinate if (!Objects.equals(chunkPos, chunkcoordintpair1)) { -@@ -185,7 +202,7 @@ public class ChunkSerializer { +@@ -178,7 +195,7 @@ public class ChunkSerializer { achunksection[k] = chunksection; SectionPos sectionposition = SectionPos.of(chunkPos, b0); @@ -20268,16 +20373,16 @@ index c6115477cc94bf47a5f459418a232412b7c358ba..e67ebc8517a1afb0c7fe23f19a781942 } boolean flag3 = nbttagcompound1.contains("BlockLight", 7); -@@ -331,7 +348,7 @@ public class ChunkSerializer { +@@ -325,7 +342,7 @@ public class ChunkSerializer { } - if (chunkstatus_type == ChunkStatus.ChunkType.LEVELCHUNK) { + if (chunktype == ChunkType.LEVELCHUNK) { - return new ImposterProtoChunk((LevelChunk) object1, false); + return new InProgressChunkHolder(new ImposterProtoChunk((LevelChunk) object1, false)); // Paper - Async chunk loading } else { ProtoChunk protochunk1 = (ProtoChunk) object1; -@@ -366,9 +383,41 @@ public class ChunkSerializer { +@@ -360,9 +377,41 @@ public class ChunkSerializer { protochunk1.setCarvingMask(worldgenstage_features, new CarvingMask(nbttagcompound5.getLongArray(s1), ((ChunkAccess) object1).getMinBuildHeight())); } @@ -20303,7 +20408,7 @@ index c6115477cc94bf47a5f459418a232412b7c358ba..e67ebc8517a1afb0c7fe23f19a781942 + + ListTag blockEntitiesSerialized = new ListTag(); + for (final BlockPos blockPos : chunk.getBlockEntitiesPos()) { -+ final CompoundTag blockEntityNbt = chunk.getBlockEntityNbtForSaving(blockPos); ++ final CompoundTag blockEntityNbt = chunk.getBlockEntityNbtForSaving(blockPos, world.registryAccess()); + if (blockEntityNbt != null) { + blockEntitiesSerialized.add(blockEntityNbt); + } @@ -20320,7 +20425,7 @@ index c6115477cc94bf47a5f459418a232412b7c358ba..e67ebc8517a1afb0c7fe23f19a781942 private static void logErrors(ChunkPos chunkPos, int y, String message) { ChunkSerializer.LOGGER.error("Recoverable errors when loading section [" + chunkPos.x + ", " + y + ", " + chunkPos.z + "]: " + message); -@@ -385,6 +434,11 @@ public class ChunkSerializer { +@@ -379,6 +428,11 @@ public class ChunkSerializer { // CraftBukkit end public static CompoundTag write(ServerLevel world, ChunkAccess chunk) { @@ -20332,7 +20437,7 @@ index c6115477cc94bf47a5f459418a232412b7c358ba..e67ebc8517a1afb0c7fe23f19a781942 // Paper start - rewrite light impl final int minSection = io.papermc.paper.util.WorldUtil.getMinLightSection(world); final int maxSection = io.papermc.paper.util.WorldUtil.getMaxLightSection(world); -@@ -397,7 +451,7 @@ public class ChunkSerializer { +@@ -391,7 +445,7 @@ public class ChunkSerializer { nbttagcompound.putInt("xPos", chunkcoordintpair.x); nbttagcompound.putInt("yPos", chunk.getMinSection()); nbttagcompound.putInt("zPos", chunkcoordintpair.z); @@ -20341,7 +20446,7 @@ index c6115477cc94bf47a5f459418a232412b7c358ba..e67ebc8517a1afb0c7fe23f19a781942 nbttagcompound.putLong("InhabitedTime", chunk.getInhabitedTime()); nbttagcompound.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(chunk.getStatus()).toString()); BlendingData blendingdata = chunk.getBlendingData(); -@@ -497,8 +551,17 @@ public class ChunkSerializer { +@@ -485,8 +539,17 @@ public class ChunkSerializer { nbttagcompound.putBoolean("isLightOn", false); // Paper - set to false but still store, this allows us to detect --eraseCache (as eraseCache _removes_) } @@ -20361,7 +20466,7 @@ index c6115477cc94bf47a5f459418a232412b7c358ba..e67ebc8517a1afb0c7fe23f19a781942 CompoundTag nbttagcompound2; -@@ -534,7 +597,14 @@ public class ChunkSerializer { +@@ -522,7 +585,14 @@ public class ChunkSerializer { nbttagcompound.put("CarvingMasks", nbttagcompound2); } @@ -20376,7 +20481,7 @@ index c6115477cc94bf47a5f459418a232412b7c358ba..e67ebc8517a1afb0c7fe23f19a781942 nbttagcompound.put("PostProcessing", ChunkSerializer.packOffsets(chunk.getPostProcessing())); CompoundTag nbttagcompound3 = new CompoundTag(); Iterator iterator1 = chunk.getHeightmaps().iterator(); -@@ -590,7 +660,7 @@ public class ChunkSerializer { +@@ -578,7 +648,7 @@ public class ChunkSerializer { return nbttaglist == null && nbttaglist1 == null ? null : (chunk) -> { if (nbttaglist != null) { @@ -20386,10 +20491,10 @@ index c6115477cc94bf47a5f459418a232412b7c358ba..e67ebc8517a1afb0c7fe23f19a781942 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 eebaf98bc0fa4696af59b2a79563beb73501a554..645a1773237f2002c233ec1f3ff6f0ca46ca4024 100644 +index a62c90e10c0dfa4c6211a05c4071932756d7b218..554dede2ad0e45d3ee4ccc5510b7644f2e9e4250 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkStorage.java -@@ -28,18 +28,21 @@ import net.minecraft.world.level.storage.DimensionDataStorage; +@@ -31,18 +31,21 @@ import net.minecraft.world.level.storage.DimensionDataStorage; public class ChunkStorage implements AutoCloseable { public static final int LAST_MONOLYTH_STRUCTURE_DATA_VERSION = 1493; @@ -20402,19 +20507,19 @@ index eebaf98bc0fa4696af59b2a79563beb73501a554..645a1773237f2002c233ec1f3ff6f0ca @Nullable private volatile LegacyStructureDataHandler legacyStructureHandler; - public ChunkStorage(Path directory, DataFixer dataFixer, boolean dsync) { + public ChunkStorage(RegionStorageInfo storageKey, Path directory, DataFixer dataFixer, boolean dsync) { this.fixerUpper = dataFixer; -- this.worker = new IOWorker(directory, dsync, "chunk"); -+ this.regionFileCache = new RegionFileStorage(directory, dsync); // Paper - rewrite chunk system; async chunk IO +- this.worker = new IOWorker(storageKey, directory, dsync); ++ this.regionFileCache = new RegionFileStorage(storageKey, directory, dsync); // Paper - rewrite chunk system; async chunk IO } public boolean isOldChunkAround(ChunkPos chunkPos, int checkRadius) { - return this.worker.isOldChunkAround(chunkPos, checkRadius); -+ return true; // Paper - rewrite chunk system; (for now, unoptimised behavior) TODO implement later? the chunk status that blender uses SHOULD already have this radius loaded, no need to go back later for it... ++ return true; // Paper - rewrite chunk system } // CraftBukkit start -@@ -47,8 +50,9 @@ public class ChunkStorage implements AutoCloseable { +@@ -50,8 +53,9 @@ public class ChunkStorage implements AutoCloseable { if (true) return true; // Paper - Perf: 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) { @@ -20426,27 +20531,27 @@ index eebaf98bc0fa4696af59b2a79563beb73501a554..645a1773237f2002c233ec1f3ff6f0ca return true; } } -@@ -76,6 +80,7 @@ public class ChunkStorage implements AutoCloseable { +@@ -79,6 +83,7 @@ public class ChunkStorage implements AutoCloseable { - public CompoundTag upgradeChunkTag(ResourceKey resourcekey, Supplier supplier, CompoundTag nbttagcompound, Optional>> optional, ChunkPos pos, @Nullable LevelAccessor generatoraccess) { + public CompoundTag upgradeChunkTag(ResourceKey resourcekey, Supplier supplier, CompoundTag nbttagcompound, Optional>> optional, ChunkPos pos, @Nullable LevelAccessor generatoraccess) { // CraftBukkit end + nbttagcompound = nbttagcompound.copy(); // Paper - defensive copy, another thread might modify this int i = ChunkStorage.getVersion(nbttagcompound); - // CraftBukkit start -@@ -93,9 +98,11 @@ public class ChunkStorage implements AutoCloseable { - if (i < 1493) { - ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.CHUNK, nbttagcompound, i, 1493); // Paper - replace chunk converter - if (nbttagcompound.getCompound("Level").getBoolean("hasLegacyStructureData")) { -+ synchronized (this.persistentDataLock) { // Paper - Async chunk loading - LegacyStructureDataHandler persistentstructurelegacy = this.getLegacyStructureHandler(resourcekey, supplier); + try { +@@ -97,9 +102,11 @@ public class ChunkStorage implements AutoCloseable { + if (i < 1493) { + ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.CHUNK, nbttagcompound, i, 1493); // Paper - replace chunk converter + if (nbttagcompound.getCompound("Level").getBoolean("hasLegacyStructureData")) { ++ synchronized (this.persistentDataLock) { // Paper - Async chunk loading + LegacyStructureDataHandler persistentstructurelegacy = this.getLegacyStructureHandler(resourcekey, supplier); - nbttagcompound = persistentstructurelegacy.updateFromLegacy(nbttagcompound); -+ } // Paper - Async chunk loading + nbttagcompound = persistentstructurelegacy.updateFromLegacy(nbttagcompound); ++ } // Paper - Async chunk loading + } } - } -@@ -128,7 +135,7 @@ public class ChunkStorage implements AutoCloseable { +@@ -139,7 +146,7 @@ public class ChunkStorage implements AutoCloseable { LegacyStructureDataHandler persistentstructurelegacy = this.legacyStructureHandler; if (persistentstructurelegacy == null) { @@ -20455,7 +20560,7 @@ index eebaf98bc0fa4696af59b2a79563beb73501a554..645a1773237f2002c233ec1f3ff6f0ca persistentstructurelegacy = this.legacyStructureHandler; if (persistentstructurelegacy == null) { this.legacyStructureHandler = persistentstructurelegacy = LegacyStructureDataHandler.getLegacyStructureHandler(worldKey, (DimensionDataStorage) stateManagerGetter.get()); -@@ -154,10 +161,20 @@ public class ChunkStorage implements AutoCloseable { +@@ -165,10 +172,20 @@ public class ChunkStorage implements AutoCloseable { } public CompletableFuture> read(ChunkPos chunkPos) { @@ -20473,17 +20578,23 @@ index eebaf98bc0fa4696af59b2a79563beb73501a554..645a1773237f2002c233ec1f3ff6f0ca } + // Paper end - async chunk io -- public void write(ChunkPos chunkPos, CompoundTag nbt) { -+ public void write(ChunkPos chunkPos, CompoundTag nbt) throws IOException { // Paper - rewrite chunk system; async chunk io +- public CompletableFuture write(ChunkPos chunkPos, CompoundTag nbt) { ++ public CompletableFuture write(ChunkPos chunkPos, CompoundTag nbt) throws IOException { // Paper - rewrite chunk system; async chunk io // Paper start - guard against serializing mismatching coordinates if (nbt != null && !chunkPos.equals(ChunkSerializer.getChunkCoordinate(nbt))) { final String world = (this instanceof net.minecraft.server.level.ChunkMap) ? ((net.minecraft.server.level.ChunkMap) this).level.getWorld().getName() : null; -@@ -165,22 +182,33 @@ public class ChunkStorage implements AutoCloseable { +@@ -176,26 +193,39 @@ public class ChunkStorage implements AutoCloseable { + " but compound says coordinate is " + ChunkSerializer.getChunkCoordinate(nbt) + (world == null ? " for an unknown world" : (" for world: " + world))); } // Paper end - guard against serializing mismatching coordinates -- this.worker.store(chunkPos, nbt); -+ this.regionFileCache.write(chunkPos, nbt); // Paper - rewrite chunk system; async chunk io ++ this.regionFileCache.write(chunkPos, nbt); // Paper - rewrite chunk system; async chunk io, move above legacy structure index + this.handleLegacyStructureIndex(chunkPos); +- return this.worker.store(chunkPos, nbt); ++ // Paper - rewrite chunk system; async chunk io, move above legacy structure index ++ return null; + } + + protected void handleLegacyStructureIndex(ChunkPos chunkPos) { if (this.legacyStructureHandler != null) { + synchronized (this.persistentDataLock) { // Paper - rewrite chunk system; async chunk io this.legacyStructureHandler.removeIndex(chunkPos.toLong()); @@ -20517,25 +20628,24 @@ index eebaf98bc0fa4696af59b2a79563beb73501a554..645a1773237f2002c233ec1f3ff6f0ca } } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -index 3b842297774472af5999438e883c1cd262f3c286..e8f8e1f2128df81705a88cee4b9a7760fb123750 100644 +index 49d8a62d2b6ca6da4e02b3cec7e42c38b7781b57..9fdf8f857a5f9b231c6d0633eaba498244214f74 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/EntityStorage.java -@@ -30,45 +30,31 @@ public class EntityStorage implements EntityPersistentStorage { +@@ -27,43 +27,30 @@ public class EntityStorage implements EntityPersistentStorage { private static final String ENTITIES_TAG = "Entities"; private static final String POSITION_TAG = "Position"; public final ServerLevel level; -- private final IOWorker worker; +- private final SimpleRegionStorage simpleRegionStorage; + // Paper - rewrite chunk system private final LongSet emptyChunks = new LongOpenHashSet(); - public final ProcessorMailbox entityDeserializerQueue; + // Paper - rewrite chunk system - protected final DataFixer fixerUpper; - public EntityStorage(ServerLevel world, Path path, DataFixer dataFixer, boolean dsync, Executor executor) { + public EntityStorage(SimpleRegionStorage storage, ServerLevel world, Executor executor) { +- this.simpleRegionStorage = storage; ++ // Paper - rewrite chunk system this.level = world; - this.fixerUpper = dataFixer; - this.entityDeserializerQueue = ProcessorMailbox.create(executor, "entity-deserializer"); -- this.worker = new IOWorker(path, dsync, "entities"); + // Paper - rewrite chunk system } @@ -20543,7 +20653,7 @@ index 3b842297774472af5999438e883c1cd262f3c286..e8f8e1f2128df81705a88cee4b9a7760 public CompletableFuture> loadEntities(ChunkPos pos) { - return this.emptyChunks.contains(pos.toLong()) - ? CompletableFuture.completedFuture(emptyChunk(pos)) -- : this.worker.loadAsync(pos).thenApplyAsync(nbt -> { +- : this.simpleRegionStorage.read(pos).thenApplyAsync(nbt -> { - if (nbt.isEmpty()) { - this.emptyChunks.add(pos.toLong()); - return emptyChunk(pos); @@ -20557,7 +20667,7 @@ index 3b842297774472af5999438e883c1cd262f3c286..e8f8e1f2128df81705a88cee4b9a7760 - LOGGER.warn("Failed to parse chunk {} position info", pos, var6); - } - -- CompoundTag compoundTag = this.upgradeChunkTag(nbt.get()); +- CompoundTag compoundTag = this.simpleRegionStorage.upgradeChunkTag(nbt.get(), -1); - ListTag listTag = compoundTag.getList("Entities", 10); - List list = EntityType.loadEntitiesRecursive(listTag, this.level).collect(ImmutableList.toImmutableList()); - return new ChunkEntities<>(pos, list); @@ -20579,7 +20689,7 @@ index 3b842297774472af5999438e883c1cd262f3c286..e8f8e1f2128df81705a88cee4b9a7760 int[] is = chunkNbt.getIntArray("Position"); return new ChunkPos(is[0], is[1]); } -@@ -83,43 +69,74 @@ public class EntityStorage implements EntityPersistentStorage { +@@ -78,38 +65,74 @@ public class EntityStorage implements EntityPersistentStorage { @Override public void storeEntities(ChunkEntities dataList) { @@ -20591,8 +20701,8 @@ index 3b842297774472af5999438e883c1cd262f3c286..e8f8e1f2128df81705a88cee4b9a7760 ChunkPos chunkPos = dataList.getPos(); if (dataList.isEmpty()) { if (this.emptyChunks.add(chunkPos.toLong())) { -- this.worker.store(chunkPos, null); -+ // Paper - rewrite chunk system +- this.simpleRegionStorage.write(chunkPos, null); ++ // Paper - rewrite chunk system - fix compile for unused field in dead code } } else { - ListTag listTag = new ListTag(); @@ -20605,7 +20715,7 @@ index 3b842297774472af5999438e883c1cd262f3c286..e8f8e1f2128df81705a88cee4b9a7760 - CompoundTag compoundTag = NbtUtils.addCurrentDataVersion(new CompoundTag()); - compoundTag.put("Entities", listTag); - writeChunkPos(compoundTag, chunkPos); -- this.worker.store(chunkPos, compoundTag).exceptionally(ex -> { +- this.simpleRegionStorage.write(chunkPos, compoundTag).exceptionally(ex -> { - LOGGER.error("Failed to store chunk {}", chunkPos, ex); - return null; - }); @@ -20652,40 +20762,39 @@ index 3b842297774472af5999438e883c1cd262f3c286..e8f8e1f2128df81705a88cee4b9a7760 + + return !force && listTag.isEmpty() ? null : compoundTag; + } ++ ++ public static CompoundTag upgradeChunkTag(CompoundTag chunkNbt) { ++ int i = NbtUtils.getDataVersion(chunkNbt, -1); ++ return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY_CHUNK, chunkNbt, i, net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion()); ++ } + // Paper end - rewrite chunk system + @Override public void flush(boolean sync) { -- this.worker.synchronize(sync).join(); +- this.simpleRegionStorage.synchronize(sync).join(); - this.entityDeserializerQueue.runAll(); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } -- private CompoundTag upgradeChunkTag(CompoundTag chunkNbt) { -+ public static CompoundTag upgradeChunkTag(CompoundTag chunkNbt) { // Paper - public and static - int i = NbtUtils.getDataVersion(chunkNbt, -1); - return ca.spottedleaf.dataconverter.minecraft.MCDataConverter.convertTag(ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.ENTITY_CHUNK, chunkNbt, i, net.minecraft.SharedConstants.getCurrentVersion().getDataVersion().getVersion()); // Paper - route to new converter system - } - @Override public void close() throws IOException { -- this.worker.close(); +- this.simpleRegionStorage.close(); + throw new UnsupportedOperationException(); // Paper - rewrite chunk system } } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -index 8d20e265872e1f8200de186a69a29f498ceb8588..bc8038da65f834249c61a262fc1a5abb7cc91a63 100644 +index e858436bcf1b234d4bc6e6a117f5224d5c2d9f90..307196b2a58d4f8db3e6e3c3517a8004d4908b13 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -44,6 +44,7 @@ public class RegionFile implements AutoCloseable { +@@ -48,6 +48,7 @@ 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(); // Paper - public RegionFile(Path file, Path directory, boolean dsync) throws IOException { - this(file, directory, RegionFileVersion.getCompressionFormat(), dsync); // Paper - Configurable region compression format -@@ -228,7 +229,7 @@ public class RegionFile implements AutoCloseable { + public RegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { + this(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); // Paper - Configurable region compression format +@@ -250,7 +251,7 @@ public class RegionFile implements AutoCloseable { return (byteCount + 4096 - 1) / 4096; } @@ -20694,7 +20803,7 @@ index 8d20e265872e1f8200de186a69a29f498ceb8588..bc8038da65f834249c61a262fc1a5abb int i = this.getOffset(pos); if (i == 0) { -@@ -395,6 +396,11 @@ public class RegionFile implements AutoCloseable { +@@ -417,6 +418,11 @@ public class RegionFile implements AutoCloseable { } public void close() throws IOException { @@ -20706,7 +20815,7 @@ index 8d20e265872e1f8200de186a69a29f498ceb8588..bc8038da65f834249c61a262fc1a5abb try { this.padToFullSector(); } finally { -@@ -404,6 +410,10 @@ public class RegionFile implements AutoCloseable { +@@ -426,6 +432,10 @@ public class RegionFile implements AutoCloseable { this.file.close(); } } @@ -20718,14 +20827,14 @@ index 8d20e265872e1f8200de186a69a29f498ceb8588..bc8038da65f834249c61a262fc1a5abb } diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index fa086a19f038b929f356292b2f657929765f7b6f..f1ecc3832da094400ed9d45bfc60af10da682b4a 100644 +index c4eef3aade889c69cefd873bec2d031cc54103ea..3f6955be976064eb542b5c50a9d6d74457c1833c 100644 --- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -25,30 +25,98 @@ public class RegionFileStorage implements AutoCloseable { +@@ -26,31 +26,99 @@ public class RegionFileStorage implements AutoCloseable { private final Path folder; private final boolean sync; -- RegionFileStorage(Path directory, boolean dsync) { +- RegionFileStorage(RegionStorageInfo storageKey, Path directory, boolean dsync) { + // Paper start - cache regionfile does not exist state + static final int MAX_NON_EXISTING_CACHE = 1024 * 64; + private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet(); @@ -20755,9 +20864,10 @@ index fa086a19f038b929f356292b2f657929765f7b6f..f1ecc3832da094400ed9d45bfc60af10 + } + // Paper end - cache regionfile does not exist state + -+ protected RegionFileStorage(Path directory, boolean dsync) { // Paper - protected constructor ++ protected RegionFileStorage(RegionStorageInfo storageKey, Path directory, boolean dsync) { // Paper - protected constructor this.folder = directory; this.sync = dsync; + this.info = storageKey; } - private RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit @@ -20813,7 +20923,7 @@ index fa086a19f038b929f356292b2f657929765f7b6f..f1ecc3832da094400ed9d45bfc60af10 + } + // Paper end - cache regionfile does not exist state + FileUtil.createDirectoriesSafe(this.folder); // Paper - only create directory if not existing only - moved from above - RegionFile regionfile1 = new RegionFile(path1, this.folder, this.sync); + RegionFile regionfile1 = new RegionFile(this.info, path1, this.folder, this.sync); this.regionCache.putAndMoveToFirst(i, regionfile1); + // Paper start @@ -20825,7 +20935,7 @@ index fa086a19f038b929f356292b2f657929765f7b6f..f1ecc3832da094400ed9d45bfc60af10 return regionfile1; } } -@@ -56,11 +124,12 @@ public class RegionFileStorage implements AutoCloseable { +@@ -58,11 +126,12 @@ public class RegionFileStorage implements AutoCloseable { @Nullable 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 @@ -20839,7 +20949,7 @@ index fa086a19f038b929f356292b2f657929765f7b6f..f1ecc3832da094400ed9d45bfc60af10 DataInputStream datainputstream = regionfile.getChunkDataInputStream(pos); CompoundTag nbttagcompound; -@@ -97,6 +166,9 @@ public class RegionFileStorage implements AutoCloseable { +@@ -99,6 +168,9 @@ public class RegionFileStorage implements AutoCloseable { } return nbttagcompound; @@ -20849,7 +20959,7 @@ index fa086a19f038b929f356292b2f657929765f7b6f..f1ecc3832da094400ed9d45bfc60af10 } public void scanChunk(ChunkPos chunkPos, StreamTagVisitor scanner) throws IOException { -@@ -131,7 +203,13 @@ public class RegionFileStorage implements AutoCloseable { +@@ -133,7 +205,13 @@ public class RegionFileStorage implements AutoCloseable { } protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { @@ -20864,7 +20974,7 @@ index fa086a19f038b929f356292b2f657929765f7b6f..f1ecc3832da094400ed9d45bfc60af10 // Paper start - Chunk save reattempt int attempts = 0; Exception lastException = null; -@@ -177,9 +255,14 @@ public class RegionFileStorage implements AutoCloseable { +@@ -179,9 +257,14 @@ public class RegionFileStorage implements AutoCloseable { net.minecraft.server.MinecraftServer.LOGGER.error("Failed to save chunk {}", pos, lastException); } // Paper end - Chunk save reattempt @@ -20880,7 +20990,7 @@ index fa086a19f038b929f356292b2f657929765f7b6f..f1ecc3832da094400ed9d45bfc60af10 ExceptionCollector exceptionsuppressor = new ExceptionCollector<>(); ObjectIterator objectiterator = this.regionCache.values().iterator(); -@@ -196,7 +279,7 @@ public class RegionFileStorage implements AutoCloseable { +@@ -198,7 +281,7 @@ public class RegionFileStorage implements AutoCloseable { exceptionsuppressor.throwIfPresent(); } @@ -20890,10 +21000,10 @@ index fa086a19f038b929f356292b2f657929765f7b6f..f1ecc3832da094400ed9d45bfc60af10 while (objectiterator.hasNext()) { 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 809da7fec1e1288a7a7bf1ee46c5b7bdd12bca01..bc6043a21227ce8c9c3879bc9c93c3803f79857b 100644 +index 151fcbca34e02783e19fbb7b54ec4fbec2eed190..428ed5adce8510dbcd3518f645f0ecdacf3a0132 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 -@@ -34,17 +34,17 @@ import net.minecraft.world.level.ChunkPos; +@@ -31,15 +31,15 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import org.slf4j.Logger; @@ -20901,47 +21011,38 @@ index 809da7fec1e1288a7a7bf1ee46c5b7bdd12bca01..bc6043a21227ce8c9c3879bc9c93c380 +public class SectionStorage extends RegionFileStorage implements AutoCloseable { // Paper - nuke IOWorker private static final Logger LOGGER = LogUtils.getLogger(); private static final String SECTIONS_TAG = "Sections"; -- private final IOWorker worker; +- private final SimpleRegionStorage simpleRegionStorage; + // Paper - remove mojang I/O thread private final Long2ObjectMap> storage = new Long2ObjectOpenHashMap<>(); private final LongLinkedOpenHashSet dirty = new LongLinkedOpenHashSet(); private final Function> codec; private final Function factory; - private final DataFixer fixerUpper; - private final DataFixTypes type; - private final RegistryAccess registryAccess; -+ public final RegistryAccess registryAccess; // Paper - rewrite chunk system ++ public final RegistryAccess registryAccess; // Paper - rewrite chunk system - public protected final LevelHeightAccessor levelHeightAccessor; public SectionStorage( -@@ -57,13 +57,14 @@ public class SectionStorage implements AutoCloseable { - RegistryAccess dynamicRegistryManager, +@@ -49,7 +49,7 @@ public class SectionStorage implements AutoCloseable { + RegistryAccess registryManager, LevelHeightAccessor world ) { -+ super(path, dsync); // Paper - remove mojang I/O thread +- this.simpleRegionStorage = storageAccess; ++ super(,path, dsync); // Paper - remove mojang I/O thread TODO this trash this.codec = codecFactory; this.factory = factory; - this.fixerUpper = dataFixer; - this.type = dataFixTypes; - this.registryAccess = dynamicRegistryManager; - this.levelHeightAccessor = world; -- this.worker = new IOWorker(path, dsync, path.getFileName().toString()); -+ // Paper - remove mojang I/O thread - } - - protected void tick(BooleanSupplier shouldKeepTicking) { -@@ -122,23 +123,21 @@ public class SectionStorage implements AutoCloseable { + this.registryAccess = registryManager; +@@ -112,23 +112,21 @@ public class SectionStorage implements AutoCloseable { } private void readColumn(ChunkPos pos) { - Optional optional = this.tryRead(pos).join(); -- RegistryOps registryOps = RegistryOps.create(NbtOps.INSTANCE, this.registryAccess); +- RegistryOps registryOps = this.registryAccess.createSerializationContext(NbtOps.INSTANCE); - this.readColumn(pos, registryOps, optional.orElse(null)); + throw new IllegalStateException("Only chunk system can load in state, offending class:" + this.getClass().getName()); // Paper - rewrite chunk system } private CompletableFuture> tryRead(ChunkPos pos) { -- return this.worker.loadAsync(pos).exceptionally(throwable -> { +- return this.simpleRegionStorage.read(pos).exceptionally(throwable -> { - if (throwable instanceof IOException iOException) { - LOGGER.error("Error reading chunk {} data from disk", pos, iOException); - return Optional.empty(); @@ -20958,21 +21059,30 @@ index 809da7fec1e1288a7a7bf1ee46c5b7bdd12bca01..bc6043a21227ce8c9c3879bc9c93c380 + // Paper end - rewrite chunk system } - private void readColumn(ChunkPos pos, DynamicOps ops, @Nullable T data) { + private void readColumn(ChunkPos pos, RegistryOps ops, @Nullable CompoundTag nbt) { + if (true) throw new IllegalStateException("Only chunk system can load in state, offending class:" + this.getClass().getName()); // Paper - rewrite chunk system - if (data == null) { + if (nbt == null) { for (int i = this.levelHeightAccessor.getMinSection(); i < this.levelHeightAccessor.getMaxSection(); i++) { this.storage.put(getKey(pos, i), Optional.empty()); -@@ -179,7 +178,7 @@ public class SectionStorage implements AutoCloseable { +@@ -138,7 +136,7 @@ public class SectionStorage implements AutoCloseable { + int j = getVersion(dynamic); + int k = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); + boolean bl = j != k; +- Dynamic dynamic2 = this.simpleRegionStorage.upgradeChunkTag(dynamic, j); ++ Dynamic dynamic2 = null; // Paper - rewrite chunk system + OptionalDynamic optionalDynamic = dynamic2.get("Sections"); + + for (int l = this.levelHeightAccessor.getMinSection(); l < this.levelHeightAccessor.getMaxSection(); l++) { +@@ -162,7 +160,7 @@ public class SectionStorage implements AutoCloseable { Dynamic dynamic = this.writeColumn(pos, registryOps); Tag tag = dynamic.getValue(); if (tag instanceof CompoundTag) { -- this.worker.store(pos, (CompoundTag)tag); -+ try { this.write(pos, (CompoundTag)tag); } catch (IOException ioexception) { SectionStorage.LOGGER.error("Error writing data to disk", ioexception); } // Paper - nuke IOWorker +- this.simpleRegionStorage.write(pos, (CompoundTag)tag); ++ try { this.write(pos, (CompoundTag)tag); } catch (IOException ex) { SectionStorage.LOGGER.error("Error writing poi chunk data to disk for chunk " + pos, ex); } // Paper - nuke IOWorker } else { LOGGER.error("Expected compound tag, got {}", tag); } -@@ -229,7 +228,7 @@ public class SectionStorage implements AutoCloseable { +@@ -212,7 +210,7 @@ public class SectionStorage implements AutoCloseable { } private static int getVersion(Dynamic dynamic) { @@ -20981,16 +21091,13 @@ index 809da7fec1e1288a7a7bf1ee46c5b7bdd12bca01..bc6043a21227ce8c9c3879bc9c93c380 } public void flush(ChunkPos pos) { -@@ -246,6 +245,9 @@ public class SectionStorage implements AutoCloseable { +@@ -229,6 +227,6 @@ public class SectionStorage implements AutoCloseable { @Override public void close() throws IOException { -- this.worker.close(); -+ //this.worker.close(); // Paper - nuke I/O worker - don't call the worker -+ super.close(); // Paper - nuke I/O worker - call super.close method which is responsible for closing used files. +- this.simpleRegionStorage.close(); ++ super.close(); // Paper - nuke I/O worker - don't call the worker } -+ -+ // Paper - rewrite chunk system } diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java index 74a285b8b018a9c94ccea519f1ce8b9e2ef3cb64..83a39f900551e39d5af6f17a339a386ddee4feef 100644 @@ -21068,7 +21175,7 @@ index 74a285b8b018a9c94ccea519f1ce8b9e2ef3cb64..83a39f900551e39d5af6f17a339a386d } } diff --git a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java -index 54308f1decc3982f30bf8b7a8a9d8865bfdbb9fd..902156477bdfc9917105f1229f760c26e5af302a 100644 +index 5d15c228c044a36c67014793decb314240cf6be1..dc765b92cc90f5f370254e68bbbdfa5add7935ce 100644 --- a/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java +++ b/src/main/java/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java @@ -87,7 +87,7 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { @@ -21090,10 +21197,10 @@ index 54308f1decc3982f30bf8b7a8a9d8865bfdbb9fd..902156477bdfc9917105f1229f760c26 while (iterator.hasNext()) { diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java -index 769a8c5788e6a01666b9b5ac24b02c632c6c9e48..09867812600b24b3b7d05b58f98582650d313fc8 100644 +index 97a0ce3044457d22ad532e24f3330c85f73f12dc..fdf5afdba68cdeddb351ac3932057a1aa2d3167f 100644 --- a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java +++ b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureCheck.java -@@ -49,8 +49,101 @@ public class StructureCheck { +@@ -47,8 +47,101 @@ public class StructureCheck { private final BiomeSource biomeSource; private final long seed; private final DataFixer fixerUpper; @@ -21197,18 +21304,18 @@ index 769a8c5788e6a01666b9b5ac24b02c632c6c9e48..09867812600b24b3b7d05b58f9858265 public StructureCheck( ChunkScanAccess chunkIoWorker, -@@ -80,7 +173,7 @@ public class StructureCheck { +@@ -76,7 +169,7 @@ public class StructureCheck { - public StructureCheckResult checkStart(ChunkPos pos, Structure type, boolean skipReferencedStructures) { + public StructureCheckResult checkStart(ChunkPos pos, Structure type, StructurePlacement placement, boolean skipReferencedStructures) { long l = pos.toLong(); - Object2IntMap object2IntMap = this.loadedChunks.get(l); + Object2IntMap object2IntMap = this.loadedChunksSafe.get(l); // Paper - rewrite chunk system - synchronise this class if (object2IntMap != null) { return this.checkStructureInfo(object2IntMap, type, skipReferencedStructures); } else { -@@ -88,9 +181,9 @@ public class StructureCheck { - if (structureCheckResult != null) { - return structureCheckResult; +@@ -86,9 +179,9 @@ public class StructureCheck { + } else if (!placement.applyAdditionalChunkRestrictions(pos.x, pos.z, this.seed)) { + return StructureCheckResult.START_NOT_PRESENT; } else { - boolean bl = this.featureChecks - .computeIfAbsent(type, structure2 -> new Long2BooleanOpenHashMap()) @@ -21219,7 +21326,7 @@ index 769a8c5788e6a01666b9b5ac24b02c632c6c9e48..09867812600b24b3b7d05b58f9858265 return !bl ? StructureCheckResult.START_NOT_PRESENT : StructureCheckResult.CHUNK_LOAD_NEEDED; } } -@@ -216,15 +309,26 @@ public class StructureCheck { +@@ -214,15 +307,26 @@ public class StructureCheck { } private void storeFullResults(long pos, Object2IntMap referencesByStructure) { @@ -21320,7 +21427,7 @@ index 47c2b2da9799690291396effb9e1b06d71efc6fd..2cdd18f724296f10cd4a522d1e819672 for (SavedTick savedTick : this.pendingTicks) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java -index 260ca4a9c170567b27488466f802c91212997f91..e47b00912fc76e9639f9c51d96e6d39da3c963e3 100644 +index 7dae8d91b74cc7df0745f0c121e3bea09b8d0b6d..1e2530c9e5212b6d2bdbc94817beddb4247dac73 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -115,7 +115,7 @@ public class CraftChunk implements Chunk { @@ -21386,18 +21493,18 @@ index 260ca4a9c170567b27488466f802c91212997f91..e47b00912fc76e9639f9c51d96e6d39d @Override diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 92369eb350fd795a4e99731d7ceda4f8b890791e..a76f966d72b749f1706363d33caa351b54e9fa14 100644 +index 1baf861ba5a59d3413647331f19391968ac2e8db..78c9a729f188e0888d3df1f5d988391488bc9a43 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1396,7 +1396,6 @@ public final class CraftServer implements Server { +@@ -1414,7 +1414,6 @@ public final class CraftServer implements Server { + // Paper end - 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 this.pluginManager.callEvent(new WorldLoadEvent(internal.getWorld())); return internal.getWorld(); -@@ -1441,7 +1440,7 @@ public final class CraftServer implements Server { +@@ -1459,7 +1458,7 @@ public final class CraftServer implements Server { } handle.getChunkSource().close(save); @@ -21406,7 +21513,7 @@ index 92369eb350fd795a4e99731d7ceda4f8b890791e..a76f966d72b749f1706363d33caa351b handle.convertable.close(); } catch (Exception ex) { this.getLogger().log(Level.SEVERE, null, ex); -@@ -2456,7 +2455,7 @@ public final class CraftServer implements Server { +@@ -2495,7 +2494,7 @@ public final class CraftServer implements Server { @Override public boolean isPrimaryThread() { @@ -21416,15 +21523,15 @@ index 92369eb350fd795a4e99731d7ceda4f8b890791e..a76f966d72b749f1706363d33caa351b // Paper start - Adventure diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 93c10b5a699f4f8a8aa97a0f666999fc4a495a5b..75ddeceb3f6c381b95dca0a93643aaca69d418e3 100644 +index 25ccbeace5bfc10fe3c885ea8dd984b08b4668ae..4bcfae1ca9c2ba590d800534bb199f947c114c20 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -508,10 +508,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -510,10 +510,14 @@ public class CraftWorld extends CraftRegionAccessor implements World { ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); if (playerChunk == null) return false; - playerChunk.getTickingChunkFuture().thenAccept(either -> { -- either.left().ifPresent(chunk -> { +- either.ifSuccess(chunk -> { + // Paper start - rewrite player chunk loader + net.minecraft.world.level.chunk.LevelChunk chunk = playerChunk.getSendingChunk(); + if (chunk == null) { @@ -21437,7 +21544,7 @@ index 93c10b5a699f4f8a8aa97a0f666999fc4a495a5b..75ddeceb3f6c381b95dca0a93643aaca ClientboundLevelChunkWithLightPacket refreshPacket = new ClientboundLevelChunkWithLightPacket(chunk, this.world.getLightEngine(), null, null); for (ServerPlayer player : playersInRange) { -@@ -519,8 +523,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -521,8 +525,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { player.connection.send(refreshPacket); } @@ -21447,7 +21554,7 @@ index 93c10b5a699f4f8a8aa97a0f666999fc4a495a5b..75ddeceb3f6c381b95dca0a93643aaca return true; } -@@ -599,20 +602,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -601,20 +604,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public Collection getPluginChunkTickets(int x, int z) { DistanceManager chunkDistanceManager = this.world.getChunkSource().chunkMap.distanceManager; @@ -21469,7 +21576,7 @@ index 93c10b5a699f4f8a8aa97a0f666999fc4a495a5b..75ddeceb3f6c381b95dca0a93643aaca } @Override -@@ -620,7 +610,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -622,7 +612,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { Map> ret = new HashMap<>(); DistanceManager chunkDistanceManager = this.world.getChunkSource().chunkMap.distanceManager; @@ -21478,7 +21585,7 @@ index 93c10b5a699f4f8a8aa97a0f666999fc4a495a5b..75ddeceb3f6c381b95dca0a93643aaca long chunkKey = chunkTickets.getLongKey(); SortedArraySet> tickets = chunkTickets.getValue(); -@@ -1308,12 +1298,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -1319,12 +1309,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public int getViewDistance() { @@ -21493,7 +21600,7 @@ index 93c10b5a699f4f8a8aa97a0f666999fc4a495a5b..75ddeceb3f6c381b95dca0a93643aaca } public BlockMetadataStore getBlockMetadata() { -@@ -2479,17 +2469,20 @@ public class CraftWorld extends CraftRegionAccessor implements World { +@@ -2487,17 +2477,20 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public void setSimulationDistance(final int simulationDistance) { @@ -21518,10 +21625,10 @@ index 93c10b5a699f4f8a8aa97a0f666999fc4a495a5b..75ddeceb3f6c381b95dca0a93643aaca // Paper start - implement pointers diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 25450884fa763b27ceaf16dd1bb3e80c10cb40c3..3fbc0312ed291a3878c26c005bfc79f417c695e4 100644 +index 21bd0ee68fa3785fdb1d9b30f0d55bb2b5d2a3ec..03e16706e378e7d4d1e74aca7daef62c3cbe3592 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -3400,31 +3400,31 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -3462,31 +3462,31 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public int getViewDistance() { @@ -21560,7 +21667,7 @@ index 25450884fa763b27ceaf16dd1bb3e80c10cb40c3..3fbc0312ed291a3878c26c005bfc79f4 } } diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java -index f6d003ea707f43287e52f8ffad24be35eeefec69..c6e5d3b7ef3886d0ffa9302d1270c048eaaeb671 100644 +index b65710b648e31ab74204b5abd9397d9e6e26dac4..c77f722131e0e40e9de29bf8d42f9bc5d8fa2f7d 100644 --- a/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java +++ b/src/main/java/org/bukkit/craftbukkit/generator/CustomChunkGenerator.java @@ -264,7 +264,7 @@ public class CustomChunkGenerator extends InternalChunkGenerator { @@ -21573,10 +21680,10 @@ index f6d003ea707f43287e52f8ffad24be35eeefec69..c6e5d3b7ef3886d0ffa9302d1270c048 @Override diff --git a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -index 7ed861cd67889e525ab4987c0afed245aca08833..86a20c91beff6b27e6ec886e49ba902b216106f2 100644 +index cd7f1309cf01a5f01a28aded03a36fe15adb1756..41a291d42667c38d3e5bbe47236772761e85929b 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java +++ b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -@@ -826,19 +826,39 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel { +@@ -815,19 +815,39 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel { @Nullable @Override public BlockState getBlockStateIfLoaded(final BlockPos blockposition) { @@ -21620,7 +21727,7 @@ index 7ed861cd67889e525ab4987c0afed245aca08833..86a20c91beff6b27e6ec886e49ba902b // Paper end } diff --git a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java -index 7956002e2d4d583c27e277562312d27ea6871557..819a67aa19c6bd624f5ed28d09b35ff2c151749a 100644 +index e8a73d34dbb372581b03018aade170a31c266099..210f454a840aa5564f7cbf33b83d31aa74814c84 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java +++ b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java @@ -268,4 +268,19 @@ public class DummyGeneratorAccess implements WorldGenLevel { @@ -21657,7 +21764,7 @@ index e8e3cc48cf1c58bd8151d1f28df28781859cd0e3..2e074c16dab1ead47914070329da0398 MinecraftServer.LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable()); // Paper throw new IllegalStateException( "Asynchronous " + reason + "!" ); diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java -index b1ac7338fa632611ea8332044b09070f78f8f5f1..a284d3b8526a743ba4389ec5b44d80af6d0e5a5f 100644 +index ad282d34919716b75acd10426cd071da9d064a51..9e5d08f57aa448552d100ca892c211d44441ef68 100644 --- a/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java @@ -8,7 +8,7 @@ import java.util.logging.Logger;