From 0e87f0a94fc6e8d15d0e789c46a94cb01b030cb8 Mon Sep 17 00:00:00 2001 From: TechnicallyCoded Date: Tue, 11 Apr 2023 14:38:58 +0200 Subject: [PATCH] v0.2.0, Add cancellable tasks, Add entity tasks, Remove scopes and use separate method names instead, Change server version checks to use class names instead of version name --- build.gradle | 2 +- .../java/com/tcoded/folialib/FoliaLib.java | 40 ++-- .../folialib/enums/EntityTaskResult.java | 9 + .../folialib/enums/ImplementationType.java | 23 ++- .../tcoded/folialib/enums/ThreadScope.java | 6 - .../folialib/impl/FoliaImplementation.java | 176 ++++++++++++++---- .../folialib/impl/ServerImplementation.java | 166 +++++++++++++++-- .../folialib/impl/SpigotImplementation.java | 154 +++++++++++---- .../impl/UnsupportedImplementation.java | 28 ++- .../tcoded/folialib/wrapper/WrappedTask.java | 14 ++ .../wrapper/task/WrappedBukkitTask.java | 29 +++ .../wrapper/task/WrappedFoliaTask.java | 29 +++ 12 files changed, 547 insertions(+), 129 deletions(-) create mode 100644 src/main/java/com/tcoded/folialib/enums/EntityTaskResult.java delete mode 100644 src/main/java/com/tcoded/folialib/enums/ThreadScope.java create mode 100644 src/main/java/com/tcoded/folialib/wrapper/WrappedTask.java create mode 100644 src/main/java/com/tcoded/folialib/wrapper/task/WrappedBukkitTask.java create mode 100644 src/main/java/com/tcoded/folialib/wrapper/task/WrappedFoliaTask.java diff --git a/build.gradle b/build.gradle index 8131883..049419f 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { } group 'com.tcoded' -version '0.1.1' +version '0.2.0' java { sourceCompatibility = JavaVersion.VERSION_17 diff --git a/src/main/java/com/tcoded/folialib/FoliaLib.java b/src/main/java/com/tcoded/folialib/FoliaLib.java index 9f89003..cf4caea 100644 --- a/src/main/java/com/tcoded/folialib/FoliaLib.java +++ b/src/main/java/com/tcoded/folialib/FoliaLib.java @@ -14,24 +14,32 @@ public class FoliaLib { public FoliaLib(JavaPlugin plugin) { this.plugin = plugin; - String version = plugin.getServer().getVersion(); + // Find the implementation type based on the class names + ImplementationType foundType = ImplementationType.UNKNOWN; + typeLoop: + for (ImplementationType type : ImplementationType.values()) { + String[] classNames = type.getClassNames(); - // Init implementation based on server version string - if (version.startsWith("git-Folia-")) { - this.implementationType = ImplementationType.FOLIA; - this.implementation = new FoliaImplementation(this); - } - else if (version.startsWith("git-Paper-")) { - this.implementationType = ImplementationType.PAPER; - this.implementation = new PaperImplementation(this); - } - else if (version.contains("-Spigot-")) { - this.implementationType = ImplementationType.SPIGOT; - this.implementation = new SpigotImplementation(this); + // Check if any of the class names are present + for (String className : classNames) { + try { + // Try to load the class + Class.forName(className); + + // Found the server type, remember that and break the loop + foundType = type; + break typeLoop; + } catch (ClassNotFoundException ignored) {} + } } - else { - this.implementationType = ImplementationType.UNKNOWN; - this.implementation = new UnsupportedImplementation(this); + + // Apply the implementation based on the type + this.implementationType = foundType; + switch (foundType) { + case FOLIA -> this.implementation = new FoliaImplementation(this); + case PAPER -> this.implementation = new PaperImplementation(this); + case SPIGOT -> this.implementation = new SpigotImplementation(this); + default -> this.implementation = new UnsupportedImplementation(this); } } diff --git a/src/main/java/com/tcoded/folialib/enums/EntityTaskResult.java b/src/main/java/com/tcoded/folialib/enums/EntityTaskResult.java new file mode 100644 index 0000000..c874759 --- /dev/null +++ b/src/main/java/com/tcoded/folialib/enums/EntityTaskResult.java @@ -0,0 +1,9 @@ +package com.tcoded.folialib.enums; + +public enum EntityTaskResult { + + SUCCESS, + ENTITY_RETIRED, + SCHEDULER_RETIRED + +} diff --git a/src/main/java/com/tcoded/folialib/enums/ImplementationType.java b/src/main/java/com/tcoded/folialib/enums/ImplementationType.java index 0d0abea..78d3ed8 100644 --- a/src/main/java/com/tcoded/folialib/enums/ImplementationType.java +++ b/src/main/java/com/tcoded/folialib/enums/ImplementationType.java @@ -1,8 +1,23 @@ package com.tcoded.folialib.enums; public enum ImplementationType { - SPIGOT, - PAPER, - FOLIA, - UNKNOWN + + // Ordered by priority + @SuppressWarnings("SpellCheckingInspection") + FOLIA ("io.papermc.paper.threadedregions.RegionizedServer"), + @SuppressWarnings("SpellCheckingInspection") + PAPER ("com.destroystokyo.paper.PaperConfig", "io.papermc.paper.configuration.Configuration"), + @SuppressWarnings("SpellCheckingInspection") + SPIGOT ("org.spigotmc.SpigotConfig"), + UNKNOWN; + + private final String[] classNames; + + ImplementationType(String... classNames) { + this.classNames = classNames; + } + + public String[] getClassNames() { + return classNames; + } } diff --git a/src/main/java/com/tcoded/folialib/enums/ThreadScope.java b/src/main/java/com/tcoded/folialib/enums/ThreadScope.java deleted file mode 100644 index 194bbb9..0000000 --- a/src/main/java/com/tcoded/folialib/enums/ThreadScope.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.tcoded.folialib.enums; - -public enum ThreadScope { - SYNC, - ASYNC -} diff --git a/src/main/java/com/tcoded/folialib/impl/FoliaImplementation.java b/src/main/java/com/tcoded/folialib/impl/FoliaImplementation.java index b66868c..66d2fad 100644 --- a/src/main/java/com/tcoded/folialib/impl/FoliaImplementation.java +++ b/src/main/java/com/tcoded/folialib/impl/FoliaImplementation.java @@ -1,14 +1,17 @@ package com.tcoded.folialib.impl; import com.tcoded.folialib.FoliaLib; -import com.tcoded.folialib.enums.ThreadScope; +import com.tcoded.folialib.enums.EntityTaskResult; import com.tcoded.folialib.util.TimeConverter; +import com.tcoded.folialib.wrapper.WrappedTask; +import com.tcoded.folialib.wrapper.task.WrappedFoliaTask; import io.papermc.paper.threadedregions.scheduler.AsyncScheduler; import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler; import org.bukkit.Location; -import org.bukkit.entity.Player; +import org.bukkit.entity.Entity; import org.bukkit.plugin.java.JavaPlugin; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; public class FoliaImplementation implements ServerImplementation { @@ -24,61 +27,158 @@ public FoliaImplementation(FoliaLib foliaLib) { } @Override - public void runLater(Runnable runnable, long delay, TimeUnit unit) { - this.runLater(ThreadScope.ASYNC, runnable, delay, unit); + public CompletableFuture runNextTick(Runnable runnable) { + CompletableFuture future = new CompletableFuture<>(); + + this.globalRegionScheduler.execute(plugin, () -> { + runnable.run(); + future.complete(null); + }); + + return future; } @Override - public void runLater(ThreadScope scope, Runnable runnable, long delay, TimeUnit unit) { - switch (scope) { - case ASYNC: - this.asyncScheduler.runDelayed(plugin, task -> runnable.run(), delay, unit); - break; - default: - this.globalRegionScheduler.runDelayed(plugin, task -> runnable.run(), TimeConverter.toTicks(delay, unit)); - break; - } + public CompletableFuture runAsync(Runnable runnable) { + CompletableFuture future = new CompletableFuture<>(); + + this.asyncScheduler.runNow(plugin, task -> { + runnable.run(); + future.complete(null); + }); + + return future; } @Override - public void runTimer(Runnable runnable, long delay, long period, TimeUnit unit) { - this.runTimer(ThreadScope.ASYNC, runnable, delay, period, unit); + public WrappedTask runLater(Runnable runnable, long delay, TimeUnit unit) { + return new WrappedFoliaTask( + this.globalRegionScheduler.runDelayed( + plugin, task -> runnable.run(), TimeConverter.toTicks(delay, unit) + ) + ); } @Override - public void runTimer(ThreadScope scope, Runnable runnable, long delay, long period, TimeUnit unit) { - switch (scope) { - case ASYNC: - this.asyncScheduler.runAtFixedRate(plugin, task -> runnable.run(), delay, period, unit); - break; - default: - this.globalRegionScheduler.runAtFixedRate(plugin, task -> runnable.run(), TimeConverter.toTicks(delay, unit), TimeConverter.toTicks(period, unit)); - break; - } + public WrappedTask runLaterAsync(Runnable runnable, long delay, TimeUnit unit) { + return new WrappedFoliaTask( + this.asyncScheduler.runDelayed( + plugin, task -> runnable.run(), delay, unit + ) + ); + } + + @Override + public WrappedTask runTimer(Runnable runnable, long delay, long period, TimeUnit unit) { + return new WrappedFoliaTask( + this.globalRegionScheduler.runAtFixedRate( + plugin, task -> runnable.run(), + TimeConverter.toTicks(delay, unit), + TimeConverter.toTicks(period, unit) + ) + ); + } + + @Override + public WrappedTask runTimerAsync(Runnable runnable, long delay, long period, TimeUnit unit) { + return new WrappedFoliaTask( + this.asyncScheduler.runAtFixedRate( + plugin, task -> runnable.run(), + delay, period, unit + ) + ); + } + + @Override + public CompletableFuture runAtLocation(Location location, Runnable runnable) { + CompletableFuture future = new CompletableFuture<>(); + + this.plugin.getServer().getRegionScheduler().execute(plugin, location, () -> { + runnable.run(); + future.complete(null); + }); + + return future; + } + + @Override + public WrappedTask runAtLocationLater(Location location, Runnable runnable, long delay, TimeUnit unit) { + return new WrappedFoliaTask( + this.plugin.getServer().getRegionScheduler().runDelayed( + plugin, location, task -> runnable.run(), + TimeConverter.toTicks(delay, unit) + ) + ); } @Override - public void runInGlobalScope(ThreadScope scope, Runnable runnable) { - switch (scope) { - case ASYNC: - this.asyncScheduler.runNow(plugin, task -> runnable.run()); - break; - default: - this.globalRegionScheduler.execute(plugin, runnable); - break; + public WrappedTask runAtLocationTimer(Location location, Runnable runnable, long delay, long period, TimeUnit unit) { + return new WrappedFoliaTask( + this.plugin.getServer().getRegionScheduler().runAtFixedRate( + plugin, location, task -> runnable.run(), + TimeConverter.toTicks(delay, unit), + TimeConverter.toTicks(period, unit) + ) + ); + } + + @Override + public CompletableFuture runAtEntity(Entity entity, Runnable runnable) { + CompletableFuture future = new CompletableFuture<>(); + + boolean success = entity.getScheduler().execute(this.plugin, () -> { + runnable.run(); + future.complete(EntityTaskResult.SUCCESS); + }, null, 0); + + if (!success) { + future.complete(EntityTaskResult.SCHEDULER_RETIRED); } + + return future; } @Override - public void runInRegion(Location location, Runnable runnable) { - //this.globalRegionScheduler.// - this.plugin.getServer().getRegionScheduler().run(plugin, location, task -> runnable.run()); + public CompletableFuture runAtEntityWithFallback(Entity entity, Runnable runnable, Runnable fallback) { + CompletableFuture future = new CompletableFuture<>(); + + boolean success = entity.getScheduler().execute(this.plugin, () -> { + runnable.run(); + future.complete(EntityTaskResult.SUCCESS); + }, () -> { + fallback.run(); + future.complete(EntityTaskResult.ENTITY_RETIRED); + }, 0); + + if (!success) { + future.complete(EntityTaskResult.SCHEDULER_RETIRED); + } + + return future; } @Override - public void runInPlayerRegion(Player player, Runnable runnable) { - //this.globalRegionScheduler.// - this.plugin.getServer().getRegionScheduler().run(plugin, player.getLocation(), task -> runnable.run()); + public WrappedTask runAtEntityLater(Entity entity, Runnable runnable, long delay, TimeUnit unit) { + return new WrappedFoliaTask( + entity.getScheduler().runDelayed( + plugin, + task -> runnable.run(), + null, + TimeConverter.toTicks(delay, unit) + ) + ); } + @Override + public WrappedTask runAtEntityTimer(Entity entity, Runnable runnable, long delay, long period, TimeUnit unit) { + return new WrappedFoliaTask( + entity.getScheduler().runAtFixedRate( + plugin, + task -> runnable.run(), + null, + TimeConverter.toTicks(delay, unit), + TimeConverter.toTicks(period, unit) + ) + ); + } } diff --git a/src/main/java/com/tcoded/folialib/impl/ServerImplementation.java b/src/main/java/com/tcoded/folialib/impl/ServerImplementation.java index 4e230e9..33cdc51 100644 --- a/src/main/java/com/tcoded/folialib/impl/ServerImplementation.java +++ b/src/main/java/com/tcoded/folialib/impl/ServerImplementation.java @@ -1,27 +1,169 @@ package com.tcoded.folialib.impl; -import com.tcoded.folialib.enums.ThreadScope; +import com.tcoded.folialib.enums.EntityTaskResult; +import com.tcoded.folialib.wrapper.WrappedTask; import org.bukkit.Location; -import org.bukkit.entity.Player; +import org.bukkit.entity.Entity; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +@SuppressWarnings("unused") public interface ServerImplementation { - // Delayed - void runLater(Runnable runnable, long delay, TimeUnit unit); + // ----- Run now ----- - void runLater(ThreadScope scope, Runnable runnable, long delay, TimeUnit unit); + /** + * Folia: Synced with the server daylight cycle tick + * Paper: Synced with the server main thread + * Spigot: Synced with the server main thread + * @param runnable Task to run + * @return Future when the task is completed + */ + CompletableFuture runNextTick(Runnable runnable); - // Timers - void runTimer(Runnable runnable, long delay, long period, TimeUnit unit); + /** + * Folia: Async + * Paper: Async + * Spigot: Async + * @param runnable Task to run + * @return Future when the task is completed + */ + CompletableFuture runAsync(Runnable runnable); - void runTimer(ThreadScope scope, Runnable runnable, long delay, long period, TimeUnit unit); + // ----- Run Later ----- - // Run now - void runInGlobalScope(ThreadScope scope, Runnable runnable); + /** + * Folia: Synced with the server daylight cycle tick + * Paper: Synced with the server main thread + * Spigot: Synced with the server main thread + * @param runnable Task to run + * @param delay Delay before execution + * @param unit Time unit + * @return WrappedTask instance + */ + WrappedTask runLater(Runnable runnable, long delay, TimeUnit unit); - void runInRegion(Location location, Runnable runnable); + /** + * Folia: Async + * Paper: Async + * Spigot: Async + * @param runnable Task to run + * @param delay Delay before execution + * @param unit Time unit + * @return WrappedTask instance + */ + WrappedTask runLaterAsync(Runnable runnable, long delay, TimeUnit unit); - void runInPlayerRegion(Player player, Runnable runnable); + // ----- Global Timers ----- + + /** + * Folia: Synced with the server daylight cycle tick + * Paper: Synced with the server main thread + * Spigot: Synced with the server main thread + * @param runnable Task to run + * @param delay Delay before first execution + * @param period Delay between executions + * @param unit Time unit + * @return WrappedTask instance + */ + WrappedTask runTimer(Runnable runnable, long delay, long period, TimeUnit unit); + + /** + * Folia: Async + * Paper: Async + * Spigot: Async + * @param runnable Task to run + * @param delay Delay before first execution + * @param period Delay between executions + * @param unit Time unit + * @return WrappedTask instance + */ + WrappedTask runTimerAsync(Runnable runnable, long delay, long period, TimeUnit unit); + + + // ----- Location/Region based ----- + + /** + * Folia: Synced with the tick of the region of the chunk of the location + * Paper: Synced with the server main thread + * Spigot: Synced with the server main thread + * @param location Location to run the task at + * @param runnable Task to run + * @return Future when the task is completed + */ + CompletableFuture runAtLocation(Location location, Runnable runnable); + + /** + * Folia: Synced with the tick of the region of the chunk of the location + * Paper: Synced with the server main thread + * Spigot: Synced with the server main thread + * @param location Location to run the task at + * @param runnable Task to run + * @param delay Delay before execution + * @param unit Time unit + * @return WrappedTask instance + */ + WrappedTask runAtLocationLater(Location location, Runnable runnable, long delay, TimeUnit unit); + + /** + * Folia: Synced with the tick of the region of the chunk of the location + * Paper: Synced with the server main thread + * Spigot: Synced with the server main thread + * @param location Location to run the task at + * @param runnable Task to run + * @param delay Delay before first execution + * @param period Delay between executions + * @param unit Time unit + * @return WrappedTask instance + */ + WrappedTask runAtLocationTimer(Location location, Runnable runnable, long delay, long period, TimeUnit unit); + + + // ----- Entity based ----- + + /** + * Folia: Synced with the tick of the region of the entity (even if the entity moves) + * Paper: Synced with the server main thread + * Spigot: Synced with the server main thread + * @param entity Entity to run the task at + * @param runnable Task to run + * @return Future when the task is completed + */ + CompletableFuture runAtEntity(Entity entity, Runnable runnable); + + /** + * Folia: Synced with the tick of the region of the entity (even if the entity moves) + * Paper: Synced with the server main thread + * Spigot: Synced with the server main thread + * @param entity Entity to run the task at + * @param runnable Task to run + * @return Future when the task is completed + */ + CompletableFuture runAtEntityWithFallback(Entity entity, Runnable runnable, Runnable fallback); + + /** + * Folia: Synced with the tick of the region of the entity (even if the entity moves) + * Paper: Synced with the server main thread + * Spigot: Synced with the server main thread + * @param entity Entity to run the task at + * @param runnable Task to run + * @param delay Delay before execution + * @param unit Time unit + * @return WrappedTask instance + */ + WrappedTask runAtEntityLater(Entity entity, Runnable runnable, long delay, TimeUnit unit); + + /** + * Folia: Synced with the tick of the region of the entity (even if the entity moves) + * Paper: Synced with the server main thread + * Spigot: Synced with the server main thread + * @param entity Entity to run the task at + * @param runnable Task to run + * @param delay Delay before first execution + * @param period Delay between executions + * @param unit Time unit + * @return WrappedTask instance + */ + WrappedTask runAtEntityTimer(Entity entity, Runnable runnable, long delay, long period, TimeUnit unit); } diff --git a/src/main/java/com/tcoded/folialib/impl/SpigotImplementation.java b/src/main/java/com/tcoded/folialib/impl/SpigotImplementation.java index c0150c1..14dc9a9 100644 --- a/src/main/java/com/tcoded/folialib/impl/SpigotImplementation.java +++ b/src/main/java/com/tcoded/folialib/impl/SpigotImplementation.java @@ -1,19 +1,23 @@ package com.tcoded.folialib.impl; import com.tcoded.folialib.FoliaLib; -import com.tcoded.folialib.enums.ThreadScope; +import com.tcoded.folialib.enums.EntityTaskResult; import com.tcoded.folialib.util.TimeConverter; +import com.tcoded.folialib.wrapper.WrappedTask; +import com.tcoded.folialib.wrapper.task.WrappedBukkitTask; import org.bukkit.Location; -import org.bukkit.entity.Player; +import org.bukkit.entity.Entity; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitScheduler; import org.jetbrains.annotations.NotNull; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; public class SpigotImplementation implements ServerImplementation { private final JavaPlugin plugin; + @SuppressWarnings("deprecation") private final @NotNull BukkitScheduler scheduler; public SpigotImplementation(FoliaLib foliaLib) { @@ -21,60 +25,136 @@ public SpigotImplementation(FoliaLib foliaLib) { this.scheduler = plugin.getServer().getScheduler(); } + @Override + public CompletableFuture runNextTick(Runnable runnable) { + CompletableFuture future = new CompletableFuture<>(); + + this.scheduler.runTask(plugin, () -> { + runnable.run(); + future.complete(null); + }); + + return future; + } + + @Override + public CompletableFuture runAsync(Runnable runnable) { + CompletableFuture future = new CompletableFuture<>(); + + this.scheduler.runTaskAsynchronously(plugin, () -> { + runnable.run(); + future.complete(null); + }); + + return future; + } @Override - public void runLater(Runnable runnable, long delay, TimeUnit unit) { - this.runLater(ThreadScope.SYNC, runnable, delay, unit); + public WrappedTask runLater(Runnable runnable, long delay, TimeUnit unit) { + return new WrappedBukkitTask( + this.scheduler.runTaskLater(plugin, runnable, TimeConverter.toTicks(delay, unit)) + ); } @Override - public void runLater(ThreadScope scope, Runnable runnable, long delay, TimeUnit unit) { - switch (scope) { - case ASYNC: - this.scheduler.runTaskLaterAsynchronously(plugin, runnable, TimeConverter.toTicks(delay, unit)); - break; - default: - this.scheduler.runTaskLater(plugin, runnable, TimeConverter.toTicks(delay, unit)); - break; - } + public WrappedTask runLaterAsync(Runnable runnable, long delay, TimeUnit unit) { + return new WrappedBukkitTask( + this.scheduler.runTaskLaterAsynchronously(plugin, runnable, TimeConverter.toTicks(delay, unit)) + ); } @Override - public void runTimer(Runnable runnable, long delay, long period, TimeUnit unit) { - this.runTimer(ThreadScope.SYNC, runnable, delay, period, unit); + public WrappedTask runTimer(Runnable runnable, long delay, long period, TimeUnit unit) { + return new WrappedBukkitTask( + this.scheduler.runTaskTimer( + plugin, runnable, + TimeConverter.toTicks(delay, unit), + TimeConverter.toTicks(period, unit)) + ); } @Override - public void runTimer(ThreadScope scope, Runnable runnable, long delay, long period, TimeUnit unit) { - switch (scope) { - case ASYNC: - this.scheduler.runTaskTimerAsynchronously(plugin, runnable, TimeConverter.toTicks(delay, unit), TimeConverter.toTicks(period, unit)); - break; - default: - this.scheduler.runTaskTimer(plugin, runnable, TimeConverter.toTicks(delay, unit), TimeConverter.toTicks(period, unit)); - break; - } + public WrappedTask runTimerAsync(Runnable runnable, long delay, long period, TimeUnit unit) { + return new WrappedBukkitTask( + this.scheduler.runTaskTimerAsynchronously( + plugin, runnable, + TimeConverter.toTicks(delay, unit), + TimeConverter.toTicks(period, unit)) + ); + } + + @Override + public CompletableFuture runAtLocation(Location location, Runnable runnable) { + CompletableFuture future = new CompletableFuture<>(); + + this.scheduler.runTask(plugin, () -> { + runnable.run(); + future.complete(null); + }); + + return future; } @Override - public void runInGlobalScope(ThreadScope scope, Runnable runnable) { - switch (scope) { - case ASYNC: - this.scheduler.runTaskAsynchronously(plugin, runnable); - break; - default: - this.scheduler.runTask(plugin, runnable); - break; - } + public WrappedTask runAtLocationLater(Location location, Runnable runnable, long delay, TimeUnit unit) { + return new WrappedBukkitTask( + this.scheduler.runTaskLater(plugin, runnable, TimeConverter.toTicks(delay, unit)) + ); + } + + @Override + public WrappedTask runAtLocationTimer(Location location, Runnable runnable, long delay, long period, TimeUnit unit) { + return new WrappedBukkitTask( + this.scheduler.runTaskTimer( + plugin, runnable, + TimeConverter.toTicks(delay, unit), + TimeConverter.toTicks(period, unit)) + ); + } + + @Override + public CompletableFuture runAtEntity(Entity entity, Runnable runnable) { + CompletableFuture future = new CompletableFuture<>(); + + this.scheduler.runTask(plugin, () -> { + runnable.run(); + future.complete(EntityTaskResult.SUCCESS); + }); + + return future; + } + + @Override + public CompletableFuture runAtEntityWithFallback(Entity entity, Runnable runnable, Runnable fallback) { + CompletableFuture future = new CompletableFuture<>(); + + this.scheduler.runTask(plugin, () -> { + if (entity.isValid()) { + runnable.run(); + future.complete(EntityTaskResult.SUCCESS); + } else { + fallback.run(); + future.complete(EntityTaskResult.ENTITY_RETIRED); + } + }); + + return future; } @Override - public void runInRegion(Location location, Runnable runnable) { - this.runInGlobalScope(ThreadScope.SYNC, runnable); + public WrappedTask runAtEntityLater(Entity entity, Runnable runnable, long delay, TimeUnit unit) { + return new WrappedBukkitTask( + this.scheduler.runTaskLater(plugin, runnable, TimeConverter.toTicks(delay, unit)) + ); } @Override - public void runInPlayerRegion(Player player, Runnable runnable) { - this.runInGlobalScope(ThreadScope.SYNC, runnable); + public WrappedTask runAtEntityTimer(Entity entity, Runnable runnable, long delay, long period, TimeUnit unit) { + return new WrappedBukkitTask( + this.scheduler.runTaskTimer( + plugin, runnable, + TimeConverter.toTicks(delay, unit), + TimeConverter.toTicks(period, unit)) + ); } } diff --git a/src/main/java/com/tcoded/folialib/impl/UnsupportedImplementation.java b/src/main/java/com/tcoded/folialib/impl/UnsupportedImplementation.java index f5202eb..b69e0d0 100644 --- a/src/main/java/com/tcoded/folialib/impl/UnsupportedImplementation.java +++ b/src/main/java/com/tcoded/folialib/impl/UnsupportedImplementation.java @@ -1,30 +1,28 @@ package com.tcoded.folialib.impl; import com.tcoded.folialib.FoliaLib; -import com.tcoded.folialib.enums.ThreadScope; -import org.bukkit.Location; import org.bukkit.plugin.java.JavaPlugin; -import java.util.concurrent.TimeUnit; import java.util.logging.Logger; public class UnsupportedImplementation extends SpigotImplementation { - private final JavaPlugin plugin; - private final Logger logger; - public UnsupportedImplementation(FoliaLib foliaLib) { super(foliaLib); - this.plugin = foliaLib.getPlugin(); - this.logger = plugin.getLogger(); + JavaPlugin plugin = foliaLib.getPlugin(); + Logger logger = plugin.getLogger(); - logger.warning(String.format( - "\n" + - "---------------------------------------------------------------------\n" + - "FoliaLib does not support this server software! (%s)\n" + - "FoliaLib will attempt to use the default spigot implementation.\n" + - "---------------------------------------------------------------------\n", - plugin.getServer().getVersion())); + logger.warning( + String.format(""" + + --------------------------------------------------------------------- + FoliaLib does not support this server software! (%s) + FoliaLib will attempt to use the default spigot implementation. + --------------------------------------------------------------------- + """, + plugin.getServer().getVersion() + ) + ); } } diff --git a/src/main/java/com/tcoded/folialib/wrapper/WrappedTask.java b/src/main/java/com/tcoded/folialib/wrapper/WrappedTask.java new file mode 100644 index 0000000..bae0e13 --- /dev/null +++ b/src/main/java/com/tcoded/folialib/wrapper/WrappedTask.java @@ -0,0 +1,14 @@ +package com.tcoded.folialib.wrapper; + +import org.bukkit.plugin.Plugin; + +@SuppressWarnings("unused") +public interface WrappedTask { + + void cancel(); + + boolean isCancelled(); + + Plugin getOwningPlugin(); + +} diff --git a/src/main/java/com/tcoded/folialib/wrapper/task/WrappedBukkitTask.java b/src/main/java/com/tcoded/folialib/wrapper/task/WrappedBukkitTask.java new file mode 100644 index 0000000..aa1a74a --- /dev/null +++ b/src/main/java/com/tcoded/folialib/wrapper/task/WrappedBukkitTask.java @@ -0,0 +1,29 @@ +package com.tcoded.folialib.wrapper.task; + +import com.tcoded.folialib.wrapper.WrappedTask; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitTask; + +public class WrappedBukkitTask implements WrappedTask { + + private final BukkitTask task; + + public WrappedBukkitTask(BukkitTask task) { + this.task = task; + } + + @Override + public void cancel() { + this.task.cancel(); + } + + @Override + public boolean isCancelled() { + return this.task.isCancelled(); + } + + @Override + public Plugin getOwningPlugin() { + return this.task.getOwner(); + } +} diff --git a/src/main/java/com/tcoded/folialib/wrapper/task/WrappedFoliaTask.java b/src/main/java/com/tcoded/folialib/wrapper/task/WrappedFoliaTask.java new file mode 100644 index 0000000..469a7ef --- /dev/null +++ b/src/main/java/com/tcoded/folialib/wrapper/task/WrappedFoliaTask.java @@ -0,0 +1,29 @@ +package com.tcoded.folialib.wrapper.task; + +import com.tcoded.folialib.wrapper.WrappedTask; +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import org.bukkit.plugin.Plugin; + +public class WrappedFoliaTask implements WrappedTask { + + private final ScheduledTask task; + + public WrappedFoliaTask(ScheduledTask task) { + this.task = task; + } + + @Override + public void cancel() { + this.task.cancel(); + } + + @Override + public boolean isCancelled() { + return this.task.isCancelled(); + } + + @Override + public Plugin getOwningPlugin() { + return this.task.getOwningPlugin(); + } +}