9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-21 15:59:23 +00:00
Files
DivineMC/divinemc-server/minecraft-patches/features/0012-Chunk-System-optimization.patch
2025-03-16 22:02:11 +03:00

677 lines
41 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/level/entity/ChunkEntitySlices.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
index d21ce54ebb5724c04eadf56a2cde701d5eeb5db2..fe0edbb5c91258e620bf42f700aa399bf8b49066 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
@@ -40,9 +40,11 @@ public final class ChunkEntitySlices {
private final EntityCollectionBySection allEntities;
private final EntityCollectionBySection hardCollidingEntities;
- private final Reference2ObjectOpenHashMap<Class<? extends Entity>, EntityCollectionBySection> entitiesByClass;
- private final Reference2ObjectOpenHashMap<EntityType<?>, EntityCollectionBySection> entitiesByType;
- private final EntityList entities = new EntityList();
+ // DivineMC start - Chunk System optimization
+ private final Reference2ObjectMap<Class<? extends Entity>, EntityCollectionBySection> entitiesByClass;
+ private final Reference2ObjectMap<EntityType<?>, EntityCollectionBySection> entitiesByType;
+ private final java.util.Set<Entity> entities = com.google.common.collect.Sets.newConcurrentHashSet();
+ // DivineMC end - Chunk System optimization
public FullChunkStatus status;
public final ChunkData chunkData;
@@ -67,8 +69,10 @@ public final class ChunkEntitySlices {
this.allEntities = new EntityCollectionBySection(this);
this.hardCollidingEntities = new EntityCollectionBySection(this);
- this.entitiesByClass = new Reference2ObjectOpenHashMap<>();
- this.entitiesByType = new Reference2ObjectOpenHashMap<>();
+ // DivineMC start - Chunk System optimization
+ this.entitiesByClass = it.unimi.dsi.fastutil.objects.Reference2ObjectMaps.synchronize(new Reference2ObjectOpenHashMap<>());
+ this.entitiesByType = it.unimi.dsi.fastutil.objects.Reference2ObjectMaps.synchronize(new Reference2ObjectOpenHashMap<>());
+ // DivineMC end - Chunk System optimization
this.status = status;
this.chunkData = chunkData;
@@ -134,7 +138,7 @@ public final class ChunkEntitySlices {
return null;
}
- final Entity[] rawData = this.entities.getRawData();
+ final Entity[] rawData = this.entities.toArray(new Entity[0]); // DivineMC - Chunk System optimization
final List<Entity> collectedEntities = new ArrayList<>(len);
for (int i = 0; i < len; ++i) {
final Entity entity = rawData[i];
@@ -153,7 +157,7 @@ public final class ChunkEntitySlices {
// returns true if this chunk has transient entities remaining
public boolean unload() {
final int len = this.entities.size();
- final Entity[] collectedEntities = Arrays.copyOf(this.entities.getRawData(), len);
+ final Entity[] collectedEntities = Arrays.copyOf(this.entities.toArray(new Entity[0]), len); // DivineMC - Chunk System optimization
for (int i = 0; i < len; ++i) {
final Entity entity = collectedEntities[i];
@@ -182,7 +186,7 @@ public final class ChunkEntitySlices {
return new ArrayList<>();
}
- final Entity[] rawData = this.entities.getRawData();
+ final Entity[] rawData = this.entities.toArray(new Entity[0]); // DivineMC - Chunk System optimization
final List<Entity> collectedEntities = new ArrayList<>(len);
for (int i = 0; i < len; ++i) {
collectedEntities.add(rawData[i]);
@@ -196,7 +200,7 @@ public final class ChunkEntitySlices {
}
public void mergeInto(final ChunkEntitySlices slices) {
- final Entity[] entities = this.entities.getRawData();
+ final Entity[] entities = this.entities.toArray(new Entity[0]); // DivineMC - Chunk System optimization
for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) {
final Entity entity = entities[i];
slices.addEntity(entity, ((ChunkSystemEntity)entity).moonrise$getSectionY());
@@ -221,11 +225,7 @@ public final class ChunkEntitySlices {
public void updateStatus(final FullChunkStatus status, final EntityLookup lookup) {
this.status = status;
- final Entity[] entities = this.entities.getRawData();
-
- for (int i = 0, size = this.entities.size(); i < size; ++i) {
- final Entity entity = entities[i];
-
+ for (final Entity entity : this.entities) { // DivineMC - Chunk System optimization
final Visibility oldVisibility = EntityLookup.getEntityStatus(entity);
((ChunkSystemEntity)entity).moonrise$setChunkStatus(status);
final Visibility newVisibility = EntityLookup.getEntityStatus(entity);
@@ -248,10 +248,7 @@ public final class ChunkEntitySlices {
this.hardCollidingEntities.addEntity(entity, sectionIndex);
}
- for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
- this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
- final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
-
+ for (final java.util.Map.Entry<Class<? extends Entity>, EntityCollectionBySection> entry : this.entitiesByClass.entrySet()) { // DivineMC - Chunk System optimization
if (entry.getKey().isInstance(entity)) {
entry.getValue().addEntity(entity, sectionIndex);
}
@@ -282,10 +279,7 @@ public final class ChunkEntitySlices {
this.hardCollidingEntities.removeEntity(entity, sectionIndex);
}
- for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
- this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
- final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
-
+ for (final java.util.Map.Entry<Class<? extends Entity>, EntityCollectionBySection> entry : this.entitiesByClass.entrySet()) { // DivineMC - Chunk System optimization
if (entry.getKey().isInstance(entity)) {
entry.getValue().removeEntity(entity, sectionIndex);
}
@@ -436,13 +430,15 @@ public final class ChunkEntitySlices {
return false;
}
- final int size = --this.size;
+ // DivineMC start - Chunk System optimization
+ final int lastIdx = --this.size;
final E[] storage = this.storage;
- if (idx != size) {
- System.arraycopy(storage, idx + 1, storage, idx, size - idx);
+ if (idx < lastIdx) {
+ storage[idx] = storage[lastIdx];
}
- storage[size] = null;
+ storage[lastIdx] = null;
+ // DivineMC end - Chunk System optimization
return true;
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
index b28083be4384d6c5efbdce898a0e9d7a2f5bd3d3..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);
}
@@ -499,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
@@ -633,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) {
@@ -652,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()) {
@@ -691,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) {
@@ -767,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();
@@ -799,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()) {
@@ -830,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);
@@ -898,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();
@@ -919,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();
@@ -1071,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");
@@ -1099,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..6094b9f2d4a686a4c639c739d182aba7aac430e8 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
@@ -1208,6 +1208,27 @@ public final class ChunkHolderManager {
}
}
+ // DivineMC start - Chunk System optimization
+ public final org.agrona.collections.Object2ObjectHashMap<Long, NewChunkHolder> blockTickingChunkHolders = new org.agrona.collections.Object2ObjectHashMap<>(16384, 0.25f);
+ public final org.agrona.collections.Object2ObjectHashMap<Long, NewChunkHolder> entityTickingChunkHolders = new org.agrona.collections.Object2ObjectHashMap<>(16384, 0.25f);
+
+ public void markBlockTicking(NewChunkHolder newChunkHolder) {
+ this.blockTickingChunkHolders.put(newChunkHolder.getCachedLongPos(), newChunkHolder);
+ }
+
+ public void markNonBlockTickingIfPossible(NewChunkHolder newChunkHolder) {
+ this.blockTickingChunkHolders.remove(newChunkHolder.getCachedLongPos());
+ }
+
+ public void markEntityTicking(NewChunkHolder newChunkHolder) {
+ this.entityTickingChunkHolders.put(newChunkHolder.getCachedLongPos(), newChunkHolder);
+ }
+
+ public void markNonEntityTickingIfPossible(NewChunkHolder newChunkHolder) {
+ this.entityTickingChunkHolders.remove(newChunkHolder.getCachedLongPos());
+ }
+ // DivineMC end - Chunk System optimization
+
public enum TicketOperationType {
ADD, REMOVE, ADD_IF_REMOVED, ADD_AND_REMOVE
}
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/net/minecraft/server/level/DistanceManager.java b/net/minecraft/server/level/DistanceManager.java
index 5eab6179ce3913cb4e4d424f910ba423faf21c85..189205fbeed7673398fa6f7706864d3723467811 100644
--- a/net/minecraft/server/level/DistanceManager.java
+++ b/net/minecraft/server/level/DistanceManager.java
@@ -178,14 +178,14 @@ 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);
+ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().entityTickingChunkHolders.get(chunkPos); // DivineMC - Chunk System optimization
return chunkHolder != null && chunkHolder.isEntityTickingReady();
// 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);
+ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().blockTickingChunkHolders.get(chunkPos); // DivineMC - Chunk System optimization
return chunkHolder != null && chunkHolder.isTickingReady();
// Paper end - rewrite chunk system
}
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
index 2678bf59d557f085c7265e2f3eb038647723d35e..b30d6968fba2ab4d9cde0ac9d4f1cfc629c65359 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -441,7 +441,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);
+ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder newChunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.get(chunkPos); // DivineMC Chunk System optimization
return newChunkHolder != null && newChunkHolder.isTickingReady();
// Paper end - rewrite chunk system
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index a3f363d0c86142e03edc7fc6e2ff6ed81de8ed65..57668810e86b1f293c661d01c2486a3da7256c1e 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -857,7 +857,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);
+ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.get(chunkPos); // DivineMC - Chunk System optimization
return holder != null && holder.isTickingReady();
// Paper end - rewrite chunk system
}
@@ -2567,7 +2567,7 @@ 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);
+ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.get(chunkPos); // DivineMC - Chunk System optimization
// isTicking implies the chunk is loaded, and the chunk is loaded now implies the entities are loaded
return chunkHolder != null && chunkHolder.isTickingReady();
// Paper end - rewrite chunk system
@@ -2582,14 +2582,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
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));
+ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.entityTickingChunkHolders.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos)); // DivineMC - Chunk System optimization
return chunkHolder != null && chunkHolder.isEntityTickingReady();
// 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));
+ final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.entityTickingChunkHolders.get(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkPos)); // DivineMC - Chunk System optimization
return chunkHolder != null && chunkHolder.isEntityTickingReady();
// 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/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
}