diff --git a/patches/server/0020-Multithreaded-Tracker.patch b/patches/server/0020-Multithreaded-Tracker.patch index c31207d3..3a5210f6 100644 --- a/patches/server/0020-Multithreaded-Tracker.patch +++ b/patches/server/0020-Multithreaded-Tracker.patch @@ -30,134 +30,3 @@ index d217994b16f2f749fe48fe0b895416e0ae02eee4..46233c5845cffb67d89f360c4dfdcc80 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 entityTickingChunks; -+ private final AtomicInteger taskIndex = new AtomicInteger(); -+ -+ private final ConcurrentLinkedQueue mainThreadTasks; -+ private final AtomicInteger finishedTasks = new AtomicInteger(); -+ -+ public MultithreadedTracker(IteratorSafeOrderedReferenceSet entityTickingChunks, ConcurrentLinkedQueue 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); -+ } -+ } -+ } -+ */ -+ } -+}