mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-19 14:59:25 +00:00
387 lines
22 KiB
Diff
387 lines
22 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
|
Date: Mon, 9 Jun 2025 13:51:43 +0300
|
|
Subject: [PATCH] Regionized Chunk Ticking
|
|
|
|
This patch adds regionized chunk ticking feature, by grouping adjacent chunks into regions and processing each region on its own thread.
|
|
|
|
Original idea by Dueris, modified by NONPLAYT and heavily optimized by dan28000
|
|
|
|
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
|
index 35b6f8365f4568da7bc0f4e47c39cb3690292aaf..e28d859b457ca0e24bc6dc9d6cd4a97f12ae0671 100644
|
|
--- a/net/minecraft/network/Connection.java
|
|
+++ b/net/minecraft/network/Connection.java
|
|
@@ -327,7 +327,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
|
|
|
private static void syncAfterConfigurationChange(ChannelFuture future) {
|
|
try {
|
|
- future.syncUninterruptibly();
|
|
+ future.awaitUninterruptibly(5000L); // DivineMC - In rare cases this can get stuck, so we time out instead in worst case 5s of lag
|
|
} catch (Exception var2) {
|
|
if (var2 instanceof ClosedChannelException) {
|
|
LOGGER.info("Connection closed during protocol change");
|
|
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
|
index 04dd1bec1aff470e67a21fb0b25932685992ec82..72a0a80f1fffa43e143c80c689db5302f462114e 100644
|
|
--- a/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/net/minecraft/server/level/ChunkMap.java
|
|
@@ -737,7 +737,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
// Paper start - optimise chunk tick iteration
|
|
final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.world.level.chunk.LevelChunk> tickingChunks = ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel)this.level).moonrise$getPlayerTickingChunks();
|
|
|
|
- final LevelChunk[] raw = tickingChunks.getRawDataUnchecked();
|
|
+ final LevelChunk[] raw = tickingChunks.toArray(new LevelChunk[0]); // DivineMC - Regionized Chunk Ticking - sync fix
|
|
final int size = tickingChunks.size();
|
|
|
|
Objects.checkFromToIndex(0, size, raw.length);
|
|
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
|
index 6ea62fbffda38e477ef8e119608fc93793db95c3..dda53860397ee52f64209a8d08a7707cfa2f7592 100644
|
|
--- a/net/minecraft/server/level/ServerChunkCache.java
|
|
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
|
@@ -57,7 +57,7 @@ import org.slf4j.Logger;
|
|
public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache { // Paper - rewrite chunk system
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
private final DistanceManager distanceManager;
|
|
- private final ServerLevel level;
|
|
+ protected final ServerLevel level; // DivineMC - Regionized Chunk Ticking - private -> protected
|
|
public final Thread mainThread;
|
|
final ThreadedLevelLightEngine lightEngine;
|
|
public final ServerChunkCache.MainThreadExecutor mainThreadProcessor;
|
|
@@ -71,8 +71,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
private final long[] lastChunkPos = new long[4];
|
|
private final ChunkStatus[] lastChunkStatus = new ChunkStatus[4];
|
|
private final ChunkAccess[] lastChunk = new ChunkAccess[4];
|
|
- private final List<LevelChunk> spawningChunks = new ObjectArrayList<>();
|
|
- private final Set<ChunkHolder> chunkHoldersToBroadcast = new ReferenceOpenHashSet<>();
|
|
+ // DivineMC start - Regionized Chunk Ticking
|
|
+ private final ObjectArrayList<LevelChunk> spawningChunks = new ObjectArrayList<>();
|
|
+ private final Set<ChunkHolder> chunkHoldersToBroadcast = java.util.Collections.synchronizedSet(new ReferenceOpenHashSet<>());
|
|
+ // DivineMC end - Regionized Chunk Ticking
|
|
@Nullable
|
|
@VisibleForDebug
|
|
private NaturalSpawner.SpawnState lastSpawnState;
|
|
@@ -156,34 +158,46 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
// Paper end - rewrite chunk system
|
|
// Paper start - chunk tick iteration optimisations
|
|
private final ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom shuffleRandom = new ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom(0L);
|
|
- private void iterateTickingChunksFaster() {
|
|
+ private void iterateTickingChunksFaster(final CompletableFuture<Void> spawns) { // DivineMC - Regionized Chunk Ticking
|
|
final ServerLevel world = this.level;
|
|
final int randomTickSpeed = world.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
|
|
|
|
// TODO check on update: impl of forEachBlockTickingChunk will only iterate ENTITY ticking chunks!
|
|
// TODO check on update: consumer just runs tickChunk
|
|
- final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.world.level.chunk.LevelChunk> entityTickingChunks = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getEntityTickingChunks();
|
|
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<LevelChunk> entityTickingChunks = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getEntityTickingChunks(); // DivineMC - Regionized Chunk Ticking
|
|
|
|
// note: we can use the backing array here because:
|
|
// 1. we do not care about new additions
|
|
// 2. _removes_ are impossible at this stage in the tick
|
|
- final LevelChunk[] raw = entityTickingChunks.getRawDataUnchecked();
|
|
+ final LevelChunk[] raw = entityTickingChunks.toArray(new LevelChunk[0]); // DivineMC - use toArray instead of getRawDataUnchecked this way is safe and doesn't have performance impact
|
|
final int size = entityTickingChunks.size();
|
|
|
|
- java.util.Objects.checkFromToIndex(0, size, raw.length);
|
|
- for (int i = 0; i < size; ++i) {
|
|
- world.tickChunk(raw[i], randomTickSpeed);
|
|
-
|
|
- // call mid-tick tasks for chunk system
|
|
- if ((i & 7) == 0) {
|
|
- // DivineMC start - Parallel world ticking
|
|
- if (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableParallelWorldTicking) {
|
|
- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer) this.level.getServer()).moonrise$executeMidTickTasks();
|
|
- continue;
|
|
+ // DivineMC start - Regionized Chunk Ticking
|
|
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableRegionizedChunkTicking) {
|
|
+ if (this instanceof org.bxteam.divinemc.async.rct.RegionizedChunkTicking rct) {
|
|
+ rct.execute(spawns, raw);
|
|
+ }
|
|
+ } else {
|
|
+ java.util.Objects.checkFromToIndex(0, size, raw.length);
|
|
+ for (int i = 0; i < size; ++i) {
|
|
+ world.tickChunk(raw[i], randomTickSpeed);
|
|
+
|
|
+ // call mid-tick tasks for chunk system
|
|
+ if ((i & 7) == 0) {
|
|
+ // DivineMC start - Parallel world ticking
|
|
+ if (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableParallelWorldTicking) {
|
|
+ ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer) this.level.getServer()).moonrise$executeMidTickTasks();
|
|
+ continue;
|
|
+ }
|
|
+ // DivineMC end - Parallel world ticking
|
|
}
|
|
- // DivineMC end - Parallel world ticking
|
|
+ }
|
|
+
|
|
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncNaturalSpawn) {
|
|
+ spawns.join();
|
|
}
|
|
}
|
|
+ // DivineMC end - Regionized Chunk Ticking
|
|
}
|
|
// Paper end - chunk tick iteration optimisations
|
|
|
|
@@ -502,14 +516,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
long gameTime = this.level.getGameTime();
|
|
long l = gameTime - this.lastInhabitedUpdate;
|
|
this.lastInhabitedUpdate = gameTime;
|
|
- if (!this.level.isDebug()) {
|
|
- if (this.level.tickRateManager().runsNormally()) {
|
|
- this.tickChunks(l);
|
|
- }
|
|
|
|
+ // DivineMC start - Regionized Chunk Ticking
|
|
+ if (this.level.isDebug()) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (!this.level.tickRateManager().runsNormally()) { // DivineMC - when frozen only broadcast changed chunks and don't run async mob spawning
|
|
this.broadcastChangedChunks();
|
|
+ return;
|
|
}
|
|
|
|
+ this.tickChunks(l);
|
|
+ this.broadcastChangedChunks();
|
|
+ // DivineMC end - Regionized Chunk Ticking
|
|
+
|
|
// DivineMC start - Pufferfish: Optimize mob spawning
|
|
if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) {
|
|
for (ServerPlayer player : this.level.players) {
|
|
@@ -553,14 +574,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
}
|
|
|
|
private void broadcastChangedChunks() {
|
|
- for (ChunkHolder chunkHolder : this.chunkHoldersToBroadcast) {
|
|
- LevelChunk tickingChunk = chunkHolder.getChunkToSend(); // Paper - rewrite chunk system
|
|
- if (tickingChunk != null) {
|
|
- chunkHolder.broadcastChanges(tickingChunk);
|
|
+ // DivineMC start - Regionized Chunk Ticking
|
|
+ synchronized (chunkHoldersToBroadcast) {
|
|
+ for (ChunkHolder chunkHolder : this.chunkHoldersToBroadcast) {
|
|
+ LevelChunk tickingChunk = chunkHolder.getChunkToSend(); // Paper - rewrite chunk system
|
|
+ if (tickingChunk != null) {
|
|
+ chunkHolder.broadcastChanges(tickingChunk);
|
|
+ }
|
|
}
|
|
- }
|
|
|
|
- this.chunkHoldersToBroadcast.clear();
|
|
+ this.chunkHoldersToBroadcast.clear();
|
|
+ }
|
|
+ // DivineMC end - Regionized Chunk Ticking
|
|
}
|
|
|
|
private void tickChunks(long timeInhabited) {
|
|
@@ -610,6 +635,24 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
filteredSpawningCategories = List.of();
|
|
}
|
|
|
|
+ // DivineMC start - Regionized Chunk Ticking
|
|
+ final CompletableFuture<Void> spawns;
|
|
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncNaturalSpawn) {
|
|
+ spawns = CompletableFuture.runAsync(() -> naturalSpawn(filteredSpawningCategories, timeInhabited), org.bxteam.divinemc.async.rct.RegionizedChunkTicking.REGION_EXECUTOR);
|
|
+ } else {
|
|
+ naturalSpawn(filteredSpawningCategories, timeInhabited);
|
|
+ spawns = new CompletableFuture<>();
|
|
+ }
|
|
+ // DivineMC end - Regionized Chunk Ticking
|
|
+
|
|
+ this.iterateTickingChunksFaster(spawns); // Paper - chunk tick iteration optimisations // DivineMC - Regionized Chunk Ticking
|
|
+ if (_boolean) {
|
|
+ this.level.tickCustomSpawners(this.spawnEnemies);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ // DivineMC start - Regionized Chunk Ticking
|
|
+ private void naturalSpawn(List<MobCategory> filteredSpawningCategories, long timeInhabited) {
|
|
List<LevelChunk> list = this.spawningChunks;
|
|
|
|
try {
|
|
@@ -627,12 +670,12 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
} finally {
|
|
list.clear();
|
|
}
|
|
+ }
|
|
|
|
- this.iterateTickingChunksFaster(); // Paper - chunk tick iteration optimisations
|
|
- if (_boolean) {
|
|
- this.level.tickCustomSpawners(this.spawnEnemies);
|
|
- }
|
|
+ protected net.minecraft.world.level.entity.EntityTickList getEntityTickList() {
|
|
+ return level.entityTickList;
|
|
}
|
|
+ // DivineMC end - Regionized Chunk Ticking
|
|
|
|
private void tickSpawningChunk(LevelChunk chunk, long timeInhabited, List<MobCategory> spawnCategories, NaturalSpawner.SpawnState spawnState) {
|
|
ChunkPos pos = chunk.getPos();
|
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
|
index ca9883277c0f036c94e861f7917ca42facd3c47b..8c98c2593eec14a8a378041e94cf52b8fbfedc30 100644
|
|
--- a/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
|
@@ -197,7 +197,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
private final LevelTicks<Block> blockTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded);
|
|
private final LevelTicks<Fluid> fluidTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded);
|
|
private final PathTypeCache pathTypesByPosCache = new PathTypeCache();
|
|
- final Set<Mob> navigatingMobs = new ObjectOpenHashSet<>();
|
|
+ final Set<Mob> navigatingMobs = java.util.Collections.synchronizedSet(new ObjectOpenHashSet<>()); // DivineMC - Regionized Chunk Ticking
|
|
volatile boolean isUpdatingNavigations;
|
|
protected final Raids raids;
|
|
private final ObjectLinkedOpenHashSet<BlockEventData> blockEvents = new ObjectLinkedOpenHashSet<>();
|
|
@@ -666,19 +666,37 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
boolean flag = server.forceSynchronousWrites();
|
|
DataFixer fixerUpper = server.getFixerUpper();
|
|
// Paper - rewrite chunk system
|
|
- this.chunkSource = new ServerChunkCache(
|
|
- this,
|
|
- levelStorageAccess,
|
|
- fixerUpper,
|
|
- server.getStructureManager(),
|
|
- dispatcher,
|
|
- chunkGenerator,
|
|
- this.spigotConfig.viewDistance, // Spigot
|
|
- this.spigotConfig.simulationDistance, // Spigot
|
|
- flag,
|
|
- null, // Paper - rewrite chunk system
|
|
- () -> server.overworld().getDataStorage()
|
|
- );
|
|
+ // DivineMC start - Regionized Chunk Ticking
|
|
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableRegionizedChunkTicking) {
|
|
+ this.chunkSource = new org.bxteam.divinemc.async.rct.RegionizedChunkTicking(
|
|
+ this,
|
|
+ levelStorageAccess,
|
|
+ fixerUpper,
|
|
+ server.getStructureManager(),
|
|
+ dispatcher,
|
|
+ chunkGenerator,
|
|
+ this.spigotConfig.viewDistance, // Spigot
|
|
+ this.spigotConfig.simulationDistance, // Spigot
|
|
+ flag,
|
|
+ null, // Paper - rewrite chunk system
|
|
+ () -> server.overworld().getDataStorage()
|
|
+ );
|
|
+ } else {
|
|
+ this.chunkSource = new ServerChunkCache(
|
|
+ this,
|
|
+ levelStorageAccess,
|
|
+ fixerUpper,
|
|
+ server.getStructureManager(),
|
|
+ dispatcher,
|
|
+ chunkGenerator,
|
|
+ this.spigotConfig.viewDistance, // Spigot
|
|
+ this.spigotConfig.simulationDistance, // Spigot
|
|
+ flag,
|
|
+ null, // Paper - rewrite chunk system
|
|
+ () -> server.overworld().getDataStorage()
|
|
+ );
|
|
+ }
|
|
+ // DivineMC end - Regionized Chunk Ticking
|
|
this.chunkSource.getGeneratorState().ensureStructuresGenerated();
|
|
this.portalForcer = new PortalForcer(this);
|
|
this.updateSkyBrightness();
|
|
@@ -846,6 +864,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
this.dragonFight.tick();
|
|
}
|
|
|
|
+ // DivineMC start - Regionized Chunk Ticking
|
|
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableRegionizedChunkTicking) {
|
|
+ this.tickBlockEntities();
|
|
+ return;
|
|
+ }
|
|
+ // DivineMC end - Regionized Chunk Ticking
|
|
+
|
|
io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR
|
|
this.entityTickList
|
|
.forEach(
|
|
@@ -1874,22 +1899,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
if (Shapes.joinIsNotEmpty(collisionShape, collisionShape1, BooleanOp.NOT_SAME)) {
|
|
List<PathNavigation> list = new ObjectArrayList<>();
|
|
|
|
- try { // Paper - catch CME see below why
|
|
- for (Mob mob : this.navigatingMobs) {
|
|
- PathNavigation navigation = mob.getNavigation();
|
|
- if (navigation.shouldRecomputePath(pos)) {
|
|
- list.add(navigation);
|
|
+ // DivineMC start - Regionized Chunk Ticking
|
|
+ synchronized (this.navigatingMobs) {
|
|
+ for (Mob mob : this.navigatingMobs) {
|
|
+ PathNavigation navigation = mob.getNavigation();
|
|
+ if (navigation.shouldRecomputePath(pos)) {
|
|
+ list.add(navigation);
|
|
+ }
|
|
}
|
|
}
|
|
- // Paper start - catch CME see below why
|
|
- } catch (final java.util.ConcurrentModificationException concurrentModificationException) {
|
|
- // This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register
|
|
- // In this case we just run the update again across all the iterators as the chunk will then be loaded
|
|
- // As this is a relative edge case it is much faster than copying navigators (on either read or write)
|
|
- this.sendBlockUpdated(pos, oldState, newState, flags);
|
|
- return;
|
|
- }
|
|
- // Paper end - catch CME see below why
|
|
+ // DivineMC end - Regionized Chunk Ticking
|
|
|
|
try {
|
|
this.isUpdatingNavigations = true;
|
|
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
|
index 7fe5cb2ea1c81b12baf302999a2794f20018707c..738cbde3595165e0f05c0a6fde21499e98dc850b 100644
|
|
--- a/net/minecraft/world/level/Level.java
|
|
+++ b/net/minecraft/world/level/Level.java
|
|
@@ -113,7 +113,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
.build();
|
|
public final org.bxteam.divinemc.util.BlockEntityTickersList blockEntityTickers = new org.bxteam.divinemc.util.BlockEntityTickersList(); // DivineMC - optimize block entity removals - Fix MC-117075
|
|
protected final CollectingNeighborUpdater neighborUpdater;
|
|
- private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
|
|
+ private final List<TickingBlockEntity> pendingBlockEntityTickers = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Regionized Chunk Ticking
|
|
private boolean tickingBlockEntities;
|
|
public final Thread thread;
|
|
private final boolean isDebug;
|
|
@@ -145,7 +145,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
|
|
public boolean captureBlockStates = false;
|
|
public boolean captureTreeGeneration = false;
|
|
- public Map<BlockPos, org.bukkit.craftbukkit.block.CraftBlockState> capturedBlockStates = new java.util.LinkedHashMap<>(); // Paper
|
|
+ public Map<BlockPos, org.bukkit.craftbukkit.block.CraftBlockState> capturedBlockStates = java.util.Collections.synchronizedMap(new java.util.LinkedHashMap<>()); // Paper // DivineMC - Regionized Chunk Ticking
|
|
public Map<BlockPos, BlockEntity> capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper - Retain block place order when capturing blockstates
|
|
@Nullable
|
|
public List<net.minecraft.world.entity.item.ItemEntity> captureDrops;
|
|
@@ -1459,10 +1459,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
|
|
public void tickBlockEntities() {
|
|
this.tickingBlockEntities = true;
|
|
- if (!this.pendingBlockEntityTickers.isEmpty()) {
|
|
- this.blockEntityTickers.addAll(this.pendingBlockEntityTickers);
|
|
- this.pendingBlockEntityTickers.clear();
|
|
+ // DivineMC start - Regionized Chunk Ticking - synchronization fix
|
|
+ synchronized (pendingBlockEntityTickers) {
|
|
+ if (!this.pendingBlockEntityTickers.isEmpty()) {
|
|
+ this.blockEntityTickers.addAll(this.pendingBlockEntityTickers);
|
|
+ this.pendingBlockEntityTickers.clear();
|
|
+ }
|
|
}
|
|
+ // DivineMC end - Regionized Chunk Ticking - synchronization fix
|
|
|
|
// Spigot start
|
|
boolean runsNormally = this.tickRateManager().runsNormally();
|
|
diff --git a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
|
|
index 5d17213a692016d2f005c7820bf2cf1f42ce411f..ccb2e0c28aeaebbeef15fbb650fa3c2e5c241ceb 100644
|
|
--- a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
|
|
+++ b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
|
|
@@ -53,7 +53,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
|
|
this.addAndRun(pos, new CollectingNeighborUpdater.MultiNeighborUpdate(pos.immutable(), block, orientation, facing));
|
|
}
|
|
|
|
- private void addAndRun(BlockPos pos, CollectingNeighborUpdater.NeighborUpdates updates) {
|
|
+ private synchronized void addAndRun(BlockPos pos, CollectingNeighborUpdater.NeighborUpdates updates) { // DivineMC - Regionized Chunk Ticking - synchronized
|
|
boolean flag = this.count > 0;
|
|
boolean flag1 = this.maxChainedNeighborUpdates >= 0 && this.count >= this.maxChainedNeighborUpdates;
|
|
this.count++;
|
|
@@ -72,7 +72,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
|
|
}
|
|
}
|
|
|
|
- private void runUpdates() {
|
|
+ private synchronized void runUpdates() { // DivineMC - Regionized Chunk Ticking - synchronized
|
|
try {
|
|
while (!this.stack.isEmpty() || !this.addedThisLayer.isEmpty()) {
|
|
for (int i = this.addedThisLayer.size() - 1; i >= 0; i--) {
|