From 4a2cab24bc38109d8bffdbaa2366add32c2bbac0 Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:14:32 +0200 Subject: [PATCH 01/21] Update DedicatedServer.java --- .../src/main/java/net/minecraft/server/DedicatedServer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/DedicatedServer.java b/WindSpigot-Server/src/main/java/net/minecraft/server/DedicatedServer.java index b51e8c07..3e94a9e1 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/DedicatedServer.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/DedicatedServer.java @@ -42,8 +42,8 @@ public class DedicatedServer extends MinecraftServer implements IMinecraftServer private boolean s; // CraftBukkit start - Signature changed - public DedicatedServer(joptsimple.OptionSet options, Thread thread1) { // WindSpigot - backport modern tick loop - super(options, Proxy.NO_PROXY, DedicatedServer.a, thread1); + public DedicatedServer(joptsimple.OptionSet options) { + super(options, Proxy.NO_PROXY, DedicatedServer.a); // CraftBukkit end if (!WindSpigotConfig.disableInfiniSleeperThreadUsage) { Thread thread = new Thread("Server Infinisleeper") { From 4fea4af3d4dfb8244d5be0cc8c144b5453557c6d Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:14:51 +0200 Subject: [PATCH 02/21] Create IAsyncTaskHandler.java --- .../minecraft/server/IAsyncTaskHandler.java | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandler.java diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandler.java b/WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandler.java new file mode 100644 index 00000000..2f9b58a6 --- /dev/null +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandler.java @@ -0,0 +1,109 @@ +package net.minecraft.server; + +import io.papermc.paper.util.linkedqueue.CachedSizeConcurrentLinkedQueue; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Queue; +import java.util.concurrent.locks.LockSupport; +import java.util.function.BooleanSupplier; + +public abstract class IAsyncTaskHandler { + + public static final long BLOCK_TIME_NANOS = 100000L; + private static final Logger LOGGER = LogManager.getLogger(); + private final String name; + private final Queue pendingTasks = new CachedSizeConcurrentLinkedQueue<>(); // Paper - Make size() constant-time + private int blockingCount; + + protected IAsyncTaskHandler(final String name) { + this.name = name; + } + + public static boolean isNonRecoverable(final Throwable t) { + return t instanceof ReportedException ? isNonRecoverable(t.getCause()) : t instanceof OutOfMemoryError || t instanceof StackOverflowError; + } + + protected abstract R wrapRunnable(final Runnable runnable); + + protected abstract boolean shouldRun(final R task); + + public boolean isMainThread() { + return Thread.currentThread() == this.aM(); + } // Poor name, just to maintain compatibility + + protected abstract Thread aM(); // Poor name, just to maintain compatibility + + protected boolean scheduleExecutables() { + return !this.isMainThread(); + } + + public String name() { + return this.name; + } + + public void schedule(final R task) { + this.pendingTasks.add(task); + LockSupport.unpark(aM()); + } + + public void execute(final Runnable command) { + R task = this.wrapRunnable(command); + if (this.scheduleExecutables()) { + this.schedule(task); + } else { + this.doRunTask(task); + } + } + + public void postToMainThread(final Runnable runnable) { + execute(runnable); + } + + protected void runAllTasks() { + while (this.pollTask()) { + } + } + + protected boolean pollTask() { + R task = this.pendingTasks.peek(); + if (task == null) { + return false; + } else if (this.blockingCount == 0 && !shouldRun(task)) { + return false; + } else { + this.doRunTask(this.pendingTasks.remove()); + return true; + } + } + + public void managedBlock(final BooleanSupplier condition) { + this.blockingCount++; + + try { + while (!condition.getAsBoolean()) { + if (!this.pollTask()) { + this.waitForTasks(); + } + } + } finally { + this.blockingCount--; + } + } + + protected void waitForTasks() { + Thread.yield(); + LockSupport.parkNanos("waiting for tasks", BLOCK_TIME_NANOS); + } + + protected void doRunTask(final R task) { + try { + task.run(); + } catch (Exception e) { + LOGGER.fatal("Error executing task on {}", this.name, e); + if (isNonRecoverable(e)) { + throw e; + } + } + } +} From dd60a494a8e1847bca11ce230fda7970e865fbcd Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:15:01 +0200 Subject: [PATCH 03/21] Create IAsyncTaskHandlerReentrant.java --- .../server/IAsyncTaskHandlerReentrant.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandlerReentrant.java diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandlerReentrant.java b/WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandlerReentrant.java new file mode 100644 index 00000000..fd7fc857 --- /dev/null +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandlerReentrant.java @@ -0,0 +1,30 @@ +package net.minecraft.server; + +public abstract class IAsyncTaskHandlerReentrant extends IAsyncTaskHandler { + + private int reentrantCount; + + public IAsyncTaskHandlerReentrant(final String name) { + super(name); + } + + @Override + protected boolean scheduleExecutables() { + return this.runningTask() || super.scheduleExecutables(); + } + + protected boolean runningTask() { + return this.reentrantCount > 0; + } + + @Override + protected void doRunTask(final R task) { + this.reentrantCount++; + + try { + super.doRunTask(task); + } finally { + this.reentrantCount--; + } + } +} From 312f55a1dd60b69615d6f962a67af9c578ea3b9a Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:15:09 +0200 Subject: [PATCH 04/21] Create TickTask.java --- .../java/net/minecraft/server/TickTask.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 WindSpigot-Server/src/main/java/net/minecraft/server/TickTask.java diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/TickTask.java b/WindSpigot-Server/src/main/java/net/minecraft/server/TickTask.java new file mode 100644 index 00000000..d9ac24c0 --- /dev/null +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/TickTask.java @@ -0,0 +1,21 @@ +package net.minecraft.server; + +public class TickTask implements Runnable { + + private final int tick; + private final Runnable runnable; + + public TickTask(final int tick, final Runnable runnable) { + this.tick = tick; + this.runnable = runnable; + } + + public int getTick() { + return tick; + } + + @Override + public void run() { + this.runnable.run(); + } +} From 68a37ef4d3513b6a75226867d18a18adf80aa24b Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:15:31 +0200 Subject: [PATCH 05/21] Update Main.java --- .../java/org/bukkit/craftbukkit/Main.java | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/WindSpigot-Server/src/main/java/org/bukkit/craftbukkit/Main.java b/WindSpigot-Server/src/main/java/org/bukkit/craftbukkit/Main.java index f90f1ee7..52fa91b8 100644 --- a/WindSpigot-Server/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/WindSpigot-Server/src/main/java/org/bukkit/craftbukkit/Main.java @@ -14,8 +14,6 @@ import joptsimple.OptionParser; import joptsimple.OptionSet; -import net.minecraft.server.DedicatedServer; -import net.minecraft.server.DispenserRegistry; import net.minecraft.server.MinecraftServer; public class Main { @@ -198,29 +196,7 @@ public static void main(String[] args) { // while // loading System.out.println("Loading libraries, please wait..."); - - DispenserRegistry.c(); - OptionSet finalOptions = options; - - DedicatedServer server = MinecraftServer.spin(thread -> { - DedicatedServer dedicatedserver = new DedicatedServer(finalOptions, thread); - - if (finalOptions.has("port")) { - int port = (Integer) finalOptions.valueOf("port"); - if (port > 0) { - dedicatedserver.setPort(port); - } - } - - if (finalOptions.has("universe")) { - dedicatedserver.universe = (File) finalOptions.valueOf("universe"); - } - - if (finalOptions.has("world")) { - dedicatedserver.setWorld((String) finalOptions.valueOf("world")); - } - return dedicatedserver; - }); + MinecraftServer.main(options); } catch (Throwable t) { t.printStackTrace(); } From 30b894bb4ae8f8b4459cb8582cc5c42a3777e933 Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:22:45 +0200 Subject: [PATCH 06/21] Update MinecraftServer.java --- .../net/minecraft/server/MinecraftServer.java | 362 ++++++++++-------- 1 file changed, 196 insertions(+), 166 deletions(-) diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java b/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java index ef5f9a28..df90e196 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java @@ -11,20 +11,14 @@ import java.util.Collections; import java.util.Date; import java.util.List; -import java.util.Queue; import java.util.UUID; import java.util.concurrent.Callable; -import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; -import java.util.function.BooleanSupplier; -import java.util.function.Function; import javax.imageio.ImageIO; -import io.papermc.paper.util.linkedqueue.CachedSizeConcurrentLinkedQueue; import org.apache.commons.lang3.Validate; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -32,9 +26,6 @@ import com.google.common.base.Charsets; import com.google.common.collect.Lists; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListenableFutureTask; import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfileRepository; import com.mojang.authlib.minecraft.MinecraftSessionService; @@ -42,8 +33,6 @@ import com.windpvp.windspigot.WindSpigot; import com.windpvp.windspigot.config.WindSpigotConfig; import com.windpvp.windspigot.statistics.StatisticsClient; -import com.windpvp.windspigot.tickloop.ReentrantIAsyncHandler; -import com.windpvp.windspigot.tickloop.TasksPerTick; import com.windpvp.windspigot.world.WorldTickManager; import co.aikar.timings.SpigotTimings; // Spigot @@ -65,7 +54,7 @@ // WindSpigot start import net.openhft.affinity.AffinityLock; -public abstract class MinecraftServer extends ReentrantIAsyncHandler implements ICommandListener, IAsyncTaskHandler, IMojangStatistics { +public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant implements Runnable, ICommandListener, IAsyncTaskHandler, IMojangStatistics { // PandaSpigot - Modern Tick Loop public static final Logger LOGGER = LogManager.getLogger(); public static final File a = new File("usercache.json"); @@ -120,9 +109,9 @@ public int getServerPort() { private long X = 0L; private final GameProfileRepository Y; private final UserCache Z; - protected final Queue> j = new CachedSizeConcurrentLinkedQueue<>(); // Spigot, PAIL: Rename // Paper - Make size() constant-time + // protected final Queue> j = new CachedSizeConcurrentLinkedQueue<>(); // Spigot, PAIL: Rename // Paper - Make size() constant-time // PandaSpigot - IAsyncTaskHandler handles this now private Thread serverThread; - private long ab = az(); + private long ab = getNanoTime(); // PandaSpigot - Modern Tick Loop // CraftBukkit start public List worlds = Lists.newCopyOnWriteArrayList(); @@ -137,36 +126,23 @@ public int getServerPort() { public java.util.Queue priorityProcessQueue = new java.util.concurrent.ConcurrentLinkedQueue(); // WindSpigot public int autosavePeriod; // CraftBukkit end + // PandaSpigot start - Modern Tick Loop + private static final long OVERLOADED_THRESHOLD_NANOS = 20L * TimeUnit.SECONDS.toNanos(1L) / 20L; + private static final int OVERLOADED_TICKS_THRESHOLD = 20; + private static final long OVERLOADED_WARNING_INTERVAL_NANOS = 10L * TimeUnit.SECONDS.toNanos(1L); + private static final int OVERLOADED_TICKS_WARNING_INTERVAL = 100; + private static final long NANOSECONDS_PER_TICK = TimeUnit.SECONDS.toNanos(1L) / 20L; + private static final long NANOSECONDS_MILLI_PER_MILLISECOND = TimeUnit.MILLISECONDS.toNanos(1L); + private boolean mayHaveDelayedTasks; + private long delayedTasksMaxNextTickTime; + private boolean waitingForNextTick = false; + // PandaSpigot end // WindSpigot - MSPT for tps command private double lastMspt; - // WindSpigot start - backport modern tick loop - private long nextTickTime; - private long delayedTasksMaxNextTickTime; - private boolean mayHaveDelayedTasks; - private boolean forceTicks; - private volatile boolean isReady; - private long lastOverloadWarning; - public long serverStartTime; - public volatile Thread shutdownThread; // Paper - - public static S spin(Function serverFactory) { - AtomicReference reference = new AtomicReference<>(); - Thread thread = new Thread(() -> reference.get().run(), "Server thread"); - - thread.setUncaughtExceptionHandler((thread1, throwable) -> MinecraftServer.LOGGER.error(throwable)); - S server = serverFactory.apply(thread); // CraftBukkit - decompile error - - reference.set(server); - thread.setPriority(Thread.NORM_PRIORITY + 2); // Paper - boost priority - thread.start(); - return server; - } - // WindSpigot end - - public MinecraftServer(OptionSet options, Proxy proxy, File file1, Thread thread) { - super("Server"); // WindSpigot - backport modern tick loop + public MinecraftServer(OptionSet options, Proxy proxy, File file1) { + super("Server"); // PandaSpigot - Modern Tick Loop io.netty.util.ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED); // [Nacho-0040] Change // deprecated Netty @@ -183,12 +159,6 @@ public MinecraftServer(OptionSet options, Proxy proxy, File file1, Thread thread this.V = new YggdrasilAuthenticationService(proxy, UUID.randomUUID().toString()); this.W = this.V.createMinecraftSessionService(); this.Y = this.V.createProfileRepository(); - - // WindSpigot start - backport modern tick loop - this.nextTickTime = getMillis(); - this.serverThread = thread; - this.primaryThread = thread; - // WindSpigot end // CraftBukkit start this.options = options; @@ -215,6 +185,8 @@ public MinecraftServer(OptionSet options, Proxy proxy, File file1, Thread thread } } Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this)); + + this.serverThread = primaryThread = new Thread(this, "Server thread"); // Moved from main } public abstract PropertyManager getPropertyManager(); @@ -582,14 +554,11 @@ public void safeShutdown() { } // Paper start - Further improve server tick loop + private long lastTick = 0; // PandaSpigot - Modern Tick Loop private static final int TPS = 20; private static final long SEC_IN_NANO = 1000000000; private static final long TICK_TIME = SEC_IN_NANO / TPS; private static final long MAX_CATCHUP_BUFFER = TICK_TIME * TPS * 60L; - // WindSpigot start - backport modern tick loop - private long lastTick = 0; - private long catchupTime = 0; - // WindSpigot end private static final int SAMPLE_INTERVAL = 20; public final RollingAverage tps1 = new RollingAverage(60); public final RollingAverage tps5 = new RollingAverage(60 * 5); @@ -599,43 +568,47 @@ public void safeShutdown() { public static class RollingAverage { private final int size; private long time; - private java.math.BigDecimal total; + private java.math.BigDecimal total; // PandaSpigot - Use BigDecimal to improve accuracy of TPS results private int index = 0; - private final java.math.BigDecimal[] samples; + private final java.math.BigDecimal[] samples; // PandaSpigot - Use BigDecimal to improve accuracy of TPS results private final long[] times; RollingAverage(int size) { this.size = size; this.time = size * SEC_IN_NANO; + // PandaSpigot start - Use BigDecimal to improve accuracy of TPS results this.total = dec(TPS).multiply(dec(SEC_IN_NANO)).multiply(dec(size)); this.samples = new java.math.BigDecimal[size]; + // PandaSpigot end this.times = new long[size]; for (int i = 0; i < size; i++) { - this.samples[i] = dec(TPS); + this.samples[i] = dec(TPS); // PandaSpigot - Use BigDecimal to improve accuracy of TPS results this.times[i] = SEC_IN_NANO; } } + // PandaSpigot start - Use BigDecimal to improve accuracy of TPS results private static java.math.BigDecimal dec(long t) { return new java.math.BigDecimal(t); } public void add(java.math.BigDecimal x, long t) { + // PandaSpigot end time -= times[index]; - total = total.subtract(samples[index].multiply(dec(times[index]))); + total = total.subtract(samples[index].multiply(dec(times[index]))); // PandaSpigot - Use BigDecimal to improve accuracy of TPS results samples[index] = x; times[index] = t; time += t; - total = total.add(x.multiply(dec(t))); + total = total.add(x.multiply(dec(t))); // PandaSpigot - Use BigDecimal to improve accuracy of TPS results if (++index == size) { index = 0; } } public double getAverage() { - return total.divide(dec(time), 30, java.math.RoundingMode.HALF_UP).doubleValue(); + return total.divide(dec(time), 30, java.math.RoundingMode.HALF_UP).doubleValue(); // PandaSpigot - Use BigDecimal to improve accuracy of TPS results } } - private static final java.math.BigDecimal TPS_BASE = new java.math.BigDecimal(1E9).multiply(new java.math.BigDecimal(SAMPLE_INTERVAL)); + private static final java.math.BigDecimal TPS_BASE = new java.math.BigDecimal(1E9).multiply(new java.math.BigDecimal(SAMPLE_INTERVAL)); // PandaSpigot - Use BigDecimal to improve accuracy of TPS results // Paper End private AffinityLock lock = null; @@ -645,11 +618,11 @@ public AffinityLock getLock() { return this.lock; } + @Override public void run() { // Don't disable statistics if server failed to start boolean disableStatistics = false; try { - serverStartTime = getNanos(); // Paper if (this.init()) { //WindSpigot - statistics disableStatistics = true; @@ -678,7 +651,7 @@ public void run() { // WindSpigot - parallel worlds this.worldTickerManager = new WorldTickManager(); - this.ab = az(); + this.ab = getNanoTime(); // PandaSpigot - Modern Tick Loop this.r.setMOTD(new ChatComponentText(this.motd)); this.r.setServerInfo(new ServerPing.ServerData("1.8.8", 47)); this.a(this.r); @@ -686,24 +659,56 @@ public void run() { // Spigot start // PaperSpigot start - Further improve tick loop Arrays.fill(recentTps, 20); - long start = System.nanoTime(), curTime, tickSection = start; // Paper - Further improve server tick loop - lastTick = start - TICK_TIME; + // PandaSpigot start - Modern Tick Loop + long start = getNanoTime(), curTime, tickSection = start; + lastTick = start - TICK_TIME; + // PandaSpigot end // PaperSpigot end while (this.isRunning) { - long i = ((curTime = System.nanoTime()) / (1000L * 1000L)) - this.nextTickTime; // Paper - if (i > 5000L && this.nextTickTime - this.lastOverloadWarning >= 30000L && ticks > 500) { // CraftBukkit // WindSpigot - prevent display of overload on first 500 ticks - long j = i / 50L; - if (this.server.getWarnOnOverload()) // CraftBukkit - MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", i, j); - this.nextTickTime += j * 50L; - this.lastOverloadWarning = this.nextTickTime; + // PandaSpigot start - Modern Tick Loop + long behindTime = (curTime = getNanoTime()) - this.ab; + if (behindTime > OVERLOADED_THRESHOLD_NANOS + OVERLOADED_TICKS_THRESHOLD * NANOSECONDS_PER_TICK && this.ab - this.R >= OVERLOADED_WARNING_INTERVAL_NANOS + OVERLOADED_TICKS_WARNING_INTERVAL * NANOSECONDS_PER_TICK) { + long behindTicks = behindTime / NANOSECONDS_PER_TICK; + if (server.getWarnOnOverload()) { // CraftBukkit + LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", behindTime / NANOSECONDS_MILLI_PER_MILLISECOND, behindTicks); + } + this.ab += behindTicks * NANOSECONDS_PER_TICK; + this.R = this.ab; + } + /* + curTime = System.nanoTime(); + // PaperSpigot start - Further improve tick loop + wait = TICK_TIME - (curTime - lastTick); + if (wait > 0) { + // TacoSpigot start - fix the tick loop improvements + if (catchupTime < 2E6) { + wait += Math.abs(catchupTime); + } else if (wait < catchupTime) { + catchupTime -= wait; + wait = 0; + } else { + wait -= catchupTime; + catchupTime = 0; + } + // TacoSpigot end } + if (wait > 0) { - if (++MinecraftServer.currentTick % MinecraftServer.SAMPLE_INTERVAL == 0) { + Thread.sleep(wait / 1000000); + + curTime = System.nanoTime(); + wait = TICK_TIME - (curTime - lastTick); + } + + catchupTime = Math.min(MAX_CATCHUP_BUFFER, catchupTime - wait); + */ + // PandaSpigot end + + if (++MinecraftServer.currentTick % SAMPLE_INTERVAL == 0) { final long diff = curTime - tickSection; //double currentTps = 1E9 / diff * SAMPLE_INTERVAL; - java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP); + java.math.BigDecimal currentTps = TPS_BASE.divide(new java.math.BigDecimal(diff), 30, java.math.RoundingMode.HALF_UP); // PandaSpigot - Use BigDecimal to improve accuracy of TPS results tps1.add(currentTps, diff); tps5.add(currentTps, diff); @@ -717,15 +722,16 @@ public void run() { } lastTick = curTime; - this.nextTickTime += 50L; - this.methodProfiler.a("tick"); // push - this.A(this::haveTime); - this.methodProfiler.c("nextTickWait"); // popPush + // PandaSpigot start - Modern Tick Loop + this.ab += NANOSECONDS_PER_TICK; + + this.A(); this.mayHaveDelayedTasks = true; - this.delayedTasksMaxNextTickTime = Math.max(getMillis() + 50L, this.nextTickTime); + this.delayedTasksMaxNextTickTime = Math.max(getNanoTime() + NANOSECONDS_PER_TICK, this.ab); this.waitUntilNextTick(); - this.methodProfiler.b(); // pop - this.isReady = true; + // PandaSpigot end + + this.Q = true; } // Spigot end @@ -811,78 +817,50 @@ public void run() { } - // WindSpigot start - backport modern tick loop - private boolean haveTime() { - // CraftBukkit start - if (isOversleep) return canOversleep();// Paper - because of our changes, this logic is broken - return this.forceTicks || this.runningTask() || getMillis() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTime : this.nextTickTime); - } - // Paper start - boolean isOversleep = false; - private boolean canOversleep() { - return this.mayHaveDelayedTasks && getMillis() < this.delayedTasksMaxNextTickTime; + // PandaSpigot start - Modern Tick Loop + public long getNanoTime() { + return System.nanoTime(); } - private boolean canSleepForTickNoOversleep() { - return this.forceTicks || this.runningTask() || getMillis() < this.nextTickTime; + private boolean haveTime() { + return this.runningTask() || getNanoTime() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTime : this.ab); } - // Paper end - private void executeModerately() { - this.runAllRunnable(); - LockSupport.parkNanos("executing tasks", 1000L); - } - // CraftBukkit end protected void waitUntilNextTick() { - this.controlTerminate(() -> !this.canSleepForTickNoOversleep()); - } - @Override - protected TasksPerTick packUpRunnable(Runnable runnable) { - // Paper start - anything that does try to post to main during watchdog crash, run on watchdog - if (this.hasStopped && Thread.currentThread().equals(shutdownThread)) { - runnable.run(); - runnable = () -> {}; + // this.runAllTasks(); // PandaSpigot - Moved this into the tick method for timings + this.waitingForNextTick = true; + + try { + this.managedBlock(() -> !this.haveTime()); + } finally { + this.waitingForNextTick = false; } - // Paper end - return new TasksPerTick(this.ticks, runnable); } @Override - protected boolean shouldRun(TasksPerTick task) { - return task.getTick() + 3 < this.ticks || this.haveTime(); + protected void waitForTasks() { + long waitTime = this.waitingForNextTick ? this.ab - getNanoTime() : IAsyncTaskHandler.BLOCK_TIME_NANOS; + LockSupport.parkNanos("waiting for tasks", waitTime); } - @Override - public boolean drawRunnable() { - boolean flag = this.pollTaskInternal(); - - this.mayHaveDelayedTasks = flag; - return flag; + public TickTask wrapRunnable(final Runnable runnable) { + return new TickTask(this.ticks, runnable); } - // TODO: WorldServer ticker - private boolean pollTaskInternal() { - if (super.drawRunnable()) { - return true; - } else { - if (this.haveTime()) { - -// for (WorldServer worldserver : this.worldServer) { -// if (worldserver.chunkProviderServer.pollTask()) { -// return true; -// } -// } - } + protected boolean shouldRun(final TickTask task) { + return task.getTick() + 3 < this.ticks || haveTime(); + } - return false; - } + @Override + protected boolean pollTask() { + return this.mayHaveDelayedTasks = super.pollTask(); } @Override - public Thread getMainThread() { - return serverThread; + public boolean scheduleExecutables() { + return super.scheduleExecutables() /*&& !this.isStopped*/; // CraftBukkit - Fix MC-142590 } - // WindSpigot end + // PandaSpigot end private void a(ServerPing serverping) { File file = this.d("server-icon.png"); @@ -924,21 +902,10 @@ protected void a(CrashReport crashreport) { protected void z() { } - // WindSpigot - backport modern tick loop - protected void A(BooleanSupplier shouldKeepTicking) throws ExceptionWorldConflict { // CraftBukkit - added throws + protected void A() throws ExceptionWorldConflict { // CraftBukkit - added throws co.aikar.timings.TimingsManager.FULL_SERVER_TICK.startTiming(); // Spigot - - // WindSpigot start - backport modern tick loop - long i = getNanos(); - - // Paper start - move oversleep into full server tick - isOversleep = true; - this.controlTerminate(() -> !this.canOversleep()); - isOversleep = false; - // Paper end - + long i = getNanoTime(); this.server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.ticks+1)); // Paper - // WindSpigot end ++this.ticks; if (this.T) { @@ -983,18 +950,9 @@ protected void A(BooleanSupplier shouldKeepTicking) throws ExceptionWorldConflic this.methodProfiler.b(); SpigotTimings.worldSaveTimer.stopTiming(); // Spigot } - - // WindSpigot start - backport modern tick loop - // Paper start - long endTime = System.nanoTime(); - long remaining = (TICK_TIME - (endTime - lastTick)) - catchupTime; - this.lastMspt = ((double) (endTime - lastTick) / 1000000D); - this.server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerTickEndEvent(this.ticks, this.lastMspt, remaining)); - // Paper end - // WindSpigot end this.methodProfiler.a("tallying"); - this.h[this.ticks % 100] = System.nanoTime() - i; + this.h[this.ticks % 100] = getNanoTime() - i; this.methodProfiler.b(); // this.methodProfiler.a("snooper"); // if (false && getSnooperEnabled() && !this.n.d() && this.ticks > 100) { // Spigot @@ -1008,12 +966,20 @@ protected void A(BooleanSupplier shouldKeepTicking) throws ExceptionWorldConflic // this.methodProfiler.b(); this.methodProfiler.b(); org.spigotmc.WatchdogThread.tick(); // Spigot + // Paper start + long endTime = getNanoTime(); + long remaining = (TICK_TIME - (endTime - lastTick)); + this.lastMspt = ((double) (endTime - lastTick) / 1000000D); + this.server.getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerTickEndEvent(this.ticks, this.lastMspt, remaining)); + // Paper end co.aikar.timings.TimingsManager.FULL_SERVER_TICK.stopTiming(); // Spigot } private WorldTickManager worldTickerManager; public void B() { + // PandaSpigot start - IAsyncTaskHandler handles this now + /* SpigotTimings.minecraftSchedulerTimer.startTiming(); // Spigot this.methodProfiler.a("jobs"); @@ -1024,6 +990,9 @@ public void B() { SystemUtils.a(entry, MinecraftServer.LOGGER); } // Spigot end + */ + this.runAllTasks(); // Moved from waitUntilNextTick() for timings + // PandaSpigot end SpigotTimings.minecraftSchedulerTimer.stopTiming(); // Spigot this.methodProfiler.c("levels"); @@ -1112,6 +1081,75 @@ public void a(IUpdatePlayerListBox iupdateplayerlistbox) { this.p.add(iupdateplayerlistbox); } + public static void main(final OptionSet options) { // CraftBukkit - replaces main(String[] astring) + DispenserRegistry.c(); + + try { + /* + * CraftBukkit start - Replace everything boolean flag = true; String s = null; + * String s1 = "."; String s2 = null; boolean flag1 = false; boolean flag2 = + * false; int i = -1; + * + * for (int j = 0; j < astring.length; ++j) { String s3 = astring[j]; String s4 + * = j == astring.length - 1 ? null : astring[j + 1]; boolean flag3 = false; + * + * if (!s3.equals("nogui") && !s3.equals("--nogui")) { if (s3.equals("--port") + * && s4 != null) { flag3 = true; + * + * try { i = Integer.parseInt(s4); } catch (NumberFormatException + * numberformatexception) { ; } } else if (s3.equals("--singleplayer") && s4 != + * null) { flag3 = true; s = s4; } else if (s3.equals("--universe") && s4 != + * null) { flag3 = true; s1 = s4; } else if (s3.equals("--world") && s4 != null) + * { flag3 = true; s2 = s4; } else if (s3.equals("--demo")) { flag1 = true; } + * else if (s3.equals("--bonusChest")) { flag2 = true; } } else { flag = false; + * } + * + * if (flag3) { ++j; } } + * + * final DedicatedServer dedicatedserver = new DedicatedServer(new File(s1)); + * + * if (s != null) { dedicatedserver.i(s); } + * + * if (s2 != null) { dedicatedserver.setWorld(s2); } + * + * if (i >= 0) { dedicatedserver.setPort(i); } + * + * if (flag1) { dedicatedserver.b(true); } + * + * if (flag2) { dedicatedserver.c(true); } + * + * if (flag && !GraphicsEnvironment.isHeadless()) { dedicatedserver.aQ(); } + * + * dedicatedserver.D(); Runtime.getRuntime().addShutdownHook(new + * Thread("Server Shutdown Thread") { public void run() { + * dedicatedserver.stop(); } }); + */ + + DedicatedServer dedicatedserver = new DedicatedServer(options); + + if (options.has("port")) { + int port = (Integer) options.valueOf("port"); + if (port > 0) { + dedicatedserver.setPort(port); + } + } + + if (options.has("universe")) { + dedicatedserver.universe = (File) options.valueOf("universe"); + } + + if (options.has("world")) { + dedicatedserver.setWorld((String) options.valueOf("world")); + } + + dedicatedserver.primaryThread.start(); + // CraftBukkit end + } catch (Exception exception) { + MinecraftServer.LOGGER.fatal("Failed to start the minecraft server", exception); + } + + } + public void C() { /* * CraftBukkit start - prevent abuse this.serverThread = new Thread(this, @@ -1582,19 +1620,9 @@ public Proxy ay() { return this.e; } - // WindSpigot start - backport modern tick loo public static long az() { - return getMillis(); + return System.currentTimeMillis(); } - - public static long getMillis() { - return getNanos() / 1000000L; - } - - public static long getNanos() { - return System.nanoTime(); // Paper - } - // WindSpigot end public int getIdleTimeout() { return this.G; @@ -1667,6 +1695,7 @@ public int aI() { return 29999984; } + /* // PandaSpigot start - IAsyncTaskHandler handles this now public ListenableFuture a(Callable callable) { Validate.notNull(callable); if (!this.isMainThread()) { // CraftBukkit && !this.isStopped()) { @@ -1696,6 +1725,7 @@ public ListenableFuture postToMainThread(Runnable runnable) { public boolean isMainThread() { return Thread.currentThread() == this.serverThread; } + */ // PandaSpigot start public int aK() { return 256; From 9373643c015646f51e0005a51d5616329e3ecb6f Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:22:53 +0200 Subject: [PATCH 07/21] Update Packet.java --- .../src/main/java/net/minecraft/server/Packet.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/Packet.java b/WindSpigot-Server/src/main/java/net/minecraft/server/Packet.java index 03e9eb23..a4d1e51a 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/Packet.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/Packet.java @@ -8,8 +8,4 @@ public interface Packet { void b(PacketDataSerializer var1) throws IOException; void a(T var1); - - default boolean instant() { - return false; - } } From d504f3aa1f0d5e6a7d3a62cf072e570ac03f84eb Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:23:10 +0200 Subject: [PATCH 08/21] Update PlayerConnectionUtils.java --- .../net/minecraft/server/PlayerConnectionUtils.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/PlayerConnectionUtils.java b/WindSpigot-Server/src/main/java/net/minecraft/server/PlayerConnectionUtils.java index 5a291abc..2cbc46c9 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/PlayerConnectionUtils.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/PlayerConnectionUtils.java @@ -1,9 +1,14 @@ package net.minecraft.server; public class PlayerConnectionUtils { - public static void ensureMainThread(final Packet packet, final T listener, - IAsyncTaskHandler handler) throws CancelledPacketHandleException { - if (!packet.instant() && !handler.isMainThread()) { + // PandaSpigot start - Redirect to MinecraftServer so that IAsyncTaskHandler can handle it + public static void ensureMainThread(final Packet packet, final T listener, WorldServer worldServer) throws CancelledPacketHandleException { + ensureMainThread(packet, listener, worldServer.getMinecraftServer()); + } + + public static void ensureMainThread(final Packet packet, final T listener, IAsyncTaskHandler handler) throws CancelledPacketHandleException { + // PandaSpigot end + if (!handler.isMainThread()) { handler.postToMainThread(() -> packet.a(listener)); throw CancelledPacketHandleException.INSTANCE; } From f7e434f2c767b62b5162a4032f1e56983e90d5db Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:23:41 +0200 Subject: [PATCH 09/21] Update WorldServer.java --- .../src/main/java/net/minecraft/server/WorldServer.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java b/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java index a24ad904..d53e025d 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java @@ -23,12 +23,11 @@ import com.google.common.base.Predicate; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.util.concurrent.ListenableFuture; import com.windpvp.windspigot.async.entitytracker.AsyncEntityTracker; import com.windpvp.windspigot.config.WindSpigotConfig; import com.windpvp.windspigot.world.WorldTicker; -public class WorldServer extends World implements IAsyncTaskHandler { +public class WorldServer extends World /*implements IAsyncTaskHandler*/ { // PandaSpigot - Redirect to MinecraftServer so that IAsyncTaskHandler can handle it private static final Logger a = LogManager.getLogger(); private final MinecraftServer server; @@ -1319,6 +1318,7 @@ public Entity getEntity(UUID uuid) { return this.entitiesByUUID.get(uuid); } + /* // PandaSpigot start - Redirect to MinecraftServer so that IAsyncTaskHandler can handle it @Override public ListenableFuture postToMainThread(Runnable runnable) { return this.server.postToMainThread(runnable); @@ -1328,6 +1328,7 @@ public ListenableFuture postToMainThread(Runnable runnable) { public boolean isMainThread() { return this.server.isMainThread(); } + */ // PandaSpigot end static class BlockActionDataList extends ArrayList { From b903fc3e68cfb114a14676471cc51862a0be2016 Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:24:17 +0200 Subject: [PATCH 10/21] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 202642cf..d5fcb63c 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ See the patches list below. [PandaSpigot-0112] Fix MC-120567: Bed portal crash [PandaSpigot-0107] Fix GH-276: Item durability desync when some events are cancelled [PandaSpigot-0031] Add missing InventoryView.getSlotType API +[PandaSpigot-0104] Backport modern tick loop system [Spigot-0097] Remove DataWatcher Locking by spottedleaf [Spigot-0138] Branchless NibbleArray by md5 From 53d39227daf6dc6af52e17c2e4306994669cc2e5 Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:31:34 +0200 Subject: [PATCH 11/21] actually redirect WorldServer --- .../main/java/net/minecraft/server/WorldServer.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java b/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java index d53e025d..a07247c0 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/WorldServer.java @@ -1318,17 +1318,15 @@ public Entity getEntity(UUID uuid) { return this.entitiesByUUID.get(uuid); } - /* // PandaSpigot start - Redirect to MinecraftServer so that IAsyncTaskHandler can handle it - @Override - public ListenableFuture postToMainThread(Runnable runnable) { - return this.server.postToMainThread(runnable); + // PandaSpigot start - Redirect to MinecraftServer so that IAsyncTaskHandler can handle it + public void postToMainThread(Runnable runnable) { + this.server.postToMainThread(runnable); } - @Override public boolean isMainThread() { return this.server.isMainThread(); } - */ // PandaSpigot end + // PandaSpigot end static class BlockActionDataList extends ArrayList { From 773504970476a78e215b7c3d88c4a9a10cd35394 Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:34:16 +0200 Subject: [PATCH 12/21] Update Packet.java --- .../src/main/java/net/minecraft/server/Packet.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/Packet.java b/WindSpigot-Server/src/main/java/net/minecraft/server/Packet.java index a4d1e51a..03e9eb23 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/Packet.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/Packet.java @@ -8,4 +8,8 @@ public interface Packet { void b(PacketDataSerializer var1) throws IOException; void a(T var1); + + default boolean instant() { + return false; + } } From 9341f928d26e433149315d05fc915c25599732d5 Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:34:57 +0200 Subject: [PATCH 13/21] Update PlayerConnectionUtils.java --- .../main/java/net/minecraft/server/PlayerConnectionUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/PlayerConnectionUtils.java b/WindSpigot-Server/src/main/java/net/minecraft/server/PlayerConnectionUtils.java index 2cbc46c9..f9e46d09 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/PlayerConnectionUtils.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/PlayerConnectionUtils.java @@ -8,7 +8,7 @@ public static void ensureMainThread(final Packet p public static void ensureMainThread(final Packet packet, final T listener, IAsyncTaskHandler handler) throws CancelledPacketHandleException { // PandaSpigot end - if (!handler.isMainThread()) { + if (!packet.instant() && !handler.isMainThread()) { handler.postToMainThread(() -> packet.a(listener)); throw CancelledPacketHandleException.INSTANCE; } From 8bbf418cc61ae140b4c171d83f2aeef43b94a3fe Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 02:36:33 +0200 Subject: [PATCH 14/21] Update MinecraftServer.java --- .../src/main/java/net/minecraft/server/MinecraftServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java b/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java index df90e196..7a675ab5 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java @@ -54,7 +54,7 @@ // WindSpigot start import net.openhft.affinity.AffinityLock; -public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant implements Runnable, ICommandListener, IAsyncTaskHandler, IMojangStatistics { // PandaSpigot - Modern Tick Loop +public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant implements Runnable, ICommandListener, IMojangStatistics { // PandaSpigot - Modern Tick Loop public static final Logger LOGGER = LogManager.getLogger(); public static final File a = new File("usercache.json"); From 37dc40393fedca891a4a6630b918215599cb0b42 Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 03:03:35 +0200 Subject: [PATCH 15/21] Delete IAsyncHandler.java --- .../windspigot/tickloop/IAsyncHandler.java | 141 ------------------ 1 file changed, 141 deletions(-) delete mode 100644 WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/IAsyncHandler.java diff --git a/WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/IAsyncHandler.java b/WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/IAsyncHandler.java deleted file mode 100644 index 649f368b..00000000 --- a/WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/IAsyncHandler.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.windpvp.windspigot.tickloop; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.Queue; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.Executor; -import java.util.concurrent.locks.LockSupport; -import java.util.function.BooleanSupplier; -import java.util.function.Supplier; - -public abstract class IAsyncHandler implements Executor { - private static final Logger LOGGER = LogManager.getLogger(); - private final String name; - private final Queue pendingRunnables = new ConcurrentLinkedQueue<>(); - private int terminateCount; - - protected IAsyncHandler(String name) { - this.name = name; - } - - protected abstract R packUpRunnable(Runnable runnable); - - protected abstract boolean shouldRun(R task); - - public boolean isMainThread() { - return Thread.currentThread() == this.getMainThread(); - } - - protected abstract Thread getMainThread(); - - protected boolean executables() { - return !this.isMainThread(); - } - - public int getPendingRunnables() { - return this.pendingRunnables.size(); - } - - public String getName() { - return this.name; - } - - public CompletableFuture submit(Supplier task) { - return this.executables() ? CompletableFuture.supplyAsync(task, this) - : CompletableFuture.completedFuture(task.get()); - } - - private CompletableFuture submitAsync(Runnable runnable) { - return CompletableFuture.supplyAsync(() -> { - runnable.run(); - return null; - }, this); - } - - public CompletableFuture submit(Runnable task) { - if (this.executables()) { - return this.submitAsync(task); - } else { - task.run(); - return CompletableFuture.completedFuture(null); - } - } - - public void performBlocking(Runnable runnable) { - if (!this.isMainThread()) { - this.submitAsync(runnable).join(); - } else { - runnable.run(); - } - - } - - public void call(R runnable) { - this.pendingRunnables.add(runnable); - LockSupport.unpark(this.getMainThread()); - } - - @Override - public void execute(Runnable runnable) { - if (this.executables()) { - this.call(this.packUpRunnable(runnable)); - } else { - runnable.run(); - } - - } - - protected void clearAllRunnable() { - this.pendingRunnables.clear(); - } - - public void runAllRunnable() { - while (this.drawRunnable()) { - } - } - - public boolean drawRunnable() { - R runnable = this.pendingRunnables.peek(); - if (runnable == null) { - return false; - } else if (this.terminateCount == 0 && !this.shouldRun(runnable)) { - return false; - } else { - this.doRunnable(this.pendingRunnables.remove()); - return true; - } - } - - public void controlTerminate(BooleanSupplier stopCondition) { - ++this.terminateCount; - - try { - while (!stopCondition.getAsBoolean()) { - if (!this.drawRunnable()) { - this.waitForRuns(); - } - } - } finally { - --this.terminateCount; - } - - } - - protected void waitForRuns() { - Thread.yield(); - LockSupport.parkNanos("waiting for tasks", 100000L); - } - - protected void doRunnable(R task) { - try { - task.run(); - } catch (Exception e) { - if (e.getCause() instanceof ThreadDeath) throw e; - LOGGER.fatal("Error executing task on {}", this.getName(), e); - } - - } -} \ No newline at end of file From c9b39410913063245ba7c1d0a7711b3854209739 Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 03:03:41 +0200 Subject: [PATCH 16/21] Delete ReentrantIAsyncHandler.java --- .../tickloop/ReentrantIAsyncHandler.java | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/ReentrantIAsyncHandler.java diff --git a/WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/ReentrantIAsyncHandler.java b/WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/ReentrantIAsyncHandler.java deleted file mode 100644 index 3cd77492..00000000 --- a/WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/ReentrantIAsyncHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.windpvp.windspigot.tickloop; - -public abstract class ReentrantIAsyncHandler extends IAsyncHandler { - - private int count; - - public ReentrantIAsyncHandler(String name) { - super(name); - } - - @Override - protected boolean executables() { - return this.runningTask() || super.executables(); - } - - protected boolean runningTask() { - return this.count != 0; - } - - @Override - protected void doRunnable(R task) { - ++this.count; - try { - super.doRunnable(task); - } finally { - --this.count; - } - } -} \ No newline at end of file From 1c4753c6560150aacb71b921c821ec7481a9d2b2 Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 03:03:49 +0200 Subject: [PATCH 17/21] Delete TasksPerTick.java --- .../windspigot/tickloop/TasksPerTick.java | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/TasksPerTick.java diff --git a/WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/TasksPerTick.java b/WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/TasksPerTick.java deleted file mode 100644 index 6104ca3f..00000000 --- a/WindSpigot-Server/src/main/java/com/windpvp/windspigot/tickloop/TasksPerTick.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.windpvp.windspigot.tickloop; - -public class TasksPerTick implements Runnable { - private final int tick; - private final Runnable task; - - public TasksPerTick(int creationTicks, Runnable task) { - this.tick = creationTicks; - this.task = task; - } - - public int getTick() { - return tick; - } - - @Override - public void run() { - task.run(); - } -} \ No newline at end of file From e78a39a6fd2bb5652b8c645b9c6fe00ce2076bda Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 03:42:27 +0200 Subject: [PATCH 18/21] Update IAsyncTaskHandler.java --- .../src/main/java/net/minecraft/server/IAsyncTaskHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandler.java b/WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandler.java index 2f9b58a6..2413e320 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandler.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/IAsyncTaskHandler.java @@ -1,6 +1,6 @@ package net.minecraft.server; -import io.papermc.paper.util.linkedqueue.CachedSizeConcurrentLinkedQueue; +import com.google.common.collect.Queues; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -13,7 +13,7 @@ public abstract class IAsyncTaskHandler { public static final long BLOCK_TIME_NANOS = 100000L; private static final Logger LOGGER = LogManager.getLogger(); private final String name; - private final Queue pendingTasks = new CachedSizeConcurrentLinkedQueue<>(); // Paper - Make size() constant-time + private final Queue pendingTasks = Queues.newConcurrentLinkedQueue(); private int blockingCount; protected IAsyncTaskHandler(final String name) { From 85c7496f7bfa42a003eead5cd39dcf13381dff9e Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 03:42:44 +0200 Subject: [PATCH 19/21] Delete CachedSizeConcurrentLinkedQueue.java --- .../CachedSizeConcurrentLinkedQueue.java | 31 ------------------- 1 file changed, 31 deletions(-) delete mode 100644 WindSpigot-Server/src/main/java/io/papermc/paper/util/linkedqueue/CachedSizeConcurrentLinkedQueue.java diff --git a/WindSpigot-Server/src/main/java/io/papermc/paper/util/linkedqueue/CachedSizeConcurrentLinkedQueue.java b/WindSpigot-Server/src/main/java/io/papermc/paper/util/linkedqueue/CachedSizeConcurrentLinkedQueue.java deleted file mode 100644 index 5f59b67b..00000000 --- a/WindSpigot-Server/src/main/java/io/papermc/paper/util/linkedqueue/CachedSizeConcurrentLinkedQueue.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.papermc.paper.util.linkedqueue; - -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.LongAdder; - -public class CachedSizeConcurrentLinkedQueue extends ConcurrentLinkedQueue { - private final LongAdder cachedSize = new LongAdder(); - - @Override - public boolean add(E e) { - boolean result = super.add(e); - if (result) { - cachedSize.increment(); - } - return result; - } - - @Override - public E poll() { - E result = super.poll(); - if (result != null) { - cachedSize.decrement(); - } - return result; - } - - @Override - public int size() { - return cachedSize.intValue(); - } -} \ No newline at end of file From 6d0b0a04985972b0d83e953417c3f5d246886538 Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 03:44:10 +0200 Subject: [PATCH 20/21] [skip] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d5fcb63c..7aa1e1aa 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,6 @@ See the patches list below. [SportPaper-0201] Cache block break animation packet [SportPaper-0203] Fix Teleport Invisibility [SportPaper-0204] Optimize toLegacyData removing unneeded sanity checks -[SportPaper-0108] Optimize Network Queue [SportPaper-0260] Migrate from Trove to fastutil [PaperBin-????] WorldServer#everyoneDeeplySleeping optimization From 5dc0e17fa0321a6eff129b4a1422d9aa852b997e Mon Sep 17 00:00:00 2001 From: Elias Date: Tue, 25 Aug 2026 13:56:13 +0200 Subject: [PATCH 21/21] Update MinecraftServer.java --- .../src/main/java/net/minecraft/server/MinecraftServer.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java b/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java index 7a675ab5..1d565377 100644 --- a/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/WindSpigot-Server/src/main/java/net/minecraft/server/MinecraftServer.java @@ -978,11 +978,10 @@ protected void A() throws ExceptionWorldConflict { // CraftBukkit - added throws private WorldTickManager worldTickerManager; public void B() { - // PandaSpigot start - IAsyncTaskHandler handles this now - /* SpigotTimings.minecraftSchedulerTimer.startTiming(); // Spigot this.methodProfiler.a("jobs"); - + // PandaSpigot start - IAsyncTaskHandler handles this now + /* // Spigot start FutureTask entry; int count = this.j.size();