9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-22 16:29:23 +00:00

regionized chunk ticking

This commit is contained in:
NONPLAYT
2025-02-24 20:55:34 +03:00
parent 4232332e79
commit 1ed5e090a8
3 changed files with 148 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Mon, 24 Feb 2025 19:58:39 +0300
Subject: [PATCH] Regionized Chunk Ticking
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
index 2678bf59d557f085c7265e2f3eb038647723d35e..ee4e5462c784ea8588c12eb2b248c708c4d84bee 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -56,6 +56,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
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.DivineConfig.regionizedChunkTickingExecutorThreadCount, new org.bxteam.divinemc.util.NamedAgnosticThreadFactory<>("region_ticking", ca.spottedleaf.moonrise.common.util.TickThread::new, org.bxteam.divinemc.DivineConfig.regionizedChunkTickingExecutorThreadPriority)); // DivineMC - Regionized Chunk Ticking
public final Thread mainThread;
final ThreadedLevelLightEngine lightEngine;
public final ServerChunkCache.MainThreadExecutor mainThreadProcessor;
@@ -479,6 +480,41 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
}
// CraftBukkit end
+ // DivineMC start - Regionized Chunk Ticking
+ private static final int[] DX = {1, -1, 0, 0, 1, -1, -1, 1};
+ private static final int[] DZ = {0, 0, 1, -1, 1, 1, -1, -1};
+
+ private List<List<LevelChunk>> splitChunksIntoRegions(List<LevelChunk> chunks) {
+ Set<LevelChunk> chunkSet = new java.util.HashSet<>(chunks);
+ Set<LevelChunk> visited = new java.util.HashSet<>(chunks.size());
+ List<List<LevelChunk>> groups = new ArrayList<>();
+
+ for (LevelChunk chunk : chunks) {
+ if (visited.contains(chunk)) continue;
+
+ List<LevelChunk> group = new ArrayList<>(64);
+ java.util.ArrayDeque<net.minecraft.world.level.chunk.LevelChunk> stack = new java.util.ArrayDeque<>();
+ stack.push(chunk);
+ visited.add(chunk);
+
+ while (!stack.isEmpty()) {
+ LevelChunk current = stack.pop();
+ group.add(current);
+
+ for (int i = 0; i < 8; i++) {
+ LevelChunk neighbor = getChunk(current.locX + DX[i], current.locZ + DZ[i], false);
+ if (neighbor == null || !chunkSet.contains(neighbor) || !visited.add(neighbor)) continue;
+ stack.push(neighbor);
+ }
+ }
+
+ groups.add(group);
+ }
+
+ return groups;
+ }
+ // DivineMC end - Regionized Chunk Ticking
+
@Override
public void tick(BooleanSupplier hasTimeLeft, boolean tickChunks) {
ProfilerFiller profilerFiller = Profiler.get();
@@ -519,7 +555,27 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
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
- this.tickChunks(profilerFiller, l, list);
+ // DivineMC start - Regionized Chunk Ticking
+ if (org.bxteam.divinemc.DivineConfig.enableRegionizedChunkTicking) {
+ List<List<LevelChunk>> regions = splitChunksIntoRegions(list);
+ List<CompletableFuture<Void>> futures = new ArrayList<>();
+ for (List<LevelChunk> region : regions) {
+ CompletableFuture<Void> future = new CompletableFuture<>();
+ futures.add(future);
+ REGION_EXECUTOR.execute(() -> {
+ try {
+ tickChunks(profilerFiller, l, region);
+ } finally {
+ future.complete(null);
+ }
+ });
+ }
+ CompletableFuture<Void> finalFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
+ finalFuture.join();
+ } else {
+ this.tickChunks(profilerFiller, l, list);
+ }
+ // DivineMC end - Regionized Chunk Ticking
profilerFiller.pop();
} finally {
list.clear();

View File

@@ -246,6 +246,24 @@ public class DivineConfig {
"modpacks where many structure mods are using very high weight values in their template pools.");
}
public static boolean enableRegionizedChunkTicking = false;
public static int regionizedChunkTickingExecutorThreadCount = 4;
public static int regionizedChunkTickingExecutorThreadPriority = Thread.NORM_PRIORITY;
private static void regionizedChunkTicking() {
enableRegionizedChunkTicking = getBoolean("settings.regionized-chunk-ticking.enable", enableRegionizedChunkTicking,
"Enables regionized chunk ticking. This feature is similar to Folia");
regionizedChunkTickingExecutorThreadCount = getInt("settings.regionized-chunk-ticking.executor-thread-count", regionizedChunkTickingExecutorThreadCount,
"The amount of threads to allocate to regionized chunk ticking.");
regionizedChunkTickingExecutorThreadPriority = getInt("settings.regionized-chunk-ticking.executor-thread-priority", regionizedChunkTickingExecutorThreadPriority,
"Configures the thread priority of the executor");
if (regionizedChunkTickingExecutorThreadCount < 1 || regionizedChunkTickingExecutorThreadCount > 10) {
LOGGER.warn("Invalid regionized chunk ticking thread count: " + regionizedChunkTickingExecutorThreadCount + ", resetting to default (5)");
regionizedChunkTickingExecutorThreadCount = 5;
}
}
public static boolean skipUselessSecondaryPoiSensor = true;
public static boolean clumpOrbs = true;
public static boolean ignoreMovedTooQuicklyWhenLagging = true;

View File

@@ -0,0 +1,41 @@
package org.bxteam.divinemc.util;
import com.mojang.logging.LogUtils;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
public class NamedAgnosticThreadFactory<T extends Thread> implements ThreadFactory {
private static final Logger LOGGER = LogUtils.getLogger();
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
private final ThreadBuilderFunction<T> typeOfThread;
private final int priority;
public NamedAgnosticThreadFactory(String name, ThreadBuilderFunction<T> typeOfThread, int priority) {
this.typeOfThread = typeOfThread;
this.priority = priority;
this.group = Thread.currentThread().getThreadGroup();
this.namePrefix = name + "-";
}
@Override
public Thread newThread(@NotNull Runnable runnable) {
T thread = typeOfThread.apply(this.group, runnable, this.namePrefix + this.threadNumber.getAndIncrement());
thread.setUncaughtExceptionHandler((threadx, throwable) -> {
LOGGER.error("Caught exception in thread {} from {}", threadx, runnable);
LOGGER.error("", throwable);
});
if (thread.getPriority() != priority) {
thread.setPriority(priority);
}
return thread;
}
public interface ThreadBuilderFunction<T extends Thread> {
T apply(ThreadGroup threadGroup, Runnable runnable, String name);
}
}