mirror of
https://github.com/LeavesMC/Leaves.git
synced 2025-12-23 08:59:31 +00:00
164 lines
6.4 KiB
Diff
164 lines
6.4 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: violetc <58360096+s-yh-china@users.noreply.github.com>
|
|
Date: Sun, 14 Aug 2022 00:39:45 +0800
|
|
Subject: [PATCH] Multithreaded Tracker
|
|
|
|
This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish)
|
|
|
|
diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
|
|
index d217994b16f2f749fe48fe0b895416e0ae02eee4..46233c5845cffb67d89f360c4dfdcc80abdf00c8 100644
|
|
--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java
|
|
+++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
|
|
@@ -246,6 +246,20 @@ public final class LeavesConfig {
|
|
dontSendUselessEntityPackets = getBoolean("settings.performance.dont-send-useless-entity-packets", dontSendUselessEntityPackets);
|
|
}
|
|
|
|
+ public static boolean asyncEntityTracker = false;
|
|
+ private static boolean asyncEntityTrackerLock = false;
|
|
+ private static void asyncEntityTracker() {
|
|
+ if (!asyncEntityTrackerLock) {
|
|
+ asyncEntityTracker = getBoolean("settings.performance.async-entity-tracker", asyncEntityTracker);
|
|
+ asyncEntityTrackerLock = true;
|
|
+ }
|
|
+
|
|
+ if (asyncEntityTracker) {
|
|
+ asyncEntityTracker = false;
|
|
+ LeavesLogger.LOGGER.severe("Async EntityTracker is updating, it can't work");
|
|
+ }
|
|
+ }
|
|
+
|
|
public static final class WorldConfig {
|
|
|
|
public final String worldName;
|
|
diff --git a/src/main/java/top/leavesmc/leaves/tracker/MultithreadedTracker.java b/src/main/java/top/leavesmc/leaves/tracker/MultithreadedTracker.java
|
|
new file mode 100644
|
|
index 0000000000000000000000000000000000000000..559daa0150e395921d110efc63c477be0248ad25
|
|
--- /dev/null
|
|
+++ b/src/main/java/top/leavesmc/leaves/tracker/MultithreadedTracker.java
|
|
@@ -0,0 +1,125 @@
|
|
+package top.leavesmc.leaves.tracker;
|
|
+
|
|
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|
+import io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet;
|
|
+import io.papermc.paper.world.ChunkEntitySlices;
|
|
+import net.minecraft.server.MinecraftServer;
|
|
+import net.minecraft.server.level.ChunkMap;
|
|
+import net.minecraft.world.entity.Entity;
|
|
+import net.minecraft.world.level.chunk.LevelChunk;
|
|
+
|
|
+import java.util.concurrent.ConcurrentLinkedQueue;
|
|
+import java.util.concurrent.Executor;
|
|
+import java.util.concurrent.Executors;
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
+
|
|
+// Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish)
|
|
+public class MultithreadedTracker {
|
|
+
|
|
+ private static final int parallelism = Math.max(4, Runtime.getRuntime().availableProcessors());
|
|
+ private static final Executor trackerExecutor = Executors.newFixedThreadPool(parallelism, new ThreadFactoryBuilder()
|
|
+ .setNameFormat("puff-tracker-%d")
|
|
+ .setPriority(Thread.NORM_PRIORITY - 2)
|
|
+ .build());
|
|
+
|
|
+ private final IteratorSafeOrderedReferenceSet<LevelChunk> entityTickingChunks;
|
|
+ private final AtomicInteger taskIndex = new AtomicInteger();
|
|
+
|
|
+ private final ConcurrentLinkedQueue<Runnable> mainThreadTasks;
|
|
+ private final AtomicInteger finishedTasks = new AtomicInteger();
|
|
+
|
|
+ public MultithreadedTracker(IteratorSafeOrderedReferenceSet<LevelChunk> entityTickingChunks, ConcurrentLinkedQueue<Runnable> mainThreadTasks) {
|
|
+ this.entityTickingChunks = entityTickingChunks;
|
|
+ this.mainThreadTasks = mainThreadTasks;
|
|
+ }
|
|
+
|
|
+ public void tick() {
|
|
+ int iterator = this.entityTickingChunks.createRawIterator();
|
|
+
|
|
+ if (iterator == -1) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ try {
|
|
+ this.taskIndex.set(iterator);
|
|
+ this.finishedTasks.set(0);
|
|
+
|
|
+ for (int i = 0; i < parallelism; i++) {
|
|
+ trackerExecutor.execute(this::run);
|
|
+ }
|
|
+
|
|
+ while (this.taskIndex.get() < this.entityTickingChunks.getListSize()) {
|
|
+ this.runMainThreadTasks();
|
|
+ this.handleTasks(5); // assist
|
|
+ }
|
|
+
|
|
+ while (this.finishedTasks.get() != parallelism) {
|
|
+ this.runMainThreadTasks();
|
|
+ }
|
|
+
|
|
+ this.runMainThreadTasks(); // finish any remaining tasks
|
|
+ } finally {
|
|
+ this.entityTickingChunks.finishRawIterator();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void runMainThreadTasks() {
|
|
+ try {
|
|
+ Runnable task;
|
|
+ while ((task = this.mainThreadTasks.poll()) != null) {
|
|
+ task.run();
|
|
+ }
|
|
+ } catch (Throwable throwable) {
|
|
+ MinecraftServer.LOGGER.warn("Tasks failed while ticking track queue", throwable);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private void run() {
|
|
+ try {
|
|
+ while (handleTasks(10));
|
|
+ } finally {
|
|
+ this.finishedTasks.incrementAndGet();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private boolean handleTasks(int tasks) {
|
|
+ int index;
|
|
+ while ((index = this.taskIndex.getAndAdd(tasks)) < this.entityTickingChunks.getListSize()) {
|
|
+ for (int i = index; i < index + tasks && i < this.entityTickingChunks.getListSize(); i++) {
|
|
+ LevelChunk chunk = this.entityTickingChunks.rawGet(i);
|
|
+ if (chunk != null) {
|
|
+ try {
|
|
+ this.processChunk(chunk);
|
|
+ } catch (Throwable throwable) {
|
|
+ MinecraftServer.LOGGER.warn("Ticking tracker failed", throwable);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ private void processChunk(LevelChunk chunk) {
|
|
+ /* Updating DISABLE THIS
|
|
+ final ChunkEntitySlices entitySlices = chunk.level.entityManager.entitySliceManager.getChunk(chunk.locX, chunk.locZ);
|
|
+ if (entitySlices == null) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ final Entity[] rawEntities = entitySlices.entities.getRawData();
|
|
+ final ChunkMap chunkMap = chunk.level.chunkSource.chunkMap;
|
|
+
|
|
+ for (int i = 0; i < rawEntities.length; i++) {
|
|
+ Entity entity = rawEntities[i];
|
|
+ if (entity != null) {
|
|
+ ChunkMap.TrackedEntity entityTracker = chunkMap.entityMap.get(entity.getId());
|
|
+ if (entityTracker != null) {
|
|
+ entityTracker.updatePlayers(entityTracker.entity.getPlayersInTrackRange());
|
|
+ this.mainThreadTasks.offer(entityTracker.serverEntity::sendChanges);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ */
|
|
+ }
|
|
+}
|