diff --git a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java index 6d876973..2b986cc0 100644 --- a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java +++ b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java @@ -9,11 +9,14 @@ import com.boydti.fawe.object.brush.visualization.VirtualWorld; import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.task.SimpleAsyncNotifyQueue; +import com.boydti.fawe.object.task.ThrowableSupplier; +import com.boydti.fawe.object.task.ThrowableRunnable; import com.boydti.fawe.regions.FaweMaskManager; import com.boydti.fawe.util.*; import com.boydti.fawe.wrappers.FakePlayer; import com.boydti.fawe.wrappers.LocationMaskedPlayerWrapper; import com.boydti.fawe.wrappers.PlayerWrapper; +import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.worldedit.*; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.command.tool.BrushTool; @@ -160,16 +163,35 @@ public abstract class FawePlayer extends Metadatable { return cancelled; } - private void setConfirmTask(@Nullable WorldEditRunnable task, String command) { - setMeta("cmdConfirm", task == null ? (WorldEditRunnable) () -> - CommandManager.getInstance().handleCommandOnCurrentThread(new CommandEvent(getPlayer(), command)) - : task); + private void setConfirmTask(@Nullable ThrowableRunnable task, CommandContext context, String command) { + if (task != null) { + Runnable newTask = new Runnable() { + @Override + public void run() { + CommandManager.getInstance().handleCommandTask(new ThrowableSupplier() { + @Override + public Object get() throws Throwable { + task.run(); + return null; + } + }, context.getLocals()); + } + }; + setMeta("cmdConfirm", newTask); + } else { + setMeta("cmdConfirm", new Runnable() { + @Override + public void run() { + CommandManager.getInstance().handleCommandOnCurrentThread(new CommandEvent(getPlayer(), command)); + } + }); + } } - public void checkConfirmation(@Nullable WorldEditRunnable task, String command, int times, int limit) throws WorldEditException { + public void checkConfirmation(@Nullable ThrowableRunnable task, String command, int times, int limit, CommandContext context) throws WorldEditException { if (command != null && !getMeta("cmdConfirmRunning", false)) { if (times > limit) { - setConfirmTask(task, command); + setConfirmTask(task, context, command); String volume = ""; throw new RegionOperationException(BBC.WORLDEDIT_CANCEL_REASON_CONFIRM.f(0, times, command, volume)); } @@ -177,11 +199,11 @@ public abstract class FawePlayer extends Metadatable { if (task != null) task.run(); } - public void checkConfirmationRadius(@Nullable WorldEditRunnable task, String command, int radius) throws WorldEditException { + public void checkConfirmationRadius(@Nullable ThrowableRunnable task, String command, int radius, CommandContext context) throws WorldEditException { if (command != null && !getMeta("cmdConfirmRunning", false)) { if (radius > 0) { if (radius > 448) { - setConfirmTask(task, command); + setConfirmTask(task, context, command); long volume = (long) (Math.PI * ((double) radius * radius)); throw new RegionOperationException(BBC.WORLDEDIT_CANCEL_REASON_CONFIRM.f(0, radius, command, NumberFormat.getNumberInstance().format(volume))); } @@ -190,14 +212,14 @@ public abstract class FawePlayer extends Metadatable { if (task != null) task.run(); } - public void checkConfirmationStack(@Nullable WorldEditRunnable task, String command, Region region, int times) throws WorldEditException { + public void checkConfirmationStack(@Nullable ThrowableRunnable task, String command, Region region, int times, CommandContext context) throws WorldEditException { if (command != null && !getMeta("cmdConfirmRunning", false)) { if (region != null) { Vector min = region.getMinimumPoint().toBlockVector(); Vector max = region.getMaximumPoint().toBlockVector(); long area = (long) ((max.getX() - min.getX()) * (max.getZ() - min.getZ() + 1)) * times; if (area > 2 << 18) { - setConfirmTask(task, command); + setConfirmTask(task, context, command); long volume = (long) max.subtract(min).add(Vector.ONE).volume() * times; throw new RegionOperationException(BBC.WORLDEDIT_CANCEL_REASON_CONFIRM.f(min, max, command, NumberFormat.getNumberInstance().format(volume))); } @@ -206,14 +228,14 @@ public abstract class FawePlayer extends Metadatable { if (task != null) task.run(); } - public void checkConfirmationRegion(@Nullable WorldEditRunnable task, String command, Region region) throws WorldEditException { + public void checkConfirmationRegion(@Nullable ThrowableRunnable task, String command, Region region, CommandContext context) throws WorldEditException { if (command != null && !getMeta("cmdConfirmRunning", false)) { if (region != null) { Vector min = region.getMinimumPoint().toBlockVector(); Vector max = region.getMaximumPoint().toBlockVector(); long area = (long) ((max.getX() - min.getX()) * (max.getZ() - min.getZ() + 1)); if (area > 2 << 18) { - setConfirmTask(task, command); + setConfirmTask(task, context, command); long volume = (long) max.subtract(min).add(Vector.ONE).volume(); throw new RegionOperationException(BBC.WORLDEDIT_CANCEL_REASON_CONFIRM.f(min, max, command, NumberFormat.getNumberInstance().format(volume))); } @@ -223,7 +245,7 @@ public abstract class FawePlayer extends Metadatable { } public synchronized boolean confirm() { - WorldEditRunnable confirm = deleteMeta("cmdConfirm"); + Runnable confirm = deleteMeta("cmdConfirm"); if (!(confirm instanceof Runnable)) { return false; } @@ -231,8 +253,6 @@ public abstract class FawePlayer extends Metadatable { setMeta("cmdConfirmRunning", true); try { confirm.run(); - } catch (WorldEditException e) { - throw new RuntimeException(e); } finally { setMeta("cmdConfirmRunning", false); } diff --git a/core/src/main/java/com/boydti/fawe/object/WorldEditRunnable.java b/core/src/main/java/com/boydti/fawe/object/WorldEditRunnable.java deleted file mode 100644 index 0c1f1793..00000000 --- a/core/src/main/java/com/boydti/fawe/object/WorldEditRunnable.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.boydti.fawe.object; - -import com.sk89q.worldedit.WorldEditException; - -public interface WorldEditRunnable { - void run() throws WorldEditException; -} diff --git a/core/src/main/java/com/boydti/fawe/object/task/ThrowableRunnable.java b/core/src/main/java/com/boydti/fawe/object/task/ThrowableRunnable.java new file mode 100644 index 00000000..f8776b45 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/task/ThrowableRunnable.java @@ -0,0 +1,7 @@ +package com.boydti.fawe.object.task; + +import com.sk89q.worldedit.WorldEditException; + +public interface ThrowableRunnable { + void run() throws T; +} diff --git a/core/src/main/java/com/boydti/fawe/object/task/ThrowableSupplier.java b/core/src/main/java/com/boydti/fawe/object/task/ThrowableSupplier.java new file mode 100644 index 00000000..f51044f7 --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/task/ThrowableSupplier.java @@ -0,0 +1,5 @@ +package com.boydti.fawe.object.task; + +public interface ThrowableSupplier { + Object get() throws T; +} diff --git a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java index 15266542..dbecf329 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/ClipboardCommands.java @@ -182,7 +182,7 @@ public class ClipboardCommands extends MethodCommands { BBC.COMMAND_COPY.send(player, region.getArea()); if (!FawePlayer.wrap(player).hasPermission("fawe.tips")) BBC.TIP_PASTE.or(BBC.TIP_DOWNLOAD, BBC.TIP_ROTATE, BBC.TIP_COPYPASTE, BBC.TIP_REPLACE_MARKER, BBC.TIP_COPY_PATTERN).send(player); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -275,7 +275,7 @@ public class ClipboardCommands extends MethodCommands { BBC.COMMAND_CUT_SLOW.send(player, region.getArea()); if (!FawePlayer.wrap(player).hasPermission("fawe.tips")) BBC.TIP_LAZYCUT.send(player); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command(aliases = {"download"}, desc = "Downloads your clipboard through the configured web interface") diff --git a/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index 0f26bdde..fc527568 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -89,7 +89,7 @@ public class GenerationCommands extends MethodCommands { CavesGen gen = new CavesGen(size, frequency, rarity, minY, maxY, systemFrequency, individualRarity, pocketChance, pocketMin, pocketMax); editSession.generate(region, gen); BBC.VISITOR_BLOCK.send(fp, editSession.getBlockChangeCount()); - }, getArguments(context), region); + }, getArguments(context), region, context); } // public void addOre(Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException { @@ -107,7 +107,7 @@ public class GenerationCommands extends MethodCommands { player.checkConfirmationRegion(() -> { editSession.addOres(region, mask); BBC.VISITOR_BLOCK.send(player, editSession.getBlockChangeCount()); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -171,7 +171,7 @@ public class GenerationCommands extends MethodCommands { player.checkConfirmationRegion(() -> { editSession.addOre(region, mask, material, size, freq, rarity, minY, maxY); BBC.VISITOR_BLOCK.send(player, editSession.getBlockChangeCount()); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -195,7 +195,7 @@ public class GenerationCommands extends MethodCommands { fp.checkConfirmationRadius(() -> { int affected = editSession.makeHollowCylinder(pos, pattern, radius.getX(), radius.getZ(), Math.min(256, height), thickness - 1); BBC.VISITOR_BLOCK.send(fp, affected); - }, getArguments(context), (int) max); + }, getArguments(context), (int) max, context); } @Command( @@ -220,7 +220,7 @@ public class GenerationCommands extends MethodCommands { fp.checkConfirmationRadius(() -> { int affected = editSession.makeCylinder(pos, pattern, radius.getX(), radius.getZ(), Math.min(256, height), !hollow); BBC.VISITOR_BLOCK.send(fp, affected); - }, getArguments(context), (int) max); + }, getArguments(context), (int) max, context); } @Command( @@ -265,7 +265,7 @@ public class GenerationCommands extends MethodCommands { int affected = editSession.makeSphere(finalPos, pattern, radius.getX(), radius.getY(), radius.getZ(), !hollow); player.findFreePosition(); BBC.VISITOR_BLOCK.send(fp, affected); - }, getArguments(context), (int) max); + }, getArguments(context), (int) max, context); } @Command( @@ -328,7 +328,7 @@ public class GenerationCommands extends MethodCommands { int affected = editSession.makePyramid(pos, pattern, size, !hollow); player.findFreePosition(); BBC.VISITOR_BLOCK.send(fp, affected); - }, getArguments(context), size); + }, getArguments(context), size, context); } @Command( @@ -396,7 +396,7 @@ public class GenerationCommands extends MethodCommands { } catch (ExpressionException e) { fp.sendMessage(BBC.getPrefix() + e.getMessage()); } - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -463,7 +463,7 @@ public class GenerationCommands extends MethodCommands { } catch (ExpressionException e) { fp.sendMessage(BBC.getPrefix() + e.getMessage()); } - }, getArguments(context), region); + }, getArguments(context), region, context); } public static Class inject() { diff --git a/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java b/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java index d36d82c1..7e10d797 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/HistoryCommands.java @@ -254,7 +254,7 @@ public class HistoryCommands extends MethodCommands { break; } } - }, getArguments(context), times, 50); + }, getArguments(context), times, 50, context); } @Command( diff --git a/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index 290b939c..f02f6a26 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -285,7 +285,7 @@ public class RegionCommands extends MethodCommands { int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, thickness, !shell); BBC.VISITOR_BLOCK.send(player, blocksChanged); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -304,7 +304,7 @@ public class RegionCommands extends MethodCommands { BBC.VISITOR_BLOCK.send(player, affected); if (!player.hasPermission("fawe.tips")) BBC.TIP_REPLACE_ID.or(BBC.TIP_REPLACE_LIGHT, BBC.TIP_REPLACE_MARKER, BBC.TIP_TAB_COMPLETE).send(player); - }, getArguments(context), region); + }, getArguments(context), region, context); } // Compatibility for SKCompat @@ -331,7 +331,7 @@ public class RegionCommands extends MethodCommands { if (!player.hasPermission("fawe.tips")) BBC.TIP_FAST.or(BBC.TIP_CANCEL, BBC.TIP_MASK, BBC.TIP_MASK_ANGLE, BBC.TIP_SET_LINEAR, BBC.TIP_SURFACE_SPREAD, BBC.TIP_SET_HAND).send(player); } - }, getArguments(context), selection); + }, getArguments(context), selection, context); } @Command( @@ -347,7 +347,7 @@ public class RegionCommands extends MethodCommands { player.checkConfirmationRegion(() -> { int affected = editSession.overlayCuboidBlocks(region, pattern); BBC.VISITOR_BLOCK.send(player, affected); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -382,7 +382,7 @@ public class RegionCommands extends MethodCommands { affected++; } BBC.VISITOR_BLOCK.send(player, affected); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -412,7 +412,7 @@ public class RegionCommands extends MethodCommands { player.checkConfirmationRegion(() -> { int affected = editSession.naturalizeCuboidBlocks(region); BBC.VISITOR_BLOCK.send(player, affected); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -428,7 +428,7 @@ public class RegionCommands extends MethodCommands { player.checkConfirmationRegion(() -> { int affected = editSession.makeWalls(region, pattern); BBC.VISITOR_BLOCK.send(player, affected); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -444,7 +444,7 @@ public class RegionCommands extends MethodCommands { player.checkConfirmationRegion(() -> { int affected = editSession.makeCuboidFaces(region, pattern); BBC.VISITOR_BLOCK.send(player, affected); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -478,7 +478,7 @@ public class RegionCommands extends MethodCommands { } catch (Throwable e) { throw new RuntimeException(e); } - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -556,7 +556,7 @@ public class RegionCommands extends MethodCommands { } BBC.VISITOR_BLOCK.send(player, affected); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -580,7 +580,7 @@ public class RegionCommands extends MethodCommands { player.checkConfirmationRegion(() -> { int affected = editSession.fall(region, !notFullHeight, replace); BBC.VISITOR_BLOCK.send(player, affected); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -626,7 +626,7 @@ public class RegionCommands extends MethodCommands { } BBC.VISITOR_BLOCK.send(player, affected); - }, getArguments(context), region, count); + }, getArguments(context), region, count, context); } @Command( @@ -678,7 +678,7 @@ public class RegionCommands extends MethodCommands { } catch (ExpressionException e) { fp.sendMessage(BBC.getPrefix() + e.getMessage()); } - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -721,7 +721,7 @@ public class RegionCommands extends MethodCommands { } else { BBC.COMMAND_REGEN_2.send(player); } - }, getArguments(args), region); + }, getArguments(args), region, args); } @Command( @@ -745,7 +745,7 @@ public class RegionCommands extends MethodCommands { player.checkConfirmationRegion(() -> { int affected = editSession.hollowOutRegion(region, thickness, pattern); BBC.VISITOR_BLOCK.send(player, affected); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -768,7 +768,7 @@ public class RegionCommands extends MethodCommands { Operations.completeLegacy(visitor); BBC.COMMAND_TREE.send(player, ground.getAffected()); - }, getArguments(context), region); + }, getArguments(context), region, context); } @Command( @@ -789,7 +789,7 @@ public class RegionCommands extends MethodCommands { Operations.completeLegacy(visitor); BBC.COMMAND_FLORA.send(player, ground.getAffected()); - }, getArguments(context), region); + }, getArguments(context), region, context); } public static Class inject() { diff --git a/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java index 56d6096d..b3876599 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java @@ -27,6 +27,7 @@ import com.boydti.fawe.command.PatternBinding; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.exception.FaweException; +import com.boydti.fawe.object.task.ThrowableSupplier; import com.boydti.fawe.util.StringMan; import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.chat.UsageMessage; @@ -60,6 +61,7 @@ import com.sk89q.worldedit.util.eventbus.Subscribe; import com.sk89q.worldedit.util.logging.DynamicStreamHandler; import com.sk89q.worldedit.util.logging.LogFormat; +import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.util.HashSet; @@ -375,6 +377,8 @@ public final class CommandManager { throw new IllegalArgumentException("FAWE doesn't support: " + actor); } final Set failedPermissions = new LinkedHashSet<>(); + locals.put("failed_permissions", failedPermissions); + locals.put(LocalSession.class, session); if (actor instanceof Player) { Player player = (Player) actor; Player unwrapped = LocationMaskedPlayerWrapper.unwrap(player); @@ -399,10 +403,28 @@ public final class CommandManager { } }; } - Request.reset(); locals.put(Actor.class, actor); final Actor finalActor = actor; locals.put("arguments", args); + + ThrowableSupplier task = new ThrowableSupplier() { + @Override + public Object get() throws Throwable { + return dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]); + } + }; + + handleCommandTask(task, locals, actor, session, failedPermissions, fp); + } + + public Object handleCommandTask(ThrowableSupplier task, CommandLocals locals) { + return handleCommandTask(task, locals, null, null, null, null); + } + + private Object handleCommandTask(ThrowableSupplier task, CommandLocals locals, @Nullable Actor actor, @Nullable LocalSession session, @Nullable Set failedPermissions, @Nullable FawePlayer fp) { + Request.reset(); + if (actor == null) actor = locals.get(Actor.class); + if (session == null) session = locals.get(LocalSession.class); long start = System.currentTimeMillis(); try { // This is a bit of a hack, since the call method can only throw CommandExceptions @@ -410,8 +432,8 @@ public final class CommandManager { // exceptions without writing a hook into every dispatcher, we need to unwrap these // exceptions and rethrow their converted form, if their is one. try { - Request.request().setActor(finalActor); - Object result = dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]); + Request.request().setActor(actor); + return task.get(); } catch (Throwable t) { // Use the exception converter to convert the exception if any of its causes // can be converted, otherwise throw the original exception @@ -424,28 +446,31 @@ public final class CommandManager { throw next; } } catch (CommandPermissionsException e) { - BBC.NO_PERM.send(finalActor, StringMan.join(failedPermissions, " ")); + if (failedPermissions == null) failedPermissions = (Set) locals.get("failed_permissions"); + if (failedPermissions != null) BBC.NO_PERM.send(actor, StringMan.join(failedPermissions, " ")); } catch (InvalidUsageException e) { if (e.isFullHelpSuggested()) { CommandCallable cmd = e.getCommand(); if (cmd instanceof Dispatcher) { try { - CommandContext context = new CommandContext(("ignoreThis " + Joiner.on(" ").join(split)).split(" "), new HashSet<>(), false, locals); + String args = locals.get("arguments") + ""; + CommandContext context = new CommandContext(("ignoreThis " + args).split(" "), new HashSet<>(), false, locals); UtilityCommands.help(context, worldEdit, actor); } catch (CommandException e1) { e1.printStackTrace(); } } else { + if (fp == null) fp = FawePlayer.wrap(actor); new UsageMessage(cmd, e.getCommandUsed((WorldEdit.getInstance().getConfiguration().noDoubleSlash ? "" : "/"), ""), locals).send(fp); } String message = e.getMessage(); if (message != null) { - finalActor.printError(message); + actor.printError(message); } } else { String message = e.getMessage(); - finalActor.printRaw(BBC.getPrefix() + (message != null ? message : "The command was not used properly (no more help available).")); - BBC.COMMAND_SYNTAX.send(finalActor, e.getSimpleUsageString("/")); + actor.printRaw(BBC.getPrefix() + (message != null ? message : "The command was not used properly (no more help available).")); + BBC.COMMAND_SYNTAX.send(actor, e.getSimpleUsageString("/")); } } catch (CommandException e) { String message = e.getMessage(); @@ -459,25 +484,26 @@ public final class CommandManager { Exception faweException = FaweException.get(e); String message = e.getMessage(); if (faweException != null) { - BBC.WORLDEDIT_CANCEL_REASON.send(finalActor, faweException.getMessage()); + BBC.WORLDEDIT_CANCEL_REASON.send(actor, faweException.getMessage()); } else { - finalActor.printError("There was an error handling a FAWE command: [See console]"); - finalActor.printRaw(e.getClass().getName() + ": " + e.getMessage()); + actor.printError("There was an error handling a FAWE command: [See console]"); + actor.printRaw(e.getClass().getName() + ": " + e.getMessage()); log.log(Level.SEVERE, "An unexpected error occurred while handling a FAWE command", e); } } finally { final EditSession editSession = locals.get(EditSession.class); if (editSession != null) { editSession.flushQueue(); - worldEdit.flushBlockBag(finalActor, editSession); + worldEdit.flushBlockBag(locals.get(Actor.class), editSession); session.remember(editSession); final long time = System.currentTimeMillis() - start; if (time > 1000) { - BBC.ACTION_COMPLETE.send(finalActor, (time / 1000d)); + BBC.ACTION_COMPLETE.send(actor, (time / 1000d)); } Request.reset(); } } + return null; } @Subscribe