From 5a3eacde0b1f92bd8dfbcd25a61db8d3a8017f04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Fri, 17 Jul 2020 16:25:57 +0200 Subject: [PATCH] Replace method synchronization logic --- .../plotsquared/bukkit/util/BukkitUtil.java | 20 ++-- .../bukkit/util/task/BukkitTaskManager.java | 8 ++ .../com/plotsquared/core/command/Auto.java | 10 +- .../com/plotsquared/core/command/Claim.java | 57 +++++----- .../core/generator/HybridUtils.java | 25 ++--- .../core/plot/world/SinglePlotArea.java | 22 ++-- .../core/queue/BasicLocalBlockQueue.java | 14 ++- .../core/util/task/AutoClaimFinishTask.java | 10 +- .../core/util/task/TaskManager.java | 103 +++++++++--------- 9 files changed, 144 insertions(+), 125 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java index f25fdc621..5864b528e 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java @@ -42,7 +42,6 @@ import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.StringComparison; import com.plotsquared.core.util.WorldUtil; -import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; @@ -54,7 +53,6 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import io.papermc.lib.PaperLib; - import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Material; @@ -96,11 +94,11 @@ import org.bukkit.entity.Snowman; import org.bukkit.entity.Tameable; import org.bukkit.entity.Vehicle; import org.bukkit.entity.WaterMob; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -423,14 +421,18 @@ import java.util.stream.Stream; @Override @Nullable public String[] getSignSynchronous(@Nonnull final Location location) { Block block = getWorld(location.getWorldName()) .getBlockAt(location.getX(), location.getY(), location.getZ()); - return TaskManager.getImplementation().sync(new RunnableVal() { - @Override public void run(String[] value) { + try { + return TaskManager.getImplementation().sync(() -> { if (block.getState() instanceof Sign) { Sign sign = (Sign) block.getState(); - this.value = sign.getLines(); + return sign.getLines(); } - } - }); + return new String[0]; + }); + } catch (final Exception e) { + e.printStackTrace(); + } + return new String[0]; } @Override public Location getSpawn(@Nonnull final String world) { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/task/BukkitTaskManager.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/task/BukkitTaskManager.java index dd1168ab0..a8d054fc9 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/task/BukkitTaskManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/task/BukkitTaskManager.java @@ -31,8 +31,12 @@ import com.plotsquared.bukkit.BukkitPlatform; import com.plotsquared.core.util.task.PlotSquaredTask; import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskTime; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; /** * Bukkit implementation of {@link TaskManager} using @@ -75,6 +79,10 @@ import javax.annotation.Nonnull; } } + @Override public Future callMethodSync(@NotNull final Callable method) { + return Bukkit.getScheduler().callSyncMethod(this.bukkitMain, method); + } + @Override public void task(@Nonnull final Runnable runnable) { new BukkitPlotSquaredTask(runnable).runTaskAsynchronously(this.bukkitMain); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Auto.java b/Core/src/main/java/com/plotsquared/core/command/Auto.java index e212d3e58..adfb04ef6 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Auto.java +++ b/Core/src/main/java/com/plotsquared/core/command/Auto.java @@ -147,13 +147,17 @@ public class Auto extends SubCommand { * @param start * @param schematic */ - public static void autoClaimSafe(final PlotPlayer player, final PlotArea area, PlotId start, + public static void autoClaimSafe(final PlotPlayer player, final PlotArea area, PlotId start, final String schematic) { player.setMeta(Auto.class.getName(), true); autoClaimFromDatabase(player, area, start, new RunnableVal() { @Override public void run(final Plot plot) { - TaskManager.getImplementation().sync(new AutoClaimFinishTask(player, plot, area, schematic, - PlotSquared.get().getEventDispatcher())); + try { + TaskManager.getImplementation().sync(new AutoClaimFinishTask(player, plot, area, schematic, + PlotSquared.get().getEventDispatcher())); + } catch (final Exception e) { + e.printStackTrace(); + } } }); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Claim.java b/Core/src/main/java/com/plotsquared/core/command/Claim.java index 7b51ea6cf..f698bdc10 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Claim.java +++ b/Core/src/main/java/com/plotsquared/core/command/Claim.java @@ -27,7 +27,6 @@ package com.plotsquared.core.command; import com.google.common.primitives.Ints; import com.google.inject.Inject; -import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.CaptionUtility; import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.Settings; @@ -44,29 +43,24 @@ import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.Expression; import com.plotsquared.core.util.Permissions; -import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@CommandDeclaration(command = "claim", - aliases = "c", - description = "Claim the current plot you're standing on", - category = CommandCategory.CLAIMING, - requiredType = RequiredType.PLAYER, - permission = "plots.claim", - usage = "/plot claim") +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +@CommandDeclaration(command = "claim", aliases = "c", description = "Claim the current plot you're standing on", category = CommandCategory.CLAIMING, requiredType = RequiredType.PLAYER, permission = "plots.claim", usage = "/plot claim") public class Claim extends SubCommand { - private static final Logger logger = LoggerFactory.getLogger("P2/" + Claim.class.getSimpleName()); + private static final Logger logger = + LoggerFactory.getLogger("P2/" + Claim.class.getSimpleName()); private final EventDispatcher eventDispatcher; private final EconHandler econHandler; @Inject public Claim(@Nonnull final EventDispatcher eventDispatcher, - @Nullable final EconHandler econHandler) { + @Nullable final EconHandler econHandler) { this.eventDispatcher = eventDispatcher; this.econHandler = econHandler; } @@ -146,24 +140,29 @@ public class Claim extends SubCommand { } plot.setOwnerAbs(player.getUUID()); final String finalSchematic = schematic; - DBFunc.createPlotSafe(plot, () -> TaskManager.getImplementation().sync(new RunnableVal() { - @Override public void run(Object value) { - if (!plot.claim(player, true, finalSchematic, false)) { - logger.info(Captions.PREFIX.getTranslated() + String - .format("Failed to claim plot %s", plot.getId().toCommaSeparatedString())); - sendMessage(player, Captions.PLOT_NOT_CLAIMED); - plot.setOwnerAbs(null); - } else if (area.isAutoMerge()) { - PlotMergeEvent event = Claim.this.eventDispatcher - .callMerge(plot, Direction.ALL, Integer.MAX_VALUE, player); - if (event.getEventResult() == Result.DENY) { - sendMessage(player, Captions.EVENT_DENIED, "Auto merge on claim"); - } else { - plot.autoMerge(event.getDir(), event.getMax(), player.getUUID(), true); + DBFunc.createPlotSafe(plot, () -> { + try { + TaskManager.getImplementation().sync(() -> { + if (!plot.claim(player, true, finalSchematic, false)) { + logger.info(Captions.PREFIX.getTranslated() + String + .format("Failed to claim plot %s", plot.getId().toCommaSeparatedString())); + sendMessage(player, Captions.PLOT_NOT_CLAIMED); + plot.setOwnerAbs(null); + } else if (area.isAutoMerge()) { + PlotMergeEvent mergeEvent = Claim.this.eventDispatcher + .callMerge(plot, Direction.ALL, Integer.MAX_VALUE, player); + if (mergeEvent.getEventResult() == Result.DENY) { + sendMessage(player, Captions.EVENT_DENIED, "Auto merge on claim"); + } else { + plot.autoMerge(mergeEvent.getDir(), mergeEvent.getMax(), player.getUUID(), true); + } } - } + return null; + }); + } catch (final Exception e) { + e.printStackTrace(); } - }), () -> { + }, () -> { logger.info(Captions.PREFIX.getTranslated() + String .format("Failed to add plot %s to the database", plot.getId().toCommaSeparatedString())); diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java b/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java index 5da96f94b..3846e9e72 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridUtils.java @@ -479,21 +479,20 @@ public class HybridUtils { } } if (!chunks.isEmpty()) { - TaskManager.getImplementation().sync(new RunnableVal() { - @Override public void run(Object value) { - long start = System.currentTimeMillis(); - Iterator iterator = chunks.iterator(); - while (System.currentTimeMillis() - start < 20 && !chunks - .isEmpty()) { - final BlockVector2 chunk = iterator.next(); - iterator.remove(); - boolean regenedRoads = - regenerateRoad(area, chunk, extend); - if (!regenedRoads && Settings.DEBUG) { - logger.info("[P2] Failed to regenerate road"); - } + TaskManager.getImplementation().sync(() -> { + long start = System.currentTimeMillis(); + Iterator iterator = chunks.iterator(); + while (System.currentTimeMillis() - start < 20 && !chunks + .isEmpty()) { + final BlockVector2 chunk = iterator.next(); + iterator.remove(); + boolean regenedRoads = + regenerateRoad(area, chunk, extend); + if (!regenedRoads && Settings.DEBUG) { + logger.info("[P2] Failed to regenerate road"); } } + return null; }); } } catch (Exception e) { diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotArea.java b/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotArea.java index a7dcd8f22..ecda867bc 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotArea.java +++ b/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotArea.java @@ -47,11 +47,10 @@ import com.plotsquared.core.setup.PlotAreaBuilder; import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EventDispatcher; -import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; + import javax.annotation.Nonnull; import javax.annotation.Nullable; - import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -141,15 +140,18 @@ public class SinglePlotArea extends GridPlotWorld { } } - TaskManager.getImplementation().sync(new RunnableVal() { - @Override public void run(Object value) { - String worldName = id.getX() + "." + id.getY(); - if (PlotSquared.platform().getWorldUtil().isWorld(worldName)) { - return; + try { + TaskManager.getImplementation().sync(() -> { + final String name = id.getX() + "." + id.getY(); + if (!PlotSquared.platform().getWorldUtil().isWorld(name)) { + PlotSquared.platform().getSetupUtils().setupWorld(builder); } - PlotSquared.platform().getSetupUtils().setupWorld(builder); - } - }); + return null; + }); + } catch (final Exception e) { + e.printStackTrace(); + } + // String worldName = plot.getWorldName(); // World world = Bukkit.getWorld(worldName); // if (world != null) { diff --git a/Core/src/main/java/com/plotsquared/core/queue/BasicLocalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/BasicLocalBlockQueue.java index e2bdd37e6..a5d0734c5 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/BasicLocalBlockQueue.java +++ b/Core/src/main/java/com/plotsquared/core/queue/BasicLocalBlockQueue.java @@ -28,14 +28,13 @@ package com.plotsquared.core.queue; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.PatternUtil; -import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; -import javax.annotation.Nonnull; +import javax.annotation.Nonnull; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ExecutionException; @@ -185,12 +184,15 @@ public abstract class BasicLocalBlockQueue extends LocalBlockQueue { @Override public void flush() { this.globalBlockQueue.dequeue(this); - TaskManager.getImplementation().sync(new RunnableVal() { - @Override public void run(Object value) { + try { + TaskManager.getImplementation().sync(() -> { while (next()) { } - } - }); + return null; + }); + } catch (final Exception e) { + e.printStackTrace(); + } } diff --git a/Core/src/main/java/com/plotsquared/core/util/task/AutoClaimFinishTask.java b/Core/src/main/java/com/plotsquared/core/util/task/AutoClaimFinishTask.java index 1ac9c81e8..cdcdee0e7 100644 --- a/Core/src/main/java/com/plotsquared/core/util/task/AutoClaimFinishTask.java +++ b/Core/src/main/java/com/plotsquared/core/util/task/AutoClaimFinishTask.java @@ -36,10 +36,12 @@ import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.util.EventDispatcher; import lombok.RequiredArgsConstructor; +import java.util.concurrent.Callable; + import static com.plotsquared.core.util.MainUtil.sendMessage; @RequiredArgsConstructor -public final class AutoClaimFinishTask extends RunnableVal { +public final class AutoClaimFinishTask implements Callable { private final PlotPlayer player; private final Plot plot; @@ -47,11 +49,11 @@ public final class AutoClaimFinishTask extends RunnableVal { private final String schematic; private final EventDispatcher eventDispatcher; - @Override public void run(Object value) { + @Override public Boolean call() { player.deleteMeta(Auto.class.getName()); if (plot == null) { sendMessage(player, Captions.NO_FREE_PLOTS); - return; + return false; } plot.claim(player, true, schematic, false); if (area.isAutoMerge()) { @@ -62,5 +64,7 @@ public final class AutoClaimFinishTask extends RunnableVal { plot.autoMerge(event.getDir(), event.getMax(), player.getUUID(), true); } } + return true; } + } diff --git a/Core/src/main/java/com/plotsquared/core/util/task/TaskManager.java b/Core/src/main/java/com/plotsquared/core/util/task/TaskManager.java index e39d8182b..629057583 100644 --- a/Core/src/main/java/com/plotsquared/core/util/task/TaskManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/task/TaskManager.java @@ -26,20 +26,30 @@ package com.plotsquared.core.util.task; import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.util.RuntimeExceptionRunnableVal; import lombok.Getter; import lombok.Setter; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +/** + * Task manager that handles scheduling of tasks. + * Synchronous methods make no guarantee of being scheduled on the + * server thread, instead they guarantee that no two synchronous + * operations happen at the same time. Implementations of + * the task manager might make other guarantees. All asynchronous + * operations will happen on another thread, no matter where + * they're scheduled from. + */ public abstract class TaskManager { public static final HashSet TELEPORT_QUEUE = new HashSet<>(); @@ -57,7 +67,7 @@ public abstract class TaskManager { * @return Created task object, can be used to cancel the task */ @Nonnull public static PlotSquaredTask runTaskRepeat(@Nullable final Runnable runnable, - @Nonnull final TaskTime taskTime) { + @Nonnull final TaskTime taskTime) { if (runnable != null) { if (getImplementation() == null) { throw new IllegalArgumentException("disabled"); @@ -67,25 +77,6 @@ public abstract class TaskManager { return PlotSquaredTask.nullTask(); } - /** - * Run a repeating asynchronous task. This will never run on the - * server thread - * - * @param runnable Task to run - * @param taskTime Task interval - * @return Created task object, can be used to cancel the task - */ - @Nonnull public static PlotSquaredTask runTaskRepeatAsync(@Nullable final Runnable runnable, - @NotNull final TaskTime taskTime) { - if (runnable != null) { - if (getImplementation() == null) { - throw new IllegalArgumentException("disabled"); - } - return getImplementation().taskRepeatAsync(runnable, taskTime); - } - return PlotSquaredTask.nullTask(); - } - /** * Run an asynchronous task. This will never run on the server thread * @@ -125,7 +116,7 @@ public abstract class TaskManager { * @param taskTime Task delay */ public static void runTaskLater(@Nullable final Runnable runnable, - @Nonnull final TaskTime taskTime) { + @Nonnull final TaskTime taskTime) { if (runnable != null) { if (getImplementation() == null) { runnable.run(); @@ -143,7 +134,7 @@ public abstract class TaskManager { * @param taskTime Task delay */ public static void runTaskLaterAsync(@Nullable final Runnable runnable, - @Nonnull final TaskTime taskTime) { + @Nonnull final TaskTime taskTime) { if (runnable != null) { if (getImplementation() == null) { runnable.run(); @@ -162,34 +153,44 @@ public abstract class TaskManager { TaskManager.runTask(new ObjectTaskRunnable<>(iterator, task, whenDone)); } - public T sync(final RunnableVal function) { + /** + * Make a synchronous method call and return the result + * + * @param function Method to call + * @param Return type + * @return Method result + * @throws Exception If the call fails + */ + public T sync(final Callable function) throws Exception { return sync(function, Integer.MAX_VALUE); } - public T sync(final RunnableVal function, int timeout) { + /** + * Make a synchronous method call and return the result + * + * @param function Method to call + * @param timeout Timeout (ms) + * @param Return type + * @return Method result + * @throws Exception If the call fails + */ + public T sync(final Callable function, int timeout) throws Exception { if (PlotSquared.get().isMainThread(Thread.currentThread())) { - function.run(); - return function.value; + return function.call(); } - final AtomicBoolean running = new AtomicBoolean(true); - final RuntimeExceptionRunnableVal run = - new RuntimeExceptionRunnableVal<>(function, running); - TaskManager.getImplementation().task(run); - try { - synchronized (function) { - while (running.get()) { - function.wait(timeout); - } - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - if (run.value != null) { - throw run.value; - } - return function.value; + return this.callMethodSync(function).get(timeout, TimeUnit.MILLISECONDS); } + /** + * Call a method synchronously and return a future with + * the result of the result + * + * @param method Method to be ran synchronously + * @param Return type + * @return Future completing with the result + */ + public abstract Future callMethodSync(@Nonnegative final Callable method); + /** * Run a repeating synchronous task. If using a platform scheduler, * this is guaranteed to run on the server thread @@ -199,7 +200,7 @@ public abstract class TaskManager { * @return Created task object, can be used to cancel the task */ public abstract PlotSquaredTask taskRepeat(@Nonnull Runnable runnable, - @Nonnull TaskTime taskTime); + @Nonnull TaskTime taskTime); /** * Run a repeating asynchronous task. This will never run on the @@ -210,7 +211,7 @@ public abstract class TaskManager { * @return Created task object, can be used to cancel the task */ public abstract PlotSquaredTask taskRepeatAsync(@Nonnull Runnable runnable, - @Nonnull TaskTime taskTime); + @Nonnull TaskTime taskTime); /** * Run an asynchronous task. This will never run on the server thread @@ -234,8 +235,7 @@ public abstract class TaskManager { * @param runnable Task to run * @param taskTime Task delay */ - public abstract void taskLater(@Nonnull Runnable runnable, - @Nonnull TaskTime taskTime); + public abstract void taskLater(@Nonnull Runnable runnable, @Nonnull TaskTime taskTime); /** * Run an asynchronous task after a given delay. This will never @@ -244,7 +244,6 @@ public abstract class TaskManager { * @param runnable Task to run * @param taskTime Task delay */ - public abstract void taskLaterAsync(@Nonnull Runnable runnable, - @Nonnull TaskTime taskTime); + public abstract void taskLaterAsync(@Nonnull Runnable runnable, @Nonnull TaskTime taskTime); }