From f8035d909f281335e74937eb2b5ba5e7f7004104 Mon Sep 17 00:00:00 2001 From: HarvelsX <90945793+HarvelsX@users.noreply.github.com> Date: Thu, 3 Aug 2023 06:33:39 +0300 Subject: [PATCH 1/4] Add scheduler adapters to support Folia schedulers; --- .../scheduler/BukkitSchedulerAdapters.java | 30 +++++++++ .../adapters/BukkitSchedulerAdapter.java | 43 ++++++++++++ .../adapters/FoliaSchedulerAdapter.java | 38 +++++++++++ .../com/sk89q/worldedit/entity/Entity.java | 21 ++++++ .../platform/scheduler/SchedulerAdapter.java | 67 +++++++++++++++++++ 5 files changed, 199 insertions(+) create mode 100644 worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/BukkitSchedulerAdapters.java create mode 100644 worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/BukkitSchedulerAdapter.java create mode 100644 worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/FoliaSchedulerAdapter.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/scheduler/SchedulerAdapter.java diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/BukkitSchedulerAdapters.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/BukkitSchedulerAdapters.java new file mode 100644 index 0000000000..2f12adc217 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/BukkitSchedulerAdapters.java @@ -0,0 +1,30 @@ +package com.sk89q.worldedit.bukkit.scheduler; + +import com.sk89q.worldedit.bukkit.scheduler.adapters.BukkitSchedulerAdapter; +import com.sk89q.worldedit.bukkit.scheduler.adapters.FoliaSchedulerAdapter; +import com.sk89q.worldedit.extension.platform.scheduler.SchedulerAdapter; +import org.bukkit.plugin.Plugin; + +public final class BukkitSchedulerAdapters { + private final static boolean FOLIA_SUPPORT = foliaSupport(); + + private BukkitSchedulerAdapters() { + // Call only through a method + } + + public static SchedulerAdapter create(Plugin plugin) { + if (FOLIA_SUPPORT) { + return new FoliaSchedulerAdapter(plugin); + } + return new BukkitSchedulerAdapter(plugin); + } + + private static boolean foliaSupport() { + try { + Class.forName("io.papermc.paper.threadedregions.RegionizedServer"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } +} diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/BukkitSchedulerAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/BukkitSchedulerAdapter.java new file mode 100644 index 0000000000..eea3262e30 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/BukkitSchedulerAdapter.java @@ -0,0 +1,43 @@ +package com.sk89q.worldedit.bukkit.scheduler.adapters; + +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.extension.platform.scheduler.SchedulerAdapter; +import com.sk89q.worldedit.util.Location; +import org.bukkit.plugin.Plugin; + +public class BukkitSchedulerAdapter implements SchedulerAdapter { + + private final Plugin plugin; + @SuppressWarnings("deprecation") + private final org.bukkit.scheduler.BukkitScheduler scheduler; + + public BukkitSchedulerAdapter(final Plugin plugin) { + this.plugin = plugin; + this.scheduler = plugin.getServer().getScheduler(); + } + + @Override + public void runAsyncRate(Runnable runnable, long delay, long period) { + scheduler.runTaskTimerAsynchronously(plugin, runnable, delay, period); + } + + @Override + public void executeAtEntity(Entity entity, Runnable runnable) { + scheduler.runTask(plugin, runnable); + } + + @Override + public void runAtEntityDelayed(final Entity entity, final Runnable runnable, final long delay) { + scheduler.runTaskLater(plugin, runnable, delay); + } + + @Override + public void executeAtRegion(Location location, Runnable runnable) { + scheduler.runTask(plugin, runnable); + } + + @Override + public void cancelTasks() { + scheduler.cancelTasks(plugin); + } +} \ No newline at end of file diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/FoliaSchedulerAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/FoliaSchedulerAdapter.java new file mode 100644 index 0000000000..4c9783d333 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/FoliaSchedulerAdapter.java @@ -0,0 +1,38 @@ +package com.sk89q.worldedit.bukkit.scheduler.adapters; + +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.extension.platform.scheduler.SchedulerAdapter; +import com.sk89q.worldedit.util.Location; +import io.papermc.paper.threadedregions.scheduler.AsyncScheduler; +import io.papermc.paper.threadedregions.scheduler.RegionScheduler; +import org.bukkit.plugin.Plugin; + +import java.util.concurrent.TimeUnit; + +public class FoliaSchedulerAdapter implements SchedulerAdapter { + private final Plugin plugin; + private final AsyncScheduler asyncScheduler; + private final RegionScheduler regionScheduler; + + public FoliaSchedulerAdapter(final Plugin plugin) { + this.plugin = plugin; + this.asyncScheduler = plugin.getServer().getAsyncScheduler(); + this.regionScheduler = plugin.getServer().getRegionScheduler(); + } + + @Override + public void runAsyncRate(final Runnable runnable, final long delay, final long period) { + asyncScheduler.runAtFixedRate(plugin, task -> runnable.run(), delay * 50, period * 50, TimeUnit.MILLISECONDS); + } + + @Override + public void executeAtRegion(final Location location, final Runnable runnable) { + regionScheduler.execute(plugin, BukkitAdapter.adapt(location), runnable); + } + + @Override + public void cancelTasks() { + asyncScheduler.cancelTasks(plugin); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Entity.java b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Entity.java index ffa5dfd0fa..2f54ebc033 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Entity.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/entity/Entity.java @@ -54,4 +54,25 @@ public interface Entity extends Faceted, Locatable { */ boolean remove(); + /** + * Schedules a task. + * + * @see com.sk89q.worldedit.extension.platform.scheduler.SchedulerAdapter + * @param runnable The task to execute. + */ + default void executeAtEntity(Runnable runnable) { + throw new UnsupportedOperationException("Not implemented in this platform"); + } + + /** + * Schedules a task with the given delay. + * + * @see com.sk89q.worldedit.extension.platform.scheduler.SchedulerAdapter + * @param runnable The task to execute. + * @param delay The time delay to pass before the task should be executed, in ticks. + */ + default void runAtEntityDelayed(Runnable runnable, long delay) { + throw new UnsupportedOperationException("Not implemented in this platform"); + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/scheduler/SchedulerAdapter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/scheduler/SchedulerAdapter.java new file mode 100644 index 0000000000..4548f754cc --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/scheduler/SchedulerAdapter.java @@ -0,0 +1,67 @@ +package com.sk89q.worldedit.extension.platform.scheduler; + +import com.sk89q.worldedit.entity.Entity; +import com.sk89q.worldedit.util.Location; + +public interface SchedulerAdapter { + + /** + * Schedules the specified task to be executed asynchronously after the delay has passed, + * and then periodically executed with the specified period. + * + * @param runnable The task to execute. + * @param delay The time delay to pass before the task should be executed. + * @param period The time between task executions after the first execution of the task. + */ + void runAsyncRate(Runnable runnable, long delay, long period); + + /** + * Schedules a task. If the task failed to schedule because the scheduler is retired (entity removed), + * then returns {@code false}. Otherwise, either the run 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 entity The entity relative to which the scheduler is obtained. + * @param runnable The task to execute. + */ + default void executeAtEntity(Entity entity, Runnable runnable) { + entity.executeAtEntity(runnable); + } + + /** + * Schedules a task with the given delay. If the task failed to schedule because the scheduler is retired (entity removed), + * then returns {@code false}. Otherwise, either the run 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 entity The entity relative to which the scheduler is obtained. + * @param runnable The task to execute. + * @param delay The time delay to pass before the task should be executed, in ticks. + */ + default void runAtEntityDelayed(Entity entity, Runnable runnable, long delay) { + entity.runAtEntityDelayed(runnable, delay); + } + + /** + * Schedules a task to be executed on the region which owns the location. + * + * @param location The location at which the region executing should own. + * @param runnable The task to execute. + */ + void executeAtRegion(Location location, Runnable runnable); + + /** + * Attempts to cancel all tasks scheduled by the plugin. + */ + void cancelTasks(); +} \ No newline at end of file From 1ed010a9e0c1c305e916c0e656b8568e72885fdd Mon Sep 17 00:00:00 2001 From: HarvelsX <90945793+HarvelsX@users.noreply.github.com> Date: Thu, 3 Aug 2023 06:37:36 +0300 Subject: [PATCH 2/4] Use scheduler adapters instead of scheduler in Bukkit; Implement scheduler methods in Bukkit Entity; --- .../bukkit/BukkitBlockCommandSender.java | 8 +++----- .../com/sk89q/worldedit/bukkit/BukkitEntity.java | 16 ++++++++++++++++ .../worldedit/bukkit/BukkitServerInterface.java | 4 +++- .../sk89q/worldedit/bukkit/WorldEditPlugin.java | 9 ++++++++- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java index 12840c4dd7..ccd162ff8a 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockCommandSender.java @@ -156,11 +156,9 @@ public boolean isActive() { updateActive(); } else { // we should update it eventually - Bukkit.getScheduler().callSyncMethod(plugin, - () -> { - updateActive(); - return null; - }); + plugin.getScheduler().executeAtRegion( + BukkitAdapter.adapt(sender.getBlock().getLocation()), + this::updateActive); } return active; } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitEntity.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitEntity.java index e719902862..a71d8bab62 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitEntity.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitEntity.java @@ -125,4 +125,20 @@ public T getFacet(Class cls) { return null; } } + + @Override + public void executeAtEntity(Runnable runnable) { + org.bukkit.entity.Entity entity = entityRef.get(); + if (entity != null) { + entity.getScheduler().run(WorldEditPlugin.getInstance(), task -> runnable.run(), null); + } + } + + @Override + public void runAtEntityDelayed(Runnable runnable, long delay) { + org.bukkit.entity.Entity entity = entityRef.get(); + if (entity != null) { + entity.getScheduler().runDelayed(WorldEditPlugin.getInstance(), task -> runnable.run(), null, delay); + } + } } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 1a9b9c8ff2..dfed974e8d 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -120,7 +120,9 @@ public void reload() { @Override public int schedule(long delay, long period, Runnable task) { - return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, task, delay, period); + plugin.getScheduler().runAsyncRate(task, delay, period); + return 0; +// return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, task, delay, period); } @Override diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index b338b2498f..ed93b46045 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -30,6 +30,7 @@ import com.sk89q.worldedit.bukkit.adapter.AdapterLoadException; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplLoader; +import com.sk89q.worldedit.bukkit.scheduler.BukkitSchedulerAdapters; import com.sk89q.worldedit.event.platform.CommandEvent; import com.sk89q.worldedit.event.platform.CommandSuggestionEvent; import com.sk89q.worldedit.event.platform.PlatformReadyEvent; @@ -40,6 +41,7 @@ import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.extension.platform.scheduler.SchedulerAdapter; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.internal.anvil.ChunkDeleter; import com.sk89q.worldedit.internal.command.CommandUtil; @@ -119,6 +121,7 @@ public class WorldEditPlugin extends JavaPlugin implements TabCompleter { private final SimpleLifecycled adapter = SimpleLifecycled.invalid(); + private final SchedulerAdapter scheduler = BukkitSchedulerAdapters.create(this); private BukkitServerInterface platform; private BukkitConfiguration config; @@ -321,7 +324,7 @@ public void onDisable() { if (config != null) { config.unload(); } - this.getServer().getScheduler().cancelTasks(this); + scheduler.cancelTasks(); } /** @@ -517,6 +520,10 @@ BukkitImplAdapter getBukkitImplAdapter() { return adapter.value().orElse(null); } + SchedulerAdapter getScheduler() { + return scheduler; + } + private class WorldInitListener implements Listener { private boolean loaded = false; From 1a447b988942bf54a2f9f9943b3ff7ee2c207768 Mon Sep 17 00:00:00 2001 From: HarvelsX <90945793+HarvelsX@users.noreply.github.com> Date: Thu, 3 Aug 2023 06:37:54 +0300 Subject: [PATCH 3/4] Mark bukkit plugin supported folia; --- worldedit-bukkit/src/main/resources/plugin.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worldedit-bukkit/src/main/resources/plugin.yml b/worldedit-bukkit/src/main/resources/plugin.yml index aa19044bb0..d1e505931b 100644 --- a/worldedit-bukkit/src/main/resources/plugin.yml +++ b/worldedit-bukkit/src/main/resources/plugin.yml @@ -5,4 +5,6 @@ load: STARTUP api-version: 1.13 softdepend: [Vault] author: EngineHub -website: https://enginehub.org/worldedit \ No newline at end of file +website: https://enginehub.org/worldedit + +folia-supported: true From 3e4a6a07090a7db5e88c7d78b2dc91ca9bbe2b7b Mon Sep 17 00:00:00 2001 From: HarvelsX <90945793+HarvelsX@users.noreply.github.com> Date: Thu, 3 Aug 2023 07:36:43 +0300 Subject: [PATCH 4/4] Fix licenses; --- .../scheduler/BukkitSchedulerAdapters.java | 19 +++++++++++++++++++ .../adapters/BukkitSchedulerAdapter.java | 19 +++++++++++++++++++ .../adapters/FoliaSchedulerAdapter.java | 19 +++++++++++++++++++ .../platform/scheduler/SchedulerAdapter.java | 19 +++++++++++++++++++ 4 files changed, 76 insertions(+) diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/BukkitSchedulerAdapters.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/BukkitSchedulerAdapters.java index 2f12adc217..8fc28659cb 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/BukkitSchedulerAdapters.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/BukkitSchedulerAdapters.java @@ -1,3 +1,22 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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.sk89q.worldedit.bukkit.scheduler; import com.sk89q.worldedit.bukkit.scheduler.adapters.BukkitSchedulerAdapter; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/BukkitSchedulerAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/BukkitSchedulerAdapter.java index eea3262e30..e76bec07df 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/BukkitSchedulerAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/BukkitSchedulerAdapter.java @@ -1,3 +1,22 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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.sk89q.worldedit.bukkit.scheduler.adapters; import com.sk89q.worldedit.entity.Entity; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/FoliaSchedulerAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/FoliaSchedulerAdapter.java index 4c9783d333..0acc76c931 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/FoliaSchedulerAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/scheduler/adapters/FoliaSchedulerAdapter.java @@ -1,3 +1,22 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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.sk89q.worldedit.bukkit.scheduler.adapters; import com.sk89q.worldedit.bukkit.BukkitAdapter; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/scheduler/SchedulerAdapter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/scheduler/SchedulerAdapter.java index 4548f754cc..e02f899352 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/scheduler/SchedulerAdapter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/scheduler/SchedulerAdapter.java @@ -1,3 +1,22 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * 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.sk89q.worldedit.extension.platform.scheduler; import com.sk89q.worldedit.entity.Entity;