Add global region scheduler

This will allow plugins to safely execute commands or perform
other global tick thread data modification.
This commit is contained in:
Spottedleaf 2023-03-19 16:43:34 -07:00
parent cbf8108d4e
commit 7e948a6179
3 changed files with 110 additions and 18 deletions

View File

@ -3,7 +3,8 @@ From: Spottedleaf <Spottedleaf@users.noreply.github.com>
Date: Sat, 4 Mar 2023 12:48:43 -0800
Subject: [PATCH] Region scheduler API
Add both a location based scheduler and an entity based scheduler
Add both a location based scheduler, an entity based scheduler,
and a global region scheduler.
diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/EntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/EntityScheduler.java
new file mode 100644
@ -58,6 +59,34 @@ index 0000000000000000000000000000000000000000..4193b13f1f51c2fb8da76f3e03187d85
+ final long delay);
+
+}
diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java
new file mode 100644
index 0000000000000000000000000000000000000000..c13c89c87a4e6fd441cac8d3c8cd5b283915467f
--- /dev/null
+++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/GlobalRegionScheduler.java
@@ -0,0 +1,22 @@
+package io.papermc.paper.threadedregions.scheduler;
+
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * The global region task scheduler may be used to schedule tasks that will execute on the global region.
+ * <p>
+ * The global region is responsible for maintaining world day time, world game time, weather cycle,
+ * sleep night skipping, executing commands for console, and other misc. tasks that do not belong to any specific region.
+ * </p>
+ */
+public interface GlobalRegionScheduler {
+
+ /**
+ * Schedules a task to be executed on the global region.
+ * @param plugin The plugin that owns the task
+ * @param run The task to execute
+ */
+ public void execute(@NotNull final Plugin plugin, @NotNull final Runnable run);
+
+}
diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/RegionisedScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/RegionisedScheduler.java
new file mode 100644
index 0000000000000000000000000000000000000000..210a3dce74959efd7ac0ca9a92a2ad8815844246
@ -91,10 +120,10 @@ index 0000000000000000000000000000000000000000..210a3dce74959efd7ac0ca9a92a2ad88
+ public void execute(@NotNull final Plugin plugin, @NotNull final Location location, @NotNull final Runnable run);
+}
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
index ac9b690fcccb60b587e5345f12f1383afd0a73a1..3b8a6d7336b0cb20594de9c6b56f215f1370ce89 100644
index ac9b690fcccb60b587e5345f12f1383afd0a73a1..4ae25cb199c6e20b51c4a1e7ac4ff55b23ae724f 100644
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -2459,6 +2459,22 @@ public final class Bukkit {
@@ -2459,6 +2459,35 @@ public final class Bukkit {
return server.getPotionBrewer();
}
// Paper end
@ -113,15 +142,28 @@ index ac9b690fcccb60b587e5345f12f1383afd0a73a1..3b8a6d7336b0cb20594de9c6b56f215f
+ public static @NotNull io.papermc.paper.threadedregions.scheduler.RegionisedScheduler getRegionScheduler() {
+ return server.getRegionScheduler();
+ }
+
+ /**
+ * Returns the global region task scheduler. The global task scheduler can be used to schedule
+ * tasks to execute on the global region.
+ * <p>
+ * The global region is responsible for maintaining world day time, world game time, weather cycle,
+ * sleep night skipping, executing commands for console, and other misc. tasks that do not belong to any specific region.
+ * </p>
+ * @return the global region scheduler
+ */
+ public static @NotNull io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler getGlobalRegionScheduler() {
+ return server.getGlobalRegionScheduler();
+ }
+ // Folia end - region threading API
@NotNull
public static Server.Spigot spigot() {
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index 2204336d8800311b65e894739ab1b27273e7c6f2..135467092eec33a21b171df39267d15bad26003e 100644
index 2204336d8800311b65e894739ab1b27273e7c6f2..1092ceef77bad421df647d349d997d02b2ba80a9 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -2139,4 +2139,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
@@ -2139,4 +2139,29 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
*/
@NotNull org.bukkit.potion.PotionBrewer getPotionBrewer();
// Paper end
@ -138,6 +180,17 @@ index 2204336d8800311b65e894739ab1b27273e7c6f2..135467092eec33a21b171df39267d15b
+ * @return the region task scheduler
+ */
+ @NotNull io.papermc.paper.threadedregions.scheduler.RegionisedScheduler getRegionScheduler();
+
+ /**
+ * Returns the global region task scheduler. The global task scheduler can be used to schedule
+ * tasks to execute on the global region.
+ * <p>
+ * The global region is responsible for maintaining world day time, world game time, weather cycle,
+ * sleep night skipping, executing commands for console, and other misc. tasks that do not belong to any specific region.
+ * </p>
+ * @return the global region scheduler
+ */
+ public @NotNull io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler getGlobalRegionScheduler();
+ // Folia end - region threading API
}
diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java

View File

@ -11,12 +11,12 @@ the schedulers depending on the result of the ownership
check.
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
index 3b8a6d7336b0cb20594de9c6b56f215f1370ce89..aee6508cec0631fc7b5fe6bf1b978a5c01437422 100644
index 4ae25cb199c6e20b51c4a1e7ac4ff55b23ae724f..b8c62f431bf802a80fa097f1e5f8e6247badd0ea 100644
--- a/src/main/java/org/bukkit/Bukkit.java
+++ b/src/main/java/org/bukkit/Bukkit.java
@@ -2474,6 +2474,100 @@ public final class Bukkit {
public static @NotNull io.papermc.paper.threadedregions.scheduler.RegionisedScheduler getRegionScheduler() {
return server.getRegionScheduler();
@@ -2487,6 +2487,100 @@ public final class Bukkit {
public static @NotNull io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler getGlobalRegionScheduler() {
return server.getGlobalRegionScheduler();
}
+
+ /**
@ -116,13 +116,13 @@ index 3b8a6d7336b0cb20594de9c6b56f215f1370ce89..aee6508cec0631fc7b5fe6bf1b978a5c
@NotNull
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index 135467092eec33a21b171df39267d15bad26003e..48902e9aec6af7a4252db5b567d08a80f5709cbf 100644
index 1092ceef77bad421df647d349d997d02b2ba80a9..3a17ccd041ca64c8ab0cd3edf4ce6fc1c6f2d459 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -2152,5 +2152,83 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
* @return the region task scheduler
@@ -2163,5 +2163,83 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
* @return the global region scheduler
*/
@NotNull io.papermc.paper.threadedregions.scheduler.RegionisedScheduler getRegionScheduler();
public @NotNull io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler getGlobalRegionScheduler();
+
+ /**
+ * Returns whether the current thread is ticking a region and that the region being ticked

View File

@ -8921,6 +8921,39 @@ index 0000000000000000000000000000000000000000..c0b9f43fc53a5c9b3d9788f080e4fd3f
+ return this.entity.taskScheduler.schedule(runNMS, runRetired, delay);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java
new file mode 100644
index 0000000000000000000000000000000000000000..cada55accf6c6b882918fe59f82cabe029f7b511
--- /dev/null
+++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaGlobalRegionScheduler.java
@@ -0,0 +1,27 @@
+package io.papermc.paper.threadedregions.scheduler;
+
+import ca.spottedleaf.concurrentutil.util.Validate;
+import io.papermc.paper.threadedregions.RegionisedServer;
+import org.bukkit.plugin.Plugin;
+import java.util.logging.Level;
+
+public final class FoliaGlobalRegionScheduler implements GlobalRegionScheduler {
+
+ private static Runnable wrap(final Plugin plugin, final Runnable run) {
+ return () -> {
+ try {
+ run.run();
+ } catch (final Throwable throwable) {
+ plugin.getLogger().log(Level.WARNING, "Global region task for " + plugin.getDescription().getFullName() + " generated an exception", throwable);
+ }
+ };
+ }
+
+ @Override
+ public void execute(final Plugin plugin, final Runnable run) {
+ Validate.notNull(plugin, "Plugin may not be null");
+ Validate.notNull(run, "Runnable may not be null");
+
+ RegionisedServer.getInstance().addTaskWithoutNotify(wrap(plugin, run));
+ }
+}
diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaRegionisedScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaRegionisedScheduler.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4637086ba0095341da9c2bfe20083375c82bc01
@ -21688,15 +21721,16 @@ index 7f1ac2cb29eb84833c0895442d611dfa0504527e..c79cfebc65fd04994735dabcf5bb6e6c
LevelChunkTicks<T> levelChunkTicks = this.allContainers.get(l);
if (levelChunkTicks == null) {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 2ea3778ee1348e5d06b15a2c5dc5d9bd4136dbe3..c970a9165657636f1a442df8aa3f566eea46a290 100644
index 2ea3778ee1348e5d06b15a2c5dc5d9bd4136dbe3..38d508b7a198df39de6d8ddc1b2aa6b8284f2d1b 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -307,6 +307,69 @@ public final class CraftServer implements Server {
@@ -307,6 +307,75 @@ public final class CraftServer implements Server {
CraftItemFactory.instance();
}
+ // Folia start - region threading API
+ private final io.papermc.paper.threadedregions.scheduler.FoliaRegionisedScheduler regionisedScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaRegionisedScheduler();
+ private final io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler globalRegionScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler();
+
+ @Override
+ public final io.papermc.paper.threadedregions.scheduler.RegionisedScheduler getRegionScheduler() {
@ -21704,6 +21738,11 @@ index 2ea3778ee1348e5d06b15a2c5dc5d9bd4136dbe3..c970a9165657636f1a442df8aa3f566e
+ }
+
+ @Override
+ public final io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler getGlobalRegionScheduler() {
+ return this.globalRegionScheduler;
+ }
+
+ @Override
+ public final boolean isOwnedByCurrentRegion(World world, org.bukkit.util.Vector position) {
+ return io.papermc.paper.util.TickThread.isTickThreadFor(
+ ((CraftWorld)world).getHandle(), position.getBlockX() >> 4, position.getBlockZ() >> 4
@ -21761,7 +21800,7 @@ index 2ea3778ee1348e5d06b15a2c5dc5d9bd4136dbe3..c970a9165657636f1a442df8aa3f566e
public CraftServer(DedicatedServer console, PlayerList playerList) {
this.console = console;
this.playerList = (DedicatedPlayerList) playerList;
@@ -879,6 +942,9 @@ public final class CraftServer implements Server {
@@ -879,6 +948,9 @@ public final class CraftServer implements Server {
// NOTE: Should only be called from DedicatedServer.ah()
public boolean dispatchServerCommand(CommandSender sender, ConsoleInput serverCommand) {
@ -21771,7 +21810,7 @@ index 2ea3778ee1348e5d06b15a2c5dc5d9bd4136dbe3..c970a9165657636f1a442df8aa3f566e
if (sender instanceof Conversable) {
Conversable conversable = (Conversable) sender;
@@ -898,12 +964,44 @@ public final class CraftServer implements Server {
@@ -898,12 +970,44 @@ public final class CraftServer implements Server {
}
}
@ -21816,7 +21855,7 @@ index 2ea3778ee1348e5d06b15a2c5dc5d9bd4136dbe3..c970a9165657636f1a442df8aa3f566e
// Paper Start
if (!org.spigotmc.AsyncCatcher.shuttingDown && !Bukkit.isPrimaryThread()) {
final CommandSender fSender = sender;
@@ -2913,7 +3011,7 @@ public final class CraftServer implements Server {
@@ -2913,7 +3017,7 @@ public final class CraftServer implements Server {
@Override
public int getCurrentTick() {