diff --git a/src/main/java/com/intellectualcrafters/plot/config/C.java b/src/main/java/com/intellectualcrafters/plot/config/C.java index 3432fa728..dcdc9e24a 100644 --- a/src/main/java/com/intellectualcrafters/plot/config/C.java +++ b/src/main/java/com/intellectualcrafters/plot/config/C.java @@ -142,6 +142,8 @@ public enum C { /* * WorldEdit masks */ + WORLDEDIT_DELAYED("$2Please wait while we process your WorldEdit action...", "WorldEdit Masks"), + WORLDEDIT_RUN("$2Apologies for the delay. Now executing: %s", "WorldEdit Masks"), REQUIRE_SELECTION_IN_MASK("$2%s of your selection is not within your plot mask. You can only make edits within your plot.", "WorldEdit Masks"), WORLDEDIT_VOLUME("$2You cannot select a volume of %current%. The maximum volume you can modify is %max%.", "WorldEdit Masks"), WORLDEDIT_ITERATIONS("$2You cannot iterate %current% times. The maximum number of iterations allowed is %max%.", "WorldEdit Masks"), diff --git a/src/main/java/com/intellectualcrafters/plot/util/SetBlockQueue.java b/src/main/java/com/intellectualcrafters/plot/util/SetBlockQueue.java index 8ffcaf99e..6e9b15b6f 100644 --- a/src/main/java/com/intellectualcrafters/plot/util/SetBlockQueue.java +++ b/src/main/java/com/intellectualcrafters/plot/util/SetBlockQueue.java @@ -1,7 +1,7 @@ package com.intellectualcrafters.plot.util; +import java.util.ArrayDeque; import java.util.HashMap; -import java.util.HashSet; import java.util.Map.Entry; import com.intellectualcrafters.plot.PS; @@ -14,7 +14,7 @@ public class SetBlockQueue { private volatile static int allocate = 25; private volatile static boolean running = false; private volatile static boolean locked = false; - private volatile static HashSet runnables; + private volatile static ArrayDeque runnables; private volatile static boolean slow = false; private static long last; private static int lastInt = 0; @@ -32,15 +32,22 @@ public class SetBlockQueue { slow = value; } - public synchronized static void addNotify(Runnable whenDone) { + public synchronized static boolean addNotify(Runnable whenDone) { if (runnables == null) { - TaskManager.runTask(whenDone); - slow = false; - locked = false; + if (blocks == null) { + if (whenDone != null) { + whenDone.run(); + } + slow = false; + locked = false; + return true; + } + runnables = new ArrayDeque<>(); } - else { + if (whenDone != null) { runnables.add(whenDone); } + return false; } public synchronized static void init() { @@ -49,7 +56,7 @@ public class SetBlockQueue { MainUtil.initCache(); } blocks = new HashMap<>(); - runnables = new HashSet<>(); + runnables = new ArrayDeque<>(); } if (!running) { TaskManager.index.incrementAndGet(); @@ -62,17 +69,18 @@ public class SetBlockQueue { } if (blocks == null || blocks.size() == 0) { PS.get().TASK.cancelTask(TaskManager.tasks.get(current)); - if (runnables != null) { - for (Runnable runnable : runnables) { - TaskManager.runTask(runnable); - } - } + ArrayDeque tasks = runnables; lastInt = -1; lastBlock = null; runnables = null; - blocks = new HashMap<>(); + blocks = null; running = false; slow = false; + if (tasks != null) { + for (Runnable runnable : tasks) { + runnable.run(); + } + } return; } long newLast = System.currentTimeMillis(); diff --git a/src/main/java/com/plotsquared/bukkit/listeners/worldedit/WEListener.java b/src/main/java/com/plotsquared/bukkit/listeners/worldedit/WEListener.java index e72e6a571..b4919ab5d 100644 --- a/src/main/java/com/plotsquared/bukkit/listeners/worldedit/WEListener.java +++ b/src/main/java/com/plotsquared/bukkit/listeners/worldedit/WEListener.java @@ -3,7 +3,9 @@ package com.plotsquared.bukkit.listeners.worldedit; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.EventHandler; @@ -19,8 +21,10 @@ import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.RegionWrapper; import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.Permissions; +import com.intellectualcrafters.plot.util.SetBlockQueue; import com.plotsquared.bukkit.BukkitMain; import com.plotsquared.bukkit.util.BukkitUtil; +import com.plotsquared.bukkit.util.SetBlockFast; import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.bukkit.selections.Selection; @@ -39,6 +43,7 @@ public class WEListener implements Listener { public final HashSet unregioned = new HashSet<>(Arrays.asList("paste", "redo", "undo", "rotate", "flip", "generate", "schematic", "schem")); public final HashSet unsafe1 = new HashSet<>(Arrays.asList("cs", ".s", "restore", "snapshot", "delchunks", "listchunks")); public final HashSet restricted = new HashSet<>(Arrays.asList("up")); + public final HashSet other = new HashSet<>(Arrays.asList("undo", "redo")); public boolean checkCommand(List list, String cmd) { for (String identifier : list) { @@ -134,6 +139,36 @@ public class WEListener implements Listener { return checkVolume(pp, volume, max, e); } + private boolean set = false; + + public boolean delay(final Player player, final String command, boolean delayed) { + if (!Settings.EXPERIMENTAL_FAST_ASYNC_WORLDEDIT || set) { + return false; + } + boolean free = SetBlockQueue.addNotify(null); + if (free) { + if (delayed) { + MainUtil.sendMessage(BukkitUtil.getPlayer(player), C.WORLDEDIT_RUN, command); + Bukkit.getServer().dispatchCommand(player, command.substring(1)); + } + else { + return false; + } + } + else { + if (!delayed) { + MainUtil.sendMessage(BukkitUtil.getPlayer(player), C.WORLDEDIT_DELAYED); + } + SetBlockQueue.addNotify(new Runnable() { + @Override + public void run() { + delay(player, command, true); + } + }); + } + return true; + } + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public boolean onPlayerCommand(final PlayerCommandPreprocessEvent e) { final Player p = e.getPlayer(); @@ -141,23 +176,26 @@ public class WEListener implements Listener { if (!PS.get().isPlotWorld(p.getWorld().getName())) { return true; } - String cmd = e.getMessage().toLowerCase(); + String message = e.getMessage(); + String cmd = message.toLowerCase(); boolean single = true; String[] split = cmd.split(" "); long maxVolume = Settings.WE_MAX_VOLUME; long maxIterations = Settings.WE_MAX_ITERATIONS; - if (pp.getAttribute("worldedit" )) { + if (pp.getAttribute("worldedit")) { return true; } if (split.length >= 2) { String reduced = reduceCmd(split[0], single); String reduced2 = reduceCmd(split[0] + " " + split[1], single); if (rad1.contains(reduced)) { + if (delay(p, message, false)) { e.setCancelled(true); return true; } long volume = getInt(split[1]) * 256; return checkVolume(pp, volume, maxVolume, e); } if (rad2.contains(reduced)) { + if (delay(p, message, false)) { e.setCancelled(true); return true; } if (split.length >= 3) { long volume = getInt(split[2]) * 256; return checkVolume(pp, volume, maxVolume, e); @@ -165,6 +203,7 @@ public class WEListener implements Listener { return true; } if (rad2_1.contains(reduced)) { + if (delay(p, message, false)) { e.setCancelled(true); return true; } if (split.length >= 4) { long volume = getInt(split[2]) * getInt(split[3]); return checkVolume(pp, volume, maxVolume, e); @@ -172,6 +211,7 @@ public class WEListener implements Listener { return true; } if (rad2_2.contains(reduced)) { + if (delay(p, message, false)) { e.setCancelled(true); return true; } if (split.length >= 3) { long radius = getInt(split[2]); long volume = radius * radius; @@ -180,6 +220,7 @@ public class WEListener implements Listener { return true; } if (rad2_3.contains(reduced2)) { + if (delay(p, message, false)) { e.setCancelled(true); return true; } if (split.length >= 3) { if (split.length == 4) { int iterations = getInt(split[3]); @@ -199,6 +240,7 @@ public class WEListener implements Listener { return true; } if (rad3_1.contains(reduced2)) { + if (delay(p, message, false)) { e.setCancelled(true); return true; } if (split.length >= 3) { int i = 2; if (split[i].equalsIgnoreCase("-h")) { @@ -211,6 +253,7 @@ public class WEListener implements Listener { return true; } if (rad3_2.contains(reduced2)) { + if (delay(p, message, false)) { e.setCancelled(true); return true; } if (split.length >= 4) { int i = 3; if (split[i].equalsIgnoreCase("-h")) { @@ -223,6 +266,7 @@ public class WEListener implements Listener { return true; } if (regionExtend.contains(reduced)) { + if (delay(p, message, false)) { e.setCancelled(true); return true; } return checkSelection(p, pp, getInt(split[1]), maxVolume, e); } } @@ -237,6 +281,7 @@ public class WEListener implements Listener { if (restricted.contains(reduced)) { Plot plot = MainUtil.getPlot(pp.getLocation()); if (plot != null && plot.isAdded(pp.getUUID())) { + if (delay(p, message, false)) { e.setCancelled(true); return true; } return true; } e.setCancelled(true); @@ -247,8 +292,12 @@ public class WEListener implements Listener { return true; } if (region.contains(reduced)) { + if (delay(p, message, false)) { e.setCancelled(true); return true; } return checkSelection(p, pp, 1, maxVolume, e); } + if (other.contains(reduced)) { + if (delay(p, message, false)) { e.setCancelled(true); return true; } + } return true; } }