mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-21 15:59:23 +00:00
677 lines
41 KiB
Diff
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
|
|
}
|