diff --git a/Spigot-Server-Patches/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch b/Spigot-Server-Patches/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch index 5d5af73742..a10b773bce 100644 --- a/Spigot-Server-Patches/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch +++ b/Spigot-Server-Patches/Implement-Chunk-Priority-Urgency-System-for-Chunks.patch @@ -182,24 +182,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + AsyncCatcher.catchOp("ChunkMapDistance::addPriorityTicket"); + long pair = coords.pair(); + PlayerChunk updatingChunk = chunkMap.getUpdatingChunk(pair); -+ if (updatingChunk != null && updatingChunk.priorityBoost >= priority) { -+ return true; -+ } ++ + boolean success; + if (!(success = updatePriorityTicket(coords, ticketType, priority))) { + Ticket ticket = new Ticket(ticketType, PRIORITY_TICKET_LEVEL, coords); + ticket.priority = priority; + success = this.addTicket(pair, ticket); -+ } -+ -+ chunkMap.world.getChunkProvider().tickDistanceManager(); -+ if (updatingChunk == null) { -+ updatingChunk = chunkMap.getUpdatingChunk(pair); -+ } -+ if (updatingChunk != null && updatingChunk.priorityBoost < priority) { -+ // May not be enqueued, enqueue it if not and tick distance manager ++ } else { ++ if (updatingChunk == null) { ++ updatingChunk = chunkMap.getUpdatingChunk(pair); ++ } + chunkMap.queueHolderUpdate(updatingChunk); + } ++ chunkMap.world.getChunkProvider().tickDistanceManager(); ++ + return success; + } + @@ -211,6 +207,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + for (Ticket ticket : tickets) { + if (ticket.getTicketType() == type) { + // We only support increasing, not decreasing, too complicated ++ ticket.setCurrentTick(this.currentTick); + ticket.priority = Math.max(ticket.priority, priority); + return true; + } @@ -252,48 +249,30 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 return this.addTicket(chunkcoordintpair.pair(), new Ticket<>(ticketType, level, identifier)); // CraftBukkit end @@ -0,0 +0,0 @@ public abstract class ChunkMapDistance { + Ticket ticket = new Ticket<>(TicketType.PLAYER, 33, new ChunkCoordIntPair(i)); // Paper - no-tick view distance if (flag1) { - ChunkMapDistance.this.j.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error +- ChunkMapDistance.this.j.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error - ChunkMapDistance.this.m.execute(() -> { -+ // Paper start - smarter ticket delay based on frustum and distance -+ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet playersNearby = chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(i); -+ // delay ticket add based on distance if > 4, and penalize > 8 more -+ int delay = j < 4 ? 0 : (j > 8 ? 20 + j * 2 : j); -+ if (playersNearby != null && j < 4) { -+ Object[] backingSet = playersNearby.getBackingSet(); -+ BlockPosition chunkPos = new ChunkCoordIntPair(i).asPosition(); -+ double minDist = Double.MAX_VALUE; -+ for (int index = 0, len = backingSet.length; index < len; ++index) { -+ if (!(backingSet[index] instanceof EntityPlayer)) { -+ continue; -+ } -+ EntityPlayer player = (EntityPlayer) backingSet[index]; -+ BlockPosition pointInFront = player.getPointInFront(3 * 16); -+ -+ double dist = MCUtil.distanceSq(pointInFront, chunkPos); -+ if (dist < minDist && dist >= 4*4) { -+ minDist = dist; -+ } -+ } -+ if (minDist < Double.MAX_VALUE) { -+ delay += 10 + Math.sqrt(minDist)*3; -+ } -+ } -+ MCUtil.scheduleTask(delay, () -> { -+ // Paper end - if (this.c(this.c(i))) { +- if (this.c(this.c(i))) { ++ // Paper start - smarter ticket delay based on frustum and distance ++ scheduleChunkLoad(i, MinecraftServer.currentTick, (priority) -> { ++ ChunkMapDistance.this.j.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error ++ if (chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(i) != null && this.c(this.c(i))) { // Copy c(c()) stuff below ++ // Paper end ChunkMapDistance.this.addTicket(i, ticket); ChunkMapDistance.this.l.add(i); -@@ -0,0 +0,0 @@ public abstract class ChunkMapDistance { - - }); + } else { + ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error + }, i, false)); + } +- +- }); }, i, () -> { - return j; -+ int desired = j + chunkMap.getEffectiveViewDistance() >= j ? 20 : 30; // Paper - use less priority for no tick chunks -+ return Math.min(PlayerChunkMap.GOLDEN_TICKET, desired); // Paper - this is based on distance to player for priority, -+ // ensure new no tick tickets arent higher priority than high priority tickets... - })); +- })); ++ return priority; // Paper ++ })); }); } else { ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error ChunkMapDistance.this.m.execute(() -> { @@ -302,6 +281,90 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 }); }, i, true)); } +@@ -0,0 +0,0 @@ public abstract class ChunkMapDistance { + + } + ++ // Paper start - smart scheduling of player tickets ++ public void scheduleChunkLoad(long i, long startTick, java.util.function.Consumer task) { ++ long elapsed = MinecraftServer.currentTick - startTick; ++ PlayerChunk updatingChunk = chunkMap.getUpdatingChunk(i); ++ if ((updatingChunk != null && updatingChunk.isFullChunkReady()) || !this.c(this.c(i))) { // Copied from above ++ // no longer needed ++ task.accept(1); ++ return; ++ } ++ ++ int desireDelay = 0; ++ double minDist = Double.MAX_VALUE; ++ com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet players = chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(i); ++ ChunkCoordIntPair chunkPos = new ChunkCoordIntPair(i); ++ if (players != null) { ++ BlockPosition.PooledBlockPosition pos = BlockPosition.PooledBlockPosition.acquire(); ++ Object[] backingSet = players.getBackingSet(); ++ ++ BlockPosition blockPos = chunkPos.asPosition(); ++ ++ boolean isFront = false; ++ for (int index = 0, len = backingSet.length; index < len; ++index) { ++ if (!(backingSet[index] instanceof EntityPlayer)) { ++ continue; ++ } ++ EntityPlayer player = (EntityPlayer) backingSet[index]; ++ BlockPosition pointInFront = player.getPointInFront(3 * 16).add(0, (int) -player.locY(), 0); ++ pos.setValues(((int) player.locX() >> 4) << 4, 0, ((int) player.locZ() >> 4) << 4); ++ double frontDist = MCUtil.distanceSq(pointInFront, blockPos); ++ double center = MCUtil.distanceSq(pos, blockPos); ++ double dist = Math.min(frontDist, center); ++ if (!isFront) { ++ BlockPosition pointInBack = player.getPointInFront(3 * 16 * -1).add(0, (int) -player.locY(), 0); ++ double backDist = MCUtil.distanceSq(pointInBack, blockPos); ++ if (frontDist < backDist) { ++ isFront = true; ++ } ++ } ++ if (dist < minDist) { ++ minDist = dist; ++ } ++ } ++ pos.close(); ++ if (minDist < Double.MAX_VALUE) { ++ minDist = Math.sqrt(minDist) / 16; ++ if (minDist > 5) { ++ desireDelay += ((isFront ? 15 : 30) * 20) * (minDist / 32); ++ } ++ } ++ } else { ++ desireDelay = 1; ++ } ++ long delay = desireDelay - elapsed; ++ if (delay <= 0 && minDist > 4 && minDist < Double.MAX_VALUE) { ++ boolean hasAnyNeighbor = false; ++ for (int x = -1; x <= 1; x++) { ++ for (int z = -1; z <= 1; z++) { ++ if (x == 0 && z == 0) continue; ++ long pair = new ChunkCoordIntPair(chunkPos.x + x, chunkPos.z + z).pair(); ++ PlayerChunk neighbor = chunkMap.getUpdatingChunk(pair); ++ if (neighbor != null && neighbor.isFullChunkReady()) { ++ hasAnyNeighbor = true; ++ } ++ } ++ } ++ if (!hasAnyNeighbor) { ++ delay += 10; ++ } ++ } ++ if (delay <= 0) { ++ task.accept(Math.min(PlayerChunkMap.GOLDEN_TICKET, minDist < Double.MAX_VALUE ? (int) minDist : 15)); ++ } else { ++ MCUtil.scheduleTask((int) Math.min(delay, 20), () -> scheduleChunkLoad(i, startTick, task), "Player Ticket Delayer"); ++ } ++ } ++ // Paper end ++ + @Override + public void a() { + super.a(); diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -732,6 +795,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return; // unloaded + } + chunkDistanceManager.pendingChunkUpdates.add(playerchunk); ++ if (!chunkDistanceManager.pollingPendingChunkUpdates) { ++ world.getChunkProvider().tickDistanceManager(); ++ } + }; + if (MCUtil.isMainThread()) { + // We can't use executor here because it will not execute tasks if its currently in the middle of executing tasks... @@ -741,8 +807,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } + -+ public boolean isUnloading(PlayerChunk playerchunk) { -+ return playerchunk == null || MCUtil.getChunkStatus(playerchunk) == null || unloadQueue.contains(playerchunk.location.pair()); ++ private boolean isUnloading(PlayerChunk playerchunk) { ++ return playerchunk == null || unloadQueue.contains(playerchunk.location.pair()); + } + + public void checkHighPriorityChunks(EntityPlayer player) { diff --git a/Spigot-Server-Patches/Load-Chunks-for-Login-Asynchronously.patch b/Spigot-Server-Patches/Load-Chunks-for-Login-Asynchronously.patch index 486ebae158..9c8cfb440e 100644 --- a/Spigot-Server-Patches/Load-Chunks-for-Login-Asynchronously.patch +++ b/Spigot-Server-Patches/Load-Chunks-for-Login-Asynchronously.patch @@ -168,7 +168,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + entityplayer, finalWorldserver, networkmanager, playerconnection, + nbttagcompound, networkmanager.getSocketAddress().toString(), lastKnownName + ); -+ playerChunkMap.chunkDistanceManager.removeTicketAtLevel(TicketType.LOGIN, pos, 31, pos.pair()); ++ //playerChunkMap.chunkDistanceManager.removeTicketAtLevel(TicketType.LOGIN, pos, 31, pos.pair()); + }; + }); + } diff --git a/Spigot-Server-Patches/MC-Utils.patch b/Spigot-Server-Patches/MC-Utils.patch index 0edb936d4f..dc4849eed2 100644 --- a/Spigot-Server-Patches/MC-Utils.patch +++ b/Spigot-Server-Patches/MC-Utils.patch @@ -3568,30 +3568,12 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return MinecraftServer.getServer().isMainThread(); + } + -+ private static class DelayedRunnable implements Runnable { -+ -+ private final int ticks; -+ private final Runnable run; -+ -+ private DelayedRunnable(int ticks, Runnable run) { -+ this.ticks = ticks; -+ this.run = run; -+ } -+ -+ @Override -+ public void run() { -+ if (ticks <= 0) { -+ run.run(); -+ } else { -+ scheduleTask(ticks-1, run); -+ } -+ } ++ public static org.bukkit.scheduler.BukkitTask scheduleTask(int ticks, Runnable runnable) { ++ return scheduleTask(ticks, runnable, null); + } + -+ public static void scheduleTask(int ticks, Runnable runnable) { -+ // We use post to main instead of process queue as we don't want to process these mid tick if -+ // Someone uses processQueueWhileWaiting -+ MinecraftServer.getServer().scheduleOnMain(new DelayedRunnable(ticks, runnable)); ++ public static org.bukkit.scheduler.BukkitTask scheduleTask(int ticks, Runnable runnable, String taskName) { ++ return MinecraftServer.getServer().server.getScheduler().scheduleInternalTask(runnable, ticks, taskName); + } + + public static void processQueue() { @@ -4495,6 +4477,194 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 /** * Mirror +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +@@ -0,0 +0,0 @@ import org.bukkit.scheduler.BukkitWorker; + */ + public class CraftScheduler implements BukkitScheduler { + ++ static Plugin MINECRAFT = new MinecraftInternalPlugin(); + /** + * Counter for IDs. Order doesn't matter, only uniqueness. + */ +@@ -0,0 +0,0 @@ public class CraftScheduler implements BukkitScheduler { + runTaskTimer(plugin, (Object) task, delay, period); + } + ++ public BukkitTask scheduleInternalTask(Runnable run, int delay, String taskName) { ++ final CraftTask task = new CraftTask(run, nextId(), taskName); ++ return handle(task, delay); ++ } ++ + public BukkitTask runTaskTimer(Plugin plugin, Object runnable, long delay, long period) { + validate(plugin, runnable); + if (delay < 0L) { +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftTask.java +@@ -0,0 +0,0 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot + CraftTask(final Object task) { + this(null, task, CraftTask.NO_REPEATING, CraftTask.NO_REPEATING); + } ++ // Paper start ++ public String taskName = null; ++ boolean internal = false; ++ CraftTask(final Object task, int id, String taskName) { ++ this.rTask = (Runnable) task; ++ this.cTask = null; ++ this.plugin = CraftScheduler.MINECRAFT; ++ this.taskName = taskName; ++ this.internal = true; ++ this.id = id; ++ this.period = CraftTask.NO_REPEATING; ++ this.taskName = taskName; ++ this.timings = null; // Will be changed in later patch ++ } ++ // Paper end + + CraftTask(final Plugin plugin, final Object task, final int id, final long period) { + this.plugin = plugin; +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/MinecraftInternalPlugin.java b/src/main/java/org/bukkit/craftbukkit/scheduler/MinecraftInternalPlugin.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/MinecraftInternalPlugin.java +@@ -0,0 +0,0 @@ ++package org.bukkit.craftbukkit.scheduler; ++ ++ ++import org.bukkit.Server; ++import org.bukkit.command.Command; ++import org.bukkit.command.CommandSender; ++import org.bukkit.configuration.file.FileConfiguration; ++import org.bukkit.generator.ChunkGenerator; ++import org.bukkit.plugin.PluginBase; ++import org.bukkit.plugin.PluginDescriptionFile; ++import org.bukkit.plugin.PluginLoader; ++import org.bukkit.plugin.PluginLogger; ++ ++import java.io.File; ++import java.io.InputStream; ++import java.util.List; ++ ++public class MinecraftInternalPlugin extends PluginBase { ++ private boolean enabled = true; ++ ++ private final String pluginName; ++ private PluginDescriptionFile pdf; ++ ++ public MinecraftInternalPlugin() { ++ this.pluginName = "Minecraft"; ++ pdf = new PluginDescriptionFile(pluginName, "1.0", "nms"); ++ } ++ ++ public void setEnabled(boolean enabled) { ++ this.enabled = enabled; ++ } ++ ++ @Override ++ public File getDataFolder() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public PluginDescriptionFile getDescription() { ++ return pdf; ++ } ++ ++ @Override ++ public FileConfiguration getConfig() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public InputStream getResource(String filename) { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public void saveConfig() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public void saveDefaultConfig() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public void saveResource(String resourcePath, boolean replace) { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public void reloadConfig() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public PluginLogger getLogger() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public PluginLoader getPluginLoader() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public Server getServer() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public boolean isEnabled() { ++ return enabled; ++ } ++ ++ @Override ++ public void onDisable() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public void onLoad() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public void onEnable() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public boolean isNaggable() { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public void setNaggable(boolean canNag) { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public ChunkGenerator getDefaultWorldGenerator(String worldName, String id) { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++ ++ @Override ++ public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { ++ throw new UnsupportedOperationException("Not supported."); ++ } ++} diff --git a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/DummyGeneratorAccess.java diff --git a/Spigot-Server-Patches/Optimize-NibbleArray-to-use-pooled-buffers.patch b/Spigot-Server-Patches/Optimize-NibbleArray-to-use-pooled-buffers.patch index eb07ae7bfa..807f67ee00 100644 --- a/Spigot-Server-Patches/Optimize-NibbleArray-to-use-pooled-buffers.patch +++ b/Spigot-Server-Patches/Optimize-NibbleArray-to-use-pooled-buffers.patch @@ -62,7 +62,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 - this.data.queueUpdate(i, ((NibbleArray) this.data.getUpdating(i)).b()); // Paper - avoid copying light data + NibbleArray updating = this.data.getUpdating(i); // Paper - pool nibbles + this.data.queueUpdate(i, new NibbleArray().markPoolSafe(updating.getCloneIfSet())); // Paper - avoid copying light data - pool safe clone -+ if (updating.cleaner != null) MCUtil.scheduleTask(2, updating.cleaner); // Paper - delay clean incase anything holding ref was still using it ++ if (updating.cleaner != null) MCUtil.scheduleTask(2, updating.cleaner, "Light Engine Release"); // Paper - delay clean incase anything holding ref was still using it this.c(); } @@ -270,7 +270,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + cleaner1.run(); + cleaner2.run(); + } -+ }); ++ }, "Light Packet Release"); + } + } + diff --git a/Spigot-Server-Patches/Optimize-TileEntity-Ticking.patch b/Spigot-Server-Patches/Optimize-TileEntity-Ticking.patch index 49605b567f..28dcd268e7 100644 --- a/Spigot-Server-Patches/Optimize-TileEntity-Ticking.patch +++ b/Spigot-Server-Patches/Optimize-TileEntity-Ticking.patch @@ -61,7 +61,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + */ + MCUtil.scheduleTask(10, () -> { + this.a(SoundEffects.BLOCK_CHEST_CLOSE); -+ }); ++ }, "Chest Sounds"); + //} // Paper end if (this.a < 0.0F) { @@ -163,7 +163,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + MCUtil.scheduleTask(10, () -> { this.world.playSound((EntityHuman) null, d0, (double) j + 0.5D, d2, SoundEffects.BLOCK_ENDER_CHEST_CLOSE, SoundCategory.BLOCKS, 0.5F, this.world.random.nextFloat() * 0.1F + 0.9F); - } -+ }); ++ }, "Chest Sounds"); if (this.a < 0.0F) { this.a = 0.0F; diff --git a/Spigot-Server-Patches/Timings-v2.patch b/Spigot-Server-Patches/Timings-v2.patch index 178c10d45b..b1649830d0 100644 --- a/Spigot-Server-Patches/Timings-v2.patch +++ b/Spigot-Server-Patches/Timings-v2.patch @@ -58,6 +58,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + private MinecraftTimings() {} + ++ public static Timing getInternalTaskName(String taskName) { ++ return Timings.ofSafe(taskName); ++ } ++ + /** + * Gets a timer associated with a plugins tasks. + * @param bukkitTask @@ -2025,6 +2029,16 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.ArrayList; import java.util.Comparator; +@@ -0,0 +0,0 @@ public class CraftScheduler implements BukkitScheduler { + } + + public BukkitTask scheduleInternalTask(Runnable run, int delay, String taskName) { +- final CraftTask task = new CraftTask(run, nextId(), taskName); ++ final CraftTask task = new CraftTask(run, nextId(), "Internal - " + (taskName != null ? taskName : "Unknown")); ++ task.internal = true; + return handle(task, delay); + } + @@ -0,0 +0,0 @@ public class CraftScheduler implements BukkitScheduler { } return false; @@ -2115,8 +2129,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this(null, null, CraftTask.NO_REPEATING, CraftTask.NO_REPEATING); } @@ -0,0 +0,0 @@ public class CraftTask implements BukkitTask, Runnable { // Spigot - this(null, task, CraftTask.NO_REPEATING, CraftTask.NO_REPEATING); + this.id = id; + this.period = CraftTask.NO_REPEATING; + this.taskName = taskName; +- this.timings = null; // Will be changed in later patch ++ this.timings = MinecraftTimings.getInternalTaskName(taskName); } + // Paper end - CraftTask(final Plugin plugin, final Object task, final int id, final long period) { + CraftTask(final Plugin plugin, final Object task, final int id, final long period) { // Paper