diff --git a/Essentials/build.gradle b/Essentials/build.gradle index 2a72af81529..4d5495b163b 100644 --- a/Essentials/build.gradle +++ b/Essentials/build.gradle @@ -18,6 +18,7 @@ dependencies { // Providers api project(':providers:BaseProviders') api project(':providers:PaperProvider') + api project(':providers:FoliaProvider') api(project(':providers:NMSReflectionProvider')) { exclude group: "org.bukkit", module: "bukkit" } @@ -45,6 +46,7 @@ shadowJar { include (dependency('org.checkerframework:checker-qual')) include (project(':providers:BaseProviders')) include (project(':providers:PaperProvider')) + include (project(':providers:FoliaProvider')) include (project(':providers:NMSReflectionProvider')) include (project(':providers:1_8Provider')) include (project(':providers:1_12Provider')) diff --git a/Essentials/src/main/java/com/earth2me/essentials/AsyncTeleport.java b/Essentials/src/main/java/com/earth2me/essentials/AsyncTeleport.java index 19ab4581815..25a334df03b 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/AsyncTeleport.java +++ b/Essentials/src/main/java/com/earth2me/essentials/AsyncTeleport.java @@ -141,19 +141,6 @@ public void nowUnsafe(Location loc, TeleportCause cause, CompletableFuture taskLock = new CompletableFuture<>(); - Bukkit.getScheduler().runTask(ess, () -> { - runnable.run(); - taskLock.complete(new Object()); - }); - taskLock.get(); - } - protected void nowAsync(final IUser teleportee, final ITarget target, final TeleportCause cause, final CompletableFuture future) { cancel(false); @@ -171,8 +158,8 @@ protected void nowAsync(final IUser teleportee, final ITarget target, final Tele } try { - runOnMain(() -> teleportee.getBase().eject()); //EntityDismountEvent requires a sync context. - } catch (final ExecutionException | InterruptedException e) { + ess.ensureEntity(teleportee.getBase(), () -> teleportee.getBase().eject()); //EntityDismountEvent requires a sync context. + } catch (final RuntimeException e) { future.completeExceptionally(e); return; } @@ -192,8 +179,7 @@ protected void nowAsync(final IUser teleportee, final ITarget target, final Tele if (LocationUtil.isBlockUnsafeForUser(ess, teleportee, chunk.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) { if (ess.getSettings().isTeleportSafetyEnabled()) { if (ess.getSettings().isForceDisableTeleportSafety()) { - //The chunk we're teleporting to is 100% going to be loaded here, no need to teleport async. - teleportee.getBase().teleport(loc, cause); + PaperLib.teleportAsync(teleportee.getBase(), loc, cause); } else { try { //There's a chance the safer location is outside the loaded chunk so still teleport async here. @@ -209,8 +195,7 @@ protected void nowAsync(final IUser teleportee, final ITarget target, final Tele } } else { if (ess.getSettings().isForceDisableTeleportSafety()) { - //The chunk we're teleporting to is 100% going to be loaded here, no need to teleport async. - teleportee.getBase().teleport(loc, cause); + PaperLib.teleportAsync(teleportee.getBase(), loc, cause); } else { if (ess.getSettings().isTeleportToCenterLocation()) { loc = LocationUtil.getRoundedDestination(loc); diff --git a/Essentials/src/main/java/com/earth2me/essentials/AsyncTimedTeleport.java b/Essentials/src/main/java/com/earth2me/essentials/AsyncTimedTeleport.java index e38ee162528..df3dc6932dc 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/AsyncTimedTeleport.java +++ b/Essentials/src/main/java/com/earth2me/essentials/AsyncTimedTeleport.java @@ -2,6 +2,7 @@ import net.ess3.api.IEssentials; import net.ess3.api.IUser; +import net.ess3.provider.SchedulingProvider; import org.bukkit.Location; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; @@ -30,7 +31,7 @@ public class AsyncTimedTeleport implements Runnable { private final boolean timer_canMove; private final Trade timer_chargeFor; private final TeleportCause timer_cause; - private int timer_task; + private SchedulingProvider.EssentialsTask timer_task; private double timer_health; AsyncTimedTeleport(final IUser user, final IEssentials ess, final AsyncTeleport teleport, final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) { @@ -54,7 +55,7 @@ public class AsyncTimedTeleport implements Runnable { this.timer_respawn = respawn; this.timer_canMove = user.isAuthorized("essentials.teleport.timer.move"); - timer_task = ess.runTaskTimerAsynchronously(this, 20, 20).getTaskId(); + timer_task = ess.runTaskTimerAsynchronously(this, 20, 20); if (future != null) { this.parentFuture = future; @@ -141,16 +142,16 @@ public void run() { } } - ess.scheduleSyncDelayedTask(new DelayedTeleportTask()); + ess.scheduleEntityDelayedTask(teleportOwner.getBase(), new DelayedTeleportTask()); } //If we need to cancelTimer a pending teleportPlayer call this method void cancelTimer(final boolean notifyUser) { - if (timer_task == -1) { + if (timer_task == null) { return; } try { - ess.getServer().getScheduler().cancelTask(timer_task); + timer_task.cancel(); if (notifyUser) { teleportOwner.sendMessage(tl("pendingTeleportCancelled")); if (timer_teleportee != null && !timer_teleportee.equals(teleportOwner.getBase().getUniqueId())) { @@ -158,7 +159,7 @@ void cancelTimer(final boolean notifyUser) { } } } finally { - timer_task = -1; + timer_task = null; } } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/Backup.java b/Essentials/src/main/java/com/earth2me/essentials/Backup.java index 837170df7ca..8d2970cd3b5 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Backup.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Backup.java @@ -1,6 +1,7 @@ package com.earth2me.essentials; import net.ess3.api.IEssentials; +import net.ess3.provider.SchedulingProvider; import org.bukkit.Server; import org.bukkit.command.CommandSender; @@ -18,7 +19,7 @@ public class Backup implements Runnable { private transient final IEssentials ess; private final AtomicBoolean pendingShutdown = new AtomicBoolean(false); private transient boolean running = false; - private transient int taskId = -1; + private transient SchedulingProvider.EssentialsTask task = null; private transient boolean active = false; private transient CompletableFuture taskLock = null; @@ -36,10 +37,10 @@ public void onPlayerJoin() { public synchronized void stopTask() { running = false; - if (taskId != -1) { - server.getScheduler().cancelTask(taskId); + if (task != null) { + task.cancel(); } - taskId = -1; + task = null; } private synchronized void startTask() { @@ -48,7 +49,7 @@ private synchronized void startTask() { if (interval < 1200) { return; } - taskId = ess.scheduleSyncRepeatingTask(this, interval, interval); + task = ess.scheduleGlobalRepeatingTask(this, interval, interval); running = true; } } @@ -123,7 +124,7 @@ public void run() { } if (!pendingShutdown.get()) { - ess.scheduleSyncDelayedTask(new BackupEnableSaveTask()); + ess.scheduleGlobalDelayedTask(new BackupEnableSaveTask()); } } }); diff --git a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java index c36da635b34..8c24371d902 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java @@ -65,6 +65,7 @@ import net.ess3.provider.PersistentDataProvider; import net.ess3.provider.PotionMetaProvider; import net.ess3.provider.ProviderListener; +import net.ess3.provider.SchedulingProvider; import net.ess3.provider.SerializationProvider; import net.ess3.provider.ServerStateProvider; import net.ess3.provider.SignDataProvider; @@ -77,9 +78,11 @@ import net.ess3.provider.providers.BasePotionDataProvider; import net.ess3.provider.providers.BlockMetaSpawnerItemProvider; import net.ess3.provider.providers.BukkitMaterialTagProvider; +import net.ess3.provider.providers.BukkitSchedulingProvider; import net.ess3.provider.providers.BukkitSpawnerBlockProvider; import net.ess3.provider.providers.FixedHeightWorldInfoProvider; import net.ess3.provider.providers.FlatSpawnEggProvider; +import net.ess3.provider.providers.FoliaSchedulingProvider; import net.ess3.provider.providers.LegacyItemUnbreakableProvider; import net.ess3.provider.providers.LegacyPotionMetaProvider; import net.ess3.provider.providers.LegacySpawnEggProvider; @@ -95,6 +98,7 @@ import net.ess3.provider.providers.PaperServerStateProvider; import net.essentialsx.api.v2.services.BalanceTop; import net.essentialsx.api.v2.services.mail.MailService; +import org.bukkit.Location; import org.bukkit.Server; import org.bukkit.World; import org.bukkit.block.Block; @@ -104,6 +108,7 @@ import org.bukkit.command.PluginCommand; import org.bukkit.command.PluginIdentifiableCommand; import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.EventHandler; @@ -120,8 +125,6 @@ import org.bukkit.plugin.ServicePriority; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPluginLoader; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; import java.io.File; import java.io.IOException; @@ -135,6 +138,8 @@ import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.function.Predicate; import java.util.logging.Level; import java.util.logging.Logger; @@ -182,6 +187,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { private transient ItemUnbreakableProvider unbreakableProvider; private transient WorldInfoProvider worldInfoProvider; private transient SignDataProvider signDataProvider; + private transient SchedulingProvider schedulingProvider; private transient Kits kits; private transient RandomTeleport randomTeleport; private transient UpdateChecker updateChecker; @@ -209,6 +215,7 @@ public ISettings getSettings() { public void setupForTesting(final Server server) throws IOException, InvalidDescriptionException { LOGGER = new BaseLoggerProvider(this, BUKKIT_LOGGER); + schedulingProvider = new BukkitSchedulingProvider(this); final File dataFolder = File.createTempFile("essentialstest", ""); if (!dataFolder.delete()) { throw new IOException(); @@ -358,6 +365,12 @@ public void onEnable() { confList.add(jails); execTimer.mark("Init(Jails)"); + if (VersionUtil.FOLIA) { + schedulingProvider = new FoliaSchedulingProvider(this); + } else { + schedulingProvider = new BukkitSchedulingProvider(this); + } + EconomyLayers.onEnable(this); //Spawner item provider only uses one but it's here for legacy... @@ -454,6 +467,7 @@ public void onEnable() { } execTimer.mark("Init(Providers)"); + registerListeners(getServer().getPluginManager()); reload(); // The item spawn blacklist is loaded with all other settings, before the item @@ -464,7 +478,7 @@ public void onEnable() { alternativeCommandsHandler = new AlternativeCommandsHandler(this); timer = new EssentialsTimer(this); - scheduleSyncRepeatingTask(timer, 1000, 50); + scheduleGlobalRepeatingTask(timer, 1000, 50); Economy.setEss(this); execTimer.mark("RegHandler"); @@ -513,8 +527,6 @@ public void saveConfig() { } private void registerListeners(final PluginManager pm) { - HandlerList.unregisterAll(this); - if (getSettings().isDebug()) { LOGGER.log(Level.INFO, "Registering Listeners"); } @@ -616,9 +628,6 @@ public void reload() { command.setUsage(tl(commandName + "CommandUsage")); } } - - final PluginManager pm = getServer().getPluginManager(); - registerListeners(pm); } private IEssentialsCommand loadCommand(final String path, final String name, final IEssentialsModule module, final ClassLoader classLoader) throws Exception { @@ -881,11 +890,6 @@ public void showError(final CommandSource sender, final Throwable exception, fin } } - @Override - public BukkitScheduler getScheduler() { - return this.getServer().getScheduler(); - } - @Override public IJails getJails() { return jails; @@ -1144,33 +1148,135 @@ private int broadcastMessage(final IUser sender, final String permission, final } @Override - public BukkitTask runTaskAsynchronously(final Runnable run) { - return this.getScheduler().runTaskAsynchronously(this, run); + public void scheduleInitTask(Runnable runnable) { + schedulingProvider.registerInitTask(runnable); + } + + @Override + public void runTaskAsynchronously(final Runnable run) { + schedulingProvider.runAsyncTask(run); + } + + @Override + public void runTaskLaterAsynchronously(final Runnable run, final long delay) { + schedulingProvider.runAsyncTaskLater(run, delay); + } + + @Override + public SchedulingProvider.EssentialsTask runTaskTimerAsynchronously(final Runnable run, final long delay, final long period) { + return schedulingProvider.runAsyncTaskRepeating(run, delay, period); + } + + @Override + public void scheduleEntityDelayedTask(Entity entity, Runnable run) { + schedulingProvider.runEntityTask(entity, run); + } + + @Override + public SchedulingProvider.EssentialsTask scheduleEntityDelayedTask(Entity entity, Runnable run, long delay) { + return schedulingProvider.runEntityTask(entity, run, delay); + } + + @Override + public SchedulingProvider.EssentialsTask scheduleEntityRepeatingTask(Entity entity, Runnable run, long delay, long period) { + return schedulingProvider.runEntityTaskRepeating(entity, run, delay, period); + } + + @Override + public void scheduleLocationDelayedTask(Location location, Runnable run) { + schedulingProvider.runLocationalTask(location, run); + } + + @Override + public void scheduleLocationDelayedTask(Location location, Runnable run, long delay) { + schedulingProvider.runLocationalTask(location, run, delay); + } + + @Override + public SchedulingProvider.EssentialsTask scheduleLocationRepeatingTask(Location location, Runnable run, long delay, long period) { + return schedulingProvider.runLocationalTaskRepeating(location, run, delay, period); } @Override - public BukkitTask runTaskLaterAsynchronously(final Runnable run, final long delay) { - return this.getScheduler().runTaskLaterAsynchronously(this, run, delay); + public void scheduleGlobalDelayedTask(Runnable run, long delay) { + schedulingProvider.runGlobalLocationalTask(run, delay); } @Override - public BukkitTask runTaskTimerAsynchronously(final Runnable run, final long delay, final long period) { - return this.getScheduler().runTaskTimerAsynchronously(this, run, delay, period); + public SchedulingProvider.EssentialsTask scheduleGlobalRepeatingTask(Runnable run, long delay, long period) { + return schedulingProvider.runGlobalLocationalTaskRepeating(run, delay, period); } @Override - public int scheduleSyncDelayedTask(final Runnable run) { - return this.getScheduler().scheduleSyncDelayedTask(this, run); + public boolean isEntityThread(Entity entity) { + return schedulingProvider.isEntityThread(entity); } @Override - public int scheduleSyncDelayedTask(final Runnable run, final long delay) { - return this.getScheduler().scheduleSyncDelayedTask(this, run, delay); + public boolean isRegionThread(Location location) { + return schedulingProvider.isRegionThread(location); } @Override - public int scheduleSyncRepeatingTask(final Runnable run, final long delay, final long period) { - return this.getScheduler().scheduleSyncRepeatingTask(this, run, delay, period); + public boolean isGlobalThread() { + return schedulingProvider.isGlobalThread(); + } + + @Override + public void ensureEntity(Entity entity, Runnable runnable) { + if (isEntityThread(entity)) { + runnable.run(); + return; + } + + final CompletableFuture taskLock = new CompletableFuture<>(); + scheduleEntityDelayedTask(entity, () -> { + runnable.run(); + taskLock.complete(new Object()); + }); + try { + taskLock.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + + @Override + public void ensureRegion(Location location, Runnable runnable) { + if (isRegionThread(location)) { + runnable.run(); + return; + } + + final CompletableFuture taskLock = new CompletableFuture<>(); + scheduleLocationDelayedTask(location, () -> { + runnable.run(); + taskLock.complete(new Object()); + }); + try { + taskLock.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + + @Override + public void ensureGlobal(Runnable runnable) { + if (isGlobalThread()) { + runnable.run(); + return; + } + + final CompletableFuture taskLock = new CompletableFuture<>(); + scheduleGlobalDelayedTask(() -> { + runnable.run(); + taskLock.complete(new Object()); + }); + try { + taskLock.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } } @Override diff --git a/Essentials/src/main/java/com/earth2me/essentials/EssentialsBlockListener.java b/Essentials/src/main/java/com/earth2me/essentials/EssentialsBlockListener.java index c0a861ce737..aa44551174b 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/EssentialsBlockListener.java +++ b/Essentials/src/main/java/com/earth2me/essentials/EssentialsBlockListener.java @@ -42,7 +42,7 @@ public void onBlockPlace(final BlockPlaceEvent event) { final User user = ess.getUser(event.getPlayer()); if (user.hasUnlimited(is) && user.getBase().getGameMode() == GameMode.SURVIVAL) { - ess.scheduleSyncDelayedTask(() -> { + ess.scheduleEntityDelayedTask(user.getBase(), () -> { if (is != null && is.getType() != null && !MaterialUtil.isAir(is.getType())) { final ItemStack cloneIs = is.clone(); cloneIs.setAmount(1); diff --git a/Essentials/src/main/java/com/earth2me/essentials/EssentialsEntityListener.java b/Essentials/src/main/java/com/earth2me/essentials/EssentialsEntityListener.java index a1ab286b984..26ca4433516 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/EssentialsEntityListener.java +++ b/Essentials/src/main/java/com/earth2me/essentials/EssentialsEntityListener.java @@ -112,7 +112,7 @@ public void run() { } } - ess.scheduleSyncDelayedTask(new PowerToolInteractTask()); + ess.scheduleEntityDelayedTask(attacker.getBase(), new PowerToolInteractTask()); event.setCancelled(true); return; diff --git a/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java b/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java index b4ba60e2fef..9ce631bc845 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java +++ b/Essentials/src/main/java/com/earth2me/essentials/EssentialsPlayerListener.java @@ -15,6 +15,7 @@ import net.ess3.api.IEssentials; import net.ess3.api.events.AfkStatusChangeEvent; import net.ess3.provider.CommandSendListenerProvider; +import net.ess3.provider.SchedulingProvider; import net.ess3.provider.providers.BukkitCommandSendListenerProvider; import net.ess3.provider.providers.PaperCommandSendListenerProvider; import net.essentialsx.api.v2.events.AsyncUserDataLoadEvent; @@ -79,7 +80,7 @@ public class EssentialsPlayerListener implements Listener, FakeAccessor { private final transient IEssentials ess; - private final ConcurrentHashMap pendingMotdTasks = new ConcurrentHashMap<>(); + private final ConcurrentHashMap pendingMotdTasks = new ConcurrentHashMap<>(); public EssentialsPlayerListener(final IEssentials parent) { this.ess = parent; @@ -258,9 +259,9 @@ public void onPlayerMove(final PlayerMoveEvent event) { public void onPlayerQuit(final PlayerQuitEvent event) { final User user = ess.getUser(event.getPlayer()); - final Integer pendingId = pendingMotdTasks.remove(user.getUUID()); - if (pendingId != null) { - ess.getScheduler().cancelTask(pendingId); + final SchedulingProvider.EssentialsTask pendingTask = pendingMotdTasks.remove(user.getUUID()); + if (pendingTask != null) { + pendingTask.cancel(); } if (hideJoinQuitMessages() || (ess.getSettings().allowSilentJoinQuit() && user.isAuthorized("essentials.silentquit"))) { @@ -414,7 +415,7 @@ public void run() { final int motdDelay = ess.getSettings().getMotdDelay() / 50; final DelayMotdTask motdTask = new DelayMotdTask(user); if (motdDelay > 0) { - pendingMotdTasks.put(user.getUUID(), ess.scheduleSyncDelayedTask(motdTask, motdDelay)); + pendingMotdTasks.put(user.getUUID(), ess.scheduleEntityDelayedTask(user.getBase(), motdTask, motdDelay)); } else { motdTask.run(); } @@ -506,7 +507,7 @@ public void run() { } } - ess.scheduleSyncDelayedTask(new DelayJoinTask()); + ess.scheduleEntityDelayedTask(player, new DelayJoinTask()); } // Makes the compass item ingame always point to the first essentials home. #EasterEgg @@ -592,7 +593,7 @@ public void onPlayerBucketEmpty(final PlayerBucketEmptyEvent event) { final User user = ess.getUser(event.getPlayer()); if (user.hasUnlimited(new ItemStack(event.getBucket()))) { event.getItemStack().setType(event.getBucket()); - ess.scheduleSyncDelayedTask(user.getBase()::updateInventory); + ess.scheduleEntityDelayedTask(user.getBase(), user.getBase()::updateInventory); } } @@ -837,7 +838,7 @@ public void run() { } } - ess.scheduleSyncDelayedTask(new DelayedClickJumpTask()); + ess.scheduleEntityDelayedTask(user.getBase(), new DelayedClickJumpTask()); } catch (final Exception ex) { if (ess.getSettings().isDebug()) { ess.getLogger().log(Level.WARNING, ex.getMessage(), ex); @@ -868,7 +869,7 @@ public void run() { } } - ess.scheduleSyncDelayedTask(new PowerToolUseTask()); + ess.scheduleEntityDelayedTask(user.getBase(), new PowerToolUseTask()); } } @@ -929,7 +930,7 @@ public void onInventoryClickEvent(final InventoryClickEvent event) { } if (refreshPlayer != null) { - ess.scheduleSyncDelayedTask(refreshPlayer::updateInventory, 1); + ess.scheduleEntityDelayedTask(refreshPlayer, refreshPlayer::updateInventory, 1); } } @@ -971,7 +972,7 @@ public void onInventoryCloseEvent(final InventoryCloseEvent event) { } if (refreshPlayer != null) { - ess.scheduleSyncDelayedTask(refreshPlayer::updateInventory, 1); + ess.scheduleEntityDelayedTask(refreshPlayer, refreshPlayer::updateInventory, 1); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/EssentialsTimer.java b/Essentials/src/main/java/com/earth2me/essentials/EssentialsTimer.java index fbc96e1d214..edab1924bea 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/EssentialsTimer.java +++ b/Essentials/src/main/java/com/earth2me/essentials/EssentialsTimer.java @@ -5,7 +5,6 @@ import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedList; import java.util.Set; import java.util.UUID; import java.util.logging.Level; @@ -13,36 +12,19 @@ public class EssentialsTimer implements Runnable { private final transient IEssentials ess; private final transient Set onlineUsers = new HashSet<>(); // Field is necessary for hidden users - private final LinkedList history = new LinkedList<>(); - @SuppressWarnings("FieldCanBeLocal") - private final long maxTime = 10 * 1000000; - @SuppressWarnings("FieldCanBeLocal") - private final long tickInterval = 50; - private transient long lastPoll = System.nanoTime(); + private static final long maxTime = 10 * 1000000; private int skip1 = 0; private int skip2 = 0; EssentialsTimer(final IEssentials ess) { this.ess = ess; - history.add(20d); } @Override public void run() { final long startTime = System.nanoTime(); final long currentTime = System.currentTimeMillis(); - long timeSpent = (startTime - lastPoll) / 1000; - if (timeSpent == 0) { - timeSpent = 1; - } - if (history.size() > 10) { - history.remove(); - } - final double tps = tickInterval * 1000000.0 / timeSpent; - if (tps <= 21) { - history.add(tps); - } - lastPoll = startTime; + int count = 0; onlineUsers.clear(); for (final Player player : ess.getOnlinePlayers()) { @@ -99,14 +81,4 @@ public void run() { user.resetInvulnerabilityAfterTeleport(); } } - - public double getAverageTPS() { - double avg = 0; - for (final Double f : history) { - if (f != null) { - avg += f; - } - } - return avg / history.size(); - } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/IEssentials.java b/Essentials/src/main/java/com/earth2me/essentials/IEssentials.java index d8916a958b6..4c1c22c164c 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/IEssentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/IEssentials.java @@ -15,6 +15,7 @@ import net.ess3.provider.KnownCommandsProvider; import net.ess3.provider.MaterialTagProvider; import net.ess3.provider.PersistentDataProvider; +import net.ess3.provider.SchedulingProvider; import net.ess3.provider.SerializationProvider; import net.ess3.provider.ServerStateProvider; import net.ess3.provider.SignDataProvider; @@ -24,15 +25,15 @@ import net.ess3.provider.WorldInfoProvider; import net.essentialsx.api.v2.services.BalanceTop; import net.essentialsx.api.v2.services.mail.MailService; +import org.bukkit.Location; import org.bukkit.Server; import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.PluginCommand; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitScheduler; -import org.bukkit.scheduler.BukkitTask; import java.util.Collection; import java.util.List; @@ -82,8 +83,6 @@ public interface IEssentials extends Plugin { ISettings getSettings(); - BukkitScheduler getScheduler(); - IJails getJails(); IWarps getWarps(); @@ -98,17 +97,45 @@ public interface IEssentials extends Plugin { UpdateChecker getUpdateChecker(); - BukkitTask runTaskAsynchronously(Runnable run); + void runTaskAsynchronously(Runnable run); + + void runTaskLaterAsynchronously(Runnable run, long delay); + + SchedulingProvider.EssentialsTask runTaskTimerAsynchronously(Runnable run, long delay, long period); + + void scheduleEntityDelayedTask(Entity entity, Runnable run); + + SchedulingProvider.EssentialsTask scheduleEntityDelayedTask(Entity entity, Runnable run, long delay); + + SchedulingProvider.EssentialsTask scheduleEntityRepeatingTask(Entity entity, Runnable run, long delay, long period); + + void scheduleLocationDelayedTask(Location location, Runnable run); + + void scheduleLocationDelayedTask(Location location, Runnable run, long delay); + + SchedulingProvider.EssentialsTask scheduleLocationRepeatingTask(Location location, Runnable run, long delay, long period); + + default void scheduleGlobalDelayedTask(Runnable run) { + scheduleGlobalDelayedTask(run, 1); + } + + void scheduleGlobalDelayedTask(Runnable run, long delay); + + SchedulingProvider.EssentialsTask scheduleGlobalRepeatingTask(Runnable run, long delay, long period); + + void scheduleInitTask(Runnable runnable); + + boolean isEntityThread(Entity entity); - BukkitTask runTaskLaterAsynchronously(Runnable run, long delay); + boolean isRegionThread(Location location); - BukkitTask runTaskTimerAsynchronously(Runnable run, long delay, long period); + boolean isGlobalThread(); - int scheduleSyncDelayedTask(Runnable run); + void ensureEntity(Entity entity, Runnable runnable); - int scheduleSyncDelayedTask(Runnable run, long delay); + void ensureRegion(Location location, Runnable runnable); - int scheduleSyncRepeatingTask(Runnable run, long delay, long period); + void ensureGlobal(Runnable runnable); PermissionsHandler getPermissionsHandler(); diff --git a/Essentials/src/main/java/com/earth2me/essentials/IUser.java b/Essentials/src/main/java/com/earth2me/essentials/IUser.java index 2625b1fc8c2..46094dd064d 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/IUser.java +++ b/Essentials/src/main/java/com/earth2me/essentials/IUser.java @@ -3,7 +3,6 @@ import com.earth2me.essentials.api.IAsyncTeleport; import com.earth2me.essentials.commands.IEssentialsCommand; import com.earth2me.essentials.config.entities.CommandCooldown; -import net.ess3.api.ITeleport; import net.ess3.api.MaxMoneyException; import net.ess3.api.events.AfkStatusChangeEvent; import net.essentialsx.api.v2.services.mail.MailMessage; @@ -15,7 +14,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; import java.math.BigDecimal; - import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -71,12 +69,6 @@ public interface IUser { @Deprecated boolean hasOutstandingTeleportRequest(); - /** - * @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.api.IAsyncTeleport IAsyncTeleport} with {@link IUser#getAsyncTeleport()} - */ - @Deprecated - ITeleport getTeleport(); - IAsyncTeleport getAsyncTeleport(); BigDecimal getMoney(); diff --git a/Essentials/src/main/java/com/earth2me/essentials/Jails.java b/Essentials/src/main/java/com/earth2me/essentials/Jails.java index 123d159f3ac..677389349f8 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Jails.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Jails.java @@ -140,28 +140,6 @@ public void removeJail(String jail) throws Exception { } } - /** - * @deprecated This method does not use asynchronous teleportation. Use {@link Jails#sendToJail(IUser, String, CompletableFuture)} - */ - @SuppressWarnings("deprecation") - @Override - @Deprecated - public void sendToJail(final IUser user, String jail) throws Exception { - if (jail == null || jail.isEmpty()) { - return; - } - - jail = jail.toLowerCase(Locale.ENGLISH); - synchronized (jails) { - if (jails.containsKey(jail)) { - if (user.getBase().isOnline()) { - user.getTeleport().now(getJail(jail), false, TeleportCause.COMMAND); - } - user.setJail(jail); - } - } - } - @Override public void sendToJail(final IUser user, final String jailName, final CompletableFuture future) throws Exception { if (jailName == null || jailName.isEmpty()) { diff --git a/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java b/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java index f020a2cca17..f58bbef4b99 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java +++ b/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java @@ -124,7 +124,7 @@ public CompletableFuture getRandomLocation(final Location center, fina // Prompts caching random valid locations, up to a maximum number of attempts public void cacheRandomLocations(final Location center, final double minRange, final double maxRange) { - ess.getServer().getScheduler().scheduleSyncDelayedTask(ess, () -> { + ess.scheduleLocationDelayedTask(center, () -> { for (int i = 0; i < this.getFindAttempts(); ++i) { calculateRandomLocation(center, minRange, maxRange).thenAccept(location -> { if (isValidRandomLocation(location)) { diff --git a/Essentials/src/main/java/com/earth2me/essentials/Settings.java b/Essentials/src/main/java/com/earth2me/essentials/Settings.java index 628271bc969..601d347ea32 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Settings.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Settings.java @@ -708,7 +708,7 @@ public void reloadConfig() { // This is 2 because Settings are reloaded twice in the startup lifecycle if (reloadCount.get() < 2) { - ess.scheduleSyncDelayedTask(() -> _addAlternativeCommand(effectiveAlias, toDisable)); + ess.scheduleGlobalDelayedTask(() -> _addAlternativeCommand(effectiveAlias, toDisable)); } else { _addAlternativeCommand(effectiveAlias, toDisable); } @@ -721,7 +721,7 @@ public void reloadConfig() { ess.getLogger().log(Level.INFO, "Syncing commands"); } if (reloadCount.get() < 2) { - ess.scheduleSyncDelayedTask(() -> ess.getSyncCommandsProvider().syncCommands()); + ess.scheduleGlobalDelayedTask(() -> ess.getSyncCommandsProvider().syncCommands()); } else { ess.getSyncCommandsProvider().syncCommands(); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/Teleport.java b/Essentials/src/main/java/com/earth2me/essentials/Teleport.java deleted file mode 100644 index 6038b2e3578..00000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/Teleport.java +++ /dev/null @@ -1,403 +0,0 @@ -package com.earth2me.essentials; - -import com.earth2me.essentials.utils.DateUtil; -import com.earth2me.essentials.utils.LocationUtil; -import io.papermc.lib.PaperLib; -import net.ess3.api.IEssentials; -import net.ess3.api.ITeleport; -import net.ess3.api.IUser; -import net.ess3.api.events.UserWarpEvent; -import net.ess3.api.events.teleport.PreTeleportEvent; -import net.ess3.api.events.teleport.TeleportWarmupEvent; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerRespawnEvent; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - -import java.math.BigDecimal; -import java.util.Calendar; -import java.util.GregorianCalendar; - -import static com.earth2me.essentials.I18n.tl; - -/** - * @deprecated This API is not asynchronous. Use {@link com.earth2me.essentials.AsyncTeleport AsyncTeleport} - */ -@Deprecated -public class Teleport implements ITeleport { - private final IUser teleportOwner; - private final IEssentials ess; - private TimedTeleport timedTeleport; - - private TeleportType tpType; - - @Deprecated - public Teleport(final IUser user, final IEssentials ess) { - this.teleportOwner = user; - this.ess = ess; - tpType = TeleportType.NORMAL; - } - - @Deprecated - public void cooldown(final boolean check) throws Exception { - final Calendar time = new GregorianCalendar(); - if (teleportOwner.getLastTeleportTimestamp() > 0) { - // Take the current time, and remove the delay from it. - final double cooldown = ess.getSettings().getTeleportCooldown(); - final Calendar earliestTime = new GregorianCalendar(); - earliestTime.add(Calendar.SECOND, -(int) cooldown); - earliestTime.add(Calendar.MILLISECOND, -(int) ((cooldown * 1000.0) % 1000.0)); - // This value contains the most recent time a teleportPlayer could have been used that would allow another use. - final long earliestLong = earliestTime.getTimeInMillis(); - - // When was the last teleportPlayer used? - final long lastTime = teleportOwner.getLastTeleportTimestamp(); - - if (lastTime > time.getTimeInMillis()) { - // This is to make sure time didn't get messed up on last teleportPlayer use. - // If this happens, let's give the user the benifit of the doubt. - teleportOwner.setLastTeleportTimestamp(time.getTimeInMillis()); - return; - } else if (lastTime > earliestLong - && cooldownApplies()) { - time.setTimeInMillis(lastTime); - time.add(Calendar.SECOND, (int) cooldown); - time.add(Calendar.MILLISECOND, (int) ((cooldown * 1000.0) % 1000.0)); - throw new Exception(tl("timeBeforeTeleport", DateUtil.formatDateDiff(time.getTimeInMillis()))); - } - } - // if justCheck is set, don't update lastTeleport; we're just checking - if (!check) { - teleportOwner.setLastTeleportTimestamp(time.getTimeInMillis()); - } - } - - @Deprecated - private boolean cooldownApplies() { - boolean applies = true; - final String globalBypassPerm = "essentials.teleport.cooldown.bypass"; - switch (tpType) { - case NORMAL: - applies = !teleportOwner.isAuthorized(globalBypassPerm); - break; - case BACK: - applies = !(teleportOwner.isAuthorized(globalBypassPerm) && - teleportOwner.isAuthorized("essentials.teleport.cooldown.bypass.back")); - break; - case TPA: - applies = !(teleportOwner.isAuthorized(globalBypassPerm) && - teleportOwner.isAuthorized("essentials.teleport.cooldown.bypass.tpa")); - break; - } - return applies; - } - - @Deprecated - private void warnUser(final IUser user, final double delay) { - final Calendar c = new GregorianCalendar(); - c.add(Calendar.SECOND, (int) delay); - c.add(Calendar.MILLISECOND, (int) ((delay * 1000.0) % 1000.0)); - user.sendMessage(tl("dontMoveMessage", DateUtil.formatDateDiff(c.getTimeInMillis()))); - } - - //The now function is used when you want to skip tp delay when teleporting someone to a location or player. - @Override - @Deprecated - public void now(final Location loc, final boolean cooldown, final TeleportCause cause) throws Exception { - if (cooldown) { - cooldown(false); - } - final ITarget target = new LocationTarget(loc); - now(teleportOwner, target, cause); - } - - @Override - @Deprecated - public void now(final Player entity, final boolean cooldown, final TeleportCause cause) throws Exception { - if (cooldown) { - cooldown(false); - } - final ITarget target = new PlayerTarget(entity); - now(teleportOwner, target, cause); - teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ())); - } - - @Deprecated - protected void now(final IUser teleportee, final ITarget target, final TeleportCause cause) throws Exception { - cancel(false); - Location loc = target.getLocation(); - - final PreTeleportEvent event = new PreTeleportEvent(teleportee, cause, target); - Bukkit.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - - if (teleportee.isAuthorized("essentials.back.onteleport")) { - teleportee.setLastLocation(); - } - - if (!teleportee.getBase().isEmpty()) { - if (!ess.getSettings().isTeleportPassengerDismount()) { - throw new Exception(tl("passengerTeleportFail")); - } - teleportee.getBase().eject(); - } - - if (LocationUtil.isBlockUnsafeForUser(ess, teleportee, loc.getWorld(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())) { - if (ess.getSettings().isTeleportSafetyEnabled()) { - if (ess.getSettings().isForceDisableTeleportSafety()) { - PaperLib.teleportAsync(teleportee.getBase(), loc, cause); - } else { - PaperLib.teleportAsync(teleportee.getBase(), LocationUtil.getSafeDestination(ess, teleportee, loc), cause); - } - } else { - throw new Exception(tl("unsafeTeleportDestination", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); - } - } else { - if (ess.getSettings().isForceDisableTeleportSafety()) { - PaperLib.teleportAsync(teleportee.getBase(), loc, cause); - } else { - if (ess.getSettings().isTeleportToCenterLocation()) { - loc = LocationUtil.getRoundedDestination(loc); - } - PaperLib.teleportAsync(teleportee.getBase(), loc, cause); - } - } - } - - //The teleportPlayer function is used when you want to normally teleportPlayer someone to a location or player. - //This method is nolonger used internally and will be removed. - @Deprecated - @Override - public void teleport(final Location loc, final Trade chargeFor) throws Exception { - teleport(loc, chargeFor, TeleportCause.PLUGIN); - } - - @Override - @Deprecated - public void teleport(final Location loc, final Trade chargeFor, final TeleportCause cause) throws Exception { - teleport(teleportOwner, new LocationTarget(loc), chargeFor, cause); - } - - //This is used when teleporting to a player - @Override - @Deprecated - public void teleport(final Player entity, final Trade chargeFor, final TeleportCause cause) throws Exception { - final ITarget target = new PlayerTarget(entity); - teleportOwner.sendMessage(tl("teleportToPlayer", entity.getDisplayName())); - teleport(teleportOwner, target, chargeFor, cause); - } - - //This is used when teleporting to stored location - @Override - @Deprecated - public void teleportPlayer(final IUser teleportee, final Location loc, final Trade chargeFor, final TeleportCause cause) throws Exception { - teleport(teleportee, new LocationTarget(loc), chargeFor, cause); - } - - //This is used on /tphere - @Override - @Deprecated - public void teleportPlayer(final IUser teleportee, final Player entity, final Trade chargeFor, final TeleportCause cause) throws Exception { - final ITarget target = new PlayerTarget(entity); - teleport(teleportee, target, chargeFor, cause); - teleportee.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ())); - teleportOwner.sendMessage(tl("teleporting", target.getLocation().getWorld().getName(), target.getLocation().getBlockX(), target.getLocation().getBlockY(), target.getLocation().getBlockZ())); - } - - @Deprecated - private void teleport(final IUser teleportee, final ITarget target, final Trade chargeFor, final TeleportCause cause) throws Exception { - double delay = ess.getSettings().getTeleportDelay(); - - final TeleportWarmupEvent event = new TeleportWarmupEvent(teleportee, cause, target, delay); - Bukkit.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - delay = event.getDelay(); - - Trade cashCharge = chargeFor; - - if (chargeFor != null) { - chargeFor.isAffordableFor(teleportOwner); - - //This code is to make sure that commandcosts are checked in the initial world, and not in the resulting world. - if (!chargeFor.getCommandCost(teleportOwner).equals(BigDecimal.ZERO)) { - //By converting a command cost to a regular cost, the command cost permission isn't checked when executing the charge after teleport. - cashCharge = new Trade(chargeFor.getCommandCost(teleportOwner), ess); - } - } - - cooldown(true); - if (delay <= 0 || teleportOwner.isAuthorized("essentials.teleport.timer.bypass") || teleportee.isAuthorized("essentials.teleport.timer.bypass")) { - cooldown(false); - now(teleportee, target, cause); - if (cashCharge != null) { - cashCharge.charge(teleportOwner); - } - return; - } - - cancel(false); - warnUser(teleportee, delay); - initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false); - } - - @Deprecated - private void teleportOther(final IUser teleporter, final IUser teleportee, final ITarget target, final Trade chargeFor, final TeleportCause cause) throws Exception { - double delay = ess.getSettings().getTeleportDelay(); - - final TeleportWarmupEvent event = new TeleportWarmupEvent(teleporter, teleportee, cause, target, delay); - Bukkit.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - delay = event.getDelay(); - - Trade cashCharge = chargeFor; - - if (teleporter != null && chargeFor != null) { - chargeFor.isAffordableFor(teleporter); - - //This code is to make sure that commandcosts are checked in the initial world, and not in the resulting world. - if (!chargeFor.getCommandCost(teleporter).equals(BigDecimal.ZERO)) { - //By converting a command cost to a regular cost, the command cost permission isn't checked when executing the charge after teleport. - cashCharge = new Trade(chargeFor.getCommandCost(teleporter), ess); - } - } - - cooldown(true); - if (delay <= 0 || teleporter == null - || teleporter.isAuthorized("essentials.teleport.timer.bypass") - || teleportOwner.isAuthorized("essentials.teleport.timer.bypass") - || teleportee.isAuthorized("essentials.teleport.timer.bypass")) { - cooldown(false); - now(teleportee, target, cause); - if (teleporter != null && cashCharge != null) { - cashCharge.charge(teleporter); - } - return; - } - - cancel(false); - warnUser(teleportee, delay); - initTimer((long) (delay * 1000.0), teleportee, target, cashCharge, cause, false); - } - - //The respawn function is a wrapper used to handle tp fallback, on /jail and /home - @Override - @Deprecated - public void respawn(final Trade chargeFor, final TeleportCause cause) throws Exception { - double delay = ess.getSettings().getTeleportDelay(); - - final TeleportWarmupEvent event = new TeleportWarmupEvent(teleportOwner, cause, null, delay); - Bukkit.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - delay = event.getDelay(); - - if (chargeFor != null) { - chargeFor.isAffordableFor(teleportOwner); - } - cooldown(true); - if (delay <= 0 || teleportOwner.isAuthorized("essentials.teleport.timer.bypass")) { - cooldown(false); - respawnNow(teleportOwner, cause); - if (chargeFor != null) { - chargeFor.charge(teleportOwner); - } - return; - } - - cancel(false); - warnUser(teleportOwner, delay); - initTimer((long) (delay * 1000.0), teleportOwner, null, chargeFor, cause, true); - } - - @Deprecated - void respawnNow(final IUser teleportee, final TeleportCause cause) throws Exception { - final Player player = teleportee.getBase(); - final Location bed = player.getBedSpawnLocation(); - if (bed != null) { - now(teleportee, new LocationTarget(bed), cause); - } else { - if (ess.getSettings().isDebug()) { - ess.getLogger().info("Could not find bed spawn, forcing respawn event."); - } - final PlayerRespawnEvent pre = new PlayerRespawnEvent(player, player.getWorld().getSpawnLocation(), false); - ess.getServer().getPluginManager().callEvent(pre); - now(teleportee, new LocationTarget(pre.getRespawnLocation()), cause); - } - } - - //The warp function is a wrapper used to teleportPlayer a player to a /warp - @Override - @Deprecated - public void warp(final IUser teleportee, String warp, final Trade chargeFor, final TeleportCause cause) throws Exception { - final UserWarpEvent event = new UserWarpEvent(teleportee, warp, chargeFor); - Bukkit.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - return; - } - - warp = event.getWarp(); - final Location loc = ess.getWarps().getWarp(warp); - teleportee.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); - if (!teleportee.equals(teleportOwner)) { - teleportOwner.sendMessage(tl("warpingTo", warp, loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); - } - teleport(teleportee, new LocationTarget(loc), chargeFor, cause); - } - - //The back function is a wrapper used to teleportPlayer a player /back to their previous location. - @Override - @Deprecated - public void back(final Trade chargeFor) throws Exception { - back(teleportOwner, chargeFor); - } - - //This function is a wrapper over the other back function for cases where another player performs back for them - @Override - @Deprecated - public void back(final IUser teleporter, final Trade chargeFor) throws Exception { - tpType = TeleportType.BACK; - final Location loc = teleportOwner.getLastLocation(); - teleportOwner.sendMessage(tl("backUsageMsg", loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); - teleportOther(teleporter, teleportOwner, new LocationTarget(loc), chargeFor, TeleportCause.COMMAND); - } - - //This function is used to throw a user back after a jail sentence - @Override - @Deprecated - public void back() throws Exception { - now(teleportOwner, new LocationTarget(teleportOwner.getLastLocation()), TeleportCause.COMMAND); - } - - @Deprecated - public void setTpType(final TeleportType tpType) { - this.tpType = tpType; - } - - //If we need to cancelTimer a pending teleportPlayer call this method - @Deprecated - private void cancel(final boolean notifyUser) { - if (timedTeleport != null) { - timedTeleport.cancelTimer(notifyUser); - timedTeleport = null; - } - } - - @Deprecated - private void initTimer(final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) { - timedTeleport = new TimedTeleport(teleportOwner, ess, this, delay, teleportUser, target, chargeFor, cause, respawn); - } - - public enum TeleportType { - TPA, - BACK, - NORMAL - } -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/TimedTeleport.java b/Essentials/src/main/java/com/earth2me/essentials/TimedTeleport.java deleted file mode 100644 index 9e731918b80..00000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/TimedTeleport.java +++ /dev/null @@ -1,140 +0,0 @@ -package com.earth2me.essentials; - -import net.ess3.api.IEssentials; -import net.ess3.api.IUser; -import org.bukkit.Location; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - -import java.util.UUID; - -import static com.earth2me.essentials.I18n.tl; - -@Deprecated -public class TimedTeleport implements Runnable { - private static final double MOVE_CONSTANT = 0.3; - private final IUser teleportOwner; - private final IEssentials ess; - private final Teleport teleport; - private final UUID timer_teleportee; - private final long timer_started; // time this task was initiated - private final long timer_delay; // how long to delay the teleportPlayer - // note that I initially stored a clone of the location for reference, but... - // when comparing locations, I got incorrect mismatches (rounding errors, looked like) - // so, the X/Y/Z values are stored instead and rounded off - private final long timer_initX; - private final long timer_initY; - private final long timer_initZ; - private final ITarget timer_teleportTarget; - private final boolean timer_respawn; - private final boolean timer_canMove; - private final Trade timer_chargeFor; - private final TeleportCause timer_cause; - private int timer_task; - private double timer_health; - - TimedTeleport(final IUser user, final IEssentials ess, final Teleport teleport, final long delay, final IUser teleportUser, final ITarget target, final Trade chargeFor, final TeleportCause cause, final boolean respawn) { - this.teleportOwner = user; - this.ess = ess; - this.teleport = teleport; - this.timer_started = System.currentTimeMillis(); - this.timer_delay = delay; - this.timer_health = teleportUser.getBase().getHealth(); - this.timer_initX = Math.round(teleportUser.getBase().getLocation().getX() * MOVE_CONSTANT); - this.timer_initY = Math.round(teleportUser.getBase().getLocation().getY() * MOVE_CONSTANT); - this.timer_initZ = Math.round(teleportUser.getBase().getLocation().getZ() * MOVE_CONSTANT); - this.timer_teleportee = teleportUser.getBase().getUniqueId(); - this.timer_teleportTarget = target; - this.timer_chargeFor = chargeFor; - this.timer_cause = cause; - this.timer_respawn = respawn; - this.timer_canMove = user.isAuthorized("essentials.teleport.timer.move"); - - timer_task = ess.runTaskTimerAsynchronously(this, 20, 20).getTaskId(); - } - - @Override - public void run() { - - if (teleportOwner == null || !teleportOwner.getBase().isOnline() || teleportOwner.getBase().getLocation() == null) { - cancelTimer(false); - return; - } - - final IUser teleportUser = ess.getUser(this.timer_teleportee); - - if (teleportUser == null || !teleportUser.getBase().isOnline()) { - cancelTimer(false); - return; - } - - final Location currLocation = teleportUser.getBase().getLocation(); - if (currLocation == null) { - cancelTimer(false); - return; - } - - if (!timer_canMove && (Math.round(currLocation.getX() * MOVE_CONSTANT) != timer_initX || Math.round(currLocation.getY() * MOVE_CONSTANT) != timer_initY || Math.round(currLocation.getZ() * MOVE_CONSTANT) != timer_initZ || teleportUser.getBase().getHealth() < timer_health)) { - // user moved, cancelTimer teleportPlayer - cancelTimer(true); - return; - } - - class DelayedTeleportTask implements Runnable { - @Override - public void run() { - - timer_health = teleportUser.getBase().getHealth(); // in case user healed, then later gets injured - final long now = System.currentTimeMillis(); - if (now > timer_started + timer_delay) { - try { - teleport.cooldown(false); - } catch (final Exception ex) { - teleportOwner.sendMessage(tl("cooldownWithMessage", ex.getMessage())); - if (teleportOwner != teleportUser) { - teleportUser.sendMessage(tl("cooldownWithMessage", ex.getMessage())); - } - } - try { - cancelTimer(false); - teleportUser.sendMessage(tl("teleportationCommencing")); - - if (timer_chargeFor != null) { - timer_chargeFor.isAffordableFor(teleportOwner); - } - if (timer_respawn) { - teleport.respawnNow(teleportUser, timer_cause); - } else { - teleport.now(teleportUser, timer_teleportTarget, timer_cause); - } - if (timer_chargeFor != null) { - timer_chargeFor.charge(teleportOwner); - } - - } catch (final Exception ex) { - ess.showError(teleportOwner.getSource(), ex, "\\ teleport"); - } - } - } - } - - ess.scheduleSyncDelayedTask(new DelayedTeleportTask()); - } - - //If we need to cancelTimer a pending teleportPlayer call this method - void cancelTimer(final boolean notifyUser) { - if (timer_task == -1) { - return; - } - try { - ess.getServer().getScheduler().cancelTask(timer_task); - if (notifyUser) { - teleportOwner.sendMessage(tl("pendingTeleportCancelled")); - if (timer_teleportee != null && !timer_teleportee.equals(teleportOwner.getBase().getUniqueId())) { - ess.getUser(timer_teleportee).sendMessage(tl("pendingTeleportCancelled")); - } - } - } finally { - timer_task = -1; - } - } -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/User.java b/Essentials/src/main/java/com/earth2me/essentials/User.java index 216a20ab1f4..3918233bc3c 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/User.java +++ b/Essentials/src/main/java/com/earth2me/essentials/User.java @@ -57,7 +57,6 @@ public class User extends UserData implements Comparable, IMessageRecipien // User modules private final IMessageRecipient messageRecipient; private transient final AsyncTeleport teleport; - private transient final Teleport legacyTeleport; // User command confirmation strings private final Map confirmingPayments = new WeakHashMap<>(); @@ -97,7 +96,6 @@ public class User extends UserData implements Comparable, IMessageRecipien public User(final Player base, final IEssentials ess) { super(base, ess); teleport = new AsyncTeleport(this, ess); - legacyTeleport = new Teleport(this, ess); if (isAfk()) { afkPosition = this.getLocation(); } @@ -550,15 +548,6 @@ public AsyncTeleport getAsyncTeleport() { return teleport; } - /** - * @deprecated This API is not asynchronous. Use {@link User#getAsyncTeleport()} - */ - @Override - @Deprecated - public Teleport getTeleport() { - return legacyTeleport; - } - public long getLastOnlineActivity() { return lastOnlineActivity; } @@ -814,9 +803,7 @@ public void updateActivityOnInteract(final boolean broadcast) { public void updateActivityOnChat(final boolean broadcast) { if (ess.getSettings().cancelAfkOnChat()) { //Chat happens async, make sure we have a sync context - ess.scheduleSyncDelayedTask(() -> { - updateActivity(broadcast, AfkStatusChangeEvent.Cause.CHAT); - }); + ess.scheduleEntityDelayedTask(base, () -> updateActivity(broadcast, AfkStatusChangeEvent.Cause.CHAT)); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/api/IJails.java b/Essentials/src/main/java/com/earth2me/essentials/api/IJails.java index 94947c9c298..f39179e3383 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/api/IJails.java +++ b/Essentials/src/main/java/com/earth2me/essentials/api/IJails.java @@ -46,17 +46,6 @@ public interface IJails extends IConf { */ void removeJail(String jail) throws Exception; - /** - * Attempts to send the given user to the given jail - * - * @param user the user to send to jail - * @param jail the jail to send the user to - * @throws Exception if the user is offline or jail does not exist - * @deprecated Use {@link IJails#sendToJail(IUser, String, CompletableFuture)} - */ - @Deprecated - void sendToJail(IUser user, String jail) throws Exception; - /** * Attempts to send the given user to the given jail * diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandbalancetop.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandbalancetop.java index a0846e43dca..acdfcfc8c6e 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandbalancetop.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandbalancetop.java @@ -38,7 +38,7 @@ private void outputCache(final CommandSource sender, final int page) { new TextPager(cache).showPage(Integer.toString(page), null, "balancetop", sender); }; if (sender.getSender() instanceof BlockCommandSender) { - ess.scheduleSyncDelayedTask(runnable); + ess.scheduleGlobalDelayedTask(runnable); } else { runnable.run(); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandbeezooka.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandbeezooka.java index bc55ef47d7e..f06679d7304 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandbeezooka.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandbeezooka.java @@ -25,7 +25,7 @@ protected void run(final Server server, final User user, final String commandLab final Entity bee = Mob.BEE.spawn(user.getWorld(), server, user.getBase().getEyeLocation()); bee.setVelocity(user.getBase().getEyeLocation().getDirection().multiply(2)); - ess.scheduleSyncDelayedTask(() -> { + ess.scheduleEntityDelayedTask(bee, () -> { final Location loc = bee.getLocation(); bee.remove(); loc.getWorld().createExplosion(loc, 0F); diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandessentials.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandessentials.java index f32cc655a48..dee0c19b81f 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandessentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandessentials.java @@ -740,6 +740,7 @@ private void runVersion(final Server server, final CommandSource sender, final S sender.sendMessage(tl(serverMessageKey, "Server", server.getBukkitVersion() + " " + server.getVersion())); sender.sendMessage(tl(serverMessageKey, "Brand", server.getName())); + sender.sendMessage(tl("versionOutputFlags", "FOLIA:" + VersionUtil.FOLIA + ",FLAT:" + VersionUtil.PRE_FLATTENING + ",SUPSTAT:" + VersionUtil.getServerSupportStatus().name())); sender.sendMessage(tl("versionOutputFine", "EssentialsX", essVer)); for (final Plugin plugin : pm.getPlugins()) { diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandgc.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandgc.java index 5f7392cdea3..4569bcef36f 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandgc.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandgc.java @@ -21,7 +21,7 @@ public Commandgc() { @Override protected void run(final Server server, final CommandSource sender, final String commandLabel, final String[] args) throws Exception { - final double tps = ess.getTimer().getAverageTPS(); + final double tps = 20d; //TODO final ChatColor color; if (tps >= 18.0) { color = ChatColor.GREEN; diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkittycannon.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkittycannon.java index e40234f5218..6356fe6d075 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkittycannon.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkittycannon.java @@ -42,7 +42,7 @@ private static Entity spawnCat(final Server server, final User user) throws Mob. @Override protected void run(final Server server, final User user, final String commandLabel, final String[] args) throws Exception { final Entity ocelot = Mob.CAT.getType() == null ? spawnOcelot(server, user) : spawnCat(server, user); - ess.scheduleSyncDelayedTask(() -> { + ess.scheduleEntityDelayedTask(ocelot, () -> { final Location loc = ocelot.getLocation(); ocelot.remove(); loc.getWorld().createExplosion(loc, 0F); diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandnuke.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandnuke.java index f7bf8a33c5f..54da6594ab4 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandnuke.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandnuke.java @@ -38,17 +38,19 @@ protected void run(final Server server, final CommandSource sender, final String if (player == null) { continue; } - player.sendMessage(tl("nuke")); - final Location loc = player.getLocation(); - final World world = loc.getWorld(); - if (world != null) { - for (int x = -10; x <= 10; x += 5) { - for (int z = -10; z <= 10; z += 5) { - final TNTPrimed entity = world.spawn(new Location(world, loc.getBlockX() + x, world.getHighestBlockYAt(loc) + 64, loc.getBlockZ() + z), TNTPrimed.class); - entity.setMetadata(NUKE_META_KEY, new FixedMetadataValue(ess, true)); + ess.scheduleEntityDelayedTask(player, () -> { + player.sendMessage(tl("nuke")); + final Location loc = player.getLocation(); + final World world = loc.getWorld(); + if (world != null) { + for (int x = -10; x <= 10; x += 5) { + for (int z = -10; z <= 10; z += 5) { + final TNTPrimed entity = world.spawn(new Location(world, loc.getBlockX() + x, world.getHighestBlockYAt(loc) + 64, loc.getBlockZ() + z), TNTPrimed.class); + entity.setMetadata(NUKE_META_KEY, new FixedMetadataValue(ess, true)); + } } } - } + }); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandseen.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandseen.java index f6c3e2d0040..ba992ba878d 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandseen.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandseen.java @@ -59,7 +59,7 @@ protected void run(final Server server, final CommandSource sender, final String return; } } - ess.getScheduler().runTaskAsynchronously(ess, new Runnable() { + ess.runTaskAsynchronously(new Runnable() { @Override public void run() { final User userFromBukkit = ess.getUsers().getUser(args[0]); diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandskull.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandskull.java index b9b50b8d4bd..4fd6d122371 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandskull.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandskull.java @@ -129,7 +129,7 @@ private void editSkull(final User user, final ItemStack stack, final SkullMeta s } skullMeta.setDisplayName("§fSkull of " + shortOwnerName); - ess.scheduleSyncDelayedTask(() -> { + ess.scheduleEntityDelayedTask(user.getBase(), () -> { stack.setItemMeta(skullMeta); if (spawn) { Inventories.addItem(user.getBase(), stack); diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsudo.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsudo.java index df264f4dd7b..ebdcd790045 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsudo.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandsudo.java @@ -55,7 +55,7 @@ public void run() { } } - ess.scheduleSyncDelayedTask(new SudoCommandTask()); + ess.scheduleEntityDelayedTask(user.getBase(), new SudoCommandTask()); } } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtime.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtime.java index 06c86b2da8c..7e437339c90 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtime.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandtime.java @@ -81,15 +81,17 @@ public void run(final Server server, final CommandSource sender, final String co } final StringJoiner joiner = new StringJoiner(", "); + final boolean timeAdd = add; for (final World world : worlds) { - long time = world.getTime(); - if (!add) { - time -= time % 24000; - } - world.setTime(time + (add ? 0 : 24000) + timeTick); joiner.add(world.getName()); + ess.scheduleGlobalDelayedTask(() -> { + long time = world.getTime(); + if (!timeAdd) { + time -= time % 24000; + } + world.setTime(time + (timeAdd ? 0 : 24000) + timeTick); + }); } - sender.sendMessage(tl(add ? "timeWorldAdd" : "timeWorldSet", DescParseTickFormat.formatTicks(timeTick), joiner.toString())); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandweather.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandweather.java index 1dc9b41981d..cfcc845baa5 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandweather.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandweather.java @@ -31,16 +31,18 @@ public void run(final Server server, final User user, final String commandLabel, isStorm = args[0].equalsIgnoreCase("storm"); } - final World world = user.getWorld(); + ess.scheduleGlobalDelayedTask(() -> { + final World world = user.getWorld(); - if (args.length > 1) { + if (args.length > 1) { + world.setStorm(isStorm); + world.setWeatherDuration(Integer.parseInt(args[1]) * 20); + user.sendMessage(isStorm ? tl("weatherStormFor", world.getName(), args[1]) : tl("weatherSunFor", world.getName(), args[1])); + return; + } world.setStorm(isStorm); - world.setWeatherDuration(Integer.parseInt(args[1]) * 20); - user.sendMessage(isStorm ? tl("weatherStormFor", world.getName(), args[1]) : tl("weatherSunFor", world.getName(), args[1])); - return; - } - world.setStorm(isStorm); - user.sendMessage(isStorm ? tl("weatherStorm", world.getName()) : tl("weatherSun", world.getName())); + user.sendMessage(isStorm ? tl("weatherStorm", world.getName()) : tl("weatherSun", world.getName())); + }); } @Override @@ -55,14 +57,16 @@ protected void run(final Server server, final CommandSource sender, final String throw new Exception(tl("weatherInvalidWorld", args[0])); } - if (args.length > 2) { + ess.scheduleLocationDelayedTask(world.getSpawnLocation(), () -> { + if (args.length > 2) { + world.setStorm(isStorm); + world.setWeatherDuration(Integer.parseInt(args[2]) * 20); + sender.sendMessage(isStorm ? tl("weatherStormFor", world.getName(), args[2]) : tl("weatherSunFor", world.getName(), args[2])); + return; + } world.setStorm(isStorm); - world.setWeatherDuration(Integer.parseInt(args[2]) * 20); - sender.sendMessage(isStorm ? tl("weatherStormFor", world.getName(), args[2]) : tl("weatherSunFor", world.getName(), args[2])); - return; - } - world.setStorm(isStorm); - sender.sendMessage(isStorm ? tl("weatherStorm", world.getName()) : tl("weatherSun", world.getName())); + sender.sendMessage(isStorm ? tl("weatherStorm", world.getName()) : tl("weatherSun", world.getName())); + }); } @Override diff --git a/Essentials/src/main/java/com/earth2me/essentials/economy/EconomyLayers.java b/Essentials/src/main/java/com/earth2me/essentials/economy/EconomyLayers.java index a4184e5588a..e1ebf5d6617 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/economy/EconomyLayers.java +++ b/Essentials/src/main/java/com/earth2me/essentials/economy/EconomyLayers.java @@ -32,7 +32,7 @@ public static void init() { } public static void onEnable(final Essentials ess) { - ess.scheduleSyncDelayedTask(() -> { + ess.scheduleInitTask(() -> { serverStarted = true; for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) { if (!plugin.isEnabled()) { diff --git a/Essentials/src/main/java/com/earth2me/essentials/textreader/KeywordReplacer.java b/Essentials/src/main/java/com/earth2me/essentials/textreader/KeywordReplacer.java index 93dafa85dd0..aaf2eed391f 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/textreader/KeywordReplacer.java +++ b/Essentials/src/main/java/com/earth2me/essentials/textreader/KeywordReplacer.java @@ -348,7 +348,7 @@ private String replaceLine(String line, final String fullMatch, final String[] m } break; case TPS: - replacer = NumberUtil.formatDouble(ess.getTimer().getAverageTPS()); + replacer = NumberUtil.formatDouble(20d); //todo break; case UPTIME: replacer = DateUtil.formatDateDiff(ManagementFactory.getRuntimeMXBean().getStartTime()); diff --git a/Essentials/src/main/java/com/earth2me/essentials/utils/VersionUtil.java b/Essentials/src/main/java/com/earth2me/essentials/utils/VersionUtil.java index 93b637a7f5a..199dabab5ce 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/utils/VersionUtil.java +++ b/Essentials/src/main/java/com/earth2me/essentials/utils/VersionUtil.java @@ -42,10 +42,20 @@ public final class VersionUtil { private static final Set supportedVersions = ImmutableSet.of(v1_8_8_R01, v1_9_4_R01, v1_10_2_R01, v1_11_2_R01, v1_12_2_R01, v1_13_2_R01, v1_14_4_R01, v1_15_2_R01, v1_16_5_R01, v1_17_1_R01, v1_18_2_R01, v1_19_4_R01, v1_20_1_R01); public static final boolean PRE_FLATTENING = VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_13_0_R01); + public static final boolean FOLIA; private static final Map unsupportedServerClasses; static { + boolean isFolia; + try { + Class.forName("io.papermc.paper.threadedregions.scheduler.AsyncScheduler"); + isFolia = true; + } catch (Throwable ignored) { + isFolia = false; + } + FOLIA = isFolia; + final ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); // Yatopia - Extremely volatile patch set; diff --git a/Essentials/src/main/resources/messages.properties b/Essentials/src/main/resources/messages.properties index 84ef8c9b246..428dd3db997 100644 --- a/Essentials/src/main/resources/messages.properties +++ b/Essentials/src/main/resources/messages.properties @@ -1495,6 +1495,7 @@ versionErrorPlayer=\u00a76Error while checking EssentialsX version information! versionFetching=\u00a76Fetching version information... versionOutputVaultMissing=\u00a74Vault is not installed. Chat and permissions may not work. versionOutputFine=\u00a76{0} version: \u00a7a{1} +versionOutputFlags=\u00a76Feature Flags: \u00a7a{0} versionOutputWarn=\u00a76{0} version: \u00a7c{1} versionOutputUnsupported=\u00a7d{0} \u00a76version: \u00a7d{1} versionOutputUnsupportedPlugins=\u00a76You are running \u00a7dunsupported plugins\u00a76! diff --git a/Essentials/src/main/resources/plugin.yml b/Essentials/src/main/resources/plugin.yml index f9a8c44d741..edf56ba9ffe 100644 --- a/Essentials/src/main/resources/plugin.yml +++ b/Essentials/src/main/resources/plugin.yml @@ -8,6 +8,7 @@ description: Provides an essential, core set of commands for Bukkit. softdepend: [Vault, LuckPerms] authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology, KHobbits, md_5, Iaccidentally, drtshock, vemacs, SupaHam, mdcfe, JRoy, pop4959] api-version: "1.13" +folia-supported: true commands: afk: description: Marks you as away-from-keyboard. diff --git a/EssentialsAntiBuild/src/main/resources/plugin.yml b/EssentialsAntiBuild/src/main/resources/plugin.yml index f7dac0e8942..1558a519cea 100644 --- a/EssentialsAntiBuild/src/main/resources/plugin.yml +++ b/EssentialsAntiBuild/src/main/resources/plugin.yml @@ -8,7 +8,7 @@ description: Provides build protection. authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology, KHobbits, Iaccidentally, drtshock, mdcfe] depend: [Essentials] api-version: "1.13" - +folia-supported: true permissions: essentials.exempt.protect: default: false diff --git a/EssentialsChat/src/main/resources/plugin.yml b/EssentialsChat/src/main/resources/plugin.yml index ab1d85c5a36..7fa9d802c05 100644 --- a/EssentialsChat/src/main/resources/plugin.yml +++ b/EssentialsChat/src/main/resources/plugin.yml @@ -8,6 +8,7 @@ description: Provides chat control features for Essentials. Requires Permission authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology, KHobbits, md_5, Okamosy, Iaccidentally, mdcfe, JRoy, triagonal] depend: [Essentials] api-version: 1.13 +folia-supported: true commands: toggleshout: description: Toggles whether you are talking in shout mode diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/api/v2/events/discord/DiscordMessageEvent.java b/EssentialsDiscord/src/main/java/net/essentialsx/api/v2/events/discord/DiscordMessageEvent.java index c9f5f4765b3..72700c6880d 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/api/v2/events/discord/DiscordMessageEvent.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/api/v2/events/discord/DiscordMessageEvent.java @@ -1,6 +1,7 @@ package net.essentialsx.api.v2.events.discord; import net.essentialsx.api.v2.services.discord.MessageType; +import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; @@ -10,6 +11,8 @@ /** * Fired before a message is about to be sent to a Discord channel. + *

+ * Note: This event has no guarantee of the thread it is fired on, please use {@link #isAsynchronous()}} to see if this event is off the main Bukkit thread. */ public class DiscordMessageEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); @@ -40,6 +43,7 @@ public DiscordMessageEvent(final MessageType type, final String message, final b * @param uuid The UUID of the player which caused this event or null if this wasn't a player triggered event. */ public DiscordMessageEvent(final MessageType type, final String message, final boolean allowGroupMentions, final String avatarUrl, final String name, final UUID uuid) { + super(!Bukkit.isPrimaryThread()); this.type = type; this.message = message; this.allowGroupMentions = allowGroupMentions; diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/EssentialsDiscord.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/EssentialsDiscord.java index e45e419ffbe..b4b2f3ad53d 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/EssentialsDiscord.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/EssentialsDiscord.java @@ -60,7 +60,7 @@ public void onEnable() { jda = new JDADiscordService(this); try { jda.startup(); - ess.scheduleSyncDelayedTask(() -> ((InteractionControllerImpl) jda.getInteractionController()).processBatchRegistration()); + ess.scheduleInitTask(() -> ((InteractionControllerImpl) jda.getInteractionController()).processBatchRegistration()); } catch (Exception e) { getLogger().log(Level.SEVERE, tl("discordErrorLogin", e.getMessage())); if (ess.getSettings().isDebug()) { diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java index 4883cb634b4..485c83bbe08 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/JDADiscordService.java @@ -237,7 +237,7 @@ public void startup() throws LoginException, InterruptedException { logger.log(Level.WARNING, "Error while loading the achievement/advancement listener. You will not receive achievement/advancement notifications on Discord.", e); } - getPlugin().getEss().scheduleSyncDelayedTask(() -> DiscordUtil.dispatchDiscordMessage(JDADiscordService.this, MessageType.DefaultTypes.SERVER_START, getSettings().getStartMessage(), true, null, null, null)); + getPlugin().getEss().scheduleInitTask(() -> DiscordUtil.dispatchDiscordMessage(JDADiscordService.this, MessageType.DefaultTypes.SERVER_START, getSettings().getStartMessage(), true, null, null, null)); Bukkit.getServicesManager().register(DiscordService.class, this, plugin, ServicePriority.Normal); } @@ -266,11 +266,7 @@ public void sendMessage(MessageType type, String message, boolean allowGroupMent logger.warning("Sending message to channel \"" + type.getKey() + "\" which is an unregistered type! If you are a plugin author, you should be registering your MessageType before using them."); } final DiscordMessageEvent event = new DiscordMessageEvent(type, FormatUtil.stripFormat(message), allowGroupMentions); - if (Bukkit.getServer().isPrimaryThread()) { - Bukkit.getPluginManager().callEvent(event); - } else { - Bukkit.getScheduler().runTask(plugin, () -> Bukkit.getPluginManager().callEvent(event)); - } + Bukkit.getPluginManager().callEvent(event); } @Override diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/interactions/InteractionControllerImpl.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/interactions/InteractionControllerImpl.java index d4cd81cfdf9..0c7c4bcb893 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/interactions/InteractionControllerImpl.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/interactions/InteractionControllerImpl.java @@ -64,7 +64,8 @@ public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent even interactionEvent.reply(tl("noAccessCommand")); return; } - jda.getPlugin().getEss().scheduleSyncDelayedTask(() -> command.onCommand(interactionEvent)); + + command.onCommand(interactionEvent); } @Override diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/interactions/commands/ExecuteCommand.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/interactions/commands/ExecuteCommand.java index 0a856b53237..cd258931099 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/interactions/commands/ExecuteCommand.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/interactions/commands/ExecuteCommand.java @@ -22,7 +22,7 @@ public ExecuteCommand(JDADiscordService jda) { public void onCommand(final InteractionEvent event) { final String command = event.getStringArgument("command"); event.reply(tl("discordCommandExecuteReply", command)); - Bukkit.getScheduler().runTask(jda.getPlugin(), () -> { + jda.getPlugin().getEss().scheduleGlobalDelayedTask(() -> { try { Bukkit.dispatchCommand(new DiscordCommandSender(jda, Bukkit.getConsoleSender(), message -> event.reply(MessageUtil.sanitizeDiscordMarkdown(message))).getSender(), command); } catch (CommandException e) { diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/listeners/DiscordCommandDispatcher.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/listeners/DiscordCommandDispatcher.java index c735aa7bdc9..440305d917c 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/listeners/DiscordCommandDispatcher.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/listeners/DiscordCommandDispatcher.java @@ -30,7 +30,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { } final String command = event.getMessage().getContentRaw(); - Bukkit.getScheduler().runTask(jda.getPlugin(), () -> { + jda.getPlugin().getEss().scheduleGlobalDelayedTask(() -> { try { Bukkit.dispatchCommand(new DiscordCommandSender(jda, Bukkit.getConsoleSender(), message -> event.getMessage().reply(message).queue()).getSender(), command); diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/ConsoleInjector.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/ConsoleInjector.java index 01f5d365d01..926439dcb8a 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/ConsoleInjector.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/ConsoleInjector.java @@ -4,6 +4,7 @@ import com.google.common.base.Splitter; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.utils.TimeFormat; +import net.ess3.provider.SchedulingProvider; import net.essentialsx.discord.EssentialsDiscord; import net.essentialsx.discord.JDADiscordService; import org.apache.logging.log4j.LogManager; @@ -11,7 +12,6 @@ import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.appender.AbstractAppender; import org.apache.logging.log4j.core.config.plugins.Plugin; -import org.bukkit.Bukkit; import java.time.Instant; import java.util.concurrent.BlockingQueue; @@ -30,7 +30,7 @@ public class ConsoleInjector extends AbstractAppender { private final JDADiscordService jda; private final BlockingQueue messageQueue = new LinkedBlockingQueue<>(); - private final int taskId; + private final SchedulingProvider.EssentialsTask task; private boolean removed = false; private final AtomicLong lastRateLimitTime = new AtomicLong(0); @@ -41,7 +41,7 @@ public ConsoleInjector(JDADiscordService jda) { super("EssentialsX-ConsoleInjector", null, null, false); this.jda = jda; ((Logger) LogManager.getRootLogger()).addAppender(this); - taskId = Bukkit.getScheduler().runTaskTimerAsynchronously(jda.getPlugin(), () -> { + task = jda.getPlugin().getEss().runTaskTimerAsynchronously(() -> { // Check to see if we're supposed to be backing off, preform backoff if the case. if (recentRateLimit.get() < 0) { if (totalBackoffEvents.get() * 20 >= jda.getSettings().getConsoleSkipDelay() * 60) { @@ -60,7 +60,6 @@ public ConsoleInjector(JDADiscordService jda) { } return; } - final StringBuilder buffer = new StringBuilder(); String curLine; while ((curLine = messageQueue.peek()) != null) { @@ -74,7 +73,7 @@ public ConsoleInjector(JDADiscordService jda) { if (buffer.length() != 0) { sendMessage(buffer.toString()); } - }, 20, 20 * QUEUE_PROCESS_PERIOD_SECONDS).getTaskId(); + }, 20, 20 * QUEUE_PROCESS_PERIOD_SECONDS); } private void sendMessage(String content) { @@ -148,7 +147,7 @@ public void append(LogEvent event) { public void remove() { ((Logger) LogManager.getRootLogger()).removeAppender(this); - Bukkit.getScheduler().cancelTask(taskId); + task.cancel(); messageQueue.clear(); if (jda.getConsoleWebhook() != null && !jda.getConsoleWebhook().isShutdown()) { jda.getConsoleWebhook().close(); diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordCommandSender.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordCommandSender.java index f8389c9e43b..c65f375c6d6 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordCommandSender.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordCommandSender.java @@ -2,17 +2,16 @@ import com.earth2me.essentials.utils.FormatUtil; import com.earth2me.essentials.utils.VersionUtil; +import net.ess3.provider.SchedulingProvider; import net.ess3.provider.providers.BukkitSenderProvider; import net.ess3.provider.providers.PaperCommandSender; import net.essentialsx.discord.JDADiscordService; -import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.scheduler.BukkitTask; public class DiscordCommandSender { private final CommandSender sender; - private BukkitTask task; + private SchedulingProvider.EssentialsTask task; private String responseBuffer = ""; private long lastTime = System.currentTimeMillis(); @@ -23,7 +22,7 @@ public DiscordCommandSender(JDADiscordService jda, ConsoleCommandSender sender, }; this.sender = getCustomSender(sender, hook); - task = Bukkit.getScheduler().runTaskTimerAsynchronously(jda.getPlugin(), () -> { + task = jda.getPlugin().getEss().runTaskTimerAsynchronously(() -> { if (!responseBuffer.isEmpty() && System.currentTimeMillis() - lastTime >= 1000) { callback.onMessage(responseBuffer); responseBuffer = ""; diff --git a/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordUtil.java b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordUtil.java index 01f82a51115..e050c9c4166 100644 --- a/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordUtil.java +++ b/EssentialsDiscord/src/main/java/net/essentialsx/discord/util/DiscordUtil.java @@ -235,10 +235,6 @@ public static void dispatchDiscordMessage(final JDADiscordService jda, final Mes return; } - if (Bukkit.getServer().isPrimaryThread()) { - Bukkit.getPluginManager().callEvent(event); - } else { - Bukkit.getScheduler().runTask(jda.getPlugin(), () -> Bukkit.getPluginManager().callEvent(event)); - } + Bukkit.getPluginManager().callEvent(event); } } diff --git a/EssentialsDiscord/src/main/resources/plugin.yml b/EssentialsDiscord/src/main/resources/plugin.yml index fad076db5fe..93e6c56b8cd 100644 --- a/EssentialsDiscord/src/main/resources/plugin.yml +++ b/EssentialsDiscord/src/main/resources/plugin.yml @@ -8,6 +8,7 @@ authors: [mdcfe, JRoy, pop4959, Glare] depend: [Essentials] softdepend: [EssentialsChat, PlaceholderAPI] api-version: 1.13 +folia-supported: true commands: discordbroadcast: description: Broadcasts a message to the specified Discord channel. diff --git a/EssentialsDiscordLink/src/main/java/net/essentialsx/discordlink/AccountLinkManager.java b/EssentialsDiscordLink/src/main/java/net/essentialsx/discordlink/AccountLinkManager.java index 982a3756244..1087bfd6846 100644 --- a/EssentialsDiscordLink/src/main/java/net/essentialsx/discordlink/AccountLinkManager.java +++ b/EssentialsDiscordLink/src/main/java/net/essentialsx/discordlink/AccountLinkManager.java @@ -136,7 +136,7 @@ private void ensureSync(final Runnable runnable) { runnable.run(); return; } - ess.getEss().scheduleSyncDelayedTask(runnable); + ess.getEss().scheduleGlobalDelayedTask(runnable); } private void ensureAsync(final Runnable runnable) { diff --git a/EssentialsDiscordLink/src/main/java/net/essentialsx/discordlink/listeners/LinkBukkitListener.java b/EssentialsDiscordLink/src/main/java/net/essentialsx/discordlink/listeners/LinkBukkitListener.java index 10651d90769..4b97455bfd7 100644 --- a/EssentialsDiscordLink/src/main/java/net/essentialsx/discordlink/listeners/LinkBukkitListener.java +++ b/EssentialsDiscordLink/src/main/java/net/essentialsx/discordlink/listeners/LinkBukkitListener.java @@ -157,7 +157,7 @@ public void onUserLinkStatusChange(final DiscordLinkStatusChangeEvent event) { if (Bukkit.isPrimaryThread()) { kickTask.run(); } else { - ess.getEss().scheduleSyncDelayedTask(kickTask); + ess.getEss().scheduleEntityDelayedTask(event.getUser().getBase(), kickTask); } break; } diff --git a/EssentialsDiscordLink/src/main/resources/plugin.yml b/EssentialsDiscordLink/src/main/resources/plugin.yml index 49df5f7f3d0..aa0568eabd7 100644 --- a/EssentialsDiscordLink/src/main/resources/plugin.yml +++ b/EssentialsDiscordLink/src/main/resources/plugin.yml @@ -7,6 +7,7 @@ description: EssentialsX Discord addon which allows you link your Minecraft and authors: [JRoy] depend: [EssentialsDiscord] api-version: 1.13 +folia-supported: true commands: link: description: Generates a code to link your Minecraft account to Discord. diff --git a/EssentialsGeoIP/src/main/resources/plugin.yml b/EssentialsGeoIP/src/main/resources/plugin.yml index 2ddee7b1201..6a52547ffad 100644 --- a/EssentialsGeoIP/src/main/resources/plugin.yml +++ b/EssentialsGeoIP/src/main/resources/plugin.yml @@ -8,3 +8,4 @@ description: Shows the country or city of a user on login and /whois. authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology, kjiang, pop4959] depend: [Essentials] api-version: 1.13 +folia-supported: true diff --git a/EssentialsProtect/src/main/resources/plugin.yml b/EssentialsProtect/src/main/resources/plugin.yml index 65764be4a41..25340332643 100644 --- a/EssentialsProtect/src/main/resources/plugin.yml +++ b/EssentialsProtect/src/main/resources/plugin.yml @@ -8,3 +8,4 @@ description: Provides protection for various parts of the world. authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology, KHobbits, drtshock] softdepend: [Essentials] api-version: 1.13 +folia-supported: true diff --git a/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/EssentialsSpawnPlayerListener.java b/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/EssentialsSpawnPlayerListener.java index 72f36803de7..016a7ce4d1b 100644 --- a/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/EssentialsSpawnPlayerListener.java +++ b/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/EssentialsSpawnPlayerListener.java @@ -83,7 +83,7 @@ private void delayedJoin(final Player player) { final User user = ess.getUser(player); if (ess.getSettings().isUserInSpawnOnJoinGroup(user) && !user.isAuthorized("essentials.spawn-on-join.exempt")) { - ess.scheduleSyncDelayedTask(() -> { + ess.scheduleEntityDelayedTask(player, () -> { final Location spawn = spawns.getSpawn(user.getGroup()); if (spawn == null) { return; @@ -104,10 +104,10 @@ private void delayedJoin(final Player player) { final User user = ess.getUser(player); if (!"none".equalsIgnoreCase(ess.getSettings().getNewbieSpawn())) { - ess.scheduleSyncDelayedTask(new NewPlayerTeleport(user), 1L); + ess.scheduleEntityDelayedTask(player, new NewPlayerTeleport(user), 1L); } - ess.scheduleSyncDelayedTask(() -> { + ess.scheduleEntityDelayedTask(player, () -> { if (!user.getBase().isOnline()) { return; } diff --git a/EssentialsSpawn/src/main/resources/plugin.yml b/EssentialsSpawn/src/main/resources/plugin.yml index e0a7b770d05..3746812f451 100644 --- a/EssentialsSpawn/src/main/resources/plugin.yml +++ b/EssentialsSpawn/src/main/resources/plugin.yml @@ -8,6 +8,7 @@ description: Provides spawn control commands, utilizing Essentials. authors: [Zenexer, ementalo, Aelux, Brettflan, KimKandor, snowleo, ceulemans, Xeology, KHobbits, SupaHam, mdcfe, DoNotSpamPls, JRoy] depend: [Essentials] api-version: 1.13 +folia-supported: true commands: setspawn: description: Sets the spawn point to your current position. diff --git a/providers/BaseProviders/src/main/java/net/ess3/provider/SchedulingProvider.java b/providers/BaseProviders/src/main/java/net/ess3/provider/SchedulingProvider.java new file mode 100644 index 00000000000..8206a16f213 --- /dev/null +++ b/providers/BaseProviders/src/main/java/net/ess3/provider/SchedulingProvider.java @@ -0,0 +1,40 @@ +package net.ess3.provider; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; + +public interface SchedulingProvider extends Provider { + void registerInitTask(Runnable runnable); + + boolean isEntityThread(Entity entity); + + boolean isRegionThread(Location location); + + boolean isGlobalThread(); + + void runEntityTask(Entity entity, Runnable runnable); + + EssentialsTask runEntityTask(Entity entity, Runnable runnable, long delay); + + EssentialsTask runEntityTaskRepeating(Entity entity, Runnable runnable, long delay, long period); + + void runLocationalTask(Location location, Runnable runnable); + + void runLocationalTask(Location location, Runnable runnable, long delay); + + EssentialsTask runLocationalTaskRepeating(Location location, Runnable runnable, long delay, long period); + + void runGlobalLocationalTask(Runnable runnable, long delay); + + EssentialsTask runGlobalLocationalTaskRepeating(Runnable runnable, long delay, long period); + + void runAsyncTask(Runnable runnable); + + void runAsyncTaskLater(Runnable runnable, long delay); + + EssentialsTask runAsyncTaskRepeating(Runnable runnable, long delay, long period); + + interface EssentialsTask { + void cancel(); + } +} diff --git a/providers/BaseProviders/src/main/java/net/ess3/provider/providers/BukkitSchedulingProvider.java b/providers/BaseProviders/src/main/java/net/ess3/provider/providers/BukkitSchedulingProvider.java new file mode 100644 index 00000000000..ac21c00405a --- /dev/null +++ b/providers/BaseProviders/src/main/java/net/ess3/provider/providers/BukkitSchedulingProvider.java @@ -0,0 +1,107 @@ +package net.ess3.provider.providers; + +import net.ess3.provider.SchedulingProvider; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitTask; + +public class BukkitSchedulingProvider implements SchedulingProvider { + private final Plugin plugin; + + public BukkitSchedulingProvider(final Plugin plugin) { + this.plugin = plugin; + } + + @Override + public void registerInitTask(Runnable runnable) { + plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, runnable); + } + + @Override + public boolean isEntityThread(Entity entity) { + return plugin.getServer().isPrimaryThread(); + } + + @Override + public boolean isRegionThread(Location location) { + return plugin.getServer().isPrimaryThread(); + } + + @Override + public boolean isGlobalThread() { + return Bukkit.isPrimaryThread(); + } + + @Override + public void runEntityTask(Entity entity, Runnable runnable) { + runEntityTask(entity, runnable, 1); + } + + @Override + public EssentialsTask runEntityTask(Entity entity, Runnable runnable, long delay) { + return scheduleSyncTask(runnable, delay); + } + + @Override + public EssentialsTask runEntityTaskRepeating(Entity entity, Runnable runnable, long delay, long period) { + return scheduleSyncTaskRepeating(runnable, delay, period); + } + + @Override + public void runLocationalTask(Location location, Runnable runnable) { + runGlobalLocationalTask(runnable, 1); + } + + @Override + public void runLocationalTask(Location location, Runnable runnable, long delay) { + runGlobalLocationalTask(runnable, delay); + } + + @Override + public EssentialsTask runLocationalTaskRepeating(Location location, Runnable runnable, long delay, long period) { + return scheduleSyncTaskRepeating(runnable, delay, period); + } + + @Override + public void runGlobalLocationalTask(Runnable runnable, long delay) { + scheduleSyncTask(runnable, delay); + } + + @Override + public EssentialsTask runGlobalLocationalTaskRepeating(Runnable runnable, long delay, long period) { + return scheduleSyncTaskRepeating(runnable, delay, period); + } + + private EssentialsTask scheduleSyncTask(Runnable runnable, long delay) { + final int task = plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, runnable, delay); + return () -> plugin.getServer().getScheduler().cancelTask(task); + } + + private EssentialsTask scheduleSyncTaskRepeating(Runnable runnable, long delay, long period) { + final BukkitTask task = plugin.getServer().getScheduler().runTaskTimer(plugin, runnable, delay, period); + return task::cancel; + } + + @Override + public void runAsyncTask(Runnable runnable) { + runAsyncTaskLater(runnable, 0); + } + + @Override + public void runAsyncTaskLater(Runnable runnable, long delay) { + plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay); + } + + @Override + public EssentialsTask runAsyncTaskRepeating(Runnable runnable, long delay, long period) { + final BukkitTask task = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, runnable, delay, period); + return task::cancel; + } + + @Override + public String getDescription() { + return "Bukkit Scheduling Provider"; + } +} diff --git a/providers/FoliaProvider/build.gradle b/providers/FoliaProvider/build.gradle new file mode 100644 index 00000000000..fe183290bd8 --- /dev/null +++ b/providers/FoliaProvider/build.gradle @@ -0,0 +1,19 @@ +plugins { + id("essentials.base-conventions") +} + +java { + disableAutoTargetJvm() +} + +dependencies { + implementation(project(':providers:BaseProviders')) { + exclude(module: 'spigot-api') + } + compileOnly 'dev.folia:folia-api:1.20.1-R0.1-SNAPSHOT' +} + +essentials { + injectBukkitApi.set(false) + injectBstats.set(false) +} diff --git a/providers/FoliaProvider/src/main/java/net/ess3/provider/providers/FoliaSchedulingProvider.java b/providers/FoliaProvider/src/main/java/net/ess3/provider/providers/FoliaSchedulingProvider.java new file mode 100644 index 00000000000..0e5e538f507 --- /dev/null +++ b/providers/FoliaProvider/src/main/java/net/ess3/provider/providers/FoliaSchedulingProvider.java @@ -0,0 +1,127 @@ +package net.ess3.provider.providers; + +import io.papermc.paper.threadedregions.RegionizedServerInitEvent; +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; +import net.ess3.provider.SchedulingProvider; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class FoliaSchedulingProvider implements SchedulingProvider, Listener { + private final Plugin plugin; + private List initTasks = new ArrayList<>(); + + public FoliaSchedulingProvider(Plugin plugin) { + this.plugin = plugin; + plugin.getServer().getPluginManager().registerEvents(this, plugin); + } + + @EventHandler + public void onServerInit(RegionizedServerInitEvent event) { + for (final Runnable tasks : initTasks) { + tasks.run(); + } + initTasks = null; + } + + @Override + public void registerInitTask(Runnable runnable) { + if (initTasks == null) { + throw new IllegalStateException(); + } + initTasks.add(runnable); + } + + @Override + public boolean isEntityThread(Entity entity) { + return plugin.getServer().isOwnedByCurrentRegion(entity); + } + + @Override + public boolean isRegionThread(Location location) { + return plugin.getServer().isOwnedByCurrentRegion(location); + } + + @Override + public boolean isGlobalThread() { + return plugin.getServer().isGlobalTickThread(); + } + + @Override + public void runEntityTask(Entity entity, Runnable runnable) { + runEntityTask(entity, runnable, 1); + } + + @Override + public EssentialsTask runEntityTask(Entity entity, Runnable runnable, long delay) { + final ScheduledTask task = entity.getScheduler().runDelayed(plugin, scheduledTask -> runnable.run(), null, delay); + if (task == null) { + throw new IllegalArgumentException("entity is removed!"); + } + return task::cancel; + } + + @Override + public EssentialsTask runEntityTaskRepeating(Entity entity, Runnable runnable, long delay, long period) { + final ScheduledTask task = entity.getScheduler().runAtFixedRate(plugin, scheduledTask -> runnable.run(), null, delay, period); + if (task == null) { + throw new IllegalArgumentException("entity is removed!"); + } + return task::cancel; + } + + @Override + public void runLocationalTask(Location location, Runnable runnable) { + plugin.getServer().getRegionScheduler().execute(plugin, location, runnable); + } + + @Override + public void runLocationalTask(Location location, Runnable runnable, long delay) { + plugin.getServer().getRegionScheduler().runDelayed(plugin, location, scheduledTask -> runnable.run(), delay); + } + + @Override + public EssentialsTask runLocationalTaskRepeating(Location location, Runnable runnable, long delay, long period) { + final ScheduledTask task = plugin.getServer().getRegionScheduler().runAtFixedRate(plugin, location, scheduledTask -> runnable.run(), delay, period);; + return task::cancel; + } + + @Override + public void runGlobalLocationalTask(Runnable runnable, long delay) { + plugin.getServer().getGlobalRegionScheduler().runDelayed(plugin, scheduledTask -> runnable.run(), delay); + } + + @Override + public EssentialsTask runGlobalLocationalTaskRepeating(Runnable runnable, long delay, long period) { + final ScheduledTask task = plugin.getServer().getGlobalRegionScheduler().runAtFixedRate(plugin, scheduledTask -> runnable.run(), delay, period); + return task::cancel; + } + + @Override + public void runAsyncTask(Runnable runnable) { + plugin.getServer().getAsyncScheduler().runNow(plugin, scheduledTask -> runnable.run()); + } + + @Override + public void runAsyncTaskLater(Runnable runnable, long delay) { + plugin.getServer().getAsyncScheduler().runDelayed(plugin, scheduledTask -> runnable.run(), delay * 50L, TimeUnit.MILLISECONDS); + } + + @Override + public EssentialsTask runAsyncTaskRepeating(Runnable runnable, long delay, long period) { + final ScheduledTask task = plugin.getServer().getAsyncScheduler().runAtFixedRate(plugin, scheduledTask -> runnable.run(), delay, period * 50, TimeUnit.MILLISECONDS); + return task::cancel; + } + + @Override + public String getDescription() { + return "Folia Scheduling Provider"; + } + +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 270e567afa0..b2ab4fe2844 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -50,5 +50,6 @@ sequenceOf( include(":providers:BaseProviders") include(":providers:NMSReflectionProvider") include(":providers:PaperProvider") +include(":providers:FoliaProvider") include(":providers:1_8Provider") include(":providers:1_12Provider")