From 35b37ac8e9f57e8a4cf5b51e1415cc8348485c1d Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Fri, 16 Sep 2016 17:47:53 +1000 Subject: [PATCH] Allow multiple actions at a time Closes #287 --- .../java/com/boydti/fawe/config/Settings.java | 3 + .../fawe/example/DefaultFaweQueueMap.java | 8 +- .../fawe/example/NMSMappedFaweQueue.java | 1 + .../com/boydti/fawe/object/FaweCommand.java | 13 +- .../com/boydti/fawe/object/FaweLimit.java | 3 + .../com/boydti/fawe/object/FawePlayer.java | 115 +++++++++--------- .../com/boydti/fawe/object/FaweQueue.java | 10 +- .../fawe/object/brush/CommandBrush.java | 2 - .../java/com/sk89q/worldedit/EditSession.java | 1 + .../command/composition/SelectionCommand.java | 2 +- .../extension/platform/CommandManager.java | 101 +++++++-------- .../extension/platform/PlatformManager.java | 12 +- .../com/thevoxelbox/voxelsniper/Sniper.java | 35 ++---- 13 files changed, 154 insertions(+), 152 deletions(-) diff --git a/core/src/main/java/com/boydti/fawe/config/Settings.java b/core/src/main/java/com/boydti/fawe/config/Settings.java index ee4540de..eea1b36e 100644 --- a/core/src/main/java/com/boydti/fawe/config/Settings.java +++ b/core/src/main/java/com/boydti/fawe/config/Settings.java @@ -59,6 +59,8 @@ public class Settings extends Config { }) @BlockName("default") // The name for the default block public static final class LIMITS extends ConfigBlock { + @Comment("Max actions that can be run concurrently (i.e. commands)") + public int MAX_ACTIONS = 1; @Comment("Max number of block changes (e.g. by `//set stone`).") public int MAX_CHANGES = 50000000; @Comment("Max number of blocks checked (e.g. `//count stone` which doesn't change blocks)") @@ -275,6 +277,7 @@ public class Settings extends Config { for (String key : keys) { if (key.equals("default") || (player != null && player.hasPermission("fawe.limit." + key))) { LIMITS newLimit = LIMITS.get(key); + limit.MAX_ACTIONS = Math.max(limit.MAX_ACTIONS, newLimit.MAX_ACTIONS != -1 ? newLimit.MAX_ACTIONS : Integer.MAX_VALUE); limit.MAX_CHANGES = Math.max(limit.MAX_CHANGES, newLimit.MAX_CHANGES != -1 ? newLimit.MAX_CHANGES : Integer.MAX_VALUE); limit.MAX_BLOCKSTATES = Math.max(limit.MAX_BLOCKSTATES, newLimit.MAX_BLOCKSTATES != -1 ? newLimit.MAX_BLOCKSTATES : Integer.MAX_VALUE); limit.MAX_CHECKS = Math.max(limit.MAX_CHECKS, newLimit.MAX_CHECKS != -1 ? newLimit.MAX_CHECKS : Integer.MAX_VALUE); diff --git a/core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java b/core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java index 19ccbdf5..9f44fbde 100644 --- a/core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java +++ b/core/src/main/java/com/boydti/fawe/example/DefaultFaweQueueMap.java @@ -124,6 +124,7 @@ public class DefaultFaweQueueMap implements IFaweQueueMap { return !blocks.isEmpty(); } boolean result = true; + // amount = 8; for (int i = 0; i < amount && (result = iter.hasNext()); i++, added++) { Map.Entry item = iter.next(); FaweChunk chunk = item.getValue(); @@ -131,17 +132,16 @@ public class DefaultFaweQueueMap implements IFaweQueueMap { pool.submit(chunk); iter.remove(); } + // if result, then submitted = amount if (result) { long start = System.currentTimeMillis(); - while (System.currentTimeMillis() - start < time) { - for (int i = 0; i < amount && (iter.hasNext()); i++, added++) { + while (System.currentTimeMillis() - start < time && result) { + if (result = iter.hasNext()) { Map.Entry item = iter.next(); FaweChunk chunk = item.getValue(); parent.start(chunk); pool.submit(chunk); iter.remove(); - } - for (int i = 0; i < amount; i++, added--) { FaweChunk fc = ((FaweChunk) pool.take().get()); parent.end(fc); } diff --git a/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java b/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java index 73bed151..fdb82dcf 100644 --- a/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/example/NMSMappedFaweQueue.java @@ -56,6 +56,7 @@ public abstract class NMSMappedFaweQueue ex public void end(FaweChunk chunk) { super.end(chunk); if (Settings.LIGHTING.MODE == 0) { + refreshChunk(chunk); return; } if (relighter == null) { diff --git a/core/src/main/java/com/boydti/fawe/object/FaweCommand.java b/core/src/main/java/com/boydti/fawe/object/FaweCommand.java index f57d72f7..9598b78b 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweCommand.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweCommand.java @@ -34,18 +34,15 @@ public abstract class FaweCommand { } }); } else { - if (player.getMeta("fawe_action") != null) { - BBC.WORLDEDIT_COMMAND_LIMIT.send(player); - return true; - } - player.setMeta("fawe_action", true); - TaskManager.IMP.async(new Runnable() { + if (!player.runAction(new Runnable() { @Override public void run() { execute(player, args); - player.deleteMeta("fawe_action"); } - }); + }, true, true)) { + BBC.WORLDEDIT_COMMAND_LIMIT.send(player); + return true; + } } return true; } catch (Throwable e) { diff --git a/core/src/main/java/com/boydti/fawe/object/FaweLimit.java b/core/src/main/java/com/boydti/fawe/object/FaweLimit.java index 9b3bbbe4..4b7ea348 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweLimit.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweLimit.java @@ -4,6 +4,7 @@ package com.boydti.fawe.object; * Created by Jesse on 4/5/2016. */ public class FaweLimit { + public int MAX_ACTIONS = 0; public int MAX_CHANGES = 0; public int MAX_FAILS = 0; public int MAX_CHECKS = 0; @@ -41,6 +42,7 @@ public class FaweLimit { return true; } }; + MAX.MAX_ACTIONS = Integer.MAX_VALUE; MAX.MAX_CHANGES = Integer.MAX_VALUE; MAX.MAX_FAILS = Integer.MAX_VALUE; MAX.MAX_CHECKS = Integer.MAX_VALUE; @@ -77,6 +79,7 @@ public class FaweLimit { public FaweLimit copy() { FaweLimit limit = new FaweLimit(); + limit.MAX_ACTIONS = MAX_ACTIONS; limit.MAX_CHANGES = MAX_CHANGES; limit.MAX_BLOCKSTATES = MAX_BLOCKSTATES; limit.MAX_CHECKS = MAX_CHECKS; 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 1444b370..41680a30 100644 --- a/core/src/main/java/com/boydti/fawe/object/FawePlayer.java +++ b/core/src/main/java/com/boydti/fawe/object/FawePlayer.java @@ -33,6 +33,7 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; public abstract class FawePlayer { @@ -106,6 +107,61 @@ public abstract class FawePlayer { } } + private AtomicInteger getActions() { + AtomicInteger adder = getMeta("fawe_action_v2"); + if (adder == null) { + adder = new AtomicInteger(); + AtomicInteger previous = (AtomicInteger) setMeta("fawe_action_v2", adder); + if (previous != null) { + setMeta("fawe_action_v2", adder = previous); + } + } + return adder; + } + + public boolean runAsyncIfFree(Runnable r) { + return runAction(r, true, true); + } + + public boolean runIfFree(Runnable r) { + return runAction(r, true, false); + } + + public boolean runAction(final Runnable ifFree, boolean checkFree, boolean async) { + if (checkFree) { + FaweLimit limit = getLimit(); + int actionLimit = limit.MAX_ACTIONS; + final AtomicInteger current = getActions(); + int val = current.incrementAndGet(); + if (val > actionLimit) { + current.decrementAndGet(); + return false; + } + Runnable r = new Runnable() { + @Override + public void run() { + try { + ifFree.run(); + } catch (Throwable e) { + FaweException faweException = FaweException.get(e); + if (faweException != null) { + BBC.WORLDEDIT_CANCEL_REASON.send(FawePlayer.this, faweException.getMessage()); + } else { + throw new RuntimeException(e); + } + } finally { + current.decrementAndGet(); + } + } + }; + TaskManager.IMP.taskNow(r, async); + return true; + } else { + ifFree.run(); + } + return false; + } + /** * Loads any history items from disk: * - Should already be called if history on disk is enabled @@ -321,12 +377,13 @@ public abstract class FawePlayer { * Set some session only metadata for the player * @param key * @param value + * @return previous value */ - public void setMeta(String key, Object value) { + public Object setMeta(String key, Object value) { if (this.meta == null) { this.meta = new ConcurrentHashMap<>(8, 0.9f, 1); } - this.meta.put(key, value); + return this.meta.put(key, value); } /** @@ -388,60 +445,6 @@ public abstract class FawePlayer { return WorldEdit.getInstance().getEditSessionFactory().getEditSession(getWorld(), -1, getPlayer()); } - /** - * Run a task if the player has no currently running action - * @param run - * @return If the task was run - */ - public boolean runIfFree(Runnable run) { - if (getMeta("fawe_action") != null) { - return false; - } - setMeta("fawe_action", true); - try { - run.run(); - } catch (Throwable e) { - FaweException faweException = FaweException.get(e); - if (faweException != null) { - BBC.WORLDEDIT_CANCEL_REASON.send(FawePlayer.this, faweException.getMessage()); - } else { - MainUtil.handleError(e); - } - } finally { - deleteMeta("fawe_action"); - } - return true; - } - - /** - * Run an async task if the player has no currently running action - * @param run - * @return If the task was run - */ - public boolean runAsyncIfFree(final Runnable run) { - if (getMeta("fawe_action") != null) { - return false; - } - setMeta("fawe_action", true); - TaskManager.IMP.async(new Runnable() { - @Override - public void run() { - try { - run.run(); - } catch (Throwable e) { - FaweException faweException = FaweException.get(e); - if (faweException != null) { - BBC.WORLDEDIT_CANCEL_REASON.send(FawePlayer.this, faweException.getMessage()); - } else { - MainUtil.handleError(e); - } - } finally { - deleteMeta("fawe_action"); - } - } - }); - return true; - } /** * Get the tracked EditSession(s) for this player
diff --git a/core/src/main/java/com/boydti/fawe/object/FaweQueue.java b/core/src/main/java/com/boydti/fawe/object/FaweQueue.java index 9d17e78a..7ea7171d 100644 --- a/core/src/main/java/com/boydti/fawe/object/FaweQueue.java +++ b/core/src/main/java/com/boydti/fawe/object/FaweQueue.java @@ -401,10 +401,12 @@ public abstract class FaweQueue { } while (!tasks.isEmpty()) { Runnable task = tasks.poll(); - try { - task.run(); - } catch (Throwable e) { - MainUtil.handleError(e); + if (task != null) { + try { + task.run(); + } catch (Throwable e) { + MainUtil.handleError(e); + } } } } diff --git a/core/src/main/java/com/boydti/fawe/object/brush/CommandBrush.java b/core/src/main/java/com/boydti/fawe/object/brush/CommandBrush.java index bb75c916..a516e745 100644 --- a/core/src/main/java/com/boydti/fawe/object/brush/CommandBrush.java +++ b/core/src/main/java/com/boydti/fawe/object/brush/CommandBrush.java @@ -43,7 +43,6 @@ public class CommandBrush implements Brush { position = face.getFaceVector(); } FawePlayer fp = FawePlayer.wrap(player); - fp.deleteMeta("fawe_action"); fp.setSelection(selector); PlayerWrapper wePlayer = new SilentPlayerWrapper(new LocationMaskedPlayerWrapper(player, position)); String[] cmds = replaced.split(";"); @@ -51,6 +50,5 @@ public class CommandBrush implements Brush { CommandEvent event = new CommandEvent(wePlayer, cmd); CommandManager.getInstance().handleCommand(event); } - FawePlayer.wrap(player).setMeta("fawe_action", true); } } diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index c37158a8..99fd1fae 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -351,6 +351,7 @@ public class EditSession extends AbstractWorld { */ public FaweLimit getLimitUsed() { FaweLimit newLimit = new FaweLimit(); + newLimit.MAX_ACTIONS = originalLimit.MAX_ACTIONS - limit.MAX_ACTIONS; newLimit.MAX_CHANGES = originalLimit.MAX_CHANGES - limit.MAX_CHANGES; newLimit.MAX_FAILS = originalLimit.MAX_FAILS - limit.MAX_FAILS; newLimit.MAX_CHECKS = originalLimit.MAX_CHECKS - limit.MAX_CHECKS; diff --git a/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java b/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java index 01473efe..e186ca0c 100644 --- a/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java +++ b/core/src/main/java/com/sk89q/worldedit/command/composition/SelectionCommand.java @@ -151,7 +151,7 @@ public class SelectionCommand extends SimpleCommand { long start = System.currentTimeMillis(); BBC.OPERATION.send(actor, BBC.VISITOR_BLOCK.format(cuboid.getArea())); queue.flush(); - BBC.ACTION_COMPLETE.send(actor, (System.currentTimeMillis() - start) / 1000); + BBC.ACTION_COMPLETE.send(actor, (System.currentTimeMillis() - start) / 1000d); return null; } } catch (Throwable e) { 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 a8e0bf30..72d417bb 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 @@ -246,36 +246,29 @@ public final class CommandManager { return split; } - @Subscribe - public void handleCommand(final CommandEvent event) { - Request.reset(); - TaskManager.IMP.taskNow(new Runnable() { + public void handleCommandOnCurrentThread(final CommandEvent event, boolean checkLimit) { + Actor actor = platformManager.createProxyActor(event.getActor()); + final String args = event.getArguments(); + final String[] split = commandDetection(args.split(" ")); + // No command found! + if (!dispatcher.contains(split[0])) { + return; + } + if (!actor.isPlayer()) { + actor = new FakePlayer(actor.getName(), actor.getUniqueId(), actor); + } + final LocalSession session = worldEdit.getSessionManager().get(actor); + LocalConfiguration config = worldEdit.getConfiguration(); + final CommandLocals locals = new CommandLocals(); + final FawePlayer fp = FawePlayer.wrap(actor); + if (fp == null) { + throw new IllegalArgumentException("FAWE doesn't support: " + actor); + } + locals.put(Actor.class, actor instanceof Player ? new PlayerWrapper((Player) actor) : actor); + final Actor finalActor = actor; + if (!fp.runAction(new Runnable() { @Override public void run() { - Actor actor = platformManager.createProxyActor(event.getActor()); - String args = event.getArguments(); - String[] split = commandDetection(args.split(" ")); - // No command found! - if (!dispatcher.contains(split[0])) { - return; - } - if (!actor.isPlayer()) { - actor = new FakePlayer(actor.getName(), actor.getUniqueId(), actor); - } - final LocalSession session = worldEdit.getSessionManager().get(actor); - LocalConfiguration config = worldEdit.getConfiguration(); - CommandLocals locals = new CommandLocals(); - final FawePlayer fp = FawePlayer.wrap(actor); - if (fp != null) { - if (fp.getMeta("fawe_action") != null) { - BBC.WORLDEDIT_COMMAND_LIMIT.send(fp); - return; - } - fp.setMeta("fawe_action", true); - locals.put(Actor.class, actor instanceof Player ? new PlayerWrapper((Player) actor) : actor); - } else { - locals.put(Actor.class, actor); - } locals.put("arguments", args); final long start = System.currentTimeMillis(); try { @@ -297,35 +290,35 @@ public final class CommandManager { throw t; } } catch (CommandPermissionsException e) { - BBC.NO_PERM.send(actor, "worldedit.*"); + BBC.NO_PERM.send(finalActor, "worldedit.*"); } catch (InvalidUsageException e) { if (e.isFullHelpSuggested()) { - actor.printRaw(ColorCodeBuilder.asColorCodes(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals))); + finalActor.printRaw(ColorCodeBuilder.asColorCodes(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals))); String message = e.getMessage(); if (message != null) { - actor.printError(message); + finalActor.printError(message); } } else { String message = e.getMessage(); - actor.print(BBC.getPrefix() + (message != null ? message : "The command was not used properly (no more help available).")); - BBC.COMMAND_SYNTAX.send(actor, e.getSimpleUsageString("/")); + finalActor.print(BBC.getPrefix() + (message != null ? message : "The command was not used properly (no more help available).")); + BBC.COMMAND_SYNTAX.send(finalActor, e.getSimpleUsageString("/")); } } catch (WrappedCommandException e) { FaweException faweException = FaweException.get(e); if (faweException != null) { - BBC.WORLDEDIT_CANCEL_REASON.send(actor, faweException.getMessage()); + BBC.WORLDEDIT_CANCEL_REASON.send(finalActor, faweException.getMessage()); } else { Throwable t = e.getCause(); - actor.printError("Please report this error: [See console]"); - actor.printRaw(t.getClass().getName() + ": " + t.getMessage()); + finalActor.printError("Please report this error: [See console]"); + finalActor.printRaw(t.getClass().getName() + ": " + t.getMessage()); log.log(Level.SEVERE, "An unexpected error while handling a WorldEdit command", t); } } catch (CommandException e) { String message = e.getMessage(); if (message != null) { - actor.printError(e.getMessage()); + finalActor.printError(e.getMessage()); } else { - actor.printError("An unknown error has occurred! Please see console."); + finalActor.printError("An unknown error has occurred! Please see console."); log.log(Level.SEVERE, "An unknown error occurred", e); } } finally { @@ -333,25 +326,35 @@ public final class CommandManager { boolean hasSession = false; if (editSession != null) { editSession.flushQueue(); - worldEdit.flushBlockBag(actor, editSession); + worldEdit.flushBlockBag(finalActor, editSession); session.remember(editSession); hasSession = editSession.size() > 0; } - if (fp != null) { - fp.deleteMeta("fawe_action"); - if (editSession != null) { - final long time = System.currentTimeMillis() - start; - if (time > 5 && hasSession) { - BBC.ACTION_COMPLETE.send(actor, (time / 1000d)); - ChangeSet fcs = editSession.getChangeSet(); - if (fcs != null && fcs instanceof FaweStreamChangeSet) { - MainUtil.sendCompressedMessage((FaweStreamChangeSet) fcs, editSession.getPlayer()); - } + if (editSession != null) { + final long time = System.currentTimeMillis() - start; + if (time > 5 && hasSession) { + BBC.ACTION_COMPLETE.send(finalActor, (time / 1000d)); + ChangeSet fcs = editSession.getChangeSet(); + if (fcs != null && fcs instanceof FaweStreamChangeSet) { + MainUtil.sendCompressedMessage((FaweStreamChangeSet) fcs, fp); } } } } } + }, checkLimit, false)) { + BBC.WORLDEDIT_COMMAND_LIMIT.send(fp); + } + } + + @Subscribe + public void handleCommand(final CommandEvent event) { + Request.reset(); + TaskManager.IMP.taskNow(new Runnable() { + @Override + public void run() { + handleCommandOnCurrentThread(event, true); + } }, Fawe.get().isMainThread()); event.setCancelled(true); } diff --git a/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java index bfcd65ad..2cb9bcc5 100644 --- a/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java +++ b/core/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java @@ -368,12 +368,12 @@ public class PlatformManager { final BlockTool superPickaxe = session.getSuperPickaxe(); if (superPickaxe != null && superPickaxe.canUse(player)) { FawePlayer fp = FawePlayer.wrap(player); - fp.runAsyncIfFree(new Runnable() { + fp.runAction(new Runnable() { @Override public void run() { superPickaxe.actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location); } - }); + }, true, true); event.setCancelled(true); return; } @@ -382,12 +382,12 @@ public class PlatformManager { if (tool != null && tool instanceof DoubleActionBlockTool) { if (tool.canUse(player)) { FawePlayer fp = FawePlayer.wrap(player); - fp.runAsyncIfFree(new Runnable() { + fp.runAction(new Runnable() { @Override public void run() { ((DoubleActionBlockTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location); } - }); + }, true, true); event.setCancelled(true); } } @@ -414,12 +414,12 @@ public class PlatformManager { if (tool != null && tool instanceof BlockTool) { if (tool.canUse(player)) { FawePlayer fp = FawePlayer.wrap(player); - fp.runAsyncIfFree(new Runnable() { + fp.runAction(new Runnable() { @Override public void run() { ((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location); } - }); + }, true, true); event.setCancelled(true); } } diff --git a/favs/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java b/favs/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java index 352dd3c0..42167534 100644 --- a/favs/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java +++ b/favs/src/main/java/com/thevoxelbox/voxelsniper/Sniper.java @@ -10,6 +10,7 @@ import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.MaskedFaweQueue; import com.boydti.fawe.object.RegionWrapper; +import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.object.changeset.FaweChangeSet; import com.boydti.fawe.util.StringMan; import com.boydti.fawe.util.WEManager; @@ -119,17 +120,11 @@ public class Sniper { */ public boolean snipe(Action action, Material itemInHand, Block clickedBlock, BlockFace clickedFace) { try { - // Added - { - Player player = getPlayer(); - FawePlayer fp = FawePlayer.wrap(player); - if (fp.getMeta("fawe_action") != null) { - return false; - } - maskQueue = null; - if (clickedBlock != null) { - clickedBlock = getWorld().getBlockAt(clickedBlock.getX(), clickedBlock.getY(), clickedBlock.getZ()); - } + Player player = getPlayer(); + FawePlayer fp = FawePlayer.wrap(player); + maskQueue = null; + if (clickedBlock != null) { + clickedBlock = getWorld().getBlockAt(clickedBlock.getX(), clickedBlock.getY(), clickedBlock.getZ()); } return snipe(action, itemInHand, getWorld(), clickedBlock, clickedFace); } catch (Throwable e) { @@ -301,20 +296,16 @@ public class Sniper { performerBrush.initP(snipeData); } final FawePlayer fp = FawePlayer.wrap(getPlayer()); - fp.runAsyncIfFree(new Runnable() { + fp.runAction(new RunnableVal() { @Override - public void run() { - try { - boolean result = brush.perform(snipeAction, snipeData, targetBlock, lastBlock); - if (result) { - MetricsManager.increaseBrushUsage(brush.getName()); - } - world.commit(); - } catch (Throwable e) { - e.printStackTrace(); + public void run(Boolean value) { + boolean result = brush.perform(snipeAction, snipeData, targetBlock, lastBlock); + if (result) { + MetricsManager.increaseBrushUsage(brush.getName()); } + world.commit(); } - }); + }, true, true); return true; } }