From 2577344ac065ea7bec36bebad972957a15b710f9 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 13 Jun 2025 19:48:42 +0200 Subject: [PATCH 01/26] implement platform specific schedulers --- core/build.gradle.kts | 1 + scheduler/build.gradle.kts | 7 + .../volmit/iris/util/scheduling/Platform.java | 190 ++++++++++++++++++ .../com/volmit/iris/util/scheduling/Ref.java | 5 + .../com/volmit/iris/util/scheduling/Task.java | 27 +++ .../util/scheduling/paper/PaperPlatform.java | 107 ++++++++++ .../iris/util/scheduling/paper/PaperTask.java | 59 ++++++ .../paper/split/PaperAsyncScheduler.java | 48 +++++ .../paper/split/PaperEntityScheduler.java | 49 +++++ .../paper/split/PaperGlobalScheduler.java | 39 ++++ .../paper/split/PaperRegionScheduler.java | 45 +++++ .../scheduling/spigot/SpigotPlatform.java | 105 ++++++++++ .../util/scheduling/spigot/SpigotTask.java | 60 ++++++ .../spigot/split/SpigotAsyncScheduler.java | 44 ++++ .../spigot/split/SpigotEntityScheduler.java | 53 +++++ .../spigot/split/SpigotGlobalScheduler.java | 37 ++++ .../spigot/split/SpigotRegionScheduler.java | 30 +++ .../scheduling/split/IAsyncScheduler.java | 75 +++++++ .../scheduling/split/IEntityScheduler.java | 136 +++++++++++++ .../scheduling/split/IGlobalScheduler.java | 74 +++++++ .../scheduling/split/IRegionScheduler.java | 182 +++++++++++++++++ settings.gradle.kts | 21 +- 22 files changed, 1384 insertions(+), 10 deletions(-) create mode 100644 scheduler/build.gradle.kts create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/Platform.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/Ref.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/Task.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperPlatform.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperTask.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperEntityScheduler.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperGlobalScheduler.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperRegionScheduler.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotPlatform.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotTask.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotAsyncScheduler.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotEntityScheduler.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotGlobalScheduler.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotRegionScheduler.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java create mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java diff --git a/core/build.gradle.kts b/core/build.gradle.kts index cebfbc6c5..1cf20ed96 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -70,6 +70,7 @@ dependencies { implementation("net.kyori:adventure-platform-bukkit:4.3.4") implementation("net.kyori:adventure-api:4.17.0") implementation("org.bstats:bstats-bukkit:3.1.0") + implementation(project(":scheduler")) //implementation("org.bytedeco:javacpp:1.5.10") //implementation("org.bytedeco:cuda-platform:12.3-8.9-1.5.10") diff --git a/scheduler/build.gradle.kts b/scheduler/build.gradle.kts new file mode 100644 index 000000000..cdb3e49b1 --- /dev/null +++ b/scheduler/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + java +} + +dependencies { + compileOnly("dev.folia:folia-api:1.20.1-R0.1-SNAPSHOT") +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/Platform.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/Platform.java new file mode 100644 index 000000000..95db49223 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/Platform.java @@ -0,0 +1,190 @@ +package com.volmit.iris.util.scheduling; + +import com.volmit.iris.util.scheduling.paper.PaperPlatform; +import com.volmit.iris.util.scheduling.spigot.SpigotPlatform; +import com.volmit.iris.util.scheduling.split.IAsyncScheduler; +import com.volmit.iris.util.scheduling.split.IEntityScheduler; +import com.volmit.iris.util.scheduling.split.IGlobalScheduler; +import com.volmit.iris.util.scheduling.split.IRegionScheduler; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +@SuppressWarnings("unused") +public interface Platform { + /** + * Folia: Returns whether the current thread is ticking a region and that + * the region being ticked owns the chunk at the specified world and block + * position as included in the specified location. + * Paper/Spigot: Returns {@link Server#isPrimaryThread()} + * + * @param location Specified location, must have a non-null world + * @return true if the current thread is ticking the region that owns the chunk at the specified location + */ + boolean isOwnedByCurrentRegion(@NotNull Location location); + + /** + * Folia: Returns whether the current thread is ticking a region and that + * the region being ticked owns the chunks centered at the specified world + * and block position as included in the specified location within the + * specified square radius. Specifically, this function checks that every + * chunk with position x in [centerX - radius, centerX + radius] and + * position z in [centerZ - radius, centerZ + radius] is owned by the + * current ticking region. + * Paper/Spigot: Returns {@link Server#isPrimaryThread()} + * + * @param location Specified location, must have a non-null world + * @param squareRadiusChunks Specified square radius. Must be >= 0. Note that this parameter is not a squared radius, but rather a Chebyshev Distance + * @return true if the current thread is ticking the region that owns the chunks centered at the specified location within the specified square radius + */ + boolean isOwnedByCurrentRegion(@NotNull Location location, int squareRadiusChunks); + + /** + * Folia: Returns whether the current thread is ticking a region and that + * the region being ticked owns the chunk at the specified block position. + * Paper/Spigot: Returns {@link Server#isPrimaryThread()} + * + * @param block Specified block position + * @return true if the current thread is ticking the region that owns the chunk at the specified block position + */ + boolean isOwnedByCurrentRegion(@NotNull Block block); + + /** + * Folia: Returns whether the current thread is ticking a region and that + * the region being ticked owns the chunk at the specified world and chunk + * position. + * Paper/Spigot: Returns {@link Server#isPrimaryThread()} + * + * @param world Specified world + * @param chunkX Specified x-coordinate of the chunk position + * @param chunkZ Specified z-coordinate of the chunk position + * @return true if the current thread is ticking the region that owns the chunk at the specified world and chunk position + */ + boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ); + + /** + * Folia: Returns whether the current thread is ticking a region and that + * the region being ticked owns the chunks centered at the specified world + * and chunk position within the specified square radius. Specifically, + * this function checks that every chunk with position x in [centerX - + * radius, centerX + radius] and position z in [centerZ - radius, centerZ + + * radius] is owned by the current ticking region. + * Paper/Spigot: Returns {@link Server#isPrimaryThread()} + * + * @param world Specified world + * @param chunkX Specified x-coordinate of the chunk position + * @param chunkZ Specified z-coordinate of the chunk position + * @param squareRadiusChunks Specified square radius. Must be >= 0. Note that this parameter is not a squared radius, but rather a Chebyshev Distance. + * @return true if the current thread is ticking the region that owns the chunks centered at the specified world and chunk position within the specified square radius + */ + boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ, int squareRadiusChunks); + + /** + * Folia: Returns whether the current thread is ticking a region and that + * the region being ticked owns the specified entity. Note that this + * function is the only appropriate method of checking for ownership of an + * entity, as retrieving the entity's location is undefined unless the + * entity is owned by the current region. + * Paper/Spigot: Returns {@link Server#isPrimaryThread()} + * + * @param entity Specified entity + * @return true if the current thread is ticking the region that owns the specified entity + */ + boolean isOwnedByCurrentRegion(@NotNull Entity entity); + + /** + * Folia: Returns whether the current thread is ticking the global region. + * Paper/Spigot: Returns {@link Server#isPrimaryThread()} + * + * @return true if the current thread is ticking the global region + */ + boolean isGlobalTickThread(); + + /** + * Scheduler that may be used by plugins to schedule tasks to execute asynchronously from the server tick process. + */ + @NotNull IAsyncScheduler async(); + + /** + * An entity can move between worlds with an arbitrary tick delay, be temporarily removed + * for players (i.e end credits), be partially removed from world state (i.e inactive but not removed), + * teleport between ticking regions, teleport between worlds, and even be removed entirely from the server. + * The uncertainty of an entity's state can make it difficult to schedule tasks without worrying about undefined + * behaviors resulting from any of the states listed previously. + * + *

+ * This class is designed to eliminate those states by providing an interface to run tasks only when an entity + * is contained in a world, on the owning thread for the region, and by providing the current Entity object. + * The scheduler also allows a task to provide a callback, the "retired" callback, that will be invoked + * if the entity is removed before a task that was scheduled could be executed. The scheduler is also + * completely thread-safe, allowing tasks to be scheduled from any thread context. The scheduler also indicates + * properly whether a task was scheduled successfully (i.e scheduler not retired), thus the code scheduling any task + * knows whether the given callbacks will be invoked eventually or not - which may be critical for off-thread + * contexts. + *

+ */ + @NotNull IEntityScheduler entity(@NotNull Entity entity); + + /** + * The global region task scheduler may be used to schedule tasks that will execute on the global region. + *

+ * 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. + *

+ */ + @NotNull IGlobalScheduler global(); + + /** + * The region task scheduler can be used to schedule tasks by location to be executed on the region which owns the location. + *

+ * Note: It is entirely inappropriate to use the region scheduler to schedule tasks for entities. + * If you wish to schedule tasks to perform actions on entities, you should be using {@link Entity#getScheduler()} + * as the entity scheduler will "follow" an entity if it is teleported, whereas the region task scheduler + * will not. + *

+ */ + @NotNull IRegionScheduler region(); + + /** + * Teleport an entity to a location async + * @param entity Entity to teleport + * @param location Location to teleport to + * @return Future when the teleport is completed or failed + */ + default @NotNull CompletableFuture<@NotNull Boolean> teleportAsync(@NotNull Entity entity, @NotNull Location location) { + return teleportAsync(entity, location, PlayerTeleportEvent.TeleportCause.PLUGIN); + } + + /** + * Teleport an entity to a location async with a cause + * @param entity Entity to teleport + * @param location Location to teleport to + * @param cause Cause of the teleport + * @return Future when the teleport is completed or failed + */ + @NotNull CompletableFuture<@NotNull Boolean> teleportAsync(@NotNull Entity entity, @NotNull Location location, @NotNull PlayerTeleportEvent.TeleportCause cause); + + static @NotNull Platform create(@NotNull Plugin plugin) { + if (hasClass("com.destroystokyo.paper.PaperConfig") || hasClass("io.papermc.paper.configuration.Configuration")) + return new PaperPlatform(plugin); + if (hasClass("org.spigotmc.SpigotConfig")) + return new SpigotPlatform(plugin); + throw new IllegalStateException("Unsupported platform!"); + } + + static boolean hasClass(String name) { + try { + Class.forName(name); + return true; + } catch (Throwable e) { + return false; + } + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/Ref.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/Ref.java new file mode 100644 index 000000000..c9a212e2e --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/Ref.java @@ -0,0 +1,5 @@ +package com.volmit.iris.util.scheduling; + +public final class Ref { + public transient T value; +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/Task.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/Task.java new file mode 100644 index 000000000..4a09ad4fb --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/Task.java @@ -0,0 +1,27 @@ +package com.volmit.iris.util.scheduling; + +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + +public interface Task { + void cancel(); + boolean cancelled(); + @NotNull Plugin owner(); + boolean async(); + + interface Completable extends Task { + @NotNull CompletableFuture result(); + + default void complete(Function, T> function) { + var future = result(); + try { + future.complete(function.apply(this)); + } catch (Throwable e) { + future.completeExceptionally(e); + } + } + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperPlatform.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperPlatform.java new file mode 100644 index 000000000..53e7bdb2e --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperPlatform.java @@ -0,0 +1,107 @@ +package com.volmit.iris.util.scheduling.paper; + +import com.volmit.iris.util.scheduling.Platform; +import com.volmit.iris.util.scheduling.paper.split.PaperAsyncScheduler; +import com.volmit.iris.util.scheduling.paper.split.PaperEntityScheduler; +import com.volmit.iris.util.scheduling.paper.split.PaperGlobalScheduler; +import com.volmit.iris.util.scheduling.paper.split.PaperRegionScheduler; +import com.volmit.iris.util.scheduling.split.IAsyncScheduler; +import com.volmit.iris.util.scheduling.split.IEntityScheduler; +import com.volmit.iris.util.scheduling.split.IGlobalScheduler; +import com.volmit.iris.util.scheduling.split.IRegionScheduler; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; +import java.util.function.BooleanSupplier; + +public class PaperPlatform implements Platform { + private final Plugin plugin; + private final Server server; + private final IAsyncScheduler async; + private final IGlobalScheduler global; + private final IRegionScheduler region; + private final BooleanSupplier globalTickThread; + + public PaperPlatform(@NotNull Plugin plugin) { + this.plugin = plugin; + this.server = plugin.getServer(); + async = new PaperAsyncScheduler(plugin, server.getAsyncScheduler()); + global = new PaperGlobalScheduler(plugin, server.getGlobalRegionScheduler()); + region = new PaperRegionScheduler(plugin, server.getRegionScheduler()); + + BooleanSupplier method; + try { + method = server::isGlobalTickThread; + } catch (Throwable e) { + method = server::isPrimaryThread; + } + globalTickThread = method; + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull Location location) { + return server.isOwnedByCurrentRegion(location); + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull Location location, int squareRadiusChunks) { + return server.isOwnedByCurrentRegion(location, squareRadiusChunks); + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull Block block) { + return server.isOwnedByCurrentRegion(block); + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ) { + return server.isOwnedByCurrentRegion(world, chunkX, chunkZ); + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ, int squareRadiusChunks) { + return server.isOwnedByCurrentRegion(world, chunkX, chunkZ, squareRadiusChunks); + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull Entity entity) { + return server.isOwnedByCurrentRegion(entity); + } + + @Override + public boolean isGlobalTickThread() { + return globalTickThread.getAsBoolean(); + } + + @Override + public @NotNull IAsyncScheduler async() { + return async; + } + + @Override + public @NotNull IEntityScheduler entity(@NotNull Entity entity) { + return new PaperEntityScheduler(plugin, entity.getScheduler()); + } + + @Override + public @NotNull IGlobalScheduler global() { + return global; + } + + @Override + public @NotNull IRegionScheduler region() { + return region; + } + + @Override + public @NotNull CompletableFuture<@NotNull Boolean> teleportAsync(@NotNull Entity entity, @NotNull Location location, PlayerTeleportEvent.@NotNull TeleportCause cause) { + return entity.teleportAsync(location, cause); + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperTask.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperTask.java new file mode 100644 index 000000000..ea90b8371 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperTask.java @@ -0,0 +1,59 @@ +package com.volmit.iris.util.scheduling.paper; + +import com.volmit.iris.util.scheduling.Task; +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +public class PaperTask implements Task { + protected final ScheduledTask task; + protected final boolean async; + + public PaperTask(@NotNull ScheduledTask task, boolean async) { + this.task = task; + this.async = async; + } + + @Override + public void cancel() { + task.cancel(); + } + + @Override + public boolean cancelled() { + return task.isCancelled(); + } + + @Override + public @NotNull Plugin owner() { + return task.getOwningPlugin(); + } + + @Override + public boolean async() { + return async; + } + + public static class Completable extends PaperTask implements Task.Completable { + private final CompletableFuture result = new CompletableFuture<>(); + + public Completable(@NotNull ScheduledTask task, boolean async) { + super(task, async); + } + + @Override + public void cancel() { + ScheduledTask.CancelledState cancel = task.cancel(); + if (cancel == ScheduledTask.CancelledState.CANCELLED_BY_CALLER || cancel == ScheduledTask.CancelledState.NEXT_RUNS_CANCELLED || cancel == ScheduledTask.CancelledState.CANCELLED_ALREADY) { + result.cancel(false); + } + } + + @Override + public @NotNull CompletableFuture result() { + return result; + } + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java new file mode 100644 index 000000000..f35b644b6 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java @@ -0,0 +1,48 @@ +package com.volmit.iris.util.scheduling.paper.split; + +import com.volmit.iris.util.scheduling.Ref; +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import com.volmit.iris.util.scheduling.paper.PaperTask; +import com.volmit.iris.util.scheduling.split.IAsyncScheduler; +import io.papermc.paper.threadedregions.scheduler.AsyncScheduler; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Function; + +public class PaperAsyncScheduler implements IAsyncScheduler { + private final Plugin plugin; + private final AsyncScheduler scheduler; + + public PaperAsyncScheduler(Plugin plugin, AsyncScheduler scheduler) { + this.plugin = plugin; + this.scheduler = scheduler; + } + + @Override + public @NotNull Completable run(@NotNull Function, R> task) { + Ref> ref = new Ref<>(); + return ref.value = new PaperTask.Completable<>(scheduler.runNow(plugin, t -> ref.value.complete(task)), true); + } + + @Override + public @NotNull Completable runDelayed(@NotNull Function, R> task, + @Range(from = 1, to = Long.MAX_VALUE) long delay, + @NotNull TimeUnit unit) { + Ref> ref = new Ref<>(); + return ref.value = new PaperTask.Completable<>(scheduler.runDelayed(plugin, t -> ref.value.complete(task), delay, unit), true); + } + + @Override + public @NotNull Task runAtFixedRate(@NotNull Consumer task, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelay, + @Range(from = 1, to = Long.MAX_VALUE) long period, + @NotNull TimeUnit unit) { + Ref ref = new Ref<>(); + return ref.value = new PaperTask(scheduler.runAtFixedRate(plugin, t -> task.accept(ref.value), initialDelay, period, unit), true); + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperEntityScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperEntityScheduler.java new file mode 100644 index 000000000..4748398db --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperEntityScheduler.java @@ -0,0 +1,49 @@ +package com.volmit.iris.util.scheduling.paper.split; + +import com.volmit.iris.util.scheduling.Ref; +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import com.volmit.iris.util.scheduling.paper.PaperTask; +import com.volmit.iris.util.scheduling.split.IEntityScheduler; +import io.papermc.paper.threadedregions.scheduler.EntityScheduler; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; + +import java.util.function.Consumer; +import java.util.function.Function; + +public class PaperEntityScheduler implements IEntityScheduler { + private final Plugin plugin; + private final EntityScheduler scheduler; + + public PaperEntityScheduler(Plugin plugin, EntityScheduler scheduler) { + this.plugin = plugin; + this.scheduler = scheduler; + } + + @Override + public @Nullable Completable runDelayed(@NotNull Function, R> task, + @Nullable Runnable retired, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + Ref> ref = new Ref<>(); + var raw = scheduler.runDelayed(plugin, t -> ref.value.complete(task), () -> { + if (retired != null) retired.run(); + ref.value.cancel(); + }, delayTicks); + if (raw == null) return null; + return ref.value = new PaperTask.Completable<>(raw, false); + } + + @Override + public @Nullable Task runAtFixedRate(@NotNull Consumer task, + @Nullable Runnable retired, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, + @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { + Ref ref = new Ref<>(); + var raw = scheduler.runAtFixedRate(plugin, t -> task.accept(ref.value), retired, initialDelayTicks, periodTicks); + if (raw == null) return null; + return ref.value = new PaperTask(raw, false); + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperGlobalScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperGlobalScheduler.java new file mode 100644 index 000000000..de369951f --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperGlobalScheduler.java @@ -0,0 +1,39 @@ +package com.volmit.iris.util.scheduling.paper.split; + +import com.volmit.iris.util.scheduling.Ref; +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import com.volmit.iris.util.scheduling.paper.PaperTask; +import com.volmit.iris.util.scheduling.split.IGlobalScheduler; +import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.util.function.Consumer; +import java.util.function.Function; + +public class PaperGlobalScheduler implements IGlobalScheduler { + private final Plugin plugin; + private final GlobalRegionScheduler scheduler; + + public PaperGlobalScheduler(Plugin plugin, GlobalRegionScheduler scheduler) { + this.plugin = plugin; + this.scheduler = scheduler; + } + + @Override + public @NotNull Completable runDelayed(@NotNull Function, R> task, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + Ref> ref = new Ref<>(); + return ref.value = new PaperTask.Completable<>(scheduler.runDelayed(plugin, t -> ref.value.complete(task), delayTicks), false); + } + + @Override + public @NotNull Task runAtFixedRate(@NotNull Consumer task, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, + @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { + Ref ref = new Ref<>(); + return ref.value = new PaperTask(scheduler.runAtFixedRate(plugin, t -> task.accept(ref.value), initialDelayTicks, periodTicks), false); + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperRegionScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperRegionScheduler.java new file mode 100644 index 000000000..7ac140b2f --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperRegionScheduler.java @@ -0,0 +1,45 @@ +package com.volmit.iris.util.scheduling.paper.split; + +import com.volmit.iris.util.scheduling.Ref; +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import com.volmit.iris.util.scheduling.paper.PaperTask; +import com.volmit.iris.util.scheduling.split.IRegionScheduler; +import io.papermc.paper.threadedregions.scheduler.RegionScheduler; +import org.bukkit.World; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.util.function.Consumer; +import java.util.function.Function; + +public class PaperRegionScheduler implements IRegionScheduler { + private final Plugin plugin; + private final RegionScheduler scheduler; + + public PaperRegionScheduler(Plugin plugin, RegionScheduler scheduler) { + this.plugin = plugin; + this.scheduler = scheduler; + } + + @Override + public @NotNull Completable runDelayed(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Function, R> task, @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + Ref> ref = new Ref<>(); + return ref.value = new PaperTask.Completable<>(scheduler.runDelayed(plugin, world, chunkX, chunkZ, t -> ref.value.complete(task), delayTicks), false); + } + + @Override + public @NotNull Task runAtFixedRate(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Consumer task, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, + @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { + Ref ref = new Ref<>(); + return ref.value = new PaperTask(scheduler.runAtFixedRate(plugin, world, chunkX, chunkZ, t -> task.accept(ref.value), initialDelayTicks, periodTicks), false); + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotPlatform.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotPlatform.java new file mode 100644 index 000000000..22f84dae9 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotPlatform.java @@ -0,0 +1,105 @@ +package com.volmit.iris.util.scheduling.spigot; + +import com.volmit.iris.util.scheduling.Platform; +import com.volmit.iris.util.scheduling.spigot.split.SpigotAsyncScheduler; +import com.volmit.iris.util.scheduling.spigot.split.SpigotEntityScheduler; +import com.volmit.iris.util.scheduling.spigot.split.SpigotGlobalScheduler; +import com.volmit.iris.util.scheduling.spigot.split.SpigotRegionScheduler; +import com.volmit.iris.util.scheduling.split.IAsyncScheduler; +import com.volmit.iris.util.scheduling.split.IEntityScheduler; +import com.volmit.iris.util.scheduling.split.IGlobalScheduler; +import com.volmit.iris.util.scheduling.split.IRegionScheduler; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +public class SpigotPlatform implements Platform { + private final Server server; + private final IAsyncScheduler async; + private final IGlobalScheduler global; + private final IRegionScheduler region; + + public SpigotPlatform(@NotNull Plugin plugin) { + server = plugin.getServer(); + var scheduler = server.getScheduler(); + async = new SpigotAsyncScheduler(plugin, scheduler); + global = new SpigotGlobalScheduler(plugin, scheduler); + region = new SpigotRegionScheduler(global); + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull Location location) { + return server.isPrimaryThread(); + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull Location location, int squareRadiusChunks) { + return server.isPrimaryThread(); + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull Block block) { + return server.isPrimaryThread(); + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ) { + return server.isPrimaryThread(); + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ, int squareRadiusChunks) { + return server.isPrimaryThread(); + } + + @Override + public boolean isOwnedByCurrentRegion(@NotNull Entity entity) { + return server.isPrimaryThread(); + } + + @Override + public boolean isGlobalTickThread() { + return server.isPrimaryThread(); + } + + @Override + public @NotNull IAsyncScheduler async() { + return async; + } + + @Override + public @NotNull IEntityScheduler entity(@NotNull Entity entity) { + return new SpigotEntityScheduler(global, entity); + } + + @Override + public @NotNull IGlobalScheduler global() { + return global; + } + + @Override + public @NotNull IRegionScheduler region() { + return region; + } + + @Override + public @NotNull CompletableFuture<@NotNull Boolean> teleportAsync(@NotNull Entity entity, @NotNull Location location, PlayerTeleportEvent.@NotNull TeleportCause cause) { + return global().run(task -> isValid(entity) && entity.teleport(location)).result().thenApply(b -> b != null ? b : false); + } + + public static boolean isValid(Entity entity) { + if (entity.isValid()) { + return !(entity instanceof Player) || ((Player) entity).isOnline(); + } + return entity instanceof Projectile && !entity.isDead(); + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotTask.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotTask.java new file mode 100644 index 000000000..3991b1f22 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotTask.java @@ -0,0 +1,60 @@ +package com.volmit.iris.util.scheduling.spigot; + +import com.volmit.iris.util.scheduling.Task; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +public class SpigotTask implements Task { + protected final BukkitTask task; + + public SpigotTask(@NotNull BukkitTask task) { + this.task = task; + } + + @Override + public void cancel() { + task.cancel(); + } + + @Override + public boolean cancelled() { + return task.isCancelled(); + } + + @Override + public @NotNull Plugin owner() { + return task.getOwner(); + } + + @Override + public boolean async() { + return !task.isSync(); + } + + @SuppressWarnings("deprecation") + public static class Completable extends SpigotTask implements Task.Completable { + private final CompletableFuture result = new CompletableFuture<>(); + private final BukkitScheduler scheduler; + + public Completable(@NotNull BukkitTask task, @NotNull BukkitScheduler scheduler) { + super(task); + this.scheduler = scheduler; + } + + @Override + public void cancel() { + scheduler.cancelTask(task.getTaskId()); + if (scheduler.isCurrentlyRunning(task.getTaskId())) return; + result.cancel(false); + } + + @Override + public @NotNull CompletableFuture result() { + return result; + } + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotAsyncScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotAsyncScheduler.java new file mode 100644 index 000000000..ea474f377 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotAsyncScheduler.java @@ -0,0 +1,44 @@ +package com.volmit.iris.util.scheduling.spigot.split; + +import com.volmit.iris.util.scheduling.Ref; +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import com.volmit.iris.util.scheduling.spigot.SpigotTask; +import com.volmit.iris.util.scheduling.split.IAsyncScheduler; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitScheduler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Function; + +@SuppressWarnings("deprecation") +public class SpigotAsyncScheduler implements IAsyncScheduler { + private final Plugin plugin; + private final BukkitScheduler scheduler; + + public SpigotAsyncScheduler(Plugin plugin, BukkitScheduler scheduler) { + this.plugin = plugin; + this.scheduler = scheduler; + } + + @Override + public @NotNull Completable run(@NotNull Function, R> task) { + Ref> ref = new Ref<>(); + return ref.value = new SpigotTask.Completable<>(scheduler.runTaskAsynchronously(plugin, () -> ref.value.complete(task)), scheduler); + } + + @Override + public @NotNull Completable runDelayed(@NotNull Function, R> task, @Range(from = 0, to = Long.MAX_VALUE) long delay, @NotNull TimeUnit unit) { + Ref> ref = new Ref<>(); + return ref.value = new SpigotTask.Completable<>(scheduler.runTaskLaterAsynchronously(plugin, () -> ref.value.complete(task), unit.toMillis(delay) / 50), scheduler); + } + + @Override + public @NotNull Task runAtFixedRate(@NotNull Consumer task, @Range(from = 0, to = Long.MAX_VALUE) long initialDelay, @Range(from = 0, to = Long.MAX_VALUE) long period, @NotNull TimeUnit unit) { + Ref ref = new Ref<>(); + return ref.value = new SpigotTask(scheduler.runTaskTimerAsynchronously(plugin, () -> task.accept(ref.value), unit.toMillis(initialDelay) / 50, unit.toMillis(period) / 50)); + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotEntityScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotEntityScheduler.java new file mode 100644 index 000000000..45d390354 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotEntityScheduler.java @@ -0,0 +1,53 @@ +package com.volmit.iris.util.scheduling.spigot.split; + +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import com.volmit.iris.util.scheduling.split.IEntityScheduler; +import com.volmit.iris.util.scheduling.split.IGlobalScheduler; +import org.bukkit.entity.Entity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; + +import java.util.function.Consumer; +import java.util.function.Function; + +import static com.volmit.iris.util.scheduling.spigot.SpigotPlatform.isValid; + +public class SpigotEntityScheduler implements IEntityScheduler { + private final IGlobalScheduler scheduler; + private final Entity entity; + + public SpigotEntityScheduler(IGlobalScheduler scheduler, Entity entity) { + this.scheduler = scheduler; + this.entity = entity; + } + + @Override + public @Nullable Completable runDelayed(@NotNull Function, R> task, @Nullable Runnable retired, @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + if (!isValid(entity)) return null; + return scheduler.runDelayed(t -> { + if (!isValid(entity)) { + t.cancel(); + if (retired != null) + retired.run(); + return null; + } + return task.apply(t); + }, delayTicks); + } + + @Override + public @Nullable Task runAtFixedRate(@NotNull Consumer task, @Nullable Runnable retired, @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { + if (!isValid(entity)) return null; + return scheduler.runAtFixedRate(t -> { + if (!isValid(entity)) { + t.cancel(); + if (retired != null) + retired.run(); + return; + } + task.accept(t); + }, initialDelayTicks, periodTicks); + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotGlobalScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotGlobalScheduler.java new file mode 100644 index 000000000..9b82eba56 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotGlobalScheduler.java @@ -0,0 +1,37 @@ +package com.volmit.iris.util.scheduling.spigot.split; + +import com.volmit.iris.util.scheduling.Ref; +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import com.volmit.iris.util.scheduling.spigot.SpigotTask; +import com.volmit.iris.util.scheduling.split.IGlobalScheduler; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitScheduler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.util.function.Consumer; +import java.util.function.Function; + +@SuppressWarnings("deprecation") +public class SpigotGlobalScheduler implements IGlobalScheduler { + private final Plugin plugin; + private final BukkitScheduler scheduler; + + public SpigotGlobalScheduler(Plugin plugin, BukkitScheduler scheduler) { + this.plugin = plugin; + this.scheduler = scheduler; + } + + @Override + public @NotNull Completable runDelayed(@NotNull Function, R> task, @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + Ref> ref = new Ref<>(); + return ref.value = new SpigotTask.Completable<>(scheduler.runTaskLater(plugin, () -> ref.value.complete(task), delayTicks), scheduler); + } + + @Override + public @NotNull Task runAtFixedRate(@NotNull Consumer task, @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { + Ref ref = new Ref<>(); + return ref.value = new SpigotTask(scheduler.runTaskTimer(plugin, () -> task.accept(ref.value), initialDelayTicks, periodTicks)); + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotRegionScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotRegionScheduler.java new file mode 100644 index 000000000..75c83e58e --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotRegionScheduler.java @@ -0,0 +1,30 @@ +package com.volmit.iris.util.scheduling.spigot.split; + +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import com.volmit.iris.util.scheduling.split.IGlobalScheduler; +import com.volmit.iris.util.scheduling.split.IRegionScheduler; +import org.bukkit.World; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.util.function.Consumer; +import java.util.function.Function; + +public class SpigotRegionScheduler implements IRegionScheduler { + private final IGlobalScheduler scheduler; + + public SpigotRegionScheduler(IGlobalScheduler scheduler) { + this.scheduler = scheduler; + } + + @Override + public @NotNull Completable runDelayed(@NotNull World world, int chunkX, int chunkZ, @NotNull Function, R> task, @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return scheduler.runDelayed(task, delayTicks); + } + + @Override + public @NotNull Task runAtFixedRate(@NotNull World world, int chunkX, int chunkZ, @NotNull Consumer task, @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { + return scheduler.runAtFixedRate(task, initialDelayTicks, periodTicks); + } +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java new file mode 100644 index 000000000..d4b91cf80 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java @@ -0,0 +1,75 @@ +package com.volmit.iris.util.scheduling.split; + +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * Scheduler that may be used by plugins to schedule tasks to execute asynchronously from the server tick process. + */ +public interface IAsyncScheduler { + /** + * Schedules the specified task to be executed asynchronously immediately. + * @param task Specified task. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task run(@NotNull Consumer task) { + return run(t -> { + task.accept(t); + return null; + }); + } + + /** + * Schedules the specified task to be executed asynchronously immediately. + * @param task Specified task. + * @return The {@link Completable} that represents the scheduled task. + */ + @NotNull Completable run(@NotNull Function, R> task); + + /** + * Schedules the specified task to be executed asynchronously after the time delay has passed. + * @param task Specified task. + * @param delay The time delay to pass before the task should be executed. + * @param unit The time unit for the time delay. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runDelayed(@NotNull Consumer task, + @Range(from = 0, to = Long.MAX_VALUE) long delay, + @NotNull TimeUnit unit) { + return runDelayed(t -> { + task.accept(t); + return null; + }, delay, unit); + } + + /** + * Schedules the specified task to be executed asynchronously after the time delay has passed. + * @param task Specified task. + * @param delay The time delay to pass before the task should be executed. + * @param unit The time unit for the time delay. + * @return The {@link Completable} that represents the scheduled task. + */ + @NotNull Completable runDelayed(@NotNull Function, R> task, + @Range(from = 0, to = Long.MAX_VALUE) long delay, + @NotNull TimeUnit unit); + + /** + * Schedules the specified task to be executed asynchronously after the initial delay has passed, + * and then periodically executed with the specified period. + * @param task Specified task. + * @param initialDelay The time delay to pass before the first execution of the task. + * @param period The time between task executions after the first execution of the task. + * @param unit The time unit for the initial delay and period. + * @return The {@link Task} that represents the scheduled task. + */ + @NotNull Task runAtFixedRate(@NotNull Consumer task, + @Range(from = 0, to = Long.MAX_VALUE) long initialDelay, + @Range(from = 0, to = Long.MAX_VALUE) long period, + @NotNull TimeUnit unit); +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java new file mode 100644 index 000000000..0bfc22124 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java @@ -0,0 +1,136 @@ +package com.volmit.iris.util.scheduling.split; + +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Range; + +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * An entity can move between worlds with an arbitrary tick delay, be temporarily removed + * for players (i.e end credits), be partially removed from world state (i.e inactive but not removed), + * teleport between ticking regions, teleport between worlds, and even be removed entirely from the server. + * The uncertainty of an entity's state can make it difficult to schedule tasks without worrying about undefined + * behaviors resulting from any of the states listed previously. + * + *

+ * This class is designed to eliminate those states by providing an interface to run tasks only when an entity + * is contained in a world, on the owning thread for the region, and by providing the current Entity object. + * The scheduler also allows a task to provide a callback, the "retired" callback, that will be invoked + * if the entity is removed before a task that was scheduled could be executed. The scheduler is also + * completely thread-safe, allowing tasks to be scheduled from any thread context. The scheduler also indicates + * properly whether a task was scheduled successfully (i.e scheduler not retired), thus the code scheduling any task + * knows whether the given callbacks will be invoked eventually or not - which may be critical for off-thread + * contexts. + *

+ */ +public interface IEntityScheduler { + + /** + * Schedules a task to execute on the next tick. If the task failed to schedule because the scheduler is retired (entity + * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, + * or the retired callback will be invoked if the scheduler is retired. + * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove + * other entities, load chunks, load worlds, modify ticket levels, etc. + * + *

+ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. + *

+ * @param task The task to execute + * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. + * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. + */ + default @Nullable Task run(@NotNull Consumer task, + @Nullable Runnable retired) { + return run(t -> { + task.accept(t); + return null; + }, retired); + } + + /** + * Schedules a task to execute on the next tick. If the task failed to schedule because the scheduler is retired (entity + * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, + * or the retired callback will be invoked if the scheduler is retired. + * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove + * other entities, load chunks, load worlds, modify ticket levels, etc. + * + *

+ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. + *

+ * @param task The task to execute + * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. + * @return The {@link Completable} that represents the scheduled task, or {@code null} if the entity has been removed. + */ + default @Nullable Completable run(@NotNull Function, R> task, + @Nullable Runnable retired) { + return runDelayed(task, retired, 1); + } + + /** + * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity + * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, + * or the retired callback will be invoked if the scheduler is retired. + * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove + * other entities, load chunks, load worlds, modify ticket levels, etc. + * + *

+ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. + *

+ * @param task The task to execute + * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. + * @param delayTicks The delay, in ticks. + * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. + */ + default @Nullable Task runDelayed(@NotNull Consumer task, + @Nullable Runnable retired, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return runDelayed(t -> { + task.accept(t); + return null; + }, retired, delayTicks); + } + + /** + * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity + * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, + * or the retired callback will be invoked if the scheduler is retired. + * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove + * other entities, load chunks, load worlds, modify ticket levels, etc. + * + *

+ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. + *

+ * @param task The task to execute + * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. + * @param delayTicks The delay, in ticks. + * @return The {@link Completable} that represents the scheduled task, or {@code null} if the entity has been removed. + */ + @Nullable Completable runDelayed(@NotNull Function, R> task, + @Nullable Runnable retired, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks); + + /** + * Schedules a repeating task with the given delay and period. If the task failed to schedule because the scheduler + * is retired (entity removed), then returns {@code null}. Otherwise, either the task callback will be invoked after + * the specified delay, or the retired callback will be invoked if the scheduler is retired. + * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove + * other entities, load chunks, load worlds, modify ticket levels, etc. + * + *

+ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. + *

+ * @param task The task to execute + * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. + * @param initialDelayTicks The initial delay, in ticks. + * @param periodTicks The period, in ticks. + * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. + */ + @Nullable Task runAtFixedRate(@NotNull Consumer task, + @Nullable Runnable retired, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, + @Range(from = 1, to = Long.MAX_VALUE) long periodTicks); +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java new file mode 100644 index 000000000..9dea29cb8 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java @@ -0,0 +1,74 @@ +package com.volmit.iris.util.scheduling.split; + +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * The global region task scheduler may be used to schedule tasks that will execute on the global region. + *

+ * 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. + *

+ */ +public interface IGlobalScheduler { + /** + * Schedules a task to be executed on the global region on the next tick. + * @param task The task to execute + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task run(@NotNull Consumer task) { + return run(t -> { + task.accept(t); + return null; + }); + } + + /** + * Schedules a task to be executed on the global region on the next tick. + * @param task The task to execute + * @return The {@link Completable} that represents the scheduled task. + */ + default @NotNull Completable run(@NotNull Function, R> task) { + return runDelayed(task, 1); + } + + /** + * Schedules a task to be executed on the global region after the specified delay in ticks. + * @param task The task to execute + * @param delayTicks The delay, in ticks. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runDelayed(@NotNull Consumer task, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return runDelayed(t -> { + task.accept(t); + return null; + }, delayTicks); + } + + /** + * Schedules a task to be executed on the global region after the specified delay in ticks. + * @param task The task to execute + * @param delayTicks The delay, in ticks. + * @return The {@link Completable} that represents the scheduled task. + */ + @NotNull Completable runDelayed(@NotNull Function, R> task, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks); + + /** + * Schedules a repeating task to be executed on the global region after the initial delay with the + * specified period. + * @param task The task to execute + * @param initialDelayTicks The initial delay, in ticks. + * @param periodTicks The period, in ticks. + * @return The {@link Task} that represents the scheduled task. + */ + @NotNull Task runAtFixedRate(@NotNull Consumer task, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, + @Range(from = 1, to = Long.MAX_VALUE) long periodTicks); +} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java new file mode 100644 index 000000000..55607f2b9 --- /dev/null +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java @@ -0,0 +1,182 @@ +package com.volmit.iris.util.scheduling.split; + +import com.volmit.iris.util.scheduling.Task; +import com.volmit.iris.util.scheduling.Task.Completable; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Entity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * The region task scheduler can be used to schedule tasks by location to be executed on the region which owns the location. + *

+ * Note: It is entirely inappropriate to use the region scheduler to schedule tasks for entities. + * If you wish to schedule tasks to perform actions on entities, you should be using {@link Entity#getScheduler()} + * as the entity scheduler will "follow" an entity if it is teleported, whereas the region task scheduler + * will not. + *

+ */ +public interface IRegionScheduler { + /** + * Schedules a task to be executed on the region which owns the location on the next tick. + * + * @param world The world of the region that owns the task + * @param chunkX The chunk X coordinate of the region that owns the task + * @param chunkZ The chunk Z coordinate of the region that owns the task + * @param task The task to execute + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task run(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Consumer task) { + return run(world, chunkX, chunkZ, t -> { + task.accept(t); + return null; + }); + } + + /** + * Schedules a task to be executed on the region which owns the location on the next tick. + * + * @param world The world of the region that owns the task + * @param chunkX The chunk X coordinate of the region that owns the task + * @param chunkZ The chunk Z coordinate of the region that owns the task + * @param task The task to execute + * @return The {@link Completable} that represents the scheduled task. + */ + default @NotNull Completable run(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Function, R> task) { + return runDelayed(world, chunkX, chunkZ, task, 1); + } + + /** + * Schedules a task to be executed on the region which owns the location on the next tick. + * + * @param location The location at which the region executing should own + * @param task The task to execute + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task run(@NotNull Location location, + @NotNull Consumer task) { + return run(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task); + } + + /** + * Schedules a task to be executed on the region which owns the location on the next tick. + * + * @param location The location at which the region executing should own + * @param task The task to execute + * @return The {@link Completable} that represents the scheduled task. + */ + default @NotNull Completable run(@NotNull Location location, + @NotNull Function, R> task) { + return run(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task); + } + + /** + * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. + * + * @param world The world of the region that owns the task + * @param chunkX The chunk X coordinate of the region that owns the task + * @param chunkZ The chunk Z coordinate of the region that owns the task + * @param task The task to execute + * @param delayTicks The delay, in ticks. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runDelayed(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Consumer task, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return runDelayed(world, chunkX, chunkZ, t -> { + task.accept(t); + return null; + }, delayTicks); + } + + /** + * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. + * + * @param world The world of the region that owns the task + * @param chunkX The chunk X coordinate of the region that owns the task + * @param chunkZ The chunk Z coordinate of the region that owns the task + * @param task The task to execute + * @param delayTicks The delay, in ticks. + * @return The {@link Completable} that represents the scheduled task. + */ + @NotNull Completable runDelayed(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Function, R> task, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks); + + /** + * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. + * + * @param location The location at which the region executing should own + * @param task The task to execute + * @param delayTicks The delay, in ticks. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runDelayed(@NotNull Location location, + @NotNull Consumer task, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return runDelayed(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, delayTicks); + } + /** + * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. + * + * @param location The location at which the region executing should own + * @param task The task to execute + * @param delayTicks The delay, in ticks. + * @return The {@link Completable} that represents the scheduled task. + */ + default @NotNull Completable runDelayed(@NotNull Location location, + @NotNull Function, R> task, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return runDelayed(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, delayTicks); + } + + /** + * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the + * specified period. + * + * @param world The world of the region that owns the task + * @param chunkX The chunk X coordinate of the region that owns the task + * @param chunkZ The chunk Z coordinate of the region that owns the task + * @param task The task to execute + * @param initialDelayTicks The initial delay, in ticks. + * @param periodTicks The period, in ticks. + * @return The {@link Task} that represents the scheduled task. + */ + @NotNull Task runAtFixedRate(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Consumer task, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, + @Range(from = 1, to = Long.MAX_VALUE) long periodTicks); + + /** + * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the + * specified period. + * + * @param location The location at which the region executing should own + * @param task The task to execute + * @param initialDelayTicks The initial delay, in ticks. + * @param periodTicks The period, in ticks. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runAtFixedRate(@NotNull Location location, + @NotNull Consumer task, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, + @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { + return runAtFixedRate(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, initialDelayTicks, periodTicks); + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index c45462895..89f8e7dc4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -23,19 +23,20 @@ pluginManagement { } } plugins { - id ("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } rootProject.name = "Iris" include(":core") include( - ":nms:v1_21_R4", - ":nms:v1_21_R3", - ":nms:v1_21_R2", - ":nms:v1_21_R1", - ":nms:v1_20_R4", - ":nms:v1_20_R3", - ":nms:v1_20_R2", - ":nms:v1_20_R1", -) \ No newline at end of file + ":nms:v1_21_R4", + ":nms:v1_21_R3", + ":nms:v1_21_R2", + ":nms:v1_21_R1", + ":nms:v1_20_R4", + ":nms:v1_20_R3", + ":nms:v1_20_R2", + ":nms:v1_20_R1", +) +include("scheduler") \ No newline at end of file From ba6fac5422824062031de930de2362676b56e0f5 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 13 Jun 2025 21:05:11 +0200 Subject: [PATCH 02/26] more helper methods --- .../paper/split/PaperAsyncScheduler.java | 4 +- .../scheduling/split/IAsyncScheduler.java | 73 ++++++++- .../scheduling/split/IEntityScheduler.java | 114 ++++++++++++++ .../scheduling/split/IGlobalScheduler.java | 65 ++++++++ .../scheduling/split/IRegionScheduler.java | 146 ++++++++++++++++++ 5 files changed, 399 insertions(+), 3 deletions(-) diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java index f35b644b6..6eb38f052 100644 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java @@ -31,7 +31,7 @@ public PaperAsyncScheduler(Plugin plugin, AsyncScheduler scheduler) { @Override public @NotNull Completable runDelayed(@NotNull Function, R> task, - @Range(from = 1, to = Long.MAX_VALUE) long delay, + @Range(from = 0, to = Long.MAX_VALUE) long delay, @NotNull TimeUnit unit) { Ref> ref = new Ref<>(); return ref.value = new PaperTask.Completable<>(scheduler.runDelayed(plugin, t -> ref.value.complete(task), delay, unit), true); @@ -39,7 +39,7 @@ public PaperAsyncScheduler(Plugin plugin, AsyncScheduler scheduler) { @Override public @NotNull Task runAtFixedRate(@NotNull Consumer task, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelay, + @Range(from = 0, to = Long.MAX_VALUE) long initialDelay, @Range(from = 1, to = Long.MAX_VALUE) long period, @NotNull TimeUnit unit) { Ref ref = new Ref<>(); diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java index d4b91cf80..5a5968be3 100644 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java @@ -8,6 +8,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; /** * Scheduler that may be used by plugins to schedule tasks to execute asynchronously from the server tick process. @@ -25,6 +26,29 @@ public interface IAsyncScheduler { }); } + /** + * Schedules the specified task to be executed asynchronously immediately. + * @param task Specified task. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task run(@NotNull Runnable task) { + return run(t -> { + task.run(); + return null; + }); + } + + /** + * Schedules the specified task to be executed asynchronously immediately. + * @param task Specified task. + * @return The {@link Completable} that represents the scheduled task. + */ + default @NotNull Completable run(@NotNull Supplier task) { + return run(t -> { + return task.get(); + }); + } + /** * Schedules the specified task to be executed asynchronously immediately. * @param task Specified task. @@ -48,6 +72,37 @@ public interface IAsyncScheduler { }, delay, unit); } + /** + * Schedules the specified task to be executed asynchronously after the time delay has passed. + * @param task Specified task. + * @param delay The time delay to pass before the task should be executed. + * @param unit The time unit for the time delay. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runDelayed(@NotNull Runnable task, + @Range(from = 0, to = Long.MAX_VALUE) long delay, + @NotNull TimeUnit unit) { + return runDelayed(t -> { + task.run(); + return null; + }, delay, unit); + } + + /** + * Schedules the specified task to be executed asynchronously after the time delay has passed. + * @param task Specified task. + * @param delay The time delay to pass before the task should be executed. + * @param unit The time unit for the time delay. + * @return The {@link Completable} that represents the scheduled task. + */ + default @NotNull Completable runDelayed(@NotNull Supplier task, + @Range(from = 0, to = Long.MAX_VALUE) long delay, + @NotNull TimeUnit unit) { + return runDelayed(t -> { + return task.get(); + }, delay, unit); + } + /** * Schedules the specified task to be executed asynchronously after the time delay has passed. * @param task Specified task. @@ -59,6 +114,22 @@ public interface IAsyncScheduler { @Range(from = 0, to = Long.MAX_VALUE) long delay, @NotNull TimeUnit unit); + /** + * Schedules the specified task to be executed asynchronously after the initial delay has passed, + * and then periodically executed with the specified period. + * @param task Specified task. + * @param initialDelay The time delay to pass before the first execution of the task. + * @param period The time between task executions after the first execution of the task. + * @param unit The time unit for the initial delay and period. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runAtFixedRate(@NotNull Runnable task, + @Range(from = 0, to = Long.MAX_VALUE) long initialDelay, + @Range(from = 1, to = Long.MAX_VALUE) long period, + @NotNull TimeUnit unit) { + return runAtFixedRate(t -> task.run(), initialDelay, period, unit); + } + /** * Schedules the specified task to be executed asynchronously after the initial delay has passed, * and then periodically executed with the specified period. @@ -70,6 +141,6 @@ public interface IAsyncScheduler { */ @NotNull Task runAtFixedRate(@NotNull Consumer task, @Range(from = 0, to = Long.MAX_VALUE) long initialDelay, - @Range(from = 0, to = Long.MAX_VALUE) long period, + @Range(from = 1, to = Long.MAX_VALUE) long period, @NotNull TimeUnit unit); } diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java index 0bfc22124..141630a12 100644 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java @@ -8,6 +8,7 @@ import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; /** * An entity can move between worlds with an arbitrary tick delay, be temporarily removed @@ -51,6 +52,49 @@ public interface IEntityScheduler { }, retired); } + /** + * Schedules a task to execute on the next tick. If the task failed to schedule because the scheduler is retired (entity + * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, + * or the retired callback will be invoked if the scheduler is retired. + * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove + * other entities, load chunks, load worlds, modify ticket levels, etc. + * + *

+ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. + *

+ * @param task The task to execute + * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. + * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. + */ + default @Nullable Task run(@NotNull Runnable task, + @Nullable Runnable retired) { + return run(t -> { + task.run(); + return null; + }, retired); + } + + /** + * Schedules a task to execute on the next tick. If the task failed to schedule because the scheduler is retired (entity + * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, + * or the retired callback will be invoked if the scheduler is retired. + * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove + * other entities, load chunks, load worlds, modify ticket levels, etc. + * + *

+ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. + *

+ * @param task The task to execute + * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. + * @return The {@link Completable} that represents the scheduled task, or {@code null} if the entity has been removed. + */ + default @Nullable Completable run(@NotNull Supplier task, + @Nullable Runnable retired) { + return run(t -> { + return task.get(); + }, retired); + } + /** * Schedules a task to execute on the next tick. If the task failed to schedule because the scheduler is retired (entity * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, @@ -94,6 +138,53 @@ public interface IEntityScheduler { }, retired, delayTicks); } + /** + * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity + * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, + * or the retired callback will be invoked if the scheduler is retired. + * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove + * other entities, load chunks, load worlds, modify ticket levels, etc. + * + *

+ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. + *

+ * @param task The task to execute + * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. + * @param delayTicks The delay, in ticks. + * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. + */ + default @Nullable Task runDelayed(@NotNull Runnable task, + @Nullable Runnable retired, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return runDelayed(t -> { + task.run(); + return null; + }, retired, delayTicks); + } + + /** + * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity + * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, + * or the retired callback will be invoked if the scheduler is retired. + * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove + * other entities, load chunks, load worlds, modify ticket levels, etc. + * + *

+ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. + *

+ * @param task The task to execute + * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. + * @param delayTicks The delay, in ticks. + * @return The {@link Completable} that represents the scheduled task, or {@code null} if the entity has been removed. + */ + default @Nullable Completable runDelayed(@NotNull Supplier task, + @Nullable Runnable retired, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return runDelayed(t -> { + return task.get(); + }, retired, delayTicks); + } + /** * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, @@ -113,6 +204,29 @@ public interface IEntityScheduler { @Nullable Runnable retired, @Range(from = 1, to = Long.MAX_VALUE) long delayTicks); + /** + * Schedules a repeating task with the given delay and period. If the task failed to schedule because the scheduler + * is retired (entity removed), then returns {@code null}. Otherwise, either the task callback will be invoked after + * the specified delay, or the retired callback will be invoked if the scheduler is retired. + * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove + * other entities, load chunks, load worlds, modify ticket levels, etc. + * + *

+ * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. + *

+ * @param task The task to execute + * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. + * @param initialDelayTicks The initial delay, in ticks. + * @param periodTicks The period, in ticks. + * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. + */ + default @Nullable Task runAtFixedRate(@NotNull Runnable task, + @Nullable Runnable retired, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, + @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { + return runAtFixedRate(t -> task.run(), retired, initialDelayTicks, periodTicks); + } + /** * Schedules a repeating task with the given delay and period. If the task failed to schedule because the scheduler * is retired (entity removed), then returns {@code null}. Otherwise, either the task callback will be invoked after diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java index 9dea29cb8..5644443ee 100644 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java @@ -7,6 +7,7 @@ import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; /** * The global region task scheduler may be used to schedule tasks that will execute on the global region. @@ -28,6 +29,29 @@ public interface IGlobalScheduler { }); } + /** + * Schedules a task to be executed on the global region on the next tick. + * @param task The task to execute + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task run(@NotNull Runnable task) { + return run(t -> { + task.run(); + return null; + }); + } + + /** + * Schedules a task to be executed on the global region on the next tick. + * @param task The task to execute + * @return The {@link Completable} that represents the scheduled task. + */ + default @NotNull Completable run(@NotNull Supplier task) { + return run(t -> { + return task.get(); + }); + } + /** * Schedules a task to be executed on the global region on the next tick. * @param task The task to execute @@ -51,6 +75,33 @@ public interface IGlobalScheduler { }, delayTicks); } + /** + * Schedules a task to be executed on the global region after the specified delay in ticks. + * @param task The task to execute + * @param delayTicks The delay, in ticks. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runDelayed(@NotNull Runnable task, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return runDelayed(t -> { + task.run(); + return null; + }, delayTicks); + } + + /** + * Schedules a task to be executed on the global region after the specified delay in ticks. + * @param task The task to execute + * @param delayTicks The delay, in ticks. + * @return The {@link Completable} that represents the scheduled task. + */ + default @NotNull Completable runDelayed(@NotNull Supplier task, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return runDelayed(t -> { + return task.get(); + }, delayTicks); + } + /** * Schedules a task to be executed on the global region after the specified delay in ticks. * @param task The task to execute @@ -60,6 +111,20 @@ public interface IGlobalScheduler { @NotNull Completable runDelayed(@NotNull Function, R> task, @Range(from = 1, to = Long.MAX_VALUE) long delayTicks); + /** + * Schedules a repeating task to be executed on the global region after the initial delay with the + * specified period. + * @param task The task to execute + * @param initialDelayTicks The initial delay, in ticks. + * @param periodTicks The period, in ticks. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runAtFixedRate(@NotNull Runnable task, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, + @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { + return runAtFixedRate(t -> task.run(), initialDelayTicks, periodTicks); + } + /** * Schedules a repeating task to be executed on the global region after the initial delay with the * specified period. diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java index 55607f2b9..b57a07038 100644 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java +++ b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java @@ -10,6 +10,7 @@ import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; /** * The region task scheduler can be used to schedule tasks by location to be executed on the region which owns the location. @@ -40,6 +41,43 @@ public interface IRegionScheduler { }); } + /** + * Schedules a task to be executed on the region which owns the location on the next tick. + * + * @param world The world of the region that owns the task + * @param chunkX The chunk X coordinate of the region that owns the task + * @param chunkZ The chunk Z coordinate of the region that owns the task + * @param task The task to execute + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task run(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Runnable task) { + return run(world, chunkX, chunkZ, t -> { + task.run(); + return null; + }); + } + + /** + * Schedules a task to be executed on the region which owns the location on the next tick. + * + * @param world The world of the region that owns the task + * @param chunkX The chunk X coordinate of the region that owns the task + * @param chunkZ The chunk Z coordinate of the region that owns the task + * @param task The task to execute + * @return The {@link Completable} that represents the scheduled task. + */ + default @NotNull Completable run(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Supplier task) { + return run(world, chunkX, chunkZ, t -> { + return task.get(); + }); + } + /** * Schedules a task to be executed on the region which owns the location on the next tick. * @@ -68,6 +106,34 @@ public interface IRegionScheduler { return run(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task); } + /** + * Schedules a task to be executed on the region which owns the location on the next tick. + * + * @param location The location at which the region executing should own + * @param task The task to execute + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task run(@NotNull Location location, + @NotNull Runnable task) { + return run(location, t -> { + task.run(); + }); + } + + /** + * Schedules a task to be executed on the region which owns the location on the next tick. + * + * @param location The location at which the region executing should own + * @param task The task to execute + * @return The {@link Completable} that represents the scheduled task. + */ + default @NotNull Completable run(@NotNull Location location, + @NotNull Supplier task) { + return run(location, t -> { + return task.get(); + }); + } + /** * Schedules a task to be executed on the region which owns the location on the next tick. * @@ -101,6 +167,47 @@ public interface IRegionScheduler { }, delayTicks); } + /** + * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. + * + * @param world The world of the region that owns the task + * @param chunkX The chunk X coordinate of the region that owns the task + * @param chunkZ The chunk Z coordinate of the region that owns the task + * @param task The task to execute + * @param delayTicks The delay, in ticks. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runDelayed(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Runnable task, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return runDelayed(world, chunkX, chunkZ, t -> { + task.run(); + return null; + }, delayTicks); + } + + /** + * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. + * + * @param world The world of the region that owns the task + * @param chunkX The chunk X coordinate of the region that owns the task + * @param chunkZ The chunk Z coordinate of the region that owns the task + * @param task The task to execute + * @param delayTicks The delay, in ticks. + * @return The {@link Completable} that represents the scheduled task. + */ + default @NotNull Completable runDelayed(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Supplier task, + @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { + return runDelayed(world, chunkX, chunkZ, t -> { + return task.get(); + }, delayTicks); + } + /** * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. * @@ -130,6 +237,7 @@ public interface IRegionScheduler { @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { return runDelayed(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, delayTicks); } + /** * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. * @@ -144,6 +252,27 @@ public interface IRegionScheduler { return runDelayed(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, delayTicks); } + /** + * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the + * specified period. + * + * @param world The world of the region that owns the task + * @param chunkX The chunk X coordinate of the region that owns the task + * @param chunkZ The chunk Z coordinate of the region that owns the task + * @param task The task to execute + * @param initialDelayTicks The initial delay, in ticks. + * @param periodTicks The period, in ticks. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runAtFixedRate(@NotNull World world, + int chunkX, + int chunkZ, + @NotNull Runnable task, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, + @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { + return runAtFixedRate(world, chunkX, chunkZ, t -> task.run(), initialDelayTicks, periodTicks); + } + /** * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the * specified period. @@ -163,6 +292,23 @@ public interface IRegionScheduler { @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, @Range(from = 1, to = Long.MAX_VALUE) long periodTicks); + /** + * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the + * specified period. + * + * @param location The location at which the region executing should own + * @param task The task to execute + * @param initialDelayTicks The initial delay, in ticks. + * @param periodTicks The period, in ticks. + * @return The {@link Task} that represents the scheduled task. + */ + default @NotNull Task runAtFixedRate(@NotNull Location location, + @NotNull Runnable task, + @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, + @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { + return runAtFixedRate(location, t -> task.run(), initialDelayTicks, periodTicks); + } + /** * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the * specified period. From 35b879f0df8b023f10c32d143fb865cb9c68c54e Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 13 Jun 2025 21:44:02 +0200 Subject: [PATCH 03/26] get iris to load on folia, but it will not load worlds as this is currently not possible --- build.gradle.kts | 15 ++++ core/src/main/java/com/volmit/iris/Iris.java | 10 ++- .../iris/core/commands/CommandIris.java | 10 +-- .../iris/core/commands/CommandStudio.java | 42 +++++----- .../volmit/iris/core/edit/BlockSignal.java | 11 ++- .../volmit/iris/core/edit/JigsawEditor.java | 5 +- .../pregenerator/DeepSearchPregenerator.java | 16 ++-- .../core/pregenerator/LazyPregenerator.java | 16 ++-- .../core/pregenerator/TurboPregenerator.java | 16 ++-- .../com/volmit/iris/core/service/EditSVC.java | 2 +- .../volmit/iris/core/service/ObjectSVC.java | 27 +++--- .../volmit/iris/core/tools/IrisConverter.java | 9 +- .../com/volmit/iris/engine/IrisEngine.java | 5 +- .../framework/EngineAssignedWorldManager.java | 9 +- .../iris/engine/object/IrisCommand.java | 5 +- .../volmit/iris/engine/object/IrisEntity.java | 13 ++- .../volmit/iris/util/board/BoardManager.java | 7 +- .../iris/util/board/BoardUpdateTask.java | 3 +- .../volmit/iris/util/plugin/VolmitPlugin.java | 1 - .../volmit/iris/util/plugin/VolmitSender.java | 8 +- .../volmit/iris/util/profile/MsptTimings.java | 14 ++-- .../com/volmit/iris/util/scheduling/AR.java | 12 +-- .../com/volmit/iris/util/scheduling/J.java | 84 +++++-------------- .../com/volmit/iris/util/scheduling/SR.java | 12 ++- .../volmit/iris/util/scheduling/jobs/Job.java | 4 +- core/src/main/resources/plugin.yml | 3 +- 26 files changed, 152 insertions(+), 207 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index bb061f2bc..d4cd82c4f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,6 +2,7 @@ import com.volmit.nmstools.NMSToolsExtension import com.volmit.nmstools.NMSToolsPlugin import de.undercouch.gradle.tasks.download.Download import xyz.jpenilla.runpaper.task.RunServer +import xyz.jpenilla.runtask.service.DownloadsAPIService import kotlin.system.exitProcess /* @@ -104,6 +105,20 @@ nmsBindings.forEach { key, value -> systemProperty("net.kyori.ansi.colorLevel", color) systemProperty("com.mojang.eula.agree", true) } + + tasks.register("runFolia-$key") { + group = "servers" + downloadsApiService = DownloadsAPIService.folia(project) + minecraftVersion(value.split("-")[0]) + minHeapSize = serverMinHeap + maxHeapSize = serverMaxHeap + pluginJars(tasks.jar.flatMap { it.archiveFile }) + javaLauncher = javaToolchains.launcherFor { languageVersion = JavaLanguageVersion.of(jvmVersion.getOrDefault(key, 21))} + runDirectory.convention(layout.buildDirectory.dir("run/$key")) + systemProperty("disable.watchdog", "") + systemProperty("net.kyori.ansi.colorLevel", color) + systemProperty("com.mojang.eula.agree", true) + } } tasks { diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 3192a2a61..87cb2cd0a 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -63,6 +63,7 @@ import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.reflect.ShadeFix; import com.volmit.iris.util.scheduling.J; +import com.volmit.iris.util.scheduling.Platform; import com.volmit.iris.util.scheduling.Queue; import com.volmit.iris.util.scheduling.ShurikenQueue; import com.volmit.iris.util.sentry.Attachments; @@ -98,6 +99,7 @@ import java.net.URL; import java.text.NumberFormat; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -115,6 +117,7 @@ public class Iris extends VolmitPlugin implements Listener { public static MythicMobsLink linkMythicMobs; public static IrisCompat compat; public static FileWatcher configWatcher; + public static Platform scheduler; private static VolmitSender sender; static { @@ -333,15 +336,14 @@ public static void safeguard(String format, Object... args) { @SuppressWarnings("deprecation") public static void later(NastyRunnable object) { try { - Bukkit.getScheduler().scheduleAsyncDelayedTask(instance, () -> - { + scheduler.async().runDelayed(task -> { try { object.run(); } catch (Throwable e) { e.printStackTrace(); Iris.reportError(e); } - }, RNG.r.i(100, 1200)); + }, RNG.r.i(5, 60), TimeUnit.SECONDS); } catch (IllegalPluginAccessException ignored) { } @@ -459,6 +461,7 @@ private static void fixShading() { } private void enable() { instance = this; + scheduler = Platform.create(this); services = new KMap<>(); setupAudience(); setupSentry(); @@ -580,7 +583,6 @@ public void onEnable() { public void onDisable() { services.values().forEach(IrisService::onDisable); - Bukkit.getScheduler().cancelTasks(this); HandlerList.unregisterAll((Plugin) this); postShutdown.forEach(Runnable::run); super.onDisable(); diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java index 4723ed3e1..06c61e4c2 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java @@ -49,7 +49,6 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; -import org.bukkit.scheduler.BukkitRunnable; import java.io.File; import java.io.IOException; @@ -157,13 +156,8 @@ public void teleport( return; } - new BukkitRunnable() { - @Override - public void run() { - target.teleport(world.getSpawnLocation()); - new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + "."); - } - }.runTask(Iris.instance); + Iris.scheduler.teleportAsync(target, world.getSpawnLocation()).thenRun(() -> + new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + ".")); } @Decree(description = "Print version information") diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java index 0abb77a15..06fd6c36d 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java @@ -55,11 +55,11 @@ import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; -import com.volmit.iris.util.scheduling.O; import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.jobs.QueueJob; import io.papermc.lib.PaperLib; import org.bukkit.*; +import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.util.BlockVector; @@ -309,27 +309,25 @@ public void loot( return; } + Player player = player(); + var scheduler = Iris.scheduler.entity(player); + scheduler.run(() -> { + sender().sendMessage(C.GREEN + "Opening inventory now!"); + player.openInventory(inv); - O ta = new O<>(); - ta.set(-1); - - ta.set(Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () -> - { - if (!player().getOpenInventory().getType().equals(InventoryType.CHEST)) { - Bukkit.getScheduler().cancelTask(ta.get()); - sender().sendMessage(C.GREEN + "Opened inventory!"); - return; - } - - if (!add) { - inv.clear(); - } + scheduler.runAtFixedRate(refresh -> { + if (!player.getOpenInventory().getType().equals(InventoryType.CHEST)) { + refresh.cancel(); + return; + } - engine().addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player().getWorld(), player().getLocation().getBlockX(), player().getLocation().getBlockY(), player().getLocation().getBlockZ(), 1); - }, 0, fast ? 5 : 35)); + if (!add) { + inv.clear(); + } - sender().sendMessage(C.GREEN + "Opening inventory now!"); - player().openInventory(inv); + engine().addItems(true, inv, new RNG(RNG.r.imax()), tables, InventorySlotType.STORAGE, player.getWorld(), player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ(), 1); + }, null, 1, fast ? 5 : 35); + }, null); } @@ -350,9 +348,7 @@ public void distances(@Param(description = "The radius in chunks") int radius) { var loc = player().getLocation(); int totalTasks = d * d; AtomicInteger completedTasks = new AtomicInteger(0); - int c = J.ar(() -> { - sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding structures"); - }, 0); + var c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding structures"), 0); new Spiraler(d, d, (x, z) -> executor.queue(() -> { var struct = engine.getStructureAt(x, z); @@ -364,7 +360,7 @@ public void distances(@Param(description = "The radius in chunks") int radius) { executor.complete(); multiBurst.close(); - J.car(c); + if (c != null) c.cancel(); for (var key : data.keySet()) { var list = data.get(key); diff --git a/core/src/main/java/com/volmit/iris/core/edit/BlockSignal.java b/core/src/main/java/com/volmit/iris/core/edit/BlockSignal.java index 65526cd87..d6c302893 100644 --- a/core/src/main/java/com/volmit/iris/core/edit/BlockSignal.java +++ b/core/src/main/java/com/volmit/iris/core/edit/BlockSignal.java @@ -18,7 +18,9 @@ package com.volmit.iris.core.edit; +import com.volmit.iris.Iris; import com.volmit.iris.util.parallel.MultiBurst; +import com.volmit.iris.util.scheduling.AR; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.SR; import org.bukkit.Location; @@ -79,7 +81,7 @@ public static Runnable forever(Block block) { e.setTicksLived(1); e.setVelocity(new Vector(0, 0, 0)); - new SR(20) { + new AR(20) { @Override public void run() { if (e.isDead()) { @@ -87,9 +89,10 @@ public void run() { return; } - e.setTicksLived(1); - e.teleport(tg.clone()); - e.setVelocity(new Vector(0, 0, 0)); + Iris.scheduler.teleportAsync(e, tg.clone()).thenAccept(b -> { + e.setTicksLived(1); + e.setVelocity(new Vector(0, 0, 0)); + }).join(); } }; diff --git a/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java b/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java index 2b20693be..808a46844 100644 --- a/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java +++ b/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java @@ -30,6 +30,7 @@ import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; +import com.volmit.iris.util.scheduling.Task; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Particle; @@ -55,7 +56,7 @@ public class JigsawEditor implements Listener { private final IrisJigsawPiece piece; private final Location origin; private final Cuboid cuboid; - private final int ticker; + private final Task ticker; private final KMap falling = new KMap<>(); private final ChronoLatch cl = new ChronoLatch(100); private Location target; @@ -197,7 +198,7 @@ public void close() { } public void exit() { - J.car(ticker); + if (ticker != null) ticker.cancel(); Iris.instance.unregisterListener(this); try { J.sfut(() -> { diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/DeepSearchPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/DeepSearchPregenerator.java index e9d2b8f74..685898c65 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/DeepSearchPregenerator.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/DeepSearchPregenerator.java @@ -22,7 +22,6 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.world.WorldUnloadEvent; -import org.bukkit.scheduler.BukkitRunnable; import java.io.File; import java.io.FileWriter; @@ -235,16 +234,13 @@ public void shutdownInstance(World world) throws IOException { } save(); jobs.remove(world.getName()); - new BukkitRunnable() { - @Override - public void run() { - while (deepFile.exists()){ - deepFile.delete(); - J.sleep(1000); - } - Iris.info("DeepSearch: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed."); + J.a(() -> { + while (deepFile.exists()) { + deepFile.delete(); + J.sleep(1000); } - }.runTaskLater(Iris.instance, 20L); + Iris.info("DeepSearch: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed."); + }, 10); } catch (Exception e) { Iris.error("Failed to shutdown DeepSearch for " + world.getName()); e.printStackTrace(); diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java index dc58f2ed5..ebfbf81de 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java @@ -19,7 +19,6 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.world.WorldUnloadEvent; -import org.bukkit.scheduler.BukkitRunnable; import java.io.File; import java.io.IOException; @@ -238,16 +237,13 @@ public void shutdownInstance(World world) throws IOException { } save(); jobs.remove(world.getName()); - new BukkitRunnable() { - @Override - public void run() { - while (lazyFile.exists()){ - lazyFile.delete(); - J.sleep(1000); - } - Iris.info("LazyGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed."); + J.a(() -> { + while (lazyFile.exists()){ + lazyFile.delete(); + J.sleep(1000); } - }.runTaskLater(Iris.instance, 20L); + Iris.info("LazyGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed."); + }, 20); } catch (Exception e) { Iris.error("Failed to shutdown Lazygen for " + world.getName()); e.printStackTrace(); diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/TurboPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/TurboPregenerator.java index 4588597c3..5a8312307 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/TurboPregenerator.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/TurboPregenerator.java @@ -26,7 +26,6 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.world.WorldUnloadEvent; -import org.bukkit.scheduler.BukkitRunnable; import org.checkerframework.checker.units.qual.N; import java.io.File; @@ -302,16 +301,13 @@ public void shutdownInstance(World world) throws IOException { } save(); jobs.remove(world.getName()); - new BukkitRunnable() { - @Override - public void run() { - while (turboFile.exists()) { - turboFile.delete(); - J.sleep(1000); - } - Iris.info("turboGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed."); + J.a(() -> { + while (turboFile.exists()) { + turboFile.delete(); + J.sleep(1000); } - }.runTaskLater(Iris.instance, 20L); + Iris.info("turboGen: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed."); + }, 20); } catch (Exception e) { Iris.error("Failed to shutdown turbogen for " + world.getName()); e.printStackTrace(); diff --git a/core/src/main/java/com/volmit/iris/core/service/EditSVC.java b/core/src/main/java/com/volmit/iris/core/service/EditSVC.java index dc944f1f2..f8aa2ca92 100644 --- a/core/src/main/java/com/volmit/iris/core/service/EditSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/EditSVC.java @@ -38,7 +38,7 @@ public class EditSVC implements IrisService { @Override public void onEnable() { this.editors = new KMap<>(); - Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::update, 1000, 1000); + Iris.scheduler.global().runAtFixedRate(this::update, 1000, 1000); } @Override diff --git a/core/src/main/java/com/volmit/iris/core/service/ObjectSVC.java b/core/src/main/java/com/volmit/iris/core/service/ObjectSVC.java index 5fadf8b4a..08311871f 100644 --- a/core/src/main/java/com/volmit/iris/core/service/ObjectSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/ObjectSVC.java @@ -71,21 +71,18 @@ private void loopChange(int amount) { */ private void revert(Map blocks) { Iterator> it = blocks.entrySet().iterator(); - Bukkit.getScheduler().runTask(Iris.instance, () -> { - int amount = 0; - while (it.hasNext()) { - Map.Entry entry = it.next(); - BlockData data = entry.getValue(); - entry.getKey().setBlockData(data, false); - - it.remove(); - - amount++; + var scheduler = Iris.scheduler.region(); + for (int i = 0; i < 200 && it.hasNext(); i++) { + Map.Entry entry = it.next(); + Block block = entry.getKey(); + BlockData data = entry.getValue(); + it.remove(); + + scheduler.run(block.getLocation(), () -> block.setBlockData(data, false)); + } - if (amount > 200) { - J.s(() -> revert(blocks), 1); - } - } - }); + if (it.hasNext()) { + J.s(() -> revert(blocks), 1); + } } } \ No newline at end of file diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java b/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java index f58cc5c69..a355d14b5 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java @@ -11,6 +11,7 @@ import com.volmit.iris.util.reflect.V; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; +import com.volmit.iris.util.scheduling.Task; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import org.apache.commons.io.FileUtils; import org.bukkit.Bukkit; @@ -58,7 +59,7 @@ public static void convertSchematics(VolmitSender sender) { int objW = ((ShortTag) compound.get("Width")).getValue(); int objH = ((ShortTag) compound.get("Height")).getValue(); int objD = ((ShortTag) compound.get("Length")).getValue(); - int i = -1; + Task i = null; int mv = objW * objH * objD; AtomicInteger v = new AtomicInteger(0); if (mv > 500_000) { @@ -66,9 +67,7 @@ public static void convertSchematics(VolmitSender sender) { Iris.info(C.GRAY + "Converting.. "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob")); Iris.info(C.GRAY + "- It may take a while"); if (sender.isPlayer()) { - i = J.ar(() -> { - sender.sendProgress((double) v.get() / mv, "Converting"); - }, 0); + i = J.ar(() -> sender.sendProgress((double) v.get() / mv, "Converting"), 0); } } @@ -97,7 +96,7 @@ public static void convertSchematics(VolmitSender sender) { } } } - if (i != -1) J.car(i); + if (i != null) i.cancel(); try { object.shrinkwrap(); object.write(new File(folder, schem.getName().replace(".schem", ".iob"))); diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java index 2f9bd5a88..47845161d 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -50,6 +50,7 @@ import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; +import com.volmit.iris.util.scheduling.Task; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -85,7 +86,7 @@ public class IrisEngine implements Engine { private final EngineMetrics metrics; private final boolean studio; private final AtomicRollingSequence wallClock; - private final int art; + private final Task art; private final AtomicCache engineData = new AtomicCache<>(); private final AtomicBoolean cleaning; private final ChronoLatch cleanLatch; @@ -418,7 +419,7 @@ public void printMetrics(CommandSender sender) { public void close() { PregeneratorJob.shutdownInstance(); closed = true; - J.car(art); + art.cancel(); getWorldManager().close(); getTarget().close(); saveEngineData(); diff --git a/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java b/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java index e53b35e5c..0dc0c49d0 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java @@ -24,6 +24,7 @@ import com.volmit.iris.util.format.C; import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.plugin.VolmitSender; +import com.volmit.iris.util.scheduling.Task; import org.bukkit.*; import org.bukkit.entity.EnderSignal; import org.bukkit.entity.Player; @@ -41,18 +42,18 @@ import java.util.concurrent.atomic.AtomicBoolean; public abstract class EngineAssignedWorldManager extends EngineAssignedComponent implements EngineWorldManager, Listener { - private final int taskId; + private final Task task; protected AtomicBoolean ignoreTP = new AtomicBoolean(false); public EngineAssignedWorldManager() { super(null, null); - taskId = -1; + task = null; } public EngineAssignedWorldManager(Engine engine) { super(engine, "World"); Iris.instance.registerListener(this); - taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, this::onTick, 0, 0); + task = Iris.scheduler.global().runAtFixedRate(this::onTick, 1, 1); } @EventHandler @@ -129,6 +130,6 @@ public void on(ChunkLoadEvent e) { public void close() { super.close(); Iris.instance.unregisterListener(this); - Bukkit.getScheduler().cancelTask(taskId); + if (task != null) task.cancel(); } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCommand.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCommand.java index 36f47fb44..2c151534f 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCommand.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCommand.java @@ -65,6 +65,7 @@ public void run(Location at) { return; } + var scheduler = Iris.scheduler.global(); for (String command : commands) { command = (command.startsWith("/") ? command.replaceFirst("/", "") : command) .replaceAll("\\Q{x}\\E", String.valueOf(at.getBlockX())) @@ -72,9 +73,9 @@ public void run(Location at) { .replaceAll("\\Q{z}\\E", String.valueOf(at.getBlockZ())); final String finalCommand = command; if (repeat) { - Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, () -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), delay, repeatDelay); + scheduler.runAtFixedRate(() -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), Math.max(delay, 1), Math.max(repeatDelay, 1)); } else { - Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), delay); + scheduler.runDelayed(() -> Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), finalCommand), Math.max(delay, 1)); } } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java index dfb2508d0..109d9a9c1 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java @@ -337,9 +337,7 @@ public void fillInventory(Inventory inventory, Random random, LootContext contex if (e instanceof Villager) { Villager villager = (Villager) e; villager.setRemoveWhenFarAway(false); - Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> { - villager.setPersistent(true); - }, 1); + Iris.scheduler.entity(villager).run(() -> villager.setPersistent(true), null); } if (e instanceof Mob) { @@ -377,10 +375,9 @@ public void fillInventory(Inventory inventory, Random random, LootContext contex ((LivingEntity) e).setCollidable(false); ((LivingEntity) e).setNoDamageTicks(100000); AtomicInteger t = new AtomicInteger(0); - AtomicInteger v = new AtomicInteger(0); - v.set(J.sr(() -> { + Iris.scheduler.global().runAtFixedRate(task -> { if (t.get() > 100) { - J.csr(v.get()); + task.cancel(); return; } @@ -393,13 +390,13 @@ public void fillInventory(Inventory inventory, Random random, LootContext contex e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f); } } else { - J.csr(v.get()); + task.cancel(); ((LivingEntity) e).setNoDamageTicks(0); ((LivingEntity) e).setCollidable(true); ((LivingEntity) e).setAI(true); e.setInvulnerable(false); } - }, 0)); + }, 1, 1); } }); diff --git a/core/src/main/java/com/volmit/iris/util/board/BoardManager.java b/core/src/main/java/com/volmit/iris/util/board/BoardManager.java index fe61666de..d4813df7f 100644 --- a/core/src/main/java/com/volmit/iris/util/board/BoardManager.java +++ b/core/src/main/java/com/volmit/iris/util/board/BoardManager.java @@ -18,10 +18,11 @@ package com.volmit.iris.util.board; +import com.volmit.iris.Iris; +import com.volmit.iris.util.scheduling.Task; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitTask; import java.util.Collections; import java.util.Map; @@ -34,7 +35,7 @@ public class BoardManager { private final JavaPlugin plugin; private final Map scoreboards; - private final BukkitTask updateTask; + private final Task updateTask; private BoardSettings boardSettings; @@ -42,7 +43,7 @@ public BoardManager(JavaPlugin plugin, BoardSettings boardSettings) { this.plugin = plugin; this.boardSettings = boardSettings; this.scoreboards = new ConcurrentHashMap<>(); - this.updateTask = new BoardUpdateTask(this).runTaskTimer(plugin, 2L, 20L); + this.updateTask = Iris.scheduler.global().runAtFixedRate(new BoardUpdateTask(this), 2L, 20L); plugin.getServer().getOnlinePlayers().forEach(this::setup); } diff --git a/core/src/main/java/com/volmit/iris/util/board/BoardUpdateTask.java b/core/src/main/java/com/volmit/iris/util/board/BoardUpdateTask.java index ce7ded229..9ae24d7d1 100644 --- a/core/src/main/java/com/volmit/iris/util/board/BoardUpdateTask.java +++ b/core/src/main/java/com/volmit/iris/util/board/BoardUpdateTask.java @@ -20,7 +20,6 @@ import lombok.RequiredArgsConstructor; import org.bukkit.Bukkit; -import org.bukkit.scheduler.BukkitRunnable; import java.util.UUID; import java.util.function.Predicate; @@ -30,7 +29,7 @@ * @since 5/31/2018 */ @RequiredArgsConstructor -public class BoardUpdateTask extends BukkitRunnable { +public class BoardUpdateTask implements Runnable { private static final Predicate PLAYER_IS_ONLINE = uuid -> Bukkit.getPlayer(uuid) != null; diff --git a/core/src/main/java/com/volmit/iris/util/plugin/VolmitPlugin.java b/core/src/main/java/com/volmit/iris/util/plugin/VolmitPlugin.java index 130f8b686..0174b06fb 100644 --- a/core/src/main/java/com/volmit/iris/util/plugin/VolmitPlugin.java +++ b/core/src/main/java/com/volmit/iris/util/plugin/VolmitPlugin.java @@ -245,7 +245,6 @@ private void registerPermission(MortarPermission pc) { @Override public void onDisable() { stop(); - Bukkit.getScheduler().cancelTasks(this); unregisterListener(this); unregisterAll(); } diff --git a/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java b/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java index dccb95ce7..efe7ae481 100644 --- a/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java +++ b/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java @@ -48,6 +48,7 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; @@ -298,17 +299,16 @@ private Component createComponentRaw(String message) { } public void showWaiting(String passive, CompletableFuture f) { - AtomicInteger v = new AtomicInteger(); AtomicReference g = new AtomicReference<>(); - v.set(J.ar(() -> { + Iris.scheduler.async().runAtFixedRate(task -> { if (f.isDone() && g.get() != null) { - J.car(v.get()); + task.cancel(); sendAction(" "); return; } sendProgress(-1, passive); - }, 0)); + }, 0, 50, TimeUnit.MILLISECONDS); J.a(() -> { try { g.set(f.get()); diff --git a/core/src/main/java/com/volmit/iris/util/profile/MsptTimings.java b/core/src/main/java/com/volmit/iris/util/profile/MsptTimings.java index 2d098e1e7..8ce433285 100644 --- a/core/src/main/java/com/volmit/iris/util/profile/MsptTimings.java +++ b/core/src/main/java/com/volmit/iris/util/profile/MsptTimings.java @@ -1,8 +1,10 @@ package com.volmit.iris.util.profile; +import com.volmit.iris.Iris; import com.volmit.iris.util.math.M; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.Looper; +import com.volmit.iris.util.scheduling.Task; import org.bukkit.Bukkit; import java.util.concurrent.atomic.AtomicInteger; @@ -12,7 +14,7 @@ public abstract class MsptTimings extends Looper { private final AtomicInteger currentTick = new AtomicInteger(0); private int lastTick, lastMspt; private long lastTime; - private int taskId = -1; + private Task task = null; public MsptTimings() { setName("MsptTimings"); @@ -52,18 +54,18 @@ public final int getMspt() { protected abstract void update(int mspt); private boolean startTickTask() { - if (taskId != -1 && (Bukkit.getScheduler().isQueued(taskId) || Bukkit.getScheduler().isCurrentlyRunning(taskId))) + if (task != null && !task.cancelled()) return false; - taskId = J.sr(() -> { + task = Iris.scheduler.global().runAtFixedRate(t -> { if (isInterrupted()) { - J.csr(taskId); + t.cancel(); return; } currentTick.incrementAndGet(); - }, 1); - return taskId != -1; + }, 1, 1); + return true; } private static class Simple extends MsptTimings { diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/AR.java b/core/src/main/java/com/volmit/iris/util/scheduling/AR.java index b5fda2c52..244781e21 100644 --- a/core/src/main/java/com/volmit/iris/util/scheduling/AR.java +++ b/core/src/main/java/com/volmit/iris/util/scheduling/AR.java @@ -21,22 +21,18 @@ import com.volmit.iris.util.plugin.CancellableTask; public abstract class AR implements Runnable, CancellableTask { - private int id = 0; + private final Task task; public AR() { - this(0); + this(1); } public AR(int interval) { - id = J.ar(this, interval); + task = J.ar(this, interval); } @Override public void cancel() { - J.car(id); - } - - public int getId() { - return id; + task.cancel(); } } diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/J.java b/core/src/main/java/com/volmit/iris/util/scheduling/J.java index a669317df..264865d2c 100644 --- a/core/src/main/java/com/volmit/iris/util/scheduling/J.java +++ b/core/src/main/java/com/volmit/iris/util/scheduling/J.java @@ -31,6 +31,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; @@ -91,7 +92,7 @@ public static void aBukkit(Runnable a) { if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { return; } - Bukkit.getScheduler().scheduleAsyncDelayedTask(Iris.instance, a); + Iris.scheduler.async().run(a); } public static Future a(Callable a) { @@ -224,33 +225,29 @@ public static void s(Runnable r) { if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { return; } - Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, r); + Iris.scheduler.global().run(r); } public static CompletableFuture sfut(Runnable r) { - CompletableFuture f = new CompletableFuture(); - if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { return null; } - Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> { + + return Iris.scheduler.global().run(() -> { r.run(); - f.complete(null); - }); - return f; + return null; + }).result(); } public static CompletableFuture sfut(Runnable r, int delay) { - CompletableFuture f = new CompletableFuture(); - if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { return null; } - Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> { + + return Iris.scheduler.global().runDelayed(() -> { r.run(); - f.complete(null); - }, delay); - return f; + return null; + }, delay).result(); } public static CompletableFuture afut(Runnable r) { @@ -273,21 +270,12 @@ public static void s(Runnable r, int delay) { if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { return; } - Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, r, delay); + Iris.scheduler.global().runDelayed(r, delay); } catch (Throwable e) { Iris.reportError(e); } } - /** - * Cancel a sync repeating task - * - * @param id the task id - */ - public static void csr(int id) { - Bukkit.getScheduler().cancelTask(id); - } - /** * Start a sync repeating task * @@ -295,34 +283,11 @@ public static void csr(int id) { * @param interval the interval * @return the task id */ - public static int sr(Runnable r, int interval) { + public static Task sr(Runnable r, int interval) { if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { - return -1; + return null; } - return Bukkit.getScheduler().scheduleSyncRepeatingTask(Iris.instance, r, 0, interval); - } - - /** - * Start a sync repeating task for a limited amount of ticks - * - * @param r the runnable - * @param interval the interval in ticks - * @param intervals the maximum amount of intervals to run - */ - public static void sr(Runnable r, int interval, int intervals) { - FinalInteger fi = new FinalInteger(0); - - new SR() { - @Override - public void run() { - fi.add(1); - r.run(); - - if (fi.get() >= intervals) { - cancel(); - } - } - }; + return Iris.scheduler.global().runAtFixedRate(r, 1, Math.max(interval, 1)); } /** @@ -331,22 +296,12 @@ public void run() { * @param r the runnable * @param delay the delay to wait before running */ - @SuppressWarnings("deprecation") public static void a(Runnable r, int delay) { if (Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { - Bukkit.getScheduler().scheduleAsyncDelayedTask(Iris.instance, r, delay); + Iris.scheduler.async().runDelayed(r, Math.max(delay * 50, 0), TimeUnit.MILLISECONDS); } } - /** - * Cancel an async repeat task - * - * @param id the id - */ - public static void car(int id) { - Bukkit.getScheduler().cancelTask(id); - } - /** * Start an async repeat task * @@ -354,12 +309,11 @@ public static void car(int id) { * @param interval the interval in ticks * @return the task id */ - @SuppressWarnings("deprecation") - public static int ar(Runnable r, int interval) { + public static Task ar(Runnable r, int interval) { if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { - return -1; + return null; } - return Bukkit.getScheduler().scheduleAsyncRepeatingTask(Iris.instance, r, 0, interval); + return Iris.scheduler.async().runAtFixedRate(r, 0, Math.max(interval, 1) * 50, TimeUnit.MILLISECONDS); } /** diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/SR.java b/core/src/main/java/com/volmit/iris/util/scheduling/SR.java index bbb41cd85..50c882e36 100644 --- a/core/src/main/java/com/volmit/iris/util/scheduling/SR.java +++ b/core/src/main/java/com/volmit/iris/util/scheduling/SR.java @@ -21,22 +21,20 @@ import com.volmit.iris.util.plugin.CancellableTask; public abstract class SR implements Runnable, CancellableTask { - private int id = 0; + private final Task id; public SR() { this(0); } public SR(int interval) { - id = J.sr(this, interval); + this.id = J.sr(this, interval); } @Override public void cancel() { - J.csr(id); - } - - public int getId() { - return id; + if (id != null) { + id.cancel(); + } } } diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/jobs/Job.java b/core/src/main/java/com/volmit/iris/util/scheduling/jobs/Job.java index a378770b5..1b2408bba 100644 --- a/core/src/main/java/com/volmit/iris/util/scheduling/jobs/Job.java +++ b/core/src/main/java/com/volmit/iris/util/scheduling/jobs/Job.java @@ -63,7 +63,7 @@ default void execute(VolmitSender sender, Runnable whenComplete) { default void execute(VolmitSender sender, boolean silentMsg, Runnable whenComplete) { PrecisionStopwatch p = PrecisionStopwatch.start(); CompletableFuture f = J.afut(this::execute); - int c = J.ar(() -> { + var c = J.ar(() -> { if (sender.isPlayer()) { sender.sendProgress(getProgress(), getName()); } else { @@ -71,7 +71,7 @@ default void execute(VolmitSender sender, boolean silentMsg, Runnable whenComple } }, sender.isPlayer() ? 0 : 20); f.whenComplete((fs, ff) -> { - J.car(c); + if (c != null) c.cancel(); if (!silentMsg) { sender.sendMessage(C.AQUA + "Completed " + getName() + " in " + Form.duration(p.getMilliseconds(), 1)); } diff --git a/core/src/main/resources/plugin.yml b/core/src/main/resources/plugin.yml index 0a58f5d00..e36460207 100644 --- a/core/src/main/resources/plugin.yml +++ b/core/src/main/resources/plugin.yml @@ -24,4 +24,5 @@ commands: iris: aliases: [ ir, irs ] api-version: '${apiVersion}' -hotload-dependencies: false \ No newline at end of file +hotload-dependencies: false +folia-supported: true \ No newline at end of file From e461c1e1999c58faf769788e370aa100dff3c7ab Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 14 Jun 2025 19:35:28 +0200 Subject: [PATCH 04/26] fix updater and mob spawning instantly failing --- .../volmit/iris/engine/IrisWorldManager.java | 50 ++-- .../volmit/iris/engine/framework/Engine.java | 9 +- .../volmit/iris/engine/object/IrisEntity.java | 227 +++++++----------- .../iris/engine/object/IrisEntitySpawn.java | 32 ++- .../iris/engine/object/IrisSurface.java | 6 +- .../iris/engine/object/LegacyTileData.java | 4 +- 6 files changed, 151 insertions(+), 177 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index 95ba698c9..c115898fc 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -188,9 +188,11 @@ private void discoverChunks() { for (Player i : getEngine().getWorld().realWorld().getPlayers()) { int r = 1; + int cX = i.getLocation().getBlockX() >> 4; + int cZ = i.getLocation().getBlockZ() >> 4; for (int x = -r; x <= r; x++) { for (int z = -r; z <= r; z++) { - mantle.getChunk(i.getLocation().getChunk()).flag(MantleFlag.DISCOVERED, true); + mantle.getChunk(cX + x, cZ + z).flag(MantleFlag.DISCOVERED, true); } } } @@ -200,20 +202,22 @@ private void updateChunks() { for (Player i : getEngine().getWorld().realWorld().getPlayers()) { int r = 1; - Chunk c = i.getLocation().getChunk(); - for (int x = -r; x <= r; x++) { - for (int z = -r; z <= r; z++) { - if (c.getWorld().isChunkLoaded(c.getX() + x, c.getZ() + z) && Chunks.isSafe(getEngine().getWorld().realWorld(), c.getX() + x, c.getZ() + z)) { + Iris.scheduler.entity(i).run(() -> { + Chunk c = i.getLocation().getChunk(); + for (int x = -r; x <= r; x++) { + for (int z = -r; z <= r; z++) { + int cX = c.getX() + x; + int cZ = c.getZ() + z; + if (!c.getWorld().isChunkLoaded(cX, cZ) || !Chunks.isSafe(getEngine().getWorld().realWorld(), cX, cZ)) + continue; if (IrisSettings.get().getWorld().isPostLoadBlockUpdates()) { - getEngine().updateChunk(c.getWorld().getChunkAt(c.getX() + x, c.getZ() + z)); + getEngine().updateChunk(c.getWorld().getChunkAt(cX, cZ)); } if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) { - Chunk cx = getEngine().getWorld().realWorld().getChunkAt(c.getX() + x, c.getZ() + z); - int finalX = c.getX() + x; - int finalZ = c.getZ() + z; - J.a(() -> getMantle().raiseFlag(finalX, finalZ, MantleFlag.INITIAL_SPAWNED_MARKER, + Chunk cx = getEngine().getWorld().realWorld().getChunkAt(cX, cZ); + J.a(() -> getMantle().raiseFlag(cX, cZ, MantleFlag.INITIAL_SPAWNED_MARKER, () -> { J.a(() -> spawnIn(cx, true), RNG.r.i(5, 200)); getSpawnersFromMarkers(cx).forEach((blockf, spawners) -> { @@ -229,7 +233,7 @@ private void updateChunks() { } } } - } + }, null); } } @@ -532,19 +536,17 @@ public Map> getSpawnersFromMarkers(Chunk c) { IrisPosition pos = new IrisPosition((c.getX() << 4) + x, y, (c.getZ() << 4) + z); if (mark.isEmptyAbove()) { - AtomicBoolean remove = new AtomicBoolean(false); - - try { - J.sfut(() -> { - if (c.getBlock(x, y + 1, z).getBlockData().getMaterial().isSolid() || c.getBlock(x, y + 2, z).getBlockData().getMaterial().isSolid()) { - remove.set(true); - } - }).get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - } - - if (remove.get()) { + Boolean remove = Iris.scheduler.region() + .run(c.getWorld(), c.getX(), c.getZ(), () -> c.getBlock(x, y + 1, z).getType().isSolid() || c.getBlock(x, y + 2, z).getType().isSolid()) + .result() + .exceptionally(e -> { + Iris.reportError(e); + e.printStackTrace(); + return false; + }) + .join(); + + if (remove == Boolean.TRUE) { b.add(pos); return; } diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java index 010628b7d..68172d92f 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -293,20 +293,21 @@ default void updateChunk(Chunk c) { try { Semaphore semaphore = new Semaphore(3); chunk.raiseFlag(MantleFlag.ETCHED, () -> { - chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> J.s(() -> { + var region = Iris.scheduler.region(); + chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> region.run(c.getWorld(), c.getX(), c.getZ(), () -> { mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> { int betterY = y + getWorld().minHeight(); if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData())) Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), v.getData().getMaterial().name()); }); }))); - chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> J.s(() -> { + chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> region.run(c.getWorld(), c.getX(), c.getZ(), () -> { mantle.iterateChunk(c.getX(), c.getZ(), Identifier.class, (x, y, z, v) -> { Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v); }); }))); - chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> J.s(() -> { + chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> region.runDelayed(c.getWorld(), c.getX(), c.getZ(), () -> { PrecisionStopwatch p = PrecisionStopwatch.start(); KMap updates = new KMap<>(); RNG r = new RNG(Cache.key(c.getX(), c.getZ())); @@ -353,7 +354,7 @@ default void updateChunk(Chunk c) { }); mantle.deleteChunkSlice(c.getX(), c.getZ(), MatterUpdate.class); getMetrics().getUpdates().put(p.getMilliseconds()); - }, RNG.r.i(0, 20)))); + }, RNG.r.i(1, 20)))); }); try { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java index 109d9a9c1..414ed285a 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java @@ -31,8 +31,6 @@ import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.plugin.Chunks; import com.volmit.iris.util.plugin.VolmitSender; -import com.volmit.iris.util.scheduling.J; -import com.volmit.iris.util.scheduling.PrecisionStopwatch; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; @@ -48,13 +46,11 @@ import org.bukkit.loot.LootContext; import org.bukkit.loot.LootTable; import org.bukkit.loot.Lootable; -import org.bukkit.util.Vector; import java.util.Collection; import java.util.Random; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; import static com.volmit.iris.util.data.registry.Particles.ITEM; @@ -181,37 +177,33 @@ public Entity spawn(Engine gen, Location at) { return spawn(gen, at, new RNG(at.hashCode())); } - public Entity spawn(Engine gen, Location at, RNG rng) { + public Entity spawn(Engine gen, final Location at, RNG rng) { + if (!Iris.scheduler.isOwnedByCurrentRegion(at)) { + try { + final Location finalAt = at; + return Iris.scheduler.region().run(at, () -> spawn(gen, finalAt, rng)) + .result() + .get(500, TimeUnit.MILLISECONDS); + } catch (Throwable e) { + return null; + } + } + if (!Chunks.isSafe(at)) { return null; } - if (isSpawnEffectRiseOutOfGround()) { - AtomicReference f = new AtomicReference<>(at); - try { - J.sfut(() -> { - if (Chunks.hasPlayersNearby(f.get())) { - Location b = f.get().clone(); - Location start = new Location(b.getWorld(), b.getX(), b.getY() - 5, b.getZ()); - f.set(start); - } - }).get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); - } - at = f.get(); + if (isSpawnEffectRiseOutOfGround() && Chunks.hasPlayersNearby(at)) { + at.add(0, -5, 0); } Entity ee = doSpawn(at); - - if (ee == null && !Chunks.isSafe(at)) { + if (ee == null) { return null; } if (!spawnerScript.isEmpty() && ee == null) { synchronized (this) { - gen.getExecution().getAPI().setLocation(at); + gen.getExecution().getAPI().setLocation(at.clone()); try { ee = (Entity) gen.getExecution().evaluate(spawnerScript); } catch (Throwable ex) { @@ -240,109 +232,96 @@ public Entity spawn(Engine gen, Location at, RNG rng) { int gg = 0; for (IrisEntity i : passengers) { - Entity passenger = i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++)); - if (!Bukkit.isPrimaryThread()) { - J.s(() -> e.addPassenger(passenger)); - } + e.addPassenger(i.spawn(gen, at, rng.nextParallelRNG(234858 + gg++))); } - if (e instanceof Attributable) { - Attributable a = (Attributable) e; - + if (e instanceof Attributable attributable) { for (IrisAttributeModifier i : getAttributes()) { - i.apply(rng, a); + i.apply(rng, attributable); } } - if (e instanceof Lootable) { - Lootable l = (Lootable) e; - - if (getLoot().getTables().isNotEmpty()) { - Location finalAt = at; - l.setLootTable(new LootTable() { - @Override - public NamespacedKey getKey() { - return new NamespacedKey(Iris.instance, "loot-" + IrisEntity.this.hashCode()); - } - - @Override - public Collection populateLoot(Random random, LootContext context) { - KList items = new KList<>(); + if (e instanceof Lootable lootable && getLoot().getTables().isNotEmpty()) { + lootable.setLootTable(new LootTable() { + @Override + public NamespacedKey getKey() { + return new NamespacedKey(Iris.instance, "loot-" + IrisEntity.this.hashCode()); + } - for (String fi : getLoot().getTables()) { - IrisLootTable i = gen.getData().getLootLoader().load(fi); - items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, finalAt.getWorld(), finalAt.getBlockX(), finalAt.getBlockY(), finalAt.getBlockZ())); - } + @Override + public Collection populateLoot(Random random, LootContext context) { + KList items = new KList<>(); - return items; + for (String fi : getLoot().getTables()) { + IrisLootTable i = gen.getData().getLootLoader().load(fi); + items.addAll(i.getLoot(gen.isStudio(), rng.nextParallelRNG(345911), InventorySlotType.STORAGE, at.getWorld(), at.getBlockX(), at.getBlockY(), at.getBlockZ())); } - @Override - public void fillInventory(Inventory inventory, Random random, LootContext context) { - for (ItemStack i : populateLoot(random, context)) { - inventory.addItem(i); - } + return items; + } - gen.scramble(inventory, rng); + @Override + public void fillInventory(Inventory inventory, Random random, LootContext context) { + for (ItemStack i : populateLoot(random, context)) { + inventory.addItem(i); } - }); - } + + gen.scramble(inventory, rng); + } + }); } - if (e instanceof LivingEntity) { - LivingEntity l = (LivingEntity) e; - l.setAI(isAi()); - l.setCanPickupItems(isPickupItems()); + if (e instanceof LivingEntity living) { + living.setAI(isAi()); + living.setCanPickupItems(isPickupItems()); if (getLeashHolder() != null) { - l.setLeashHolder(getLeashHolder().spawn(gen, at, rng.nextParallelRNG(234548))); + living.setLeashHolder(getLeashHolder().spawn(gen, at, rng.nextParallelRNG(234548))); } - l.setRemoveWhenFarAway(isRemovable()); + living.setRemoveWhenFarAway(isRemovable()); if (getHelmet() != null && rng.i(1, getHelmet().getRarity()) == 1) { - l.getEquipment().setHelmet(getHelmet().get(gen.isStudio(), rng)); + living.getEquipment().setHelmet(getHelmet().get(gen.isStudio(), rng)); } if (getChestplate() != null && rng.i(1, getChestplate().getRarity()) == 1) { - l.getEquipment().setChestplate(getChestplate().get(gen.isStudio(), rng)); + living.getEquipment().setChestplate(getChestplate().get(gen.isStudio(), rng)); } if (getLeggings() != null && rng.i(1, getLeggings().getRarity()) == 1) { - l.getEquipment().setLeggings(getLeggings().get(gen.isStudio(), rng)); + living.getEquipment().setLeggings(getLeggings().get(gen.isStudio(), rng)); } if (getBoots() != null && rng.i(1, getBoots().getRarity()) == 1) { - l.getEquipment().setBoots(getBoots().get(gen.isStudio(), rng)); + living.getEquipment().setBoots(getBoots().get(gen.isStudio(), rng)); } if (getMainHand() != null && rng.i(1, getMainHand().getRarity()) == 1) { - l.getEquipment().setItemInMainHand(getMainHand().get(gen.isStudio(), rng)); + living.getEquipment().setItemInMainHand(getMainHand().get(gen.isStudio(), rng)); } if (getOffHand() != null && rng.i(1, getOffHand().getRarity()) == 1) { - l.getEquipment().setItemInOffHand(getOffHand().get(gen.isStudio(), rng)); + living.getEquipment().setItemInOffHand(getOffHand().get(gen.isStudio(), rng)); } } - if (e instanceof Ageable && isBaby()) { - ((Ageable) e).setBaby(); + if (e instanceof Ageable ageable && isBaby()) { + ageable.setBaby(); } - if (e instanceof Panda) { - ((Panda) e).setMainGene(getPandaMainGene()); - ((Panda) e).setMainGene(getPandaHiddenGene()); + if (e instanceof Panda panda) { + panda.setMainGene(getPandaMainGene()); + panda.setMainGene(getPandaHiddenGene()); } - if (e instanceof Villager) { - Villager villager = (Villager) e; + if (e instanceof Villager villager) { villager.setRemoveWhenFarAway(false); - Iris.scheduler.entity(villager).run(() -> villager.setPersistent(true), null); + villager.setPersistent(true); } - if (e instanceof Mob) { - Mob m = (Mob) e; - m.setAware(isAware()); + if (e instanceof Mob mob) { + mob.setAware(isAware()); } if (spawnEffect != null) { @@ -365,40 +344,35 @@ public void fillInventory(Inventory inventory, Random random, LootContext contex rawCommands.forEach(r -> r.run(fat)); } - Location finalAt1 = at; - - J.s(() -> { - if (isSpawnEffectRiseOutOfGround() && e instanceof LivingEntity && Chunks.hasPlayersNearby(finalAt1)) { - Location start = finalAt1.clone(); - e.setInvulnerable(true); - ((LivingEntity) e).setAI(false); - ((LivingEntity) e).setCollidable(false); - ((LivingEntity) e).setNoDamageTicks(100000); - AtomicInteger t = new AtomicInteger(0); - Iris.scheduler.global().runAtFixedRate(task -> { - if (t.get() > 100) { - task.cancel(); - return; - } + if (isSpawnEffectRiseOutOfGround() && e instanceof LivingEntity living && Chunks.hasPlayersNearby(at)) { + e.setInvulnerable(true); + living.setAI(false); + living.setCollidable(false); + living.setNoDamageTicks(100000); + AtomicInteger t = new AtomicInteger(0); + Iris.scheduler.region().runAtFixedRate(at, task -> { + if (t.get() > 100) { + task.cancel(); + return; + } - t.incrementAndGet(); - if (e.getLocation().getBlock().getType().isSolid() || ((LivingEntity) e).getEyeLocation().getBlock().getType().isSolid()) { - e.teleport(start.add(new Vector(0, 0.1, 0))); - ItemStack itemCrackData = new ItemStack(((LivingEntity) e).getEyeLocation().clone().subtract(0, 2, 0).getBlock().getBlockData().getMaterial()); - e.getWorld().spawnParticle(ITEM, ((LivingEntity) e).getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, itemCrackData); - if (M.r(0.2)) { - e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f); - } - } else { - task.cancel(); - ((LivingEntity) e).setNoDamageTicks(0); - ((LivingEntity) e).setCollidable(true); - ((LivingEntity) e).setAI(true); - e.setInvulnerable(false); + t.incrementAndGet(); + if (e.getLocation().getBlock().getType().isSolid() || living.getEyeLocation().getBlock().getType().isSolid()) { + Iris.scheduler.teleportAsync(e, at.add(0, 0.1, 0)); + ItemStack itemCrackData = new ItemStack(living.getEyeLocation().clone().subtract(0, 2, 0).getBlock().getBlockData().getMaterial()); + e.getWorld().spawnParticle(ITEM, living.getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, itemCrackData); + if (M.r(0.2)) { + e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f); } - }, 1, 1); - } - }); + } else { + task.cancel(); + living.setNoDamageTicks(0); + living.setCollidable(true); + living.setAI(true); + e.setInvulnerable(false); + } + }, 1, 1); + } return e; @@ -428,29 +402,6 @@ private Entity doSpawn(Location at) { return null; } - if (!Bukkit.isPrimaryThread()) { - // Someone called spawn (worldedit maybe?) on a non server thread - // Due to the structure of iris, we will call it sync and busy wait until it's done. - AtomicReference ae = new AtomicReference<>(); - - try { - J.s(() -> ae.set(doSpawn(at))); - } catch (Throwable e) { - return null; - } - PrecisionStopwatch p = PrecisionStopwatch.start(); - - while (ae.get() == null) { - J.sleep(25); - - if (p.getMilliseconds() > 500) { - return null; - } - } - - return ae.get(); - } - if (isSpecialType()) { if (specialType.toLowerCase().startsWith("mythicmobs:")) { return Iris.linkMythicMobs.spawnMob(specialType.substring(11), at); diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java b/core/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java index a0eb9500d..b68f8a69b 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java @@ -36,8 +36,14 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.volmit.iris.Iris.scheduler; + @Snippet("entity-spawn") @Accessors(chain = true) @NoArgsConstructor @@ -164,8 +170,15 @@ private Entity spawn100(Engine g, Location at, boolean ignoreSurfaces) { return null; } - if (!ignoreSurfaces && !irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock())) { - return null; + if (!ignoreSurfaces) { + Location block = at.clone().subtract(0, 1, 0); + BlockData data = scheduler.region() + .run(block, () -> block.getBlock().getBlockData()) + .result() + .join(); + if (!irisEntity.getSurface().matches(data)) { + return null; + } } Vector3d boundingBox = INMS.get().getBoundingbox(irisEntity.getType()); @@ -199,15 +212,22 @@ private boolean isAreaClearForSpawn(Location center, Vector3d boundingBox) { int startZ = center.getBlockZ() - (int) (boundingBox.z / 2); int endZ = center.getBlockZ() + (int) (boundingBox.z / 2); + var region = scheduler.region(); + var lock = new Semaphore(Integer.MAX_VALUE, true); + var bool = new AtomicBoolean(true); for (int x = startX; x <= endX; x++) { for (int y = startY; y <= endY; y++) { for (int z = startZ; z <= endZ; z++) { - if (world.getBlockAt(x, y, z).getType() != Material.AIR) { - return false; - } + Location l = new Location(world, x, y, z); + lock.acquireUninterruptibly(); + region.run(l, () -> { + if (!bool.get()) return false; + return bool.compareAndSet(true, l.getBlock().getType() == Material.AIR); + }).result().exceptionally(f -> false).thenRun(lock::release); } } } - return true; + lock.acquireUninterruptibly(Integer.MAX_VALUE); + return bool.get(); } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisSurface.java b/core/src/main/java/com/volmit/iris/engine/object/IrisSurface.java index e8a2e2e3c..885ba95f5 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisSurface.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisSurface.java @@ -20,7 +20,7 @@ import com.volmit.iris.engine.object.annotations.Desc; import org.bukkit.Material; -import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; @Desc("The type of surface entities should spawn on") @@ -47,8 +47,8 @@ public enum IrisSurface { * @param state The blockstate * @return True if it matches */ - public boolean matches(Block state) { - Material type = state.getType(); + public boolean matches(BlockData state) { + Material type = state.getMaterial(); if (type.isSolid()) { return this == LAND || this == OVERWORLD || (this == ANIMAL && (type == Material.GRASS_BLOCK || type == Material.DIRT diff --git a/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java index 7cbcc094c..e5509581a 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java +++ b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java @@ -1,10 +1,10 @@ package com.volmit.iris.engine.object; +import com.volmit.iris.Iris; import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; -import com.volmit.iris.util.scheduling.J; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.NonNull; @@ -80,7 +80,7 @@ public boolean isApplicable(BlockData data) { @Override public void toBukkit(Block block) { - J.s(() -> handler.toBukkit(block)); + Iris.scheduler.region().run(block.getLocation(), () -> handler.toBukkit(block)); } @Override From 7570064b1aac65abbcdbd1aaf26c214f3fac337c Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 14 Jun 2025 19:36:32 +0200 Subject: [PATCH 05/26] fix locate command not teleporting --- .../main/java/com/volmit/iris/engine/framework/Engine.java | 2 +- .../main/java/com/volmit/iris/engine/framework/Locator.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java index 68172d92f..9577be6e0 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -899,7 +899,7 @@ default void gotoJigsaw(IrisJigsawStructure s, Player player, boolean teleport) player.sendMessage(C.GOLD + "No strongholds in world."); } else { Location ll = new Location(player.getWorld(), pr.getX(), 40, pr.getZ()); - J.s(() -> player.teleport(ll)); + Iris.scheduler.teleportAsync(player, ll); } return; diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Locator.java b/core/src/main/java/com/volmit/iris/engine/framework/Locator.java index 0c05c068b..a0d42f473 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Locator.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Locator.java @@ -18,6 +18,7 @@ package com.volmit.iris.engine.framework; +import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.nms.container.BlockPos; import com.volmit.iris.core.nms.container.Pair; @@ -36,7 +37,6 @@ import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.plugin.VolmitSender; -import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.jobs.SingleJob; import org.bukkit.Location; @@ -114,7 +114,7 @@ static Locator caveOrMantleBiome(String loadKey) { default void find(Player player, boolean teleport, String message) { find(player, location -> { if (teleport) { - J.s(() -> player.teleport(location)); + Iris.scheduler.teleportAsync(player, location); } else { player.sendMessage(C.GREEN + message + " at: " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ()); } From 1c5fe016cb259dee7b2350ce4f3c29d92dc6c82d Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 15 Jun 2025 12:36:53 +0200 Subject: [PATCH 06/26] handle failing world creation --- core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java index 1b881e6fe..83e5265b1 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java +++ b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java @@ -18,6 +18,7 @@ package com.volmit.iris.core.nms; +import com.volmit.iris.Iris; import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; @@ -95,6 +96,9 @@ default World createWorld(WorldCreator c) { try (var ignored = injectLevelStems()) { ignored.storeContext(); return c.createWorld(); + } catch (UnsupportedOperationException e) { + Iris.error("Failed to create world", e); + return null; } } From d61b2205c0f7eb0d2762e0462452aedb340b0b96 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 18 Jun 2025 11:25:41 +0200 Subject: [PATCH 07/26] handle failing restart command better --- .../main/java/com/volmit/iris/core/ServerConfigurator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java index b3709e43f..a84d22ef6 100644 --- a/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java +++ b/core/src/main/java/com/volmit/iris/core/ServerConfigurator.java @@ -172,11 +172,14 @@ public static void restart() { Iris.warn("New data pack entries have been installed in Iris! Restarting server!"); Iris.warn("This will only happen when your pack changes (updates/first time setup)"); Iris.warn("(You can disable this auto restart in iris settings)"); + if (!Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart")) { + Iris.warn("Looks like the restart command didn't work. Stopping the server instead!"); + Bukkit.shutdown(); + } J.s(() -> { Iris.warn("Looks like the restart command didn't work. Stopping the server instead!"); Bukkit.shutdown(); }, 100); - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart"); }); } From 96a384c09cebeb9c39f748b9cd8d3a41b0c25829 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 18 Jun 2025 11:51:09 +0200 Subject: [PATCH 08/26] fix modern tile states not applying --- build.gradle.kts | 1 + .../main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java | 2 +- .../main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java | 2 +- .../main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java | 2 +- .../main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java | 2 +- .../main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java | 2 +- .../main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java | 2 +- .../main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java | 2 +- .../main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java | 2 +- 9 files changed, 9 insertions(+), 8 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index bdccca70d..91007d4db 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -90,6 +90,7 @@ nmsBindings.forEach { key, value -> dependencies { compileOnly(project(":core")) + compileOnly(project(":scheduler")) compileOnly("org.jetbrains:annotations:26.0.2") } } diff --git a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java index 8f974008b..b0f332d2e 100644 --- a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java +++ b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java @@ -211,7 +211,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - J.s(() -> merge(level, blockPos, tag)); + Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java index c68a8a19e..bd02f244d 100644 --- a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java +++ b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java @@ -208,7 +208,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - J.s(() -> merge(level, blockPos, tag)); + Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java index 2d0e08931..1cd08a88c 100644 --- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java @@ -208,7 +208,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - J.s(() -> merge(level, blockPos, tag)); + Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java index ec076e7df..a3685828d 100644 --- a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java +++ b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java @@ -217,7 +217,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - J.s(() -> merge(level, blockPos, tag)); + Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java index 7613bf71f..b9b043836 100644 --- a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java @@ -214,7 +214,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - J.s(() -> merge(level, blockPos, tag)); + Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java index 41b75953b..1b2ed64b2 100644 --- a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java +++ b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java @@ -204,7 +204,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - J.s(() -> merge(level, blockPos, tag)); + Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java index c6ba0e6dd..f7a5b5f9a 100644 --- a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java +++ b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java @@ -203,7 +203,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - J.s(() -> merge(level, blockPos, tag)); + Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java b/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java index 3b11e017b..465a78f8c 100644 --- a/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java +++ b/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java @@ -201,7 +201,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - J.s(() -> merge(level, blockPos, tag)); + Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { From bef99f18c3cc4965e450192eae1070ee4984ec73 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Wed, 18 Jun 2025 12:00:55 +0200 Subject: [PATCH 09/26] fix effects --- .../volmit/iris/engine/object/IrisEffect.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisEffect.java b/core/src/main/java/com/volmit/iris/engine/object/IrisEffect.java index c28467877..e751d41b2 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisEffect.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisEffect.java @@ -195,7 +195,7 @@ public void apply(Player p, Engine g) { if (sound != null) { Location part = p.getLocation().clone().add(RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance)); - J.s(() -> p.playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch))); + schedule(p, () -> p.playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch))); } if (particleEffect != null) { @@ -205,7 +205,7 @@ public void apply(Player p, Engine g) { part.add(RNG.r.d(), 0, RNG.r.d()); int offset = p.getWorld().getMinHeight(); if (extra != 0) { - J.s(() -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), + schedule(p, () -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(), particleCount, randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX, @@ -213,7 +213,7 @@ public void apply(Player p, Engine g) { randomAltZ ? RNG.r.d(-particleAltZ, particleAltZ) : particleAltZ, extra)); } else { - J.s(() -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(), + schedule(p, () -> p.spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(), particleCount, randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX, randomAltY ? RNG.r.d(-particleAltY, particleAltY) : particleAltY, @@ -232,10 +232,10 @@ public void apply(Player p, Engine g) { return; } - J.s(() -> p.removePotionEffect(getRealType())); + schedule(p, () -> p.removePotionEffect(getRealType())); } - J.s(() -> p.addPotionEffect(new PotionEffect(getRealType(), + schedule(p, () -> p.addPotionEffect(new PotionEffect(getRealType(), RNG.r.i(Math.min(potionTicksMax, potionTicksMin), Math.max(potionTicksMax, potionTicksMin)), getPotionStrength(), @@ -255,7 +255,7 @@ public void apply(Entity p) { if (sound != null) { Location part = p.getLocation().clone().add(RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance), RNG.r.i(-soundDistance, soundDistance)); - J.s(() -> p.getWorld().playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch))); + schedule(p, () -> p.getWorld().playSound(part, getSound(), (float) volume, (float) RNG.r.d(minPitch, maxPitch))); } if (particleEffect != null) { @@ -263,7 +263,7 @@ public void apply(Entity p) { part.add(RNG.r.d(), 0, RNG.r.d()); int offset = p.getWorld().getMinHeight(); if (extra != 0) { - J.s(() -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), + schedule(p, () -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(), particleCount, randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX, @@ -271,7 +271,7 @@ public void apply(Entity p) { randomAltZ ? RNG.r.d(-particleAltZ, particleAltZ) : particleAltZ, extra)); } else { - J.s(() -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(), + schedule(p, () -> p.getWorld().spawnParticle(particleEffect, part.getX(), part.getY() + offset + RNG.r.i(particleOffset), part.getZ(), particleCount, randomAltX ? RNG.r.d(-particleAltX, particleAltX) : particleAltX, randomAltY ? RNG.r.d(-particleAltY, particleAltY) : particleAltY, @@ -279,4 +279,8 @@ public void apply(Entity p) { } } } + + private void schedule(Entity entity, Runnable task) { + Iris.scheduler.entity(entity).run(task, null); + } } From cf0bc81778c014f915f1766d6566ee32603ca127 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 19 Jun 2025 17:46:08 +0200 Subject: [PATCH 10/26] replace scheduler and paperlib with platform utils --- build.gradle.kts | 4 +- core/build.gradle.kts | 6 +- core/src/main/java/com/volmit/iris/Iris.java | 12 +- .../iris/core/commands/CommandIris.java | 2 +- .../iris/core/commands/CommandStudio.java | 5 +- .../volmit/iris/core/edit/BlockSignal.java | 3 +- .../volmit/iris/core/edit/JigsawEditor.java | 2 +- .../iris/core/pregenerator/ChunkUpdater.java | 7 +- .../core/pregenerator/LazyPregenerator.java | 21 +- .../core/pregenerator/TurboPregenerator.java | 3 +- .../methods/AsyncOrMedievalPregenMethod.java | 73 ---- .../methods/AsyncPregenMethod.java | 11 +- .../methods/HybridPregenMethod.java | 74 ---- .../methods/MedievalPregenMethod.java | 138 -------- .../com/volmit/iris/core/service/EditSVC.java | 3 +- .../volmit/iris/core/service/ObjectSVC.java | 3 +- .../volmit/iris/core/tools/IrisConverter.java | 2 +- .../volmit/iris/core/tools/IrisToolbelt.java | 7 +- .../com/volmit/iris/engine/IrisEngine.java | 2 +- .../volmit/iris/engine/IrisWorldManager.java | 10 +- .../volmit/iris/engine/framework/Engine.java | 9 +- .../framework/EngineAssignedWorldManager.java | 10 +- .../volmit/iris/engine/framework/Locator.java | 2 +- .../iris/engine/object/IrisCommand.java | 2 +- .../volmit/iris/engine/object/IrisEffect.java | 3 +- .../volmit/iris/engine/object/IrisEntity.java | 10 +- .../iris/engine/object/IrisEntitySpawn.java | 10 +- .../iris/engine/object/LegacyTileData.java | 2 +- .../engine/platform/BukkitChunkGenerator.java | 3 +- .../volmit/iris/util/board/BoardManager.java | 4 +- .../volmit/iris/util/plugin/VolmitSender.java | 3 +- .../volmit/iris/util/profile/MsptTimings.java | 8 +- .../com/volmit/iris/util/scheduling/AR.java | 1 + .../com/volmit/iris/util/scheduling/J.java | 21 +- .../com/volmit/iris/util/scheduling/SR.java | 1 + .../iris/core/nms/v1_20_R1/NMSBinding.java | 16 +- .../iris/core/nms/v1_20_R2/NMSBinding.java | 13 +- .../iris/core/nms/v1_20_R3/NMSBinding.java | 13 +- .../iris/core/nms/v1_20_R4/NMSBinding.java | 10 +- .../iris/core/nms/v1_21_R1/NMSBinding.java | 14 +- .../iris/core/nms/v1_21_R2/NMSBinding.java | 5 +- .../iris/core/nms/v1_21_R3/NMSBinding.java | 5 +- .../iris/core/nms/v1_21_R4/NMSBinding.java | 3 +- scheduler/build.gradle.kts | 7 - .../volmit/iris/util/scheduling/Platform.java | 190 ---------- .../com/volmit/iris/util/scheduling/Ref.java | 5 - .../com/volmit/iris/util/scheduling/Task.java | 27 -- .../util/scheduling/paper/PaperPlatform.java | 107 ------ .../iris/util/scheduling/paper/PaperTask.java | 59 ---- .../paper/split/PaperAsyncScheduler.java | 48 --- .../paper/split/PaperEntityScheduler.java | 49 --- .../paper/split/PaperGlobalScheduler.java | 39 --- .../paper/split/PaperRegionScheduler.java | 45 --- .../scheduling/spigot/SpigotPlatform.java | 105 ------ .../util/scheduling/spigot/SpigotTask.java | 60 ---- .../spigot/split/SpigotAsyncScheduler.java | 44 --- .../spigot/split/SpigotEntityScheduler.java | 53 --- .../spigot/split/SpigotGlobalScheduler.java | 37 -- .../spigot/split/SpigotRegionScheduler.java | 30 -- .../scheduling/split/IAsyncScheduler.java | 146 -------- .../scheduling/split/IEntityScheduler.java | 250 ------------- .../scheduling/split/IGlobalScheduler.java | 139 -------- .../scheduling/split/IRegionScheduler.java | 328 ------------------ settings.gradle.kts | 3 +- 64 files changed, 88 insertions(+), 2239 deletions(-) delete mode 100644 core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncOrMedievalPregenMethod.java delete mode 100644 core/src/main/java/com/volmit/iris/core/pregenerator/methods/HybridPregenMethod.java delete mode 100644 core/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java delete mode 100644 scheduler/build.gradle.kts delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/Platform.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/Ref.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/Task.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperPlatform.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperTask.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperEntityScheduler.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperGlobalScheduler.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperRegionScheduler.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotPlatform.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotTask.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotAsyncScheduler.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotEntityScheduler.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotGlobalScheduler.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotRegionScheduler.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java delete mode 100644 scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java diff --git a/build.gradle.kts b/build.gradle.kts index 91007d4db..4697b9574 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -90,7 +90,9 @@ nmsBindings.forEach { key, value -> dependencies { compileOnly(project(":core")) - compileOnly(project(":scheduler")) + compileOnly("com.github.CrazyDev05:PlatformUtils:4bac4f6e75") { + isTransitive = false + } compileOnly("org.jetbrains:annotations:26.0.2") } } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 1cf20ed96..a17c89a46 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -65,12 +65,13 @@ dependencies { // Shaded implementation("com.dfsek:paralithic:0.8.1") - implementation("io.papermc:paperlib:1.0.5") implementation("net.kyori:adventure-text-minimessage:4.17.0") implementation("net.kyori:adventure-platform-bukkit:4.3.4") implementation("net.kyori:adventure-api:4.17.0") implementation("org.bstats:bstats-bukkit:3.1.0") - implementation(project(":scheduler")) + implementation("com.github.CrazyDev05:PlatformUtils:4bac4f6e75") { + isTransitive = false + } //implementation("org.bytedeco:javacpp:1.5.10") //implementation("org.bytedeco:cuda-platform:12.3-8.9-1.5.10") @@ -135,6 +136,7 @@ tasks { relocate("net.kyori", "com.volmit.iris.util.kyori") relocate("org.bstats", "com.volmit.iris.util.metrics") relocate("io.sentry", "com.volmit.iris.util.sentry") + relocate("de.crazydev22.platformutils", "com.volmit.iris.util.platform") //minimize() dependencies { diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 8e8d86cd8..1cb41cf3f 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -64,13 +64,13 @@ import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.reflect.ShadeFix; import com.volmit.iris.util.scheduling.J; -import com.volmit.iris.util.scheduling.Platform; import com.volmit.iris.util.scheduling.Queue; import com.volmit.iris.util.scheduling.ShurikenQueue; import com.volmit.iris.util.sentry.Attachments; import com.volmit.iris.util.sentry.IrisLogger; import com.volmit.iris.util.sentry.ServerID; -import io.papermc.lib.PaperLib; +import de.crazydev22.platformutils.Platform; +import de.crazydev22.platformutils.PlatformUtils; import io.sentry.Sentry; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.text.serializer.ComponentSerializer; @@ -119,7 +119,7 @@ public class Iris extends VolmitPlugin implements Listener { public static MythicMobsLink linkMythicMobs; public static IrisCompat compat; public static FileWatcher configWatcher; - public static Platform scheduler; + public static Platform platform; private static VolmitSender sender; static { @@ -338,7 +338,7 @@ public static void safeguard(String format, Object... args) { @SuppressWarnings("deprecation") public static void later(NastyRunnable object) { try { - scheduler.async().runDelayed(task -> { + platform.getAsyncScheduler().runDelayed(task -> { try { object.run(); } catch (Throwable e) { @@ -463,7 +463,7 @@ private static void fixShading() { } private void enable() { instance = this; - scheduler = Platform.create(this); + platform = PlatformUtils.createPlatform(this); services = new KMap<>(); setupAudience(); setupSentry(); @@ -482,7 +482,7 @@ private void enable() { services.values().forEach(IrisService::onEnable); services.values().forEach(this::registerListener); J.s(() -> { - J.a(() -> PaperLib.suggestPaper(this)); + //J.a(() -> PaperLib.suggestPaper(this)); //TODO reimplement this J.a(() -> IO.delete(getTemp())); J.a(LazyPregenerator::loadLazyGenerators, 100); J.a(this::bstats); diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java index 06c61e4c2..6df5230c3 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java @@ -156,7 +156,7 @@ public void teleport( return; } - Iris.scheduler.teleportAsync(target, world.getSpawnLocation()).thenRun(() -> + Iris.platform.teleportAsync(target, world.getSpawnLocation()).thenRun(() -> new VolmitSender(target).sendMessage(C.GREEN + "You have been teleported to " + world.getName() + ".")); } diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java index 06fd6c36d..9c53c9edf 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java @@ -57,7 +57,6 @@ import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.jobs.QueueJob; -import io.papermc.lib.PaperLib; import org.bukkit.*; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; @@ -310,7 +309,7 @@ public void loot( } Player player = player(); - var scheduler = Iris.scheduler.entity(player); + var scheduler = Iris.platform.getEntityScheduler(player); scheduler.run(() -> { sender().sendMessage(C.GREEN + "Opening inventory now!"); player.openInventory(inv); @@ -692,7 +691,7 @@ public void objects() { pw.println("Iris Version: " + Iris.instance.getDescription().getVersion()); pw.println("Bukkit Version: " + Bukkit.getBukkitVersion()); pw.println("MC Version: " + Bukkit.getVersion()); - pw.println("PaperSpigot: " + (PaperLib.isPaper() ? "Yup!" : "Nope!")); + //pw.println("PaperSpigot: " + (PaperLib.isPaper() ? "Yup!" : "Nope!")); //TODO update this pw.println("Report Captured At: " + new Date()); pw.println("Chunks: (" + chunks.size() + "): "); diff --git a/core/src/main/java/com/volmit/iris/core/edit/BlockSignal.java b/core/src/main/java/com/volmit/iris/core/edit/BlockSignal.java index d6c302893..05315838b 100644 --- a/core/src/main/java/com/volmit/iris/core/edit/BlockSignal.java +++ b/core/src/main/java/com/volmit/iris/core/edit/BlockSignal.java @@ -22,7 +22,6 @@ import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.scheduling.AR; import com.volmit.iris.util.scheduling.J; -import com.volmit.iris.util.scheduling.SR; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; @@ -89,7 +88,7 @@ public void run() { return; } - Iris.scheduler.teleportAsync(e, tg.clone()).thenAccept(b -> { + Iris.platform.teleportAsync(e, tg.clone()).thenAccept(b -> { e.setTicksLived(1); e.setVelocity(new Vector(0, 0, 0)); }).join(); diff --git a/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java b/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java index 808a46844..60ac6a243 100644 --- a/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java +++ b/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java @@ -30,7 +30,7 @@ import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; -import com.volmit.iris.util.scheduling.Task; +import de.crazydev22.platformutils.scheduler.task.Task; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Particle; diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/ChunkUpdater.java b/core/src/main/java/com/volmit/iris/core/pregenerator/ChunkUpdater.java index 572ce98d4..de5a767e2 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/ChunkUpdater.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/ChunkUpdater.java @@ -14,7 +14,6 @@ import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.profile.LoadBalancer; import com.volmit.iris.util.scheduling.J; -import io.papermc.lib.PaperLib; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; @@ -223,7 +222,7 @@ private boolean loadChunksIfGenerated(int x, int z) { for (int dx = -1; dx <= 1; dx++) { for (int dz = -1; dz <= 1; dz++) { - if (!PaperLib.isChunkGenerated(world, x + dx, z + dz)) { + if (!Iris.platform.isChunkGenerated(world, x + dx, z + dz)) { return false; } } @@ -239,7 +238,7 @@ private boolean loadChunksIfGenerated(int x, int z) { try { Chunk c; try { - c = PaperLib.getChunkAtAsync(world, xx, zz, false, true) + c = Iris.platform.getChunkAtAsync(world, xx, zz, false, true) .thenApply(chunk -> { if (chunk != null) chunk.addPluginChunkTicket(Iris.instance); @@ -260,7 +259,7 @@ private boolean loadChunksIfGenerated(int x, int z) { if (future != null) future.join(); } - if (!PaperLib.isChunkGenerated(c.getWorld(), xx, zz)) + if (!Iris.platform.isChunkGenerated(c.getWorld(), xx, zz)) generated.set(false); var pair = lastUse.computeIfAbsent(Cache.key(c), k -> new Pair<>(0L, new AtomicInteger(-1))); diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java index ebfbf81de..db4180c2d 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/LazyPregenerator.java @@ -11,7 +11,6 @@ import com.volmit.iris.util.math.Spiraler; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; -import io.papermc.lib.PaperLib; import lombok.Data; import lombok.Getter; import org.bukkit.Bukkit; @@ -148,23 +147,9 @@ private long computeETA() { private void tickGenerate(Position2 chunk) { executorService.submit(() -> { - CountDownLatch latch = new CountDownLatch(1); - if (PaperLib.isPaper()) { - PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true) - .thenAccept((i) -> { - Iris.verbose("Generated Async " + chunk); - latch.countDown(); - }); - } else { - J.s(() -> { - world.getChunkAt(chunk.getX(), chunk.getZ()); - Iris.verbose("Generated " + chunk); - latch.countDown(); - }); - } - try { - latch.await(); - } catch (InterruptedException ignored) {} + Iris.platform.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true).thenAccept((i) -> { + Iris.verbose("Generated Async " + chunk); + }).join(); lazyGeneratedChunks.addAndGet(1); }); } diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/TurboPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/TurboPregenerator.java index 5a8312307..46f72108e 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/TurboPregenerator.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/TurboPregenerator.java @@ -17,7 +17,6 @@ import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; -import io.papermc.lib.PaperLib; import lombok.Data; import lombok.Getter; import org.apache.logging.log4j.core.util.ExecutorServices; @@ -226,7 +225,7 @@ private long computeETA() { private void tickGenerate(Position2 chunk) { executorService.submit(() -> { CountDownLatch latch = new CountDownLatch(1); - PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true) + Iris.platform.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true) .thenAccept((i) -> { latch.countDown(); }); diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncOrMedievalPregenMethod.java b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncOrMedievalPregenMethod.java deleted file mode 100644 index f33fe2cdc..000000000 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncOrMedievalPregenMethod.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.volmit.iris.core.pregenerator.methods; - -import com.volmit.iris.core.pregenerator.PregenListener; -import com.volmit.iris.core.pregenerator.PregeneratorMethod; -import com.volmit.iris.util.mantle.Mantle; -import io.papermc.lib.PaperLib; -import org.bukkit.World; - -public class AsyncOrMedievalPregenMethod implements PregeneratorMethod { - private final PregeneratorMethod method; - - public AsyncOrMedievalPregenMethod(World world, int threads) { - method = PaperLib.isPaper() ? new AsyncPregenMethod(world, threads) : new MedievalPregenMethod(world); - } - - @Override - public void init() { - method.init(); - } - - @Override - public void close() { - method.close(); - } - - @Override - public void save() { - method.save(); - } - - @Override - public String getMethod(int x, int z) { - return method.getMethod(x, z); - } - - @Override - public boolean supportsRegions(int x, int z, PregenListener listener) { - return false; - } - - @Override - public void generateRegion(int x, int z, PregenListener listener) { - throw new UnsupportedOperationException(); - } - - @Override - public void generateChunk(int x, int z, PregenListener listener) { - method.generateChunk(x, z, listener); - } - - @Override - public Mantle getMantle() { - return method.getMantle(); - } -} diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java index 0dcfffcfc..6639a2f09 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java @@ -28,7 +28,6 @@ import com.volmit.iris.util.math.M; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.scheduling.J; -import io.papermc.lib.PaperLib; import org.bukkit.Chunk; import org.bukkit.World; @@ -48,11 +47,7 @@ public class AsyncPregenMethod implements PregeneratorMethod { private final boolean urgent; private final Map lastUse; - public AsyncPregenMethod(World world, int unusedThreads) { - if (!PaperLib.isPaper()) { - throw new UnsupportedOperationException("Cannot use PaperAsync on non paper!"); - } - + public AsyncPregenMethod(World world) { this.world = world; this.executor = IrisSettings.get().getPregen().isUseTicketQueue() ? new TicketExecutor() : new ServiceExecutor(); this.threads = IrisSettings.get().getPregen().getMaxConcurrency(); @@ -197,7 +192,7 @@ private class ServiceExecutor implements Executor { public void generate(int x, int z, PregenListener listener) { service.submit(() -> { try { - PaperLib.getChunkAtAsync(world, x, z, true, urgent).thenAccept((i) -> { + Iris.platform.getChunkAtAsync(world, x, z, true, urgent).thenAccept((i) -> { listener.onChunkGenerated(x, z); listener.onChunkCleaned(x, z); if (i == null) return; @@ -222,7 +217,7 @@ public void shutdown() { private class TicketExecutor implements Executor { @Override public void generate(int x, int z, PregenListener listener) { - PaperLib.getChunkAtAsync(world, x, z, true, urgent) + Iris.platform.getChunkAtAsync(world, x, z, true, urgent) .exceptionally(e -> { Iris.reportError(e); e.printStackTrace(); diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/HybridPregenMethod.java b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/HybridPregenMethod.java deleted file mode 100644 index 8ae773641..000000000 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/HybridPregenMethod.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.volmit.iris.core.pregenerator.methods; - -import com.volmit.iris.core.pregenerator.PregenListener; -import com.volmit.iris.core.pregenerator.PregeneratorMethod; -import com.volmit.iris.util.mantle.Mantle; -import org.bukkit.World; - -public class HybridPregenMethod implements PregeneratorMethod { - private final PregeneratorMethod inWorld; - private final World world; - - public HybridPregenMethod(World world, int threads) { - this.world = world; - inWorld = new AsyncOrMedievalPregenMethod(world, threads); - } - - @Override - public String getMethod(int x, int z) { - return "Hybrid<" + inWorld.getMethod(x, z) + ">"; - } - - @Override - public void init() { - inWorld.init(); - } - - @Override - public void close() { - inWorld.close(); - } - - @Override - public void save() { - inWorld.save(); - } - - @Override - public boolean supportsRegions(int x, int z, PregenListener listener) { - return inWorld.supportsRegions(x, z, listener); - } - - @Override - public void generateRegion(int x, int z, PregenListener listener) { - inWorld.generateRegion(x, z, listener); - } - - @Override - public void generateChunk(int x, int z, PregenListener listener) { - inWorld.generateChunk(x, z, listener); - } - - @Override - public Mantle getMantle() { - return inWorld.getMantle(); - } -} diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java deleted file mode 100644 index 2ebfb64b2..000000000 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/MedievalPregenMethod.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Iris is a World Generator for Minecraft Bukkit Servers - * Copyright (c) 2022 Arcane Arts (Volmit Software) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.volmit.iris.core.pregenerator.methods; - -import com.volmit.iris.Iris; -import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.core.pregenerator.PregenListener; -import com.volmit.iris.core.pregenerator.PregeneratorMethod; -import com.volmit.iris.core.tools.IrisToolbelt; -import com.volmit.iris.util.collection.KList; -import com.volmit.iris.util.collection.KMap; -import com.volmit.iris.util.mantle.Mantle; -import com.volmit.iris.util.math.M; -import com.volmit.iris.util.scheduling.J; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.World; - -import java.util.ArrayList; -import java.util.Map; -import java.util.concurrent.CompletableFuture; - -public class MedievalPregenMethod implements PregeneratorMethod { - private final World world; - private final KList> futures; - private final Map lastUse; - - public MedievalPregenMethod(World world) { - this.world = world; - futures = new KList<>(); - this.lastUse = new KMap<>(); - } - - private void waitForChunks() { - for (CompletableFuture i : futures) { - try { - i.get(); - } catch (Throwable e) { - e.printStackTrace(); - } - } - - futures.clear(); - } - - private void unloadAndSaveAllChunks() { - try { - J.sfut(() -> { - if (world == null) { - Iris.warn("World was null somehow..."); - return; - } - - for (Chunk i : new ArrayList<>(lastUse.keySet())) { - Long lastUseTime = lastUse.get(i); - if (lastUseTime != null && M.ms() - lastUseTime >= 10) { - i.unload(); - lastUse.remove(i); - } - } - world.save(); - }).get(); - } catch (Throwable e) { - e.printStackTrace(); - } - } - - @Override - public void init() { - unloadAndSaveAllChunks(); - } - - @Override - public void close() { - unloadAndSaveAllChunks(); - } - - @Override - public void save() { - unloadAndSaveAllChunks(); - } - - @Override - public boolean supportsRegions(int x, int z, PregenListener listener) { - return false; - } - - @Override - public void generateRegion(int x, int z, PregenListener listener) { - throw new UnsupportedOperationException(); - } - - @Override - public String getMethod(int x, int z) { - return "Medieval"; - } - - @Override - public void generateChunk(int x, int z, PregenListener listener) { - if (futures.size() > IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())) { - waitForChunks(); - } - - listener.onChunkGenerating(x, z); - futures.add(J.sfut(() -> { - world.getChunkAt(x, z); - Chunk c = Bukkit.getWorld(world.getUID()).getChunkAt(x, z); - lastUse.put(c, M.ms()); - listener.onChunkGenerated(x, z); - listener.onChunkCleaned(x, z); - })); - } - - @Override - public Mantle getMantle() { - if (IrisToolbelt.isIrisWorld(world)) { - return IrisToolbelt.access(world).getEngine().getMantle().getMantle(); - } - - return null; - } -} diff --git a/core/src/main/java/com/volmit/iris/core/service/EditSVC.java b/core/src/main/java/com/volmit/iris/core/service/EditSVC.java index f8aa2ca92..95c1d0ce9 100644 --- a/core/src/main/java/com/volmit/iris/core/service/EditSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/EditSVC.java @@ -24,7 +24,6 @@ import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.math.M; import com.volmit.iris.util.plugin.IrisService; -import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; @@ -38,7 +37,7 @@ public class EditSVC implements IrisService { @Override public void onEnable() { this.editors = new KMap<>(); - Iris.scheduler.global().runAtFixedRate(this::update, 1000, 1000); + Iris.platform.getGlobalScheduler().runAtFixedRate(this::update, 1000, 1000); } @Override diff --git a/core/src/main/java/com/volmit/iris/core/service/ObjectSVC.java b/core/src/main/java/com/volmit/iris/core/service/ObjectSVC.java index 08311871f..07a76268a 100644 --- a/core/src/main/java/com/volmit/iris/core/service/ObjectSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/ObjectSVC.java @@ -22,7 +22,6 @@ import com.volmit.iris.util.plugin.IrisService; import com.volmit.iris.util.scheduling.J; import lombok.Getter; -import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; @@ -71,7 +70,7 @@ private void loopChange(int amount) { */ private void revert(Map blocks) { Iterator> it = blocks.entrySet().iterator(); - var scheduler = Iris.scheduler.region(); + var scheduler = Iris.platform.getRegionScheduler(); for (int i = 0; i < 200 && it.hasNext(); i++) { Map.Entry entry = it.next(); Block block = entry.getKey(); diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java b/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java index a355d14b5..38e44f38a 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java @@ -11,7 +11,7 @@ import com.volmit.iris.util.reflect.V; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; -import com.volmit.iris.util.scheduling.Task; +import de.crazydev22.platformutils.scheduler.task.Task; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import org.apache.commons.io.FileUtils; import org.bukkit.Bukkit; diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java b/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java index 06651213c..043b8eab6 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java @@ -24,8 +24,8 @@ import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.pregenerator.PregenTask; import com.volmit.iris.core.pregenerator.PregeneratorMethod; +import com.volmit.iris.core.pregenerator.methods.AsyncPregenMethod; import com.volmit.iris.core.pregenerator.methods.CachedPregenMethod; -import com.volmit.iris.core.pregenerator.methods.HybridPregenMethod; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisDimension; @@ -165,8 +165,7 @@ public static PregeneratorJob pregenerate(PregenTask task, PregeneratorMethod me * @return the pregenerator job (already started) */ public static PregeneratorJob pregenerate(PregenTask task, PlatformChunkGenerator gen) { - return pregenerate(task, new HybridPregenMethod(gen.getEngine().getWorld().realWorld(), - IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), gen.getEngine()); + return pregenerate(task, new AsyncPregenMethod(gen.getEngine().getWorld().realWorld()), gen.getEngine()); } /** @@ -182,7 +181,7 @@ public static PregeneratorJob pregenerate(PregenTask task, World world) { return pregenerate(task, access(world)); } - return pregenerate(task, new HybridPregenMethod(world, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), null); + return pregenerate(task, new AsyncPregenMethod(world), null); } /** diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java index 47845161d..b6414e240 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -50,7 +50,7 @@ import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; -import com.volmit.iris.util.scheduling.Task; +import de.crazydev22.platformutils.scheduler.task.Task; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; diff --git a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index c115898fc..38158ae4c 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -41,7 +41,6 @@ import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.Looper; import com.volmit.iris.util.scheduling.jobs.QueueJob; -import io.papermc.lib.PaperLib; import lombok.Data; import lombok.EqualsAndHashCode; import org.bukkit.Chunk; @@ -62,7 +61,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -202,7 +200,7 @@ private void updateChunks() { for (Player i : getEngine().getWorld().realWorld().getPlayers()) { int r = 1; - Iris.scheduler.entity(i).run(() -> { + Iris.platform.getEntityScheduler(i).run(() -> { Chunk c = i.getLocation().getChunk(); for (int x = -r; x <= r; x++) { for (int z = -r; z <= r; z++) { @@ -499,7 +497,7 @@ private void warmupAreaAsync(Player player, Location to, Runnable r) { } futures.add(MultiBurst.burst.completeValue(() - -> PaperLib.getChunkAtAsync(to.getWorld(), + -> Iris.platform.getChunkAtAsync(to.getWorld(), (to.getBlockX() >> 4) + finalI, (to.getBlockZ() >> 4) + finalJ, true, IrisSettings.get().getWorld().getAsyncTeleport().isUrgent()).get())); @@ -536,9 +534,9 @@ public Map> getSpawnersFromMarkers(Chunk c) { IrisPosition pos = new IrisPosition((c.getX() << 4) + x, y, (c.getZ() << 4) + z); if (mark.isEmptyAbove()) { - Boolean remove = Iris.scheduler.region() + Boolean remove = Iris.platform.getRegionScheduler() .run(c.getWorld(), c.getX(), c.getZ(), () -> c.getBlock(x, y + 1, z).getType().isSolid() || c.getBlock(x, y + 2, z).getType().isSolid()) - .result() + .getResult() .exceptionally(e -> { Iris.reportError(e); e.printStackTrace(); diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java index 9577be6e0..aeae15fc9 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -64,7 +64,6 @@ import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.stream.ProceduralStream; -import io.papermc.lib.PaperLib; import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.Block; @@ -293,7 +292,7 @@ default void updateChunk(Chunk c) { try { Semaphore semaphore = new Semaphore(3); chunk.raiseFlag(MantleFlag.ETCHED, () -> { - var region = Iris.scheduler.region(); + var region = Iris.platform.getRegionScheduler(); chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> region.run(c.getWorld(), c.getX(), c.getZ(), () -> { mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> { int betterY = y + getWorld().minHeight(); @@ -541,8 +540,8 @@ default void addItems(boolean debug, Inventory inv, RNG rng, KList> 4, z >> 4).thenAccept((c) -> { + if (getWorld().hasRealWorld()) { + Iris.platform.getChunkAtAsync(getWorld().realWorld(), x >> 4, z >> 4, true, false).thenAccept((c) -> { Runnable r = () -> { for (ItemStack i : items) { inv.addItem(i); @@ -899,7 +898,7 @@ default void gotoJigsaw(IrisJigsawStructure s, Player player, boolean teleport) player.sendMessage(C.GOLD + "No strongholds in world."); } else { Location ll = new Location(player.getWorld(), pr.getX(), 40, pr.getZ()); - Iris.scheduler.teleportAsync(player, ll); + Iris.platform.teleportAsync(player, ll); } return; diff --git a/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java b/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java index 0dc0c49d0..d016927c9 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java @@ -20,24 +20,18 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.events.IrisEngineHotloadEvent; -import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.format.C; -import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.plugin.VolmitSender; -import com.volmit.iris.util.scheduling.Task; +import de.crazydev22.platformutils.scheduler.task.Task; import org.bukkit.*; -import org.bukkit.entity.EnderSignal; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.WorldSaveEvent; import org.bukkit.event.world.WorldUnloadEvent; -import org.bukkit.inventory.EquipmentSlot; import java.util.concurrent.atomic.AtomicBoolean; @@ -53,7 +47,7 @@ public EngineAssignedWorldManager() { public EngineAssignedWorldManager(Engine engine) { super(engine, "World"); Iris.instance.registerListener(this); - task = Iris.scheduler.global().runAtFixedRate(this::onTick, 1, 1); + task = Iris.platform.getGlobalScheduler().runAtFixedRate(this::onTick, 1, 1); } @EventHandler diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Locator.java b/core/src/main/java/com/volmit/iris/engine/framework/Locator.java index a0d42f473..794b3838e 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Locator.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Locator.java @@ -114,7 +114,7 @@ static Locator caveOrMantleBiome(String loadKey) { default void find(Player player, boolean teleport, String message) { find(player, location -> { if (teleport) { - Iris.scheduler.teleportAsync(player, location); + Iris.platform.teleportAsync(player, location); } else { player.sendMessage(C.GREEN + message + " at: " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ()); } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisCommand.java b/core/src/main/java/com/volmit/iris/engine/object/IrisCommand.java index 2c151534f..d678a4f4d 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisCommand.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisCommand.java @@ -65,7 +65,7 @@ public void run(Location at) { return; } - var scheduler = Iris.scheduler.global(); + var scheduler = Iris.platform.getGlobalScheduler(); for (String command : commands) { command = (command.startsWith("/") ? command.replaceFirst("/", "") : command) .replaceAll("\\Q{x}\\E", String.valueOf(at.getBlockX())) diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisEffect.java b/core/src/main/java/com/volmit/iris/engine/object/IrisEffect.java index e751d41b2..7752f6f87 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisEffect.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisEffect.java @@ -24,7 +24,6 @@ import com.volmit.iris.engine.object.annotations.*; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.scheduling.ChronoLatch; -import com.volmit.iris.util.scheduling.J; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -281,6 +280,6 @@ public void apply(Entity p) { } private void schedule(Entity entity, Runnable task) { - Iris.scheduler.entity(entity).run(task, null); + Iris.platform.getEntityScheduler(entity).run(task, null); } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java index 414ed285a..d76adabae 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java @@ -178,11 +178,11 @@ public Entity spawn(Engine gen, Location at) { } public Entity spawn(Engine gen, final Location at, RNG rng) { - if (!Iris.scheduler.isOwnedByCurrentRegion(at)) { + if (!Iris.platform.isOwnedByCurrentRegion(at)) { try { final Location finalAt = at; - return Iris.scheduler.region().run(at, () -> spawn(gen, finalAt, rng)) - .result() + return Iris.platform.getRegionScheduler().run(at, () -> spawn(gen, finalAt, rng)) + .getResult() .get(500, TimeUnit.MILLISECONDS); } catch (Throwable e) { return null; @@ -350,7 +350,7 @@ public void fillInventory(Inventory inventory, Random random, LootContext contex living.setCollidable(false); living.setNoDamageTicks(100000); AtomicInteger t = new AtomicInteger(0); - Iris.scheduler.region().runAtFixedRate(at, task -> { + Iris.platform.getRegionScheduler().runAtFixedRate(at, task -> { if (t.get() > 100) { task.cancel(); return; @@ -358,7 +358,7 @@ public void fillInventory(Inventory inventory, Random random, LootContext contex t.incrementAndGet(); if (e.getLocation().getBlock().getType().isSolid() || living.getEyeLocation().getBlock().getType().isSolid()) { - Iris.scheduler.teleportAsync(e, at.add(0, 0.1, 0)); + Iris.platform.teleportAsync(e, at.add(0, 0.1, 0)); ItemStack itemCrackData = new ItemStack(living.getEyeLocation().clone().subtract(0, 2, 0).getBlock().getBlockData().getMaterial()); e.getWorld().spawnParticle(ITEM, living.getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, itemCrackData); if (M.r(0.2)) { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java b/core/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java index b68f8a69b..acbee7305 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisEntitySpawn.java @@ -42,7 +42,7 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; -import static com.volmit.iris.Iris.scheduler; +import static com.volmit.iris.Iris.platform; @Snippet("entity-spawn") @Accessors(chain = true) @@ -172,9 +172,9 @@ private Entity spawn100(Engine g, Location at, boolean ignoreSurfaces) { if (!ignoreSurfaces) { Location block = at.clone().subtract(0, 1, 0); - BlockData data = scheduler.region() + BlockData data = platform.getRegionScheduler() .run(block, () -> block.getBlock().getBlockData()) - .result() + .getResult() .join(); if (!irisEntity.getSurface().matches(data)) { return null; @@ -212,7 +212,7 @@ private boolean isAreaClearForSpawn(Location center, Vector3d boundingBox) { int startZ = center.getBlockZ() - (int) (boundingBox.z / 2); int endZ = center.getBlockZ() + (int) (boundingBox.z / 2); - var region = scheduler.region(); + var region = platform.getRegionScheduler(); var lock = new Semaphore(Integer.MAX_VALUE, true); var bool = new AtomicBoolean(true); for (int x = startX; x <= endX; x++) { @@ -223,7 +223,7 @@ private boolean isAreaClearForSpawn(Location center, Vector3d boundingBox) { region.run(l, () -> { if (!bool.get()) return false; return bool.compareAndSet(true, l.getBlock().getType() == Material.AIR); - }).result().exceptionally(f -> false).thenRun(lock::release); + }).getResult().exceptionally(f -> false).thenRun(lock::release); } } } diff --git a/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java index e5509581a..b4a7e2b7c 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java +++ b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java @@ -80,7 +80,7 @@ public boolean isApplicable(BlockData data) { @Override public void toBukkit(Block block) { - Iris.scheduler.region().run(block.getLocation(), () -> handler.toBukkit(block)); + Iris.platform.getRegionScheduler().run(block.getLocation(), () -> handler.toBukkit(block)); } @Override diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index ab5d67066..e8bfcdc4a 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -40,7 +40,6 @@ import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.Looper; -import io.papermc.lib.PaperLib; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Setter; @@ -149,7 +148,7 @@ public void onWorldInit(WorldInitEvent event) { @Override public Location getFixedSpawnLocation(@NotNull World world, @NotNull Random random) { Location location = new Location(world, 0, 64, 0); - PaperLib.getChunkAtAsync(location) + Iris.platform.getChunkAtAsync(location) .thenAccept(c -> { World w = c.getWorld(); if (!w.getSpawnLocation().equals(location)) diff --git a/core/src/main/java/com/volmit/iris/util/board/BoardManager.java b/core/src/main/java/com/volmit/iris/util/board/BoardManager.java index d4813df7f..e0d01514a 100644 --- a/core/src/main/java/com/volmit/iris/util/board/BoardManager.java +++ b/core/src/main/java/com/volmit/iris/util/board/BoardManager.java @@ -19,7 +19,7 @@ package com.volmit.iris.util.board; import com.volmit.iris.Iris; -import com.volmit.iris.util.scheduling.Task; +import de.crazydev22.platformutils.scheduler.task.Task; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; @@ -43,7 +43,7 @@ public BoardManager(JavaPlugin plugin, BoardSettings boardSettings) { this.plugin = plugin; this.boardSettings = boardSettings; this.scoreboards = new ConcurrentHashMap<>(); - this.updateTask = Iris.scheduler.global().runAtFixedRate(new BoardUpdateTask(this), 2L, 20L); + this.updateTask = Iris.platform.getGlobalScheduler().runAtFixedRate(new BoardUpdateTask(this), 2L, 20L); plugin.getServer().getOnlinePlayers().forEach(this::setup); } diff --git a/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java b/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java index efe7ae481..4825a4df6 100644 --- a/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java +++ b/core/src/main/java/com/volmit/iris/util/plugin/VolmitSender.java @@ -50,7 +50,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; /** @@ -300,7 +299,7 @@ private Component createComponentRaw(String message) { public void showWaiting(String passive, CompletableFuture f) { AtomicReference g = new AtomicReference<>(); - Iris.scheduler.async().runAtFixedRate(task -> { + Iris.platform.getAsyncScheduler().runAtFixedRate(task -> { if (f.isDone() && g.get() != null) { task.cancel(); sendAction(" "); diff --git a/core/src/main/java/com/volmit/iris/util/profile/MsptTimings.java b/core/src/main/java/com/volmit/iris/util/profile/MsptTimings.java index 8ce433285..75fb5eddc 100644 --- a/core/src/main/java/com/volmit/iris/util/profile/MsptTimings.java +++ b/core/src/main/java/com/volmit/iris/util/profile/MsptTimings.java @@ -2,10 +2,8 @@ import com.volmit.iris.Iris; import com.volmit.iris.util.math.M; -import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.Looper; -import com.volmit.iris.util.scheduling.Task; -import org.bukkit.Bukkit; +import de.crazydev22.platformutils.scheduler.task.Task; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -54,10 +52,10 @@ public final int getMspt() { protected abstract void update(int mspt); private boolean startTickTask() { - if (task != null && !task.cancelled()) + if (task != null && !task.isCancelled()) return false; - task = Iris.scheduler.global().runAtFixedRate(t -> { + task = Iris.platform.getGlobalScheduler().runAtFixedRate(t -> { if (isInterrupted()) { t.cancel(); return; diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/AR.java b/core/src/main/java/com/volmit/iris/util/scheduling/AR.java index 244781e21..e7fb25eb0 100644 --- a/core/src/main/java/com/volmit/iris/util/scheduling/AR.java +++ b/core/src/main/java/com/volmit/iris/util/scheduling/AR.java @@ -19,6 +19,7 @@ package com.volmit.iris.util.scheduling; import com.volmit.iris.util.plugin.CancellableTask; +import de.crazydev22.platformutils.scheduler.task.Task; public abstract class AR implements Runnable, CancellableTask { private final Task task; diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/J.java b/core/src/main/java/com/volmit/iris/util/scheduling/J.java index 264865d2c..426cf8066 100644 --- a/core/src/main/java/com/volmit/iris/util/scheduling/J.java +++ b/core/src/main/java/com/volmit/iris/util/scheduling/J.java @@ -26,6 +26,7 @@ import com.volmit.iris.util.function.NastySupplier; import com.volmit.iris.util.math.FinalInteger; import com.volmit.iris.util.parallel.MultiBurst; +import de.crazydev22.platformutils.scheduler.task.Task; import org.bukkit.Bukkit; import java.util.concurrent.Callable; @@ -92,7 +93,7 @@ public static void aBukkit(Runnable a) { if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { return; } - Iris.scheduler.async().run(a); + Iris.platform.getAsyncScheduler().run(a); } public static Future a(Callable a) { @@ -225,7 +226,7 @@ public static void s(Runnable r) { if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { return; } - Iris.scheduler.global().run(r); + Iris.platform.getGlobalScheduler().run(r); } public static CompletableFuture sfut(Runnable r) { @@ -233,10 +234,10 @@ public static CompletableFuture sfut(Runnable r) { return null; } - return Iris.scheduler.global().run(() -> { + return Iris.platform.getGlobalScheduler().run(() -> { r.run(); return null; - }).result(); + }).getResult(); } public static CompletableFuture sfut(Runnable r, int delay) { @@ -244,10 +245,10 @@ public static CompletableFuture sfut(Runnable r, int delay) { return null; } - return Iris.scheduler.global().runDelayed(() -> { + return Iris.platform.getGlobalScheduler().runDelayed(() -> { r.run(); return null; - }, delay).result(); + }, delay).getResult(); } public static CompletableFuture afut(Runnable r) { @@ -270,7 +271,7 @@ public static void s(Runnable r, int delay) { if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { return; } - Iris.scheduler.global().runDelayed(r, delay); + Iris.platform.getGlobalScheduler().runDelayed(r, delay); } catch (Throwable e) { Iris.reportError(e); } @@ -287,7 +288,7 @@ public static Task sr(Runnable r, int interval) { if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { return null; } - return Iris.scheduler.global().runAtFixedRate(r, 1, Math.max(interval, 1)); + return Iris.platform.getGlobalScheduler().runAtFixedRate(r, 1, Math.max(interval, 1)); } /** @@ -298,7 +299,7 @@ public static Task sr(Runnable r, int interval) { */ public static void a(Runnable r, int delay) { if (Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { - Iris.scheduler.async().runDelayed(r, Math.max(delay * 50, 0), TimeUnit.MILLISECONDS); + Iris.platform.getAsyncScheduler().runDelayed(r, Math.max(delay * 50, 0), TimeUnit.MILLISECONDS); } } @@ -313,7 +314,7 @@ public static Task ar(Runnable r, int interval) { if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { return null; } - return Iris.scheduler.async().runAtFixedRate(r, 0, Math.max(interval, 1) * 50, TimeUnit.MILLISECONDS); + return Iris.platform.getAsyncScheduler().runAtFixedRate(r, 0, Math.max(interval, 1) * 50, TimeUnit.MILLISECONDS); } /** diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/SR.java b/core/src/main/java/com/volmit/iris/util/scheduling/SR.java index 50c882e36..a53c877a3 100644 --- a/core/src/main/java/com/volmit/iris/util/scheduling/SR.java +++ b/core/src/main/java/com/volmit/iris/util/scheduling/SR.java @@ -19,6 +19,7 @@ package com.volmit.iris.util.scheduling; import com.volmit.iris.util.plugin.CancellableTask; +import de.crazydev22.platformutils.scheduler.task.Task; public abstract class SR implements Runnable, CancellableTask { private final Task id; diff --git a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java index b0f332d2e..88f8cdc53 100644 --- a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java +++ b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java @@ -16,11 +16,9 @@ import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.matter.MatterBiomeInject; -import com.volmit.iris.util.nbt.io.NBTUtil; import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; -import com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.SneakyThrows; import net.minecraft.core.*; @@ -35,9 +33,7 @@ import net.minecraft.server.commands.data.BlockDataAccessor; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; -import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -63,31 +59,21 @@ import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_20_R1.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; -import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.entity.EntityType; import org.bukkit.generator.ChunkGenerator; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import sun.misc.Unsafe; import java.awt.Color; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; public class NMSBinding implements INMSBinding { @@ -211,7 +197,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); + Iris.platform.getRegionScheduler().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java index bd02f244d..5eacdf5a5 100644 --- a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java +++ b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java @@ -1,23 +1,17 @@ package com.volmit.iris.core.nms.v1_20_R2; import java.awt.Color; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Lifecycle; import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; -import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; import net.minecraft.core.*; import net.minecraft.core.Registry; @@ -45,10 +39,8 @@ import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_20_R2.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey; -import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; @@ -68,7 +60,6 @@ import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.matter.MatterBiomeInject; -import com.volmit.iris.util.nbt.io.NBTUtil; import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; @@ -79,14 +70,12 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; -import sun.misc.Unsafe; public class NMSBinding implements INMSBinding { private final KMap baseBiomeCache = new KMap<>(); @@ -208,7 +197,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); + Iris.platform.getRegionScheduler().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java index 1cd08a88c..4d3c1c179 100644 --- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java +++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java @@ -1,23 +1,17 @@ package com.volmit.iris.core.nms.v1_20_R3; import java.awt.Color; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Lifecycle; import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; -import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; import net.minecraft.core.*; import net.minecraft.core.Registry; @@ -45,10 +39,8 @@ import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey; -import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; @@ -68,7 +60,6 @@ import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.matter.MatterBiomeInject; -import com.volmit.iris.util.nbt.io.NBTUtil; import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; @@ -79,14 +70,12 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; -import sun.misc.Unsafe; public class NMSBinding implements INMSBinding { private final KMap baseBiomeCache = new KMap<>(); @@ -208,7 +197,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); + Iris.platform.getRegionScheduler().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java index a3685828d..db4bf2a80 100644 --- a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java +++ b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java @@ -7,7 +7,6 @@ import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Lifecycle; @@ -15,7 +14,6 @@ import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.util.nbt.tag.CompoundTag; -import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; import net.minecraft.core.*; import net.minecraft.core.Registry; @@ -33,7 +31,6 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.WorldLoader; import net.minecraft.server.commands.data.BlockDataAccessor; -import net.minecraft.server.commands.data.DataCommands; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.world.item.component.CustomData; @@ -41,7 +38,6 @@ import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.dimension.LevelStem; @@ -56,13 +52,9 @@ import org.bukkit.craftbukkit.v1_20_R4.CraftWorld; import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockStates; -import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockType; import org.bukkit.craftbukkit.v1_20_R4.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_20_R4.entity.CraftDolphin; -import org.bukkit.craftbukkit.v1_20_R4.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R4.util.CraftNamespacedKey; -import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; @@ -217,7 +209,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); + Iris.platform.getRegionScheduler().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java index b9b043836..c2ecbf658 100644 --- a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java +++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java @@ -1,24 +1,18 @@ package com.volmit.iris.core.nms.v1_21_R1; import java.awt.Color; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; import com.mojang.datafixers.util.Pair; import com.mojang.serialization.Lifecycle; import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; -import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; import net.minecraft.core.*; import net.minecraft.core.Registry; @@ -28,7 +22,6 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.WorldLoader; import net.minecraft.server.commands.data.BlockDataAccessor; -import net.minecraft.server.level.ChunkMap; import net.minecraft.tags.TagKey; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.level.LevelReader; @@ -51,10 +44,8 @@ import org.bukkit.craftbukkit.v1_21_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_21_R1.block.CraftBlockStates; import org.bukkit.craftbukkit.v1_21_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_21_R1.entity.CraftDolphin; import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_21_R1.util.CraftNamespacedKey; -import org.bukkit.entity.Dolphin; import org.bukkit.entity.Entity; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.generator.ChunkGenerator; @@ -74,7 +65,6 @@ import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.matter.MatterBiomeInject; -import com.volmit.iris.util.nbt.io.NBTUtil; import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; @@ -85,13 +75,11 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; -import sun.misc.Unsafe; public class NMSBinding implements INMSBinding { private final KMap baseBiomeCache = new KMap<>(); @@ -214,7 +202,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); + Iris.platform.getRegionScheduler().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java index 1b2ed64b2..ed6b6c2d8 100644 --- a/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java +++ b/nms/v1_21_R2/src/main/java/com/volmit/iris/core/nms/v1_21_R2/NMSBinding.java @@ -7,14 +7,11 @@ import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; import com.mojang.serialization.Lifecycle; import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; -import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.core.nms.datapack.DataVersion; -import com.volmit.iris.util.scheduling.J; import lombok.SneakyThrows; import net.minecraft.core.*; import net.minecraft.core.Registry; @@ -204,7 +201,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); + Iris.platform.getRegionScheduler().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java index f7a5b5f9a..7c940f506 100644 --- a/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java +++ b/nms/v1_21_R3/src/main/java/com/volmit/iris/core/nms/v1_21_R3/NMSBinding.java @@ -6,7 +6,6 @@ import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.core.nms.container.AutoClosing; import com.volmit.iris.core.nms.container.BiomeColor; -import com.volmit.iris.core.nms.container.Pair; import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; @@ -20,7 +19,6 @@ import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; -import com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.SneakyThrows; import net.minecraft.core.Registry; @@ -80,7 +78,6 @@ import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Function; public class NMSBinding implements INMSBinding { private final KMap baseBiomeCache = new KMap<>(); @@ -203,7 +200,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); + Iris.platform.getRegionScheduler().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java b/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java index 465a78f8c..a4ddcd98d 100644 --- a/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java +++ b/nms/v1_21_R4/src/main/java/com/volmit/iris/core/nms/v1_21_R4/NMSBinding.java @@ -19,7 +19,6 @@ import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.*; import com.volmit.iris.util.nbt.tag.CompoundTag; -import com.volmit.iris.util.scheduling.J; import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.SneakyThrows; import net.minecraft.core.Registry; @@ -201,7 +200,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - Iris.scheduler.region().run(pos, () -> merge(level, blockPos, tag)); + Iris.platform.getRegionScheduler().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { diff --git a/scheduler/build.gradle.kts b/scheduler/build.gradle.kts deleted file mode 100644 index cdb3e49b1..000000000 --- a/scheduler/build.gradle.kts +++ /dev/null @@ -1,7 +0,0 @@ -plugins { - java -} - -dependencies { - compileOnly("dev.folia:folia-api:1.20.1-R0.1-SNAPSHOT") -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/Platform.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/Platform.java deleted file mode 100644 index 95db49223..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/Platform.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.volmit.iris.util.scheduling; - -import com.volmit.iris.util.scheduling.paper.PaperPlatform; -import com.volmit.iris.util.scheduling.spigot.SpigotPlatform; -import com.volmit.iris.util.scheduling.split.IAsyncScheduler; -import com.volmit.iris.util.scheduling.split.IEntityScheduler; -import com.volmit.iris.util.scheduling.split.IGlobalScheduler; -import com.volmit.iris.util.scheduling.split.IRegionScheduler; -import org.bukkit.Location; -import org.bukkit.Server; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.entity.Entity; -import org.bukkit.event.player.PlayerTeleportEvent; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.CompletableFuture; - -@SuppressWarnings("unused") -public interface Platform { - /** - * Folia: Returns whether the current thread is ticking a region and that - * the region being ticked owns the chunk at the specified world and block - * position as included in the specified location. - * Paper/Spigot: Returns {@link Server#isPrimaryThread()} - * - * @param location Specified location, must have a non-null world - * @return true if the current thread is ticking the region that owns the chunk at the specified location - */ - boolean isOwnedByCurrentRegion(@NotNull Location location); - - /** - * Folia: Returns whether the current thread is ticking a region and that - * the region being ticked owns the chunks centered at the specified world - * and block position as included in the specified location within the - * specified square radius. Specifically, this function checks that every - * chunk with position x in [centerX - radius, centerX + radius] and - * position z in [centerZ - radius, centerZ + radius] is owned by the - * current ticking region. - * Paper/Spigot: Returns {@link Server#isPrimaryThread()} - * - * @param location Specified location, must have a non-null world - * @param squareRadiusChunks Specified square radius. Must be >= 0. Note that this parameter is not a squared radius, but rather a Chebyshev Distance - * @return true if the current thread is ticking the region that owns the chunks centered at the specified location within the specified square radius - */ - boolean isOwnedByCurrentRegion(@NotNull Location location, int squareRadiusChunks); - - /** - * Folia: Returns whether the current thread is ticking a region and that - * the region being ticked owns the chunk at the specified block position. - * Paper/Spigot: Returns {@link Server#isPrimaryThread()} - * - * @param block Specified block position - * @return true if the current thread is ticking the region that owns the chunk at the specified block position - */ - boolean isOwnedByCurrentRegion(@NotNull Block block); - - /** - * Folia: Returns whether the current thread is ticking a region and that - * the region being ticked owns the chunk at the specified world and chunk - * position. - * Paper/Spigot: Returns {@link Server#isPrimaryThread()} - * - * @param world Specified world - * @param chunkX Specified x-coordinate of the chunk position - * @param chunkZ Specified z-coordinate of the chunk position - * @return true if the current thread is ticking the region that owns the chunk at the specified world and chunk position - */ - boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ); - - /** - * Folia: Returns whether the current thread is ticking a region and that - * the region being ticked owns the chunks centered at the specified world - * and chunk position within the specified square radius. Specifically, - * this function checks that every chunk with position x in [centerX - - * radius, centerX + radius] and position z in [centerZ - radius, centerZ + - * radius] is owned by the current ticking region. - * Paper/Spigot: Returns {@link Server#isPrimaryThread()} - * - * @param world Specified world - * @param chunkX Specified x-coordinate of the chunk position - * @param chunkZ Specified z-coordinate of the chunk position - * @param squareRadiusChunks Specified square radius. Must be >= 0. Note that this parameter is not a squared radius, but rather a Chebyshev Distance. - * @return true if the current thread is ticking the region that owns the chunks centered at the specified world and chunk position within the specified square radius - */ - boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ, int squareRadiusChunks); - - /** - * Folia: Returns whether the current thread is ticking a region and that - * the region being ticked owns the specified entity. Note that this - * function is the only appropriate method of checking for ownership of an - * entity, as retrieving the entity's location is undefined unless the - * entity is owned by the current region. - * Paper/Spigot: Returns {@link Server#isPrimaryThread()} - * - * @param entity Specified entity - * @return true if the current thread is ticking the region that owns the specified entity - */ - boolean isOwnedByCurrentRegion(@NotNull Entity entity); - - /** - * Folia: Returns whether the current thread is ticking the global region. - * Paper/Spigot: Returns {@link Server#isPrimaryThread()} - * - * @return true if the current thread is ticking the global region - */ - boolean isGlobalTickThread(); - - /** - * Scheduler that may be used by plugins to schedule tasks to execute asynchronously from the server tick process. - */ - @NotNull IAsyncScheduler async(); - - /** - * An entity can move between worlds with an arbitrary tick delay, be temporarily removed - * for players (i.e end credits), be partially removed from world state (i.e inactive but not removed), - * teleport between ticking regions, teleport between worlds, and even be removed entirely from the server. - * The uncertainty of an entity's state can make it difficult to schedule tasks without worrying about undefined - * behaviors resulting from any of the states listed previously. - * - *

- * This class is designed to eliminate those states by providing an interface to run tasks only when an entity - * is contained in a world, on the owning thread for the region, and by providing the current Entity object. - * The scheduler also allows a task to provide a callback, the "retired" callback, that will be invoked - * if the entity is removed before a task that was scheduled could be executed. The scheduler is also - * completely thread-safe, allowing tasks to be scheduled from any thread context. The scheduler also indicates - * properly whether a task was scheduled successfully (i.e scheduler not retired), thus the code scheduling any task - * knows whether the given callbacks will be invoked eventually or not - which may be critical for off-thread - * contexts. - *

- */ - @NotNull IEntityScheduler entity(@NotNull Entity entity); - - /** - * The global region task scheduler may be used to schedule tasks that will execute on the global region. - *

- * 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. - *

- */ - @NotNull IGlobalScheduler global(); - - /** - * The region task scheduler can be used to schedule tasks by location to be executed on the region which owns the location. - *

- * Note: It is entirely inappropriate to use the region scheduler to schedule tasks for entities. - * If you wish to schedule tasks to perform actions on entities, you should be using {@link Entity#getScheduler()} - * as the entity scheduler will "follow" an entity if it is teleported, whereas the region task scheduler - * will not. - *

- */ - @NotNull IRegionScheduler region(); - - /** - * Teleport an entity to a location async - * @param entity Entity to teleport - * @param location Location to teleport to - * @return Future when the teleport is completed or failed - */ - default @NotNull CompletableFuture<@NotNull Boolean> teleportAsync(@NotNull Entity entity, @NotNull Location location) { - return teleportAsync(entity, location, PlayerTeleportEvent.TeleportCause.PLUGIN); - } - - /** - * Teleport an entity to a location async with a cause - * @param entity Entity to teleport - * @param location Location to teleport to - * @param cause Cause of the teleport - * @return Future when the teleport is completed or failed - */ - @NotNull CompletableFuture<@NotNull Boolean> teleportAsync(@NotNull Entity entity, @NotNull Location location, @NotNull PlayerTeleportEvent.TeleportCause cause); - - static @NotNull Platform create(@NotNull Plugin plugin) { - if (hasClass("com.destroystokyo.paper.PaperConfig") || hasClass("io.papermc.paper.configuration.Configuration")) - return new PaperPlatform(plugin); - if (hasClass("org.spigotmc.SpigotConfig")) - return new SpigotPlatform(plugin); - throw new IllegalStateException("Unsupported platform!"); - } - - static boolean hasClass(String name) { - try { - Class.forName(name); - return true; - } catch (Throwable e) { - return false; - } - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/Ref.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/Ref.java deleted file mode 100644 index c9a212e2e..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/Ref.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.volmit.iris.util.scheduling; - -public final class Ref { - public transient T value; -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/Task.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/Task.java deleted file mode 100644 index 4a09ad4fb..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/Task.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.volmit.iris.util.scheduling; - -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.CompletableFuture; -import java.util.function.Function; - -public interface Task { - void cancel(); - boolean cancelled(); - @NotNull Plugin owner(); - boolean async(); - - interface Completable extends Task { - @NotNull CompletableFuture result(); - - default void complete(Function, T> function) { - var future = result(); - try { - future.complete(function.apply(this)); - } catch (Throwable e) { - future.completeExceptionally(e); - } - } - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperPlatform.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperPlatform.java deleted file mode 100644 index 53e7bdb2e..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperPlatform.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.volmit.iris.util.scheduling.paper; - -import com.volmit.iris.util.scheduling.Platform; -import com.volmit.iris.util.scheduling.paper.split.PaperAsyncScheduler; -import com.volmit.iris.util.scheduling.paper.split.PaperEntityScheduler; -import com.volmit.iris.util.scheduling.paper.split.PaperGlobalScheduler; -import com.volmit.iris.util.scheduling.paper.split.PaperRegionScheduler; -import com.volmit.iris.util.scheduling.split.IAsyncScheduler; -import com.volmit.iris.util.scheduling.split.IEntityScheduler; -import com.volmit.iris.util.scheduling.split.IGlobalScheduler; -import com.volmit.iris.util.scheduling.split.IRegionScheduler; -import org.bukkit.Location; -import org.bukkit.Server; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.entity.Entity; -import org.bukkit.event.player.PlayerTeleportEvent; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.CompletableFuture; -import java.util.function.BooleanSupplier; - -public class PaperPlatform implements Platform { - private final Plugin plugin; - private final Server server; - private final IAsyncScheduler async; - private final IGlobalScheduler global; - private final IRegionScheduler region; - private final BooleanSupplier globalTickThread; - - public PaperPlatform(@NotNull Plugin plugin) { - this.plugin = plugin; - this.server = plugin.getServer(); - async = new PaperAsyncScheduler(plugin, server.getAsyncScheduler()); - global = new PaperGlobalScheduler(plugin, server.getGlobalRegionScheduler()); - region = new PaperRegionScheduler(plugin, server.getRegionScheduler()); - - BooleanSupplier method; - try { - method = server::isGlobalTickThread; - } catch (Throwable e) { - method = server::isPrimaryThread; - } - globalTickThread = method; - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull Location location) { - return server.isOwnedByCurrentRegion(location); - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull Location location, int squareRadiusChunks) { - return server.isOwnedByCurrentRegion(location, squareRadiusChunks); - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull Block block) { - return server.isOwnedByCurrentRegion(block); - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ) { - return server.isOwnedByCurrentRegion(world, chunkX, chunkZ); - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ, int squareRadiusChunks) { - return server.isOwnedByCurrentRegion(world, chunkX, chunkZ, squareRadiusChunks); - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull Entity entity) { - return server.isOwnedByCurrentRegion(entity); - } - - @Override - public boolean isGlobalTickThread() { - return globalTickThread.getAsBoolean(); - } - - @Override - public @NotNull IAsyncScheduler async() { - return async; - } - - @Override - public @NotNull IEntityScheduler entity(@NotNull Entity entity) { - return new PaperEntityScheduler(plugin, entity.getScheduler()); - } - - @Override - public @NotNull IGlobalScheduler global() { - return global; - } - - @Override - public @NotNull IRegionScheduler region() { - return region; - } - - @Override - public @NotNull CompletableFuture<@NotNull Boolean> teleportAsync(@NotNull Entity entity, @NotNull Location location, PlayerTeleportEvent.@NotNull TeleportCause cause) { - return entity.teleportAsync(location, cause); - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperTask.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperTask.java deleted file mode 100644 index ea90b8371..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/PaperTask.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.volmit.iris.util.scheduling.paper; - -import com.volmit.iris.util.scheduling.Task; -import io.papermc.paper.threadedregions.scheduler.ScheduledTask; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.CompletableFuture; - -public class PaperTask implements Task { - protected final ScheduledTask task; - protected final boolean async; - - public PaperTask(@NotNull ScheduledTask task, boolean async) { - this.task = task; - this.async = async; - } - - @Override - public void cancel() { - task.cancel(); - } - - @Override - public boolean cancelled() { - return task.isCancelled(); - } - - @Override - public @NotNull Plugin owner() { - return task.getOwningPlugin(); - } - - @Override - public boolean async() { - return async; - } - - public static class Completable extends PaperTask implements Task.Completable { - private final CompletableFuture result = new CompletableFuture<>(); - - public Completable(@NotNull ScheduledTask task, boolean async) { - super(task, async); - } - - @Override - public void cancel() { - ScheduledTask.CancelledState cancel = task.cancel(); - if (cancel == ScheduledTask.CancelledState.CANCELLED_BY_CALLER || cancel == ScheduledTask.CancelledState.NEXT_RUNS_CANCELLED || cancel == ScheduledTask.CancelledState.CANCELLED_ALREADY) { - result.cancel(false); - } - } - - @Override - public @NotNull CompletableFuture result() { - return result; - } - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java deleted file mode 100644 index 6eb38f052..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperAsyncScheduler.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.volmit.iris.util.scheduling.paper.split; - -import com.volmit.iris.util.scheduling.Ref; -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import com.volmit.iris.util.scheduling.paper.PaperTask; -import com.volmit.iris.util.scheduling.split.IAsyncScheduler; -import io.papermc.paper.threadedregions.scheduler.AsyncScheduler; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Range; - -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import java.util.function.Function; - -public class PaperAsyncScheduler implements IAsyncScheduler { - private final Plugin plugin; - private final AsyncScheduler scheduler; - - public PaperAsyncScheduler(Plugin plugin, AsyncScheduler scheduler) { - this.plugin = plugin; - this.scheduler = scheduler; - } - - @Override - public @NotNull Completable run(@NotNull Function, R> task) { - Ref> ref = new Ref<>(); - return ref.value = new PaperTask.Completable<>(scheduler.runNow(plugin, t -> ref.value.complete(task)), true); - } - - @Override - public @NotNull Completable runDelayed(@NotNull Function, R> task, - @Range(from = 0, to = Long.MAX_VALUE) long delay, - @NotNull TimeUnit unit) { - Ref> ref = new Ref<>(); - return ref.value = new PaperTask.Completable<>(scheduler.runDelayed(plugin, t -> ref.value.complete(task), delay, unit), true); - } - - @Override - public @NotNull Task runAtFixedRate(@NotNull Consumer task, - @Range(from = 0, to = Long.MAX_VALUE) long initialDelay, - @Range(from = 1, to = Long.MAX_VALUE) long period, - @NotNull TimeUnit unit) { - Ref ref = new Ref<>(); - return ref.value = new PaperTask(scheduler.runAtFixedRate(plugin, t -> task.accept(ref.value), initialDelay, period, unit), true); - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperEntityScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperEntityScheduler.java deleted file mode 100644 index 4748398db..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperEntityScheduler.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.volmit.iris.util.scheduling.paper.split; - -import com.volmit.iris.util.scheduling.Ref; -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import com.volmit.iris.util.scheduling.paper.PaperTask; -import com.volmit.iris.util.scheduling.split.IEntityScheduler; -import io.papermc.paper.threadedregions.scheduler.EntityScheduler; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.Range; - -import java.util.function.Consumer; -import java.util.function.Function; - -public class PaperEntityScheduler implements IEntityScheduler { - private final Plugin plugin; - private final EntityScheduler scheduler; - - public PaperEntityScheduler(Plugin plugin, EntityScheduler scheduler) { - this.plugin = plugin; - this.scheduler = scheduler; - } - - @Override - public @Nullable Completable runDelayed(@NotNull Function, R> task, - @Nullable Runnable retired, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - Ref> ref = new Ref<>(); - var raw = scheduler.runDelayed(plugin, t -> ref.value.complete(task), () -> { - if (retired != null) retired.run(); - ref.value.cancel(); - }, delayTicks); - if (raw == null) return null; - return ref.value = new PaperTask.Completable<>(raw, false); - } - - @Override - public @Nullable Task runAtFixedRate(@NotNull Consumer task, - @Nullable Runnable retired, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, - @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { - Ref ref = new Ref<>(); - var raw = scheduler.runAtFixedRate(plugin, t -> task.accept(ref.value), retired, initialDelayTicks, periodTicks); - if (raw == null) return null; - return ref.value = new PaperTask(raw, false); - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperGlobalScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperGlobalScheduler.java deleted file mode 100644 index de369951f..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperGlobalScheduler.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.volmit.iris.util.scheduling.paper.split; - -import com.volmit.iris.util.scheduling.Ref; -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import com.volmit.iris.util.scheduling.paper.PaperTask; -import com.volmit.iris.util.scheduling.split.IGlobalScheduler; -import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Range; - -import java.util.function.Consumer; -import java.util.function.Function; - -public class PaperGlobalScheduler implements IGlobalScheduler { - private final Plugin plugin; - private final GlobalRegionScheduler scheduler; - - public PaperGlobalScheduler(Plugin plugin, GlobalRegionScheduler scheduler) { - this.plugin = plugin; - this.scheduler = scheduler; - } - - @Override - public @NotNull Completable runDelayed(@NotNull Function, R> task, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - Ref> ref = new Ref<>(); - return ref.value = new PaperTask.Completable<>(scheduler.runDelayed(plugin, t -> ref.value.complete(task), delayTicks), false); - } - - @Override - public @NotNull Task runAtFixedRate(@NotNull Consumer task, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, - @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { - Ref ref = new Ref<>(); - return ref.value = new PaperTask(scheduler.runAtFixedRate(plugin, t -> task.accept(ref.value), initialDelayTicks, periodTicks), false); - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperRegionScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperRegionScheduler.java deleted file mode 100644 index 7ac140b2f..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/paper/split/PaperRegionScheduler.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.volmit.iris.util.scheduling.paper.split; - -import com.volmit.iris.util.scheduling.Ref; -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import com.volmit.iris.util.scheduling.paper.PaperTask; -import com.volmit.iris.util.scheduling.split.IRegionScheduler; -import io.papermc.paper.threadedregions.scheduler.RegionScheduler; -import org.bukkit.World; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Range; - -import java.util.function.Consumer; -import java.util.function.Function; - -public class PaperRegionScheduler implements IRegionScheduler { - private final Plugin plugin; - private final RegionScheduler scheduler; - - public PaperRegionScheduler(Plugin plugin, RegionScheduler scheduler) { - this.plugin = plugin; - this.scheduler = scheduler; - } - - @Override - public @NotNull Completable runDelayed(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Function, R> task, @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - Ref> ref = new Ref<>(); - return ref.value = new PaperTask.Completable<>(scheduler.runDelayed(plugin, world, chunkX, chunkZ, t -> ref.value.complete(task), delayTicks), false); - } - - @Override - public @NotNull Task runAtFixedRate(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Consumer task, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, - @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { - Ref ref = new Ref<>(); - return ref.value = new PaperTask(scheduler.runAtFixedRate(plugin, world, chunkX, chunkZ, t -> task.accept(ref.value), initialDelayTicks, periodTicks), false); - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotPlatform.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotPlatform.java deleted file mode 100644 index 22f84dae9..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotPlatform.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.volmit.iris.util.scheduling.spigot; - -import com.volmit.iris.util.scheduling.Platform; -import com.volmit.iris.util.scheduling.spigot.split.SpigotAsyncScheduler; -import com.volmit.iris.util.scheduling.spigot.split.SpigotEntityScheduler; -import com.volmit.iris.util.scheduling.spigot.split.SpigotGlobalScheduler; -import com.volmit.iris.util.scheduling.spigot.split.SpigotRegionScheduler; -import com.volmit.iris.util.scheduling.split.IAsyncScheduler; -import com.volmit.iris.util.scheduling.split.IEntityScheduler; -import com.volmit.iris.util.scheduling.split.IGlobalScheduler; -import com.volmit.iris.util.scheduling.split.IRegionScheduler; -import org.bukkit.Location; -import org.bukkit.Server; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.entity.Projectile; -import org.bukkit.event.player.PlayerTeleportEvent; -import org.bukkit.plugin.Plugin; -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.CompletableFuture; - -public class SpigotPlatform implements Platform { - private final Server server; - private final IAsyncScheduler async; - private final IGlobalScheduler global; - private final IRegionScheduler region; - - public SpigotPlatform(@NotNull Plugin plugin) { - server = plugin.getServer(); - var scheduler = server.getScheduler(); - async = new SpigotAsyncScheduler(plugin, scheduler); - global = new SpigotGlobalScheduler(plugin, scheduler); - region = new SpigotRegionScheduler(global); - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull Location location) { - return server.isPrimaryThread(); - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull Location location, int squareRadiusChunks) { - return server.isPrimaryThread(); - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull Block block) { - return server.isPrimaryThread(); - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ) { - return server.isPrimaryThread(); - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull World world, int chunkX, int chunkZ, int squareRadiusChunks) { - return server.isPrimaryThread(); - } - - @Override - public boolean isOwnedByCurrentRegion(@NotNull Entity entity) { - return server.isPrimaryThread(); - } - - @Override - public boolean isGlobalTickThread() { - return server.isPrimaryThread(); - } - - @Override - public @NotNull IAsyncScheduler async() { - return async; - } - - @Override - public @NotNull IEntityScheduler entity(@NotNull Entity entity) { - return new SpigotEntityScheduler(global, entity); - } - - @Override - public @NotNull IGlobalScheduler global() { - return global; - } - - @Override - public @NotNull IRegionScheduler region() { - return region; - } - - @Override - public @NotNull CompletableFuture<@NotNull Boolean> teleportAsync(@NotNull Entity entity, @NotNull Location location, PlayerTeleportEvent.@NotNull TeleportCause cause) { - return global().run(task -> isValid(entity) && entity.teleport(location)).result().thenApply(b -> b != null ? b : false); - } - - public static boolean isValid(Entity entity) { - if (entity.isValid()) { - return !(entity instanceof Player) || ((Player) entity).isOnline(); - } - return entity instanceof Projectile && !entity.isDead(); - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotTask.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotTask.java deleted file mode 100644 index 3991b1f22..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/SpigotTask.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.volmit.iris.util.scheduling.spigot; - -import com.volmit.iris.util.scheduling.Task; -import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; -import org.jetbrains.annotations.NotNull; - -import java.util.concurrent.CompletableFuture; - -public class SpigotTask implements Task { - protected final BukkitTask task; - - public SpigotTask(@NotNull BukkitTask task) { - this.task = task; - } - - @Override - public void cancel() { - task.cancel(); - } - - @Override - public boolean cancelled() { - return task.isCancelled(); - } - - @Override - public @NotNull Plugin owner() { - return task.getOwner(); - } - - @Override - public boolean async() { - return !task.isSync(); - } - - @SuppressWarnings("deprecation") - public static class Completable extends SpigotTask implements Task.Completable { - private final CompletableFuture result = new CompletableFuture<>(); - private final BukkitScheduler scheduler; - - public Completable(@NotNull BukkitTask task, @NotNull BukkitScheduler scheduler) { - super(task); - this.scheduler = scheduler; - } - - @Override - public void cancel() { - scheduler.cancelTask(task.getTaskId()); - if (scheduler.isCurrentlyRunning(task.getTaskId())) return; - result.cancel(false); - } - - @Override - public @NotNull CompletableFuture result() { - return result; - } - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotAsyncScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotAsyncScheduler.java deleted file mode 100644 index ea474f377..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotAsyncScheduler.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.volmit.iris.util.scheduling.spigot.split; - -import com.volmit.iris.util.scheduling.Ref; -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import com.volmit.iris.util.scheduling.spigot.SpigotTask; -import com.volmit.iris.util.scheduling.split.IAsyncScheduler; -import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitScheduler; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Range; - -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import java.util.function.Function; - -@SuppressWarnings("deprecation") -public class SpigotAsyncScheduler implements IAsyncScheduler { - private final Plugin plugin; - private final BukkitScheduler scheduler; - - public SpigotAsyncScheduler(Plugin plugin, BukkitScheduler scheduler) { - this.plugin = plugin; - this.scheduler = scheduler; - } - - @Override - public @NotNull Completable run(@NotNull Function, R> task) { - Ref> ref = new Ref<>(); - return ref.value = new SpigotTask.Completable<>(scheduler.runTaskAsynchronously(plugin, () -> ref.value.complete(task)), scheduler); - } - - @Override - public @NotNull Completable runDelayed(@NotNull Function, R> task, @Range(from = 0, to = Long.MAX_VALUE) long delay, @NotNull TimeUnit unit) { - Ref> ref = new Ref<>(); - return ref.value = new SpigotTask.Completable<>(scheduler.runTaskLaterAsynchronously(plugin, () -> ref.value.complete(task), unit.toMillis(delay) / 50), scheduler); - } - - @Override - public @NotNull Task runAtFixedRate(@NotNull Consumer task, @Range(from = 0, to = Long.MAX_VALUE) long initialDelay, @Range(from = 0, to = Long.MAX_VALUE) long period, @NotNull TimeUnit unit) { - Ref ref = new Ref<>(); - return ref.value = new SpigotTask(scheduler.runTaskTimerAsynchronously(plugin, () -> task.accept(ref.value), unit.toMillis(initialDelay) / 50, unit.toMillis(period) / 50)); - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotEntityScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotEntityScheduler.java deleted file mode 100644 index 45d390354..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotEntityScheduler.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.volmit.iris.util.scheduling.spigot.split; - -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import com.volmit.iris.util.scheduling.split.IEntityScheduler; -import com.volmit.iris.util.scheduling.split.IGlobalScheduler; -import org.bukkit.entity.Entity; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.Range; - -import java.util.function.Consumer; -import java.util.function.Function; - -import static com.volmit.iris.util.scheduling.spigot.SpigotPlatform.isValid; - -public class SpigotEntityScheduler implements IEntityScheduler { - private final IGlobalScheduler scheduler; - private final Entity entity; - - public SpigotEntityScheduler(IGlobalScheduler scheduler, Entity entity) { - this.scheduler = scheduler; - this.entity = entity; - } - - @Override - public @Nullable Completable runDelayed(@NotNull Function, R> task, @Nullable Runnable retired, @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - if (!isValid(entity)) return null; - return scheduler.runDelayed(t -> { - if (!isValid(entity)) { - t.cancel(); - if (retired != null) - retired.run(); - return null; - } - return task.apply(t); - }, delayTicks); - } - - @Override - public @Nullable Task runAtFixedRate(@NotNull Consumer task, @Nullable Runnable retired, @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { - if (!isValid(entity)) return null; - return scheduler.runAtFixedRate(t -> { - if (!isValid(entity)) { - t.cancel(); - if (retired != null) - retired.run(); - return; - } - task.accept(t); - }, initialDelayTicks, periodTicks); - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotGlobalScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotGlobalScheduler.java deleted file mode 100644 index 9b82eba56..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotGlobalScheduler.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.volmit.iris.util.scheduling.spigot.split; - -import com.volmit.iris.util.scheduling.Ref; -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import com.volmit.iris.util.scheduling.spigot.SpigotTask; -import com.volmit.iris.util.scheduling.split.IGlobalScheduler; -import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitScheduler; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Range; - -import java.util.function.Consumer; -import java.util.function.Function; - -@SuppressWarnings("deprecation") -public class SpigotGlobalScheduler implements IGlobalScheduler { - private final Plugin plugin; - private final BukkitScheduler scheduler; - - public SpigotGlobalScheduler(Plugin plugin, BukkitScheduler scheduler) { - this.plugin = plugin; - this.scheduler = scheduler; - } - - @Override - public @NotNull Completable runDelayed(@NotNull Function, R> task, @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - Ref> ref = new Ref<>(); - return ref.value = new SpigotTask.Completable<>(scheduler.runTaskLater(plugin, () -> ref.value.complete(task), delayTicks), scheduler); - } - - @Override - public @NotNull Task runAtFixedRate(@NotNull Consumer task, @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { - Ref ref = new Ref<>(); - return ref.value = new SpigotTask(scheduler.runTaskTimer(plugin, () -> task.accept(ref.value), initialDelayTicks, periodTicks)); - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotRegionScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotRegionScheduler.java deleted file mode 100644 index 75c83e58e..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/spigot/split/SpigotRegionScheduler.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.volmit.iris.util.scheduling.spigot.split; - -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import com.volmit.iris.util.scheduling.split.IGlobalScheduler; -import com.volmit.iris.util.scheduling.split.IRegionScheduler; -import org.bukkit.World; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Range; - -import java.util.function.Consumer; -import java.util.function.Function; - -public class SpigotRegionScheduler implements IRegionScheduler { - private final IGlobalScheduler scheduler; - - public SpigotRegionScheduler(IGlobalScheduler scheduler) { - this.scheduler = scheduler; - } - - @Override - public @NotNull Completable runDelayed(@NotNull World world, int chunkX, int chunkZ, @NotNull Function, R> task, @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return scheduler.runDelayed(task, delayTicks); - } - - @Override - public @NotNull Task runAtFixedRate(@NotNull World world, int chunkX, int chunkZ, @NotNull Consumer task, @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { - return scheduler.runAtFixedRate(task, initialDelayTicks, periodTicks); - } -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java deleted file mode 100644 index 5a5968be3..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IAsyncScheduler.java +++ /dev/null @@ -1,146 +0,0 @@ -package com.volmit.iris.util.scheduling.split; - -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Range; - -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * Scheduler that may be used by plugins to schedule tasks to execute asynchronously from the server tick process. - */ -public interface IAsyncScheduler { - /** - * Schedules the specified task to be executed asynchronously immediately. - * @param task Specified task. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task run(@NotNull Consumer task) { - return run(t -> { - task.accept(t); - return null; - }); - } - - /** - * Schedules the specified task to be executed asynchronously immediately. - * @param task Specified task. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task run(@NotNull Runnable task) { - return run(t -> { - task.run(); - return null; - }); - } - - /** - * Schedules the specified task to be executed asynchronously immediately. - * @param task Specified task. - * @return The {@link Completable} that represents the scheduled task. - */ - default @NotNull Completable run(@NotNull Supplier task) { - return run(t -> { - return task.get(); - }); - } - - /** - * Schedules the specified task to be executed asynchronously immediately. - * @param task Specified task. - * @return The {@link Completable} that represents the scheduled task. - */ - @NotNull Completable run(@NotNull Function, R> task); - - /** - * Schedules the specified task to be executed asynchronously after the time delay has passed. - * @param task Specified task. - * @param delay The time delay to pass before the task should be executed. - * @param unit The time unit for the time delay. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runDelayed(@NotNull Consumer task, - @Range(from = 0, to = Long.MAX_VALUE) long delay, - @NotNull TimeUnit unit) { - return runDelayed(t -> { - task.accept(t); - return null; - }, delay, unit); - } - - /** - * Schedules the specified task to be executed asynchronously after the time delay has passed. - * @param task Specified task. - * @param delay The time delay to pass before the task should be executed. - * @param unit The time unit for the time delay. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runDelayed(@NotNull Runnable task, - @Range(from = 0, to = Long.MAX_VALUE) long delay, - @NotNull TimeUnit unit) { - return runDelayed(t -> { - task.run(); - return null; - }, delay, unit); - } - - /** - * Schedules the specified task to be executed asynchronously after the time delay has passed. - * @param task Specified task. - * @param delay The time delay to pass before the task should be executed. - * @param unit The time unit for the time delay. - * @return The {@link Completable} that represents the scheduled task. - */ - default @NotNull Completable runDelayed(@NotNull Supplier task, - @Range(from = 0, to = Long.MAX_VALUE) long delay, - @NotNull TimeUnit unit) { - return runDelayed(t -> { - return task.get(); - }, delay, unit); - } - - /** - * Schedules the specified task to be executed asynchronously after the time delay has passed. - * @param task Specified task. - * @param delay The time delay to pass before the task should be executed. - * @param unit The time unit for the time delay. - * @return The {@link Completable} that represents the scheduled task. - */ - @NotNull Completable runDelayed(@NotNull Function, R> task, - @Range(from = 0, to = Long.MAX_VALUE) long delay, - @NotNull TimeUnit unit); - - /** - * Schedules the specified task to be executed asynchronously after the initial delay has passed, - * and then periodically executed with the specified period. - * @param task Specified task. - * @param initialDelay The time delay to pass before the first execution of the task. - * @param period The time between task executions after the first execution of the task. - * @param unit The time unit for the initial delay and period. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runAtFixedRate(@NotNull Runnable task, - @Range(from = 0, to = Long.MAX_VALUE) long initialDelay, - @Range(from = 1, to = Long.MAX_VALUE) long period, - @NotNull TimeUnit unit) { - return runAtFixedRate(t -> task.run(), initialDelay, period, unit); - } - - /** - * Schedules the specified task to be executed asynchronously after the initial delay has passed, - * and then periodically executed with the specified period. - * @param task Specified task. - * @param initialDelay The time delay to pass before the first execution of the task. - * @param period The time between task executions after the first execution of the task. - * @param unit The time unit for the initial delay and period. - * @return The {@link Task} that represents the scheduled task. - */ - @NotNull Task runAtFixedRate(@NotNull Consumer task, - @Range(from = 0, to = Long.MAX_VALUE) long initialDelay, - @Range(from = 1, to = Long.MAX_VALUE) long period, - @NotNull TimeUnit unit); -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java deleted file mode 100644 index 141630a12..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IEntityScheduler.java +++ /dev/null @@ -1,250 +0,0 @@ -package com.volmit.iris.util.scheduling.split; - -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.Range; - -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * An entity can move between worlds with an arbitrary tick delay, be temporarily removed - * for players (i.e end credits), be partially removed from world state (i.e inactive but not removed), - * teleport between ticking regions, teleport between worlds, and even be removed entirely from the server. - * The uncertainty of an entity's state can make it difficult to schedule tasks without worrying about undefined - * behaviors resulting from any of the states listed previously. - * - *

- * This class is designed to eliminate those states by providing an interface to run tasks only when an entity - * is contained in a world, on the owning thread for the region, and by providing the current Entity object. - * The scheduler also allows a task to provide a callback, the "retired" callback, that will be invoked - * if the entity is removed before a task that was scheduled could be executed. The scheduler is also - * completely thread-safe, allowing tasks to be scheduled from any thread context. The scheduler also indicates - * properly whether a task was scheduled successfully (i.e scheduler not retired), thus the code scheduling any task - * knows whether the given callbacks will be invoked eventually or not - which may be critical for off-thread - * contexts. - *

- */ -public interface IEntityScheduler { - - /** - * Schedules a task to execute on the next tick. If the task failed to schedule because the scheduler is retired (entity - * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, - * or the retired callback will be invoked if the scheduler is retired. - * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove - * other entities, load chunks, load worlds, modify ticket levels, etc. - * - *

- * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. - *

- * @param task The task to execute - * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. - * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. - */ - default @Nullable Task run(@NotNull Consumer task, - @Nullable Runnable retired) { - return run(t -> { - task.accept(t); - return null; - }, retired); - } - - /** - * Schedules a task to execute on the next tick. If the task failed to schedule because the scheduler is retired (entity - * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, - * or the retired callback will be invoked if the scheduler is retired. - * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove - * other entities, load chunks, load worlds, modify ticket levels, etc. - * - *

- * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. - *

- * @param task The task to execute - * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. - * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. - */ - default @Nullable Task run(@NotNull Runnable task, - @Nullable Runnable retired) { - return run(t -> { - task.run(); - return null; - }, retired); - } - - /** - * Schedules a task to execute on the next tick. If the task failed to schedule because the scheduler is retired (entity - * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, - * or the retired callback will be invoked if the scheduler is retired. - * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove - * other entities, load chunks, load worlds, modify ticket levels, etc. - * - *

- * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. - *

- * @param task The task to execute - * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. - * @return The {@link Completable} that represents the scheduled task, or {@code null} if the entity has been removed. - */ - default @Nullable Completable run(@NotNull Supplier task, - @Nullable Runnable retired) { - return run(t -> { - return task.get(); - }, retired); - } - - /** - * Schedules a task to execute on the next tick. If the task failed to schedule because the scheduler is retired (entity - * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, - * or the retired callback will be invoked if the scheduler is retired. - * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove - * other entities, load chunks, load worlds, modify ticket levels, etc. - * - *

- * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. - *

- * @param task The task to execute - * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. - * @return The {@link Completable} that represents the scheduled task, or {@code null} if the entity has been removed. - */ - default @Nullable Completable run(@NotNull Function, R> task, - @Nullable Runnable retired) { - return runDelayed(task, retired, 1); - } - - /** - * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity - * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, - * or the retired callback will be invoked if the scheduler is retired. - * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove - * other entities, load chunks, load worlds, modify ticket levels, etc. - * - *

- * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. - *

- * @param task The task to execute - * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. - * @param delayTicks The delay, in ticks. - * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. - */ - default @Nullable Task runDelayed(@NotNull Consumer task, - @Nullable Runnable retired, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return runDelayed(t -> { - task.accept(t); - return null; - }, retired, delayTicks); - } - - /** - * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity - * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, - * or the retired callback will be invoked if the scheduler is retired. - * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove - * other entities, load chunks, load worlds, modify ticket levels, etc. - * - *

- * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. - *

- * @param task The task to execute - * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. - * @param delayTicks The delay, in ticks. - * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. - */ - default @Nullable Task runDelayed(@NotNull Runnable task, - @Nullable Runnable retired, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return runDelayed(t -> { - task.run(); - return null; - }, retired, delayTicks); - } - - /** - * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity - * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, - * or the retired callback will be invoked if the scheduler is retired. - * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove - * other entities, load chunks, load worlds, modify ticket levels, etc. - * - *

- * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. - *

- * @param task The task to execute - * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. - * @param delayTicks The delay, in ticks. - * @return The {@link Completable} that represents the scheduled task, or {@code null} if the entity has been removed. - */ - default @Nullable Completable runDelayed(@NotNull Supplier task, - @Nullable Runnable retired, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return runDelayed(t -> { - return task.get(); - }, retired, delayTicks); - } - - /** - * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity - * removed), then returns {@code null}. Otherwise, either the task callback will be invoked after the specified delay, - * or the retired callback will be invoked if the scheduler is retired. - * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove - * other entities, load chunks, load worlds, modify ticket levels, etc. - * - *

- * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. - *

- * @param task The task to execute - * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. - * @param delayTicks The delay, in ticks. - * @return The {@link Completable} that represents the scheduled task, or {@code null} if the entity has been removed. - */ - @Nullable Completable runDelayed(@NotNull Function, R> task, - @Nullable Runnable retired, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks); - - /** - * Schedules a repeating task with the given delay and period. If the task failed to schedule because the scheduler - * is retired (entity removed), then returns {@code null}. Otherwise, either the task callback will be invoked after - * the specified delay, or the retired callback will be invoked if the scheduler is retired. - * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove - * other entities, load chunks, load worlds, modify ticket levels, etc. - * - *

- * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. - *

- * @param task The task to execute - * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. - * @param initialDelayTicks The initial delay, in ticks. - * @param periodTicks The period, in ticks. - * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. - */ - default @Nullable Task runAtFixedRate(@NotNull Runnable task, - @Nullable Runnable retired, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, - @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { - return runAtFixedRate(t -> task.run(), retired, initialDelayTicks, periodTicks); - } - - /** - * Schedules a repeating task with the given delay and period. If the task failed to schedule because the scheduler - * is retired (entity removed), then returns {@code null}. Otherwise, either the task callback will be invoked after - * the specified delay, or the retired callback will be invoked if the scheduler is retired. - * Note that the retired callback is invoked in critical code, so it should not attempt to remove the entity, remove - * other entities, load chunks, load worlds, modify ticket levels, etc. - * - *

- * It is guaranteed that the task and retired callback are invoked on the region which owns the entity. - *

- * @param task The task to execute - * @param retired Retire callback to run if the entity is retired before the run callback can be invoked, may be null. - * @param initialDelayTicks The initial delay, in ticks. - * @param periodTicks The period, in ticks. - * @return The {@link Task} that represents the scheduled task, or {@code null} if the entity has been removed. - */ - @Nullable Task runAtFixedRate(@NotNull Consumer task, - @Nullable Runnable retired, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, - @Range(from = 1, to = Long.MAX_VALUE) long periodTicks); -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java deleted file mode 100644 index 5644443ee..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IGlobalScheduler.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.volmit.iris.util.scheduling.split; - -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Range; - -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * The global region task scheduler may be used to schedule tasks that will execute on the global region. - *

- * 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. - *

- */ -public interface IGlobalScheduler { - /** - * Schedules a task to be executed on the global region on the next tick. - * @param task The task to execute - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task run(@NotNull Consumer task) { - return run(t -> { - task.accept(t); - return null; - }); - } - - /** - * Schedules a task to be executed on the global region on the next tick. - * @param task The task to execute - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task run(@NotNull Runnable task) { - return run(t -> { - task.run(); - return null; - }); - } - - /** - * Schedules a task to be executed on the global region on the next tick. - * @param task The task to execute - * @return The {@link Completable} that represents the scheduled task. - */ - default @NotNull Completable run(@NotNull Supplier task) { - return run(t -> { - return task.get(); - }); - } - - /** - * Schedules a task to be executed on the global region on the next tick. - * @param task The task to execute - * @return The {@link Completable} that represents the scheduled task. - */ - default @NotNull Completable run(@NotNull Function, R> task) { - return runDelayed(task, 1); - } - - /** - * Schedules a task to be executed on the global region after the specified delay in ticks. - * @param task The task to execute - * @param delayTicks The delay, in ticks. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runDelayed(@NotNull Consumer task, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return runDelayed(t -> { - task.accept(t); - return null; - }, delayTicks); - } - - /** - * Schedules a task to be executed on the global region after the specified delay in ticks. - * @param task The task to execute - * @param delayTicks The delay, in ticks. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runDelayed(@NotNull Runnable task, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return runDelayed(t -> { - task.run(); - return null; - }, delayTicks); - } - - /** - * Schedules a task to be executed on the global region after the specified delay in ticks. - * @param task The task to execute - * @param delayTicks The delay, in ticks. - * @return The {@link Completable} that represents the scheduled task. - */ - default @NotNull Completable runDelayed(@NotNull Supplier task, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return runDelayed(t -> { - return task.get(); - }, delayTicks); - } - - /** - * Schedules a task to be executed on the global region after the specified delay in ticks. - * @param task The task to execute - * @param delayTicks The delay, in ticks. - * @return The {@link Completable} that represents the scheduled task. - */ - @NotNull Completable runDelayed(@NotNull Function, R> task, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks); - - /** - * Schedules a repeating task to be executed on the global region after the initial delay with the - * specified period. - * @param task The task to execute - * @param initialDelayTicks The initial delay, in ticks. - * @param periodTicks The period, in ticks. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runAtFixedRate(@NotNull Runnable task, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, - @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { - return runAtFixedRate(t -> task.run(), initialDelayTicks, periodTicks); - } - - /** - * Schedules a repeating task to be executed on the global region after the initial delay with the - * specified period. - * @param task The task to execute - * @param initialDelayTicks The initial delay, in ticks. - * @param periodTicks The period, in ticks. - * @return The {@link Task} that represents the scheduled task. - */ - @NotNull Task runAtFixedRate(@NotNull Consumer task, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, - @Range(from = 1, to = Long.MAX_VALUE) long periodTicks); -} diff --git a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java b/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java deleted file mode 100644 index b57a07038..000000000 --- a/scheduler/src/main/java/com/volmit/iris/util/scheduling/split/IRegionScheduler.java +++ /dev/null @@ -1,328 +0,0 @@ -package com.volmit.iris.util.scheduling.split; - -import com.volmit.iris.util.scheduling.Task; -import com.volmit.iris.util.scheduling.Task.Completable; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.entity.Entity; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Range; - -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * The region task scheduler can be used to schedule tasks by location to be executed on the region which owns the location. - *

- * Note: It is entirely inappropriate to use the region scheduler to schedule tasks for entities. - * If you wish to schedule tasks to perform actions on entities, you should be using {@link Entity#getScheduler()} - * as the entity scheduler will "follow" an entity if it is teleported, whereas the region task scheduler - * will not. - *

- */ -public interface IRegionScheduler { - /** - * Schedules a task to be executed on the region which owns the location on the next tick. - * - * @param world The world of the region that owns the task - * @param chunkX The chunk X coordinate of the region that owns the task - * @param chunkZ The chunk Z coordinate of the region that owns the task - * @param task The task to execute - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task run(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Consumer task) { - return run(world, chunkX, chunkZ, t -> { - task.accept(t); - return null; - }); - } - - /** - * Schedules a task to be executed on the region which owns the location on the next tick. - * - * @param world The world of the region that owns the task - * @param chunkX The chunk X coordinate of the region that owns the task - * @param chunkZ The chunk Z coordinate of the region that owns the task - * @param task The task to execute - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task run(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Runnable task) { - return run(world, chunkX, chunkZ, t -> { - task.run(); - return null; - }); - } - - /** - * Schedules a task to be executed on the region which owns the location on the next tick. - * - * @param world The world of the region that owns the task - * @param chunkX The chunk X coordinate of the region that owns the task - * @param chunkZ The chunk Z coordinate of the region that owns the task - * @param task The task to execute - * @return The {@link Completable} that represents the scheduled task. - */ - default @NotNull Completable run(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Supplier task) { - return run(world, chunkX, chunkZ, t -> { - return task.get(); - }); - } - - /** - * Schedules a task to be executed on the region which owns the location on the next tick. - * - * @param world The world of the region that owns the task - * @param chunkX The chunk X coordinate of the region that owns the task - * @param chunkZ The chunk Z coordinate of the region that owns the task - * @param task The task to execute - * @return The {@link Completable} that represents the scheduled task. - */ - default @NotNull Completable run(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Function, R> task) { - return runDelayed(world, chunkX, chunkZ, task, 1); - } - - /** - * Schedules a task to be executed on the region which owns the location on the next tick. - * - * @param location The location at which the region executing should own - * @param task The task to execute - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task run(@NotNull Location location, - @NotNull Consumer task) { - return run(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task); - } - - /** - * Schedules a task to be executed on the region which owns the location on the next tick. - * - * @param location The location at which the region executing should own - * @param task The task to execute - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task run(@NotNull Location location, - @NotNull Runnable task) { - return run(location, t -> { - task.run(); - }); - } - - /** - * Schedules a task to be executed on the region which owns the location on the next tick. - * - * @param location The location at which the region executing should own - * @param task The task to execute - * @return The {@link Completable} that represents the scheduled task. - */ - default @NotNull Completable run(@NotNull Location location, - @NotNull Supplier task) { - return run(location, t -> { - return task.get(); - }); - } - - /** - * Schedules a task to be executed on the region which owns the location on the next tick. - * - * @param location The location at which the region executing should own - * @param task The task to execute - * @return The {@link Completable} that represents the scheduled task. - */ - default @NotNull Completable run(@NotNull Location location, - @NotNull Function, R> task) { - return run(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task); - } - - /** - * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. - * - * @param world The world of the region that owns the task - * @param chunkX The chunk X coordinate of the region that owns the task - * @param chunkZ The chunk Z coordinate of the region that owns the task - * @param task The task to execute - * @param delayTicks The delay, in ticks. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runDelayed(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Consumer task, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return runDelayed(world, chunkX, chunkZ, t -> { - task.accept(t); - return null; - }, delayTicks); - } - - /** - * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. - * - * @param world The world of the region that owns the task - * @param chunkX The chunk X coordinate of the region that owns the task - * @param chunkZ The chunk Z coordinate of the region that owns the task - * @param task The task to execute - * @param delayTicks The delay, in ticks. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runDelayed(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Runnable task, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return runDelayed(world, chunkX, chunkZ, t -> { - task.run(); - return null; - }, delayTicks); - } - - /** - * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. - * - * @param world The world of the region that owns the task - * @param chunkX The chunk X coordinate of the region that owns the task - * @param chunkZ The chunk Z coordinate of the region that owns the task - * @param task The task to execute - * @param delayTicks The delay, in ticks. - * @return The {@link Completable} that represents the scheduled task. - */ - default @NotNull Completable runDelayed(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Supplier task, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return runDelayed(world, chunkX, chunkZ, t -> { - return task.get(); - }, delayTicks); - } - - /** - * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. - * - * @param world The world of the region that owns the task - * @param chunkX The chunk X coordinate of the region that owns the task - * @param chunkZ The chunk Z coordinate of the region that owns the task - * @param task The task to execute - * @param delayTicks The delay, in ticks. - * @return The {@link Completable} that represents the scheduled task. - */ - @NotNull Completable runDelayed(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Function, R> task, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks); - - /** - * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. - * - * @param location The location at which the region executing should own - * @param task The task to execute - * @param delayTicks The delay, in ticks. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runDelayed(@NotNull Location location, - @NotNull Consumer task, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return runDelayed(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, delayTicks); - } - - /** - * Schedules a task to be executed on the region which owns the location after the specified delay in ticks. - * - * @param location The location at which the region executing should own - * @param task The task to execute - * @param delayTicks The delay, in ticks. - * @return The {@link Completable} that represents the scheduled task. - */ - default @NotNull Completable runDelayed(@NotNull Location location, - @NotNull Function, R> task, - @Range(from = 1, to = Long.MAX_VALUE) long delayTicks) { - return runDelayed(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, delayTicks); - } - - /** - * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the - * specified period. - * - * @param world The world of the region that owns the task - * @param chunkX The chunk X coordinate of the region that owns the task - * @param chunkZ The chunk Z coordinate of the region that owns the task - * @param task The task to execute - * @param initialDelayTicks The initial delay, in ticks. - * @param periodTicks The period, in ticks. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runAtFixedRate(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Runnable task, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, - @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { - return runAtFixedRate(world, chunkX, chunkZ, t -> task.run(), initialDelayTicks, periodTicks); - } - - /** - * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the - * specified period. - * - * @param world The world of the region that owns the task - * @param chunkX The chunk X coordinate of the region that owns the task - * @param chunkZ The chunk Z coordinate of the region that owns the task - * @param task The task to execute - * @param initialDelayTicks The initial delay, in ticks. - * @param periodTicks The period, in ticks. - * @return The {@link Task} that represents the scheduled task. - */ - @NotNull Task runAtFixedRate(@NotNull World world, - int chunkX, - int chunkZ, - @NotNull Consumer task, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, - @Range(from = 1, to = Long.MAX_VALUE) long periodTicks); - - /** - * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the - * specified period. - * - * @param location The location at which the region executing should own - * @param task The task to execute - * @param initialDelayTicks The initial delay, in ticks. - * @param periodTicks The period, in ticks. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runAtFixedRate(@NotNull Location location, - @NotNull Runnable task, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, - @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { - return runAtFixedRate(location, t -> task.run(), initialDelayTicks, periodTicks); - } - - /** - * Schedules a repeating task to be executed on the region which owns the location after the initial delay with the - * specified period. - * - * @param location The location at which the region executing should own - * @param task The task to execute - * @param initialDelayTicks The initial delay, in ticks. - * @param periodTicks The period, in ticks. - * @return The {@link Task} that represents the scheduled task. - */ - default @NotNull Task runAtFixedRate(@NotNull Location location, - @NotNull Consumer task, - @Range(from = 1, to = Long.MAX_VALUE) long initialDelayTicks, - @Range(from = 1, to = Long.MAX_VALUE) long periodTicks) { - return runAtFixedRate(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, task, initialDelayTicks, periodTicks); - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 89f8e7dc4..1612b63d0 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -38,5 +38,4 @@ include( ":nms:v1_20_R3", ":nms:v1_20_R2", ":nms:v1_20_R1", -) -include("scheduler") \ No newline at end of file +) \ No newline at end of file From fa3e35f7022aa2f4ed42e1d50199ef3f4b7cd644 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 19 Jun 2025 18:28:22 +0200 Subject: [PATCH 11/26] fix pregen save chunk failing --- .../methods/AsyncPregenMethod.java | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java index 6639a2f09..988b16ee6 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/methods/AsyncPregenMethod.java @@ -23,16 +23,17 @@ import com.volmit.iris.core.pregenerator.PregenListener; import com.volmit.iris.core.pregenerator.PregeneratorMethod; import com.volmit.iris.core.tools.IrisToolbelt; +import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.M; import com.volmit.iris.util.parallel.MultiBurst; -import com.volmit.iris.util.scheduling.J; import org.bukkit.Chunk; import org.bukkit.World; import java.lang.reflect.InvocationTargetException; import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; @@ -58,26 +59,28 @@ public AsyncPregenMethod(World world) { private void unloadAndSaveAllChunks() { try { - J.sfut(() -> { - if (world == null) { - Iris.warn("World was null somehow..."); - return; - } + if (world == null) { + Iris.warn("World was null somehow..."); + return; + } - long minTime = M.ms() - 10_000; - lastUse.entrySet().removeIf(i -> { - final Chunk chunk = i.getKey(); - final Long lastUseTime = i.getValue(); - if (!chunk.isLoaded() || lastUseTime == null) - return true; - if (lastUseTime < minTime) { - chunk.unload(); - return true; - } - return false; - }); - world.save(); - }).get(); + long minTime = M.ms() - 10_000; + KList> futures = new KList<>(); + lastUse.entrySet().removeIf(i -> { + final Chunk chunk = i.getKey(); + final Long lastUseTime = i.getValue(); + if (!chunk.isLoaded() || lastUseTime == null) + return true; + if (lastUseTime < minTime) { + futures.add(Iris.platform.getRegionScheduler() + .run(chunk.getWorld(), chunk.getX(), chunk.getZ(), () -> chunk.unload()) + .getResult()); + return true; + } + return false; + }); + futures.add(Iris.platform.getRegionScheduler().run(world, 0, 0, world::save).getResult()); + CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).join(); } catch (Throwable e) { e.printStackTrace(); } From c8eab2242740fc558fb360810626e825b2568da7 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 19 Jun 2025 18:28:46 +0200 Subject: [PATCH 12/26] fix a few sync teleports --- core/src/main/java/com/volmit/iris/Iris.java | 2 +- .../java/com/volmit/iris/core/commands/CommandStudio.java | 5 +++-- core/src/main/java/com/volmit/iris/core/gui/VisionGUI.java | 2 +- .../main/java/com/volmit/iris/core/tools/IrisCreator.java | 4 +--- .../main/java/com/volmit/iris/core/tools/IrisToolbelt.java | 4 ++-- .../main/java/com/volmit/iris/engine/IrisWorldManager.java | 4 ++-- 6 files changed, 10 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index 1cb41cf3f..e9404c544 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -551,7 +551,7 @@ private void autoStartStudio() { J.s(() -> { for (Player i : getServer().getOnlinePlayers()) { i.setGameMode(GameMode.SPECTATOR); - i.teleport(new Location(w, 0, 200, 0)); + platform.teleportAsync(i, new Location(w, 0, 200, 0)); } }); }); diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java index 9c53c9edf..7868228d9 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java @@ -637,8 +637,9 @@ public void tpstudio() { } sender().sendMessage(C.GREEN + "Sending you to the studio world!"); - player().teleport(Iris.service(StudioSVC.class).getActiveProject().getActiveProvider().getTarget().getWorld().spawnLocation()); - player().setGameMode(GameMode.SPECTATOR); + Player player = player(); + Iris.platform.teleportAsync(player, Iris.service(StudioSVC.class).getActiveProject().getActiveProvider().getTarget().getWorld().spawnLocation()); + Iris.platform.getEntityScheduler(player).run(() -> player.setGameMode(GameMode.SPECTATOR), null); } @Decree(description = "Update your dimension projects VSCode workspace") diff --git a/core/src/main/java/com/volmit/iris/core/gui/VisionGUI.java b/core/src/main/java/com/volmit/iris/core/gui/VisionGUI.java index 24cc09f73..6111b59d8 100644 --- a/core/src/main/java/com/volmit/iris/core/gui/VisionGUI.java +++ b/core/src/main/java/com/volmit/iris/core/gui/VisionGUI.java @@ -755,7 +755,7 @@ private void teleport() { int xx = (int) getWorldX(hx); int zz = (int) getWorldZ(hz); int h = engine.getComplex().getRoundedHeighteightStream().get(xx, zz); - player.teleport(new Location(player.getWorld(), xx, h, zz)); + Iris.platform.teleportAsync(player, new Location(player.getWorld(), xx, h, zz)); notify("Teleporting to " + xx + ", " + h + ", " + zz); } else { notify("No player in world, can't teleport."); diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java index ddcd5ff85..6c7966316 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java @@ -184,9 +184,7 @@ public World create() throws IrisException { done.set(true); if (sender.isPlayer() && !benchmark) { - J.s(() -> { - sender.player().teleport(new Location(world.get(), 0, world.get().getHighestBlockYAt(0, 0), 0)); - }); + J.s(() -> Iris.platform.teleportAsync(sender.player(), new Location(world.get(), 0, world.get().getHighestBlockYAt(0, 0), 0))); } if (studio || benchmark) { diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java b/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java index 043b8eab6..314deb1ba 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisToolbelt.java @@ -195,7 +195,7 @@ public static boolean evacuate(World world) { if (!i.getName().equals(world.getName())) { for (Player j : world.getPlayers()) { new VolmitSender(j, Iris.instance.getTag()).sendMessage("You have been evacuated from this world."); - j.teleport(i.getSpawnLocation()); + Iris.platform.teleportAsync(j, i.getSpawnLocation()); } return true; @@ -217,7 +217,7 @@ public static boolean evacuate(World world, String m) { if (!i.getName().equals(world.getName())) { for (Player j : world.getPlayers()) { new VolmitSender(j, Iris.instance.getTag()).sendMessage("You have been evacuated from this world. " + m); - j.teleport(i.getSpawnLocation()); + Iris.platform.teleportAsync(j, i.getSpawnLocation()); } return true; } diff --git a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index 38158ae4c..70d98045d 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -476,8 +476,8 @@ public void teleportAsync(PlayerTeleportEvent e) { e.setCancelled(true); warmupAreaAsync(e.getPlayer(), e.getTo(), () -> J.s(() -> { ignoreTP.set(true); - e.getPlayer().teleport(e.getTo(), e.getCause()); - ignoreTP.set(false); + Iris.platform.teleportAsync(e.getPlayer(), e.getTo(), e.getCause()) + .thenRun(() -> ignoreTP.set(false)); })); } } From 42a26a1de26eecf30ac0a353f5159c6285cfb373 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 19 Jun 2025 19:43:53 +0200 Subject: [PATCH 13/26] fix spawning empty particles and improve message for invalid tile states --- build.gradle.kts | 1 + .../main/java/com/volmit/iris/engine/framework/Engine.java | 6 +++--- .../main/java/com/volmit/iris/engine/object/IrisEntity.java | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4697b9574..776f14ee9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -123,6 +123,7 @@ nmsBindings.forEach { key, value -> systemProperty("disable.watchdog", "") systemProperty("net.kyori.ansi.colorLevel", color) systemProperty("com.mojang.eula.agree", true) + systemProperty("iris.suppressReporting", !errorReporting) } } diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java index aeae15fc9..20b7f31f1 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -295,9 +295,9 @@ default void updateChunk(Chunk c) { var region = Iris.platform.getRegionScheduler(); chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> region.run(c.getWorld(), c.getX(), c.getZ(), () -> { mantle.iterateChunk(c.getX(), c.getZ(), TileWrapper.class, (x, y, z, v) -> { - int betterY = y + getWorld().minHeight(); - if (!TileData.setTileState(c.getBlock(x, betterY, z), v.getData())) - Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", x, betterY, z, c.getBlock(x, betterY, z).getBlockData().getMaterial().getKey(), v.getData().getMaterial().name()); + Block block = c.getBlock(x, y + getWorld().minHeight(), z); + if (!TileData.setTileState(block, v.getData())) + Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", block.getX(), block.getY(), block.getZ(), block.getType().getKey(), v.getData().getMaterial().getKey()); }); }))); chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> region.run(c.getWorld(), c.getX(), c.getZ(), () -> { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java index d76adabae..d39f1d270 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IrisEntity.java @@ -359,8 +359,8 @@ public void fillInventory(Inventory inventory, Random random, LootContext contex t.incrementAndGet(); if (e.getLocation().getBlock().getType().isSolid() || living.getEyeLocation().getBlock().getType().isSolid()) { Iris.platform.teleportAsync(e, at.add(0, 0.1, 0)); - ItemStack itemCrackData = new ItemStack(living.getEyeLocation().clone().subtract(0, 2, 0).getBlock().getBlockData().getMaterial()); - e.getWorld().spawnParticle(ITEM, living.getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, itemCrackData); + Material material = living.getEyeLocation().subtract(0, 2, 0).getBlock().getType(); + if (!material.isAir()) e.getWorld().spawnParticle(ITEM, living.getEyeLocation(), 6, 0.2, 0.4, 0.2, 0.06f, new ItemStack(material)); if (M.r(0.2)) { e.getWorld().playSound(e.getLocation(), Sound.BLOCK_CHORUS_FLOWER_GROW, 0.8f, 0.1f); } From b440d0257d02e30f7a252e9eff4926501f91f7e1 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Thu, 19 Jun 2025 19:50:08 +0200 Subject: [PATCH 14/26] fix iris what commands --- .../iris/core/commands/CommandWhat.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java b/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java index 48d8c726e..c2c8015da 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java @@ -74,22 +74,22 @@ public void biome() { } catch (Throwable e) { Iris.reportError(e); sender().sendMessage("Non-Iris Biome: " + player().getLocation().getBlock().getBiome().name()); - - if (player().getLocation().getBlock().getBiome().equals(Biome.CUSTOM)) { - try { - sender().sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(player().getLocation()) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(player().getLocation())) + ")"); - } catch (Throwable ee) { - Iris.reportError(ee); - } - } + var loc = player().getLocation(); + var sender = sender(); + Iris.platform.getRegionScheduler().run(loc, () -> { + var biome = loc.getBlock().getBiome(); + if (biome != Biome.CUSTOM && biome.getKey().getNamespace().equals("minecraft")) + return; + sender.sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(loc) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(loc)) + ")"); + }); } } @Decree(description = "What region am i in?", origin = DecreeOrigin.PLAYER) public void region() { try { - Chunk chunk = world().getChunkAt(player().getLocation().getBlockZ() / 16, player().getLocation().getBlockZ() / 16); - IrisRegion r = engine().getRegion(chunk); + var loc = player().getLocation(); + IrisRegion r = engine().getRegion(loc); sender().sendMessage("IRegion: " + r.getLoadKey() + " (" + r.getName() + ")"); } catch (Throwable e) { From fd3971018b959b942bee68462570b52605dafcfc Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Mon, 23 Jun 2025 16:16:25 +0200 Subject: [PATCH 15/26] update platform utils --- build.gradle.kts | 2 +- core/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 776f14ee9..b236ae7a3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -90,7 +90,7 @@ nmsBindings.forEach { key, value -> dependencies { compileOnly(project(":core")) - compileOnly("com.github.CrazyDev05:PlatformUtils:4bac4f6e75") { + compileOnly("com.github.CrazyDev05:PlatformUtils:e396f93d56") { isTransitive = false } compileOnly("org.jetbrains:annotations:26.0.2") diff --git a/core/build.gradle.kts b/core/build.gradle.kts index a17c89a46..30b57e47a 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -69,7 +69,7 @@ dependencies { implementation("net.kyori:adventure-platform-bukkit:4.3.4") implementation("net.kyori:adventure-api:4.17.0") implementation("org.bstats:bstats-bukkit:3.1.0") - implementation("com.github.CrazyDev05:PlatformUtils:4bac4f6e75") { + implementation("com.github.CrazyDev05:PlatformUtils:e396f93d56") { isTransitive = false } From fcbbd2135b33a4d14e8bb5f5b21bcdb6085be6c4 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 19 Jul 2025 22:53:06 +0200 Subject: [PATCH 16/26] apply folia modification to 1.21.7 nms --- .../main/java/com/volmit/iris/core/nms/v1_21_R5/NMSBinding.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/NMSBinding.java b/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/NMSBinding.java index 425dd25a7..ea97a76d5 100644 --- a/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/NMSBinding.java +++ b/nms/v1_21_R5/src/main/java/com/volmit/iris/core/nms/v1_21_R5/NMSBinding.java @@ -210,7 +210,7 @@ public void deserializeTile(KMap map, Location pos) { net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) convertToTag(map, 0, 64); var level = ((CraftWorld) pos.getWorld()).getHandle(); var blockPos = new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); - J.s(() -> merge(level, blockPos, tag)); + Iris.platform.getRegionScheduler().run(pos, () -> merge(level, blockPos, tag)); } private void merge(ServerLevel level, BlockPos blockPos, net.minecraft.nbt.CompoundTag tag) { From 49d2392c80b4e709ec0aa3de96051c0e9312da12 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 19 Jul 2025 22:55:25 +0200 Subject: [PATCH 17/26] use platform utils for regen --- .../com/volmit/iris/engine/platform/BukkitChunkGenerator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index 159962a89..9ad0eba8a 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -207,8 +207,9 @@ public void injectChunkReplacement(World world, int x, int z, Executor syncExecu this.world.bind(world); getEngine().generate(x << 4, z << 4, tc, false); - Chunk c = PaperLib.getChunkAtAsync(world, x, z) + Chunk c = Iris.platform.getChunkAtAsync(world, x, z) .thenApply(d -> { + if (d == null) throw new IllegalStateException("Chunk is null!"); d.addPluginChunkTicket(Iris.instance); for (Entity ee : d.getEntities()) { From 68a214edb531447efd8e1d8f07f8bc839c516d2f Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 19 Jul 2025 23:02:49 +0200 Subject: [PATCH 18/26] move platform utils to the version catalog --- build.gradle.kts | 2 +- core/build.gradle.kts | 2 +- gradle/libs.versions.toml | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 90273558a..6b52129b2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -96,7 +96,7 @@ nmsBindings.forEach { key, value -> compileOnly(project(":core")) compileOnly(rootProject.libs.annotations) compileOnly(rootProject.libs.byteBuddy.core) - compileOnly("com.github.CrazyDev05:PlatformUtils:e396f93d56") { + compileOnly(rootProject.libs.platformUtils) { isTransitive = false } } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index b4d85ff18..177314149 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -66,7 +66,7 @@ dependencies { // Shaded implementation(slimjar()) - implementation("com.github.CrazyDev05:PlatformUtils:e396f93d56") { + implementation(rootProject.libs.platformUtils) { isTransitive = false } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f697c836e..3a930d5d1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,7 @@ spigot = "1.20.1-R0.1-SNAPSHOT" # https://hub.spigotmc.org/nexus/repository/snap log4j = "2.19.0" # https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-api adventure-api = "4.23.0" # https://github.com/KyoriPowered/adventure adventure-platform = "4.4.0" # https://github.com/KyoriPowered/adventure-platform +platform-utils = "e396f93d56" # https://github.com/CrazyDev05/PlatformUtils annotations = "26.0.2" # https://central.sonatype.com/artifact/org.jetbrains/annotations paralithic = "0.8.1" # https://github.com/PolyhedralDev/Paralithic/ @@ -56,6 +57,7 @@ spigot = { module = "org.spigotmc:spigot-api", version.ref = "spigot" } log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j" } log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } annotations = { module = "org.jetbrains:annotations", version.ref = "annotations" } +platformUtils = { module = "com.github.CrazyDev05:PlatformUtils", version.ref = "platform-utils" } # Dynamically Loaded adventure-api = { module = "net.kyori:adventure-api", version.ref = "adventure-api" } From bddc62f385b57d3a5d3c5b206686f9206206b655 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 20 Jul 2025 00:50:11 +0200 Subject: [PATCH 19/26] fix object saving --- .../com/volmit/iris/core/service/WandSVC.java | 79 +----------- .../com/volmit/iris/util/data/Cuboid.java | 8 +- .../iris/util/scheduling/jobs/ScanJob.java | 118 ++++++++++++++++++ 3 files changed, 127 insertions(+), 78 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/util/scheduling/jobs/ScanJob.java diff --git a/core/src/main/java/com/volmit/iris/core/service/WandSVC.java b/core/src/main/java/com/volmit/iris/core/service/WandSVC.java index 8d984ba91..ffe84e900 100644 --- a/core/src/main/java/com/volmit/iris/core/service/WandSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/WandSVC.java @@ -35,6 +35,7 @@ import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.SR; import com.volmit.iris.util.scheduling.jobs.Job; +import com.volmit.iris.util.scheduling.jobs.ScanJob; import org.bukkit.*; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; @@ -86,80 +87,10 @@ public static IrisObject createSchematic(Player p, boolean legacy) { Cuboid c = new Cuboid(f[0], f[1]); IrisObject s = new IrisObject(c.getSizeX(), c.getSizeY(), c.getSizeZ()); - var it = c.chunkedIterator(); - - int total = c.getSizeX() * c.getSizeY() * c.getSizeZ(); - var latch = new CountDownLatch(1); - new Job() { - private int i; - private Chunk chunk; - - @Override - public String getName() { - return "Scanning Selection"; - } - - @Override - public void execute() { - new SR() { - @Override - public void run() { - var time = M.ms() + MS_PER_TICK; - while (time > M.ms()) { - if (!it.hasNext()) { - if (chunk != null) { - chunk.removePluginChunkTicket(Iris.instance); - chunk = null; - } - - cancel(); - latch.countDown(); - return; - } - - try { - var b = it.next(); - var bChunk = b.getChunk(); - if (chunk == null) { - chunk = bChunk; - chunk.addPluginChunkTicket(Iris.instance); - } else if (chunk != bChunk) { - chunk.removePluginChunkTicket(Iris.instance); - chunk = bChunk; - } - - if (b.getType().equals(Material.AIR)) - continue; - - BlockVector bv = b.getLocation().subtract(c.getLowerNE().toVector()).toVector().toBlockVector(); - s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b, legacy); - } finally { - i++; - } - } - } - }; - try { - latch.await(); - } catch (InterruptedException ignored) {} - } - - @Override - public void completeWork() {} - - @Override - public int getTotalWork() { - return total; - } - - @Override - public int getWorkCompleted() { - return i; - } - }.execute(new VolmitSender(p), true, () -> {}); - try { - latch.await(); - } catch (InterruptedException ignored) {} + new ScanJob("Scanning Selection", c, MS_PER_TICK, (bv, b) -> { + if (b.getType().equals(Material.AIR)) return; + s.setUnsigned(bv.getBlockX(), bv.getBlockY(), bv.getBlockZ(), b, legacy); + }).execute(new VolmitSender(p), true, () -> {}); return s; } catch (Throwable e) { diff --git a/core/src/main/java/com/volmit/iris/util/data/Cuboid.java b/core/src/main/java/com/volmit/iris/util/data/Cuboid.java index ccd837eb2..df377fec6 100644 --- a/core/src/main/java/com/volmit/iris/util/data/Cuboid.java +++ b/core/src/main/java/com/volmit/iris/util/data/Cuboid.java @@ -652,7 +652,7 @@ public Iterator iterator() { return new CuboidIterator(getWorld(), x1, y1, z1, x2, y2, z2); } - public Iterator chunkedIterator() { + public Iterator chunkedIterator() { return new ChunkedCuboidIterator(getWorld(), x1, y1, z1, x2, y2, z2); } @@ -751,7 +751,7 @@ public void remove() { } } - public static class ChunkedCuboidIterator implements Iterator { + public static class ChunkedCuboidIterator implements Iterator { private final World w; private final int minRX, minY, minRZ, maxRX, maxY, maxRZ; private final int minCX, minCZ, maxCX, maxCZ; @@ -795,7 +795,7 @@ public boolean hasNextChunk() { } @Override - public Block next() { + public Location next() { if (chunk == null) { chunk = new Position2(cX, cZ); if (++cX > maxCX) { @@ -809,7 +809,7 @@ public Block next() { rZ = chunk.getZ() == minCZ ? minRZ : 0; } - var b = w.getBlockAt((chunk.getX() << 4) + rX, y, (chunk.getZ() << 4) + rZ); + var b = new Location(w, (chunk.getX() << 4) + rX, y, (chunk.getZ() << 4) + rZ); if (++y > maxY) { y = minY; if (++rX > mX) { diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/jobs/ScanJob.java b/core/src/main/java/com/volmit/iris/util/scheduling/jobs/ScanJob.java new file mode 100644 index 000000000..42036fe7a --- /dev/null +++ b/core/src/main/java/com/volmit/iris/util/scheduling/jobs/ScanJob.java @@ -0,0 +1,118 @@ +package com.volmit.iris.util.scheduling.jobs; + +import com.volmit.iris.Iris; +import com.volmit.iris.util.data.Cuboid; +import com.volmit.iris.util.math.M; +import com.volmit.iris.util.plugin.VolmitSender; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.util.BlockVector; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; + +public class ScanJob implements Job { + private final CountDownLatch latch = new CountDownLatch(1); + private final AtomicInteger completed = new AtomicInteger(); + private final String name; + private final Cuboid cuboid; + private final BiConsumer action; + private final int msPerTick, total; + private volatile Chunk chunk; + + public ScanJob(String name, + Cuboid cuboid, + int msPerTick, + BiConsumer action + ) { + this.name = name; + this.cuboid = cuboid; + this.action = action; + this.msPerTick = msPerTick; + total = cuboid.volume(); + } + + @Override + public String getName() { + return name; + } + + @Override + public void execute() { + Thread.ofVirtual() + .name("Iris Job - " + name) + .start(this::executeTask); + await(); + } + + public void await() { + try { + latch.await(); + } catch (InterruptedException ignored) {} + } + + private void executeTask() { + var it = cuboid.chunkedIterator(); + var region = Iris.platform.getRegionScheduler(); + + var tmp = it.next(); + while (tmp != null) { + Location finalTmp = tmp; + tmp = region.run(tmp, () -> { + var time = M.ms() + msPerTick; + var next = finalTmp; + + while (time > M.ms()) { + if (!consume(next)) break; + completed.incrementAndGet(); + next = it.hasNext() ? it.next() : null; + } + + return next; + }).getResult().join(); + } + + latch.countDown(); + } + + private boolean consume(Location next) { + if (!Iris.platform.isOwnedByCurrentRegion(next)) + return true; + + final Chunk nextChunk = next.getChunk(); + if (chunk == null) { + chunk.removePluginChunkTicket(Iris.instance); + chunk = next.getChunk(); + } else if (chunk != nextChunk) { + chunk.removePluginChunkTicket(Iris.instance); + chunk = nextChunk; + chunk.addPluginChunkTicket(Iris.instance); + } + + final Block block = next.getBlock(); + action.accept(next.subtract(cuboid.getLowerNE().toVector()).toVector().toBlockVector(), block); + return false; + } + + @Override + public void completeWork() { + } + + @Override + public int getTotalWork() { + return total; + } + + @Override + public int getWorkCompleted() { + return completed.get(); + } + + @Override + public void execute(VolmitSender sender, boolean silentMsg, Runnable whenComplete) { + Job.super.execute(sender, silentMsg, whenComplete); + await(); + } +} From f7ac827692ba3c34c6edf87d617a05a95eed7b1e Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Fri, 25 Jul 2025 22:34:05 +0200 Subject: [PATCH 20/26] don't relocate platform utils for now --- core/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 177314149..a775b5c1b 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -150,7 +150,6 @@ tasks { mergeServiceFiles() //minimize() relocate("io.github.slimjar", "$lib.slimjar") - relocate("de.crazydev22.platformutils", "$lib.platform") } } From d5ec6a18a42ae44a683b2258ebc60c8a1ac36029 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 26 Jul 2025 12:31:24 +0200 Subject: [PATCH 21/26] fix loot not being applied --- .../java/com/volmit/iris/engine/framework/Engine.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java index cbdefe4e1..38fc6e824 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -540,8 +540,9 @@ default void addItems(boolean debug, Inventory inv, RNG rng, KList> 4, z >> 4, true, false).thenAccept((c) -> { + if (world != null) { + final int cX = x >> 4, cZ = z >> 4; + Iris.platform.getChunkAtAsync(world, cX, cZ, true, false).thenAccept((c) -> { Runnable r = () -> { for (ItemStack i : items) { inv.addItem(i); @@ -550,10 +551,10 @@ default void addItems(boolean debug, Inventory inv, RNG rng, KList Date: Sat, 2 Aug 2025 22:23:05 +0200 Subject: [PATCH 22/26] add link for Worlds to bring back world creation on folia --- build.gradle.kts | 1 + core/build.gradle.kts | 1 + core/src/main/java/com/volmit/iris/Iris.java | 9 ++- .../iris/core/link/FoliaWorldsLink.java | 68 +++++++++++++++++++ .../com/volmit/iris/core/nms/INMSBinding.java | 11 +++ .../volmit/iris/core/tools/IrisCreator.java | 64 +++++++++-------- gradle/libs.versions.toml | 2 + 7 files changed, 121 insertions(+), 35 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/core/link/FoliaWorldsLink.java diff --git a/build.gradle.kts b/build.gradle.kts index 6b52129b2..3c275b9ca 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -215,6 +215,7 @@ allprojects { maven("https://mvn.lumine.io/repository/maven-public/") // mythic maven("https://nexus.phoenixdevt.fr/repository/maven-public/") //MMOItems maven("https://repo.onarandombox.com/content/groups/public/") //Multiverse Core + maven("https://repo.thenextlvl.net/releases") //Worlds } dependencies { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index a91d4c72f..a587f6c2a 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -65,6 +65,7 @@ dependencies { isTransitive = false } compileOnly(libs.multiverseCore) + compileOnly(libs.worlds) // Shaded implementation(slimjarHelper("spigot")) diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index dd4b0e51d..e9455150a 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -490,8 +490,13 @@ public void checkForBukkitWorlds(Predicate filter) { WorldCreator c = new WorldCreator(s) .generator(gen) .environment(dim.getEnvironment()); - INMS.get().createWorld(c); - Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!"); + INMS.get().createWorldAsync(c) + .thenAccept(w -> Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!")) + .exceptionally(e -> { + Iris.error("Failed to load world " + s + "!"); + e.printStackTrace(); + return null; + }); } catch (Throwable e) { Iris.error("Failed to load world " + s + "!"); e.printStackTrace(); diff --git a/core/src/main/java/com/volmit/iris/core/link/FoliaWorldsLink.java b/core/src/main/java/com/volmit/iris/core/link/FoliaWorldsLink.java new file mode 100644 index 000000000..f21ac8a78 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/link/FoliaWorldsLink.java @@ -0,0 +1,68 @@ +package com.volmit.iris.core.link; + +import lombok.NonNull; +import net.thenextlvl.worlds.api.WorldsProvider; +import net.thenextlvl.worlds.api.generator.GeneratorType; +import net.thenextlvl.worlds.api.generator.LevelStem; +import org.bukkit.Bukkit; +import org.bukkit.Server; +import org.bukkit.World; +import org.bukkit.WorldCreator; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.concurrent.CompletableFuture; + +public class FoliaWorldsLink { + private static FoliaWorldsLink instance; + private final Object provider; + + private FoliaWorldsLink(Object provider) { + this.provider = provider; + } + + public static FoliaWorldsLink get() { + if(instance == null) { + synchronized (FoliaWorldsLink.class) { + try { + Server.class.getDeclaredMethod("isGlobalTickThread"); + instance = new FoliaWorldsLink(Bukkit.getServicesManager().load(WorldsProvider.class)); + } catch (Throwable e) { + instance = new FoliaWorldsLink(null); + } + } + } + + return instance; + } + + public boolean isActive() { + return provider != null; + } + + @Nullable + public CompletableFuture createWorld(@NonNull WorldCreator creator) { + if (provider == null) return null; + return ((WorldsProvider) provider) + .levelBuilder(new File(Bukkit.getWorldContainer(), creator.name()).toPath()) + .name(creator.name()) + .seed(creator.seed()) + .levelStem(switch (creator.environment()) { + case CUSTOM, NORMAL -> LevelStem.OVERWORLD; + case NETHER -> LevelStem.NETHER; + case THE_END -> LevelStem.END; + }) + .chunkGenerator(creator.generator()) + .biomeProvider(creator.biomeProvider()) + .generatorType(switch (creator.type()) { + case NORMAL -> GeneratorType.NORMAL; + case FLAT -> GeneratorType.FLAT; + case LARGE_BIOMES -> GeneratorType.LARGE_BIOMES; + case AMPLIFIED -> GeneratorType.AMPLIFIED; + }) + .structures(creator.generateStructures()) + .hardcore(creator.hardcore()) + .build() + .createAsync(); + } +} diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java index 29fa4e37d..ccc27d72d 100644 --- a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java +++ b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java @@ -18,6 +18,7 @@ package com.volmit.iris.core.nms; +import com.volmit.iris.core.link.FoliaWorldsLink; import com.volmit.iris.core.nms.container.BiomeColor; import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.engine.framework.Engine; @@ -39,6 +40,7 @@ import org.jetbrains.annotations.Nullable; import java.awt.Color; +import java.util.concurrent.CompletableFuture; public interface INMSBinding { boolean hasTile(Material material); @@ -96,6 +98,15 @@ && missingDimensionTypes(gen.getTarget().getDimension().getDimensionTypeKey())) return c.createWorld(); } + default CompletableFuture createWorldAsync(WorldCreator c) { + try { + var link = FoliaWorldsLink.get(); + return link.isActive() ? link.createWorld(c) : CompletableFuture.completedFuture(createWorld(c)); + } catch (Throwable e) { + return CompletableFuture.failedFuture(e); + } + } + int countCustomBiomes(); void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk); diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java index 2c1eed0f3..c7d877d8d 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java @@ -44,6 +44,8 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.function.IntSupplier; import java.util.function.Supplier; import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML; @@ -128,11 +130,7 @@ public World create() throws IrisException { Iris.service(StudioSVC.class).installIntoWorld(sender, d.getLoadKey(), new File(Bukkit.getWorldContainer(), name())); } - PlatformChunkGenerator access; - AtomicReference world = new AtomicReference<>(); AtomicDouble pp = new AtomicDouble(0); - O done = new O<>(); - done.set(false); WorldCreator wc = new IrisWorldCreator() .dimension(dimension) .name(name) @@ -141,28 +139,32 @@ public World create() throws IrisException { .create(); ServerConfigurator.installDataPacks(false); - access = (PlatformChunkGenerator) wc.generator(); - PlatformChunkGenerator finalAccess1 = access; + PlatformChunkGenerator access = (PlatformChunkGenerator) wc.generator(); + if (access == null) throw new IrisException("Access is null. Something bad happened."); - J.a(() -> - { - Supplier g = () -> { - if (finalAccess1 == null || finalAccess1.getEngine() == null) { + AtomicBoolean failed = new AtomicBoolean(false); + J.a(() -> { + IntSupplier g = () -> { + if (access.getEngine() == null) { return 0; } - return finalAccess1.getEngine().getGenerated(); + return access.getEngine().getGenerated(); }; if(!benchmark) { - if (finalAccess1 == null) return; - int req = finalAccess1.getSpawnChunks().join(); + int req = access.getSpawnChunks().join(); - while (g.get() < req) { - double v = (double) g.get() / (double) req; + while (g.getAsInt() < req) { + if (failed.get()) { + sender.sendMessage(C.RED + "Failed to create world!"); + return; + } + + double v = (double) g.getAsInt() / (double) req; if (sender.isPlayer()) { sender.sendProgress(v, "Generating"); J.sleep(16); } else { - sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - g.get()) + " Left)"))); + sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - g.getAsInt()) + " Left)"))); J.sleep(1000); } } @@ -170,37 +172,33 @@ public World create() throws IrisException { }); + final World world; try { - J.sfut(() -> { - world.set(INMS.get().createWorld(wc)); - }).get(); + world = J.sfut(() -> INMS.get().createWorldAsync(wc)) + .thenCompose(Function.identity()) + .get(); } catch (Throwable e) { - e.printStackTrace(); + failed.set(true); + throw new IrisException("Failed to create world!", e); } - if (access == null) { - throw new IrisException("Access is null. Something bad happened."); - } - - done.set(true); - if (sender.isPlayer() && !benchmark) { - J.s(() -> Iris.platform.teleportAsync(sender.player(), new Location(world.get(), 0, world.get().getHighestBlockYAt(0, 0), 0))); + J.s(() -> Iris.platform.teleportAsync(sender.player(), new Location(world, 0, world.getHighestBlockYAt(0, 0), 0))); } if (studio || benchmark) { J.s(() -> { - Iris.linkMultiverseCore.removeFromConfig(world.get()); + Iris.linkMultiverseCore.removeFromConfig(world); if (IrisSettings.get().getStudio().isDisableTimeAndWeather()) { - world.get().setGameRule(GameRule.DO_WEATHER_CYCLE, false); - world.get().setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false); - world.get().setTime(6000); + world.setGameRule(GameRule.DO_WEATHER_CYCLE, false); + world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false); + world.setTime(6000); } }); } else { addToBukkitYml(); - J.s(() -> Iris.linkMultiverseCore.updateWorld(world.get(), dimension)); + J.s(() -> Iris.linkMultiverseCore.updateWorld(world, dimension)); } if (pregen != null) { @@ -231,7 +229,7 @@ public World create() throws IrisException { e.printStackTrace(); } } - return world.get(); + return world; } private void addToBukkitYml() { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a2753148c..46aac93b3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,6 +50,7 @@ mythic = "5.9.5" mythic-chrucible = "2.1.0" kgenerators = "7.3" # https://repo.codemc.io/repository/maven-public/me/kryniowesegryderiusz/kgenerators-core/maven-metadata.xml multiverseCore = "5.1.0" +worlds = "3.2.5" # https://modrinth.com/plugin/worlds-1 [libraries] # Core Libraries @@ -96,6 +97,7 @@ mythic = { module = "io.lumine:Mythic-Dist", version.ref = "mythic" } mythicChrucible = { module = "io.lumine:MythicCrucible-Dist", version.ref = "mythic-chrucible" } kgenerators = { module = "me.kryniowesegryderiusz:kgenerators-core", version.ref = "kgenerators" } multiverseCore = { module = "org.mvplugins.multiverse.core:multiverse-core", version.ref = "multiverseCore" } +worlds = { module = "net.thenextlvl:worlds", version.ref = "worlds" } [plugins] shadow = { id = "com.gradleup.shadow", version.ref = "shadow" } From dc8cf0ad38a1d9e9a8f0edb7ece184e9013aec8a Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 2 Aug 2025 23:15:21 +0200 Subject: [PATCH 23/26] remove last usages of the bukkit scheduler --- .../com/volmit/iris/util/plugin/VirtualCommand.java | 3 ++- .../main/java/com/volmit/iris/util/scheduling/J.java | 10 +--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/util/plugin/VirtualCommand.java b/core/src/main/java/com/volmit/iris/util/plugin/VirtualCommand.java index 789c88661..bfd021efa 100644 --- a/core/src/main/java/com/volmit/iris/util/plugin/VirtualCommand.java +++ b/core/src/main/java/com/volmit/iris/util/plugin/VirtualCommand.java @@ -24,6 +24,7 @@ import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.format.C; import com.volmit.iris.util.reflect.V; +import com.volmit.iris.util.scheduling.J; import org.bukkit.Bukkit; import org.bukkit.Sound; import org.bukkit.command.CommandSender; @@ -171,7 +172,7 @@ private boolean checkPermissions(CommandSender sender, ICommand command2) { for (String i : command.getRequiredPermissions()) { if (!sender.hasPermission(i)) { failed = true; - Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> sender.sendMessage("- " + C.WHITE + i), 0); + J.s(() -> sender.sendMessage("- " + C.WHITE + i)); } } diff --git a/core/src/main/java/com/volmit/iris/util/scheduling/J.java b/core/src/main/java/com/volmit/iris/util/scheduling/J.java index c2e9667c8..3200737c9 100644 --- a/core/src/main/java/com/volmit/iris/util/scheduling/J.java +++ b/core/src/main/java/com/volmit/iris/util/scheduling/J.java @@ -241,18 +241,10 @@ public static CompletableFuture sfut(Runnable r) { } public static CompletableFuture sfut(Supplier r) { - CompletableFuture f = new CompletableFuture<>(); if (!Bukkit.getPluginManager().isPluginEnabled(Iris.instance)) { return null; } - Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> { - try { - f.complete(r.get()); - } catch (Throwable e) { - f.completeExceptionally(e); - } - }); - return f; + return Iris.platform.getGlobalScheduler().run(r).getResult(); } public static CompletableFuture sfut(Runnable r, int delay) { From aaf2f2f8a6c9853deb73d989b27db25d58dbb721 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 2 Aug 2025 23:15:57 +0200 Subject: [PATCH 24/26] fix teleport after world creation --- .../java/com/volmit/iris/core/tools/IrisCreator.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java index c7d877d8d..935ef01be 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java @@ -183,7 +183,15 @@ public World create() throws IrisException { } if (sender.isPlayer() && !benchmark) { - J.s(() -> Iris.platform.teleportAsync(sender.player(), new Location(world, 0, world.getHighestBlockYAt(0, 0), 0))); + Iris.platform.getRegionScheduler() + .run(world, 0, 0, () -> world.getHighestBlockYAt(0, 0) + 1) + .getResult() + .thenAccept(y -> Iris.platform.teleportAsync(sender.player(), new Location(world, 0, y, 0))) + .exceptionally(err -> { + sender.sendMessage(C.RED + "Failed to teleport you to the world!"); + err.printStackTrace(); + return null; + }); } if (studio || benchmark) { From bddc061f461a41732d9b2a0d7b8e6ac5e1cb1a60 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sat, 2 Aug 2025 23:31:17 +0200 Subject: [PATCH 25/26] make chunk retrieval to teleport async --- .../java/com/volmit/iris/core/tools/IrisCreator.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java index 935ef01be..6575ba5dd 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java @@ -32,7 +32,6 @@ import com.volmit.iris.util.format.Form; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; -import com.volmit.iris.util.scheduling.O; import lombok.Data; import lombok.experimental.Accessors; import org.bukkit.*; @@ -41,12 +40,11 @@ import java.io.File; import java.io.IOException; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.function.IntSupplier; -import java.util.function.Supplier; import static com.volmit.iris.util.misc.ServerProperties.BUKKIT_YML; @@ -183,9 +181,9 @@ public World create() throws IrisException { } if (sender.isPlayer() && !benchmark) { - Iris.platform.getRegionScheduler() - .run(world, 0, 0, () -> world.getHighestBlockYAt(0, 0) + 1) - .getResult() + Iris.platform.getChunkAtAsync(world, 0, 0, true, true) + .thenApply(Objects::requireNonNull) + .thenApply(c -> c.getChunkSnapshot(true, false, false).getHighestBlockYAt(0, 0) + 1) .thenAccept(y -> Iris.platform.teleportAsync(sender.player(), new Location(world, 0, y, 0))) .exceptionally(err -> { sender.sendMessage(C.RED + "Failed to teleport you to the world!"); From 6d3edff459f766a7f37aec82eb73f37b8c0cab00 Mon Sep 17 00:00:00 2001 From: Julian Krings Date: Sun, 21 Sep 2025 20:54:13 +0200 Subject: [PATCH 26/26] make studio tools work on folia --- core/build.gradle.kts | 11 +- .../iris/core/commands/CommandObject.java | 2 +- .../iris/core/commands/CommandStudio.java | 98 +++++++++------- .../iris/core/commands/CommandWhat.java | 2 +- .../volmit/iris/core/edit/JigsawEditor.java | 15 ++- .../com/volmit/iris/core/service/TreeSVC.java | 8 +- .../volmit/iris/engine/IrisWorldManager.java | 47 ++++++-- .../framework/placer/SafeObjectPlacer.java | 111 ++++++++++++++++++ .../iris/engine/jigsaw/PlannedStructure.java | 3 +- .../iris/engine/object/IObjectPlacer.java | 11 +- .../engine/platform/BukkitChunkGenerator.java | 27 ++--- .../platform/PlatformChunkGenerator.java | 4 +- .../com/volmit/iris/util/data/Cuboid.java | 21 ++-- .../decree/virtual/VirtualDecreeCommand.java | 7 +- .../volmit/iris/util/math/BlockPosition.java | 1 + .../iris/util/parallel/SyncExecutor.java | 46 -------- gradle/libs.versions.toml | 5 +- 17 files changed, 273 insertions(+), 146 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/engine/framework/placer/SafeObjectPlacer.java delete mode 100644 core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 904586dbe..12c1ee35f 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -78,9 +78,10 @@ dependencies { // Dynamically Loaded slim(libs.paralithic) slim(libs.paperlib) - slim(libs.adventure.api) slim(libs.adventure.minimessage) slim(libs.adventure.platform) + slim(libs.adventure.gson) + slim(libs.adventure.legacy) slim(libs.bstats) slim(libs.sentry) @@ -112,6 +113,11 @@ dependencies { slim(libs.mavenCore) } } + + constraints { + slim(libs.gson) + compileOnly(libs.gson) + } } java { @@ -135,8 +141,7 @@ slimJar { )) relocate("com.dfsek.paralithic", "$lib.paralithic") - relocate("io.papermc.lib", "$lib.paper") - relocate("net.kyori", "$lib.kyori") + relocate("net.kyori.audience", "$lib.audience") relocate("org.bstats", "$lib.metrics") relocate("io.sentry", "$lib.sentry") relocate("org.apache.maven", "$lib.maven") diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java b/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java index fd057b300..080e9908b 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandObject.java @@ -128,7 +128,7 @@ public void setTile(int xx, int yy, int zz, TileData tile) { public Engine getEngine() { return null; } - }; + }.sync(world); } @Decree(description = "Check the composition of an object") diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java index e02728d80..c203aaffd 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandStudio.java @@ -47,18 +47,14 @@ import com.volmit.iris.util.json.JSONArray; import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.mantle.MantleChunk; -import com.volmit.iris.util.math.M; -import com.volmit.iris.util.math.Position2; -import com.volmit.iris.util.math.RNG; -import com.volmit.iris.util.math.Spiraler; +import com.volmit.iris.util.math.*; import com.volmit.iris.util.noise.CNG; import com.volmit.iris.util.parallel.MultiBurst; -import com.volmit.iris.util.parallel.SyncExecutor; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.PrecisionStopwatch; import com.volmit.iris.util.scheduling.jobs.ParallelQueueJob; -import io.papermc.lib.PaperLib; +import de.crazydev22.platformutils.scheduler.task.Task; import org.bukkit.*; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; @@ -77,6 +73,7 @@ import java.util.Arrays; import java.util.Date; import java.util.Objects; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; @@ -174,7 +171,7 @@ public void regen( PlatformChunkGenerator plat = IrisToolbelt.access(world); Engine engine = plat.getEngine(); DecreeContext.touch(sender); - try (SyncExecutor executor = new SyncExecutor(20)) { + try (var executor = Iris.platform.createRegionExecutor(20)) { int x = loc.getBlockX() >> 4; int z = loc.getBlockZ() >> 4; @@ -376,7 +373,7 @@ public void regions(@Param(description = "The radius in chunks", defaultValue = var loc = player.getLocation(); int totalTasks = d * d; AtomicInteger completedTasks = new AtomicInteger(0); - int c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding regions"), 0); + Task c = J.ar(() -> sender.sendProgress((double) completedTasks.get() / totalTasks, "Finding regions"), 0); new Spiraler(d, d, (x, z) -> executor.queue(() -> { var region = engine.getRegion((x << 4) + 8, (z << 4) + 8); data.computeIfAbsent(region.getLoadKey(), (k) -> new AtomicInteger(0)) @@ -385,7 +382,7 @@ public void regions(@Param(description = "The radius in chunks", defaultValue = })).setOffset(loc.getBlockX(), loc.getBlockZ()).drain(); executor.complete(); multiBurst.close(); - J.car(c); + c.cancel(); sender.sendMessage(C.GREEN + "Done!"); var loader = engine.getData().getRegionLoader(); @@ -718,7 +715,7 @@ public void update( } } - @Decree(aliases = "find-objects", description = "Get information about nearby structures") + @Decree(aliases = "find-objects", description = "Get information about nearby structures", origin = DecreeOrigin.PLAYER) public void objects() { if (!IrisToolbelt.isIrisWorld(player().getWorld())) { sender().sendMessage(C.RED + "You must be in an Iris world"); @@ -731,21 +728,29 @@ public void objects() { sender().sendMessage("You must be in an iris world."); return; } - KList chunks = new KList<>(); - int bx = player().getLocation().getChunk().getX(); - int bz = player().getLocation().getChunk().getZ(); + KMap> chunks = new KMap<>(); + var location = player().getLocation(); + int bx = location.getBlockX() >> 4; + int bz = location.getBlockZ() >> 4; + Spiraled spiraled = (x, z) -> chunks.putIfAbsent(new Position2(x, z), Iris.platform.getChunkAtAsync(world, x, z)); try { - Location l = player().getTargetBlockExact(48, FluidCollisionMode.NEVER).getLocation(); - - int cx = l.getChunk().getX(); - int cz = l.getChunk().getZ(); - new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + cx, z + cz))).drain(); + var player = player(); + var task = Iris.platform.getEntityScheduler(player).run(() -> { + var target = player.getTargetBlockExact(48, FluidCollisionMode.NEVER); + if (target == null) return; + Location l = target.getLocation(); + + int cx = l.getBlockX() >> 4; + int cz = l.getBlockZ() >> 4; + new Spiraler(3, 3, (x, z) -> spiraled.on(x + cx, z + cz)).drain(); + }, null); + if (task != null) task.getResult().join(); } catch (Throwable e) { Iris.reportError(e); } - new Spiraler(3, 3, (x, z) -> chunks.addIfMissing(world.getChunkAt(x + bx, z + bz))).drain(); + new Spiraler(3, 3, (x, z) -> spiraled.on(x + bx, z + bz)).drain(); sender().sendMessage("Capturing IGenData from " + chunks.size() + " nearby chunks."); try { File ff = Iris.instance.getDataFile("reports/" + M.ms() + ".txt"); @@ -759,7 +764,7 @@ public void objects() { pw.println("Report Captured At: " + new Date()); pw.println("Chunks: (" + chunks.size() + "): "); - for (Chunk i : chunks) { + for (Position2 i : chunks.keySet()) { pw.println("- [" + i.getX() + ", " + i.getZ() + "]"); } @@ -784,25 +789,31 @@ public void objects() { Iris.reportError(e); } - KList biomes = new KList<>(); - KList caveBiomes = new KList<>(); - KMap>> objects = new KMap<>(); - - for (Chunk i : chunks) { - for (int j = 0; j < 16; j += 3) { - - for (int k = 0; k < 16; k += 3) { - - assert engine() != null; - IrisBiome bb = engine().getSurfaceBiome((i.getX() * 16) + j, (i.getZ() * 16) + k); - IrisBiome bxf = engine().getCaveBiome((i.getX() * 16) + j, (i.getZ() * 16) + k); - biomes.addIfMissing(bb.getName() + " [" + Form.capitalize(bb.getInferredType().name().toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")"); - caveBiomes.addIfMissing(bxf.getName() + " (" + bxf.getLoadFile().getName() + ")"); - exportObjects(bb, pw, engine(), objects); - exportObjects(bxf, pw, engine(), objects); + KSet biomes = new KSet<>(); + KSet caveBiomes = new KSet<>(); + KMap>> objects = new KMap<>(); + + var engine = engine(); + assert engine != null; + + KList> futures = new KList<>(chunks.size()); + for (var future : chunks.values()) { + futures.add(future.thenAccept(i -> { + int bX = i.getX() << 4; + int bZ = i.getZ() << 4; + for (int j = 0; j < 16; j += 3) { + for (int k = 0; k < 16; k += 3) { + IrisBiome bb = engine.getSurfaceBiome(bX + j, bZ + k); + IrisBiome bxf = engine.getCaveBiome(bX + j, bZ + k); + biomes.add(bb.getName() + " [" + Form.capitalize(String.valueOf(bb.getInferredType()).toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")"); + caveBiomes.add(bxf.getName() + " (" + bxf.getLoadFile().getName() + ")"); + exportObjects(bb, pw, engine, objects); + exportObjects(bxf, pw, engine, objects); + } } - } + })); } + CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).join(); regions = Objects.requireNonNull(new File(world.getWorldFolder().getPath() + "/region").list()).length; @@ -822,6 +833,13 @@ public void objects() { pw.println("- " + i); } pw.println(); + pw.println("== Cave Biome Info =="); + pw.println("Found " + caveBiomes.size() + " Cave Biome(s): "); + + for (String i : caveBiomes) { + pw.println("- " + i); + } + pw.println(); pw.println("== Object Info =="); @@ -847,8 +865,8 @@ public void objects() { } } - private void exportObjects(IrisBiome bb, PrintWriter pw, Engine g, KMap>> objects) { - String n1 = bb.getName() + " [" + Form.capitalize(bb.getInferredType().name().toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")"; + private void exportObjects(IrisBiome bb, PrintWriter pw, Engine g, KMap>> objects) { + String n1 = bb.getName() + " [" + Form.capitalize(String.valueOf(bb.getInferredType()).toLowerCase()) + "] " + " (" + bb.getLoadFile().getName() + ")"; int m = 0; KSet stop = new KSet<>(); for (IrisObjectPlacement f : bb.getObjects()) { @@ -873,7 +891,7 @@ private void exportObjects(IrisBiome bb, PrintWriter pw, Engine g, KMap new KMap<>()) - .computeIfAbsent(n2, (k) -> new KList<>()).addIfMissing(n3); + .computeIfAbsent(n2, (k) -> new KSet<>()).add(n3); } } } diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java b/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java index c2c8015da..c26376085 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java @@ -98,7 +98,7 @@ public void region() { } } - @Decree(description = "What block am i looking at?", origin = DecreeOrigin.PLAYER) + @Decree(description = "What block am i looking at?", origin = DecreeOrigin.PLAYER, sync = true) public void block() { BlockData bd; try { diff --git a/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java b/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java index 60ac6a243..0fce7e919 100644 --- a/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java +++ b/core/src/main/java/com/volmit/iris/core/edit/JigsawEditor.java @@ -107,21 +107,26 @@ public void on(PlayerMoveEvent e) { } public Location toLocation(IrisPosition i) { - return origin.clone() + return toBlock(origin.clone() .add(new Vector(i.getX(), i.getY(), i.getZ())) - .add(object.getCenter()) - .getBlock() - .getLocation(); + .add(object.getCenter())); } public IrisPosition toPosition(Location l) { - return new IrisPosition(l.clone().getBlock().getLocation() + return new IrisPosition(l.clone() .subtract(origin.clone()) .subtract(object.getCenter()) .add(1, 1, 1) .toVector()); } + private Location toBlock(Location location) { + location.setX(Math.floor(location.getX())); + location.setY(Math.floor(location.getY())); + location.setZ(Math.floor(location.getZ())); + return location; + } + @EventHandler public void on(PlayerInteractEvent e) { if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) { diff --git a/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java b/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java index 58be7738c..69a937367 100644 --- a/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/TreeSVC.java @@ -142,9 +142,10 @@ public int getHighest(int x, int z, IrisData data, boolean ignoreFluid) { public void set(int x, int y, int z, BlockData d) { Block b = event.getWorld().getBlockAt(x, y, z); BlockState state = b.getState(); - if (d instanceof IrisCustomData data) + if (d instanceof IrisCustomData data) { state.setBlockData(data.getBase()); - else state.setBlockData(d); + Iris.service(ExternalDataSVC.class).processUpdate(engine, b, data.getCustom()); + } else state.setBlockData(d); blockStateList.add(b.getState()); dataCache.put(new Location(event.getWorld(), x, y, z), d); } @@ -207,8 +208,7 @@ public Engine getEngine() { event.setCancelled(true); - J.s(() -> { - + Iris.platform.getRegionScheduler().run(event.getLocation(), () -> { StructureGrowEvent iGrow = new StructureGrowEvent(event.getLocation(), event.getSpecies(), event.isFromBonemeal(), event.getPlayer(), blockStateList); block = true; Bukkit.getServer().getPluginManager().callEvent(iGrow); diff --git a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index 2e867a87b..db1ae2405 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -60,9 +60,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; +import java.util.concurrent.*; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -199,21 +197,39 @@ private void discoverChunks() { } private void updateChunks() { - for (Player i : getEngine().getWorld().realWorld().getPlayers()) { - int r = 1; + int radius = 1; + int diameter = radius * 2 + 1; + int count = (diameter * diameter) + 1; + + var players = new KList<>(getEngine().getWorld().realWorld().getPlayers()); + var latch = new CountDownLatch(count * players.size()); + + for (Player i : players) { + if (!i.isOnline() || !i.isValid() || i.isDead()) { + for (int j = 0; j < count; j++) { + latch.countDown(); + } + continue; + } Iris.platform.getEntityScheduler(i).run(() -> { Chunk c = i.getLocation().getChunk(); - for (int x = -r; x <= r; x++) { - for (int z = -r; z <= r; z++) { + for (int x = -radius; x <= radius; x++) { + for (int z = -radius; z <= radius; z++) { int cX = c.getX() + x; int cZ = c.getZ() + z; - if (!c.getWorld().isChunkLoaded(cX, cZ) || !Chunks.isSafe(getEngine().getWorld().realWorld(), cX, cZ)) + if (!c.getWorld().isChunkLoaded(cX, cZ) || !Chunks.isSafe(getEngine().getWorld().realWorld(), cX, cZ)) { + latch.countDown(); continue; + } if (IrisSettings.get().getWorld().isPostLoadBlockUpdates()) { - getEngine().updateChunk(c.getWorld().getChunkAt(cX, cZ)); - } + Chunk cx = c.getWorld().getChunkAt(cX, cZ); + J.a(() -> { + getEngine().updateChunk(cx); + latch.countDown(); + }); + } else latch.countDown(); if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) { Chunk cx = getEngine().getWorld().realWorld().getChunkAt(cX, cZ); @@ -233,8 +249,17 @@ private void updateChunks() { } } } - }, null); + latch.countDown(); + }, () -> { + for (int j = 0; j < count; j++) { + latch.countDown(); + } + }); } + + try { + latch.await(); + } catch (InterruptedException ignored) {} } private boolean onAsyncTick() { diff --git a/core/src/main/java/com/volmit/iris/engine/framework/placer/SafeObjectPlacer.java b/core/src/main/java/com/volmit/iris/engine/framework/placer/SafeObjectPlacer.java new file mode 100644 index 000000000..f7fd61109 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/engine/framework/placer/SafeObjectPlacer.java @@ -0,0 +1,111 @@ +package com.volmit.iris.engine.framework.placer; + +import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.object.IObjectPlacer; +import com.volmit.iris.engine.object.TileData; +import lombok.EqualsAndHashCode; +import org.bukkit.World; +import org.bukkit.block.data.BlockData; + +import static com.volmit.iris.Iris.platform; + +@EqualsAndHashCode +public class SafeObjectPlacer implements IObjectPlacer { + private final World world; + private final IObjectPlacer placer; + + public SafeObjectPlacer(World world, IObjectPlacer placer) { + this.world = world; + this.placer = placer; + } + + @Override + public int getHighest(int x, int z, IrisData data) { + if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) { + return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> getHighest(x, z, data)) + .getResult() + .join(); + } + return placer.getHighest(x, z, data); + } + + @Override + public int getHighest(int x, int z, IrisData data, boolean ignoreFluid) { + if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) { + if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!"); + return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> getHighest(x, z, data, ignoreFluid)) + .getResult() + .join(); + } + return placer.getHighest(x, z, data); + } + + @Override + public void set(int x, int y, int z, BlockData d) { + if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) { + if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!"); + platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> set(x, y, z, d)).getResult().join(); + } else placer.set(x, y, z, d); + } + + @Override + public BlockData get(int x, int y, int z) { + if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) { + if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!"); + return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> get(x, y, z)).getResult().join(); + } + return placer.get(x, y, z); + } + + @Override + public boolean isPreventingDecay() { + return placer.isPreventingDecay(); + } + + @Override + public boolean isCarved(int x, int y, int z) { + return placer.isCarved(x, y, z); + } + + @Override + public boolean isSolid(int x, int y, int z) { + if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) { + if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!"); + return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> isSolid(x, y, z)).getResult().join(); + } + return placer.isSolid(x, y, z); + } + + @Override + public boolean isUnderwater(int x, int z) { + if (!platform.isOwnedByCurrentRegion(world, x >> 4, z >> 4)) { + if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!"); + return platform.getRegionScheduler().run(world, x >> 4, z >> 4, () -> isUnderwater(x, z)).getResult().join(); + } + return placer.isUnderwater(x, z); + } + + @Override + public int getFluidHeight() { + return placer.getFluidHeight(); + } + + @Override + public boolean isDebugSmartBore() { + return placer.isDebugSmartBore(); + } + + @Override + public void setTile(int xx, int yy, int zz, TileData tile) { + if (!platform.isOwnedByCurrentRegion(world, xx >> 4, zz >> 4)) { + if (platform.isTickThread()) throw new IllegalStateException("Cannot run async on primary thread!"); + platform.getRegionScheduler().run(world, xx >> 4, zz >> 4, () -> setTile(xx, yy, zz, tile)).getResult().join(); + } else placer.setTile(xx, yy, zz, tile); + } + + @Override + public Engine getEngine() { + return placer.getEngine(); + } +} diff --git a/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java b/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java index c045cf922..72662fcac 100644 --- a/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java +++ b/core/src/main/java/com/volmit/iris/engine/jigsaw/PlannedStructure.java @@ -160,8 +160,9 @@ public boolean place(PlannedPiece i, int startHeight, IrisObjectPlacement o, IOb }, null, getData().getEngine() != null ? getData() : eng.getData()) != -1; } + //TODO properly fix for folia public void place(WorldObjectPlacer placer, Consumer consumer) { - J.s(() -> consumer.accept(place(placer, placer.getMantle().getMantle(), placer.getEngine()))); + Iris.platform.getRegionScheduler().run(placer.getWorld(), position.getX() >> 4, position.getZ() >> 4, () -> consumer.accept(place(placer, placer.getMantle().getMantle(), placer.getEngine()))); } private void generateOutwards() { diff --git a/core/src/main/java/com/volmit/iris/engine/object/IObjectPlacer.java b/core/src/main/java/com/volmit/iris/engine/object/IObjectPlacer.java index 3a7a89a38..46c955cec 100644 --- a/core/src/main/java/com/volmit/iris/engine/object/IObjectPlacer.java +++ b/core/src/main/java/com/volmit/iris/engine/object/IObjectPlacer.java @@ -18,9 +18,12 @@ package com.volmit.iris.engine.object; +import com.volmit.iris.Iris; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.engine.framework.Engine; -import org.bukkit.block.TileState; +import com.volmit.iris.engine.framework.placer.SafeObjectPlacer; +import de.crazydev22.platformutils.Type; +import org.bukkit.World; import org.bukkit.block.data.BlockData; public interface IObjectPlacer { @@ -47,4 +50,10 @@ public interface IObjectPlacer { void setTile(int xx, int yy, int zz, TileData tile); Engine getEngine(); + + default IObjectPlacer sync(World world) { + if (Iris.platform.getType() == Type.FOLIA) + return new SafeObjectPlacer(world, this); + return this; + } } diff --git a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index c3a3b13c5..a68dd5481 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -38,9 +38,11 @@ import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder; import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder; import com.volmit.iris.util.io.ReactiveFolder; +import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.Looper; +import de.crazydev22.platformutils.scheduler.IRegionExecutor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Setter; @@ -194,13 +196,12 @@ public EngineTarget getTarget() { } @Override - public void injectChunkReplacement(World world, int x, int z, Executor syncExecutor) { + public void injectChunkReplacement(World world, int x, int z, IRegionExecutor executor) { try { loadLock.acquire(); IrisBiomeStorage st = new IrisBiomeStorage(); TerrainChunk tc = TerrainChunk.createUnsafe(world, st); - this.world.bind(world); - getEngine().generate(x << 4, z << 4, tc, IrisSettings.get().getGenerator().useMulticore); + generateNoise(world, RNG.r, x, z, tc); Chunk c = Iris.platform.getChunkAtAsync(world, x, z) .thenApply(d -> { @@ -223,7 +224,7 @@ public void injectChunkReplacement(World world, int x, int z, Executor syncExecu KList> futures = new KList<>(1 + getEngine().getHeight() >> 4); for (int i = getEngine().getHeight() >> 4; i >= 0; i--) { int finalI = i << 4; - futures.add(CompletableFuture.runAsync(() -> { + futures.add(executor.queue(world, x, z, () -> { for (int xx = 0; xx < 16; xx++) { for (int yy = 0; yy < 16; yy++) { for (int zz = 0; zz < 16; zz++) { @@ -235,15 +236,15 @@ public void injectChunkReplacement(World world, int x, int z, Executor syncExecu } } } - }, syncExecutor)); + })); } - futures.add(CompletableFuture.runAsync(() -> INMS.get().placeStructures(c), syncExecutor)); - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) - .thenRunAsync(() -> { + CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)) + .thenCompose($ -> executor.queue(world, x, z, () -> INMS.get().placeStructures(c))) + .thenCompose($ -> executor.queue(world, x, z, () -> { c.removePluginChunkTicket(Iris.instance); engine.getWorldManager().onChunkLoad(c, true); - }, syncExecutor) + })) .get(); Iris.debug("Regenerated " + x + " " + z); @@ -254,14 +255,6 @@ public void injectChunkReplacement(World world, int x, int z, Executor syncExecu e.printStackTrace(); Iris.reportErrorChunk(x, z, e, "CHUNK"); Iris.error("======================================"); - - ChunkData d = Bukkit.createChunkData(world); - - for (int i = 0; i < 16; i++) { - for (int j = 0; j < 16; j++) { - d.setBlock(i, 0, j, Material.RED_GLAZED_TERRACOTTA.createBlockData()); - } - } } } diff --git a/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java b/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java index 93066fb62..5a6427d8e 100644 --- a/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java +++ b/core/src/main/java/com/volmit/iris/engine/platform/PlatformChunkGenerator.java @@ -23,12 +23,12 @@ import com.volmit.iris.engine.framework.EngineTarget; import com.volmit.iris.engine.framework.Hotloadable; import com.volmit.iris.util.data.DataProvider; +import de.crazydev22.platformutils.scheduler.IRegionExecutor; import org.bukkit.World; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; public interface PlatformChunkGenerator extends Hotloadable, DataProvider { @Nullable @@ -42,7 +42,7 @@ default IrisData getData() { @NotNull EngineTarget getTarget(); - void injectChunkReplacement(World world, int x, int z, Executor syncExecutor); + void injectChunkReplacement(World world, int x, int z, IRegionExecutor executor); void close(); diff --git a/core/src/main/java/com/volmit/iris/util/data/Cuboid.java b/core/src/main/java/com/volmit/iris/util/data/Cuboid.java index df377fec6..2411bb621 100644 --- a/core/src/main/java/com/volmit/iris/util/data/Cuboid.java +++ b/core/src/main/java/com/volmit/iris/util/data/Cuboid.java @@ -316,17 +316,17 @@ public int getUpperZ() { * * @return array of Block objects representing the Cuboid corners */ - public Block[] corners() { - Block[] res = new Block[8]; + public Location[] corners() { + Location[] res = new Location[8]; World w = getWorld(); - res[0] = w.getBlockAt(x1, y1, z1); - res[1] = w.getBlockAt(x1, y1, z2); - res[2] = w.getBlockAt(x1, y2, z1); - res[3] = w.getBlockAt(x1, y2, z2); - res[4] = w.getBlockAt(x2, y1, z1); - res[5] = w.getBlockAt(x2, y1, z2); - res[6] = w.getBlockAt(x2, y2, z1); - res[7] = w.getBlockAt(x2, y2, z2); + res[0] = new Location(w, x1, y1, z1); + res[1] = new Location(w, x1, y1, z2); + res[2] = new Location(w, x1, y2, z1); + res[3] = new Location(w, x1, y2, z2); + res[4] = new Location(w, x2, y1, z1); + res[5] = new Location(w, x2, y1, z2); + res[6] = new Location(w, x2, y2, z1); + res[7] = new Location(w, x2, y2, z2); return res; } @@ -648,6 +648,7 @@ public List getChunks() { * @see java.lang.Iterable#iterator() */ @Override + @Deprecated(forRemoval = true) public Iterator iterator() { return new CuboidIterator(getWorld(), x1, y1, z1, x2, y2, z2); } diff --git a/core/src/main/java/com/volmit/iris/util/decree/virtual/VirtualDecreeCommand.java b/core/src/main/java/com/volmit/iris/util/decree/virtual/VirtualDecreeCommand.java index 4bd5e9168..c370d8f9b 100644 --- a/core/src/main/java/com/volmit/iris/util/decree/virtual/VirtualDecreeCommand.java +++ b/core/src/main/java/com/volmit/iris/util/decree/virtual/VirtualDecreeCommand.java @@ -31,8 +31,8 @@ import com.volmit.iris.util.plugin.CommandDummy; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.ChronoLatch; -import com.volmit.iris.util.scheduling.J; import lombok.Data; +import org.bukkit.entity.Entity; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -493,7 +493,10 @@ private boolean invokeNode(VolmitSender sender, KMap map) { }; if (getNode().isSync()) { - J.s(rx); + switch (sender.getS()) { + case Entity entity -> Iris.platform.getEntityScheduler(entity).run(rx, null); + case null, default -> Iris.platform.getGlobalScheduler().run(rx); + } } else { rx.run(); } diff --git a/core/src/main/java/com/volmit/iris/util/math/BlockPosition.java b/core/src/main/java/com/volmit/iris/util/math/BlockPosition.java index 9ca1363f8..ec564fca2 100644 --- a/core/src/main/java/com/volmit/iris/util/math/BlockPosition.java +++ b/core/src/main/java/com/volmit/iris/util/math/BlockPosition.java @@ -89,6 +89,7 @@ public long asLong() { return toLong(getX(), getY(), getZ()); } + @Deprecated(forRemoval = true) public Block toBlock(World world) { return world.getBlockAt(x, y, z); } diff --git a/core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java b/core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java deleted file mode 100644 index 00966b226..000000000 --- a/core/src/main/java/com/volmit/iris/util/parallel/SyncExecutor.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.volmit.iris.util.parallel; - -import com.volmit.iris.util.math.M; -import com.volmit.iris.util.scheduling.SR; -import org.jetbrains.annotations.NotNull; - -import java.util.Queue; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicBoolean; - -public class SyncExecutor implements Executor, AutoCloseable { - private final CountDownLatch latch = new CountDownLatch(1); - private final Queue queue = new ConcurrentLinkedQueue<>(); - private final AtomicBoolean closed = new AtomicBoolean(false); - - public SyncExecutor(int msPerTick) { - new SR() { - @Override - public void run() { - var time = M.ms() + msPerTick; - while (time > M.ms()) { - Runnable r = queue.poll(); - if (r == null) break; - r.run(); - } - - if (closed.get() && queue.isEmpty()) { - cancel(); - latch.countDown(); - } - } - }; - } - - @Override - public void execute(@NotNull Runnable command) { - if (closed.get()) throw new IllegalStateException("Executor is closed!"); - queue.add(command); - } - - @Override - public void close() throws Exception { - closed.set(true); - latch.await(); - } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c99bd4b2b..309eca7ee 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ spigot = "1.20.1-R0.1-SNAPSHOT" # https://hub.spigotmc.org/nexus/repository/snap log4j = "2.19.0" # https://central.sonatype.com/artifact/org.apache.logging.log4j/log4j-api adventure-api = "4.24.0" # https://github.com/KyoriPowered/adventure adventure-platform = "4.4.1" # https://github.com/KyoriPowered/adventure-platform -platform-utils = "e396f93d56" # https://github.com/CrazyDev05/PlatformUtils +platform-utils = "27453094ed" # https://github.com/CrazyDev05/PlatformUtils annotations = "26.0.2" # https://central.sonatype.com/artifact/org.jetbrains/annotations paralithic = "0.8.1" # https://github.com/PolyhedralDev/Paralithic/ @@ -68,8 +68,9 @@ annotations = { module = "org.jetbrains:annotations", version.ref = "annotations platformUtils = { module = "com.github.CrazyDev05:PlatformUtils", version.ref = "platform-utils" } # Dynamically Loaded -adventure-api = { module = "net.kyori:adventure-api", version.ref = "adventure-api" } adventure-minimessage = { module = "net.kyori:adventure-text-minimessage", version.ref = "adventure-api" } +adventure-gson = { module = "net.kyori:adventure-text-serializer-gson", version.ref = "adventure-api" } +adventure-legacy = { module = "net.kyori:adventure-text-serializer-legacy", version.ref = "adventure-api" } adventure-platform = { module = "net.kyori:adventure-platform-bukkit", version.ref = "adventure-platform" } paralithic = { module = "com.dfsek:paralithic", version.ref = "paralithic" }