diff options
author | Spottedleaf <[email protected]> | 2024-06-19 10:29:03 -0700 |
---|---|---|
committer | Spottedleaf <[email protected]> | 2024-06-19 10:29:03 -0700 |
commit | 38428c0d6cf9aeea31fffe8f63b8a92c982c8a4f (patch) | |
tree | 2164311ca8ff8f4587c7ef1d34421305ac47f023 | |
parent | c0268ca86eeb5ca767e5e2860aa2d936e5e7fc4f (diff) | |
download | Paper-38428c0d6cf9aeea31fffe8f63b8a92c982c8a4f.tar.gz Paper-38428c0d6cf9aeea31fffe8f63b8a92c982c8a4f.zip |
Cleanup MCUtils patch for chunk system
Remove utilities that are unused, as well as replacing
the full chunk map with a concurrentutil implementation.
Additionally, fix the addition/removal of chunks to/from the
full chunk map so that getChunkIfLoaded correctly returns a
non-null chunk when calling the load or unload events.
79 files changed, 365 insertions, 2552 deletions
diff --git a/leaf_notes.txt b/leaf_notes.txt index 7c8d0c37cc..4bd9fdf957 100644 --- a/leaf_notes.txt +++ b/leaf_notes.txt @@ -1,13 +1,4 @@ - note: for paper, the chunk debug command -- rebase IntervalledCounter into util patch - mcutil diff - paper debug chunks --async in DedicatedServer - TODO keep around region file lock? -- mcutil#getTicketLevelFor is wrong, just delete it later - -on another note, clean up mcutils... - -apply todo in levelmixin - -to fix later: -- Change loadedChunkMap in ServerChunkCache to use concurrent long map diff --git a/patches/server/0009-MC-Utils.patch b/patches/server/0009-MC-Utils.patch index 1d50fab8f5..c12a8e7c5c 100644 --- a/patches/server/0009-MC-Utils.patch +++ b/patches/server/0009-MC-Utils.patch @@ -12,456 +12,6 @@ public net.minecraft.server.level.ServerChunkCache mainThreadProcessor public net.minecraft.server.level.ServerChunkCache$MainThreadExecutor public net.minecraft.world.level.chunk.LevelChunkSection states -diff --git a/src/main/java/com/destroystokyo/paper/util/concurrent/WeakSeqLock.java b/src/main/java/com/destroystokyo/paper/util/concurrent/WeakSeqLock.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4029dc68cf35d63aa70c4a76c35bf65a7fc6358f ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/util/concurrent/WeakSeqLock.java -@@ -0,0 +1,68 @@ -+package com.destroystokyo.paper.util.concurrent; -+ -+import java.util.concurrent.atomic.AtomicLong; -+ -+/** -+ * copied from https://github.com/Spottedleaf/ConcurrentUtil/blob/master/src/main/java/ca/spottedleaf/concurrentutil/lock/WeakSeqLock.java -+ * @author Spottedleaf -+ */ -+public final class WeakSeqLock { -+ // TODO when the switch to J11 is made, nuke this class from orbit -+ -+ protected final AtomicLong lock = new AtomicLong(); -+ -+ public WeakSeqLock() { -+ //VarHandle.storeStoreFence(); // warn: usages must be checked to ensure this behaviour isn't needed -+ } -+ -+ public void acquireWrite() { -+ // must be release-type write -+ this.lock.lazySet(this.lock.get() + 1); -+ } -+ -+ public boolean canRead(final long read) { -+ return (read & 1) == 0; -+ } -+ -+ public boolean tryAcquireWrite() { -+ this.acquireWrite(); -+ return true; -+ } -+ -+ public void releaseWrite() { -+ // must be acquire-type write -+ final long lock = this.lock.get(); // volatile here acts as store-store -+ this.lock.lazySet(lock + 1); -+ } -+ -+ public void abortWrite() { -+ // must be acquire-type write -+ final long lock = this.lock.get(); // volatile here acts as store-store -+ this.lock.lazySet(lock ^ 1); -+ } -+ -+ public long acquireRead() { -+ int failures = 0; -+ long curr; -+ -+ for (curr = this.lock.get(); !this.canRead(curr); curr = this.lock.get()) { -+ // without j11, our only backoff is the yield() call... -+ -+ if (++failures > 5_000) { /* TODO determine a threshold */ -+ Thread.yield(); -+ } -+ /* Better waiting is beyond the scope of this lock; if it is needed the lock is being misused */ -+ } -+ -+ //VarHandle.loadLoadFence(); // volatile acts as the load-load barrier -+ return curr; -+ } -+ -+ public boolean tryReleaseRead(final long read) { -+ return this.lock.get() == read; // volatile acts as the load-load barrier -+ } -+ -+ public long getSequentialCounter() { -+ return this.lock.get(); -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Int.java b/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Int.java -new file mode 100644 -index 0000000000000000000000000000000000000000..59868f37d14bbc0ece0836095cdad148778995e6 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Int.java -@@ -0,0 +1,162 @@ -+package com.destroystokyo.paper.util.map; -+ -+import com.destroystokyo.paper.util.concurrent.WeakSeqLock; -+import it.unimi.dsi.fastutil.longs.Long2IntMap; -+import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap; -+import it.unimi.dsi.fastutil.longs.LongIterator; -+import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -+import it.unimi.dsi.fastutil.objects.ObjectIterator; -+ -+/** -+ * @author Spottedleaf -+ */ -+public class QueuedChangesMapLong2Int { -+ -+ protected final Long2IntOpenHashMap updatingMap; -+ protected final Long2IntOpenHashMap visibleMap; -+ protected final Long2IntOpenHashMap queuedPuts; -+ protected final LongOpenHashSet queuedRemove; -+ -+ protected int queuedDefaultReturnValue; -+ -+ // we use a seqlock as writes are not common. -+ protected final WeakSeqLock updatingMapSeqLock = new WeakSeqLock(); -+ -+ public QueuedChangesMapLong2Int() { -+ this(16, 0.75f); -+ } -+ -+ public QueuedChangesMapLong2Int(final int capacity, final float loadFactor) { -+ this.updatingMap = new Long2IntOpenHashMap(capacity, loadFactor); -+ this.visibleMap = new Long2IntOpenHashMap(capacity, loadFactor); -+ this.queuedPuts = new Long2IntOpenHashMap(); -+ this.queuedRemove = new LongOpenHashSet(); -+ } -+ -+ public void queueDefaultReturnValue(final int dfl) { -+ this.queuedDefaultReturnValue = dfl; -+ this.updatingMap.defaultReturnValue(dfl); -+ } -+ -+ public int queueUpdate(final long k, final int v) { -+ this.queuedRemove.remove(k); -+ this.queuedPuts.put(k, v); -+ -+ return this.updatingMap.put(k, v); -+ } -+ -+ public int queueRemove(final long k) { -+ this.queuedPuts.remove(k); -+ this.queuedRemove.add(k); -+ -+ return this.updatingMap.remove(k); -+ } -+ -+ public int getUpdating(final long k) { -+ return this.updatingMap.get(k); -+ } -+ -+ public int getVisible(final long k) { -+ return this.visibleMap.get(k); -+ } -+ -+ public int getVisibleAsync(final long k) { -+ long readlock; -+ int ret = 0; -+ -+ do { -+ readlock = this.updatingMapSeqLock.acquireRead(); -+ try { -+ ret = this.visibleMap.get(k); -+ } catch (final Throwable thr) { -+ if (thr instanceof ThreadDeath) { -+ throw (ThreadDeath)thr; -+ } -+ // ignore... -+ continue; -+ } -+ -+ } while (!this.updatingMapSeqLock.tryReleaseRead(readlock)); -+ -+ return ret; -+ } -+ -+ public boolean performUpdates() { -+ this.updatingMapSeqLock.acquireWrite(); -+ this.visibleMap.defaultReturnValue(this.queuedDefaultReturnValue); -+ this.updatingMapSeqLock.releaseWrite(); -+ -+ if (this.queuedPuts.isEmpty() && this.queuedRemove.isEmpty()) { -+ return false; -+ } -+ -+ // update puts -+ final ObjectIterator<Long2IntMap.Entry> iterator0 = this.queuedPuts.long2IntEntrySet().fastIterator(); -+ while (iterator0.hasNext()) { -+ final Long2IntMap.Entry entry = iterator0.next(); -+ final long key = entry.getLongKey(); -+ final int val = entry.getIntValue(); -+ -+ this.updatingMapSeqLock.acquireWrite(); -+ try { -+ this.visibleMap.put(key, val); -+ } finally { -+ this.updatingMapSeqLock.releaseWrite(); -+ } -+ } -+ -+ this.queuedPuts.clear(); -+ -+ final LongIterator iterator1 = this.queuedRemove.iterator(); -+ while (iterator1.hasNext()) { -+ final long key = iterator1.nextLong(); -+ -+ this.updatingMapSeqLock.acquireWrite(); -+ try { -+ this.visibleMap.remove(key); -+ } finally { -+ this.updatingMapSeqLock.releaseWrite(); -+ } -+ } -+ -+ this.queuedRemove.clear(); -+ -+ return true; -+ } -+ -+ public boolean performUpdatesLockMap() { -+ this.updatingMapSeqLock.acquireWrite(); -+ try { -+ this.visibleMap.defaultReturnValue(this.queuedDefaultReturnValue); -+ -+ if (this.queuedPuts.isEmpty() && this.queuedRemove.isEmpty()) { -+ return false; -+ } -+ -+ // update puts -+ final ObjectIterator<Long2IntMap.Entry> iterator0 = this.queuedPuts.long2IntEntrySet().fastIterator(); -+ while (iterator0.hasNext()) { -+ final Long2IntMap.Entry entry = iterator0.next(); -+ final long key = entry.getLongKey(); -+ final int val = entry.getIntValue(); -+ -+ this.visibleMap.put(key, val); -+ } -+ -+ this.queuedPuts.clear(); -+ -+ final LongIterator iterator1 = this.queuedRemove.iterator(); -+ while (iterator1.hasNext()) { -+ final long key = iterator1.nextLong(); -+ -+ this.visibleMap.remove(key); -+ } -+ -+ this.queuedRemove.clear(); -+ -+ return true; -+ } finally { -+ this.updatingMapSeqLock.releaseWrite(); -+ } -+ } -+} -diff --git a/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Object.java b/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Object.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7bab31a312463cc963d9621cdc543a281459bd32 ---- /dev/null -+++ b/src/main/java/com/destroystokyo/paper/util/map/QueuedChangesMapLong2Object.java -@@ -0,0 +1,202 @@ -+package com.destroystokyo.paper.util.map; -+ -+import com.destroystokyo.paper.util.concurrent.WeakSeqLock; -+import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -+import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -+import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; -+import java.util.ArrayList; -+import java.util.Collection; -+import java.util.List; -+ -+/** -+ * @author Spottedleaf -+ */ -+public class QueuedChangesMapLong2Object<V> { -+ -+ protected static final Object REMOVED = new Object(); -+ -+ protected final Long2ObjectLinkedOpenHashMap<V> updatingMap; -+ protected final Long2ObjectLinkedOpenHashMap<V> visibleMap; -+ protected final Long2ObjectLinkedOpenHashMap<Object> queuedChanges; -+ -+ // we use a seqlock as writes are not common. -+ protected final WeakSeqLock updatingMapSeqLock = new WeakSeqLock(); -+ -+ public QueuedChangesMapLong2Object() { -+ this(16, 0.75f); // dfl for fastutil -+ } -+ -+ public QueuedChangesMapLong2Object(final int capacity, final float loadFactor) { -+ this.updatingMap = new Long2ObjectLinkedOpenHashMap<>(capacity, loadFactor); -+ this.visibleMap = new Long2ObjectLinkedOpenHashMap<>(capacity, loadFactor); -+ this.queuedChanges = new Long2ObjectLinkedOpenHashMap<>(); -+ } -+ -+ public V queueUpdate(final long k, final V value) { -+ this.queuedChanges.put(k, value); -+ return this.updatingMap.put(k, value); -+ } -+ -+ public V queueRemove(final long k) { -+ this.queuedChanges.put(k, REMOVED); -+ return this.updatingMap.remove(k); -+ } -+ -+ public V getUpdating(final long k) { -+ return this.updatingMap.get(k); -+ } -+ -+ public boolean updatingContainsKey(final long k) { -+ return this.updatingMap.containsKey(k); -+ } -+ -+ public V getVisible(final long k) { -+ return this.visibleMap.get(k); -+ } -+ -+ public boolean visibleContainsKey(final long k) { -+ return this.visibleMap.containsKey(k); -+ } -+ -+ public V getVisibleAsync(final long k) { -+ long readlock; -+ V ret = null; -+ -+ do { -+ readlock = this.updatingMapSeqLock.acquireRead(); -+ -+ try { -+ ret = this.visibleMap.get(k); -+ } catch (final Throwable thr) { -+ if (thr instanceof ThreadDeath) { -+ throw (ThreadDeath)thr; -+ } -+ // ignore... -+ continue; -+ } -+ -+ } while (!this.updatingMapSeqLock.tryReleaseRead(readlock)); -+ -+ return ret; -+ } -+ -+ public boolean visibleContainsKeyAsync(final long k) { -+ long readlock; -+ boolean ret = false; -+ -+ do { -+ readlock = this.updatingMapSeqLock.acquireRead(); -+ -+ try { -+ ret = this.visibleMap.containsKey(k); -+ } catch (final Throwable thr) { -+ if (thr instanceof ThreadDeath) { -+ throw (ThreadDeath)thr; -+ } -+ // ignore... -+ continue; -+ } -+ -+ } while (!this.updatingMapSeqLock.tryReleaseRead(readlock)); -+ -+ return ret; -+ } -+ -+ public Long2ObjectLinkedOpenHashMap<V> getVisibleMap() { -+ return this.visibleMap; -+ } -+ -+ public Long2ObjectLinkedOpenHashMap<V> getUpdatingMap() { -+ return this.updatingMap; -+ } -+ -+ public int getVisibleSize() { -+ return this.visibleMap.size(); -+ } -+ -+ public int getVisibleSizeAsync() { -+ long readlock; -+ int ret; -+ -+ do { -+ readlock = this.updatingMapSeqLock.acquireRead(); -+ ret = this.visibleMap.size(); -+ } while (!this.updatingMapSeqLock.tryReleaseRead(readlock)); -+ -+ return ret; -+ } -+ -+ // unlike mojang's impl this cannot be used async since it's not a view of an immutable map -+ public Collection<V> getUpdatingValues() { -+ return this.updatingMap.values(); -+ } -+ -+ public List<V> getUpdatingValuesCopy() { -+ return new ArrayList<>(this.updatingMap.values()); -+ } -+ -+ // unlike mojang's impl this cannot be used async since it's not a view of an immutable map -+ public Collection<V> getVisibleValues() { -+ return this.visibleMap.values(); -+ } -+ -+ public List<V> getVisibleValuesCopy() { -+ return new ArrayList<>(this.visibleMap.values()); -+ } -+ -+ public boolean performUpdates() { -+ if (this.queuedChanges.isEmpty()) { -+ return false; -+ } -+ -+ final ObjectBidirectionalIterator<Long2ObjectMap.Entry<Object>> iterator = this.queuedChanges.long2ObjectEntrySet().fastIterator(); -+ while (iterator.hasNext()) { -+ final Long2ObjectMap.Entry<Object> entry = iterator.next(); -+ final long key = entry.getLongKey(); -+ final Object val = entry.getValue(); -+ -+ this.updatingMapSeqLock.acquireWrite(); -+ try { -+ if (val == REMOVED) { -+ this.visibleMap.remove(key); -+ } else { -+ this.visibleMap.put(key, (V)val); -+ } -+ } finally { -+ this.updatingMapSeqLock.releaseWrite(); -+ } -+ } -+ -+ this.queuedChanges.clear(); -+ return true; -+ } -+ -+ public boolean performUpdatesLockMap() { -+ if (this.queuedChanges.isEmpty()) { -+ return false; -+ } -+ -+ final ObjectBidirectionalIterator<Long2ObjectMap.Entry<Object>> iterator = this.queuedChanges.long2ObjectEntrySet().fastIterator(); -+ -+ try { -+ this.updatingMapSeqLock.acquireWrite(); -+ -+ while (iterator.hasNext()) { -+ final Long2ObjectMap.Entry<Object> entry = iterator.next(); -+ final long key = entry.getLongKey(); -+ final Object val = entry.getValue(); -+ -+ if (val == REMOVED) { -+ this.visibleMap.remove(key); -+ } else { -+ this.visibleMap.put(key, (V)val); -+ } -+ } -+ } finally { -+ this.updatingMapSeqLock.releaseWrite(); -+ } -+ -+ this.queuedChanges.clear(); -+ return true; -+ } -+} diff --git a/src/main/java/com/destroystokyo/paper/util/maplist/ChunkList.java b/src/main/java/com/destroystokyo/paper/util/maplist/ChunkList.java new file mode 100644 index 0000000000000000000000000000000000000000..554f4d4e63c1431721989e6f502a32ccc53a8807 @@ -2178,495 +1728,12 @@ index 46cab7a8c7b87ab01b26074b04f5a02b3907cfc4..49019b4a9bc4e634d54a9b0acaf9229a + } + // Paper end } -diff --git a/src/main/java/io/papermc/paper/chunk/SingleThreadChunkRegionManager.java b/src/main/java/io/papermc/paper/chunk/SingleThreadChunkRegionManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a5f706d6f716b2a463ae58adcde69d9e665c7733 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/chunk/SingleThreadChunkRegionManager.java -@@ -0,0 +1,477 @@ -+package io.papermc.paper.chunk; -+ -+import io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet; -+import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -+import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet; -+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; -+import io.papermc.paper.util.MCUtil; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.world.level.ChunkPos; -+import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.Iterator; -+import java.util.List; -+import java.util.function.Supplier; -+ -+public final class SingleThreadChunkRegionManager { -+ -+ protected final int regionSectionMergeRadius; -+ protected final int regionSectionChunkSize; -+ public final int regionChunkShift; // log2(REGION_CHUNK_SIZE) -+ -+ public final ServerLevel world; -+ public final String name; -+ -+ protected final Long2ObjectOpenHashMap<RegionSection> regionsBySection = new Long2ObjectOpenHashMap<>(); -+ protected final ReferenceLinkedOpenHashSet<Region> needsRecalculation = new ReferenceLinkedOpenHashSet<>(); -+ protected final int minSectionRecalcCount; -+ protected final double maxDeadRegionPercent; -+ protected final Supplier<RegionData> regionDataSupplier; -+ protected final Supplier<RegionSectionData> regionSectionDataSupplier; -+ -+ public SingleThreadChunkRegionManager(final ServerLevel world, final int minSectionRecalcCount, -+ final double maxDeadRegionPercent, final int sectionMergeRadius, -+ final int regionSectionChunkShift, -+ final String name, final Supplier<RegionData> regionDataSupplier, -+ final Supplier<RegionSectionData> regionSectionDataSupplier) { -+ this.regionSectionMergeRadius = sectionMergeRadius; -+ this.regionSectionChunkSize = 1 << regionSectionChunkShift; -+ this.regionChunkShift = regionSectionChunkShift; -+ this.world = world; -+ this.name = name; -+ this.minSectionRecalcCount = Math.max(2, minSectionRecalcCount); -+ this.maxDeadRegionPercent = maxDeadRegionPercent; -+ this.regionDataSupplier = regionDataSupplier; -+ this.regionSectionDataSupplier = regionSectionDataSupplier; -+ } -+ -+ // tested via https://gist.github.com/Spottedleaf/aa7ade3451c37b4cac061fc77074db2f -+ -+ /* -+ protected void check() { -+ ReferenceOpenHashSet<Region<T>> checked = new ReferenceOpenHashSet<>(); -+ -+ for (RegionSection<T> section : this.regionsBySection.values()) { -+ if (!checked.add(section.region)) { -+ section.region.check(); -+ } -+ } -+ for (Region<T> region : this.needsRecalculation) { -+ region.check(); -+ } -+ } -+ */ -+ -+ protected void addToRecalcQueue(final Region region) { -+ this.needsRecalculation.add(region); -+ } -+ -+ protected void removeFromRecalcQueue(final Region region) { -+ this.needsRecalculation.remove(region); -+ } -+ -+ public RegionSection getRegionSection(final int chunkX, final int chunkZ) { -+ return this.regionsBySection.get(MCUtil.getCoordinateKey(chunkX >> this.regionChunkShift, chunkZ >> this.regionChunkShift)); -+ } -+ -+ public Region getRegion(final int chunkX, final int chunkZ) { -+ final RegionSection section = this.regionsBySection.get(MCUtil.getCoordinateKey(chunkX >> regionChunkShift, chunkZ >> regionChunkShift)); -+ return section != null ? section.region : null; -+ } -+ -+ private final List<Region> toMerge = new ArrayList<>(); -+ -+ protected RegionSection getOrCreateAndMergeSection(final int sectionX, final int sectionZ, final RegionSection force) { -+ final long sectionKey = MCUtil.getCoordinateKey(sectionX, sectionZ); -+ -+ if (force == null) { -+ RegionSection region = this.regionsBySection.get(sectionKey); -+ if (region != null) { -+ return region; -+ } -+ } -+ -+ int mergeCandidateSectionSize = -1; -+ Region mergeIntoCandidate = null; -+ -+ // find optimal candidate to merge into -+ -+ final int minX = sectionX - this.regionSectionMergeRadius; -+ final int maxX = sectionX + this.regionSectionMergeRadius; -+ final int minZ = sectionZ - this.regionSectionMergeRadius; -+ final int maxZ = sectionZ + this.regionSectionMergeRadius; -+ for (int currX = minX; currX <= maxX; ++currX) { -+ for (int currZ = minZ; currZ <= maxZ; ++currZ) { -+ final RegionSection section = this.regionsBySection.get(MCUtil.getCoordinateKey(currX, currZ)); -+ if (section == null) { -+ continue; -+ } -+ final Region region = section.region; -+ if (region.dead) { -+ throw new IllegalStateException("Dead region should not be in live region manager state: " + region); -+ } -+ final int sections = region.sections.size(); -+ -+ if (sections > mergeCandidateSectionSize) { -+ mergeCandidateSectionSize = sections; -+ mergeIntoCandidate = region; -+ } -+ this.toMerge.add(region); -+ } -+ } -+ -+ // merge -+ if (mergeIntoCandidate != null) { -+ for (int i = 0; i < this.toMerge.size(); ++i) { -+ final Region region = this.toMerge.get(i); -+ if (region.dead || mergeIntoCandidate == region) { -+ continue; -+ } -+ region.mergeInto(mergeIntoCandidate); -+ } -+ this.toMerge.clear(); -+ } else { -+ mergeIntoCandidate = new Region(this); -+ } -+ -+ final RegionSection section; -+ if (force == null) { -+ this.regionsBySection.put(sectionKey, section = new RegionSection(sectionKey, this)); -+ } else { -+ final RegionSection existing = this.regionsBySection.putIfAbsent(sectionKey, force); -+ if (existing != null) { -+ throw new IllegalStateException("Attempting to override section '" + existing.toStringWithRegion() + -+ ", with " + force.toStringWithRegion()); -+ } -+ -+ section = force; -+ } -+ -+ mergeIntoCandidate.addRegionSection(section); -+ //mergeIntoCandidate.check(); -+ //this.check(); -+ -+ return section; -+ } -+ -+ public void addChunk(final int chunkX, final int chunkZ) { -+ this.getOrCreateAndMergeSection(chunkX >> this.regionChunkShift, chunkZ >> this.regionChunkShift, null).addChunk(chunkX, chunkZ); -+ } -+ -+ public void removeChunk(final int chunkX, final int chunkZ) { -+ final RegionSection section = this.regionsBySection.get( -+ MCUtil.getCoordinateKey(chunkX >> this.regionChunkShift, chunkZ >> this.regionChunkShift) -+ ); -+ if (section != null) { -+ section.removeChunk(chunkX, chunkZ); -+ } else { -+ throw new IllegalStateException("Cannot remove chunk at (" + chunkX + "," + chunkZ + ") from region state, section does not exist"); -+ } -+ } -+ -+ public void recalculateRegions() { -+ for (int i = 0, len = this.needsRecalculation.size(); i < len; ++i) { -+ final Region region = this.needsRecalculation.removeFirst(); -+ -+ this.recalculateRegion(region); -+ //this.check(); -+ } -+ } -+ -+ protected void recalculateRegion(final Region region) { -+ region.markedForRecalc = false; -+ //region.check(); -+ // clear unused regions -+ for (final Iterator<RegionSection> iterator = region.deadSections.iterator(); iterator.hasNext();) { -+ final RegionSection deadSection = iterator.next(); -+ -+ if (deadSection.hasChunks()) { -+ throw new IllegalStateException("Dead section '" + deadSection.toStringWithRegion() + "' is marked dead but has chunks!"); -+ } -+ if (!region.removeRegionSection(deadSection)) { -+ throw new IllegalStateException("Region " + region + " has inconsistent state, it should contain section " + deadSection); -+ } -+ if (!this.regionsBySection.remove(deadSection.regionCoordinate, deadSection)) { -+ throw new IllegalStateException("Cannot remove dead section '" + -+ deadSection.toStringWithRegion() + "' from section state! State at section coordinate: " + -+ this.regionsBySection.get(deadSection.regionCoordinate)); -+ } -+ } -+ region.deadSections.clear(); -+ -+ // implicitly cover cases where size == 0 -+ if (region.sections.size() < this.minSectionRecalcCount) { -+ //region.check(); -+ return; -+ } -+ -+ // run a test to see if we actually need to recalculate -+ // TODO -+ -+ // destroy and rebuild the region -+ region.dead = true; -+ -+ // destroy region state -+ for (final Iterator<RegionSection> iterator = region.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ final RegionSection aliveSection = iterator.next(); -+ if (!aliveSection.hasChunks()) { -+ throw new IllegalStateException("Alive section '" + aliveSection.toStringWithRegion() + "' has no chunks!"); -+ } -+ if (!this.regionsBySection.remove(aliveSection.regionCoordinate, aliveSection)) { -+ throw new IllegalStateException("Cannot remove alive section '" + -+ aliveSection.toStringWithRegion() + "' from section state! State at section coordinate: " + -+ this.regionsBySection.get(aliveSection.regionCoordinate)); -+ } -+ } -+ -+ // rebuild regions -+ for (final Iterator<RegionSection> iterator = region.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ final RegionSection aliveSection = iterator.next(); -+ this.getOrCreateAndMergeSection(aliveSection.getSectionX(), aliveSection.getSectionZ(), aliveSection); -+ } -+ } -+ -+ public static final class Region { -+ protected final IteratorSafeOrderedReferenceSet<RegionSection> sections = new IteratorSafeOrderedReferenceSet<>(); -+ protected final ReferenceOpenHashSet<RegionSection> deadSections = new ReferenceOpenHashSet<>(16, 0.7f); -+ protected boolean dead; -+ protected boolean markedForRecalc; -+ -+ public final SingleThreadChunkRegionManager regionManager; -+ public final RegionData regionData; -+ -+ protected Region(final SingleThreadChunkRegionManager regionManager) { -+ this.regionManager = regionManager; -+ this.regionData = regionManager.regionDataSupplier.get(); -+ } -+ -+ public IteratorSafeOrderedReferenceSet.Iterator<RegionSection> getSections() { -+ return this.sections.iterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); -+ } -+ -+ protected final double getDeadSectionPercent() { -+ return (double)this.deadSections.size() / (double)this.sections.size(); -+ } -+ -+ /* -+ protected void check() { -+ if (this.dead) { -+ throw new IllegalStateException("Dead region!"); -+ } -+ for (final Iterator<RegionSection<T>> iterator = this.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ final RegionSection<T> section = iterator.next(); -+ if (section.region != this) { -+ throw new IllegalStateException("Region section must point to us!"); -+ } -+ if (this.regionManager.regionsBySection.get(section.regionCoordinate) != section) { -+ throw new IllegalStateException("Region section must match the regionmanager state!"); -+ } -+ } -+ } -+ */ -+ -+ // note: it is not true that the region at this point is not in any region. use the region field on the section -+ // to see if it is currently in another region. -+ protected final boolean addRegionSection(final RegionSection section) { -+ if (!this.sections.add(section)) { -+ return false; -+ } -+ -+ section.sectionData.addToRegion(section, section.region, this); -+ -+ section.region = this; -+ return true; -+ } -+ -+ protected final boolean removeRegionSection(final RegionSection section) { -+ if (!this.sections.remove(section)) { -+ return false; -+ } -+ -+ section.sectionData.removeFromRegion(section, this); -+ -+ return true; -+ } -+ -+ protected void mergeInto(final Region mergeTarget) { -+ if (this == mergeTarget) { -+ throw new IllegalStateException("Cannot merge a region onto itself"); -+ } -+ if (this.dead) { -+ throw new IllegalStateException("Source region is dead! Source " + this + ", target " + mergeTarget); -+ } else if (mergeTarget.dead) { -+ throw new IllegalStateException("Target region is dead! Source " + this + ", target " + mergeTarget); -+ } -+ this.dead = true; -+ if (this.markedForRecalc) { -+ this.regionManager.removeFromRecalcQueue(this); -+ } -+ -+ for (final Iterator<RegionSection> iterator = this.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ final RegionSection section = iterator.next(); -+ -+ if (!mergeTarget.addRegionSection(section)) { -+ throw new IllegalStateException("Target cannot contain source's sections! Source " + this + ", target " + mergeTarget); -+ } -+ } -+ -+ for (final RegionSection deadSection : this.deadSections) { -+ if (!this.sections.contains(deadSection)) { -+ throw new IllegalStateException("Source region does not even contain its own dead sections! Missing " + deadSection + " from region " + this); -+ } -+ mergeTarget.deadSections.add(deadSection); -+ } -+ //mergeTarget.check(); -+ } -+ -+ protected void markSectionAlive(final RegionSection section) { -+ this.deadSections.remove(section); -+ if (this.markedForRecalc && (this.sections.size() < this.regionManager.minSectionRecalcCount || this.getDeadSectionPercent() < this.regionManager.maxDeadRegionPercent)) { -+ this.regionManager.removeFromRecalcQueue(this); -+ this.markedForRecalc = false; -+ } -+ } -+ -+ protected void markSectionDead(final RegionSection section) { -+ this.deadSections.add(section); -+ if (!this.markedForRecalc && (this.sections.size() >= this.regionManager.minSectionRecalcCount || this.sections.size() == this.deadSections.size()) && this.getDeadSectionPercent() >= this.regionManager.maxDeadRegionPercent) { -+ this.regionManager.addToRecalcQueue(this); -+ this.markedForRecalc = true; -+ } -+ } -+ -+ @Override -+ public String toString() { -+ final StringBuilder ret = new StringBuilder(128); -+ -+ ret.append("Region{"); -+ ret.append("dead=").append(this.dead).append(','); -+ ret.append("markedForRecalc=").append(this.markedForRecalc).append(','); -+ -+ ret.append("sectionCount=").append(this.sections.size()).append(','); -+ ret.append("sections=["); -+ for (final Iterator<RegionSection> iterator = this.sections.unsafeIterator(IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); iterator.hasNext();) { -+ final RegionSection section = iterator.next(); -+ ret.append(section); -+ if (iterator.hasNext()) { -+ ret.append(','); -+ } -+ } -+ ret.append(']'); -+ -+ ret.append('}'); -+ return ret.toString(); -+ } -+ } -+ -+ public static final class RegionSection { -+ protected final long regionCoordinate; -+ protected final long[] chunksBitset; -+ protected int chunkCount; -+ protected Region region; -+ -+ public final SingleThreadChunkRegionManager regionManager; -+ public final RegionSectionData sectionData; -+ -+ protected RegionSection(final long regionCoordinate, final SingleThreadChunkRegionManager regionManager) { -+ this.regionCoordinate = regionCoordinate; -+ this.regionManager = regionManager; -+ this.chunksBitset = new long[Math.max(1, regionManager.regionSectionChunkSize * regionManager.regionSectionChunkSize / Long.SIZE)]; -+ this.sectionData = regionManager.regionSectionDataSupplier.get(); -+ } -+ -+ public int getSectionX() { -+ return MCUtil.getCoordinateX(this.regionCoordinate); -+ } -+ -+ public int getSectionZ() { -+ return MCUtil.getCoordinateZ(this.regionCoordinate); -+ } -+ -+ public Region getRegion() { -+ return this.region; -+ } -+ -+ private int getChunkIndex(final int chunkX, final int chunkZ) { -+ return (chunkX & (this.regionManager.regionSectionChunkSize - 1)) | ((chunkZ & (this.regionManager.regionSectionChunkSize - 1)) << this.regionManager.regionChunkShift); -+ } -+ -+ protected boolean hasChunks() { -+ return this.chunkCount != 0; -+ } -+ -+ protected void addChunk(final int chunkX, final int chunkZ) { -+ final int index = this.getChunkIndex(chunkX, chunkZ); -+ final long bitset = this.chunksBitset[index >>> 6]; // index / Long.SIZE -+ final long after = this.chunksBitset[index >>> 6] = bitset | (1L << (index & (Long.SIZE - 1))); -+ if (after == bitset) { -+ throw new IllegalStateException("Cannot add a chunk to a section which already has the chunk! RegionSection: " + this + ", global chunk: " + new ChunkPos(chunkX, chunkZ).toString()); -+ } -+ if (++this.chunkCount != 1) { -+ return; -+ } -+ this.region.markSectionAlive(this); -+ } -+ -+ protected void removeChunk(final int chunkX, final int chunkZ) { -+ final int index = this.getChunkIndex(chunkX, chunkZ); -+ final long before = this.chunksBitset[index >>> 6]; // index / Long.SIZE -+ final long bitset = this.chunksBitset[index >>> 6] = before & ~(1L << (index & (Long.SIZE - 1))); -+ if (before == bitset) { -+ throw new IllegalStateException("Cannot remove a chunk from a section which does not have that chunk! RegionSection: " + this + ", global chunk: " + new ChunkPos(chunkX, chunkZ).toString()); -+ } -+ if (--this.chunkCount != 0) { -+ return; -+ } -+ this.region.markSectionDead(this); -+ } -+ -+ @Override -+ public String toString() { -+ return "RegionSection{" + -+ "regionCoordinate=" + new ChunkPos(this.regionCoordinate).toString() + "," + -+ "chunkCount=" + this.chunkCount + "," + -+ "chunksBitset=" + toString(this.chunksBitset) + "," + -+ "hash=" + this.hashCode() + -+ "}"; -+ } -+ -+ public String toStringWithRegion() { -+ return "RegionSection{" + -+ "regionCoordinate=" + new ChunkPos(this.regionCoordinate).toString() + "," + -+ "chunkCount=" + this.chunkCount + "," + -+ "chunksBitset=" + toString(this.chunksBitset) + "," + -+ "hash=" + this.hashCode() + "," + -+ "region=" + this.region + -+ "}"; -+ } -+ -+ private static String toString(final long[] array) { -+ final StringBuilder ret = new StringBuilder(); -+ for (final long value : array) { -+ // zero pad the hex string -+ final char[] zeros = new char[Long.SIZE / 4]; -+ Arrays.fill(zeros, '0'); -+ final String string = Long.toHexString(value); -+ System.arraycopy(string.toCharArray(), 0, zeros, zeros.length - string.length(), string.length()); -+ -+ ret.append(zeros); -+ } -+ -+ return ret.toString(); -+ } -+ } -+ -+ public static interface RegionData { -+ -+ } -+ -+ public static interface RegionSectionData { -+ -+ public void removeFromRegion(final RegionSection section, final Region from); -+ -+ // removal from the old region is handled via removeFromRegion -+ public void addToRegion(final RegionSection section, final Region oldRegion, final Region newRegion); -+ -+ } -+} diff --git a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java new file mode 100644 -index 0000000000000000000000000000000000000000..0d0cb3e63acd5156b6f9d6d78cc949b0af36a77b +index 0000000000000000000000000000000000000000..a79abe9b26f68d573812e91554124783075ae17a --- /dev/null +++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java -@@ -0,0 +1,303 @@ +@@ -0,0 +1,297 @@ +package io.papermc.paper.chunk.system; + +import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; @@ -2720,12 +1787,16 @@ index 0000000000000000000000000000000000000000..0d0cb3e63acd5156b6f9d6d78cc949b0 + } + scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { + if (chunk == null) { -+ onComplete.accept(null); ++ if (onComplete != null) { ++ onComplete.accept(null); ++ } + } else { + if (chunk.getPersistedStatus().isOrAfter(toStatus)) { + scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); + } else { -+ onComplete.accept(null); ++ if (onComplete != null) { ++ onComplete.accept(null); ++ } + } + } + }); @@ -2757,8 +1828,6 @@ index 0000000000000000000000000000000000000000..0d0cb3e63acd5156b6f9d6d78cc949b0 + if (onComplete != null) { + onComplete.accept(chunk); + } -+ } catch (final ThreadDeath death) { -+ throw death; + } catch (final Throwable thr) { + LOGGER.error("Exception handling chunk load callback", thr); + SneakyThrow.sneaky(thr); @@ -2825,8 +1894,6 @@ index 0000000000000000000000000000000000000000..0d0cb3e63acd5156b6f9d6d78cc949b0 + if (onComplete != null) { + onComplete.accept(chunk); + } -+ } catch (final ThreadDeath death) { -+ throw death; + } catch (final Throwable thr) { + LOGGER.error("Exception handling chunk load callback", thr); + SneakyThrow.sneaky(thr); @@ -2905,21 +1972,15 @@ index 0000000000000000000000000000000000000000..0d0cb3e63acd5156b6f9d6d78cc949b0 + } + + public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { -+ final ChunkMap chunkMap = level.chunkSource.chunkMap; -+ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { -+ chunkMap.regionManagers.get(index).addChunk(holder.getPos().x, holder.getPos().z); -+ } ++ + } + + public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { -+ final ChunkMap chunkMap = level.chunkSource.chunkMap; -+ for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { -+ chunkMap.regionManagers.get(index).removeChunk(holder.getPos().x, holder.getPos().z); -+ } ++ + } + + public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { -+ chunk.playerChunk = holder; ++ + } + + public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { @@ -3368,14 +2429,16 @@ index 0000000000000000000000000000000000000000..16785bd5c0524f6bad0691ca7ecd4514 +} diff --git a/src/main/java/io/papermc/paper/util/IntervalledCounter.java b/src/main/java/io/papermc/paper/util/IntervalledCounter.java new file mode 100644 -index 0000000000000000000000000000000000000000..cea9c098ade00ee87b8efc8164ab72f5279758f0 +index 0000000000000000000000000000000000000000..c90acc3bde887b9c8f8d49fcc3195657c721bc14 --- /dev/null +++ b/src/main/java/io/papermc/paper/util/IntervalledCounter.java -@@ -0,0 +1,115 @@ +@@ -0,0 +1,128 @@ +package io.papermc.paper.util; + +public final class IntervalledCounter { + ++ private static final int INITIAL_SIZE = 8; ++ + protected long[] times; + protected long[] counts; + protected final long interval; @@ -3385,8 +2448,8 @@ index 0000000000000000000000000000000000000000..cea9c098ade00ee87b8efc8164ab72f5 + protected int tail; // exclusive + + public IntervalledCounter(final long interval) { -+ this.times = new long[8]; -+ this.counts = new long[8]; ++ this.times = new long[INITIAL_SIZE]; ++ this.counts = new long[INITIAL_SIZE]; + this.interval = interval; + } + @@ -3441,13 +2504,13 @@ index 0000000000000000000000000000000000000000..cea9c098ade00ee87b8efc8164ab72f5 + this.tail = nextTail; + } + -+ public void updateAndAdd(final int count) { ++ public void updateAndAdd(final long count) { + final long currTime = System.nanoTime(); + this.updateCurrentTime(currTime); + this.addTime(currTime, count); + } + -+ public void updateAndAdd(final int count, final long currTime) { ++ public void updateAndAdd(final long count, final long currTime) { + this.updateCurrentTime(currTime); + this.addTime(currTime, count); + } @@ -3467,9 +2530,12 @@ index 0000000000000000000000000000000000000000..cea9c098ade00ee87b8efc8164ab72f5 + this.tail = size; + + if (tail >= head) { ++ // sequentially ordered from [head, tail) + System.arraycopy(oldElements, head, newElements, 0, size); + System.arraycopy(oldCounts, head, newCounts, 0, size); + } else { ++ // ordered from [head, length) ++ // then followed by [0, tail) + System.arraycopy(oldElements, head, newElements, 0, oldElements.length - head); + System.arraycopy(oldElements, 0, newElements, oldElements.length - head, tail); + @@ -3480,19 +2546,27 @@ index 0000000000000000000000000000000000000000..cea9c098ade00ee87b8efc8164ab72f5 + + // returns in units per second + public double getRate() { -+ return this.size() / (this.interval * 1.0e-9); ++ return (double)this.sum / ((double)this.interval * 1.0E-9); + } + -+ public long size() { ++ public long getInterval() { ++ return this.interval; ++ } ++ ++ public long getSum() { + return this.sum; + } ++ ++ public int totalDataPoints() { ++ return this.tail >= this.head ? (this.tail - this.head) : (this.tail + (this.counts.length - this.head)); ++ } +} diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java new file mode 100644 -index 0000000000000000000000000000000000000000..eb36bef19e6729c1cc44aefa927317963aba929e +index 0000000000000000000000000000000000000000..c6c723d9378c593c8608d5940f63c98dff097cd0 --- /dev/null +++ b/src/main/java/io/papermc/paper/util/MCUtil.java -@@ -0,0 +1,554 @@ +@@ -0,0 +1,550 @@ +package io.papermc.paper.util; + +import com.google.common.collect.ImmutableList; @@ -4020,10 +3094,6 @@ index 0000000000000000000000000000000000000000..eb36bef19e6729c1cc44aefa92731796 + } + } + -+ public static int getTicketLevelFor(net.minecraft.world.level.chunk.status.ChunkStatus status) { -+ return net.minecraft.server.level.ChunkMap.MAX_VIEW_DISTANCE + io.papermc.paper.chunk.system.ChunkSystem.getDistance(status); -+ } -+ + @NotNull + public static <T> List<T> copyListAndAdd(@NotNull final List<T> original, + @NotNull final T newElement) { @@ -4469,1033 +3539,6 @@ index 0000000000000000000000000000000000000000..0fd814f1d65c111266a2b20f86561839 + } + } +} -diff --git a/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java b/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java -new file mode 100644 -index 0000000000000000000000000000000000000000..470402573bc31106d5a63e415b958fb7f9c36aa9 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java -@@ -0,0 +1,297 @@ -+package io.papermc.paper.util.misc; -+ -+import io.papermc.paper.util.CoordinateUtils; -+import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -+import it.unimi.dsi.fastutil.longs.LongIterator; -+import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; -+ -+public final class Delayed26WayDistancePropagator3D { -+ -+ // this map is considered "stale" unless updates are propagated. -+ protected final Delayed8WayDistancePropagator2D.LevelMap levels = new Delayed8WayDistancePropagator2D.LevelMap(8192*2, 0.6f); -+ -+ // this map is never stale -+ protected final Long2ByteOpenHashMap sources = new Long2ByteOpenHashMap(4096, 0.6f); -+ -+ // Generally updates to positions are made close to other updates, so we link to decrease cache misses when -+ // propagating updates -+ protected final LongLinkedOpenHashSet updatedSources = new LongLinkedOpenHashSet(); -+ -+ @FunctionalInterface -+ public static interface LevelChangeCallback { -+ -+ /** -+ * This can be called for intermediate updates. So do not rely on newLevel being close to or -+ * the exact level that is expected after a full propagation has occured. -+ */ -+ public void onLevelUpdate(final long coordinate, final byte oldLevel, final byte newLevel); -+ -+ } -+ -+ protected final LevelChangeCallback changeCallback; -+ -+ public Delayed26WayDistancePropagator3D() { -+ this(null); -+ } -+ -+ public Delayed26WayDistancePropagator3D(final LevelChangeCallback changeCallback) { -+ this.changeCallback = changeCallback; -+ } -+ -+ public int getLevel(final long pos) { -+ return this.levels.get(pos); -+ } -+ -+ public int getLevel(final int x, final int y, final int z) { -+ return this.levels.get(CoordinateUtils.getChunkSectionKey(x, y, z)); -+ } -+ -+ public void setSource(final int x, final int y, final int z, final int level) { -+ this.setSource(CoordinateUtils.getChunkSectionKey(x, y, z), level); -+ } -+ -+ public void setSource(final long coordinate, final int level) { -+ if ((level & 63) != level || level == 0) { -+ throw new IllegalArgumentException("Level must be in (0, 63], not " + level); -+ } -+ -+ final byte byteLevel = (byte)level; -+ final byte oldLevel = this.sources.put(coordinate, byteLevel); -+ -+ if (oldLevel == byteLevel) { -+ return; // nothing to do -+ } -+ -+ // queue to update later -+ this.updatedSources.add(coordinate); -+ } -+ -+ public void removeSource(final int x, final int y, final int z) { -+ this.removeSource(CoordinateUtils.getChunkSectionKey(x, y, z)); -+ } -+ -+ public void removeSource(final long coordinate) { -+ if (this.sources.remove(coordinate) != 0) { -+ this.updatedSources.add(coordinate); -+ } -+ } -+ -+ // queues used for BFS propagating levels -+ protected final Delayed8WayDistancePropagator2D.WorkQueue[] levelIncreaseWorkQueues = new Delayed8WayDistancePropagator2D.WorkQueue[64]; -+ { -+ for (int i = 0; i < this.levelIncreaseWorkQueues.length; ++i) { -+ this.levelIncreaseWorkQueues[i] = new Delayed8WayDistancePropagator2D.WorkQueue(); -+ } -+ } -+ protected final Delayed8WayDistancePropagator2D.WorkQueue[] levelRemoveWorkQueues = new Delayed8WayDistancePropagator2D.WorkQueue[64]; -+ { -+ for (int i = 0; i < this.levelRemoveWorkQueues.length; ++i) { -+ this.levelRemoveWorkQueues[i] = new Delayed8WayDistancePropagator2D.WorkQueue(); -+ } -+ } -+ protected long levelIncreaseWorkQueueBitset; -+ protected long levelRemoveWorkQueueBitset; -+ -+ protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) { -+ final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[level]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelIncreaseWorkQueueBitset |= (1L << level); -+ } -+ -+ protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) { -+ final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[index]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelIncreaseWorkQueueBitset |= (1L << index); -+ } -+ -+ protected final void addToRemoveWorkQueue(final long coordinate, final byte level) { -+ final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[level]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelRemoveWorkQueueBitset |= (1L << level); -+ } -+ -+ public boolean propagateUpdates() { -+ if (this.updatedSources.isEmpty()) { -+ return false; -+ } -+ -+ boolean ret = false; -+ -+ for (final LongIterator iterator = this.updatedSources.iterator(); iterator.hasNext();) { -+ final long coordinate = iterator.nextLong(); -+ -+ final byte currentLevel = this.levels.get(coordinate); -+ final byte updatedSource = this.sources.get(coordinate); -+ -+ if (currentLevel == updatedSource) { -+ continue; -+ } -+ ret = true; -+ -+ if (updatedSource > currentLevel) { -+ // level increase -+ this.addToIncreaseWorkQueue(coordinate, updatedSource); -+ } else { -+ // level decrease -+ this.addToRemoveWorkQueue(coordinate, currentLevel); -+ // if the current coordinate is a source, then the decrease propagation will detect that and queue -+ // the source propagation -+ } -+ } -+ -+ this.updatedSources.clear(); -+ -+ // propagate source level increases first for performance reasons (in crowded areas hopefully the additions -+ // make the removes remove less) -+ this.propagateIncreases(); -+ -+ // now we propagate the decreases (which will then re-propagate clobbered sources) -+ this.propagateDecreases(); -+ -+ return ret; -+ } -+ -+ protected void propagateIncreases() { -+ for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset); -+ this.levelIncreaseWorkQueueBitset != 0L; -+ this.levelIncreaseWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset)) { -+ -+ final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex]; -+ while (!queue.queuedLevels.isEmpty()) { -+ final long coordinate = queue.queuedCoordinates.removeFirstLong(); -+ byte level = queue.queuedLevels.removeFirstByte(); -+ -+ final boolean neighbourCheck = level < 0; -+ -+ final byte currentLevel; -+ if (neighbourCheck) { -+ level = (byte)-level; -+ currentLevel = this.levels.get(coordinate); -+ } else { -+ currentLevel = this.levels.putIfGreater(coordinate, level); -+ } -+ -+ if (neighbourCheck) { -+ // used when propagating from decrease to indicate that this level needs to check its neighbours -+ // this means the level at coordinate could be equal, but would still need neighbours checked -+ -+ if (currentLevel != level) { -+ // something caused the level to change, which means something propagated to it (which means -+ // us propagating here is redundant), or something removed the level (which means we -+ // cannot propagate further) -+ continue; -+ } -+ } else if (currentLevel >= level) { -+ // something higher/equal propagated -+ continue; -+ } -+ if (this.changeCallback != null) { -+ this.changeCallback.onLevelUpdate(coordinate, currentLevel, level); -+ } -+ -+ if (level == 1) { -+ // can't propagate 0 to neighbours -+ continue; -+ } -+ -+ // propagate to neighbours -+ final byte neighbourLevel = (byte)(level - 1); -+ final int x = CoordinateUtils.getChunkSectionX(coordinate); -+ final int y = CoordinateUtils.getChunkSectionY(coordinate); -+ final int z = CoordinateUtils.getChunkSectionZ(coordinate); -+ -+ for (int dy = -1; dy <= 1; ++dy) { -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ if ((dy | dz | dx) == 0) { -+ // already propagated to coordinate -+ continue; -+ } -+ -+ // sure we can check the neighbour level in the map right now and avoid a propagation, -+ // but then we would still have to recheck it when popping the value off of the queue! -+ // so just avoid the double lookup -+ final long neighbourCoordinate = CoordinateUtils.getChunkSectionKey(dx + x, dy + y, dz + z); -+ this.addToIncreaseWorkQueue(neighbourCoordinate, neighbourLevel); -+ } -+ } -+ } -+ } -+ } -+ } -+ -+ protected void propagateDecreases() { -+ for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset); -+ this.levelRemoveWorkQueueBitset != 0L; -+ this.levelRemoveWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset)) { -+ -+ final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[queueIndex]; -+ while (!queue.queuedLevels.isEmpty()) { -+ final long coordinate = queue.queuedCoordinates.removeFirstLong(); -+ final byte level = queue.queuedLevels.removeFirstByte(); -+ -+ final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level); -+ if (currentLevel == 0) { -+ // something else removed -+ continue; -+ } -+ -+ if (currentLevel > level) { -+ // something higher propagated here or we hit the propagation of another source -+ // in the second case we need to re-propagate because we could have just clobbered another source's -+ // propagation -+ this.addToIncreaseWorkQueue(coordinate, currentLevel, (byte)-currentLevel); // indicate to the increase code that the level's neighbours need checking -+ continue; -+ } -+ -+ if (this.changeCallback != null) { -+ this.changeCallback.onLevelUpdate(coordinate, currentLevel, (byte)0); -+ } -+ -+ final byte source = this.sources.get(coordinate); -+ if (source != 0) { -+ // must re-propagate source later -+ this.addToIncreaseWorkQueue(coordinate, source); -+ } -+ -+ if (level == 0) { -+ // can't propagate -1 to neighbours -+ // we have to check neighbours for removing 1 just in case the neighbour is 2 -+ continue; -+ } -+ -+ // propagate to neighbours -+ final byte neighbourLevel = (byte)(level - 1); -+ final int x = CoordinateUtils.getChunkSectionX(coordinate); -+ final int y = CoordinateUtils.getChunkSectionY(coordinate); -+ final int z = CoordinateUtils.getChunkSectionZ(coordinate); -+ -+ for (int dy = -1; dy <= 1; ++dy) { -+ for (int dz = -1; dz <= 1; ++dz) { -+ for (int dx = -1; dx <= 1; ++dx) { -+ if ((dy | dz | dx) == 0) { -+ // already propagated to coordinate -+ continue; -+ } -+ -+ // sure we can check the neighbour level in the map right now and avoid a propagation, -+ // but then we would still have to recheck it when popping the value off of the queue! -+ // so just avoid the double lookup -+ final long neighbourCoordinate = CoordinateUtils.getChunkSectionKey(dx + x, dy + y, dz + z); -+ this.addToRemoveWorkQueue(neighbourCoordinate, neighbourLevel); -+ } -+ } -+ } -+ } -+ } -+ -+ // propagate sources we clobbered in the process -+ this.propagateIncreases(); -+ } -+} -diff --git a/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java b/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java -new file mode 100644 -index 0000000000000000000000000000000000000000..808d1449ac44ae86a650932365081fbaf178d141 ---- /dev/null -+++ b/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java -@@ -0,0 +1,718 @@ -+package io.papermc.paper.util.misc; -+ -+import it.unimi.dsi.fastutil.HashCommon; -+import it.unimi.dsi.fastutil.bytes.ByteArrayFIFOQueue; -+import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap; -+import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; -+import it.unimi.dsi.fastutil.longs.LongIterator; -+import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; -+import io.papermc.paper.util.MCUtil; -+ -+public final class Delayed8WayDistancePropagator2D { -+ -+ // Test -+ /* -+ protected static void test(int x, int z, com.destroystokyo.paper.util.misc.DistanceTrackingAreaMap<Ticket> reference, Delayed8WayDistancePropagator2D test) { -+ int got = test.getLevel(x, z); -+ -+ int expect = 0; -+ Object[] nearest = reference.getObjectsInRange(x, z) == null ? null : reference.getObjectsInRange(x, z).getBackingSet(); -+ if (nearest != null) { -+ for (Object _obj : nearest) { -+ if (_obj instanceof Ticket) { -+ Ticket ticket = (Ticket)_obj; -+ long ticketCoord = reference.getLastCoordinate(ticket); -+ int viewDistance = reference.getLastViewDistance(ticket); -+ int distance = Math.max(com.destroystokyo.paper.util.math.IntegerUtil.branchlessAbs(MCUtil.getCoordinateX(ticketCoord) - x), -+ com.destroystokyo.paper.util.math.IntegerUtil.branchlessAbs(MCUtil.getCoordinateZ(ticketCoord) - z)); -+ int level = viewDistance - distance; -+ if (level > expect) { -+ expect = level; -+ } -+ } -+ } -+ } -+ -+ if (expect != got) { -+ throw new IllegalStateException("Expected " + expect + " at pos (" + x + "," + z + ") but got " + got); -+ } -+ } -+ -+ static class Ticket { -+ -+ int x; -+ int z; -+ -+ final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<Ticket> empty -+ = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<>(this); -+ -+ } -+ -+ public static void main(final String[] args) { -+ com.destroystokyo.paper.util.misc.DistanceTrackingAreaMap<Ticket> reference = new com.destroystokyo.paper.util.misc.DistanceTrackingAreaMap<Ticket>() { -+ @Override -+ protected com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<Ticket> getEmptySetFor(Ticket object) { -+ return object.empty; -+ } -+ }; -+ Delayed8WayDistancePropagator2D test = new Delayed8WayDistancePropagator2D(); -+ -+ final int maxDistance = 64; -+ // test origin -+ { -+ Ticket originTicket = new Ticket(); -+ int originDistance = 31; -+ // test single source -+ reference.add(originTicket, 0, 0, originDistance); -+ test.setSource(0, 0, originDistance); test.propagateUpdates(); // set and propagate -+ for (int dx = -originDistance; dx <= originDistance; ++dx) { -+ for (int dz = -originDistance; dz <= originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ // test single source decrease -+ reference.update(originTicket, 0, 0, originDistance/2); -+ test.setSource(0, 0, originDistance/2); test.propagateUpdates(); // set and propagate -+ for (int dx = -originDistance; dx <= originDistance; ++dx) { -+ for (int dz = -originDistance; dz <= originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ // test source increase -+ originDistance = 2*originDistance; -+ reference.update(originTicket, 0, 0, originDistance); -+ test.setSource(0, 0, originDistance); test.propagateUpdates(); // set and propagate -+ for (int dx = -4*originDistance; dx <= 4*originDistance; ++dx) { -+ for (int dz = -4*originDistance; dz <= 4*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ reference.remove(originTicket); -+ test.removeSource(0, 0); test.propagateUpdates(); -+ } -+ -+ // test multiple sources at origin -+ { -+ int originDistance = 31; -+ java.util.List<Ticket> list = new java.util.ArrayList<>(); -+ for (int i = 0; i < 10; ++i) { -+ Ticket a = new Ticket(); -+ list.add(a); -+ a.x = (i & 1) == 1 ? -i : i; -+ a.z = (i & 1) == 1 ? -i : i; -+ } -+ for (Ticket ticket : list) { -+ reference.add(ticket, ticket.x, ticket.z, originDistance); -+ test.setSource(ticket.x, ticket.z, originDistance); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { -+ for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket level decrease -+ -+ for (Ticket ticket : list) { -+ reference.update(ticket, ticket.x, ticket.z, originDistance/2); -+ test.setSource(ticket.x, ticket.z, originDistance/2); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { -+ for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket level increase -+ -+ for (Ticket ticket : list) { -+ reference.update(ticket, ticket.x, ticket.z, originDistance*2); -+ test.setSource(ticket.x, ticket.z, originDistance*2); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { -+ for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket remove -+ for (int i = 0, len = list.size(); i < len; ++i) { -+ if ((i & 3) != 0) { -+ continue; -+ } -+ Ticket ticket = list.get(i); -+ reference.remove(ticket); -+ test.removeSource(ticket.x, ticket.z); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { -+ for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ } -+ -+ // now test at coordinate offsets -+ // test offset -+ { -+ Ticket originTicket = new Ticket(); -+ int originDistance = 31; -+ int offX = 54432; -+ int offZ = -134567; -+ // test single source -+ reference.add(originTicket, offX, offZ, originDistance); -+ test.setSource(offX, offZ, originDistance); test.propagateUpdates(); // set and propagate -+ for (int dx = -originDistance; dx <= originDistance; ++dx) { -+ for (int dz = -originDistance; dz <= originDistance; ++dz) { -+ test(dx + offX, dz + offZ, reference, test); -+ } -+ } -+ // test single source decrease -+ reference.update(originTicket, offX, offZ, originDistance/2); -+ test.setSource(offX, offZ, originDistance/2); test.propagateUpdates(); // set and propagate -+ for (int dx = -originDistance; dx <= originDistance; ++dx) { -+ for (int dz = -originDistance; dz <= originDistance; ++dz) { -+ test(dx + offX, dz + offZ, reference, test); -+ } -+ } -+ // test source increase -+ originDistance = 2*originDistance; -+ reference.update(originTicket, offX, offZ, originDistance); -+ test.setSource(offX, offZ, originDistance); test.propagateUpdates(); // set and propagate -+ for (int dx = -4*originDistance; dx <= 4*originDistance; ++dx) { -+ for (int dz = -4*originDistance; dz <= 4*originDistance; ++dz) { -+ test(dx + offX, dz + offZ, reference, test); -+ } -+ } -+ -+ reference.remove(originTicket); -+ test.removeSource(offX, offZ); test.propagateUpdates(); -+ } -+ -+ // test multiple sources at origin -+ { -+ int originDistance = 31; -+ int offX = 54432; -+ int offZ = -134567; -+ java.util.List<Ticket> list = new java.util.ArrayList<>(); -+ for (int i = 0; i < 10; ++i) { -+ Ticket a = new Ticket(); -+ list.add(a); -+ a.x = offX + ((i & 1) == 1 ? -i : i); -+ a.z = offZ + ((i & 1) == 1 ? -i : i); -+ } -+ for (Ticket ticket : list) { -+ reference.add(ticket, ticket.x, ticket.z, originDistance); -+ test.setSource(ticket.x, ticket.z, originDistance); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { -+ for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket level decrease -+ -+ for (Ticket ticket : list) { -+ reference.update(ticket, ticket.x, ticket.z, originDistance/2); -+ test.setSource(ticket.x, ticket.z, originDistance/2); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -8*originDistance; dx <= 8*originDistance; ++dx) { -+ for (int dz = -8*originDistance; dz <= 8*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket level increase -+ -+ for (Ticket ticket : list) { -+ reference.update(ticket, ticket.x, ticket.z, originDistance*2); -+ test.setSource(ticket.x, ticket.z, originDistance*2); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { -+ for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ -+ // test ticket remove -+ for (int i = 0, len = list.size(); i < len; ++i) { -+ if ((i & 3) != 0) { -+ continue; -+ } -+ Ticket ticket = list.get(i); -+ reference.remove(ticket); -+ test.removeSource(ticket.x, ticket.z); -+ } -+ test.propagateUpdates(); -+ -+ for (int dx = -16*originDistance; dx <= 16*originDistance; ++dx) { -+ for (int dz = -16*originDistance; dz <= 16*originDistance; ++dz) { -+ test(dx, dz, reference, test); -+ } -+ } -+ } -+ } -+ */ -+ -+ // this map is considered "stale" unless updates are propagated. -+ protected final LevelMap levels = new LevelMap(8192*2, 0.6f); -+ -+ // this map is never stale -+ protected final Long2ByteOpenHashMap sources = new Long2ByteOpenHashMap(4096, 0.6f); -+ -+ // Generally updates to positions are made close to other updates, so we link to decrease cache misses when -+ // propagating updates -+ protected final LongLinkedOpenHashSet updatedSources = new LongLinkedOpenHashSet(); -+ -+ @FunctionalInterface -+ public static interface LevelChangeCallback { -+ -+ /** -+ * This can be called for intermediate updates. So do not rely on newLevel being close to or -+ * the exact level that is expected after a full propagation has occured. -+ */ -+ public void onLevelUpdate(final long coordinate, final byte oldLevel, final byte newLevel); -+ -+ } -+ -+ protected final LevelChangeCallback changeCallback; -+ -+ public Delayed8WayDistancePropagator2D() { -+ this(null); -+ } -+ -+ public Delayed8WayDistancePropagator2D(final LevelChangeCallback changeCallback) { -+ this.changeCallback = changeCallback; -+ } -+ -+ public int getLevel(final long pos) { -+ return this.levels.get(pos); -+ } -+ -+ public int getLevel(final int x, final int z) { -+ return this.levels.get(MCUtil.getCoordinateKey(x, z)); -+ } -+ -+ public void setSource(final int x, final int z, final int level) { -+ this.setSource(MCUtil.getCoordinateKey(x, z), level); -+ } -+ -+ public void setSource(final long coordinate, final int level) { -+ if ((level & 63) != level || level == 0) { -+ throw new IllegalArgumentException("Level must be in (0, 63], not " + level); -+ } -+ -+ final byte byteLevel = (byte)level; -+ final byte oldLevel = this.sources.put(coordinate, byteLevel); -+ -+ if (oldLevel == byteLevel) { -+ return; // nothing to do -+ } -+ -+ // queue to update later -+ this.updatedSources.add(coordinate); -+ } -+ -+ public void removeSource(final int x, final int z) { -+ this.removeSource(MCUtil.getCoordinateKey(x, z)); -+ } -+ -+ public void removeSource(final long coordinate) { -+ if (this.sources.remove(coordinate) != 0) { -+ this.updatedSources.add(coordinate); -+ } -+ } -+ -+ // queues used for BFS propagating levels -+ protected final WorkQueue[] levelIncreaseWorkQueues = new WorkQueue[64]; -+ { -+ for (int i = 0; i < this.levelIncreaseWorkQueues.length; ++i) { -+ this.levelIncreaseWorkQueues[i] = new WorkQueue(); -+ } -+ } -+ protected final WorkQueue[] levelRemoveWorkQueues = new WorkQueue[64]; -+ { -+ for (int i = 0; i < this.levelRemoveWorkQueues.length; ++i) { -+ this.levelRemoveWorkQueues[i] = new WorkQueue(); -+ } -+ } -+ protected long levelIncreaseWorkQueueBitset; -+ protected long levelRemoveWorkQueueBitset; -+ -+ protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) { -+ final WorkQueue queue = this.levelIncreaseWorkQueues[level]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelIncreaseWorkQueueBitset |= (1L << level); -+ } -+ -+ protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) { -+ final WorkQueue queue = this.levelIncreaseWorkQueues[index]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelIncreaseWorkQueueBitset |= (1L << index); -+ } -+ -+ protected final void addToRemoveWorkQueue(final long coordinate, final byte level) { -+ final WorkQueue queue = this.levelRemoveWorkQueues[level]; -+ queue.queuedCoordinates.enqueue(coordinate); -+ queue.queuedLevels.enqueue(level); -+ -+ this.levelRemoveWorkQueueBitset |= (1L << level); -+ } -+ -+ public boolean propagateUpdates() { -+ if (this.updatedSources.isEmpty()) { -+ return false; -+ } -+ -+ boolean ret = false; -+ -+ for (final LongIterator iterator = this.updatedSources.iterator(); iterator.hasNext();) { -+ final long coordinate = iterator.nextLong(); -+ -+ final byte currentLevel = this.levels.get(coordinate); -+ final byte updatedSource = this.sources.get(coordinate); -+ -+ if (currentLevel == updatedSource) { -+ continue; -+ } -+ ret = true; -+ -+ if (updatedSource > currentLevel) { -+ // level increase -+ this.addToIncreaseWorkQueue(coordinate, updatedSource); -+ } else { -+ // level decrease -+ this.addToRemoveWorkQueue(coordinate, currentLevel); -+ // if the current coordinate is a source, then the decrease propagation will detect that and queue -+ // the source propagation -+ } -+ } -+ -+ this.updatedSources.clear(); -+ -+ // propagate source level increases first for performance reasons (in crowded areas hopefully the additions -+ // make the removes remove less) -+ this.propagateIncreases(); -+ -+ // now we propagate the decreases (which will then re-propagate clobbered sources) -+ this.propagateDecreases(); -+ -+ return ret; -+ } -+ -+ protected void propagateIncreases() { -+ for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset); -+ this.levelIncreaseWorkQueueBitset != 0L; -+ this.levelIncreaseWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset)) { -+ -+ final WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex]; -+ while (!queue.queuedLevels.isEmpty()) { -+ final long coordinate = queue.queuedCoordinates.removeFirstLong(); -+ byte level = queue.queuedLevels.removeFirstByte(); -+ -+ final boolean neighbourCheck = level < 0; -+ -+ final byte currentLevel; -+ if (neighbourCheck) { -+ level = (byte)-level; -+ currentLevel = this.levels.get(coordinate); -+ } else { -+ currentLevel = this.levels.putIfGreater(coordinate, level); -+ } -+ -+ if (neighbourCheck) { -+ // used when propagating from decrease to indicate that this level needs to check its neighbours -+ // this means the level at coordinate could be equal, but would still need neighbours checked -+ -+ if (currentLevel != level) { -+ // something caused the level to change, which means something propagated to it (which means -+ // us propagating here is redundant), or something removed the level (which means we -+ // cannot propagate further) -+ continue; -+ } -+ } else if (currentLevel >= level) { -+ // something higher/equal propagated -+ continue; -+ } -+ if (this.changeCallback != null) { -+ this.changeCallback.onLevelUpdate(coordinate, currentLevel, level); -+ } -+ -+ if (level == 1) { -+ // can't propagate 0 to neighbours -+ continue; -+ } -+ -+ // propagate to neighbours -+ final byte neighbourLevel = (byte)(level - 1); -+ final int x = (int)coordinate; -+ final int z = (int)(coordinate >>> 32); -+ -+ for (int dx = -1; dx <= 1; ++dx) { -+ for (int dz = -1; dz <= 1; ++dz) { -+ if ((dx | dz) == 0) { -+ // already propagated to coordinate -+ continue; -+ } -+ -+ // sure we can check the neighbour level in the map right now and avoid a propagation, -+ // but then we would still have to recheck it when popping the value off of the queue! -+ // so just avoid the double lookup -+ final long neighbourCoordinate = MCUtil.getCoordinateKey(x + dx, z + dz); -+ this.addToIncreaseWorkQueue(neighbourCoordinate, neighbourLevel); -+ } -+ } -+ } -+ } -+ } -+ -+ protected void propagateDecreases() { -+ for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset); -+ this.levelRemoveWorkQueueBitset != 0L; -+ this.levelRemoveWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset)) { -+ -+ final WorkQueue queue = this.levelRemoveWorkQueues[queueIndex]; -+ while (!queue.queuedLevels.isEmpty()) { -+ final long coordinate = queue.queuedCoordinates.removeFirstLong(); -+ final byte level = queue.queuedLevels.removeFirstByte(); -+ -+ final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level); -+ if (currentLevel == 0) { -+ // something else removed -+ continue; -+ } -+ -+ if (currentLevel > level) { -+ // something higher propagated here or we hit the propagation of another source -+ // in the second case we need to re-propagate because we could have just clobbered another source's -+ // propagation -+ this.addToIncreaseWorkQueue(coordinate, currentLevel, (byte)-currentLevel); // indicate to the increase code that the level's neighbours need checking -+ continue; -+ } -+ -+ if (this.changeCallback != null) { -+ this.changeCallback.onLevelUpdate(coordinate, currentLevel, (byte)0); -+ } -+ -+ final byte source = this.sources.get(coordinate); -+ if (source != 0) { -+ // must re-propagate source later -+ this.addToIncreaseWorkQueue(coordinate, source); -+ } -+ -+ if (level == 0) { -+ // can't propagate -1 to neighbours -+ // we have to check neighbours for removing 1 just in case the neighbour is 2 -+ continue; -+ } -+ -+ // propagate to neighbours -+ final byte neighbourLevel = (byte)(level - 1); -+ final int x = (int)coordinate; -+ final int z = (int)(coordinate >>> 32); -+ -+ for (int dx = -1; dx <= 1; ++dx) { -+ for (int dz = -1; dz <= 1; ++dz) { -+ if ((dx | dz) == 0) { -+ // already propagated to coordinate -+ continue; -+ } -+ -+ // sure we can check the neighbour level in the map right now and avoid a propagation, -+ // but then we would still have to recheck it when popping the value off of the queue! -+ // so just avoid the double lookup -+ final long neighbourCoordinate = MCUtil.getCoordinateKey(x + dx, z + dz); -+ this.addToRemoveWorkQueue(neighbourCoordinate, neighbourLevel); -+ } -+ } -+ } -+ } -+ -+ // propagate sources we clobbered in the process -+ this.propagateIncreases(); -+ } -+ -+ protected static final class LevelMap extends Long2ByteOpenHashMap { -+ public LevelMap() { -+ super(); -+ } -+ -+ public LevelMap(final int expected, final float loadFactor) { -+ super(expected, loadFactor); -+ } -+ -+ // copied from superclass -+ private int find(final long k) { -+ if (k == 0L) { -+ return this.containsNullKey ? this.n : -(this.n + 1); -+ } else { -+ final long[] key = this.key; -+ long curr; -+ int pos; -+ if ((curr = key[pos = (int)HashCommon.mix(k) & this.mask]) == 0L) { -+ return -(pos + 1); -+ } else if (k == curr) { -+ return pos; -+ } else { -+ while((curr = key[pos = pos + 1 & this.mask]) != 0L) { -+ if (k == curr) { -+ return pos; -+ } -+ } -+ -+ return -(pos + 1); -+ } -+ } -+ } -+ -+ // copied from superclass -+ private void insert(final int pos, final long k, final byte v) { -+ if (pos == this.n) { -+ this.containsNullKey = true; -+ } -+ -+ this.key[pos] = k; -+ this.value[pos] = v; -+ if (this.size++ >= this.maxFill) { -+ this.rehash(HashCommon.arraySize(this.size + 1, this.f)); -+ } -+ } -+ -+ // copied from superclass -+ public byte putIfGreater(final long key, final byte value) { -+ final int pos = this.find(key); -+ if (pos < 0) { -+ if (this.defRetValue < value) { -+ this.insert(-pos - 1, key, value); -+ } -+ return this.defRetValue; -+ } else { -+ final byte curr = this.value[pos]; -+ if (value > curr) { -+ this.value[pos] = value; -+ return curr; -+ } -+ return curr; -+ } -+ } -+ -+ // copied from superclass -+ private void removeEntry(final int pos) { -+ --this.size; -+ this.shiftKeys(pos); -+ if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) { -+ this.rehash(this.n / 2); -+ } -+ } -+ -+ // copied from superclass -+ private void removeNullEntry() { -+ this.containsNullKey = false; -+ --this.size; -+ if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) { -+ this.rehash(this.n / 2); -+ } -+ } -+ -+ // copied from superclass -+ public byte removeIfGreaterOrEqual(final long key, final byte value) { -+ if (key == 0L) { -+ if (!this.containsNullKey) { -+ return this.defRetValue; -+ } -+ final byte current = this.value[this.n]; -+ if (value >= current) { -+ this.removeNullEntry(); -+ return current; -+ } -+ return current; -+ } else { -+ long[] keys = this.key; -+ byte[] values = this.value; -+ long curr; -+ int pos; -+ if ((curr = keys[pos = (int)HashCommon.mix(key) & this.mask]) == 0L) { -+ return this.defRetValue; -+ } else if (key == curr) { -+ final byte current = values[pos]; -+ if (value >= current) { -+ this.removeEntry(pos); -+ return current; -+ } -+ return current; -+ } else { -+ while((curr = keys[pos = pos + 1 & this.mask]) != 0L) { -+ if (key == curr) { -+ final byte current = values[pos]; -+ if (value >= current) { -+ this.removeEntry(pos); -+ return current; -+ } -+ return current; -+ } -+ } -+ -+ return this.defRetValue; -+ } -+ } -+ } -+ } -+ -+ protected static final class WorkQueue { -+ -+ public final NoResizeLongArrayFIFODeque queuedCoordinates = new NoResizeLongArrayFIFODeque(); -+ public final NoResizeByteArrayFIFODeque queuedLevels = new NoResizeByteArrayFIFODeque(); -+ -+ } -+ -+ protected static final class NoResizeLongArrayFIFODeque extends LongArrayFIFOQueue { -+ -+ /** -+ * Assumes non-empty. If empty, undefined behaviour. -+ */ -+ public long removeFirstLong() { -+ // copied from superclass -+ long t = this.array[this.start]; -+ if (++this.start == this.length) { -+ this.start = 0; -+ } -+ -+ return t; -+ } -+ } -+ -+ protected static final class NoResizeByteArrayFIFODeque extends ByteArrayFIFOQueue { -+ -+ /** -+ * Assumes non-empty. If empty, undefined behaviour. -+ */ -+ public byte removeFirstByte() { -+ // copied from superclass -+ byte t = this.array[this.start]; -+ if (++this.start == this.length) { -+ this.start = 0; -+ } -+ -+ return t; -+ } -+ } -+} diff --git a/src/main/java/io/papermc/paper/util/player/NearbyPlayers.java b/src/main/java/io/papermc/paper/util/player/NearbyPlayers.java new file mode 100644 index 0000000000000000000000000000000000000000..c3ce8a42dddd76b7189ad5685b23f9d9f8ccadb3 @@ -6081,7 +4124,7 @@ index 3e5a85a7ad6149b04622c254fbc2e174896a4128..3f662692ed4846e026a9d48595e7b3b2 + } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 40adb6117b9e0d5f70103113202a07715e403e2a..b1325e090f2c7aff31d27fc38ca7173efe31ed7c 100644 +index 40adb6117b9e0d5f70103113202a07715e403e2a..9eb987f9d86396d6b7e9d4f3834bea3326640ac7 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -310,6 +310,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -6119,18 +4162,6 @@ index 40adb6117b9e0d5f70103113202a07715e403e2a..b1325e090f2c7aff31d27fc38ca7173e this.profiler.push("tallying"); long j = Util.getNanos() - i; int k = this.tickCount % 100; -@@ -1470,6 +1475,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa - try { - worldserver.timings.doTick.startTiming(); // Spigot - worldserver.tick(shouldKeepTicking); -+ // Paper start -+ for (final io.papermc.paper.chunk.SingleThreadChunkRegionManager regionManager : worldserver.getChunkSource().chunkMap.regionManagers) { -+ regionManager.recalculateRegions(); -+ } -+ // Paper end - worldserver.timings.doTick.stopTiming(); // Spigot - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception ticking world"); diff --git a/src/main/java/net/minecraft/server/level/ChunkHolder.java b/src/main/java/net/minecraft/server/level/ChunkHolder.java index f40a2f348c45a29168ca3d4eef07b5b628060bee..c643bb0daa5cd264fd6ebab7acf0a2bdd7fe7029 100644 --- a/src/main/java/net/minecraft/server/level/ChunkHolder.java @@ -6347,10 +4378,10 @@ index f40a2f348c45a29168ca3d4eef07b5b628060bee..c643bb0daa5cd264fd6ebab7acf0a2bd + // 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 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b8ef8fe7f 100644 +index 5b920beb39dad8d392b4e5e12a89880720e41942..d3caadb3e884d7d0468daf5eff9abd6629ac4b49 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -170,6 +170,62 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -170,6 +170,37 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider }; // CraftBukkit end @@ -6379,31 +4410,6 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b + } + // Paper end + // Paper start -+ public final List<io.papermc.paper.chunk.SingleThreadChunkRegionManager> regionManagers = new java.util.ArrayList<>(); -+ public final io.papermc.paper.chunk.SingleThreadChunkRegionManager dataRegionManager; -+ -+ public static final class DataRegionData implements io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionData { -+ } -+ -+ public static final class DataRegionSectionData implements io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSectionData { -+ -+ @Override -+ public void removeFromRegion(final io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section, -+ final io.papermc.paper.chunk.SingleThreadChunkRegionManager.Region from) { -+ final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData; -+ final DataRegionData fromData = (DataRegionData)from.regionData; -+ } -+ -+ @Override -+ public void addToRegion(final io.papermc.paper.chunk.SingleThreadChunkRegionManager.RegionSection section, -+ final io.papermc.paper.chunk.SingleThreadChunkRegionManager.Region oldRegion, -+ final io.papermc.paper.chunk.SingleThreadChunkRegionManager.Region newRegion) { -+ final DataRegionSectionData sectionData = (DataRegionSectionData)section.sectionData; -+ final DataRegionData oldRegionData = oldRegion == null ? null : (DataRegionData)oldRegion.regionData; -+ final DataRegionData newRegionData = (DataRegionData)newRegion.regionData; -+ } -+ } -+ + public final ChunkHolder getUnloadingChunkHolder(int chunkX, int chunkZ) { + return this.pendingUnloads.get(io.papermc.paper.util.CoordinateUtils.getChunkKey(chunkX, chunkZ)); + } @@ -6413,13 +4419,11 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory, int viewDistance, boolean dsync) { super(new RegionStorageInfo(session.getLevelId(), world.dimension(), "chunk"), session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); this.visibleChunkMap = this.updatingChunkMap.clone(); -@@ -221,8 +277,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -221,8 +252,22 @@ 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.getServer(), world); this.setServerViewDistance(viewDistance); this.worldGenContext = new WorldGenContext(world, chunkGenerator, structureTemplateManager, this.lightEngine, this.mainThreadMailbox); + // Paper start -+ this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new); -+ this.regionManagers.add(this.dataRegionManager); + this.nearbyPlayers = new io.papermc.paper.util.player.NearbyPlayers(this.level); + // Paper end + } @@ -6438,7 +4442,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b protected ChunkGenerator generator() { return this.worldGenContext.generator(); } -@@ -378,9 +450,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -378,9 +423,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider }; stringbuilder.append("Updating:").append(System.lineSeparator()); @@ -6450,7 +4454,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b CrashReport crashreport = CrashReport.forThrowable(exception, "Chunk loading"); CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Chunk loading"); -@@ -422,8 +494,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -422,8 +467,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider holder.setTicketLevel(level); } else { holder = new ChunkHolder(new ChunkPos(pos), level, this.level, this.lightEngine, this.queueSorter, this); @@ -6465,7 +4469,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b this.updatingChunkMap.put(pos, holder); this.modified = true; } -@@ -445,7 +523,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -445,7 +496,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider protected void saveAllChunks(boolean flush) { if (flush) { @@ -6474,7 +4478,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b MutableBoolean mutableboolean = new MutableBoolean(); do { -@@ -468,7 +546,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -468,7 +519,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider }); this.flushWorker(); } else { @@ -6483,7 +4487,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b } } -@@ -487,7 +565,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -487,7 +538,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public boolean hasWork() { @@ -6492,7 +4496,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b } private void processUnloads(BooleanSupplier shouldKeepTicking) { -@@ -504,6 +582,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -504,6 +555,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } this.updatingChunkMap.remove(j); @@ -6500,7 +4504,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b this.pendingUnloads.put(j, playerchunk); this.modified = true; ++i; -@@ -523,7 +602,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -523,7 +575,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } int l = 0; @@ -6509,7 +4513,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b while (l < 20 && shouldKeepTicking.getAsBoolean() && objectiterator.hasNext()) { if (this.saveChunkIfNeeded((ChunkHolder) objectiterator.next())) { -@@ -541,7 +620,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -541,7 +593,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } else { ChunkAccess ichunkaccess = holder.getLatestChunk(); @@ -6522,7 +4526,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b LevelChunk chunk; if (ichunkaccess instanceof LevelChunk) { -@@ -559,7 +642,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -559,7 +615,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.lightEngine.tryScheduleUpdate(); this.progressListener.onStatusChange(ichunkaccess.getPos(), (ChunkStatus) null); this.chunkSaveCooldowns.remove(ichunkaccess.getPos().toLong()); @@ -6533,7 +4537,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b } }; -@@ -896,7 +981,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -896,7 +954,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } } @@ -6542,7 +4546,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b int j = Mth.clamp(watchDistance, 2, 32); if (j != this.serverViewDistance) { -@@ -913,7 +998,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -913,7 +971,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } @@ -6551,7 +4555,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b return Mth.clamp(player.requestedViewDistance(), 2, this.serverViewDistance); } -@@ -942,7 +1027,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -942,7 +1000,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public int size() { @@ -6560,7 +4564,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b } public DistanceManager getDistanceManager() { -@@ -950,19 +1035,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -950,19 +1008,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } protected Iterable<ChunkHolder> getChunks() { @@ -6585,7 +4589,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b Optional<ChunkAccess> optional = Optional.ofNullable(playerchunk.getLatestChunk()); Optional<LevelChunk> optional1 = optional.flatMap((ichunkaccess) -> { return ichunkaccess instanceof LevelChunk ? Optional.of((LevelChunk) ichunkaccess) : Optional.empty(); -@@ -1083,6 +1168,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1083,6 +1141,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider player.setChunkTrackingView(ChunkTrackingView.EMPTY); this.updateChunkTracking(player); @@ -6593,7 +4597,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b } else { SectionPos sectionposition = player.getLastSectionPos(); -@@ -1091,6 +1177,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1091,6 +1150,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.distanceManager.removePlayer(sectionposition, player); } @@ -6601,7 +4605,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b this.applyChunkTrackingView(player, ChunkTrackingView.EMPTY); } -@@ -1142,6 +1229,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1142,6 +1202,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.updateChunkTracking(player); } @@ -6609,7 +4613,7 @@ index 5b920beb39dad8d392b4e5e12a89880720e41942..319f51eb8adde7584c74780ac0539f4b } private void updateChunkTracking(ServerPlayer player) { -@@ -1385,10 +1473,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1385,10 +1446,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider }); } @@ -6655,7 +4659,7 @@ index b6cc33943fe7e4667944f3e6f868b3033ea9ca18..27065ffc5473c518acee3a3096b83fac while (objectiterator.hasNext()) { diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index d39268911ed7c4d60ee6a82178be23245aae58c4..ab57071cc6ce8b79d883f2426855c1abf577e90d 100644 +index d39268911ed7c4d60ee6a82178be23245aae58c4..e9f53f57c363a32106880ea9aad0ccf5a7342509 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -48,6 +48,7 @@ import net.minecraft.world.level.storage.LevelStorageSource; @@ -6666,81 +4670,30 @@ index d39268911ed7c4d60ee6a82178be23245aae58c4..ab57071cc6ce8b79d883f2426855c1ab private static final List<ChunkStatus> CHUNK_STATUSES = ChunkStatus.getStatusList(); private final DistanceManager distanceManager; final ServerLevel level; -@@ -66,6 +67,14 @@ public class ServerChunkCache extends ChunkSource { +@@ -66,6 +67,12 @@ public class ServerChunkCache extends ChunkSource { @Nullable @VisibleForDebug private NaturalSpawner.SpawnState lastSpawnState; + // Paper start + public final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<LevelChunk> tickingChunks = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(4096, 0.75f, 4096, 0.15, true); + public final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<LevelChunk> 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<LevelChunk> loadedChunkMap = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>(8192, 0.5f); ++ private final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<net.minecraft.world.level.chunk.LevelChunk> fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>(); + long chunkFutureAwaitCounter; -+ private final LevelChunk[] lastLoadedChunks = new LevelChunk[4 * 4]; + // Paper end public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory) { this.level = world; -@@ -91,6 +100,124 @@ public class ServerChunkCache extends ChunkSource { +@@ -91,6 +98,54 @@ public class ServerChunkCache extends ChunkSource { return chunk.getFullChunkNow() != null; } // CraftBukkit end + // Paper start -+ private static int getChunkCacheKey(int x, int z) { -+ return x & 3 | ((z & 3) << 2); -+ } -+ + public void addLoadedChunk(LevelChunk chunk) { -+ this.loadedChunkMapSeqLock.acquireWrite(); -+ try { -+ this.loadedChunkMap.put(chunk.coordinateKey, chunk); -+ } finally { -+ this.loadedChunkMapSeqLock.releaseWrite(); -+ } -+ -+ // rewrite cache if we have to -+ // we do this since we also cache null chunks -+ int cacheKey = getChunkCacheKey(chunk.locX, chunk.locZ); -+ -+ this.lastLoadedChunks[cacheKey] = chunk; ++ this.fullChunks.put(chunk.coordinateKey, chunk); + } + + public void removeLoadedChunk(LevelChunk chunk) { -+ this.loadedChunkMapSeqLock.acquireWrite(); -+ try { -+ this.loadedChunkMap.remove(chunk.coordinateKey); -+ } finally { -+ this.loadedChunkMapSeqLock.releaseWrite(); -+ } -+ -+ // rewrite cache if we have to -+ // we do this since we also cache null chunks -+ int cacheKey = getChunkCacheKey(chunk.locX, chunk.locZ); -+ -+ LevelChunk cachedChunk = this.lastLoadedChunks[cacheKey]; -+ if (cachedChunk != null && cachedChunk.coordinateKey == chunk.coordinateKey) { -+ this.lastLoadedChunks[cacheKey] = null; -+ } -+ } -+ -+ public final LevelChunk getChunkAtIfLoadedMainThread(int x, int z) { -+ int cacheKey = getChunkCacheKey(x, z); -+ -+ LevelChunk cachedChunk = this.lastLoadedChunks[cacheKey]; -+ if (cachedChunk != null && cachedChunk.locX == x & cachedChunk.locZ == z) { -+ return cachedChunk; -+ } -+ -+ long chunkKey = ChunkPos.asLong(x, z); -+ -+ cachedChunk = this.loadedChunkMap.get(chunkKey); -+ // Skipping a null check to avoid extra instructions to improve inline capability -+ this.lastLoadedChunks[cacheKey] = cachedChunk; -+ return cachedChunk; -+ } -+ -+ public final LevelChunk getChunkAtIfLoadedMainThreadNoCache(int x, int z) { -+ return this.loadedChunkMap.get(ChunkPos.asLong(x, z)); ++ this.fullChunks.remove(chunk.coordinateKey); + } + + @Nullable @@ -6779,34 +4732,13 @@ index d39268911ed7c4d60ee6a82178be23245aae58c4..ab57071cc6ce8b79d883f2426855c1ab + + @Nullable + public LevelChunk getChunkAtIfLoadedImmediately(int x, int z) { -+ long k = ChunkPos.asLong(x, z); -+ -+ if (Thread.currentThread() == this.mainThread) { -+ return this.getChunkAtIfLoadedMainThread(x, z); -+ } -+ -+ LevelChunk ret = null; -+ long readlock; -+ do { -+ readlock = this.loadedChunkMapSeqLock.acquireRead(); -+ try { -+ ret = this.loadedChunkMap.get(k); -+ } catch (Throwable thr) { -+ if (thr instanceof ThreadDeath) { -+ throw (ThreadDeath)thr; -+ } -+ // re-try, this means a CME occurred... -+ continue; -+ } -+ } while (!this.loadedChunkMapSeqLock.tryReleaseRead(readlock)); -+ -+ return ret; ++ return this.fullChunks.get(ChunkPos.asLong(x, z)); + } + // Paper end @Override public ThreadedLevelLightEngine getLightEngine() { -@@ -286,7 +413,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -286,7 +341,7 @@ public class ServerChunkCache extends ChunkSource { return this.mainThreadProcessor.pollTask(); } @@ -6815,7 +4747,7 @@ index d39268911ed7c4d60ee6a82178be23245aae58c4..ab57071cc6ce8b79d883f2426855c1ab boolean flag = this.distanceManager.runAllUpdates(this.chunkMap); boolean flag1 = this.chunkMap.promoteChunkMap(); -@@ -299,6 +426,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -299,6 +354,12 @@ public class ServerChunkCache extends ChunkSource { } } @@ -7466,120 +5398,21 @@ index a52077f0d93c94b0ea644bc14b9b28e84fd1b154..dcc0acd259920463a4464213b9a5e793 @Nullable @Override 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 b537e7a079497db428db405edfccde74f32f4208..7898e1aaf82f096fa74bd3f5859f0f4303ea677f 100644 +index b537e7a079497db428db405edfccde74f32f4208..c664021dbfffcf0db3247041270ce9a1ee6940de 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -116,6 +116,109 @@ public class LevelChunk extends ChunkAccess { +@@ -116,6 +116,10 @@ public class LevelChunk extends ChunkAccess { public boolean needsDecoration; // CraftBukkit end + // Paper start -+ public @Nullable net.minecraft.server.level.ChunkHolder playerChunk; -+ -+ static final int NEIGHBOUR_CACHE_RADIUS = 3; -+ public static int getNeighbourCacheRadius() { -+ return NEIGHBOUR_CACHE_RADIUS; -+ } -+ + boolean loadedTicketLevel; -+ private long neighbourChunksLoadedBitset; -+ private final LevelChunk[] loadedNeighbourChunks = new LevelChunk[(NEIGHBOUR_CACHE_RADIUS * 2 + 1) * (NEIGHBOUR_CACHE_RADIUS * 2 + 1)]; -+ -+ private static int getNeighbourIndex(final int relativeX, final int relativeZ) { -+ // index = (relativeX + NEIGHBOUR_CACHE_RADIUS) + (relativeZ + NEIGHBOUR_CACHE_RADIUS) * (NEIGHBOUR_CACHE_RADIUS * 2 + 1) -+ // optimised variant of the above by moving some of the ops to compile time -+ return relativeX + (relativeZ * (NEIGHBOUR_CACHE_RADIUS * 2 + 1)) + (NEIGHBOUR_CACHE_RADIUS + NEIGHBOUR_CACHE_RADIUS * ((NEIGHBOUR_CACHE_RADIUS * 2 + 1))); -+ } -+ -+ public final LevelChunk getRelativeNeighbourIfLoaded(final int relativeX, final int relativeZ) { -+ return this.loadedNeighbourChunks[getNeighbourIndex(relativeX, relativeZ)]; -+ } -+ -+ public final boolean isNeighbourLoaded(final int relativeX, final int relativeZ) { -+ return (this.neighbourChunksLoadedBitset & (1L << getNeighbourIndex(relativeX, relativeZ))) != 0; -+ } -+ -+ public final void setNeighbourLoaded(final int relativeX, final int relativeZ, final LevelChunk chunk) { -+ if (chunk == null) { -+ throw new IllegalArgumentException("Chunk must be non-null, neighbour: (" + relativeX + "," + relativeZ + "), chunk: " + this.chunkPos); -+ } -+ final long before = this.neighbourChunksLoadedBitset; -+ final int index = getNeighbourIndex(relativeX, relativeZ); -+ this.loadedNeighbourChunks[index] = chunk; -+ this.neighbourChunksLoadedBitset |= (1L << index); -+ this.onNeighbourChange(before, this.neighbourChunksLoadedBitset); -+ } -+ -+ public final void setNeighbourUnloaded(final int relativeX, final int relativeZ) { -+ final long before = this.neighbourChunksLoadedBitset; -+ final int index = getNeighbourIndex(relativeX, relativeZ); -+ this.loadedNeighbourChunks[index] = null; -+ this.neighbourChunksLoadedBitset &= ~(1L << index); -+ this.onNeighbourChange(before, this.neighbourChunksLoadedBitset); -+ } -+ -+ public final void resetNeighbours() { -+ final long before = this.neighbourChunksLoadedBitset; -+ this.neighbourChunksLoadedBitset = 0L; -+ java.util.Arrays.fill(this.loadedNeighbourChunks, null); -+ this.onNeighbourChange(before, 0L); -+ } -+ -+ protected void onNeighbourChange(final long bitsetBefore, final long bitsetAfter) { -+ -+ } -+ -+ public final boolean isAnyNeighborsLoaded() { -+ return neighbourChunksLoadedBitset != 0; -+ } -+ public final boolean areNeighboursLoaded(final int radius) { -+ return LevelChunk.areNeighboursLoaded(this.neighbourChunksLoadedBitset, radius); -+ } -+ -+ public static boolean areNeighboursLoaded(final long bitset, final int radius) { -+ // index = relativeX + (relativeZ * (NEIGHBOUR_CACHE_RADIUS * 2 + 1)) + (NEIGHBOUR_CACHE_RADIUS + NEIGHBOUR_CACHE_RADIUS * ((NEIGHBOUR_CACHE_RADIUS * 2 + 1))) -+ switch (radius) { -+ case 0: { -+ return (bitset & (1L << getNeighbourIndex(0, 0))) != 0; -+ } -+ case 1: { -+ long mask = 0L; -+ for (int dx = -1; dx <= 1; ++dx) { -+ for (int dz = -1; dz <= 1; ++dz) { -+ mask |= (1L << getNeighbourIndex(dx, dz)); -+ } -+ } -+ return (bitset & mask) == mask; -+ } -+ case 2: { -+ long mask = 0L; -+ for (int dx = -2; dx <= 2; ++dx) { -+ for (int dz = -2; dz <= 2; ++dz) { -+ mask |= (1L << getNeighbourIndex(dx, dz)); -+ } -+ } -+ return (bitset & mask) == mask; -+ } -+ case 3: { -+ long mask = 0L; -+ for (int dx = -3; dx <= 3; ++dx) { -+ for (int dz = -3; dz <= 3; ++dz) { -+ mask |= (1L << getNeighbourIndex(dx, dz)); -+ } -+ } -+ return (bitset & mask) == mask; -+ } -+ -+ default: -+ throw new IllegalArgumentException("Radius not recognized: " + radius); -+ } -+ } + // Paper end + public LevelChunk(ServerLevel world, ProtoChunk protoChunk, @Nullable LevelChunk.PostLoadProcessor entityLoader) { this(world, protoChunk.getPos(), protoChunk.getUpgradeData(), protoChunk.unpackBlockTicks(), protoChunk.unpackFluidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), entityLoader, protoChunk.getBlendingData()); Iterator iterator = protoChunk.getBlockEntities().values().iterator(); -@@ -181,8 +284,25 @@ public class LevelChunk extends ChunkAccess { +@@ -181,8 +185,25 @@ public class LevelChunk extends ChunkAccess { } } @@ -7605,7 +5438,7 @@ index b537e7a079497db428db405edfccde74f32f4208..7898e1aaf82f096fa74bd3f5859f0f43 int i = pos.getX(); int j = pos.getY(); int k = pos.getZ(); -@@ -224,6 +344,18 @@ public class LevelChunk extends ChunkAccess { +@@ -224,6 +245,18 @@ public class LevelChunk extends ChunkAccess { } } @@ -7624,51 +5457,25 @@ index b537e7a079497db428db405edfccde74f32f4208..7898e1aaf82f096fa74bd3f5859f0f43 @Override public FluidState getFluidState(BlockPos pos) { return this.getFluidState(pos.getX(), pos.getY(), pos.getZ()); -@@ -549,7 +681,25 @@ public class LevelChunk extends ChunkAccess { +@@ -549,7 +582,11 @@ public class LevelChunk extends ChunkAccess { // CraftBukkit start public void loadCallback() { -+ // Paper start - neighbour cache -+ int chunkX = this.chunkPos.x; -+ int chunkZ = this.chunkPos.z; -+ net.minecraft.server.level.ServerChunkCache chunkProvider = this.level.getChunkSource(); -+ for (int dx = -NEIGHBOUR_CACHE_RADIUS; dx <= NEIGHBOUR_CACHE_RADIUS; ++dx) { -+ for (int dz = -NEIGHBOUR_CACHE_RADIUS; dz <= NEIGHBOUR_CACHE_RADIUS; ++dz) { -+ LevelChunk neighbour = chunkProvider.getChunkAtIfLoadedMainThreadNoCache(chunkX + dx, chunkZ + dz); -+ if (neighbour != null) { -+ neighbour.setNeighbourLoaded(-dx, -dz, this); -+ // should be in cached already -+ this.setNeighbourLoaded(dx, dz, neighbour); -+ } -+ } -+ } -+ this.setNeighbourLoaded(0, 0, this); ++ // Paper start + this.loadedTicketLevel = true; -+ // Paper end - neighbour cache ++ // Paper end org.bukkit.Server server = this.level.getCraftServer(); + this.level.getChunkSource().addLoadedChunk(this); // Paper if (server != null) { /* * If it's a new world, the first few chunks are generated inside -@@ -590,6 +740,22 @@ public class LevelChunk extends ChunkAccess { +@@ -590,6 +627,10 @@ public class LevelChunk extends ChunkAccess { server.getPluginManager().callEvent(unloadEvent); // note: saving can be prevented, but not forced if no saving is actually required this.mustNotSave = !unloadEvent.isSaveChunk(); + this.level.getChunkSource().removeLoadedChunk(this); // Paper -+ // Paper start - neighbour cache -+ int chunkX = this.chunkPos.x; -+ int chunkZ = this.chunkPos.z; -+ net.minecraft.server.level.ServerChunkCache chunkProvider = this.level.getChunkSource(); -+ for (int dx = -NEIGHBOUR_CACHE_RADIUS; dx <= NEIGHBOUR_CACHE_RADIUS; ++dx) { -+ for (int dz = -NEIGHBOUR_CACHE_RADIUS; dz <= NEIGHBOUR_CACHE_RADIUS; ++dz) { -+ LevelChunk neighbour = chunkProvider.getChunkAtIfLoadedMainThreadNoCache(chunkX + dx, chunkZ + dz); -+ if (neighbour != null) { -+ neighbour.setNeighbourUnloaded(-dx, -dz); -+ } -+ } -+ } ++ // Paper start + this.loadedTicketLevel = false; -+ this.resetNeighbours(); + // Paper end } @@ -8150,7 +5957,7 @@ index e08d4a45e313ef1b9005ef00ee0185a188171207..2fc68d129e2fdfd51e310ea5bdfb8332 public static byte toLegacyData(BlockState data) { diff --git a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -index 5fd6eb754c4edebed6798c65b06507a4e89ca48f..0794d92c42b0db6b367505ae28f09f1fd39fa312 100644 +index 5fd6eb754c4edebed6798c65b06507a4e89ca48f..524b51a0ab808a0629c871ad813115abd4b49dbd 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java +++ b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java @@ -58,6 +58,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; @@ -8170,19 +5977,19 @@ index 5fd6eb754c4edebed6798c65b06507a4e89ca48f..0794d92c42b0db6b367505ae28f09f1f + @Nullable + @Override + public BlockState getBlockStateIfLoaded(final BlockPos blockposition) { -+ return null; ++ return this.handle.getBlockStateIfLoaded(blockposition); + } + + @Nullable + @Override + public FluidState getFluidIfLoaded(final BlockPos blockposition) { -+ return null; ++ return this.handle.getFluidIfLoaded(blockposition); + } + + @Nullable + @Override + public ChunkAccess getChunkIfLoadedImmediately(final int x, final int z) { -+ return null; ++ return this.handle.getChunkIfLoadedImmediately(x, z); + } + // Paper end } diff --git a/patches/server/0010-Adventure.patch b/patches/server/0010-Adventure.patch index c6a160a49b..783ccc1503 100644 --- a/patches/server/0010-Adventure.patch +++ b/patches/server/0010-Adventure.patch @@ -2606,7 +2606,7 @@ index bb97fdb9aa6167083442a928276ebe4225a586ef..5d1758086ed4fce5b36a5b31df44ccea @Override diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index b1325e090f2c7aff31d27fc38ca7173efe31ed7c..0742aaf07f37e51d24295e7819ac6cec961c7626 100644 +index 9eb987f9d86396d6b7e9d4f3834bea3326640ac7..25d6be308be03815301cfbefdc4199c898f7b9c0 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -201,6 +201,7 @@ import org.bukkit.craftbukkit.SpigotTimings; // Spigot @@ -2644,7 +2644,7 @@ index b1325e090f2c7aff31d27fc38ca7173efe31ed7c..0742aaf07f37e51d24295e7819ac6cec this.profiler.push("commandFunctions"); SpigotTimings.commandFunctionsTimer.startTiming(); // Spigot this.getFunctions().tick(); -@@ -1805,10 +1806,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -1800,10 +1801,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @Override public String getMotd() { @@ -2666,7 +2666,7 @@ index b1325e090f2c7aff31d27fc38ca7173efe31ed7c..0742aaf07f37e51d24295e7819ac6cec this.motd = motd; } -@@ -2570,23 +2581,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2565,23 +2576,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa } public void logChatMessage(Component message, ChatType.Bound params, @Nullable String prefix) { diff --git a/patches/server/0011-Use-TerminalConsoleAppender-for-console-improvements.patch b/patches/server/0011-Use-TerminalConsoleAppender-for-console-improvements.patch index 8e5fbfaf15..35237b2e07 100644 --- a/patches/server/0011-Use-TerminalConsoleAppender-for-console-improvements.patch +++ b/patches/server/0011-Use-TerminalConsoleAppender-for-console-improvements.patch @@ -260,7 +260,7 @@ index 8323f135d6bf2e1f12525e05094ffa3f2420e7e1..a143ea1e58464a3122fbd8ccafe417bd } } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 0742aaf07f37e51d24295e7819ac6cec961c7626..e82218de79759dfaa7fe2a5a78e150f135bf01a3 100644 +index 25d6be308be03815301cfbefdc4199c898f7b9c0..b67cb9b027c33494f0ed3c6c6ac354a5c79fbf47 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -154,7 +154,7 @@ import com.mojang.serialization.Dynamic; @@ -308,7 +308,7 @@ index 0742aaf07f37e51d24295e7819ac6cec961c7626..e82218de79759dfaa7fe2a5a78e150f1 } catch (Exception ignored) { } // CraftBukkit end -@@ -1664,7 +1667,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -1659,7 +1662,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @Override public void sendSystemMessage(Component message) { diff --git a/patches/server/0020-Plugin-remapping.patch b/patches/server/0020-Plugin-remapping.patch index 8089ed1b6d..dc3aee0b84 100644 --- a/patches/server/0020-Plugin-remapping.patch +++ b/patches/server/0020-Plugin-remapping.patch @@ -1553,7 +1553,7 @@ index 0000000000000000000000000000000000000000..badff5d6ae6dd8d209c82bc7e8afe370 + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index e82218de79759dfaa7fe2a5a78e150f135bf01a3..202a6510d9d093119ff88b910cef6e47fce2e6b8 100644 +index b67cb9b027c33494f0ed3c6c6ac354a5c79fbf47..cde2e181bf1aaf92f1e96b00e03b7b001a06e6b3 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -643,6 +643,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0023-Timings-v2.patch b/patches/server/0023-Timings-v2.patch index 44e528fa96..3ed1b8f74e 100644 --- a/patches/server/0023-Timings-v2.patch +++ b/patches/server/0023-Timings-v2.patch @@ -714,7 +714,7 @@ index f7197f1347251a37dd0f6d9ffa2f09bc3a4e1233..d0d36a57ec4896bcb74970f8fb24d8f3 } catch (Exception exception) { if (exception instanceof ReportedException) { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 202a6510d9d093119ff88b910cef6e47fce2e6b8..4137cf4d716680ff1b1ab0b8a3e8f7cb4bae7dbe 100644 +index cde2e181bf1aaf92f1e96b00e03b7b001a06e6b3..a720743149f9d1f90eda3b7b928b9d25d8c8f553 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -196,7 +196,7 @@ import org.bukkit.craftbukkit.Main; @@ -861,7 +861,7 @@ index 202a6510d9d093119ff88b910cef6e47fce2e6b8..4137cf4d716680ff1b1ab0b8a3e8f7cb while (iterator.hasNext()) { ServerLevel worldserver = (ServerLevel) iterator.next(); -@@ -1499,24 +1522,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -1494,24 +1517,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa } this.profiler.popPush("connection"); @@ -978,7 +978,7 @@ index d38ecbc208c34509eaf77751ac45d9ef51a5dce8..b51c3f8c485496734ea58c15377a1215 // CraftBukkit end } diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 319f51eb8adde7584c74780ac0539f4b8ef8fe7f..ddadb0f13b96a39ec89cdaeea7bc02ee62ef2a06 100644 +index d3caadb3e884d7d0468daf5eff9abd6629ac4b49..a7de9d6bbbd0b3d60b1d49e116c388b1846f33e4 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -1,8 +1,10 @@ @@ -992,7 +992,7 @@ index 319f51eb8adde7584c74780ac0539f4b8ef8fe7f..ddadb0f13b96a39ec89cdaeea7bc02ee import com.google.common.collect.Lists; import com.google.common.collect.Queues; import com.google.common.collect.Sets; -@@ -1363,6 +1365,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1336,6 +1338,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider List<ServerPlayer> list = Lists.newArrayList(); List<ServerPlayer> list1 = this.level.players(); ObjectIterator objectiterator = this.entityMap.values().iterator(); @@ -1000,7 +1000,7 @@ index 319f51eb8adde7584c74780ac0539f4b8ef8fe7f..ddadb0f13b96a39ec89cdaeea7bc02ee ChunkMap.TrackedEntity playerchunkmap_entitytracker; -@@ -1387,14 +1390,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1360,14 +1363,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider playerchunkmap_entitytracker.serverEntity.sendChanges(); } } @@ -1019,10 +1019,10 @@ index 319f51eb8adde7584c74780ac0539f4b8ef8fe7f..ddadb0f13b96a39ec89cdaeea7bc02ee } diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index ab57071cc6ce8b79d883f2426855c1abf577e90d..c627d32e7dbc83b9fc60b89c73bff5c9992ad548 100644 +index e9f53f57c363a32106880ea9aad0ccf5a7342509..0ff45d4ce6ae0b7feac53c7a9f361f6454f8b7c3 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -269,13 +269,15 @@ public class ServerChunkCache extends ChunkSource { +@@ -197,13 +197,15 @@ public class ServerChunkCache extends ChunkSource { } gameprofilerfiller.incrementCounter("getChunkCacheMiss"); @@ -1040,7 +1040,7 @@ index ab57071cc6ce8b79d883f2426855c1abf577e90d..c627d32e7dbc83b9fc60b89c73bff5c9 ChunkResult<ChunkAccess> chunkresult = (ChunkResult) completablefuture.join(); ChunkAccess ichunkaccess1 = (ChunkAccess) chunkresult.orElse(null); // CraftBukkit - decompile error -@@ -440,7 +442,9 @@ public class ServerChunkCache extends ChunkSource { +@@ -368,7 +370,9 @@ public class ServerChunkCache extends ChunkSource { public void save(boolean flush) { this.runDistanceManagerUpdates(); @@ -1050,7 +1050,7 @@ index ab57071cc6ce8b79d883f2426855c1abf577e90d..c627d32e7dbc83b9fc60b89c73bff5c9 } @Override -@@ -482,10 +486,10 @@ public class ServerChunkCache extends ChunkSource { +@@ -410,10 +414,10 @@ public class ServerChunkCache extends ChunkSource { this.level.timings.doChunkMap.stopTiming(); // Spigot this.level.getProfiler().popPush("chunks"); if (tickChunks) { @@ -1063,7 +1063,7 @@ index ab57071cc6ce8b79d883f2426855c1abf577e90d..c627d32e7dbc83b9fc60b89c73bff5c9 } this.level.timings.doChunkUnload.startTiming(); // Spigot -@@ -508,6 +512,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -436,6 +440,7 @@ public class ServerChunkCache extends ChunkSource { gameprofilerfiller.push("filteringLoadedChunks"); List<ServerChunkCache.ChunkAndHolder> list = Lists.newArrayListWithCapacity(this.chunkMap.size()); Iterator iterator = this.chunkMap.getChunks().iterator(); @@ -1071,7 +1071,7 @@ index ab57071cc6ce8b79d883f2426855c1abf577e90d..c627d32e7dbc83b9fc60b89c73bff5c9 while (iterator.hasNext()) { ChunkHolder playerchunk = (ChunkHolder) iterator.next(); -@@ -520,8 +525,10 @@ public class ServerChunkCache extends ChunkSource { +@@ -448,8 +453,10 @@ public class ServerChunkCache extends ChunkSource { if (this.level.tickRateManager().runsNormally()) { gameprofilerfiller.popPush("naturalSpawnCount"); @@ -1082,7 +1082,7 @@ index ab57071cc6ce8b79d883f2426855c1abf577e90d..c627d32e7dbc83b9fc60b89c73bff5c9 this.lastSpawnState = spawnercreature_d; gameprofilerfiller.popPush("spawnAndTick"); -@@ -544,22 +551,25 @@ public class ServerChunkCache extends ChunkSource { +@@ -472,22 +479,25 @@ public class ServerChunkCache extends ChunkSource { } if (this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { @@ -1545,10 +1545,10 @@ index e6c586eb85c6c477a3c130e1e1a37b41f17c30c8..6e35709f2a7c32050908e7e5af5529c9 private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry(); public CraftPersistentDataContainer persistentDataContainer; 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 7898e1aaf82f096fa74bd3f5859f0f4303ea677f..05d959ccc424aaaa465ec256213f2ec4d44ef8b5 100644 +index c664021dbfffcf0db3247041270ce9a1ee6940de..332351b78fa22cd354b916c4a29bea5b4b223e40 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -710,6 +710,7 @@ public class LevelChunk extends ChunkAccess { +@@ -597,6 +597,7 @@ public class LevelChunk extends ChunkAccess { server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration)); if (this.needsDecoration) { @@ -1556,7 +1556,7 @@ index 7898e1aaf82f096fa74bd3f5859f0f4303ea677f..05d959ccc424aaaa465ec256213f2ec4 this.needsDecoration = false; java.util.Random random = new java.util.Random(); random.setSeed(this.level.getSeed()); -@@ -729,6 +730,7 @@ public class LevelChunk extends ChunkAccess { +@@ -616,6 +617,7 @@ public class LevelChunk extends ChunkAccess { } } server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk)); diff --git a/patches/server/0025-Further-improve-server-tick-loop.patch b/patches/server/0025-Further-improve-server-tick-loop.patch index 0a1f62fc08..0fc8d093bf 100644 --- a/patches/server/0025-Further-improve-server-tick-loop.patch +++ b/patches/server/0025-Further-improve-server-tick-loop.patch @@ -12,7 +12,7 @@ Previous implementation did not calculate TPS correctly. Switch to a realistic rolling average and factor in std deviation as an extra reporting variable diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 4137cf4d716680ff1b1ab0b8a3e8f7cb4bae7dbe..8fbc764fd2802f735b9d5fac2dabca6a7cebe58e 100644 +index a720743149f9d1f90eda3b7b928b9d25d8c8f553..c09f3dc29c86fef9edfe7831776a77fc73e52210 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -296,7 +296,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0034-Expose-server-build-information.patch b/patches/server/0034-Expose-server-build-information.patch index 7b10d6d232..de12c47edc 100644 --- a/patches/server/0034-Expose-server-build-information.patch +++ b/patches/server/0034-Expose-server-build-information.patch @@ -472,7 +472,7 @@ index 0000000000000000000000000000000000000000..790bad0494454ca12ee152e3de6da3da + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 8fbc764fd2802f735b9d5fac2dabca6a7cebe58e..3d9c7105bfdb1b0c63a036ba3213d51b2fb6425f 100644 +index c09f3dc29c86fef9edfe7831776a77fc73e52210..6f5b04a59fa1173bfdea2c59a9c13ca3710abb0c 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -43,7 +43,6 @@ import java.util.Set; @@ -492,7 +492,7 @@ index 8fbc764fd2802f735b9d5fac2dabca6a7cebe58e..3d9c7105bfdb1b0c63a036ba3213d51b import org.bukkit.event.server.ServerLoadEvent; // CraftBukkit end -@@ -1708,7 +1705,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -1703,7 +1700,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @DontObfuscate public String getServerModName() { diff --git a/patches/server/0038-Prevent-block-entity-and-entity-crashes.patch b/patches/server/0038-Prevent-block-entity-and-entity-crashes.patch index c4f8050de2..8c0b53d52b 100644 --- a/patches/server/0038-Prevent-block-entity-and-entity-crashes.patch +++ b/patches/server/0038-Prevent-block-entity-and-entity-crashes.patch @@ -44,10 +44,10 @@ index 6e35709f2a7c32050908e7e5af5529c9f342b787..d20f71a2098b327423cbdbbc096aa9e3 } } 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 05d959ccc424aaaa465ec256213f2ec4d44ef8b5..329f2210b73a75fc91a5ba06a1ed7f66c5aa2680 100644 +index 332351b78fa22cd354b916c4a29bea5b4b223e40..7bfe757b605f4e5a16b28214ac3b497e738b45b5 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -1073,11 +1073,11 @@ public class LevelChunk extends ChunkAccess { +@@ -948,11 +948,11 @@ public class LevelChunk extends ChunkAccess { gameprofilerfiller.pop(); } catch (Throwable throwable) { diff --git a/patches/server/0044-Optimize-explosions.patch b/patches/server/0044-Optimize-explosions.patch index e3fc8cb992..600d98a0a6 100644 --- a/patches/server/0044-Optimize-explosions.patch +++ b/patches/server/0044-Optimize-explosions.patch @@ -10,10 +10,10 @@ This patch adds a per-tick cache that is used for storing and retrieving an entity's exposure during an explosion. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 3d9c7105bfdb1b0c63a036ba3213d51b2fb6425f..5c82bf57575bbe8bea8d39bead51c6860ac86e37 100644 +index 6f5b04a59fa1173bfdea2c59a9c13ca3710abb0c..0b666bbe75a97a8e1e6153533416d156adb64a0a 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1579,6 +1579,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -1574,6 +1574,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa this.profiler.pop(); this.profiler.pop(); diff --git a/patches/server/0063-Add-exception-reporting-event.patch b/patches/server/0063-Add-exception-reporting-event.patch index d4df43a405..83206d2117 100644 --- a/patches/server/0063-Add-exception-reporting-event.patch +++ b/patches/server/0063-Add-exception-reporting-event.patch @@ -123,10 +123,10 @@ index 6a80479554f0c860a8dd6baa1a6506858fca83e3..6324689f52363f19501143c1649f0885 } 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 329f2210b73a75fc91a5ba06a1ed7f66c5aa2680..3df1ad6a4804832f4edb79a8c8fc60909a1aaa24 100644 +index 7bfe757b605f4e5a16b28214ac3b497e738b45b5..fb953b2172c322e8abf5aa50060adbc00fe92832 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -565,8 +565,13 @@ public class LevelChunk extends ChunkAccess { +@@ -466,8 +466,13 @@ public class LevelChunk extends ChunkAccess { BlockState iblockdata = this.getBlockState(blockposition); if (!iblockdata.hasBlockEntity()) { @@ -142,7 +142,7 @@ index 329f2210b73a75fc91a5ba06a1ed7f66c5aa2680..3df1ad6a4804832f4edb79a8c8fc6090 } else { BlockState iblockdata1 = blockEntity.getBlockState(); -@@ -1076,6 +1081,7 @@ public class LevelChunk extends ChunkAccess { +@@ -951,6 +956,7 @@ public class LevelChunk extends ChunkAccess { // Paper start - Prevent block entity and entity crashes final String msg = String.format("BlockEntity threw exception at %s:%s,%s,%s", LevelChunk.this.getLevel().getWorld().getName(), this.getPos().getX(), this.getPos().getY(), this.getPos().getZ()); net.minecraft.server.MinecraftServer.LOGGER.error(msg, throwable); diff --git a/patches/server/0078-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch b/patches/server/0078-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch index 70d7c34607..cea7703900 100644 --- a/patches/server/0078-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch +++ b/patches/server/0078-Only-process-BlockPhysicsEvent-if-a-plugin-has-a-lis.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Only process BlockPhysicsEvent if a plugin has a listener Saves on some object allocation and processing when no plugin listens to this diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 5c82bf57575bbe8bea8d39bead51c6860ac86e37..4fd88b63ae6e6aa3265f72f4f0ae1b1895b70be9 100644 +index 0b666bbe75a97a8e1e6153533416d156adb64a0a..c38f932fe1c22dbe9b2583aab43ae879e4e5d4ad 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1545,6 +1545,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0080-Configurable-Chunk-Inhabited-Time.patch b/patches/server/0080-Configurable-Chunk-Inhabited-Time.patch index 8af41cf8f6..9eb058e669 100644 --- a/patches/server/0080-Configurable-Chunk-Inhabited-Time.patch +++ b/patches/server/0080-Configurable-Chunk-Inhabited-Time.patch @@ -11,10 +11,10 @@ For people who want all chunks to be treated equally, you can chose a fixed valu This allows to fine-tune vanilla gameplay. 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 3df1ad6a4804832f4edb79a8c8fc60909a1aaa24..9a94b0513e8b75c8acf0117bc0fbf563655ec3d8 100644 +index fb953b2172c322e8abf5aa50060adbc00fe92832..a0f9fb2ac15f2fa51a3bbe915550155ac2e76649 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -271,6 +271,13 @@ public class LevelChunk extends ChunkAccess { +@@ -172,6 +172,13 @@ public class LevelChunk extends ChunkAccess { return new ChunkAccess.TicksToSave(this.blockTicks, this.fluidTicks); } diff --git a/patches/server/0089-Configurable-Player-Collision.patch b/patches/server/0089-Configurable-Player-Collision.patch index 01f37915a5..f64375d8bd 100644 --- a/patches/server/0089-Configurable-Player-Collision.patch +++ b/patches/server/0089-Configurable-Player-Collision.patch @@ -18,7 +18,7 @@ index 9a1a961eabd4362c171da78c6be82c867f3696a4..1d0c473442b5c72245c356054440323e ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buf, this.playerPrefix); ComponentSerialization.TRUSTED_STREAM_CODEC.encode(buf, this.playerSuffix); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 4fd88b63ae6e6aa3265f72f4f0ae1b1895b70be9..8f0a0384d12b738553a6bec02e3b9438671715a9 100644 +index c38f932fe1c22dbe9b2583aab43ae879e4e5d4ad..785e033064ac8067baba2b471797ca34cf323825 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -640,6 +640,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0094-remove-null-possibility-for-getServer-singleton.patch b/patches/server/0094-remove-null-possibility-for-getServer-singleton.patch index fb6f4a3728..22d8b6a7c0 100644 --- a/patches/server/0094-remove-null-possibility-for-getServer-singleton.patch +++ b/patches/server/0094-remove-null-possibility-for-getServer-singleton.patch @@ -6,7 +6,7 @@ Subject: [PATCH] remove null possibility for getServer singleton to stop IDE complaining about potential NPE diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 8f0a0384d12b738553a6bec02e3b9438671715a9..fa55700e61d10cc071e55dfe43b48aee2113cd44 100644 +index 785e033064ac8067baba2b471797ca34cf323825..75de08945200289b715d80f27adcfe2d22f42fbd 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -197,6 +197,7 @@ import co.aikar.timings.MinecraftTimings; // Paper @@ -25,7 +25,7 @@ index 8f0a0384d12b738553a6bec02e3b9438671715a9..fa55700e61d10cc071e55dfe43b48aee this.metricsRecorder = InactiveMetricsRecorder.INSTANCE; this.profiler = this.metricsRecorder.getProfiler(); this.onMetricsRecordingStopped = (methodprofilerresults) -> { -@@ -2554,9 +2556,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2549,9 +2551,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa return false; } diff --git a/patches/server/0098-Async-GameProfileCache-saving.patch b/patches/server/0098-Async-GameProfileCache-saving.patch index fae04396e8..b140bba3f6 100644 --- a/patches/server/0098-Async-GameProfileCache-saving.patch +++ b/patches/server/0098-Async-GameProfileCache-saving.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Async GameProfileCache saving diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index fa55700e61d10cc071e55dfe43b48aee2113cd44..56d51073eb0cd902fa2c1e790201f74d120b149f 100644 +index 75de08945200289b715d80f27adcfe2d22f42fbd..451b6fef2c13a35eb00370fccd92581c97810137 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -999,7 +999,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0129-Properly-handle-async-calls-to-restart-the-server.patch b/patches/server/0129-Properly-handle-async-calls-to-restart-the-server.patch index c5a8314eac..6bab23ed9e 100644 --- a/patches/server/0129-Properly-handle-async-calls-to-restart-the-server.patch +++ b/patches/server/0129-Properly-handle-async-calls-to-restart-the-server.patch @@ -30,7 +30,7 @@ will have plugins and worlds saving to the disk has a high potential to result in corruption/dataloss. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 56d51073eb0cd902fa2c1e790201f74d120b149f..7335f9bb936eeb585ee077b0b9c461d7946d6134 100644 +index 451b6fef2c13a35eb00370fccd92581c97810137..6c46ce47d1460dcd9b387f02a09d85048a45b049 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -242,6 +242,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0137-Basic-PlayerProfile-API.patch b/patches/server/0137-Basic-PlayerProfile-API.patch index 6a98ad657e..5cddffd5d6 100644 --- a/patches/server/0137-Basic-PlayerProfile-API.patch +++ b/patches/server/0137-Basic-PlayerProfile-API.patch @@ -559,7 +559,7 @@ index 0000000000000000000000000000000000000000..7ac27392a8647ef7d0dc78efe78703e9 + @NotNull GameProfile buildGameProfile(); +} diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java -index eb36bef19e6729c1cc44aefa927317963aba929e..4f5badb9429b34ed999183321c98b60978715638 100644 +index c6c723d9378c593c8608d5940f63c98dff097cd0..02d6c98b7a2212b13ffd9859ebfdc0a8357ebe65 100644 --- a/src/main/java/io/papermc/paper/util/MCUtil.java +++ b/src/main/java/io/papermc/paper/util/MCUtil.java @@ -1,5 +1,7 @@ diff --git a/patches/server/0165-PlayerNaturallySpawnCreaturesEvent.patch b/patches/server/0165-PlayerNaturallySpawnCreaturesEvent.patch index 06e70b667b..e9b4dead15 100644 --- a/patches/server/0165-PlayerNaturallySpawnCreaturesEvent.patch +++ b/patches/server/0165-PlayerNaturallySpawnCreaturesEvent.patch @@ -9,10 +9,10 @@ from triggering monster spawns on a server. Also a highly more effecient way to blanket block spawns in a world diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index ddadb0f13b96a39ec89cdaeea7bc02ee62ef2a06..d04b69838c6f5fd1808782cacb31c6e00087bbac 100644 +index a7de9d6bbbd0b3d60b1d49e116c388b1846f33e4..767e3aed729b630d67a702d5e5bda02e9865e6e1 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1101,7 +1101,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1074,7 +1074,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider chunkRange = (chunkRange > this.level.spigotConfig.viewDistance) ? (byte) this.level.spigotConfig.viewDistance : chunkRange; chunkRange = (chunkRange > 8) ? 8 : chunkRange; @@ -23,7 +23,7 @@ index ddadb0f13b96a39ec89cdaeea7bc02ee62ef2a06..d04b69838c6f5fd1808782cacb31c6e0 // Spigot end if (!this.distanceManager.hasPlayersNearby(chunkcoordintpair.toLong())) { return false; -@@ -1116,6 +1118,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1089,6 +1091,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } entityplayer = (ServerPlayer) iterator.next(); @@ -40,10 +40,10 @@ index ddadb0f13b96a39ec89cdaeea7bc02ee62ef2a06..d04b69838c6f5fd1808782cacb31c6e0 return true; diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index c627d32e7dbc83b9fc60b89c73bff5c9992ad548..f4451bb402abbc8e6506132b9b9702bb5d75e097 100644 +index 0ff45d4ce6ae0b7feac53c7a9f361f6454f8b7c3..035c33b1e1be4f41e5cbe09bf6c3abd617258cad 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -535,6 +535,15 @@ public class ServerChunkCache extends ChunkSource { +@@ -463,6 +463,15 @@ public class ServerChunkCache extends ChunkSource { boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit Util.shuffle(list, this.level.random); diff --git a/patches/server/0175-Implement-extended-PaperServerListPingEvent.patch b/patches/server/0175-Implement-extended-PaperServerListPingEvent.patch index bdf24696e3..4ca3384be1 100644 --- a/patches/server/0175-Implement-extended-PaperServerListPingEvent.patch +++ b/patches/server/0175-Implement-extended-PaperServerListPingEvent.patch @@ -162,7 +162,7 @@ index 0000000000000000000000000000000000000000..874dcbefea469440a9028ddc399a37c9 + +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 7335f9bb936eeb585ee077b0b9c461d7946d6134..1c024fb7f682c81c465f59f4ab5fbeac964d73e1 100644 +index 6c46ce47d1460dcd9b387f02a09d85048a45b049..f71b1c2497594b592bcc51be9fa6a6d8fe8e819b 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -3,6 +3,9 @@ package net.minecraft.server; diff --git a/patches/server/0227-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch b/patches/server/0227-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch index d443d145a4..df5cc389e6 100644 --- a/patches/server/0227-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch +++ b/patches/server/0227-Add-Debug-Entities-option-to-debug-dupe-uuid-issues.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add Debug Entities option to debug dupe uuid issues diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index d04b69838c6f5fd1808782cacb31c6e00087bbac..96b7f0ac35a1e87c3f78a24180b207c32749fb71 100644 +index 767e3aed729b630d67a702d5e5bda02e9865e6e1..27eaeea3f0719167d89e39b0b60f91ad9cc9f64e 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1321,6 +1321,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1294,6 +1294,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } else { ChunkMap.TrackedEntity playerchunkmap_entitytracker = new ChunkMap.TrackedEntity(entity, i, j, entitytypes.trackDeltas()); @@ -16,7 +16,7 @@ index d04b69838c6f5fd1808782cacb31c6e00087bbac..96b7f0ac35a1e87c3f78a24180b207c3 this.entityMap.put(entity.getId(), playerchunkmap_entitytracker); playerchunkmap_entitytracker.updatePlayers(this.level.players()); if (entity instanceof ServerPlayer) { -@@ -1361,7 +1362,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1334,7 +1335,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider if (playerchunkmap_entitytracker1 != null) { playerchunkmap_entitytracker1.broadcastRemoved(); } diff --git a/patches/server/0228-Add-Early-Warning-Feature-to-WatchDog.patch b/patches/server/0228-Add-Early-Warning-Feature-to-WatchDog.patch index 6be15047b5..545fb80f1b 100644 --- a/patches/server/0228-Add-Early-Warning-Feature-to-WatchDog.patch +++ b/patches/server/0228-Add-Early-Warning-Feature-to-WatchDog.patch @@ -9,7 +9,7 @@ thread dumps at an interval until the point of crash. This will help diagnose what was going on in that time before the crash. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 1c024fb7f682c81c465f59f4ab5fbeac964d73e1..3fbe9a4981c682ec602d8ad1c390a10f26505f08 100644 +index f71b1c2497594b592bcc51be9fa6a6d8fe8e819b..6a97ab5e8a435e67df77b1d0480ccb397314ee05 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1108,6 +1108,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0263-Improve-Server-Thread-Pool-and-Thread-Priorities.patch b/patches/server/0263-Improve-Server-Thread-Pool-and-Thread-Priorities.patch index 645b07b342..9ea7802386 100644 --- a/patches/server/0263-Improve-Server-Thread-Pool-and-Thread-Priorities.patch +++ b/patches/server/0263-Improve-Server-Thread-Pool-and-Thread-Priorities.patch @@ -92,7 +92,7 @@ index 54562fa04d14a937451ea7aa9d80194f2c31b471..4cf88f6d815d60cfbf8e4ecf9d96d0cf return executorService; } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 3fbe9a4981c682ec602d8ad1c390a10f26505f08..51cd2b33c89f2ba92ad926456551e789c8627c3b 100644 +index 6a97ab5e8a435e67df77b1d0480ccb397314ee05..c8b5714ad87b501fdf820ae2ad8e6a4bdef82651 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -323,6 +323,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0264-Optimize-World-Time-Updates.patch b/patches/server/0264-Optimize-World-Time-Updates.patch index 33b1fad747..a0210bfae8 100644 --- a/patches/server/0264-Optimize-World-Time-Updates.patch +++ b/patches/server/0264-Optimize-World-Time-Updates.patch @@ -8,7 +8,7 @@ the updates per world, so that we can re-use the same packet object for every player unless they have per-player time enabled. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 51cd2b33c89f2ba92ad926456551e789c8627c3b..3d9a333c0f8175fd3b961185f52ea9a83a2fbeb3 100644 +index c8b5714ad87b501fdf820ae2ad8e6a4bdef82651..2e96a4c61f9053c20060e9f45a313a6135ea4f16 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1563,12 +1563,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0277-Async-command-map-building.patch b/patches/server/0277-Async-command-map-building.patch index 43059464da..d6ee248a00 100644 --- a/patches/server/0277-Async-command-map-building.patch +++ b/patches/server/0277-Async-command-map-building.patch @@ -53,7 +53,7 @@ index 72756ef14b8ec8afd80313b9f6aaf76722cb18cf..a05aea8561ac102476ee1b3068942b09 event.getPlayer().getServer().getPluginManager().callEvent(event); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 3d9a333c0f8175fd3b961185f52ea9a83a2fbeb3..6494b92c6a6444a66ea0e5f8f2890c47f334c938 100644 +index 2e96a4c61f9053c20060e9f45a313a6135ea4f16..df5b553b8d1525f14dbb88ea86e1bf9d9c9e6950 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -931,6 +931,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0286-Server-Tick-Events.patch b/patches/server/0286-Server-Tick-Events.patch index df7f3cf156..7478aa71ac 100644 --- a/patches/server/0286-Server-Tick-Events.patch +++ b/patches/server/0286-Server-Tick-Events.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Server Tick Events Fires event at start and end of a server tick diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 6494b92c6a6444a66ea0e5f8f2890c47f334c938..12f530044d918ddc1ba4b2376419f9ed72283b98 100644 +index df5b553b8d1525f14dbb88ea86e1bf9d9c9e6950..ee86f2cb71b2c8dc85c27635efca3666de7a3cbe 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1435,6 +1435,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0312-Tracking-Range-Improvements.patch b/patches/server/0312-Tracking-Range-Improvements.patch index c72f88f8c8..ee9860cefa 100644 --- a/patches/server/0312-Tracking-Range-Improvements.patch +++ b/patches/server/0312-Tracking-Range-Improvements.patch @@ -8,10 +8,10 @@ Sets tracking range of watermobs to animals instead of misc and simplifies code Also ignores Enderdragon, defaulting it to Mojang's setting diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 96b7f0ac35a1e87c3f78a24180b207c32749fb71..795c81c8f6fa59eded8b5a5084a8acb46d118fdb 100644 +index 27eaeea3f0719167d89e39b0b60f91ad9cc9f64e..5b62b6ebfc1b2a9d4673953c20b12a97c50ef3a5 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1613,6 +1613,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1586,6 +1586,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider while (iterator.hasNext()) { Entity entity = (Entity) iterator.next(); int j = entity.getType().clientTrackingRange() * 16; diff --git a/patches/server/0315-Optimise-getChunkAt-calls-for-loaded-chunks.patch b/patches/server/0315-Optimise-getChunkAt-calls-for-loaded-chunks.patch index e832698085..6089b2b613 100644 --- a/patches/server/0315-Optimise-getChunkAt-calls-for-loaded-chunks.patch +++ b/patches/server/0315-Optimise-getChunkAt-calls-for-loaded-chunks.patch @@ -7,10 +7,10 @@ bypass the need to get a player chunk, then get the either, then unwrap it... diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index f4451bb402abbc8e6506132b9b9702bb5d75e097..ef35e5a9fc0bfcd13f02f9193fdd1e7a811e88fd 100644 +index 035c33b1e1be4f41e5cbe09bf6c3abd617258cad..097a333487d646c773349cde3cd08026986fd038 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -253,6 +253,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -181,6 +181,12 @@ public class ServerChunkCache extends ChunkSource { return this.getChunk(x, z, leastStatus, create); }, this.mainThreadProcessor).join(); } else { @@ -23,7 +23,7 @@ index f4451bb402abbc8e6506132b9b9702bb5d75e097..ef35e5a9fc0bfcd13f02f9193fdd1e7a ProfilerFiller gameprofilerfiller = this.level.getProfiler(); gameprofilerfiller.incrementCounter("getChunk"); -@@ -296,33 +302,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -224,33 +230,7 @@ public class ServerChunkCache extends ChunkSource { if (Thread.currentThread() != this.mainThread) { return null; } else { diff --git a/patches/server/0316-Add-debug-for-sync-chunk-loads.patch b/patches/server/0316-Add-debug-for-sync-chunk-loads.patch index b6f89a4792..2398618fb3 100644 --- a/patches/server/0316-Add-debug-for-sync-chunk-loads.patch +++ b/patches/server/0316-Add-debug-for-sync-chunk-loads.patch @@ -300,10 +300,10 @@ index 0000000000000000000000000000000000000000..95d6022c9cfb2e36ec5a71be6e343540 + } +} diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index ef35e5a9fc0bfcd13f02f9193fdd1e7a811e88fd..a94833f58eb823332890d07c147161e9e0a938e9 100644 +index 097a333487d646c773349cde3cd08026986fd038..be9604a0f267558c95125852d86761a2f175732a 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -280,6 +280,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -208,6 +208,7 @@ public class ServerChunkCache extends ChunkSource { Objects.requireNonNull(completablefuture); if (!completablefuture.isDone()) { // Paper diff --git a/patches/server/0326-Optimise-Chunk-getFluid.patch b/patches/server/0326-Optimise-Chunk-getFluid.patch index 955f6f3ed8..0e2e9cccd5 100644 --- a/patches/server/0326-Optimise-Chunk-getFluid.patch +++ b/patches/server/0326-Optimise-Chunk-getFluid.patch @@ -8,10 +8,10 @@ faster on its own, however removing the try catch makes it easier to inline due to code size 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 9a94b0513e8b75c8acf0117bc0fbf563655ec3d8..46a5d9270aaaccb2df7131fb9c921cccf914085c 100644 +index a0f9fb2ac15f2fa51a3bbe915550155ac2e76649..c7be1f8fdca34bcc12ecbe40ee5f426e0cd068d7 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -369,18 +369,20 @@ public class LevelChunk extends ChunkAccess { +@@ -270,18 +270,20 @@ public class LevelChunk extends ChunkAccess { } public FluidState getFluidState(int x, int y, int z) { @@ -38,7 +38,7 @@ index 9a94b0513e8b75c8acf0117bc0fbf563655ec3d8..46a5d9270aaaccb2df7131fb9c921ccc } catch (Throwable throwable) { CrashReport crashreport = CrashReport.forThrowable(throwable, "Getting fluid state"); CrashReportCategory crashreportsystemdetails = crashreport.addCategory("Block being got"); -@@ -390,6 +392,7 @@ public class LevelChunk extends ChunkAccess { +@@ -291,6 +293,7 @@ public class LevelChunk extends ChunkAccess { }); throw new ReportedException(crashreport); } diff --git a/patches/server/0328-Add-tick-times-API-and-mspt-command.patch b/patches/server/0328-Add-tick-times-API-and-mspt-command.patch index 06d5d06807..53ce864287 100644 --- a/patches/server/0328-Add-tick-times-API-and-mspt-command.patch +++ b/patches/server/0328-Add-tick-times-API-and-mspt-command.patch @@ -125,7 +125,7 @@ index 72f2e81b9905a0d57ed8e2a88578f62d5235c456..7b58b2d6297800c2dcdbf7539e5ab8e7 public static void registerCommands(final MinecraftServer server) { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 12f530044d918ddc1ba4b2376419f9ed72283b98..2a2b5205692573c9886a2696f376958809b899ac 100644 +index ee86f2cb71b2c8dc85c27635efca3666de7a3cbe..1e6546637c5c2ddf4aacc7a3ea8623ce55059203 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -258,6 +258,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -152,7 +152,7 @@ index 12f530044d918ddc1ba4b2376419f9ed72283b98..2a2b5205692573c9886a2696f3769588 this.logTickMethodTime(i); this.profiler.pop(); org.spigotmc.WatchdogThread.tick(); // Spigot -@@ -2863,4 +2873,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2858,4 +2868,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa public static record ServerResourcePackInfo(UUID id, String url, String hash, boolean isRequired, @Nullable Component prompt) { } diff --git a/patches/server/0334-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch b/patches/server/0334-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch index 2f32768c21..c037677373 100644 --- a/patches/server/0334-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch +++ b/patches/server/0334-Prevent-Double-PlayerChunkMap-adds-crashing-server.patch @@ -7,10 +7,10 @@ Suspected case would be around the technique used in .stopRiding Stack will identify any causer of this and warn instead of crashing. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 795c81c8f6fa59eded8b5a5084a8acb46d118fdb..1709821c73362b2ae54681ec1d59b40bfa9335b3 100644 +index 5b62b6ebfc1b2a9d4673953c20b12a97c50ef3a5..02ea2b2d5463909663bb599b6ca57198b8513456 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1308,6 +1308,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1281,6 +1281,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public void addEntity(Entity entity) { org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot diff --git a/patches/server/0345-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch b/patches/server/0345-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch index b9a47e9175..08456c3e37 100644 --- a/patches/server/0345-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch +++ b/patches/server/0345-Fire-PlayerJoinEvent-when-Player-is-actually-ready.patch @@ -31,10 +31,10 @@ delays anymore. public net.minecraft.server.level.ChunkMap addEntity(Lnet/minecraft/world/entity/Entity;)V diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 1709821c73362b2ae54681ec1d59b40bfa9335b3..68a1cc5f4f7f5997dfb7d40647e3e027c23ffb14 100644 +index 02ea2b2d5463909663bb599b6ca57198b8513456..37bfe3d315210462ed69bb1cb161604e9eb85c36 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1315,6 +1315,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1288,6 +1288,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return; } // Paper end - ignore and warn about illegal addEntity calls instead of crashing server diff --git a/patches/server/0354-misc-debugging-dumps.patch b/patches/server/0354-misc-debugging-dumps.patch index 7d0b8aaa0b..5959f30078 100644 --- a/patches/server/0354-misc-debugging-dumps.patch +++ b/patches/server/0354-misc-debugging-dumps.patch @@ -49,7 +49,7 @@ index e25fc35716aff1d1805884b18f67b0eb33d8c05c..8ca9ac8eff9d605baa878ca24e165ac5 StackTraceElement[] astacktraceelement = exception.getStackTrace(); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 2a2b5205692573c9886a2696f376958809b899ac..15938074ad20133f5ccdab0c8566556d7b807d8f 100644 +index 1e6546637c5c2ddf4aacc7a3ea8623ce55059203..af83b1c762239fe7c8c11d3904f30504b0a1ca67 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -916,6 +916,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0361-Wait-for-Async-Tasks-during-shutdown.patch b/patches/server/0361-Wait-for-Async-Tasks-during-shutdown.patch index 25e00fd77b..e7c0b4c6b0 100644 --- a/patches/server/0361-Wait-for-Async-Tasks-during-shutdown.patch +++ b/patches/server/0361-Wait-for-Async-Tasks-during-shutdown.patch @@ -10,7 +10,7 @@ Adds a 5 second grace period for any async tasks to finish and warns if any are still running after that delay just as reload does. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 15938074ad20133f5ccdab0c8566556d7b807d8f..095215a5cbf1abeb7836a6ccc87c195019a7f019 100644 +index af83b1c762239fe7c8c11d3904f30504b0a1ca67..badd42d84b6367f6926bcff0ec8426fb6402ae80 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -943,6 +943,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0376-Fix-Per-World-Difficulty-Remembering-Difficulty.patch b/patches/server/0376-Fix-Per-World-Difficulty-Remembering-Difficulty.patch index f74a80db7f..2ee047cbd9 100644 --- a/patches/server/0376-Fix-Per-World-Difficulty-Remembering-Difficulty.patch +++ b/patches/server/0376-Fix-Per-World-Difficulty-Remembering-Difficulty.patch @@ -8,7 +8,7 @@ makes it so that the server keeps the last difficulty used instead of restoring the server.properties every single load. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 095215a5cbf1abeb7836a6ccc87c195019a7f019..1d141c9ee7b8193d46ba47a8586fc334cabb62a1 100644 +index badd42d84b6367f6926bcff0ec8426fb6402ae80..331ed639496a73dbfdde795b6d6154a9c8ea78b4 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -837,7 +837,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -20,7 +20,7 @@ index 095215a5cbf1abeb7836a6ccc87c195019a7f019..1d141c9ee7b8193d46ba47a8586fc334 this.forceTicks = false; // CraftBukkit end -@@ -1854,11 +1854,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -1849,11 +1849,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa } } @@ -40,7 +40,7 @@ index 095215a5cbf1abeb7836a6ccc87c195019a7f019..1d141c9ee7b8193d46ba47a8586fc334 } } -@@ -1872,7 +1875,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -1867,7 +1870,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa while (iterator.hasNext()) { ServerLevel worldserver = (ServerLevel) iterator.next(); diff --git a/patches/server/0410-Cache-block-data-strings.patch b/patches/server/0410-Cache-block-data-strings.patch index de40dce04c..c73022bfec 100644 --- a/patches/server/0410-Cache-block-data-strings.patch +++ b/patches/server/0410-Cache-block-data-strings.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Cache block data strings diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 1d141c9ee7b8193d46ba47a8586fc334cabb62a1..eddb8792be0581d8f1c87d18b5ab7a02571addc7 100644 +index 331ed639496a73dbfdde795b6d6154a9c8ea78b4..5b7f2b2993844cbcc13742f69b0521832d1970da 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2153,6 +2153,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2148,6 +2148,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa this.getPlayerList().reloadResources(); this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary()); this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager); diff --git a/patches/server/0418-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch b/patches/server/0418-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch index b387ab8612..91a6325196 100644 --- a/patches/server/0418-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch +++ b/patches/server/0418-Fix-deop-kicking-non-whitelisted-player-when-white-l.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Fix deop kicking non-whitelisted player when white list is diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index eddb8792be0581d8f1c87d18b5ab7a02571addc7..b47110e9b5d8effdc9e768488f99a614c1070814 100644 +index 5b7f2b2993844cbcc13742f69b0521832d1970da..e39cfc9750bf1d3f20abb3a2e9d46fa51ccdc248 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2278,13 +2278,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2273,13 +2273,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa if (this.isEnforceWhitelist()) { PlayerList playerlist = source.getServer().getPlayerList(); UserWhiteList whitelist = playerlist.getWhiteList(); diff --git a/patches/server/0465-Add-ServerResourcesReloadedEvent.patch b/patches/server/0465-Add-ServerResourcesReloadedEvent.patch index 2268c27b1c..bfc98bc7e5 100644 --- a/patches/server/0465-Add-ServerResourcesReloadedEvent.patch +++ b/patches/server/0465-Add-ServerResourcesReloadedEvent.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add ServerResourcesReloadedEvent diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index b47110e9b5d8effdc9e768488f99a614c1070814..691d9d18e72a07b85bf13c6990b44e5cf56dffb5 100644 +index e39cfc9750bf1d3f20abb3a2e9d46fa51ccdc248..3511b578f137c94ed562690901952e81e6f90ee5 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2122,7 +2122,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2117,7 +2117,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa return this.functionManager; } @@ -22,7 +22,7 @@ index b47110e9b5d8effdc9e768488f99a614c1070814..691d9d18e72a07b85bf13c6990b44e5c CompletableFuture<Void> completablefuture = CompletableFuture.supplyAsync(() -> { Stream<String> stream = dataPacks.stream(); // CraftBukkit - decompile error PackRepository resourcepackrepository = this.packRepository; -@@ -2154,6 +2160,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2149,6 +2155,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary()); this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager); org.bukkit.craftbukkit.block.data.CraftBlockData.reloadCache(); // Paper - cache block data strings; they can be defined by datapacks so refresh it here diff --git a/patches/server/0489-Add-EntityMoveEvent.patch b/patches/server/0489-Add-EntityMoveEvent.patch index 999a3c35ff..724779feec 100644 --- a/patches/server/0489-Add-EntityMoveEvent.patch +++ b/patches/server/0489-Add-EntityMoveEvent.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add EntityMoveEvent diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 691d9d18e72a07b85bf13c6990b44e5cf56dffb5..64a334c368152656f0dbb811220ae20fbd3d5f85 100644 +index 3511b578f137c94ed562690901952e81e6f90ee5..93c92146c2c7961a5de970e1c18eb7a1907c551b 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1608,6 +1608,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0508-forced-whitelist-use-configurable-kick-message.patch b/patches/server/0508-forced-whitelist-use-configurable-kick-message.patch index 20600f75d1..a4cd1362fc 100644 --- a/patches/server/0508-forced-whitelist-use-configurable-kick-message.patch +++ b/patches/server/0508-forced-whitelist-use-configurable-kick-message.patch @@ -5,10 +5,10 @@ Subject: [PATCH] forced whitelist: use configurable kick message diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 64a334c368152656f0dbb811220ae20fbd3d5f85..fa37c6b43f76af0b82b056cf87ba350abf92e7bb 100644 +index 93c92146c2c7961a5de970e1c18eb7a1907c551b..84bc3fac67c8db28a7102f99bffe762cf34a4a7a 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2294,7 +2294,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2289,7 +2289,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa ServerPlayer entityplayer = (ServerPlayer) iterator.next(); if (!whitelist.isWhiteListed(entityplayer.getGameProfile()) && !this.getPlayerList().isOp(entityplayer.getGameProfile())) { // Paper - Fix kicking ops when whitelist is reloaded (MC-171420) diff --git a/patches/server/0548-Add-PlayerKickEvent-causes.patch b/patches/server/0548-Add-PlayerKickEvent-causes.patch index ebf1392ee2..050372991d 100644 --- a/patches/server/0548-Add-PlayerKickEvent-causes.patch +++ b/patches/server/0548-Add-PlayerKickEvent-causes.patch @@ -43,10 +43,10 @@ index dbcf183483766f39334d7f7e8336033906625f3f..300929a406905f5ff1ede664d5b99fb0 } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index fa37c6b43f76af0b82b056cf87ba350abf92e7bb..ee212ed5538357830ea8b69da650ab67d67634bb 100644 +index 84bc3fac67c8db28a7102f99bffe762cf34a4a7a..695d6265b4a9f98ba630593ba6c47769240bed93 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2294,7 +2294,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2289,7 +2289,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa ServerPlayer entityplayer = (ServerPlayer) iterator.next(); if (!whitelist.isWhiteListed(entityplayer.getGameProfile()) && !this.getPlayerList().isOp(entityplayer.getGameProfile())) { // Paper - Fix kicking ops when whitelist is reloaded (MC-171420) diff --git a/patches/server/0607-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch b/patches/server/0607-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch index 976f278b20..b950818c7b 100644 --- a/patches/server/0607-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch +++ b/patches/server/0607-Make-sure-inlined-getChunkAt-has-inlined-logic-for-l.patch @@ -10,22 +10,22 @@ chunks did get inlined, but the standard CPS.getChunkAt method was not inlined. diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index ed1fc466151ebebf7c3ac135c6893f4ea9a55a52..481248ef82d4257ca4cc88ab28a1a7946e22aef6 100644 +index ed1fc466151ebebf7c3ac135c6893f4ea9a55a52..38bcf9f410e8a9d47c7d486c28dbc16a6225b650 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -352,6 +352,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -352,7 +352,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Override public final LevelChunk getChunk(int chunkX, int chunkZ) { // Paper - final to help inline +- return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump + // Paper start - Perf: make sure loaded chunks get the inlined variant of this function + net.minecraft.server.level.ServerChunkCache cps = ((ServerLevel)this).getChunkSource(); -+ if (cps.mainThread == Thread.currentThread()) { -+ LevelChunk ifLoaded = cps.getChunkAtIfLoadedMainThread(chunkX, chunkZ); -+ if (ifLoaded != null) { -+ return ifLoaded; -+ } ++ LevelChunk ifLoaded = cps.getChunkAtIfLoadedImmediately(chunkX, chunkZ); ++ if (ifLoaded != null) { ++ return ifLoaded; + } ++ return (LevelChunk) cps.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump + // Paper end - Perf: make sure loaded chunks get the inlined variant of this function - return (LevelChunk) this.getChunk(chunkX, chunkZ, ChunkStatus.FULL, true); // Paper - avoid a method jump } + // Paper start - if loaded diff --git a/patches/server/0611-Oprimise-map-impl-for-tracked-players.patch b/patches/server/0611-Oprimise-map-impl-for-tracked-players.patch index 2cadeeb2a0..667d423e0c 100644 --- a/patches/server/0611-Oprimise-map-impl-for-tracked-players.patch +++ b/patches/server/0611-Oprimise-map-impl-for-tracked-players.patch @@ -7,10 +7,10 @@ Reference2BooleanOpenHashMap is going to have better lookups than HashMap. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 68a1cc5f4f7f5997dfb7d40647e3e027c23ffb14..77f064fb4437c1d98cf91dde98d4d88b28afa7c8 100644 +index 37bfe3d315210462ed69bb1cb161604e9eb85c36..be0f4a2a9c7fbc359fe79ecf82340db8f7436b22 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1529,7 +1529,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1502,7 +1502,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider final Entity entity; private final int range; SectionPos lastSectionPos; diff --git a/patches/server/0651-Expose-vanilla-BiomeProvider-from-WorldInfo.patch b/patches/server/0651-Expose-vanilla-BiomeProvider-from-WorldInfo.patch index 8306fb57e8..b31f8fcb58 100644 --- a/patches/server/0651-Expose-vanilla-BiomeProvider-from-WorldInfo.patch +++ b/patches/server/0651-Expose-vanilla-BiomeProvider-from-WorldInfo.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Expose vanilla BiomeProvider from WorldInfo diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index ee212ed5538357830ea8b69da650ab67d67634bb..22f8e49536658fabe6136dbeec6b77eaf4ae5ee8 100644 +index 695d6265b4a9f98ba630593ba6c47769240bed93..2559a40546701fefa7f28603cb637108bfc659da 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -612,7 +612,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0668-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch b/patches/server/0668-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch index 351cec2218..524fa973b7 100644 --- a/patches/server/0668-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch +++ b/patches/server/0668-Execute-chunk-tasks-fairly-for-worlds-while-waiting-.patch @@ -9,7 +9,7 @@ This might result in chunks loading far slower in the nether, for example. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 22f8e49536658fabe6136dbeec6b77eaf4ae5ee8..e5017b66b6b8b5f17fc49f0fbc5d342241cd9cad 100644 +index 2559a40546701fefa7f28603cb637108bfc659da..f728c5b75ee7db5522e558891988079c52df5e72 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1371,6 +1371,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0672-Option-to-have-default-CustomSpawners-in-custom-worl.patch b/patches/server/0672-Option-to-have-default-CustomSpawners-in-custom-worl.patch index eed2fe11bf..fb23e5d34e 100644 --- a/patches/server/0672-Option-to-have-default-CustomSpawners-in-custom-worl.patch +++ b/patches/server/0672-Option-to-have-default-CustomSpawners-in-custom-worl.patch @@ -10,7 +10,7 @@ just looking at the LevelStem key, look at the DimensionType key which is one level below that. Defaults to off to keep vanilla behavior. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index e5017b66b6b8b5f17fc49f0fbc5d342241cd9cad..f979bfd78e2d19b525e973be0ffef5bda0068c4b 100644 +index f728c5b75ee7db5522e558891988079c52df5e72..0ec8f1c94279b75369ab6bae98789c60a971502c 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -632,7 +632,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0673-Put-world-into-worldlist-before-initing-the-world.patch b/patches/server/0673-Put-world-into-worldlist-before-initing-the-world.patch index 28d59a5fbf..030720dfbf 100644 --- a/patches/server/0673-Put-world-into-worldlist-before-initing-the-world.patch +++ b/patches/server/0673-Put-world-into-worldlist-before-initing-the-world.patch @@ -7,7 +7,7 @@ Some parts of legacy conversion will need the overworld to get the legacy structure data storage diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index f979bfd78e2d19b525e973be0ffef5bda0068c4b..833ec409e3f79e1ae2b664418f219adb3af2957f 100644 +index 0ec8f1c94279b75369ab6bae98789c60a971502c..4e2ce30bc67b0033107715a5a2dbb419bdf17a4f 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -644,9 +644,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0674-Custom-Potion-Mixes.patch b/patches/server/0674-Custom-Potion-Mixes.patch index 62f7870ba8..3b95d09b1a 100644 --- a/patches/server/0674-Custom-Potion-Mixes.patch +++ b/patches/server/0674-Custom-Potion-Mixes.patch @@ -96,10 +96,10 @@ index 0000000000000000000000000000000000000000..7ea357ac2f3a93db4ebdf24b5072be7d + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 833ec409e3f79e1ae2b664418f219adb3af2957f..29011d222434cbb2c71797786b8376ea37c8023a 100644 +index 4e2ce30bc67b0033107715a5a2dbb419bdf17a4f..2408e5afb9096aa991742983bb573040fbfdb5cb 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2166,6 +2166,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2161,6 +2161,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa this.worldData.setDataConfiguration(worlddataconfiguration); this.resources.managers.updateRegistryTags(); diff --git a/patches/server/0712-Throw-exception-on-world-create-while-being-ticked.patch b/patches/server/0712-Throw-exception-on-world-create-while-being-ticked.patch index 5d2cb89f00..ccad54896d 100644 --- a/patches/server/0712-Throw-exception-on-world-create-while-being-ticked.patch +++ b/patches/server/0712-Throw-exception-on-world-create-while-being-ticked.patch @@ -7,7 +7,7 @@ There are no plans to support creating worlds while worlds are being ticked themselvess. diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 29011d222434cbb2c71797786b8376ea37c8023a..4b44447360b75b6dbe93d8176dcba2db02d77f1e 100644 +index 2408e5afb9096aa991742983bb573040fbfdb5cb..56ab40965ca6034ed430d4d5c4be99fa69a3a453 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -318,6 +318,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -36,7 +36,7 @@ index 29011d222434cbb2c71797786b8376ea37c8023a..4b44447360b75b6dbe93d8176dcba2db while (iterator.hasNext()) { ServerLevel worldserver = (ServerLevel) iterator.next(); worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent -@@ -1655,6 +1658,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -1650,6 +1653,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa this.profiler.pop(); worldserver.explosionDensityCache.clear(); // Paper - Optimize explosions } diff --git a/patches/server/0730-Warn-on-plugins-accessing-faraway-chunks.patch b/patches/server/0730-Warn-on-plugins-accessing-faraway-chunks.patch index e97023798f..f3d50c526a 100644 --- a/patches/server/0730-Warn-on-plugins-accessing-faraway-chunks.patch +++ b/patches/server/0730-Warn-on-plugins-accessing-faraway-chunks.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Warn on plugins accessing faraway chunks diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 481248ef82d4257ca4cc88ab28a1a7946e22aef6..b97427789d6162e16b9c3a56b89b2dd08a04297f 100644 +index 38bcf9f410e8a9d47c7d486c28dbc16a6225b650..210c3b6167dac93e550fe849e34b5aa404ab6dce 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -339,7 +339,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { diff --git a/patches/server/0738-Fix-plugin-loggers-on-server-shutdown.patch b/patches/server/0738-Fix-plugin-loggers-on-server-shutdown.patch index 6914ddec62..896ce1668f 100644 --- a/patches/server/0738-Fix-plugin-loggers-on-server-shutdown.patch +++ b/patches/server/0738-Fix-plugin-loggers-on-server-shutdown.patch @@ -37,7 +37,7 @@ index 0000000000000000000000000000000000000000..c1d3bac79bb8b4796c013ff4472f75dc + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 4b44447360b75b6dbe93d8176dcba2db02d77f1e..ba382397e39311598d044faf6b74665810d2e510 100644 +index 56ab40965ca6034ed430d4d5c4be99fa69a3a453..eef519384b5f8f6b2551ed61affe6cb1f3489702 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1239,6 +1239,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0751-Fix-a-bunch-of-vanilla-bugs.patch b/patches/server/0751-Fix-a-bunch-of-vanilla-bugs.patch index eba9c58e8b..72188bb0c4 100644 --- a/patches/server/0751-Fix-a-bunch-of-vanilla-bugs.patch +++ b/patches/server/0751-Fix-a-bunch-of-vanilla-bugs.patch @@ -85,10 +85,10 @@ index 6854ca4d4fec2b4fa541c3fabf63787665572609..e7b444a10b244828827b3c66c5346520 } diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 77f064fb4437c1d98cf91dde98d4d88b28afa7c8..ccbd527803a2a4e911a01f815cc9c7ab785af836 100644 +index be0f4a2a9c7fbc359fe79ecf82340db8f7436b22..b6b15e8ce98603d6e580a31ba458fedc8b3f663a 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1091,7 +1091,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1064,7 +1064,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // CraftBukkit end } diff --git a/patches/server/0778-Fix-premature-player-kicks-on-shutdown.patch b/patches/server/0778-Fix-premature-player-kicks-on-shutdown.patch index 7f465faed2..1050fc37f7 100644 --- a/patches/server/0778-Fix-premature-player-kicks-on-shutdown.patch +++ b/patches/server/0778-Fix-premature-player-kicks-on-shutdown.patch @@ -47,10 +47,10 @@ index 4d9f1fc884050993287adfa4578a87da710623fb..a8dfe7a4b3d01bf75587be078f471d1e this.disconnect((Component) Component.translatable("multiplayer.disconnect.server_shutdown")); } catch (ClassCastException classcastexception) { diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index ba382397e39311598d044faf6b74665810d2e510..fcf450f9fefda8cf2391dcb61075cbd855475d6c 100644 +index eef519384b5f8f6b2551ed61affe6cb1f3489702..374c20e530d2abd41674d80c711bd3737c6f6941 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -2099,7 +2099,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2094,7 +2094,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @Override public void executeIfPossible(Runnable runnable) { if (this.isStopped()) { diff --git a/patches/server/0780-Player-Entity-Tracking-Events.patch b/patches/server/0780-Player-Entity-Tracking-Events.patch index dbbfa39ceb..fd863e753b 100644 --- a/patches/server/0780-Player-Entity-Tracking-Events.patch +++ b/patches/server/0780-Player-Entity-Tracking-Events.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Player Entity Tracking Events diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index ccbd527803a2a4e911a01f815cc9c7ab785af836..e2521e1a56df8dcb1de815e5973de952408d3b8b 100644 +index b6b15e8ce98603d6e580a31ba458fedc8b3f663a..91ca37605bf7ba65875b588fe9764b30214f63b6 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1601,7 +1601,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1574,7 +1574,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // CraftBukkit end if (flag) { if (this.seenBy.add(player.connection)) { diff --git a/patches/server/0826-Fix-block-place-logic.patch b/patches/server/0826-Fix-block-place-logic.patch index de31264ab7..3796cc773d 100644 --- a/patches/server/0826-Fix-block-place-logic.patch +++ b/patches/server/0826-Fix-block-place-logic.patch @@ -22,10 +22,10 @@ index 7d76cdc59984b156628273c8357485eb10046007..7180996027f70aef7afe32fb2adfce64 itemstack.consume(1, entityhuman); return InteractionResult.sidedSuccess(world.isClientSide); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index b97427789d6162e16b9c3a56b89b2dd08a04297f..b8d8041aecc2ff008247449cba8d9f192cf51073 100644 +index 210c3b6167dac93e550fe849e34b5aa404ab6dce..ed1c50d31fc077e4e009719fa622a44edefcdf2c 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -554,17 +554,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -552,17 +552,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable { // CraftBukkit start iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam CraftWorld world = ((ServerLevel) this).getWorld(); diff --git a/patches/server/0851-Folia-scheduler-and-owned-region-API.patch b/patches/server/0851-Folia-scheduler-and-owned-region-API.patch index 07e4625db1..591f137a5c 100644 --- a/patches/server/0851-Folia-scheduler-and-owned-region-API.patch +++ b/patches/server/0851-Folia-scheduler-and-owned-region-API.patch @@ -1148,7 +1148,7 @@ index 0000000000000000000000000000000000000000..d306f911757a4d556c82c0070d4837db + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index fcf450f9fefda8cf2391dcb61075cbd855475d6c..b7254c342501f2d7fbbe8959a6e88a5d1f6e076e 100644 +index 374c20e530d2abd41674d80c711bd3737c6f6941..cbceb0ddea32781f89a19b1edb258bc23b96ee92 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1579,6 +1579,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0855-Only-capture-actual-tree-growth.patch b/patches/server/0855-Only-capture-actual-tree-growth.patch index 1cba6ddee8..2ca8f263b7 100644 --- a/patches/server/0855-Only-capture-actual-tree-growth.patch +++ b/patches/server/0855-Only-capture-actual-tree-growth.patch @@ -29,10 +29,10 @@ index 92be749721f26e9385e592a985db58cf05c67801..1f2e6f57ffb827ef9bf3623bfdde07db entityhuman.awardStat(Stats.ITEM_USED.get(item)); // SPIGOT-7236 - award stat } diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index b8d8041aecc2ff008247449cba8d9f192cf51073..ffaf6e65a7314479a129fed41f58bf2d75ea5dae 100644 +index ed1c50d31fc077e4e009719fa622a44edefcdf2c..8337f2f1d650fc7efb830a7034e3676dc0695ee4 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -1380,4 +1380,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1378,4 +1378,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable { return range <= 0 ? 64.0 * 64.0 : range * range; // 64 is taken from default in ServerLevel#levelEvent } // Paper end - respect global sound events gamerule diff --git a/patches/server/0869-Configurable-entity-tracking-range-by-Y-coordinate.patch b/patches/server/0869-Configurable-entity-tracking-range-by-Y-coordinate.patch index a437b50f0f..8cb5db78e2 100644 --- a/patches/server/0869-Configurable-entity-tracking-range-by-Y-coordinate.patch +++ b/patches/server/0869-Configurable-entity-tracking-range-by-Y-coordinate.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Configurable entity tracking range by Y coordinate Options to configure entity tracking by Y coordinate, also for each entity category. diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index e2521e1a56df8dcb1de815e5973de952408d3b8b..6c5557aad2455b79bb2adf8939eb9a6127ccc3c3 100644 +index 91ca37605bf7ba65875b588fe9764b30214f63b6..2943390c0ec7e542d2bb1996dbbd626445c3108e 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1593,6 +1593,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1566,6 +1566,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider double d1 = vec3d.x * vec3d.x + vec3d.z * vec3d.z; double d2 = d0 * d0; boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); diff --git a/patches/server/0901-Don-t-check-if-we-can-see-non-visible-entities.patch b/patches/server/0901-Don-t-check-if-we-can-see-non-visible-entities.patch index 109e1a443b..246f9bf864 100644 --- a/patches/server/0901-Don-t-check-if-we-can-see-non-visible-entities.patch +++ b/patches/server/0901-Don-t-check-if-we-can-see-non-visible-entities.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Don't check if we can see non-visible entities diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 6c5557aad2455b79bb2adf8939eb9a6127ccc3c3..469f1dcb22c06025681e727e281b5b53f2b21c1f 100644 +index 2943390c0ec7e542d2bb1996dbbd626445c3108e..7bc142fd0ba58846f1b2ac57df0bfc044966f4ed 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1604,7 +1604,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1577,7 +1577,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper end - Configurable entity tracking range by Y // CraftBukkit start - respect vanish API diff --git a/patches/server/0915-Don-t-fire-sync-events-during-worldgen.patch b/patches/server/0915-Don-t-fire-sync-events-during-worldgen.patch index eeeae7474c..7286e5c172 100644 --- a/patches/server/0915-Don-t-fire-sync-events-during-worldgen.patch +++ b/patches/server/0915-Don-t-fire-sync-events-during-worldgen.patch @@ -133,7 +133,7 @@ index cf8258e8d46ca7286a66c38fa24af369bd9a279f..0555abfda468c343af8244a122ebe769 // return Optional.empty(); // } diff --git a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -index 0794d92c42b0db6b367505ae28f09f1fd39fa312..cd7f1309cf01a5f01a28aded03a36fe15adb1756 100644 +index 524b51a0ab808a0629c871ad813115abd4b49dbd..fceed3d08ee6f4c171685986bb19d2be592eedc6 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java +++ b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java @@ -92,15 +92,17 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel { diff --git a/patches/server/0927-Properly-handle-experience-dropping-on-block-break.patch b/patches/server/0927-Properly-handle-experience-dropping-on-block-break.patch index 471a743c29..63f20a9c63 100644 --- a/patches/server/0927-Properly-handle-experience-dropping-on-block-break.patch +++ b/patches/server/0927-Properly-handle-experience-dropping-on-block-break.patch @@ -7,10 +7,10 @@ This causes spawnAfterBreak to spawn xp by default, removing the need to manuall For classes that use custom xp amounts, they can drop the resources with disabling diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index ffaf6e65a7314479a129fed41f58bf2d75ea5dae..16478e2b2368636394cec8a9b30c6fb03e190851 100644 +index 8337f2f1d650fc7efb830a7034e3676dc0695ee4..2f1acea765d1b6726863cdc89707ca6148548493 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -619,7 +619,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -617,7 +617,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable { if (drop) { BlockEntity tileentity = iblockdata.hasBlockEntity() ? this.getBlockEntity(pos) : null; diff --git a/patches/server/0930-Reduce-allocation-of-Vec3D-by-entity-tracker.patch b/patches/server/0930-Reduce-allocation-of-Vec3D-by-entity-tracker.patch index 86bd3e7f29..16af41429a 100644 --- a/patches/server/0930-Reduce-allocation-of-Vec3D-by-entity-tracker.patch +++ b/patches/server/0930-Reduce-allocation-of-Vec3D-by-entity-tracker.patch @@ -18,10 +18,10 @@ index a043ac10834562d357ef0b5aded2e916e2a0d056..74276c368016fcc4dbf9579b2ecbadc9 @VisibleForTesting static long encode(double value) { diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 469f1dcb22c06025681e727e281b5b53f2b21c1f..2ce7da9707d7c1a48b5609ae51a516d599d7aee8 100644 +index 7bc142fd0ba58846f1b2ac57df0bfc044966f4ed..a03385b1b0a2f9b98319137b87d917856d3c632c 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1587,10 +1587,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1560,10 +1560,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public void updatePlayer(ServerPlayer player) { org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot if (player != this.entity) { diff --git a/patches/server/0945-Add-onboarding-message-for-initial-server-start.patch b/patches/server/0945-Add-onboarding-message-for-initial-server-start.patch index 89e4195a68..e3249e5435 100644 --- a/patches/server/0945-Add-onboarding-message-for-initial-server-start.patch +++ b/patches/server/0945-Add-onboarding-message-for-initial-server-start.patch @@ -29,7 +29,7 @@ index cc847dce0116b8260790b890b1d5452c280e186c..2a5453707bc172d8d0efe3f11959cb0b return instance; } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index b7254c342501f2d7fbbe8959a6e88a5d1f6e076e..837fc12dfc57f36f06bd8e49681bb4b98a87397c 100644 +index cbceb0ddea32781f89a19b1edb258bc23b96ee92..fc0f17cd7ed4fcf10e0396aeeed115280318128d 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1136,6 +1136,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/0951-Fix-creation-of-invalid-block-entity-during-world-ge.patch b/patches/server/0951-Fix-creation-of-invalid-block-entity-during-world-ge.patch index 8769e0adaf..d810be487e 100644 --- a/patches/server/0951-Fix-creation-of-invalid-block-entity-during-world-ge.patch +++ b/patches/server/0951-Fix-creation-of-invalid-block-entity-during-world-ge.patch @@ -36,10 +36,10 @@ index 682c8cfbd917c086072f1756861a340800ea40da..b26a4a38144ec1b171db911bbf949b53 nbttagcompound.putInt("x", pos.getX()); 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 46a5d9270aaaccb2df7131fb9c921cccf914085c..8ae6a4311aa52f84130a1eba61a1ad84e2272350 100644 +index c7be1f8fdca34bcc12ecbe40ee5f426e0cd068d7..7f8983a2102787b13e5d28d6981055da6acd1012 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -1081,9 +1081,14 @@ public class LevelChunk extends ChunkAccess { +@@ -956,9 +956,14 @@ public class LevelChunk extends ChunkAccess { if (this.blockEntity.getType().isValid(iblockdata)) { this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), iblockdata, this.blockEntity); this.loggedInvalidBlockState = false; diff --git a/patches/server/0955-Per-world-ticks-per-spawn-settings.patch b/patches/server/0955-Per-world-ticks-per-spawn-settings.patch index bfd6fd26af..ea163724cf 100644 --- a/patches/server/0955-Per-world-ticks-per-spawn-settings.patch +++ b/patches/server/0955-Per-world-ticks-per-spawn-settings.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Per world ticks per spawn settings diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 16478e2b2368636394cec8a9b30c6fb03e190851..4d6409875771413de7ae20def2aaad4049709c30 100644 +index 2f1acea765d1b6726863cdc89707ca6148548493..81bdb6e64e04641f741c2c3350236685b097ec7a 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -186,6 +186,15 @@ public abstract class Level implements LevelAccessor, AutoCloseable { diff --git a/patches/server/0957-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch b/patches/server/0957-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch index 0fd49bd9ed..8caee3a137 100644 --- a/patches/server/0957-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch +++ b/patches/server/0957-Protect-Bedrock-and-End-Portal-Frames-from-being-des.patch @@ -25,10 +25,10 @@ index 69914a048987c21ee2ed2c489aab269862fda8f2..bff83fe413c7baef4ba56a3270ea4463 if (!this.level.isInWorldBounds(blockposition)) { diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 4d6409875771413de7ae20def2aaad4049709c30..dd519eacd6d4bea5447bea471f0ac6540d9bb49c 100644 +index 81bdb6e64e04641f741c2c3350236685b097ec7a..c6c9400fa155831ab11d0f059971d0123617e622 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -449,6 +449,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -447,6 +447,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) { // CraftBukkit start - tree generation if (this.captureTreeGeneration) { diff --git a/patches/server/0975-Brigadier-based-command-API.patch b/patches/server/0975-Brigadier-based-command-API.patch index e97c314b29..71f121c880 100644 --- a/patches/server/0975-Brigadier-based-command-API.patch +++ b/patches/server/0975-Brigadier-based-command-API.patch @@ -2213,7 +2213,7 @@ index 982b2bab27e3d55d0ba07060862c0c3183ad91b0..5fa8a3343ffc11e82c20b78a73205fd8 Component component = message.resolveComponent(commandSourceStack); CommandSigningContext commandSigningContext = commandSourceStack.getSigningContext(); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 837fc12dfc57f36f06bd8e49681bb4b98a87397c..6915522f669631779c1fb8a8e2db330f4b9fb921 100644 +index fc0f17cd7ed4fcf10e0396aeeed115280318128d..e14c0e1ccf526f81e28db5545d9e2351641e1bc8 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -306,7 +306,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -2243,7 +2243,7 @@ index 837fc12dfc57f36f06bd8e49681bb4b98a87397c..6915522f669631779c1fb8a8e2db330f this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP)); this.connection.acceptConnections(); } -@@ -2187,9 +2189,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2182,9 +2184,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa return new MinecraftServer.ReloadableResources(resourcemanager, datapackresources); }); }).thenAcceptAsync((minecraftserver_reloadableresources) -> { @@ -2254,7 +2254,7 @@ index 837fc12dfc57f36f06bd8e49681bb4b98a87397c..6915522f669631779c1fb8a8e2db330f this.packRepository.setSelected(dataPacks); WorldDataConfiguration worlddataconfiguration = new WorldDataConfiguration(MinecraftServer.getSelectedPacks(this.packRepository, true), this.worldData.enabledFeatures()); -@@ -2200,8 +2202,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2195,8 +2197,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa this.getPlayerList().reloadResources(); this.functionManager.replaceLibrary(this.resources.managers.getFunctionLibrary()); this.structureTemplateManager.onResourceManagerReload(this.resources.resourceManager); diff --git a/patches/server/0981-Fix-cancelling-BlockPlaceEvent-calling-onRemove.patch b/patches/server/0981-Fix-cancelling-BlockPlaceEvent-calling-onRemove.patch index 7c3afdd7bb..dc3fddbc64 100644 --- a/patches/server/0981-Fix-cancelling-BlockPlaceEvent-calling-onRemove.patch +++ b/patches/server/0981-Fix-cancelling-BlockPlaceEvent-calling-onRemove.patch @@ -21,7 +21,7 @@ index b800b03ae034b276740c3b41555a52b778ad9aad..86197725f0f2ac1e650297ae7a799075 // Brute force all possible updates diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index dd519eacd6d4bea5447bea471f0ac6540d9bb49c..6f822e9487bef5b9766d5ae86ebbd687e4eadc42 100644 +index c6c9400fa155831ab11d0f059971d0123617e622..e27d3547d1e19c137e05e6b8d075127a8bafb237 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -151,6 +151,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @@ -33,10 +33,10 @@ index dd519eacd6d4bea5447bea471f0ac6540d9bb49c..6f822e9487bef5b9766d5ae86ebbd687 public Map<BlockPos, BlockEntity> capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper - Retain block place order when capturing blockstates public List<ItemEntity> captureDrops; 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 8ae6a4311aa52f84130a1eba61a1ad84e2272350..6c0e12c9c9c0fb8377cd1f48a43ca75c9fc3e58e 100644 +index 7f8983a2102787b13e5d28d6981055da6acd1012..602ad80c2b93d320bf2a25832d25a58cb8c72e4b 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -444,7 +444,7 @@ public class LevelChunk extends ChunkAccess { +@@ -345,7 +345,7 @@ public class LevelChunk extends ChunkAccess { boolean flag3 = iblockdata1.hasBlockEntity(); diff --git a/patches/server/0991-Chunk-System-Starlight-from-Moonrise.patch b/patches/server/0991-Chunk-System-Starlight-from-Moonrise.patch index 3a0997f047..cde583319b 100644 --- a/patches/server/0991-Chunk-System-Starlight-from-Moonrise.patch +++ b/patches/server/0991-Chunk-System-Starlight-from-Moonrise.patch @@ -3105,10 +3105,10 @@ index 0000000000000000000000000000000000000000..e95cc73ddf20050aa4a241b0a309240e +} diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/ChunkSystem.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/ChunkSystem.java new file mode 100644 -index 0000000000000000000000000000000000000000..532a8c15009a4514d2682f52129785feb34a56f8 +index 0000000000000000000000000000000000000000..c2ff037e180393de6576f12c32c665ef640d6f50 --- /dev/null +++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/ChunkSystem.java -@@ -0,0 +1,156 @@ +@@ -0,0 +1,162 @@ +package ca.spottedleaf.moonrise.patches.chunk_system; + +import ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor; @@ -3194,22 +3194,28 @@ index 0000000000000000000000000000000000000000..532a8c15009a4514d2682f52129785fe + io.papermc.paper.chunk.system.ChunkSystem.onChunkHolderDelete(level, holder); + } + -+ public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { ++ public static void onChunkPreBorder(final LevelChunk chunk, final ChunkHolder holder) { + ((ChunkSystemServerChunkCache)((ServerLevel)chunk.getLevel()).getChunkSource()) + .moonrise$setFullChunk(chunk.getPos().x, chunk.getPos().z, chunk); ++ } ++ ++ public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { + // TODO move hook + io.papermc.paper.chunk.system.ChunkSystem.onChunkBorder(chunk, holder); + chunk.loadCallback(); // Paper + } + + public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { -+ ((ChunkSystemServerChunkCache)((ServerLevel)chunk.getLevel()).getChunkSource()) -+ .moonrise$setFullChunk(chunk.getPos().x, chunk.getPos().z, null); + // TODO move hook + io.papermc.paper.chunk.system.ChunkSystem.onChunkNotBorder(chunk, holder); + chunk.unloadCallback(); // Paper + } + ++ public static void onChunkPostNotBorder(final LevelChunk chunk, final ChunkHolder holder) { ++ ((ChunkSystemServerChunkCache)((ServerLevel)chunk.getLevel()).getChunkSource()) ++ .moonrise$setFullChunk(chunk.getPos().x, chunk.getPos().z, null); ++ } ++ + public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { + // TODO move hook + io.papermc.paper.chunk.system.ChunkSystem.onChunkTicking(chunk, holder); @@ -11034,10 +11040,10 @@ index 0000000000000000000000000000000000000000..faf76a5c2f9fa2eea38d2c7f2ab1c438 +} diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java new file mode 100644 -index 0000000000000000000000000000000000000000..05381b2c58c1b60f222eed672dddede047b663c5 +index 0000000000000000000000000000000000000000..d5fc5756ea960096ff23376a6b7ac68a2a462d22 --- /dev/null +++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java -@@ -0,0 +1,2032 @@ +@@ -0,0 +1,2034 @@ +package ca.spottedleaf.moonrise.patches.chunk_system.scheduling; + +import ca.spottedleaf.concurrentutil.completable.Completable; @@ -12314,6 +12320,7 @@ index 0000000000000000000000000000000000000000..05381b2c58c1b60f222eed672dddede0 + // state upgrade + if (!current.isOrAfter(FullChunkStatus.FULL) && pending.isOrAfter(FullChunkStatus.FULL)) { + this.updateCurrentState(FullChunkStatus.FULL); ++ ChunkSystem.onChunkPreBorder(chunk, this.vanillaChunkHolder); + this.scheduler.chunkHolderManager.ensureInAutosave(this); + this.changeEntityChunkStatus(FullChunkStatus.FULL); + ChunkSystem.onChunkBorder(chunk, this.vanillaChunkHolder); @@ -12351,6 +12358,7 @@ index 0000000000000000000000000000000000000000..05381b2c58c1b60f222eed672dddede0 + this.onFullChunkLoadChange(false, changedFullStatus); + this.changeEntityChunkStatus(FullChunkStatus.INACCESSIBLE); + ChunkSystem.onChunkNotBorder(chunk, this.vanillaChunkHolder); ++ ChunkSystem.onChunkPostNotBorder(chunk, this.vanillaChunkHolder); + this.updateCurrentState(FullChunkStatus.INACCESSIBLE); + } + } @@ -21949,7 +21957,7 @@ index 0000000000000000000000000000000000000000..57692a503e147a00ac4e1586cd78e12b + private SaveUtil() {} +} 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 0d0cb3e63acd5156b6f9d6d78cc949b0af36a77b..dd1649abe57d7191c15a9b2862d5fd11ff0706b1 100644 +index a79abe9b26f68d573812e91554124783075ae17a..183d99ec9b94ca20a823c46a2d6bf0a215046d48 100644 --- a/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java +++ b/src/main/java/io/papermc/paper/chunk/system/ChunkSystem.java @@ -25,6 +25,10 @@ import java.util.List; @@ -21963,7 +21971,7 @@ index 0d0cb3e63acd5156b6f9d6d78cc949b0af36a77b..dd1649abe57d7191c15a9b2862d5fd11 public final class ChunkSystem { private static final Logger LOGGER = LogUtils.getLogger(); -@@ -35,31 +39,17 @@ public final class ChunkSystem { +@@ -35,35 +39,17 @@ public final class ChunkSystem { } public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) { @@ -21985,12 +21993,16 @@ index 0d0cb3e63acd5156b6f9d6d78cc949b0af36a77b..dd1649abe57d7191c15a9b2862d5fd11 - } - scheduleChunkLoad(level, chunkX, chunkZ, ChunkStatus.EMPTY, addTicket, priority, (final ChunkAccess chunk) -> { - if (chunk == null) { -- onComplete.accept(null); +- if (onComplete != null) { +- onComplete.accept(null); +- } - } else { - if (chunk.getPersistedStatus().isOrAfter(toStatus)) { - scheduleChunkLoad(level, chunkX, chunkZ, toStatus, addTicket, priority, onComplete); - } else { -- onComplete.accept(null); +- if (onComplete != null) { +- onComplete.accept(null); +- } - } - } - }); @@ -21998,7 +22010,7 @@ index 0d0cb3e63acd5156b6f9d6d78cc949b0af36a77b..dd1649abe57d7191c15a9b2862d5fd11 } static final TicketType<Long> CHUNK_LOAD = TicketType.create("chunk_load", Long::compareTo); -@@ -67,164 +57,29 @@ public final class ChunkSystem { +@@ -71,160 +57,29 @@ public final class ChunkSystem { private static long chunkLoadCounter = 0L; public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus, final boolean addTicket, final PrioritisedExecutor.Priority priority, final Consumer<ChunkAccess> onComplete) { @@ -22023,8 +22035,6 @@ index 0d0cb3e63acd5156b6f9d6d78cc949b0af36a77b..dd1649abe57d7191c15a9b2862d5fd11 - if (onComplete != null) { - onComplete.accept(chunk); - } -- } catch (final ThreadDeath death) { -- throw death; - } catch (final Throwable thr) { - LOGGER.error("Exception handling chunk load callback", thr); - SneakyThrow.sneaky(thr); @@ -22092,8 +22102,6 @@ index 0d0cb3e63acd5156b6f9d6d78cc949b0af36a77b..dd1649abe57d7191c15a9b2862d5fd11 - if (onComplete != null) { - onComplete.accept(chunk); - } -- } catch (final ThreadDeath death) { -- throw death; - } catch (final Throwable thr) { - LOGGER.error("Exception handling chunk load callback", thr); - SneakyThrow.sneaky(thr); @@ -22169,7 +22177,7 @@ index 0d0cb3e63acd5156b6f9d6d78cc949b0af36a77b..dd1649abe57d7191c15a9b2862d5fd11 } public static boolean hasAnyChunkHolders(final ServerLevel level) { -@@ -274,27 +129,19 @@ public final class ChunkSystem { +@@ -268,27 +123,19 @@ public final class ChunkSystem { } public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) { @@ -22571,7 +22579,7 @@ index c33f85b570f159ab465b5a10a8044a81f2797f43..244a19ecd0234fa1d7a6ecfea2075159 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 6915522f669631779c1fb8a8e2db330f4b9fb921..3aecd55b9a069710c5d383b2f9113b147ad1ab57 100644 +index e14c0e1ccf526f81e28db5545d9e2351641e1bc8..3c230ae060998bfb79d5812fef21a80a9df8c8ff 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -198,7 +198,7 @@ import org.bukkit.event.server.ServerLoadEvent; @@ -22699,7 +22707,7 @@ index 6915522f669631779c1fb8a8e2db330f4b9fb921..3aecd55b9a069710c5d383b2f9113b14 if (entity.isRemoved()) { continue; } -@@ -2661,6 +2671,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2656,6 +2666,13 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa } @@ -23253,7 +23261,7 @@ index d9ad32acdf46a43a649334a3b736aeb7b3af21d1..fae17a075d7efaf24d916877dd5968eb public static final int RADIUS_AROUND_FULL_CHUNK = FULL_CHUNK_STEP.accumulatedDependencies().getRadius(); public static final int MAX_LEVEL = 33 + RADIUS_AROUND_FULL_CHUNK; diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887b8fb816e 100644 +index a03385b1b0a2f9b98319137b87d917856d3c632c..1363dda031d1b541d76241812a957a12521cbc05 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -122,10 +122,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -23294,9 +23302,9 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 // CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback() public final CallbackExecutor callbackExecutor = new CallbackExecutor(); -@@ -223,23 +218,21 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - +@@ -198,23 +193,21 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + // Paper end + // Paper start public final ChunkHolder getUnloadingChunkHolder(int chunkX, int chunkZ) { - return this.pendingUnloads.get(io.papermc.paper.util.CoordinateUtils.getChunkKey(chunkX, chunkZ)); + return null; // Paper - rewrite chunk system @@ -23321,7 +23329,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 Path path = session.getDimensionPath(world.dimension()); this.storageName = path.getFileName().toString(); -@@ -270,15 +263,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -245,15 +238,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.chunkStatusListener = chunkStatusChangeListener; ProcessorMailbox<Runnable> threadedmailbox1 = ProcessorMailbox.create(executor, "light"); @@ -23338,9 +23346,9 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 - this.worldGenContext = new WorldGenContext(world, chunkGenerator, structureTemplateManager, this.lightEngine, this.mainThreadMailbox); + this.worldGenContext = new WorldGenContext(world, chunkGenerator, structureTemplateManager, this.lightEngine, null); // Paper - rewrite chunk system // Paper start - this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new); - this.regionManagers.add(this.dataRegionManager); -@@ -319,23 +310,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + this.nearbyPlayers = new io.papermc.paper.util.player.NearbyPlayers(this.level); + // Paper end +@@ -292,23 +283,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } boolean isChunkTracked(ServerPlayer player, int chunkX, int chunkZ) { @@ -23366,7 +23374,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 } protected ThreadedLevelLightEngine getLightEngine() { -@@ -344,20 +323,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -317,20 +296,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Nullable protected ChunkHolder getUpdatingChunkIfPresent(long pos) { @@ -23396,7 +23404,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 } public String getChunkDebugData(ChunkPos chunkPos) { -@@ -386,55 +367,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -359,55 +340,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } private CompletableFuture<ChunkResult<List<ChunkAccess>>> getChunkRangeFuture(ChunkHolder centerChunk, int margin, IntFunction<ChunkStatus> distanceToStatus) { @@ -23453,7 +23461,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 } public ReportedException debugFuturesAndCreateReportedException(IllegalStateException exception, String details) { -@@ -464,93 +397,23 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -437,93 +370,23 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public CompletableFuture<ChunkResult<LevelChunk>> prepareEntityTickingChunk(ChunkHolder holder) { @@ -23553,7 +23561,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 } protected void tick(BooleanSupplier shouldKeepTicking) { -@@ -567,134 +430,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -540,134 +403,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public boolean hasWork() { @@ -23694,7 +23702,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 } private static boolean isChunkDataValid(CompoundTag nbt) { -@@ -754,137 +508,44 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -727,137 +481,44 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @Override public GenerationChunkHolder acquireGeneration(long pos) { @@ -23841,7 +23849,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 } public int getTickingGenerated() { -@@ -892,135 +553,84 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -865,135 +526,84 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } private boolean saveChunkIfNeeded(ChunkHolder chunkHolder) { @@ -24029,7 +24037,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 @Nullable public LevelChunk getChunkToSend(long pos) { ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos); -@@ -1086,7 +696,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1059,7 +669,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } // CraftBukkit start @@ -24038,7 +24046,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 return this.upgradeChunkTag(this.level.getTypeKey(), this.overworldDataStorage, nbttagcompound, this.generator().getTypeNameForDataFixer(), chunkcoordintpair, this.level); // CraftBukkit end } -@@ -1180,7 +790,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1153,7 +763,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } player.setChunkTrackingView(ChunkTrackingView.EMPTY); @@ -24047,7 +24055,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 this.addPlayerToDistanceMaps(player); // Paper - distance maps } else { SectionPos sectionposition = player.getLastSectionPos(); -@@ -1191,7 +801,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1164,7 +774,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } this.removePlayerFromDistanceMaps(player); // Paper - distance maps @@ -24056,7 +24064,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 } } -@@ -1239,71 +849,31 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1212,71 +822,31 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider this.playerMap.unIgnorePlayer(player); } @@ -24139,7 +24147,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 } public void addEntity(Entity entity) { -@@ -1374,13 +944,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1347,13 +917,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } protected void tick() { @@ -24154,7 +24162,7 @@ index 2ce7da9707d7c1a48b5609ae51a516d599d7aee8..b849e0cf15f894aa87b1bb397d85b887 List<ServerPlayer> list = Lists.newArrayList(); List<ServerPlayer> list1 = this.level.players(); -@@ -1487,27 +1051,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1460,27 +1024,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } public void waitForLightBeforeSending(ChunkPos centerPos, int radius) { @@ -24944,7 +24952,7 @@ index 3dc1daa3c6a04d3ff1a2353773b465fc380994a2..3575782f13a7f3c52e64dc5046803305 } } diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c51f9a50d 100644 +index be9604a0f267558c95125852d86761a2f175732a..014e7d3c3b9e8f6c2b456d63bcf885f55b01ded9 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -46,7 +46,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp @@ -24956,12 +24964,11 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c public static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper private static final List<ChunkStatus> CHUNK_STATUSES = ChunkStatus.getStatusList(); -@@ -75,6 +75,62 @@ public class ServerChunkCache extends ChunkSource { +@@ -73,6 +73,61 @@ public class ServerChunkCache extends ChunkSource { + private final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<net.minecraft.world.level.chunk.LevelChunk> fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>(); long chunkFutureAwaitCounter; - private final LevelChunk[] lastLoadedChunks = new LevelChunk[4 * 4]; // Paper end + // Paper start - rewrite chunk system -+ private final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<LevelChunk> fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>(); + + @Override + public final void moonrise$setFullChunk(final int chunkX, final int chunkZ, final LevelChunk chunk) { @@ -25019,7 +25026,22 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c public ServerChunkCache(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor workerExecutor, ChunkGenerator chunkGenerator, int viewDistance, int simulationDistance, boolean dsync, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier<DimensionDataStorage> persistentStateManagerFactory) { this.level = world; -@@ -248,63 +304,25 @@ public class ServerChunkCache extends ChunkSource { +@@ -99,13 +154,7 @@ public class ServerChunkCache extends ChunkSource { + } + // CraftBukkit end + // Paper start +- public void addLoadedChunk(LevelChunk chunk) { +- this.fullChunks.put(chunk.coordinateKey, chunk); +- } +- +- public void removeLoadedChunk(LevelChunk chunk) { +- this.fullChunks.remove(chunk.coordinateKey); +- } ++ // Paper - rewrite chunk system + + @Nullable + public ChunkAccess getChunkAtImmediately(int x, int z) { +@@ -176,63 +225,25 @@ public class ServerChunkCache extends ChunkSource { @Nullable @Override public ChunkAccess getChunk(int x, int z, ChunkStatus leastStatus, boolean create) { @@ -25035,13 +25057,13 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c - } - // Paper end - Perf: Optimise getChunkAt calls for loaded chunks - ProfilerFiller gameprofilerfiller = this.level.getProfiler(); -- -- gameprofilerfiller.incrementCounter("getChunk"); -- long k = ChunkPos.asLong(x, z); + // Paper start - rewrite chunk system + if (leastStatus == ChunkStatus.FULL) { + final LevelChunk ret = this.fullChunks.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(x, z)); +- 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]) { - ChunkAccess ichunkaccess = this.lastChunk[l]; @@ -25093,7 +25115,7 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c } private void clearCache() { -@@ -335,56 +353,59 @@ public class ServerChunkCache extends ChunkSource { +@@ -263,56 +274,59 @@ public class ServerChunkCache extends ChunkSource { } private CompletableFuture<ChunkResult<ChunkAccess>> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { @@ -25110,7 +25132,14 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c - FullChunkStatus oldChunkState = ChunkLevel.fullStatus(playerchunk.oldTicketLevel); - FullChunkStatus currentChunkState = ChunkLevel.fullStatus(playerchunk.getTicketLevel()); - currentlyUnloading = (oldChunkState.isOrAfter(FullChunkStatus.FULL) && !currentChunkState.isOrAfter(FullChunkStatus.FULL)); -- } ++ final int minLevel = ChunkLevel.byStatus(leastStatus); ++ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkX, chunkZ); ++ ++ final boolean needsFullScheduling = leastStatus == ChunkStatus.FULL && (chunkHolder == null || !chunkHolder.getChunkStatus().isOrAfter(FullChunkStatus.FULL)); ++ ++ if ((chunkHolder == null || chunkHolder.getTicketLevel() > minLevel || needsFullScheduling) && !create) { ++ return ChunkHolder.UNLOADED_CHUNK_FUTURE; + } - if (create && !currentlyUnloading) { - // CraftBukkit end - this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair); @@ -25123,19 +25152,7 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c - gameprofilerfiller.pop(); - if (this.chunkAbsent(playerchunk, l)) { - throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("No chunk holder after ticket has been added")); -- } -- } -+ final int minLevel = ChunkLevel.byStatus(leastStatus); -+ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkX, chunkZ); + -+ final boolean needsFullScheduling = leastStatus == ChunkStatus.FULL && (chunkHolder == null || !chunkHolder.getChunkStatus().isOrAfter(FullChunkStatus.FULL)); -+ -+ if ((chunkHolder == null || chunkHolder.getTicketLevel() > minLevel || needsFullScheduling) && !create) { -+ return ChunkHolder.UNLOADED_CHUNK_FUTURE; - } - -- return this.chunkAbsent(playerchunk, l) ? GenerationChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.scheduleChunkGenerationTask(leastStatus, this.chunkMap); -- } + final ChunkAccess ifPresent = chunkHolder == null ? null : chunkHolder.getChunkIfPresent(leastStatus); + if (needsFullScheduling || ifPresent == null) { + // schedule @@ -25145,17 +25162,21 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c + ret.complete(ChunkHolder.UNLOADED_CHUNK); + } else { + ret.complete(ChunkResult.of(chunk)); -+ } + } +- } +- } + }; -- private boolean chunkAbsent(@Nullable ChunkHolder holder, int maxLevel) { -- return holder == null || holder.oldTicketLevel > maxLevel; // CraftBukkit using oldTicketLevel for isLoaded checks +- return this.chunkAbsent(playerchunk, l) ? GenerationChunkHolder.UNLOADED_CHUNK_FUTURE : playerchunk.scheduleChunkGenerationTask(leastStatus, this.chunkMap); +- } + ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().scheduleChunkLoad( + chunkX, chunkZ, leastStatus, true, + ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGHER, + complete + ); -+ + +- private boolean chunkAbsent(@Nullable ChunkHolder holder, int maxLevel) { +- return holder == null || holder.oldTicketLevel > maxLevel; // CraftBukkit using oldTicketLevel for isLoaded checks + return ret; + } else { + // can return now @@ -25190,7 +25211,7 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c } @Override -@@ -397,16 +418,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -325,16 +339,7 @@ public class ServerChunkCache extends ChunkSource { } public boolean runDistanceManagerUpdates() { // Paper - public @@ -25208,7 +25229,7 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c } // Paper start -@@ -416,13 +428,14 @@ public class ServerChunkCache extends ChunkSource { +@@ -344,13 +349,14 @@ public class ServerChunkCache extends ChunkSource { // Paper end public boolean isPositionTicking(long pos) { @@ -25227,7 +25248,7 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c try (co.aikar.timings.Timing timed = level.timings.chunkSaveData.startTiming()) { // Paper - Timings this.chunkMap.saveAllChunks(flush); } // Paper - Timings -@@ -435,12 +448,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -363,12 +369,7 @@ public class ServerChunkCache extends ChunkSource { } public void close(boolean save) throws IOException { @@ -25241,7 +25262,7 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c } // CraftBukkit start - modelled on below -@@ -468,6 +476,7 @@ public class ServerChunkCache extends ChunkSource { +@@ -396,6 +397,7 @@ public class ServerChunkCache extends ChunkSource { this.level.getProfiler().popPush("chunks"); if (tickChunks) { this.level.timings.chunks.startTiming(); // Paper - timings @@ -25249,7 +25270,7 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c this.tickChunks(); this.level.timings.chunks.stopTiming(); // Paper - timings this.chunkMap.tick(); -@@ -567,11 +576,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -495,11 +497,12 @@ public class ServerChunkCache extends ChunkSource { } private void getFullChunk(long pos, Consumer<LevelChunk> chunkConsumer) { @@ -25266,7 +25287,7 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c } -@@ -665,6 +675,12 @@ public class ServerChunkCache extends ChunkSource { +@@ -593,6 +596,12 @@ public class ServerChunkCache extends ChunkSource { this.chunkMap.setServerViewDistance(watchDistance); } @@ -25279,7 +25300,7 @@ index a94833f58eb823332890d07c147161e9e0a938e9..cba80945fa0d8ca55b0d422925f8c94c public void setSimulationDistance(int simulationDistance) { this.distanceManager.updateSimulationDistance(simulationDistance); } -@@ -743,16 +759,14 @@ public class ServerChunkCache extends ChunkSource { +@@ -671,16 +680,14 @@ public class ServerChunkCache extends ChunkSource { @Override // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task public boolean pollTask() { @@ -26763,7 +26784,7 @@ index bd20bea7f76a7307f1698fb2dfef37125032d166..70c2017400168d4fef3c14462798edcf if (shape.isEmpty()) { return true; diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 6f822e9487bef5b9766d5ae86ebbd687e4eadc42..77c6613c39e3b266944e28cf2627483d9f32c511 100644 +index e27d3547d1e19c137e05e6b8d075127a8bafb237..557273061fa03ebaa4b9de01ad12ed4ac859c292 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -102,7 +102,7 @@ import org.bukkit.entity.SpawnCategory; @@ -26842,7 +26863,7 @@ index 6f822e9487bef5b9766d5ae86ebbd687e4eadc42..77c6613c39e3b266944e28cf2627483d } // Paper start - Cancel hit for vanished players -@@ -551,7 +604,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -549,7 +602,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { this.setBlocksDirty(blockposition, iblockdata1, iblockdata2); } @@ -26851,7 +26872,7 @@ index 6f822e9487bef5b9766d5ae86ebbd687e4eadc42..77c6613c39e3b266944e28cf2627483d this.sendBlockUpdated(blockposition, iblockdata1, iblockdata, i); } -@@ -951,7 +1004,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -949,7 +1002,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } // Paper end - Perf: Optimize capturedTileEntities lookup // CraftBukkit end @@ -26860,7 +26881,7 @@ index 6f822e9487bef5b9766d5ae86ebbd687e4eadc42..77c6613c39e3b266944e28cf2627483d } public void setBlockEntity(BlockEntity blockEntity) { -@@ -1041,28 +1094,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1039,28 +1092,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable { @Override public List<Entity> getEntities(@Nullable Entity except, AABB box, Predicate<? super Entity> predicate) { this.getProfiler().incrementCounter("getEntities"); @@ -26894,7 +26915,7 @@ index 6f822e9487bef5b9766d5ae86ebbd687e4eadc42..77c6613c39e3b266944e28cf2627483d } @Override -@@ -1077,36 +1115,77 @@ public abstract class Level implements LevelAccessor, AutoCloseable { +@@ -1075,36 +1113,77 @@ public abstract class Level implements LevelAccessor, AutoCloseable { this.getEntities(filter, box, predicate, result, Integer.MAX_VALUE); } @@ -27315,7 +27336,7 @@ index 365074be989aa4a178114fd5e9810f1a68640196..4af698930712389881601069a921f054 @Override public BlockEntity getBlockEntity(BlockPos pos) { 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 6c0e12c9c9c0fb8377cd1f48a43ca75c9fc3e58e..c4f87ff9e0c9806a1d7abc4842caa5a4caa357bd 100644 +index 602ad80c2b93d320bf2a25832d25a58cb8c72e4b..443e5e1b1c0e7c93f61c1905c78c29a17860989c 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -53,7 +53,7 @@ import net.minecraft.world.ticks.LevelChunkTicks; @@ -27327,9 +27348,9 @@ index 6c0e12c9c9c0fb8377cd1f48a43ca75c9fc3e58e..c4f87ff9e0c9806a1d7abc4842caa5a4 static final Logger LOGGER = LogUtils.getLogger(); private static final TickingBlockEntity NULL_TICKER = new TickingBlockEntity() { -@@ -218,6 +218,14 @@ public class LevelChunk extends ChunkAccess { - } - } +@@ -119,6 +119,14 @@ public class LevelChunk extends ChunkAccess { + // Paper start + boolean loadedTicketLevel; // Paper end + // Paper start - rewrite chunk system + private boolean postProcessingDone; @@ -27342,7 +27363,7 @@ index 6c0e12c9c9c0fb8377cd1f48a43ca75c9fc3e58e..c4f87ff9e0c9806a1d7abc4842caa5a4 public LevelChunk(ServerLevel world, ProtoChunk protoChunk, @Nullable LevelChunk.PostLoadProcessor entityLoader) { this(world, protoChunk.getPos(), protoChunk.getUpgradeData(), protoChunk.unpackBlockTicks(), protoChunk.unpackFluidTicks(), protoChunk.getInhabitedTime(), protoChunk.getSections(), entityLoader, protoChunk.getBlendingData()); -@@ -247,13 +255,19 @@ public class LevelChunk extends ChunkAccess { +@@ -148,13 +156,19 @@ public class LevelChunk extends ChunkAccess { } } @@ -27363,7 +27384,7 @@ index 6c0e12c9c9c0fb8377cd1f48a43ca75c9fc3e58e..c4f87ff9e0c9806a1d7abc4842caa5a4 } @Override -@@ -436,7 +450,7 @@ public class LevelChunk extends ChunkAccess { +@@ -337,7 +351,7 @@ public class LevelChunk extends ChunkAccess { ProfilerFiller gameprofilerfiller = this.level.getProfiler(); gameprofilerfiller.push("updateSkyLightSources"); @@ -27372,15 +27393,21 @@ index 6c0e12c9c9c0fb8377cd1f48a43ca75c9fc3e58e..c4f87ff9e0c9806a1d7abc4842caa5a4 gameprofilerfiller.popPush("queueCheckLight"); this.level.getChunkSource().getLightEngine().checkBlock(blockposition); gameprofilerfiller.pop(); -@@ -696,6 +710,7 @@ public class LevelChunk extends ChunkAccess { +@@ -597,11 +611,12 @@ public class LevelChunk extends ChunkAccess { // CraftBukkit start public void loadCallback() { + if (this.loadedTicketLevel) { LOGGER.error("Double calling chunk load!", new Throwable()); } // Paper - // Paper start - neighbour cache - int chunkX = this.chunkPos.x; - int chunkZ = this.chunkPos.z; -@@ -723,6 +738,7 @@ public class LevelChunk extends ChunkAccess { + // Paper start + this.loadedTicketLevel = true; + // Paper end + org.bukkit.Server server = this.level.getCraftServer(); +- this.level.getChunkSource().addLoadedChunk(this); // Paper ++ // Paper - rewrite chunk system + if (server != null) { + /* + * If it's a new world, the first few chunks are generated inside +@@ -610,6 +625,7 @@ public class LevelChunk extends ChunkAccess { */ org.bukkit.Chunk bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, this.needsDecoration)); @@ -27388,7 +27415,7 @@ index 6c0e12c9c9c0fb8377cd1f48a43ca75c9fc3e58e..c4f87ff9e0c9806a1d7abc4842caa5a4 if (this.needsDecoration) { try (co.aikar.timings.Timing ignored = this.level.timings.chunkLoadPopulate.startTiming()) { // Paper -@@ -751,9 +767,11 @@ public class LevelChunk extends ChunkAccess { +@@ -638,13 +654,15 @@ public class LevelChunk extends ChunkAccess { } public void unloadCallback() { @@ -27401,7 +27428,12 @@ index 6c0e12c9c9c0fb8377cd1f48a43ca75c9fc3e58e..c4f87ff9e0c9806a1d7abc4842caa5a4 server.getPluginManager().callEvent(unloadEvent); // note: saving can be prevented, but not forced if no saving is actually required this.mustNotSave = !unloadEvent.isSaveChunk(); -@@ -777,8 +795,27 @@ public class LevelChunk extends ChunkAccess { +- this.level.getChunkSource().removeLoadedChunk(this); // Paper ++ // Paper - rewrite chunk system + // Paper start + this.loadedTicketLevel = false; + // Paper end +@@ -652,8 +670,27 @@ public class LevelChunk extends ChunkAccess { @Override public boolean isUnsaved() { @@ -27430,7 +27462,7 @@ index 6c0e12c9c9c0fb8377cd1f48a43ca75c9fc3e58e..c4f87ff9e0c9806a1d7abc4842caa5a4 // CraftBukkit end public boolean isEmpty() { -@@ -884,6 +921,7 @@ public class LevelChunk extends ChunkAccess { +@@ -759,6 +796,7 @@ public class LevelChunk extends ChunkAccess { this.pendingBlockEntities.clear(); this.upgradeData.upgrade(this); @@ -29064,29 +29096,12 @@ index 5717c0e1d6df07a4613356dc78d970d2101c68d7..cab7ca4218e5903b6a5e518af55457b9 @Override diff --git a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -index cd7f1309cf01a5f01a28aded03a36fe15adb1756..43cb7b91945a72ab4bd998a3a3eca3cdcf0432a9 100644 +index fceed3d08ee6f4c171685986bb19d2be592eedc6..bf18f9ad7dec2b09ebfcb5ec6566f2556e842f22 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java +++ b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -@@ -815,19 +815,26 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel { - @Nullable - @Override - public BlockState getBlockStateIfLoaded(final BlockPos blockposition) { -- return null; -+ return this.handle.getBlockStateIfLoaded(blockposition); // Paper - rewrite chunk system - } - - @Nullable - @Override - public FluidState getFluidIfLoaded(final BlockPos blockposition) { -- return null; -+ return this.handle.getFluidIfLoaded(blockposition); // Paper - rewrite chunk system - } - - @Nullable - @Override +@@ -829,5 +829,12 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel { public ChunkAccess getChunkIfLoadedImmediately(final int x, final int z) { -- return null; -+ return this.handle.getChunkIfLoadedImmediately(x, z); // Paper - rewrite chunk system + return this.handle.getChunkIfLoadedImmediately(x, z); } + + // Paper start - rewrite chunk system diff --git a/patches/server/0994-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch b/patches/server/0994-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch index 2cdcbebb6f..fc25a541d6 100644 --- a/patches/server/0994-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch +++ b/patches/server/0994-Optimize-isInWorldBounds-and-getBlockState-for-inlin.patch @@ -29,7 +29,7 @@ index 02367ef1371dde94ff6c4cd40bd32e800d6ccaaf..7b0fc7135bc107103dcaed6dc0707b18 this.x = x; this.y = y; diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 77c6613c39e3b266944e28cf2627483d9f32c511..b3a433786fabf6f2cfba2cdc8d21f6447191a310 100644 +index 557273061fa03ebaa4b9de01ad12ed4ac859c292..316a72f5019d4ad65237b41ccb4ef3be729246ad 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -394,7 +394,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl diff --git a/patches/server/0996-Strip-raytracing-for-EntityLiving-hasLineOfSight.patch b/patches/server/0996-Strip-raytracing-for-EntityLiving-hasLineOfSight.patch index 52c1df5a4d..4ef94ee4ce 100644 --- a/patches/server/0996-Strip-raytracing-for-EntityLiving-hasLineOfSight.patch +++ b/patches/server/0996-Strip-raytracing-for-EntityLiving-hasLineOfSight.patch @@ -62,7 +62,7 @@ index bb8e962e63c7a2d931f9bd7f7c002aa35cfa5fd3..0fa131a6c98adb498fc8d534e0e39647 default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition) { // Paper start - Add predicate for blocks when raytracing diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index b3a433786fabf6f2cfba2cdc8d21f6447191a310..2d318964ef1f54940059b8d62bfc8f8ae87424e5 100644 +index 316a72f5019d4ad65237b41ccb4ef3be729246ad..5ea8f51accdda2387b640d2cff1d6a8baa673bee 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -386,10 +386,87 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl diff --git a/patches/server/1000-Entity-Activation-Range-2.0.patch b/patches/server/1000-Entity-Activation-Range-2.0.patch index 84b1883a6e..dcb2dabb14 100644 --- a/patches/server/1000-Entity-Activation-Range-2.0.patch +++ b/patches/server/1000-Entity-Activation-Range-2.0.patch @@ -340,7 +340,7 @@ index 0b7f52021441d633c37543e8ae485e81c292b747..d7f8464bf3eed0e42a5fc7f14a5b243d + } diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 2d318964ef1f54940059b8d62bfc8f8ae87424e5..23af11c22713ac3e005fd89b4f3b3873bf74e751 100644 +index 5ea8f51accdda2387b640d2cff1d6a8baa673bee..3fa8ae3a9afd81bf757ee1e183684442444376f4 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -156,6 +156,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl diff --git a/patches/server/1001-Optional-per-player-mob-spawns.patch b/patches/server/1001-Optional-per-player-mob-spawns.patch index f9d00cb631..8905e1ab1c 100644 --- a/patches/server/1001-Optional-per-player-mob-spawns.patch +++ b/patches/server/1001-Optional-per-player-mob-spawns.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optional per player mob spawns diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index b849e0cf15f894aa87b1bb397d85b887b8fb816e..7bebf252887ecc7594b1ce21471fb6ba7aa2c051 100644 +index 1363dda031d1b541d76241812a957a12521cbc05..b24d5b0818abfc8b969ab715ca21959c235a9d70 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -283,8 +283,26 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -256,8 +256,26 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider return this.nearbyPlayers; } @@ -37,10 +37,10 @@ index b849e0cf15f894aa87b1bb397d85b887b8fb816e..7bebf252887ecc7594b1ce21471fb6ba // Paper end diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index cba80945fa0d8ca55b0d422925f8c94c51f9a50d..a5d465a81ba6ba7dea352005bf02ae2ae424ed14 100644 +index 014e7d3c3b9e8f6c2b456d63bcf885f55b01ded9..7bb3277883a326c436ef070eaf285343fe502a32 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -517,7 +517,19 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -438,7 +438,19 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon gameprofilerfiller.popPush("naturalSpawnCount"); this.level.timings.countNaturalMobs.startTiming(); // Paper - timings int k = this.distanceManager.getNaturalSpawnChunkCount(); diff --git a/patches/server/1002-Anti-Xray.patch b/patches/server/1002-Anti-Xray.patch index 56181f6189..249d9e10fd 100644 --- a/patches/server/1002-Anti-Xray.patch +++ b/patches/server/1002-Anti-Xray.patch @@ -1168,7 +1168,7 @@ index 9b1a6d8351fb473eec75a2fd08fb892b770e3586..0d0b07c9199be9ca0d5ac3feb1d44f14 } // Paper end - Send empty chunk diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 23af11c22713ac3e005fd89b4f3b3873bf74e751..9f2fad2f4b1e4e7eda645d53eb76ed04fc0b3451 100644 +index 3fa8ae3a9afd81bf757ee1e183684442444376f4..392032d749b8a9077b61f4e1c5e413de048c7067 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -171,6 +171,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @@ -1196,7 +1196,7 @@ index 23af11c22713ac3e005fd89b4f3b3873bf74e751..9f2fad2f4b1e4e7eda645d53eb76ed04 } // Paper start - Cancel hit for vanished players -@@ -619,6 +621,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -617,6 +619,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl // CraftBukkit end BlockState iblockdata1 = chunk.setBlockState(pos, state, (flags & 64) != 0, (flags & 1024) == 0); // CraftBukkit custom NO_PLACE flag @@ -1231,7 +1231,7 @@ index 2822a9b010e6d45f9562950a94f1942784db9784..97f8ef86a0e398b7e4aa3445d5e413ad } 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 c4f87ff9e0c9806a1d7abc4842caa5a4caa357bd..e5f301f867057ac986725a76c13f260ff40489c4 100644 +index 443e5e1b1c0e7c93f61c1905c78c29a17860989c..b2a06fc1192cd6050d6d7ea8620a4fa5a12182cc 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -91,7 +91,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p diff --git a/patches/server/1004-Add-Alternate-Current-redstone-implementation.patch b/patches/server/1004-Add-Alternate-Current-redstone-implementation.patch index a5295f6b05..29b12d1dfb 100644 --- a/patches/server/1004-Add-Alternate-Current-redstone-implementation.patch +++ b/patches/server/1004-Add-Alternate-Current-redstone-implementation.patch @@ -2035,10 +2035,10 @@ index a463cdd3b9dbda64d52c86223e1f2e1164deac80..798016774df02c3f7ebf909c9cc125f8 EntityCallbacks() {} diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 9f2fad2f4b1e4e7eda645d53eb76ed04fc0b3451..96ad3868a93964247790134fa5f4b18e5c07aea8 100644 +index 392032d749b8a9077b61f4e1c5e413de048c7067..55e841269585feb6a083b48ffeecea30cc65f6d6 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -1570,4 +1570,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1568,4 +1568,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl } } // Paper end - notify observers even if grow failed diff --git a/patches/server/1005-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch b/patches/server/1005-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch index ab570def0a..3e51783f35 100644 --- a/patches/server/1005-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch +++ b/patches/server/1005-Improve-cancelling-PreCreatureSpawnEvent-with-per-pl.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Improve cancelling PreCreatureSpawnEvent with per player mob diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 7bebf252887ecc7594b1ce21471fb6ba7aa2c051..df00ea382915480be1279a5347872cf7a1417341 100644 +index b24d5b0818abfc8b969ab715ca21959c235a9d70..c96740a82eac9101f74edeb44edf4b64d1d633e0 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -300,8 +300,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -273,8 +273,25 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider ++((ServerPlayer)backingSet[i]).mobCounts[index]; } } @@ -37,10 +37,10 @@ index 7bebf252887ecc7594b1ce21471fb6ba7aa2c051..df00ea382915480be1279a5347872cf7 } // Paper end diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index a5d465a81ba6ba7dea352005bf02ae2ae424ed14..681fdab250d924a29ca160acffbcbf7f8a3ca78a 100644 +index 7bb3277883a326c436ef070eaf285343fe502a32..82e7f7c3c2f51bc135585f43bc5167bcde2f8a98 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -523,7 +523,17 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -444,7 +444,17 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled // re-set mob counts for (ServerPlayer player : this.level.players) { diff --git a/patches/server/1008-Optimize-Hoppers.patch b/patches/server/1008-Optimize-Hoppers.patch index 28b2e6b92d..aa1c0074e6 100644 --- a/patches/server/1008-Optimize-Hoppers.patch +++ b/patches/server/1008-Optimize-Hoppers.patch @@ -50,7 +50,7 @@ index 0000000000000000000000000000000000000000..5c42823726e70ce6c9d0121d07431548 + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 3aecd55b9a069710c5d383b2f9113b147ad1ab57..2a65c39feeb03a165ccc4afd974fb6935b2ff546 100644 +index 3c230ae060998bfb79d5812fef21a80a9df8c8ff..64d0e04b6f9c52d90d0bc185b16a8a4768af4ac1 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1659,6 +1659,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa diff --git a/patches/server/1023-Improved-Watchdog-Support.patch b/patches/server/1023-Improved-Watchdog-Support.patch index 9c83e55b86..94bf0b6858 100644 --- a/patches/server/1023-Improved-Watchdog-Support.patch +++ b/patches/server/1023-Improved-Watchdog-Support.patch @@ -71,7 +71,7 @@ index 589a8bf75be6ccc59f1e5dd5d8d9afed41c4772d..b24265573fdef5d9a964bcd76146f345 cause = cause.getCause(); } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 2a65c39feeb03a165ccc4afd974fb6935b2ff546..b9b8a46f1de9867cc2161ac71c2993ab422cdfbf 100644 +index 64d0e04b6f9c52d90d0bc185b16a8a4768af4ac1..68f60e77e0bfd42b6419491c1d59b6432974216b 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -307,7 +307,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -212,7 +212,7 @@ index 2a65c39feeb03a165ccc4afd974fb6935b2ff546..b9b8a46f1de9867cc2161ac71c2993ab return new TickTask(this.tickCount, runnable); } -@@ -2209,7 +2261,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa +@@ -2204,7 +2256,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa this.worldData.setDataConfiguration(worlddataconfiguration); this.resources.managers.updateRegistryTags(); this.potionBrewing = this.potionBrewing.reload(this.worldData.enabledFeatures()); // Paper - Custom Potion Mixes @@ -287,10 +287,10 @@ index 2510589400b3012b827efcab477c6483d9d55901..43487a9ee202c5b0e5a416519939111f } } diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 96ad3868a93964247790134fa5f4b18e5c07aea8..f1e085c712e4f128c813c3cf5340e6d2e4e55ccc 100644 +index 55e841269585feb6a083b48ffeecea30cc65f6d6..fee155c81df385faa474e3aec777a30375ecb07d 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -984,6 +984,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -982,6 +982,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl try { tickConsumer.accept(entity); } catch (Throwable throwable) { @@ -299,10 +299,10 @@ index 96ad3868a93964247790134fa5f4b18e5c07aea8..f1e085c712e4f128c813c3cf5340e6d2 final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ()); MinecraftServer.LOGGER.error(msg, throwable); 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 e5f301f867057ac986725a76c13f260ff40489c4..589c1f13006660c28378f447ee373651257169d9 100644 +index b2a06fc1192cd6050d6d7ea8620a4fa5a12182cc..d388fbcbff63928f0e9140c02400a63ba8f19d9c 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -1131,6 +1131,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -1006,6 +1006,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p gameprofilerfiller.pop(); } catch (Throwable throwable) { |