9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-19 14:59:25 +00:00
Files
DivineMC/divinemc-server/minecraft-patches/features/0013-Chunk-System-optimization.patch

986 lines
58 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 00:33:03 +0300
Subject: [PATCH] Chunk System optimization
diff --git a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
index 1b8193587814225c2ef2c5d9e667436eb50ff6c5..b588449cfe766c14a0cf4ea9640b04a51bbcf433 100644
--- a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
+++ b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
@@ -59,12 +59,15 @@ public final class NearbyPlayers {
public static final int GENERAL_REALLY_SMALL_AREA_VIEW_DISTANCE_BLOCKS = (GENERAL_REALLY_SMALL_VIEW_DISTANCE << 4);
private final ServerLevel world;
- private final Reference2ReferenceOpenHashMap<ServerPlayer, TrackedPlayer[]> players = new Reference2ReferenceOpenHashMap<>();
- private final Long2ReferenceOpenHashMap<TrackedChunk> byChunk = new Long2ReferenceOpenHashMap<>();
- private final Long2ReferenceOpenHashMap<ReferenceList<ServerPlayer>>[] directByChunk = new Long2ReferenceOpenHashMap[TOTAL_MAP_TYPES];
+ // DivineMC start - Chunk System optimization
+ private final Object callbackLock = new Object();
+ private final it.unimi.dsi.fastutil.objects.Reference2ReferenceMap<ServerPlayer, TrackedPlayer[]> players = it.unimi.dsi.fastutil.objects.Reference2ReferenceMaps.synchronize(new Reference2ReferenceOpenHashMap<>());
+ private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap<TrackedChunk> byChunk = it.unimi.dsi.fastutil.longs.Long2ReferenceMaps.synchronize(new Long2ReferenceOpenHashMap<>());
+ private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap<ReferenceList<ServerPlayer>>[] directByChunk = new it.unimi.dsi.fastutil.longs.Long2ReferenceMap[TOTAL_MAP_TYPES];
+ // DivineMC end - Chunk System optimization
{
for (int i = 0; i < this.directByChunk.length; ++i) {
- this.directByChunk[i] = new Long2ReferenceOpenHashMap<>();
+ this.directByChunk[i] = it.unimi.dsi.fastutil.longs.Long2ReferenceMaps.synchronize(new Long2ReferenceOpenHashMap<>()); // DivineMC - Chunk System optimization
}
}
@@ -188,7 +191,10 @@ public final class NearbyPlayers {
final ReferenceList<ServerPlayer> list = this.players[idx];
if (list == null) {
++this.nonEmptyLists;
- final ReferenceList<ServerPlayer> players = (this.players[idx] = new ReferenceList<>(EMPTY_PLAYERS_ARRAY));
+ // DivineMC start - Chunk System optimization
+ this.players[idx] = new ReferenceList<>(EMPTY_PLAYERS_ARRAY);
+ final ReferenceList<ServerPlayer> players = this.players[idx];
+ // DivineMC end - Chunk System optimization
this.nearbyPlayers.directByChunk[idx].put(this.chunkKey, players);
players.add(player);
return;
diff --git a/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/util/ZeroCollidingReferenceStateTable.java b/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/util/ZeroCollidingReferenceStateTable.java
index 866f38eb0f379ffbe2888023a7d1c290f521a231..08666b4aa1c7663861dc361f60e6f1cc46694521 100644
--- a/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/util/ZeroCollidingReferenceStateTable.java
+++ b/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/util/ZeroCollidingReferenceStateTable.java
@@ -21,13 +21,15 @@ import net.minecraft.world.level.block.state.properties.Property;
public final class ZeroCollidingReferenceStateTable<O, S> {
- private final Int2ObjectOpenHashMap<Indexer> propertyToIndexer;
+ private final it.unimi.dsi.fastutil.ints.Int2ObjectMap<Indexer> propertyToIndexer; // DivineMC - Chunk System optimization
private S[] lookup;
private final Collection<Property<?>> properties;
public ZeroCollidingReferenceStateTable(final Collection<Property<?>> properties) {
- this.propertyToIndexer = new Int2ObjectOpenHashMap<>(properties.size());
- this.properties = new ReferenceArrayList<>(properties);
+ // DivineMC start - Chunk System optimization
+ this.propertyToIndexer = it.unimi.dsi.fastutil.ints.Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>(properties.size()));
+ this.properties = it.unimi.dsi.fastutil.objects.ReferenceLists.synchronize(new ReferenceArrayList<>(properties));
+ // DivineMC end - Chunk System optimization
final List<Property<?>> sortedProperties = new ArrayList<>(properties);
@@ -77,11 +79,11 @@ public final class ZeroCollidingReferenceStateTable<O, S> {
return ret;
}
- public boolean isLoaded() {
+ public synchronized boolean isLoaded() { // DivineMC - Chunk System optimization
return this.lookup != null;
}
- public void loadInTable(final Map<Map<Property<?>, Comparable<?>>, S> universe) {
+ public synchronized void loadInTable(final Map<Map<Property<?>, Comparable<?>>, S> universe) { // DivineMC - Chunk System optimization
if (this.lookup != null) {
throw new IllegalStateException();
}
@@ -117,7 +119,7 @@ public final class ZeroCollidingReferenceStateTable<O, S> {
return ((PropertyAccess<T>)property).moonrise$getById((int)modded);
}
- public <T extends Comparable<T>> S set(final long index, final Property<T> property, final T with) {
+ public synchronized <T extends Comparable<T>> S set(final long index, final Property<T> property, final T with) { // DivineMC - Chunk System optimization
final int newValueId = ((PropertyAccess<T>)property).moonrise$getIdFor(with);
if (newValueId < 0) {
return null;
@@ -139,7 +141,7 @@ public final class ZeroCollidingReferenceStateTable<O, S> {
return this.lookup[(int)newIndex];
}
- public <T extends Comparable<T>> S trySet(final long index, final Property<T> property, final T with, final S dfl) {
+ public synchronized <T extends Comparable<T>> S trySet(final long index, final Property<T> property, final T with, final S dfl) { // DivineMC - Chunk System optimization
final Indexer indexer = this.propertyToIndexer.get(((PropertyAccess<T>)property).moonrise$getId());
if (indexer == null) {
return dfl;
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
index 8ef5a1aaac9c27873ce746eb281f77bb318a3c69..76b8d42ae530b59cdaba0583365a557da6b90ede 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -301,7 +301,7 @@ public final class RegionizedPlayerChunkLoader {
return false;
}
- public void tick() {
+ public synchronized void tick() { // DivineMC - Chunk System optimization - synchronized
TickThread.ensureTickThread("Cannot tick player chunk loader async");
long currTime = System.nanoTime();
for (final ServerPlayer player : new java.util.ArrayList<>(this.world.players())) {
@@ -312,6 +312,7 @@ public final class RegionizedPlayerChunkLoader {
}
loader.update(); // can't invoke plugin logic
loader.updateQueues(currTime);
+ player.connection.resumeFlushing(); // DivineMC - Chunk System optimization
}
}
@@ -362,7 +363,7 @@ public final class RegionizedPlayerChunkLoader {
GENERATED_TICKET_LEVEL,
TICK_TICKET_LEVEL
};
- private final Long2ByteOpenHashMap chunkTicketStage = new Long2ByteOpenHashMap();
+ private final it.unimi.dsi.fastutil.longs.Long2ByteMap chunkTicketStage = it.unimi.dsi.fastutil.longs.Long2ByteMaps.synchronize(new Long2ByteOpenHashMap()); // DivineMC - Chunk System optimization
{
this.chunkTicketStage.defaultReturnValue(CHUNK_TICKET_STAGE_NONE);
}
@@ -384,10 +385,19 @@ public final class RegionizedPlayerChunkLoader {
final int centerX = PlayerChunkLoaderData.this.lastChunkX;
final int centerZ = PlayerChunkLoaderData.this.lastChunkZ;
- return Integer.compare(
- Math.abs(c1x - centerX) + Math.abs(c1z - centerZ),
- Math.abs(c2x - centerX) + Math.abs(c2z - centerZ)
- );
+ // DivineMC start - Chunk Loading Priority Optimization
+ if (org.bxteam.divinemc.DivineConfig.chunkTaskPriority == org.bxteam.divinemc.server.chunk.ChunkTaskPriority.EUCLIDEAN_CIRCLE_PATTERN) {
+ return Integer.compare(
+ (c1x - centerX) * (c1x - centerX) + (c1z - centerZ) * (c1z - centerZ),
+ (c2x - centerX) * (c2x - centerX) + (c2z - centerZ) * (c2z - centerZ)
+ );
+ } else {
+ return Integer.compare(
+ Math.abs(c1x - centerX) + Math.abs(c1z - centerZ),
+ Math.abs(c2x - centerX) + Math.abs(c2z - centerZ)
+ );
+ }
+ // DivineMC end - Chunk Loading Priority Optimization
};
private final LongHeapPriorityQueue sendQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST);
private final LongHeapPriorityQueue tickingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST);
@@ -490,7 +500,7 @@ public final class RegionizedPlayerChunkLoader {
}
@Override
- protected void removeCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) {
+ protected synchronized void removeCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { // DivineMC - Chunk System optimization - synchronized
final long chunk = CoordinateUtils.getChunkKey(chunkX, chunkZ);
// note: by the time this is called, the tick cleanup should have ran - so, if the chunk is at
// the tick stage it was deemed in range for loading. Thus, we need to move it to generated
@@ -624,7 +634,7 @@ public final class RegionizedPlayerChunkLoader {
return Math.max(Math.abs(dx), Math.abs(dz)) <= this.lastTickDistance;
}
- private boolean areNeighboursGenerated(final int chunkX, final int chunkZ, final int radius) {
+ private synchronized boolean areNeighboursGenerated(final int chunkX, final int chunkZ, final int radius) { // DivineMC - Chunk System optimization - synchronized
for (int dz = -radius; dz <= radius; ++dz) {
for (int dx = -radius; dx <= radius; ++dx) {
if ((dx | dz) == 0) {
@@ -643,19 +653,11 @@ public final class RegionizedPlayerChunkLoader {
return true;
}
- void updateQueues(final long time) {
+ synchronized void updateQueues(final long time) { // DivineMC - Chunk System optimization - synchronized
TickThread.ensureTickThread(this.player, "Cannot tick player chunk loader async");
if (this.removed) {
throw new IllegalStateException("Ticking removed player chunk loader");
}
- // update rate limits
- final double loadRate = this.getMaxChunkLoadRate();
- final double genRate = this.getMaxChunkGenRate();
- final double sendRate = this.getMaxChunkSendRate();
-
- this.chunkLoadTicketLimiter.tickAllocation(time, loadRate, loadRate);
- this.chunkGenerateTicketLimiter.tickAllocation(time, genRate, genRate);
- this.chunkSendLimiter.tickAllocation(time, sendRate, sendRate);
// try to progress chunk loads
while (!this.loadingQueue.isEmpty()) {
@@ -682,8 +684,7 @@ public final class RegionizedPlayerChunkLoader {
}
// try to push more chunk loads
- final long maxLoads = Math.max(0L, Math.min(MAX_RATE, Math.min(this.loadQueue.size(), this.getMaxChunkLoads())));
- final int maxLoadsThisTick = (int)this.chunkLoadTicketLimiter.takeAllocation(time, loadRate, maxLoads);
+ final int maxLoadsThisTick = this.loadQueue.size(); // DivineMC - Chunk System optimization
if (maxLoadsThisTick > 0) {
final LongArrayList chunks = new LongArrayList(maxLoadsThisTick);
for (int i = 0; i < maxLoadsThisTick; ++i) {
@@ -758,9 +759,7 @@ public final class RegionizedPlayerChunkLoader {
}
// try to push more chunk generations
- final long maxGens = Math.max(0L, Math.min(MAX_RATE, Math.min(this.genQueue.size(), this.getMaxChunkGenerates())));
- // preview the allocations, as we may not actually utilise all of them
- final long maxGensThisTick = this.chunkGenerateTicketLimiter.previewAllocation(time, genRate, maxGens);
+ final long maxGensThisTick = this.genQueue.size(); // DivineMC - Chunk System optimization
long ratedGensThisTick = 0L;
while (!this.genQueue.isEmpty()) {
final long chunkKey = this.genQueue.firstLong();
@@ -790,8 +789,6 @@ public final class RegionizedPlayerChunkLoader {
);
this.generatingQueue.enqueue(chunkKey);
}
- // take the allocations we actually used
- this.chunkGenerateTicketLimiter.takeAllocation(time, genRate, ratedGensThisTick);
// try to pull ticking chunks
while (!this.tickingQueue.isEmpty()) {
@@ -821,10 +818,10 @@ public final class RegionizedPlayerChunkLoader {
}
// try to pull sending chunks
- final long maxSends = Math.max(0L, Math.min(MAX_RATE, Integer.MAX_VALUE)); // note: no logic to track concurrent sends
- final int maxSendsThisTick = Math.min((int)this.chunkSendLimiter.takeAllocation(time, sendRate, maxSends), this.sendQueue.size());
+ final int maxSendsThisTick = this.sendQueue.size(); // DivineMC - Chunk System optimization
// we do not return sends that we took from the allocation back because we want to limit the max send rate, not target it
for (int i = 0; i < maxSendsThisTick; ++i) {
+ if (this.sendQueue.isEmpty()) break; // DivineMC - Chunk System optimization
final long pendingSend = this.sendQueue.firstLong();
final int pendingSendX = CoordinateUtils.getChunkX(pendingSend);
final int pendingSendZ = CoordinateUtils.getChunkZ(pendingSend);
@@ -889,9 +886,6 @@ public final class RegionizedPlayerChunkLoader {
// reset limiters, they will start at a zero allocation
final long time = System.nanoTime();
- this.chunkLoadTicketLimiter.reset(time);
- this.chunkGenerateTicketLimiter.reset(time);
- this.chunkSendLimiter.reset(time);
// now we can update
this.update();
@@ -910,10 +904,10 @@ public final class RegionizedPlayerChunkLoader {
);
}
- void update() {
+ synchronized void update() { // DivineMC - Chunk System optimization - synchronized
TickThread.ensureTickThread(this.player, "Cannot update player asynchronously");
if (this.removed) {
- throw new IllegalStateException("Updating removed player chunk loader");
+ return; // DivineMC - Chunk System optimization
}
final ViewDistances playerDistances = ((ChunkSystemServerPlayer)this.player).moonrise$getViewDistanceHolder().getViewDistances();
final ViewDistances worldDistances = ((ChunkSystemServerLevel)this.world).moonrise$getViewDistanceHolder().getViewDistances();
@@ -1062,7 +1056,7 @@ public final class RegionizedPlayerChunkLoader {
this.flushDelayedTicketOps();
}
- void remove() {
+ synchronized void remove() { // DivineMC - Chunk System optimization - synchronized
TickThread.ensureTickThread(this.player, "Cannot add player asynchronously");
if (this.removed) {
throw new IllegalStateException("Removing removed player chunk loader");
@@ -1090,7 +1084,7 @@ public final class RegionizedPlayerChunkLoader {
}
public LongOpenHashSet getSentChunksRaw() {
- return this.sentChunks;
+ return new LongOpenHashSet(this.sentChunks); // DivineMC - Chunk System optimization
}
}
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
index 0c99bffa769d53562a10d23c4a9b37dc59c7f478..f4fcc3b2676b17ebc276dcb177285f18a0cdfe99 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
@@ -71,36 +71,49 @@ public final class ChunkHolderManager {
private static final long PROBE_MARKER = Long.MIN_VALUE + 1;
public final ReentrantAreaLock ticketLockArea;
- private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket<?>>> tickets = new ConcurrentLong2ReferenceChainedHashTable<>();
- private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = new ConcurrentLong2ReferenceChainedHashTable<>();
+ // DivineMC start - Chunk System optimization
+ private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket<?>>> tickets = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F);
+ private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F);
+ // DivineMC end - Chunk System optimization
final ChunkUnloadQueue unloadQueue;
- private final ConcurrentLong2ReferenceChainedHashTable<NewChunkHolder> chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f);
+ private final ConcurrentLong2ReferenceChainedHashTable<NewChunkHolder> chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F); // DivineMC - Chunk System optimization
private final ServerLevel world;
private final ChunkTaskScheduler taskScheduler;
private long currentTick;
- private final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = new ArrayDeque<>();
- private final ObjectRBTreeSet<NewChunkHolder> autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> {
- if (c1 == c2) {
- return 0;
- }
+ // DivineMC start - Chunk System optimization
+ public static class LevelHolderData {
+ private final java.util.concurrent.ConcurrentLinkedDeque<NewChunkHolder> pendingFullLoadUpdate = new java.util.concurrent.ConcurrentLinkedDeque<>();
+ private final ObjectRBTreeSet<NewChunkHolder> autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> {
+ if (c1 == c2) {
+ return 0;
+ }
- final int saveTickCompare = Long.compare(c1.lastAutoSave, c2.lastAutoSave);
+ final int saveTickCompare = Long.compare(c1.lastAutoSave, c2.lastAutoSave);
- if (saveTickCompare != 0) {
- return saveTickCompare;
- }
+ if (saveTickCompare != 0) {
+ return saveTickCompare;
+ }
- final long coord1 = CoordinateUtils.getChunkKey(c1.chunkX, c1.chunkZ);
- final long coord2 = CoordinateUtils.getChunkKey(c2.chunkX, c2.chunkZ);
+ final long coord1 = CoordinateUtils.getChunkKey(c1.chunkX, c1.chunkZ);
+ final long coord2 = CoordinateUtils.getChunkKey(c2.chunkX, c2.chunkZ);
- if (coord1 == coord2) {
- throw new IllegalStateException("Duplicate chunkholder in auto save queue");
- }
+ if (coord1 == coord2) {
+ throw new IllegalStateException("Duplicate chunkholder in auto save queue");
+ }
- return Long.compare(coord1, coord2);
- });
+ return Long.compare(coord1, coord2);
+ });
+ }
+
+ public LevelHolderData getData() {
+ if (this.world == null) {
+ throw new RuntimeException("World was null!");
+ }
+ return world.chunkHolderData;
+ }
+ // DivineMC end - Chunk System optimization
public ChunkHolderManager(final ServerLevel world, final ChunkTaskScheduler taskScheduler) {
this.world = world;
@@ -222,26 +235,29 @@ public final class ChunkHolderManager {
this.taskScheduler.setShutdown(true);
}
- void ensureInAutosave(final NewChunkHolder holder) {
- if (!this.autoSaveQueue.contains(holder)) {
+ // DivineMC start - Chunk System optimization
+ synchronized void ensureInAutosave(final NewChunkHolder holder) {
+ final LevelHolderData data = getData();
+ if (!data.autoSaveQueue.contains(holder)) {
holder.lastAutoSave = this.currentTick;
- this.autoSaveQueue.add(holder);
+ data.autoSaveQueue.add(holder);
}
}
- public void autoSave() {
+ public synchronized void autoSave() {
+ final LevelHolderData data = getData();
final List<NewChunkHolder> reschedule = new ArrayList<>();
final long currentTick = this.currentTick;
final long maxSaveTime = currentTick - Math.max(1L, PlatformHooks.get().configAutoSaveInterval(this.world));
final int maxToSave = PlatformHooks.get().configMaxAutoSavePerTick(this.world);
- for (int autoSaved = 0; autoSaved < maxToSave && !this.autoSaveQueue.isEmpty();) {
- final NewChunkHolder holder = this.autoSaveQueue.first();
+ for (int autoSaved = 0; autoSaved < maxToSave && !data.autoSaveQueue.isEmpty();) {
+ final NewChunkHolder holder = data.autoSaveQueue.first();
if (holder.lastAutoSave > maxSaveTime) {
break;
}
- this.autoSaveQueue.remove(holder);
+ data.autoSaveQueue.remove(holder);
holder.lastAutoSave = currentTick;
if (holder.save(false) != null) {
@@ -255,10 +271,11 @@ public final class ChunkHolderManager {
for (final NewChunkHolder holder : reschedule) {
if (holder.getChunkStatus().isOrAfter(FullChunkStatus.FULL)) {
- this.autoSaveQueue.add(holder);
+ data.autoSaveQueue.add(holder);
}
}
}
+ // DivineMC end - Chunk System optimization
public void saveAllChunks(final boolean flush, final boolean shutdown, final boolean logProgress) {
final List<NewChunkHolder> holders = this.getChunkHolders();
@@ -317,13 +334,9 @@ public final class ChunkHolderManager {
}
if (logProgress) {
final long currTime = System.nanoTime();
- if ((currTime - lastLog) > TimeUnit.SECONDS.toNanos(10L)) {
+ if ((currTime - lastLog) > TimeUnit.SECONDS.toNanos(5L)) { // DivineMC - Log a bit more frequently
lastLog = currTime;
- LOGGER.info(
- "Saved " + savedChunk + " block chunks, " + savedEntity + " entity chunks, " + savedPoi
- + " poi chunks in world '" + WorldUtil.getWorldName(this.world) + "', progress: "
- + format.format((double)(i+1)/(double)len * 100.0)
- );
+ LOGGER.info("Saved {} block chunks, {} entity chunks, {} poi chunks in world '{}', progress: {}", savedChunk, savedEntity, savedPoi, ca.spottedleaf.moonrise.common.util.WorldUtil.getWorldName(this.world), format.format((double) (i + 1) / (double) len * 100.0)); // DivineMC - Beautify log
}
}
}
@@ -425,8 +438,8 @@ public final class ChunkHolderManager {
final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> ret = new Long2ObjectOpenHashMap<>();
final Long2ObjectOpenHashMap<LongArrayList> sections = new Long2ObjectOpenHashMap<>();
final int sectionShift = this.taskScheduler.getChunkSystemLockShift();
- for (final PrimitiveIterator.OfLong iterator = this.tickets.keyIterator(); iterator.hasNext();) {
- final long coord = iterator.nextLong();
+ for (final Iterator<Long> iterator = this.tickets.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
+ final long coord = iterator.next(); // DivineMC - Chunk System optimization
sections.computeIfAbsent(
CoordinateUtils.getChunkKey(
CoordinateUtils.getChunkX(coord) >> sectionShift,
@@ -523,7 +536,7 @@ public final class ChunkHolderManager {
chunkZ >> sectionShift
);
- this.sectionToChunkToExpireCount.computeIfAbsent(sectionKey, (final long keyInMap) -> {
+ this.sectionToChunkToExpireCount.computeIfAbsent(sectionKey, (keyInMap) -> { // DivineMC - Chunk System optimization
return new Long2IntOpenHashMap();
}).addTo(chunkKey, 1);
}
@@ -567,7 +580,7 @@ public final class ChunkHolderManager {
final ReentrantAreaLock.Node ticketLock = lock ? this.ticketLockArea.lock(chunkX, chunkZ) : null;
try {
- final SortedArraySet<Ticket<?>> ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (final long keyInMap) -> {
+ final SortedArraySet<Ticket<?>> ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (keyInMap) -> { // DivineMC - Chunk System optimization
return SortedArraySet.create(4);
});
@@ -697,8 +710,8 @@ public final class ChunkHolderManager {
final Long2ObjectOpenHashMap<LongArrayList> sections = new Long2ObjectOpenHashMap<>();
final int sectionShift = this.taskScheduler.getChunkSystemLockShift();
- for (final PrimitiveIterator.OfLong iterator = this.tickets.keyIterator(); iterator.hasNext();) {
- final long coord = iterator.nextLong();
+ for (final Iterator<Long> iterator = this.tickets.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
+ final long coord = iterator.next(); // DivineMC - Chunk System optimization
sections.computeIfAbsent(
CoordinateUtils.getChunkKey(
CoordinateUtils.getChunkX(coord) >> sectionShift,
@@ -746,8 +759,8 @@ public final class ChunkHolderManager {
return removeDelay <= 0L;
};
- for (final PrimitiveIterator.OfLong iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) {
- final long sectionKey = iterator.nextLong();
+ for (final Iterator<Long> iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
+ final long sectionKey = iterator.next(); // DivineMC - Chunk System optimization
if (!this.sectionToChunkToExpireCount.containsKey(sectionKey)) {
// removed concurrently
@@ -1033,7 +1046,7 @@ public final class ChunkHolderManager {
}
if (!TickThread.isTickThreadFor(world)) { // DivineMC - parallel world ticking
this.taskScheduler.scheduleChunkTask(() -> {
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = ChunkHolderManager.this.pendingFullLoadUpdate;
+ final java.util.Deque<NewChunkHolder> pendingFullLoadUpdate = ChunkHolderManager.this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
pendingFullLoadUpdate.add(changedFullStatus.get(i));
}
@@ -1041,16 +1054,16 @@ public final class ChunkHolderManager {
ChunkHolderManager.this.processPendingFullUpdate();
}, Priority.HIGHEST);
} else {
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
+ final java.util.Deque<NewChunkHolder> pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
pendingFullLoadUpdate.add(changedFullStatus.get(i));
}
}
}
- private void removeChunkHolder(final NewChunkHolder holder) {
+ private synchronized void removeChunkHolder(final NewChunkHolder holder) { // DivineMC - Chunk System optimization
holder.onUnload();
- this.autoSaveQueue.remove(holder);
+ this.getData().autoSaveQueue.remove(holder); // DivineMC - Chunk System optimization
PlatformHooks.get().onChunkHolderDelete(this.world, holder.vanillaChunkHolder);
this.chunkHolders.remove(CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ));
}
@@ -1208,6 +1221,27 @@ public final class ChunkHolderManager {
}
}
+ // DivineMC start - Chunk System optimization
+ public final java.util.Set<Long> blockTickingChunkHolders = java.util.Collections.synchronizedSet(new org.agrona.collections.ObjectHashSet<>(10, 0.88f, true));
+ public final java.util.Set<Long> entityTickingChunkHolders = java.util.Collections.synchronizedSet(new org.agrona.collections.ObjectHashSet<>(10, 0.88f, true));
+
+ public void markBlockTicking(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.blockTickingChunkHolders.add(newChunkHolder.getCachedLongPos());
+ }
+
+ public void markNonBlockTickingIfPossible(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.blockTickingChunkHolders.remove(newChunkHolder.getCachedLongPos());
+ }
+
+ public void markEntityTicking(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.entityTickingChunkHolders.add(newChunkHolder.getCachedLongPos());
+ }
+
+ public void markNonEntityTickingIfPossible(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.entityTickingChunkHolders.remove(newChunkHolder.getCachedLongPos());
+ }
+ // DivineMC end - Chunk System optimization
+
public enum TicketOperationType {
ADD, REMOVE, ADD_IF_REMOVED, ADD_AND_REMOVE
}
@@ -1381,7 +1415,7 @@ public final class ChunkHolderManager {
// only call on tick thread
private boolean processPendingFullUpdate() {
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
+ final java.util.Deque<NewChunkHolder> pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization
boolean ret = false;
@@ -1417,8 +1451,7 @@ public final class ChunkHolderManager {
final JsonArray allTicketsJson = new JsonArray();
ret.add("tickets", allTicketsJson);
- for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket<?>>>> iterator = this.tickets.entryIterator();
- iterator.hasNext();) {
+ for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket<?>>>> iterator = this.tickets.entryIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
final ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket<?>>> coordinateTickets = iterator.next();
final long coordinate = coordinateTickets.getKey();
final SortedArraySet<Ticket<?>> tickets = coordinateTickets.getValue();
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
index e4a5fa25ed368fc4662c30934da2963ef446d782..6da0ea5cd83a00578223e0a19f952c917bcbcdae 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
@@ -644,11 +644,19 @@ public final class NewChunkHolder {
}
public final ChunkHolder vanillaChunkHolder;
+ // DivineMC start - Chunk System optimization
+ private final long cachedLongPos;
+
+ public long getCachedLongPos() {
+ return cachedLongPos;
+ }
+ // DivineMC end - Chunk System optimization
public NewChunkHolder(final ServerLevel world, final int chunkX, final int chunkZ, final ChunkTaskScheduler scheduler) {
this.world = world;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
+ this.cachedLongPos = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(this.chunkX, this.chunkZ); // DivineMC - Chunk System optimization
this.scheduler = scheduler;
this.vanillaChunkHolder = new ChunkHolder(
new ChunkPos(chunkX, chunkZ), ChunkHolderManager.MAX_TICKET_LEVEL, world,
@@ -790,9 +798,11 @@ public final class NewChunkHolder {
// note: these are completed with null to indicate that no write occurred
// they are also completed with null to indicate a null write occurred
- private UnloadTask chunkDataUnload;
- private UnloadTask entityDataUnload;
- private UnloadTask poiDataUnload;
+ // DivineMC start - Chunk System optimization
+ private volatile UnloadTask chunkDataUnload;
+ private volatile UnloadTask entityDataUnload;
+ private volatile UnloadTask poiDataUnload;
+ // DivineMC end - Chunk System optimization
public static final record UnloadTask(CallbackCompletable<CompoundTag> completable, PrioritisedExecutor.PrioritisedTask task,
LazyRunnable toRun) {}
@@ -1190,6 +1200,7 @@ public final class NewChunkHolder {
for (int dz = -NEIGHBOUR_RADIUS; dz <= NEIGHBOUR_RADIUS; ++dz) {
for (int dx = -NEIGHBOUR_RADIUS; dx <= NEIGHBOUR_RADIUS; ++dx) {
final NewChunkHolder holder = (dx | dz) == 0 ? this : this.scheduler.chunkHolderManager.getChunkHolder(dx + this.chunkX, dz + this.chunkZ);
+ if (holder == null) continue; // DivineMC - Chunk System optimization
if (loaded) {
if (holder.setNeighbourFullLoaded(-dx, -dz)) {
changedFullStatus.add(holder);
@@ -1214,6 +1225,19 @@ public final class NewChunkHolder {
private void updateCurrentState(final FullChunkStatus to) {
this.currentFullChunkStatus = to;
+ // DivineMC start - Chunk System optimization
+ if (to.isOrAfter(FullChunkStatus.BLOCK_TICKING)) {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markBlockTicking(this);
+ } else {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markNonBlockTickingIfPossible(this);
+ }
+
+ if (to.isOrAfter(FullChunkStatus.ENTITY_TICKING)) {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markEntityTicking(this);
+ } else {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markNonEntityTickingIfPossible(this);
+ }
+ // DivineMC end - Chunk System optimization
}
// only to be called on the main thread, no locks need to be held
@@ -1348,11 +1372,11 @@ public final class NewChunkHolder {
return this.requestedGenStatus;
}
- private final Reference2ObjectOpenHashMap<ChunkStatus, List<Consumer<ChunkAccess>>> statusWaiters = new Reference2ObjectOpenHashMap<>();
+ private final Map<ChunkStatus, List<Consumer<ChunkAccess>>> statusWaiters = new java.util.concurrent.ConcurrentHashMap<>(); // DivineMC - Chunk System optimization
void addStatusConsumer(final ChunkStatus status, final Consumer<ChunkAccess> consumer) {
this.statusWaiters.computeIfAbsent(status, (final ChunkStatus keyInMap) -> {
- return new ArrayList<>(4);
+ return new java.util.concurrent.CopyOnWriteArrayList<>(); // DivineMC - Chunk System optimization
}).add(consumer);
}
@@ -1394,11 +1418,11 @@ public final class NewChunkHolder {
}, Priority.HIGHEST);
}
- private final Reference2ObjectOpenHashMap<FullChunkStatus, List<Consumer<LevelChunk>>> fullStatusWaiters = new Reference2ObjectOpenHashMap<>();
+ private final Map<FullChunkStatus, List<Consumer<LevelChunk>>> fullStatusWaiters = new java.util.concurrent.ConcurrentHashMap<>();
void addFullStatusConsumer(final FullChunkStatus status, final Consumer<LevelChunk> consumer) {
this.fullStatusWaiters.computeIfAbsent(status, (final FullChunkStatus keyInMap) -> {
- return new ArrayList<>(4);
+ return new java.util.concurrent.CopyOnWriteArrayList<>(); // DivineMC - Chunk System optimization
}).add(consumer);
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
index e97e7d276faf055c89207385d3820debffb06463..4aeb75a2cdcfb4206bab3eee5ad674dd9890e720 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
@@ -2,6 +2,6 @@ package ca.spottedleaf.moonrise.patches.chunk_tick_iteration;
public final class ChunkTickConstants {
- public static final int PLAYER_SPAWN_TRACK_RANGE = 8;
+ public static final int PLAYER_SPAWN_TRACK_RANGE = (int) Math.round(org.bxteam.divinemc.DivineConfig.playerNearChunkDetectionRange / 16.0); // DivineMC - Chunk System optimization
}
diff --git a/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java b/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java
index 4ca68a903e67606fc4ef0bfa9862a73797121c8b..f94f443f862611f039454d1dc8ff2a4ba5f081d3 100644
--- a/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java
+++ b/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java
@@ -325,7 +325,7 @@ public final class SWMRNibbleArray {
}
// operation type: updating
- public boolean updateVisible() {
+ public synchronized boolean updateVisible() { // DivineMC - Chunk System optimization
if (!this.isDirty()) {
return false;
}
diff --git a/net/minecraft/server/level/DistanceManager.java b/net/minecraft/server/level/DistanceManager.java
index 5eab6179ce3913cb4e4d424f910ba423faf21c85..4b1efd53e423bdfe90d5efd472823869fc87e73b 100644
--- a/net/minecraft/server/level/DistanceManager.java
+++ b/net/minecraft/server/level/DistanceManager.java
@@ -178,15 +178,13 @@ public abstract class DistanceManager implements ca.spottedleaf.moonrise.patches
public boolean inEntityTickingRange(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().getChunkHolder(chunkPos);
- return chunkHolder != null && chunkHolder.isEntityTickingReady();
+ return this.moonrise$getChunkHolderManager().entityTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
public boolean inBlockTickingRange(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().getChunkHolder(chunkPos);
- return chunkHolder != null && chunkHolder.isTickingReady();
+ return this.moonrise$getChunkHolderManager().blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
index ab30af9cd58ff7310e05be87b08f42bacf69e11e..ae0e36d198ad8243920c8e8a55c0be4945542763 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -439,8 +439,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
public boolean isPositionTicking(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder newChunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);
- return newChunkHolder != null && newChunkHolder.isTickingReady();
+ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 973198ae0a73d6747e73548bdcbc1de46b6fb107..1581bf8ff425c6e0df28d107300d7266e9f87ed5 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -181,6 +181,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
public final ServerChunkCache chunkSource;
private final MinecraftServer server;
public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type
+ public final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.LevelHolderData chunkHolderData; // DivineMC - Chunk System optimization
private int lastSpawnChunkRadius;
final EntityTickList entityTickList = new EntityTickList(this); // DivineMC - parallel world ticking
// Paper - rewrite chunk system
@@ -689,6 +690,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper start - rewrite chunk system
this.moonrise$setEntityLookup(new ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup((ServerLevel)(Object)this, ((ServerLevel)(Object)this).new EntityCallbacks()));
this.chunkTaskScheduler = new ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler((ServerLevel)(Object)this);
+ this.chunkHolderData = new ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.LevelHolderData(); // DivineMC - Chunk System optimization
this.entityDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController(
new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController.EntityRegionFileStorage(
new RegionStorageInfo(levelStorageAccess.getLevelId(), dimension, "entities"),
@@ -832,8 +834,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override
public boolean shouldTickBlocksAt(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);
- return holder != null && holder.isTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
@@ -2525,30 +2526,25 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private boolean isPositionTickingWithEntitiesLoaded(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);
- // isTicking implies the chunk is loaded, and the chunk is loaded now implies the entities are loaded
- return chunkHolder != null && chunkHolder.isTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
public boolean isPositionEntityTicking(BlockPos pos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos));
- return chunkHolder != null && chunkHolder.isEntityTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.entityTickingChunkHolders.contains(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos)); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
public boolean isNaturalSpawningAllowed(BlockPos pos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos));
- return chunkHolder != null && chunkHolder.isEntityTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.entityTickingChunkHolders.contains(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos)); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
public boolean isNaturalSpawningAllowed(ChunkPos chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkPos));
- return chunkHolder != null && chunkHolder.isEntityTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.entityTickingChunkHolders.contains(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkPos)); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
diff --git a/net/minecraft/world/level/LevelReader.java b/net/minecraft/world/level/LevelReader.java
index 26c8c1e5598daf3550aef05b12218c47bda6618b..94c824ab1457939c425e1f99929d3222ee2c18a0 100644
--- a/net/minecraft/world/level/LevelReader.java
+++ b/net/minecraft/world/level/LevelReader.java
@@ -70,10 +70,27 @@ public interface LevelReader extends ca.spottedleaf.moonrise.patches.chunk_syste
@Override
default Holder<Biome> getNoiseBiome(int x, int y, int z) {
- ChunkAccess chunk = this.getChunk(QuartPos.toSection(x), QuartPos.toSection(z), ChunkStatus.BIOMES, false);
+ ChunkAccess chunk = this.fasterChunkAccess(this, QuartPos.toSection(x), QuartPos.toSection(z), ChunkStatus.BIOMES, false); // DivineMC - Chunk System optimization
return chunk != null ? chunk.getNoiseBiome(x, y, z) : this.getUncachedNoiseBiome(x, y, z);
}
+ // DivineMC start - Chunk System optimization
+ private @Nullable ChunkAccess fasterChunkAccess(LevelReader instance, int x, int z, ChunkStatus chunkStatus, boolean create) {
+ if (!create && instance instanceof net.minecraft.server.level.ServerLevel world) {
+ final net.minecraft.server.level.ChunkHolder holder = (world.getChunkSource().chunkMap).getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
+ if (holder != null) {
+ final java.util.concurrent.CompletableFuture<net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.LevelChunk>> future = holder.getFullChunkFuture();
+ final net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.LevelChunk> either = future.getNow(null);
+ if (either != null) {
+ final net.minecraft.world.level.chunk.LevelChunk chunk = either.orElse(null);
+ if (chunk != null) return chunk;
+ }
+ }
+ }
+ return instance.getChunk(x, z, chunkStatus, create);
+ }
+ // DivineMC end - Chunk System optimization
+
Holder<Biome> getUncachedNoiseBiome(int x, int y, int z);
boolean isClientSide();
diff --git a/net/minecraft/world/level/chunk/ProtoChunk.java b/net/minecraft/world/level/chunk/ProtoChunk.java
index e66239e2da91bd3ddf358d239be796719c0da327..35e9d8cfe12252d3419626f1cefb64d30e20069e 100644
--- a/net/minecraft/world/level/chunk/ProtoChunk.java
+++ b/net/minecraft/world/level/chunk/ProtoChunk.java
@@ -41,7 +41,7 @@ public class ProtoChunk extends ChunkAccess {
@Nullable
private volatile LevelLightEngine lightEngine;
private volatile ChunkStatus status = ChunkStatus.EMPTY;
- private final List<CompoundTag> entities = Lists.newArrayList();
+ private final List<CompoundTag> entities = Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System optimization
@Nullable
private CarvingMask carvingMask;
@Nullable
diff --git a/net/minecraft/world/level/chunk/storage/IOWorker.java b/net/minecraft/world/level/chunk/storage/IOWorker.java
index 2199a9e2a0141c646d108f2687a27f1d165453c5..c28c2583b257f92207b822a1fdde8f5b7e480992 100644
--- a/net/minecraft/world/level/chunk/storage/IOWorker.java
+++ b/net/minecraft/world/level/chunk/storage/IOWorker.java
@@ -212,7 +212,38 @@ public class IOWorker implements ChunkScanAccess, AutoCloseable {
});
}
+ // DivineMC start - Chunk System optimization
+ private void checkHardLimit() {
+ if (this.pendingWrites.size() >= org.bxteam.divinemc.DivineConfig.chunkDataCacheLimit) {
+ LOGGER.warn("Chunk data cache size exceeded hard limit ({} >= {}), forcing writes to disk (you can increase chunkDataCacheLimit in c2me.toml)", this.pendingWrites.size(), org.bxteam.divinemc.DivineConfig.chunkDataCacheLimit);
+ while (this.pendingWrites.size() >= org.bxteam.divinemc.DivineConfig.chunkDataCacheSoftLimit * 0.75) {
+ writeResult0();
+ }
+ }
+ }
+
+ private void writeResult0() {
+ java.util.Iterator<java.util.Map.Entry<net.minecraft.world.level.ChunkPos, net.minecraft.world.level.chunk.storage.IOWorker.PendingStore>> iterator = this.pendingWrites.entrySet().iterator();
+ if (iterator.hasNext()) {
+ java.util.Map.Entry<ChunkPos, IOWorker.PendingStore> entry = iterator.next();
+ iterator.remove();
+ this.runStore(entry.getKey(), entry.getValue());
+ }
+ }
+ // DivineMC end - Chunk System optimization
+
private void storePendingChunk() {
+ // DivineMC start - Chunk System optimization
+ if (!this.pendingWrites.isEmpty()) {
+ checkHardLimit();
+ if (this.pendingWrites.size() >= org.bxteam.divinemc.DivineConfig.chunkDataCacheSoftLimit) {
+ int writeFrequency = Math.min(1, (this.pendingWrites.size() - (int) org.bxteam.divinemc.DivineConfig.chunkDataCacheSoftLimit) / 16);
+ for (int i = 0; i < writeFrequency; i++) {
+ writeResult0();
+ }
+ }
+ }
+ // DivineMC end - Chunk System optimization
Entry<ChunkPos, IOWorker.PendingStore> entry = this.pendingWrites.pollFirstEntry();
if (entry != null) {
this.runStore(entry.getKey(), entry.getValue());
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 6ebd1300c2561116b83cb2472ac7939ead36d576..16cd10ab8de69ca3d29c84cf93715645322fd72a 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -244,7 +244,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
protected RegionFileStorage(RegionStorageInfo info, Path folder, boolean sync) { // Paper - protected
this.folder = folder;
- this.sync = sync;
+ this.sync = Boolean.parseBoolean(System.getProperty("com.ishland.c2me.chunkio.syncDiskWrites", String.valueOf(sync))); // DivineMC - C2ME: sync disk writes
this.info = info;
this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers
}
diff --git a/net/minecraft/world/level/levelgen/Column.java b/net/minecraft/world/level/levelgen/Column.java
index 4a1df0f8578c9ee5538ed8c94d3c7911f36f83b8..716c2c69843234cdef34339d859babc95ffe318c 100644
--- a/net/minecraft/world/level/levelgen/Column.java
+++ b/net/minecraft/world/level/levelgen/Column.java
@@ -156,7 +156,7 @@ public abstract class Column {
}
public int height() {
- return this.ceiling - this.floor - 1;
+ return net.minecraft.util.Mth.abs(this.ceiling - this.floor - 1); // DivineMC - Chunk System optimization
}
@Override
diff --git a/net/minecraft/world/level/levelgen/WorldgenRandom.java b/net/minecraft/world/level/levelgen/WorldgenRandom.java
index c2d7cd788071e25b8ba2503c30ae80c7a9f353ed..0a2e13c4a3db6517267e1f9e74b6152c73e8351f 100644
--- a/net/minecraft/world/level/levelgen/WorldgenRandom.java
+++ b/net/minecraft/world/level/levelgen/WorldgenRandom.java
@@ -73,7 +73,7 @@ public class WorldgenRandom extends LegacyRandomSource {
}
public static enum Algorithm {
- LEGACY(LegacyRandomSource::new),
+ LEGACY(ThreadSafeLegacyRandomSource::new), // DivineMC - Chunk System optimization
XOROSHIRO(XoroshiroRandomSource::new);
private final LongFunction<RandomSource> constructor;
diff --git a/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java b/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java
index f4009671880b00ecec98fe604215e2824e453cdf..c607c801223ea71343ece67b81151e31362f1c31 100644
--- a/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java
+++ b/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java
@@ -55,17 +55,21 @@ public class RandomizedIntStateProvider extends BlockStateProvider {
@Override
public BlockState getState(RandomSource random, BlockPos pos) {
- BlockState state = this.source.getState(random, pos);
- if (this.property == null || !state.hasProperty(this.property)) {
- IntegerProperty integerProperty = findProperty(state, this.propertyName);
- if (integerProperty == null) {
- return state;
+ // DivineMC start - Chunk System optimization
+ BlockState blockState = this.source.getState(random, pos);
+ IntegerProperty propertyLocal = this.property;
+ if (propertyLocal == null || !blockState.hasProperty(propertyLocal)) {
+ IntegerProperty intProperty = findProperty(blockState, this.propertyName);
+ if (intProperty == null) {
+ return blockState;
}
- this.property = integerProperty;
+ propertyLocal = intProperty;
+ this.property = intProperty;
}
- return state.setValue(this.property, Integer.valueOf(this.values.sample(random)));
+ return (BlockState)blockState.setValue(propertyLocal, this.values.sample(random));
+ // DivineMC end - Chunk System optimization
}
@Nullable
diff --git a/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java b/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java
index d122221deefb218db962e97ba2d958c33d903b8a..56311b439ac22700593d2d31da3a4efe3a519d53 100644
--- a/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java
+++ b/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java
@@ -12,7 +12,7 @@ public abstract class ScatteredFeaturePiece extends StructurePiece {
protected final int width;
protected final int height;
protected final int depth;
- protected int heightPosition = -1;
+ protected volatile int heightPosition = -1; // DivineMC - Chunk System optimization - make volatile
protected ScatteredFeaturePiece(StructurePieceType type, int x, int y, int z, int width, int height, int depth, Direction orientation) {
super(type, 0, StructurePiece.makeBoundingBox(x, y, z, orientation, width, height, depth));
diff --git a/net/minecraft/world/level/levelgen/structure/StructureStart.java b/net/minecraft/world/level/levelgen/structure/StructureStart.java
index 4dafa79dd4ec55a443ba3731a79e7cd6e8052f48..8aeab4d773473ad20b1c64295c93d6fcb4ea02a1 100644
--- a/net/minecraft/world/level/levelgen/structure/StructureStart.java
+++ b/net/minecraft/world/level/levelgen/structure/StructureStart.java
@@ -26,7 +26,7 @@ public final class StructureStart {
private final Structure structure;
private final PiecesContainer pieceContainer;
private final ChunkPos chunkPos;
- private int references;
+ private final java.util.concurrent.atomic.AtomicInteger references = new java.util.concurrent.atomic.AtomicInteger(); // DivineMC - Chunk System optimization
@Nullable
private volatile BoundingBox cachedBoundingBox;
@@ -39,7 +39,7 @@ public final class StructureStart {
public StructureStart(Structure structure, ChunkPos chunkPos, int references, PiecesContainer pieceContainer) {
this.structure = structure;
this.chunkPos = chunkPos;
- this.references = references;
+ this.references.set(references); // DivineMC - Chunk System optimization
this.pieceContainer = pieceContainer;
}
@@ -126,7 +126,7 @@ public final class StructureStart {
compoundTag.putString("id", context.registryAccess().lookupOrThrow(Registries.STRUCTURE).getKey(this.structure).toString());
compoundTag.putInt("ChunkX", chunkPos.x);
compoundTag.putInt("ChunkZ", chunkPos.z);
- compoundTag.putInt("references", this.references);
+ compoundTag.putInt("references", this.references.get()); // DivineMC - Chunk System optimization
compoundTag.put("Children", this.pieceContainer.save(context));
return compoundTag;
} else {
@@ -144,15 +144,15 @@ public final class StructureStart {
}
public boolean canBeReferenced() {
- return this.references < this.getMaxReferences();
+ return this.references.get() < this.getMaxReferences(); // DivineMC - Chunk System optimization
}
public void addReference() {
- this.references++;
+ this.references.getAndIncrement(); // DivineMC - Chunk System optimization
}
public int getReferences() {
- return this.references;
+ return this.references.get(); // DivineMC - Chunk System optimization
}
protected int getMaxReferences() {