mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-19 14:59:25 +00:00
Merge branch 'ver/1.21.8' into ver/1.21.10
# Conflicts: # divinemc-server/minecraft-patches/features/0052-Regionized-Chunk-Ticking.patch # divinemc-server/minecraft-patches/features/0061-Cleanup-dead-code-from-Paper.patch # divinemc-server/minecraft-patches/features/0068-Optimize-level-ticking.patch # divinemc-server/minecraft-patches/features/0069-Optimize-Moonrise.patch # divinemc-server/minecraft-patches/features/0072-lithium-sleeping_block_entity.patch
This commit is contained in:
@@ -8,7 +8,7 @@ This patch adds regionized chunk ticking feature, by grouping adjacent chunks in
|
||||
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 3f85f9e9551b2eed6e66ab8036dbb1f40fb8bbac..2da4ba00963c9ff6715fe60aa2f6af724fa8ed61 100644
|
||||
index 411e1284a208ca1a097cf6eaa92e1e0d2203d83d..3f60d1b0ac91cfd3418e791222cd7267774b367a 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -327,7 +327,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
@@ -20,19 +20,33 @@ index 3f85f9e9551b2eed6e66ab8036dbb1f40fb8bbac..2da4ba00963c9ff6715fe60aa2f6af72
|
||||
} 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 7ca147cf9da67c399806056e5092841f7ca32321..81a174111dc2ebc9df428a67936c302ae9ec95e3 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -730,7 +730,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
void collectSpawningChunks(List<LevelChunk> output) {
|
||||
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 bfc200f39a22664204b5aa66d3911abdb368e563..50daa39747a0f07c4d31a13c4410819a82d5f076 100644
|
||||
index 2039e636b1a52aff5403621e7281d618e4b87864..855ec5c636b9f8ca504425dafd49c4a71b1e2456 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -58,6 +58,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
@@ -56,7 +56,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;
|
||||
+ public static final Executor REGION_EXECUTOR = java.util.concurrent.Executors.newFixedThreadPool(org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadCount, new org.bxteam.divinemc.util.NamedAgnosticThreadFactory<>("Region Ticking", ca.spottedleaf.moonrise.common.util.TickThread::new, org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadPriority)); // DivineMC - Regionized Chunk Ticking
|
||||
- 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 +72,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
@@ -70,8 +70,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];
|
||||
@@ -45,141 +59,12 @@ index bfc200f39a22664204b5aa66d3911abdb368e563..50daa39747a0f07c4d31a13c4410819a
|
||||
@Nullable
|
||||
@VisibleForDebug
|
||||
private NaturalSpawner.SpawnState lastSpawnState;
|
||||
@@ -154,36 +157,253 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
return load ? this.syncLoad(chunkX, chunkZ, toStatus) : null;
|
||||
}
|
||||
@@ -155,34 +157,46 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
// Paper end - rewrite chunk system
|
||||
+
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ private record RegionData(it.unimi.dsi.fastutil.longs.LongOpenHashSet chunks, Set<Entity> entities) {
|
||||
+ public boolean isEmpty() {
|
||||
+ return chunks.isEmpty();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private record Output(RegionData[] regions, Set<Entity> entities) {}
|
||||
+
|
||||
+ private Output computePlayerRegionsParallel() {
|
||||
+ int tickViewDistance = level.moonrise$getViewDistanceHolder().getViewDistances().tickViewDistance();
|
||||
+ List<ServerPlayer> players = new java.util.ArrayList<>(level.players);
|
||||
+ int max = maxChunksForViewDistance();
|
||||
+
|
||||
+ List<it.unimi.dsi.fastutil.longs.LongOpenHashSet> playerChunkSets = players.parallelStream()
|
||||
+ .map(player -> {
|
||||
+ ChunkPos playerChunk = player.chunkPosition();
|
||||
+ int px = playerChunk.x;
|
||||
+ int pz = playerChunk.z;
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet chunkKeys = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(max);
|
||||
+ for (int dx = -tickViewDistance; dx <= tickViewDistance; dx++) {
|
||||
+ for (int dz = -tickViewDistance; dz <= tickViewDistance; dz++) {
|
||||
+ long key = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(px + dx, pz + dz);
|
||||
+ chunkKeys.add(key);
|
||||
+ }
|
||||
+ }
|
||||
+ return chunkKeys;
|
||||
+ }).toList();
|
||||
+
|
||||
+ List<it.unimi.dsi.fastutil.longs.LongOpenHashSet> mergedRegions = new java.util.ArrayList<>();
|
||||
+ boolean[] merged = new boolean[playerChunkSets.size()];
|
||||
+
|
||||
+ for (int i = 0; i < playerChunkSets.size(); i++) {
|
||||
+ if (merged[i]) continue;
|
||||
+
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet region = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(playerChunkSets.get(i));
|
||||
+ merged[i] = true;
|
||||
+
|
||||
+ boolean madeChanges;
|
||||
+ do {
|
||||
+ madeChanges = false;
|
||||
+ for (int j = i + 1; j < playerChunkSets.size(); j++) {
|
||||
+ if (merged[j]) continue;
|
||||
+
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet set = playerChunkSets.get(j);
|
||||
+
|
||||
+ boolean hasIntersection = false;
|
||||
+ it.unimi.dsi.fastutil.longs.LongIterator iter = set.iterator();
|
||||
+ while (iter.hasNext()) {
|
||||
+ if (region.contains(iter.nextLong())) {
|
||||
+ hasIntersection = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (hasIntersection) {
|
||||
+ region.addAll(set);
|
||||
+ merged[j] = true;
|
||||
+ madeChanges = true;
|
||||
+ }
|
||||
+ }
|
||||
+ } while (madeChanges);
|
||||
+
|
||||
+ mergedRegions.add(region);
|
||||
+ }
|
||||
+
|
||||
+ ObjectArrayList<RegionData> regions = new ObjectArrayList<>();
|
||||
+ it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap chunkToRegion = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap(max * mergedRegions.size());
|
||||
+ chunkToRegion.defaultReturnValue(-1);
|
||||
+ for (int i = 0; i < mergedRegions.size(); i++) {
|
||||
+ regions.add(new RegionData(mergedRegions.get(i), java.util.Collections.newSetFromMap(new java.util.concurrent.ConcurrentHashMap<>())));
|
||||
+ for (long key : mergedRegions.get(i)) {
|
||||
+ chunkToRegion.put(key, i);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final Set<Entity> firstTick = java.util.Collections.newSetFromMap(new java.util.concurrent.ConcurrentHashMap<>());
|
||||
+
|
||||
+ synchronized (level.entityTickList.entities) {
|
||||
+ final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator<Entity> iterator = level.entityTickList.entities.iterator();
|
||||
+ try {
|
||||
+ while (iterator.hasNext()) {
|
||||
+ Entity entity = iterator.next();
|
||||
+ long chunkKey = entity.chunkPosition().longKey;
|
||||
+ int regionIndex = chunkToRegion.get(chunkKey);
|
||||
+ if (regionIndex != -1) {
|
||||
+ regions.get(regionIndex).entities().add(entity);
|
||||
+ } else {
|
||||
+ firstTick.add(entity);
|
||||
+ }
|
||||
+ }
|
||||
+ } finally {
|
||||
+ iterator.finishedIterating();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return new Output(regions.toArray(new RegionData[0]), firstTick);
|
||||
+ }
|
||||
+
|
||||
+ // Should be max safe estimate of ticking chunks in a region
|
||||
+ private int maxChunksForViewDistance() {
|
||||
+ ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.ViewDistances distances = level.moonrise$getViewDistanceHolder().getViewDistances();
|
||||
+ int diameter = 2 * distances.tickViewDistance() + 1;
|
||||
+ return diameter * diameter;
|
||||
+ }
|
||||
+
|
||||
+ private void tickEntity(Entity entity) {
|
||||
+ if (!entity.isRemoved()) {
|
||||
+ if (!level.tickRateManager().isEntityFrozen(entity)) {
|
||||
+ entity.checkDespawn();
|
||||
+ // Paper - rewrite chunk system
|
||||
+ Entity vehicle = entity.getVehicle();
|
||||
+ if (vehicle != null) {
|
||||
+ if (!vehicle.isRemoved() && vehicle.hasPassenger(entity)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ entity.stopRiding();
|
||||
+ }
|
||||
+
|
||||
+ level.guardEntityTick(level::tickNonPassenger, entity);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Regionized Chunk Ticking
|
||||
+
|
||||
// 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 java.util.concurrent.CompletableFuture<Void> spawns) { // DivineMC - Regionized Chunk Ticking
|
||||
+ 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);
|
||||
|
||||
@@ -198,98 +83,17 @@ index bfc200f39a22664204b5aa66d3911abdb368e563..50daa39747a0f07c4d31a13c4410819a
|
||||
- java.util.Objects.checkFromToIndex(0, size, raw.length);
|
||||
- for (int i = 0; i < size; ++i) {
|
||||
- world.tickChunk(raw[i], randomTickSpeed);
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableRegionizedChunkTicking) {
|
||||
+ final Output output = computePlayerRegionsParallel();
|
||||
+ final RegionData[] regions = output.regions();
|
||||
+ int regionCount = regions.length;
|
||||
+
|
||||
+ java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(regionCount);
|
||||
+ io.papermc.paper.entity.activation.ActivationRange.activateEntities(level); // Paper - EAR
|
||||
+
|
||||
+ try {
|
||||
+ java.util.concurrent.ForkJoinPool.managedBlock(new java.util.concurrent.ForkJoinPool.ManagedBlocker() {
|
||||
+ @Override
|
||||
+ public boolean block() throws InterruptedException {
|
||||
+ ObjectArrayList<java.util.concurrent.CompletableFuture<it.unimi.dsi.fastutil.longs.LongOpenHashSet>> ticked = new ObjectArrayList<>(regionCount);
|
||||
+ for (final RegionData region : regions) {
|
||||
+ if (region == null || region.isEmpty()) {
|
||||
+ latch.countDown();
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ ticked.add(java.util.concurrent.CompletableFuture.supplyAsync(() -> {
|
||||
+ ObjectArrayList<LevelChunk> regionChunks = new ObjectArrayList<>(region.chunks().size());
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet regionChunksIDs = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(region.chunks().size());
|
||||
+ for (long key : region.chunks()) {
|
||||
+ LevelChunk chunk = fullChunks.get(key);
|
||||
+ if (chunk != null) {
|
||||
+ regionChunks.add(chunk);
|
||||
+ regionChunksIDs.add(key);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ for (LevelChunk chunk : regionChunks) {
|
||||
+ world.tickChunk(chunk, randomTickSpeed);
|
||||
+ }
|
||||
+ for (net.minecraft.world.entity.Entity entity : region.entities()) {
|
||||
+ tickEntity(entity);
|
||||
+ }
|
||||
+ } finally {
|
||||
+ latch.countDown();
|
||||
+ }
|
||||
+ return regionChunksIDs;
|
||||
+ }, REGION_EXECUTOR));
|
||||
+ }
|
||||
|
||||
-
|
||||
- // 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;
|
||||
+ CompletableFuture.runAsync(() -> {
|
||||
+ try {
|
||||
+ CompletableFuture.allOf(ticked.toArray(new CompletableFuture[0])).join();
|
||||
+ } catch (java.util.concurrent.CompletionException ex) {
|
||||
+ LOGGER.error("Error during region chunk ticking", ex.getCause());
|
||||
+ }
|
||||
+
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet tickedChunkKeys = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(raw.length);
|
||||
+
|
||||
+ for (CompletableFuture<it.unimi.dsi.fastutil.longs.LongOpenHashSet> future : ticked) {
|
||||
+ if (!future.isCompletedExceptionally()) {
|
||||
+ try {
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet regionChunks = future.join();
|
||||
+ tickedChunkKeys.addAll(regionChunks);
|
||||
+ } catch (Exception e) {
|
||||
+ LOGGER.error("Exception in region ticking future", e);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (LevelChunk chunk : raw) {
|
||||
+ if (!tickedChunkKeys.contains(chunk.coordinateKey)) {
|
||||
+ world.tickChunk(chunk, randomTickSpeed);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ output.entities.forEach(ServerChunkCache.this::tickEntity);
|
||||
+ spawns.join();
|
||||
+ }, REGION_EXECUTOR).join();
|
||||
+
|
||||
+ latch.await();
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isReleasable() {
|
||||
+ return latch.getCount() == 0;
|
||||
+ }
|
||||
+ });
|
||||
+ } catch (InterruptedException ex) {
|
||||
+ throw new RuntimeException("Interrupted managed block during region ticking", ex);
|
||||
+ // 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);
|
||||
@@ -306,13 +110,17 @@ index bfc200f39a22664204b5aa66d3911abdb368e563..50daa39747a0f07c4d31a13c4410819a
|
||||
+ // 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 +722,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
@@ -507,14 +521,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
long gameTime = this.level.getGameTime();
|
||||
long l = gameTime - this.lastInhabitedUpdate;
|
||||
this.lastInhabitedUpdate = gameTime;
|
||||
@@ -338,7 +146,7 @@ index bfc200f39a22664204b5aa66d3911abdb368e563..50daa39747a0f07c4d31a13c4410819a
|
||||
// DivineMC start - Pufferfish: Optimize mob spawning
|
||||
if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) {
|
||||
for (ServerPlayer player : this.level.players) {
|
||||
@@ -553,14 +780,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
@@ -558,14 +579,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
}
|
||||
|
||||
private void broadcastChangedChunks() {
|
||||
@@ -363,54 +171,53 @@ index bfc200f39a22664204b5aa66d3911abdb368e563..50daa39747a0f07c4d31a13c4410819a
|
||||
}
|
||||
|
||||
private void tickChunks(long timeInhabited) {
|
||||
@@ -610,23 +841,28 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
@@ -615,6 +640,24 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
filteredSpawningCategories = List.of();
|
||||
}
|
||||
|
||||
- List<LevelChunk> list = this.spawningChunks;
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ final java.util.concurrent.CompletableFuture<Void> spawns = java.util.concurrent.CompletableFuture.runAsync(() -> {
|
||||
+ List<LevelChunk> list = this.spawningChunks;
|
||||
|
||||
- try {
|
||||
- this.chunkMap.collectSpawningChunks(list);
|
||||
- // Paper start - chunk tick iteration optimisation
|
||||
- this.shuffleRandom.setSeed(this.level.random.nextLong());
|
||||
- if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled
|
||||
- // Paper end - chunk tick iteration optimisation
|
||||
-
|
||||
- for (LevelChunk levelChunk : list) {
|
||||
- this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Pufferfish: Optimize mob spawning
|
||||
+ try {
|
||||
+ this.chunkMap.collectSpawningChunks(list);
|
||||
+ // Paper start - chunk tick iteration optimisation
|
||||
+ this.shuffleRandom.setSeed(this.level.random.nextLong());
|
||||
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns)
|
||||
+ Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled
|
||||
+ // Paper end - chunk tick iteration optimisation
|
||||
+
|
||||
+ for (LevelChunk levelChunk : list) {
|
||||
+ this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Pufferfish: Optimize mob spawning
|
||||
+ 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<>();
|
||||
+ }
|
||||
+ } finally {
|
||||
+ list.clear();
|
||||
}
|
||||
- } finally {
|
||||
- list.clear();
|
||||
- }
|
||||
+ }, REGION_EXECUTOR);
|
||||
+ // DivineMC end - Regionized Chunk Ticking
|
||||
+
|
||||
+ this.iterateTickingChunksFaster(spawns); // Paper - chunk tick iteration optimisations // DivineMC - Regionized Chunk Ticking
|
||||
+ if (_boolean) {
|
||||
+ this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ private void naturalSpawn(List<MobCategory> filteredSpawningCategories, long timeInhabited) {
|
||||
List<LevelChunk> list = this.spawningChunks;
|
||||
|
||||
try {
|
||||
@@ -630,12 +673,12 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
} finally {
|
||||
list.clear();
|
||||
}
|
||||
+ }
|
||||
|
||||
- this.iterateTickingChunksFaster(); // Paper - chunk tick iteration optimisations
|
||||
+ this.iterateTickingChunksFaster(spawns); // Paper - chunk tick iteration optimisations // DivineMC - Regionized Chunk Ticking
|
||||
if (_boolean) {
|
||||
this.level.tickCustomSpawners(this.spawnEnemies);
|
||||
- if (_boolean) {
|
||||
- this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies);
|
||||
- }
|
||||
+ 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 d27a130f80cb8225a30b289b9d06c5c508a55ea7..f4399659d084ed9703052b3ce2c82a9e198cd514 100644
|
||||
index f9091b2daf735fd0788f8d6d60e3c812fd6dd4f2..6c59d11107958f835ebe09317ed0d129f64d4583 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
|
||||
@@ -191,7 +191,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();
|
||||
@@ -419,7 +226,59 @@ index d27a130f80cb8225a30b289b9d06c5c508a55ea7..f4399659d084ed9703052b3ce2c82a9e
|
||||
volatile boolean isUpdatingNavigations;
|
||||
protected final Raids raids;
|
||||
private final ObjectLinkedOpenHashSet<BlockEventData> blockEvents = new ObjectLinkedOpenHashSet<>();
|
||||
@@ -834,6 +834,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -640,20 +640,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,
|
||||
- progressListener,
|
||||
- null, // Paper - rewrite chunk system
|
||||
- () -> server.overworld().getDataStorage()
|
||||
- );
|
||||
+ 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,
|
||||
+ progressListener,
|
||||
+ 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,
|
||||
+ progressListener,
|
||||
+ null, // Paper - rewrite chunk system
|
||||
+ () -> server.overworld().getDataStorage()
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
this.chunkSource.getGeneratorState().ensureStructuresGenerated();
|
||||
this.portalForcer = new PortalForcer(this);
|
||||
this.updateSkyBrightness();
|
||||
@@ -806,6 +823,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
this.dragonFight.tick();
|
||||
}
|
||||
|
||||
@@ -433,7 +292,7 @@ index d27a130f80cb8225a30b289b9d06c5c508a55ea7..f4399659d084ed9703052b3ce2c82a9e
|
||||
io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR
|
||||
this.entityTickList
|
||||
.forEach(
|
||||
@@ -1862,22 +1869,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -1828,22 +1852,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
if (Shapes.joinIsNotEmpty(collisionShape, collisionShape1, BooleanOp.NOT_SAME)) {
|
||||
List<PathNavigation> list = new ObjectArrayList<>();
|
||||
|
||||
@@ -465,19 +324,19 @@ index d27a130f80cb8225a30b289b9d06c5c508a55ea7..f4399659d084ed9703052b3ce2c82a9e
|
||||
try {
|
||||
this.isUpdatingNavigations = true;
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 49c4d40e802f8adaba52d929ba013d3953704989..9f559be50c990d15d7765827b7c4c4092f5e184a 100644
|
||||
index 22a2b6b31f6f9b9b613586f7d674302304be3232..66ba223dacefb3531c46b144c4499b2b2285eafe 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -112,7 +112,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;
|
||||
@@ -106,7 +106,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
public static final int MIN_ENTITY_SPAWN_Y = -20000000;
|
||||
public final org.bxteam.divinemc.util.BlockEntityTickersList blockEntityTickers = new org.bxteam.divinemc.util.BlockEntityTickersList(); // Paper - public // DivineMC - optimize block entity removals - Fix MC-117075
|
||||
protected final NeighborUpdater 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;
|
||||
@@ -144,7 +144,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
@@ -138,7 +138,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
|
||||
public boolean captureBlockStates = false;
|
||||
public boolean captureTreeGeneration = false;
|
||||
@@ -486,9 +345,9 @@ index 49c4d40e802f8adaba52d929ba013d3953704989..9f559be50c990d15d7765827b7c4c409
|
||||
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;
|
||||
@@ -1457,10 +1457,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
@@ -1503,10 +1503,14 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
|
||||
public void tickBlockEntities() {
|
||||
protected void tickBlockEntities() {
|
||||
this.tickingBlockEntities = true;
|
||||
- if (!this.pendingBlockEntityTickers.isEmpty()) {
|
||||
- this.blockEntityTickers.addAll(this.pendingBlockEntityTickers);
|
||||
@@ -505,10 +364,10 @@ index 49c4d40e802f8adaba52d929ba013d3953704989..9f559be50c990d15d7765827b7c4c409
|
||||
// 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 879be2d05ef0fcfb8fab0c9f4e5bf66d7fce730b..ff8fde0d294c96755cdcdcef0cbf57dd259e06a7 100644
|
||||
index 028eae2f9a459b60e92f3344091083aa93b54485..51e5a54aff069cac14deef6c04899d3a469842ce 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 {
|
||||
@@ -46,7 +46,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
|
||||
this.addAndRun(pos, new CollectingNeighborUpdater.MultiNeighborUpdate(pos.immutable(), block, orientation, facing));
|
||||
}
|
||||
|
||||
@@ -517,7 +376,7 @@ index 879be2d05ef0fcfb8fab0c9f4e5bf66d7fce730b..ff8fde0d294c96755cdcdcef0cbf57dd
|
||||
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 {
|
||||
@@ -65,7 +65,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.bxteam.divinemc.async.rct;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
record RegionData(LongOpenHashSet chunks, Set<Entity> entities) {
|
||||
public boolean isEmpty() {
|
||||
return chunks.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
package org.bxteam.divinemc.async.rct;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet;
|
||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||
import ca.spottedleaf.moonrise.common.util.TickThread;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.ViewDistances;
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.papermc.paper.entity.activation.ActivationRange;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.entity.ChunkStatusUpdateListener;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import net.minecraft.world.level.storage.DimensionDataStorage;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
import org.bxteam.divinemc.config.DivineConfig;
|
||||
import org.bxteam.divinemc.util.NamedAgnosticThreadFactory;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class RegionizedChunkTicking extends ServerChunkCache {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
public static final Executor REGION_EXECUTOR = Executors.newFixedThreadPool(DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadCount,
|
||||
new NamedAgnosticThreadFactory<>("Region Ticking", TickThread::new, DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadPriority)
|
||||
);
|
||||
|
||||
public RegionizedChunkTicking(final ServerLevel level, final LevelStorageSource.LevelStorageAccess levelStorageAccess, final DataFixer fixerUpper, final StructureTemplateManager structureManager, final Executor dispatcher, final ChunkGenerator generator, final int viewDistance, final int simulationDistance, final boolean sync, final ChunkProgressListener progressListener, final ChunkStatusUpdateListener chunkStatusListener, final Supplier<DimensionDataStorage> overworldDataStorage) {
|
||||
super(level, levelStorageAccess, fixerUpper, structureManager, dispatcher, generator, viewDistance, simulationDistance, sync, progressListener, chunkStatusListener, overworldDataStorage);
|
||||
}
|
||||
|
||||
public void execute(CompletableFuture<Void> spawns, final LevelChunk[] raw) {
|
||||
final TickPair tickPair = computePlayerRegionsParallel();
|
||||
final RegionData[] regions = tickPair.regions();
|
||||
final int regionCount = regions.length;
|
||||
|
||||
ActivationRange.activateEntities(level); // Paper - EAR
|
||||
|
||||
final int randomTickSpeed = level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
|
||||
ObjectArrayList<CompletableFuture<LongOpenHashSet>> ticked = new ObjectArrayList<>(regionCount);
|
||||
|
||||
for (final RegionData region : regions) {
|
||||
if (region == null || region.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ticked.add(tick(region, randomTickSpeed));
|
||||
}
|
||||
|
||||
CompletableFuture.runAsync(() -> {
|
||||
finishTicking(ticked, randomTickSpeed, raw, tickPair);
|
||||
spawns.join();
|
||||
}, REGION_EXECUTOR).join();
|
||||
}
|
||||
|
||||
private CompletableFuture<LongOpenHashSet> tick(RegionData region, int randomTickSpeed) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
ObjectArrayList<LevelChunk> regionChunks = new ObjectArrayList<>(region.chunks().size());
|
||||
LongOpenHashSet regionChunksIDs = new LongOpenHashSet(region.chunks().size());
|
||||
for (long key : region.chunks()) {
|
||||
LevelChunk chunk = fullChunks.get(key);
|
||||
if (chunk != null) {
|
||||
regionChunks.add(chunk);
|
||||
regionChunksIDs.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (LevelChunk chunk : regionChunks) {
|
||||
level.tickChunk(chunk, randomTickSpeed);
|
||||
}
|
||||
for (Entity entity : region.entities()) {
|
||||
tickEntity(entity);
|
||||
}
|
||||
|
||||
return regionChunksIDs;
|
||||
}, REGION_EXECUTOR);
|
||||
}
|
||||
|
||||
private void finishTicking(final ObjectArrayList<CompletableFuture<LongOpenHashSet>> ticked, final int randomTickSpeed, final LevelChunk[] raw, final TickPair tickPair) {
|
||||
try {
|
||||
CompletableFuture.allOf(ticked.toArray(new CompletableFuture[0])).join();
|
||||
} catch (CompletionException ex) {
|
||||
LOGGER.error("Error during region chunk ticking", ex.getCause());
|
||||
}
|
||||
|
||||
LongOpenHashSet tickedChunkKeys = new LongOpenHashSet(raw.length);
|
||||
|
||||
for (CompletableFuture<LongOpenHashSet> future : ticked) {
|
||||
if (!future.isCompletedExceptionally()) {
|
||||
try {
|
||||
LongOpenHashSet regionChunks = future.join();
|
||||
tickedChunkKeys.addAll(regionChunks);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Exception in region ticking future", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (LevelChunk chunk : raw) {
|
||||
if (!tickedChunkKeys.contains(chunk.coordinateKey)) {
|
||||
level.tickChunk(chunk, randomTickSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
for (Entity entity : tickPair.entities()) {
|
||||
tickEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private TickPair computePlayerRegionsParallel() {
|
||||
int tickViewDistance = level.moonrise$getViewDistanceHolder().getViewDistances().tickViewDistance();
|
||||
List<ServerPlayer> players = new ArrayList<>(level.players());
|
||||
int max = maxChunksForViewDistance();
|
||||
|
||||
List<LongOpenHashSet> playerChunkSets = players.parallelStream()
|
||||
.map(player -> {
|
||||
ChunkPos playerChunk = player.chunkPosition();
|
||||
int px = playerChunk.x;
|
||||
int pz = playerChunk.z;
|
||||
LongOpenHashSet chunkKeys = new LongOpenHashSet(max);
|
||||
for (int dx = -tickViewDistance; dx <= tickViewDistance; dx++) {
|
||||
for (int dz = -tickViewDistance; dz <= tickViewDistance; dz++) {
|
||||
long key = CoordinateUtils.getChunkKey(px + dx, pz + dz);
|
||||
chunkKeys.add(key);
|
||||
}
|
||||
}
|
||||
return chunkKeys;
|
||||
}).toList();
|
||||
|
||||
List<LongOpenHashSet> mergedRegions = new ArrayList<>();
|
||||
boolean[] merged = new boolean[playerChunkSets.size()];
|
||||
|
||||
for (int i = 0; i < playerChunkSets.size(); i++) {
|
||||
if (merged[i]) continue;
|
||||
|
||||
LongOpenHashSet region = new LongOpenHashSet(playerChunkSets.get(i));
|
||||
merged[i] = true;
|
||||
|
||||
boolean madeChanges;
|
||||
do {
|
||||
madeChanges = false;
|
||||
for (int j = i + 1; j < playerChunkSets.size(); j++) {
|
||||
if (merged[j]) continue;
|
||||
|
||||
LongOpenHashSet set = playerChunkSets.get(j);
|
||||
|
||||
boolean hasIntersection = false;
|
||||
LongIterator iter = set.iterator();
|
||||
while (iter.hasNext()) {
|
||||
if (region.contains(iter.nextLong())) {
|
||||
hasIntersection = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasIntersection) {
|
||||
region.addAll(set);
|
||||
merged[j] = true;
|
||||
madeChanges = true;
|
||||
}
|
||||
}
|
||||
} while (madeChanges);
|
||||
|
||||
mergedRegions.add(region);
|
||||
}
|
||||
|
||||
ObjectArrayList<RegionData> regions = new ObjectArrayList<>();
|
||||
Long2IntOpenHashMap chunkToRegion = new Long2IntOpenHashMap(max * mergedRegions.size());
|
||||
chunkToRegion.defaultReturnValue(-1);
|
||||
for (int i = 0; i < mergedRegions.size(); i++) {
|
||||
regions.add(new RegionData(mergedRegions.get(i), new ObjectOpenHashSet<>()));
|
||||
for (long key : mergedRegions.get(i)) {
|
||||
chunkToRegion.put(key, i);
|
||||
}
|
||||
}
|
||||
|
||||
final Set<Entity> firstTick = new ObjectOpenHashSet<>();
|
||||
|
||||
synchronized (getEntityTickList().entities) {
|
||||
final IteratorSafeOrderedReferenceSet.Iterator<Entity> iterator = getEntityTickList().entities.iterator();
|
||||
try {
|
||||
while (iterator.hasNext()) {
|
||||
Entity entity = iterator.next();
|
||||
long chunkKey = entity.chunkPosition().longKey;
|
||||
int regionIndex = chunkToRegion.get(chunkKey);
|
||||
if (regionIndex != -1) {
|
||||
regions.get(regionIndex).entities().add(entity);
|
||||
} else {
|
||||
firstTick.add(entity);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
iterator.finishedIterating();
|
||||
}
|
||||
}
|
||||
|
||||
return new TickPair(regions.toArray(new RegionData[0]), firstTick);
|
||||
}
|
||||
|
||||
// Should be max safe estimate of ticking chunks in a region
|
||||
private int maxChunksForViewDistance() {
|
||||
ViewDistances distances = level.moonrise$getViewDistanceHolder().getViewDistances();
|
||||
int diameter = 2 * distances.tickViewDistance() + 1;
|
||||
return diameter * diameter;
|
||||
}
|
||||
|
||||
private void tickEntity(Entity entity) {
|
||||
if (!entity.isRemoved()) {
|
||||
if (!level.tickRateManager().isEntityFrozen(entity)) {
|
||||
entity.checkDespawn();
|
||||
// Paper - rewrite chunk system
|
||||
Entity vehicle = entity.getVehicle();
|
||||
if (vehicle != null) {
|
||||
if (!vehicle.isRemoved() && vehicle.hasPassenger(entity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
entity.stopRiding();
|
||||
}
|
||||
|
||||
level.guardEntityTick(level::tickNonPassenger, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.bxteam.divinemc.async.rct;
|
||||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
record TickPair(RegionData[] regions, Set<Entity> entities) { }
|
||||
@@ -221,6 +221,7 @@ public class DivineConfig {
|
||||
|
||||
// Async mob spawning settings
|
||||
public static boolean enableAsyncSpawning = true;
|
||||
public static boolean asyncNaturalSpawn = true;
|
||||
|
||||
public static void load() {
|
||||
parallelWorldTicking();
|
||||
@@ -335,6 +336,8 @@ public class DivineConfig {
|
||||
private static void asyncMobSpawning() {
|
||||
enableAsyncSpawning = getBoolean(ConfigCategory.ASYNC.key("mob-spawning.enable"), enableAsyncSpawning,
|
||||
"Enables optimization that will offload much of the computational effort involved with spawning new mobs to a different thread.");
|
||||
asyncNaturalSpawn = getBoolean(ConfigCategory.ASYNC.key("async-ticking-of-natural-spawns"), asyncNaturalSpawn,
|
||||
"Enables offloading of natural spawning to a different thread");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user