mirror of
https://github.com/SparklyPower/SparklyPaper.git
synced 2025-12-19 15:09:27 +00:00
138 lines
9.2 KiB
Diff
138 lines
9.2 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
Date: Sun, 19 Nov 2023 12:35:16 -0300
|
|
Subject: [PATCH] Skip EntityScheduler's executeTick checks if there isn't any
|
|
tasks to be run
|
|
|
|
On each tick, Paper runs EntityScheduler's executeTick of each entity. This is a bit expensive, due to ArrayDeque's size() call because it ain't a simple "get the current queue size" function, due to the thread checks, and because it needs to iterate all entities in all worlds.
|
|
|
|
To avoid the hefty ArrayDeque's size() call, we check if we *really* need to execute the executeTick, by adding all entities with scheduled tasks to a global set.
|
|
|
|
Most entities won't have any scheduled tasks, so this is a nice performance bonus. These optimizations, however, wouldn't work in a Folia environment, but because in SparklyPaper executeTick is always executed on the main thread, it ain't an issue for us (yay).
|
|
|
|
diff --git a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
|
|
index c03608fec96b51e1867f43d8f42e5aefb1520e46..15b21fa3907db1b77ed5b5d1050a37f42d27d5ab 100644
|
|
--- a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
|
|
+++ b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
|
|
@@ -36,6 +36,7 @@ public final class EntityScheduler {
|
|
* The Entity. Note that it is the CraftEntity, since only that class properly tracks world transfers.
|
|
*/
|
|
public final CraftEntity entity;
|
|
+ public final net.minecraft.server.MinecraftServer server; // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
|
|
|
private static final record ScheduledTask(Consumer<? extends Entity> run, Consumer<? extends Entity> retired) {}
|
|
|
|
@@ -46,7 +47,8 @@ public final class EntityScheduler {
|
|
|
|
private final ArrayDeque<ScheduledTask> currentlyExecuting = new ArrayDeque<>();
|
|
|
|
- public EntityScheduler(final CraftEntity entity) {
|
|
+ public EntityScheduler(final net.minecraft.server.MinecraftServer server, final CraftEntity entity) { // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
|
+ this.server = Validate.notNull(server);
|
|
this.entity = Validate.notNull(entity);
|
|
}
|
|
|
|
@@ -61,14 +63,16 @@ public final class EntityScheduler {
|
|
* @throws IllegalStateException If the scheduler is already retired.
|
|
*/
|
|
public void retire() {
|
|
+ final Entity thisEntity = this.entity.getHandleRaw(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
|
synchronized (this.stateLock) {
|
|
if (this.tickCount == RETIRED_TICK_COUNT) {
|
|
throw new IllegalStateException("Already retired");
|
|
}
|
|
this.tickCount = RETIRED_TICK_COUNT;
|
|
+ this.server.entitiesWithScheduledTasks.remove(thisEntity); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
|
}
|
|
|
|
- final Entity thisEntity = this.entity.getHandleRaw();
|
|
+ // final Entity thisEntity = this.entity.getHandleRaw(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (moved up)
|
|
|
|
// correctly handle and order retiring while running executeTick
|
|
for (int i = 0, len = this.currentlyExecuting.size(); i < len; ++i) {
|
|
@@ -124,6 +128,7 @@ public final class EntityScheduler {
|
|
if (this.tickCount == RETIRED_TICK_COUNT) {
|
|
return false;
|
|
}
|
|
+ this.server.entitiesWithScheduledTasks.add(this.entity.getHandleRaw()); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
|
this.oneTimeDelayed.computeIfAbsent(this.tickCount + Math.max(1L, delay), (final long keyInMap) -> {
|
|
return new ArrayList<>();
|
|
}).add(task);
|
|
@@ -143,6 +148,13 @@ public final class EntityScheduler {
|
|
TickThread.ensureTickThread(thisEntity, "May not tick entity scheduler asynchronously");
|
|
final List<ScheduledTask> toRun;
|
|
synchronized (this.stateLock) {
|
|
+ // SparklyPaper start - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
|
+ // Do we *really* have scheduled tasks tho?
|
|
+ if (this.currentlyExecuting.isEmpty() && this.oneTimeDelayed.isEmpty()) { // Check if we have any pending tasks and, if not, skip!
|
|
+ this.server.entitiesWithScheduledTasks.remove(thisEntity); // We don't! Bye bye!!
|
|
+ return;
|
|
+ }
|
|
+ // SparklyPaper end
|
|
if (this.tickCount == RETIRED_TICK_COUNT) {
|
|
throw new IllegalStateException("Ticking retired scheduler");
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index 23ddd26af762c1cd7fb3920669abb96b3213ab37..7f2e25b2ebb8fb698a4adb12d77670e126549405 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -323,7 +323,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
public volatile Thread shutdownThread; // Paper
|
|
public volatile boolean abnormalExit = false; // Paper
|
|
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
|
-
|
|
+ public final Set<Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (concurrent because plugins may schedule tasks async)
|
|
+
|
|
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
|
|
AtomicReference<S> atomicreference = new AtomicReference();
|
|
Thread thread = new ca.spottedleaf.moonrise.common.util.TickThread(() -> { // Paper - rewrite chunk system
|
|
@@ -1727,6 +1728,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
MinecraftTimings.bukkitSchedulerTimer.stopTiming(); // Spigot // Paper
|
|
// Paper start - Folia scheduler API
|
|
((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) Bukkit.getGlobalRegionScheduler()).tick();
|
|
+ // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
|
+ for (final Entity entity : entitiesWithScheduledTasks) {
|
|
+ if (entity.isRemoved()) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ final org.bukkit.craftbukkit.entity.CraftEntity bukkit = entity.getBukkitEntityRaw();
|
|
+ if (bukkit != null) {
|
|
+ bukkit.taskScheduler.executeTick();
|
|
+ }
|
|
+ }
|
|
+ /*
|
|
getAllLevels().forEach(level -> {
|
|
for (final Entity entity : level.moonrise$getEntityLookup().getAllCopy()) { // Paper - rewrite chunk system
|
|
if (entity.isRemoved()) {
|
|
@@ -1738,6 +1751,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
}
|
|
}
|
|
});
|
|
+ */
|
|
+ // SparklyPaper end
|
|
// Paper end - Folia scheduler API
|
|
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper
|
|
this.profiler.push("commandFunctions");
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
index cd789c235acf740ec29c30b180e7fbe1a140caa9..e3da31426e5fe2cf3b0c3cc6b665503cc88665a5 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
@@ -71,7 +71,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
|
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftEntity.DATA_TYPE_REGISTRY);
|
|
protected net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
|
|
// Paper start - Folia shedulers
|
|
- public final io.papermc.paper.threadedregions.EntityScheduler taskScheduler = new io.papermc.paper.threadedregions.EntityScheduler(this);
|
|
+ public final io.papermc.paper.threadedregions.EntityScheduler taskScheduler; // = new io.papermc.paper.threadedregions.EntityScheduler(this); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
|
private final io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler apiScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler(this);
|
|
|
|
@Override
|
|
@@ -84,6 +84,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
|
this.server = server;
|
|
this.entity = entity;
|
|
this.entityType = CraftEntityType.minecraftToBukkit(entity.getType());
|
|
+ this.taskScheduler = new io.papermc.paper.threadedregions.EntityScheduler(this.entity.getServer(), this); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
|
}
|
|
|
|
public static <T extends Entity> CraftEntity getEntity(CraftServer server, T entity) {
|