From 8f7bce1e31ec76283563714a003b9fdde466c9a2 Mon Sep 17 00:00:00 2001
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
Date: Sun, 27 Oct 2024 14:00:06 -0700
Subject: [PATCH] Execute spark tasks during tick sleep (#11525)

---
 patches/server/Bundle-spark.patch | 32 ++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

diff --git a/patches/server/Bundle-spark.patch b/patches/server/Bundle-spark.patch
index 74f8eb1acd..08b8705859 100644
--- a/patches/server/Bundle-spark.patch
+++ b/patches/server/Bundle-spark.patch
@@ -34,6 +34,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +import io.papermc.paper.util.MCUtil;
 +import java.util.Collection;
 +import java.util.List;
++import java.util.concurrent.ConcurrentLinkedQueue;
 +import java.util.logging.Level;
 +import java.util.logging.Logger;
 +import me.lucko.spark.paper.api.Compatibility;
@@ -59,11 +60,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +    private final Logger logger;
 +    private final PaperSparkModule spark;
++    private final ConcurrentLinkedQueue<Runnable> mainThreadTaskQueue;
 +
 +    private boolean enabled;
 +    private boolean disabledInConfigurationWarningLogged;
 +
 +    public SparksFly(final Server server) {
++        this.mainThreadTaskQueue = new ConcurrentLinkedQueue<>();
 +        this.logger = Logger.getLogger(ID);
 +        this.logger.log(Level.INFO, "This server bundles the spark profiler. For more information please visit https://docs.papermc.io/paper/profiling");
 +        this.spark = PaperSparkModule.create(Compatibility.VERSION_1_0, server, this.logger, new PaperScheduler() {
@@ -74,7 +77,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +
 +            @Override
 +            public void executeSync(final Runnable runnable) {
-+                MCUtil.ensureMain(this.catching(runnable, "synchronous"));
++                SparksFly.this.mainThreadTaskQueue.offer(this.catching(runnable, "synchronous"));
 +            }
 +
 +            private Runnable catching(final Runnable runnable, final String type) {
@@ -111,6 +114,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
 +        });
 +    }
 +
++    public void executeMainThreadTasks() {
++        Runnable task;
++        while ((task = this.mainThreadTaskQueue.poll()) != null) {
++            task.run();
++        }
++    }
++
 +    public void enableEarlyIfRequested() {
 +        if (!isPluginPreferred() && shouldEnableImmediately()) {
 +            this.enable();
@@ -299,6 +309,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
              org.spigotmc.WatchdogThread.hasStarted = true; // Paper
 @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
              }
+ 
+             if (this.emptyTicks >= j) {
++                this.server.spark.tickStart(); // Paper - spark
+                 if (this.emptyTicks == j) {
+                     MinecraftServer.LOGGER.info("Server empty for {} seconds, pausing", this.pauseWhileEmptySeconds());
+                     this.autoSave();
+                 }
+ 
+                 this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit
++                this.server.spark.executeMainThreadTasks(); // Paper - spark
+                 this.tickConnection();
++                this.server.spark.tickEnd(((double)(System.nanoTime() - lastTick) / 1000000D)); // Paper - spark
+                 return;
+             }
          }
  
 +        this.server.spark.tickStart(); // Paper - spark
@@ -306,6 +330,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
          ++this.tickCount;
          this.tickRateManager.tick();
 @@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
+         ProfilerFiller gameprofilerfiller = Profiler.get();
+ 
+         this.runAllTasks(); // Paper - move runAllTasks() into full server tick (previously for timings)
++        this.server.spark.executeMainThreadTasks(); // Paper - spark
+         // Paper start - Server Tick Events
+         long endTime = System.nanoTime();
          long remaining = (TICK_TIME - (endTime - lastTick)) - catchupTime;
          new com.destroystokyo.paper.event.server.ServerTickEndEvent(this.tickCount, ((double)(endTime - lastTick) / 1000000D), remaining).callEvent();
          // Paper end - Server Tick Events