diff --git a/pom.xml b/pom.xml
index 89e1d0efc..24b512526 100644
--- a/pom.xml
+++ b/pom.xml
@@ -492,11 +492,23 @@
true
+
+
+ org.sk89q.bukkit
+ bukkit-classloader-check
+ 1.7.2-R0.3
+ runtime
+ jar
+ true
+
+
+
org.bukkit
bukkit
- 1.7.2-R0.2
+ 1.7.2-R0.3
compile
jar
true
diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java
index bf08bf45a..1bf4c6a61 100644
--- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java
@@ -26,7 +26,9 @@ import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.ServerInterface;
import com.sk89q.worldedit.entity.Player;
+import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
+import com.sk89q.worldedit.extension.platform.MultiUserPlatform;
import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.util.command.Description;
@@ -39,11 +41,12 @@ import org.bukkit.entity.EntityType;
import javax.annotation.Nullable;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
-public class BukkitServerInterface extends ServerInterface {
+public class BukkitServerInterface extends ServerInterface implements MultiUserPlatform {
public Server server;
public WorldEditPlugin plugin;
private CommandRegistration dynamicCommands;
@@ -168,6 +171,7 @@ public class BukkitServerInterface extends ServerInterface {
public Map getCapabilities() {
Map capabilities = new EnumMap(Capability.class);
capabilities.put(Capability.CONFIGURATION, Preference.NORMAL);
+ capabilities.put(Capability.WORLDEDIT_CUI, Preference.NORMAL);
capabilities.put(Capability.GAME_HOOKS, Preference.PREFERRED);
capabilities.put(Capability.PERMISSIONS, Preference.PREFERRED);
capabilities.put(Capability.USER_COMMANDS, Preference.PREFERRED);
@@ -178,4 +182,13 @@ public class BukkitServerInterface extends ServerInterface {
public void unregisterCommands() {
dynamicCommands.unregisterCommands();
}
+
+ @Override
+ public Collection getConnectedUsers() {
+ List users = new ArrayList();
+ for (org.bukkit.entity.Player player : Bukkit.getServer().getOnlinePlayers()) {
+ users.add(new BukkitPlayer(plugin, this, player));
+ }
+ return users;
+ }
}
diff --git a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java
index 67d2152b1..458aa8477 100644
--- a/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java
+++ b/src/bukkit/java/com/sk89q/worldedit/bukkit/BukkitWorld.java
@@ -1312,4 +1312,12 @@ public class BukkitWorld extends LocalWorld {
return null;
}
+ /**
+ * @deprecated Use {@link #setBlock(Vector, BaseBlock, boolean)}
+ */
+ @Deprecated
+ public boolean setBlock(Vector pt, com.sk89q.worldedit.foundation.Block block, boolean notifyAdjacent) throws WorldEditException {
+ return setBlock(pt, (BaseBlock) block, notifyAdjacent);
+ }
+
}
diff --git a/src/forge/java/com/sk89q/worldedit/forge/ForgePlatform.java b/src/forge/java/com/sk89q/worldedit/forge/ForgePlatform.java
index 818a14573..62c04afb3 100644
--- a/src/forge/java/com/sk89q/worldedit/forge/ForgePlatform.java
+++ b/src/forge/java/com/sk89q/worldedit/forge/ForgePlatform.java
@@ -23,7 +23,9 @@ import com.sk89q.worldedit.BiomeTypes;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.ServerInterface;
import com.sk89q.worldedit.entity.Player;
+import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
+import com.sk89q.worldedit.extension.platform.MultiUserPlatform;
import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.util.command.Description;
@@ -38,13 +40,19 @@ import net.minecraft.entity.EntityList;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.Item;
import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.management.ServerConfigurationManager;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.DimensionManager;
import javax.annotation.Nullable;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Map;
-class ForgePlatform extends ServerInterface {
+class ForgePlatform extends ServerInterface implements MultiUserPlatform {
private final ForgeWorldEdit mod;
private final MinecraftServer server;
@@ -205,6 +213,7 @@ class ForgePlatform extends ServerInterface {
public Map getCapabilities() {
Map capabilities = new EnumMap(Capability.class);
capabilities.put(Capability.CONFIGURATION, Preference.PREFER_OTHERS);
+ capabilities.put(Capability.WORLDEDIT_CUI, Preference.NORMAL);
capabilities.put(Capability.GAME_HOOKS, Preference.NORMAL);
capabilities.put(Capability.PERMISSIONS, Preference.PREFER_OTHERS);
capabilities.put(Capability.USER_COMMANDS, Preference.NORMAL);
@@ -212,4 +221,16 @@ class ForgePlatform extends ServerInterface {
return capabilities;
}
+ @Override
+ public Collection getConnectedUsers() {
+ List users = new ArrayList();
+ ServerConfigurationManager scm = server.getConfigurationManager();
+ for (String name : scm.getAllUsernames()) {
+ EntityPlayerMP entity = scm.getPlayerForUsername(name);
+ if (entity != null) {
+ users.add(new ForgePlayer(entity));
+ }
+ }
+ return users;
+ }
}
diff --git a/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java b/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java
index ecfeef15d..4cb581e3d 100644
--- a/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java
+++ b/src/main/java/com/sk89q/worldedit/command/NavigationCommands.java
@@ -23,8 +23,14 @@ import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
-import com.sk89q.worldedit.*;
+import com.sk89q.worldedit.EditSession;
+import com.sk89q.worldedit.LocalConfiguration;
+import com.sk89q.worldedit.LocalSession;
+import com.sk89q.worldedit.WorldEdit;
+import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.WorldVector;
import com.sk89q.worldedit.entity.Player;
+import com.sk89q.worldedit.util.command.parametric.Optional;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION;
@@ -68,13 +74,7 @@ public class NavigationCommands {
max = 1
)
@CommandPermissions("worldedit.navigation.ascend")
- public void ascend(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
- int levelsToAscend = 0;
- if (args.argsLength() == 0) {
- levelsToAscend = 1;
- } else {
- levelsToAscend = args.getInteger(0);
- }
+ public void ascend(Player player, @Optional("1") int levelsToAscend) throws WorldEditException {
int ascentLevels = 1;
while (player.ascendLevel() && levelsToAscend != ascentLevels) {
++ascentLevels;
@@ -94,13 +94,7 @@ public class NavigationCommands {
max = 1
)
@CommandPermissions("worldedit.navigation.descend")
- public void descend(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
- int levelsToDescend = 0;
- if (args.argsLength() == 0) {
- levelsToDescend = 1;
- } else {
- levelsToDescend = args.getInteger(0);
- }
+ public void descend(Player player, @Optional("1") int levelsToDescend) throws WorldEditException {
int descentLevels = 1;
while (player.descendLevel() && levelsToDescend != descentLevels) {
++descentLevels;
@@ -181,7 +175,6 @@ public class NavigationCommands {
@CommandPermissions("worldedit.navigation.up")
@Logging(POSITION)
public void up(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
-
final int distance = args.getInteger(0);
final boolean alwaysGlass = getAlwaysGlass(args);
diff --git a/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/src/main/java/com/sk89q/worldedit/command/RegionCommands.java
index e8dd44277..5f82d1b55 100644
--- a/src/main/java/com/sk89q/worldedit/command/RegionCommands.java
+++ b/src/main/java/com/sk89q/worldedit/command/RegionCommands.java
@@ -449,7 +449,8 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.forest")
@Logging(REGION)
- public void forest(Player player, EditSession editSession, @Selection Region region, @Optional("tree") TreeType type, @Optional("5") double density) throws WorldEditException {
+ public void forest(Player player, EditSession editSession, @Selection Region region, @Optional("tree") TreeType type,
+ @Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException {
density = density / 100;
ForestGenerator generator = new ForestGenerator(editSession, new TreeGenerator(type));
GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator);
@@ -469,7 +470,7 @@ public class RegionCommands {
)
@CommandPermissions("worldedit.region.flora")
@Logging(REGION)
- public void flora(Player player, EditSession editSession, @Selection Region region, @Optional("10") double density) throws WorldEditException {
+ public void flora(Player player, EditSession editSession, @Selection Region region, @Optional("10") @Range(min = 0, max = 100) double density) throws WorldEditException {
density = density / 100;
FloraGenerator generator = new FloraGenerator(editSession);
GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator);
diff --git a/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java
index 4a4acaa84..4d8d165dc 100644
--- a/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java
+++ b/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java
@@ -20,7 +20,6 @@
package com.sk89q.worldedit.command;
import com.sk89q.minecraft.util.commands.Command;
-import com.sk89q.minecraft.util.commands.CommandAlias;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
@@ -706,7 +705,7 @@ public class SelectionCommands {
}
@Command(
- aliases = { "/sel", ";" },
+ aliases = { "/sel", ";", "/desel", "/deselect" },
usage = "[cuboid|extend|poly|ellipsoid|sphere|cyl|convex]",
desc = "Choose a region selector",
min = 0,
@@ -761,9 +760,4 @@ public class SelectionCommands {
session.dispatchCUISelection(player);
}
- @Command(aliases = {"/desel", "/deselect"}, desc = "Deselect the current selection")
- @CommandAlias("/sel")
- public void deselect() {
-
- }
}
diff --git a/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java b/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java
index d57bedd28..d1e0852d8 100644
--- a/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java
+++ b/src/main/java/com/sk89q/worldedit/command/UtilityCommands.java
@@ -22,6 +22,7 @@ package com.sk89q.worldedit.command;
import com.google.common.base.Joiner;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
+import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
@@ -36,6 +37,9 @@ import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.CommandManager;
+import com.sk89q.worldedit.internal.expression.Expression;
+import com.sk89q.worldedit.internal.expression.ExpressionException;
+import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.patterns.Pattern;
import com.sk89q.worldedit.patterns.SingleBlockPattern;
import com.sk89q.worldedit.regions.CuboidRegion;
@@ -44,6 +48,7 @@ import com.sk89q.worldedit.util.command.CommandCallable;
import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.PrimaryAliasComparator;
+import com.sk89q.worldedit.util.command.binding.Text;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.util.formatting.ColorCodeBuilder;
import com.sk89q.worldedit.util.formatting.Style;
@@ -504,6 +509,24 @@ public class UtilityCommands {
player.print("Marked " + removed + " entit(ies) for removal.");
}
+ @Command(
+ aliases = { "/calc", "/calculate", "/eval", "/evaluate", "/solve" },
+ usage = "",
+ desc = "Evaluate a mathematical expression"
+ )
+ public void calc(Actor actor, @Text String input) throws CommandException {
+ try {
+ Expression expression = Expression.compile(input);
+ actor.print("= " + expression.evaluate());
+ } catch (EvaluationException e) {
+ actor.printError(String.format(
+ "'%s' could not be parsed as a valid expression", input));
+ } catch (ExpressionException e) {
+ actor.printError(String.format(
+ "'%s' could not be evaluated (error: %s)", input, e.getMessage()));
+ }
+ }
+
@Command(
aliases = { "/help" },
usage = "[]",
diff --git a/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java b/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java
index 49b345d71..9d2b56f19 100644
--- a/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java
+++ b/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java
@@ -42,6 +42,26 @@ public class ParserContext {
private boolean restricted = true;
private boolean preferringWildcard;
+ /**
+ * Create a new instance.
+ */
+ public ParserContext() {
+ }
+
+ /**
+ * Creates a copy of another instance.
+ *
+ * @param other the other instance
+ */
+ public ParserContext(ParserContext other) {
+ setExtent(other.getExtent());
+ setSession(other.getSession());
+ setWorld(other.getWorld());
+ setActor(other.getActor());
+ setRestricted(other.isRestricted());
+ setPreferringWildcard(other.isPreferringWildcard());
+ }
+
/**
* Get the {@link Extent} set on this context.
*
diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java b/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java
index 61ee2bfb8..a753b0fd2 100644
--- a/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java
+++ b/src/main/java/com/sk89q/worldedit/extension/platform/Capability.java
@@ -65,6 +65,11 @@ public enum Capability {
*/
PERMISSIONS,
+ /**
+ * The capability of a platform to dispatch WorldEditCUI events.
+ */
+ WORLDEDIT_CUI,
+
/**
* The capability of a platform to perform modifications to a world.
*/
diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java b/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java
index 9c71cfe69..466903332 100644
--- a/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java
+++ b/src/main/java/com/sk89q/worldedit/extension/platform/CommandManager.java
@@ -33,6 +33,7 @@ import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.internal.command.ActorAuthorizer;
import com.sk89q.worldedit.internal.command.CommandLoggingHandler;
+import com.sk89q.worldedit.internal.command.UserCommandCompleter;
import com.sk89q.worldedit.internal.command.WorldEditBinding;
import com.sk89q.worldedit.internal.command.WorldEditExceptionConverter;
import com.sk89q.worldedit.session.request.Request;
@@ -93,6 +94,7 @@ public final class CommandManager {
// Set up the commands manager
ParametricBuilder builder = new ParametricBuilder();
builder.setAuthorizer(new ActorAuthorizer());
+ builder.setDefaultCompleter(new UserCommandCompleter(platformManager));
builder.addBinding(new WorldEditBinding(worldEdit));
builder.addExceptionConverter(new WorldEditExceptionConverter(worldEdit));
builder.addInvokeListener(new LegacyCommandsHandler());
diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/MultiUserPlatform.java b/src/main/java/com/sk89q/worldedit/extension/platform/MultiUserPlatform.java
new file mode 100644
index 000000000..6fa94e017
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/extension/platform/MultiUserPlatform.java
@@ -0,0 +1,36 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.extension.platform;
+
+import java.util.Collection;
+
+/**
+ * Implements a platform with multiple connected users.
+ */
+public interface MultiUserPlatform extends Platform {
+
+ /**
+ * Get a list of connected users.
+ *
+ * @return a list of connected users
+ */
+ Collection getConnectedUsers();
+
+}
diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java b/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java
index 3e70e2483..a62bc247a 100644
--- a/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java
+++ b/src/main/java/com/sk89q/worldedit/extension/platform/PlatformManager.java
@@ -240,7 +240,12 @@ public class PlatformManager {
permActor = player;
}
- return (T) new PlayerProxy(player, permActor, getWorldForEditing(player.getWorld()));
+ Player cuiActor = queryCapability(Capability.WORLDEDIT_CUI).matchPlayer(player);
+ if (cuiActor == null) {
+ cuiActor = player;
+ }
+
+ return (T) new PlayerProxy(player, permActor, cuiActor, getWorldForEditing(player.getWorld()));
} else {
return base;
}
diff --git a/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java b/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java
index 7da9d7853..4aeb23d7a 100644
--- a/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java
+++ b/src/main/java/com/sk89q/worldedit/extension/platform/PlayerProxy.java
@@ -24,6 +24,7 @@ import com.sk89q.worldedit.WorldVector;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.inventory.BlockBag;
+import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World;
@@ -33,14 +34,17 @@ class PlayerProxy extends AbstractPlayerActor {
private final Player basePlayer;
private final Actor permActor;
+ private final Actor cuiActor;
private final World world;
- PlayerProxy(Player basePlayer, Actor permActor, World world) {
+ PlayerProxy(Player basePlayer, Actor permActor, Actor cuiActor, World world) {
checkNotNull(basePlayer);
checkNotNull(permActor);
+ checkNotNull(cuiActor);
checkNotNull(world);
this.basePlayer = basePlayer;
this.permActor = permActor;
+ this.cuiActor = cuiActor;
this.world = world;
}
@@ -128,4 +132,9 @@ class PlayerProxy extends AbstractPlayerActor {
public boolean hasPermission(String perm) {
return permActor.hasPermission(perm);
}
+
+ @Override
+ public void dispatchCUIEvent(CUIEvent event) {
+ cuiActor.dispatchCUIEvent(event);
+ }
}
diff --git a/src/main/java/com/sk89q/worldedit/extension/registry/DefaultMaskParser.java b/src/main/java/com/sk89q/worldedit/extension/registry/DefaultMaskParser.java
index b85b9ff1f..304a49b60 100644
--- a/src/main/java/com/sk89q/worldedit/extension/registry/DefaultMaskParser.java
+++ b/src/main/java/com/sk89q/worldedit/extension/registry/DefaultMaskParser.java
@@ -132,7 +132,10 @@ class DefaultMaskParser extends InputParser {
}
default:
- return new BlockMask(extent, worldEdit.getBlockRegistry().parseFromListInput(component, context));
+ ParserContext tempContext = new ParserContext(context);
+ tempContext.setRestricted(false);
+ tempContext.setPreferringWildcard(true);
+ return new BlockMask(extent, worldEdit.getBlockRegistry().parseFromListInput(component, tempContext));
}
}
diff --git a/src/main/java/com/sk89q/worldedit/internal/command/UserCommandCompleter.java b/src/main/java/com/sk89q/worldedit/internal/command/UserCommandCompleter.java
new file mode 100644
index 000000000..63957cbca
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/internal/command/UserCommandCompleter.java
@@ -0,0 +1,72 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.internal.command;
+
+import com.sk89q.minecraft.util.commands.CommandException;
+import com.sk89q.minecraft.util.commands.CommandLocals;
+import com.sk89q.worldedit.extension.platform.Actor;
+import com.sk89q.worldedit.extension.platform.Capability;
+import com.sk89q.worldedit.extension.platform.MultiUserPlatform;
+import com.sk89q.worldedit.extension.platform.Platform;
+import com.sk89q.worldedit.extension.platform.PlatformManager;
+import com.sk89q.worldedit.util.command.CommandCompleter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Provides the names of connected users as suggestions.
+ */
+public class UserCommandCompleter implements CommandCompleter {
+
+ private final PlatformManager platformManager;
+
+ /**
+ * Create a new instance.
+ *
+ * @param platformManager the platform manager
+ */
+ public UserCommandCompleter(PlatformManager platformManager) {
+ checkNotNull(platformManager);
+ this.platformManager = platformManager;
+ }
+
+ @Override
+ public List getSuggestions(String arguments, CommandLocals locals) throws CommandException {
+ Platform platform = platformManager.queryCapability(Capability.USER_COMMANDS);
+ if (platform instanceof MultiUserPlatform) {
+ List suggestions = new ArrayList();
+ Collection users = ((MultiUserPlatform) platform).getConnectedUsers();
+ for (Actor user : users) {
+ if (user.getName().toLowerCase().startsWith(arguments.toLowerCase().trim())) {
+ suggestions.add(user.getName());
+ }
+ }
+ return suggestions;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+}
diff --git a/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java b/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java
index 3c75884c5..85b4133a0 100644
--- a/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java
+++ b/src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java
@@ -22,12 +22,10 @@ package com.sk89q.worldedit.util.command;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandLocals;
-import java.util.List;
-
/**
* A command that can be executed.
*/
-public interface CommandCallable {
+public interface CommandCallable extends CommandCompleter {
/**
* Execute the correct command based on the input.
@@ -41,16 +39,6 @@ public interface CommandCallable {
* @throws CommandException thrown on a command error
*/
boolean call(String arguments, CommandLocals locals, String[] parentCommands) throws CommandException;
-
- /**
- * Get a list of suggestions based on input.
- *
- * @param arguments the arguments entered up to this point
- * @param locals the locals
- * @return a list of suggestions
- * @throws CommandException thrown if there was a parsing error
- */
- List getSuggestions(String arguments, CommandLocals locals) throws CommandException;
/**
* Get an object describing this command.
diff --git a/src/main/java/com/sk89q/worldedit/util/command/CommandCompleter.java b/src/main/java/com/sk89q/worldedit/util/command/CommandCompleter.java
new file mode 100644
index 000000000..19bf47d60
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/util/command/CommandCompleter.java
@@ -0,0 +1,42 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.util.command;
+
+import com.sk89q.minecraft.util.commands.CommandException;
+import com.sk89q.minecraft.util.commands.CommandLocals;
+
+import java.util.List;
+
+/**
+ * Provides a method that can provide tab completion for commands.
+ */
+public interface CommandCompleter {
+
+ /**
+ * Get a list of suggestions based on input.
+ *
+ * @param arguments the arguments entered up to this point
+ * @param locals the locals
+ * @return a list of suggestions
+ * @throws CommandException thrown if there was a parsing error
+ */
+ List getSuggestions(String arguments, CommandLocals locals) throws CommandException;
+
+}
diff --git a/src/main/java/com/sk89q/worldedit/util/command/NullCompleter.java b/src/main/java/com/sk89q/worldedit/util/command/NullCompleter.java
new file mode 100644
index 000000000..10850c696
--- /dev/null
+++ b/src/main/java/com/sk89q/worldedit/util/command/NullCompleter.java
@@ -0,0 +1,38 @@
+/*
+ * WorldEdit, a Minecraft world manipulation toolkit
+ * Copyright (C) sk89q
+ * Copyright (C) WorldEdit team and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see .
+ */
+
+package com.sk89q.worldedit.util.command;
+
+import com.sk89q.minecraft.util.commands.CommandException;
+import com.sk89q.minecraft.util.commands.CommandLocals;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Always returns an empty list of suggestions.
+ */
+public class NullCompleter implements CommandCompleter {
+
+ @Override
+ public List getSuggestions(String arguments, CommandLocals locals) throws CommandException {
+ return Collections.emptyList();
+ }
+
+}
diff --git a/src/main/java/com/sk89q/worldedit/util/command/binding/PrimitiveBindings.java b/src/main/java/com/sk89q/worldedit/util/command/binding/PrimitiveBindings.java
index a4ed7ab0c..2a5ee0ccf 100644
--- a/src/main/java/com/sk89q/worldedit/util/command/binding/PrimitiveBindings.java
+++ b/src/main/java/com/sk89q/worldedit/util/command/binding/PrimitiveBindings.java
@@ -19,8 +19,16 @@
package com.sk89q.worldedit.util.command.binding;
-import com.sk89q.worldedit.util.command.parametric.*;
+import com.sk89q.worldedit.internal.expression.Expression;
+import com.sk89q.worldedit.internal.expression.ExpressionException;
+import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
+import com.sk89q.worldedit.util.command.parametric.ArgumentStack;
+import com.sk89q.worldedit.util.command.parametric.BindingBehavior;
+import com.sk89q.worldedit.util.command.parametric.BindingHelper;
+import com.sk89q.worldedit.util.command.parametric.BindingMatch;
+import com.sk89q.worldedit.util.command.parametric.ParameterException;
+import javax.annotation.Nullable;
import java.lang.annotation.Annotation;
/**
@@ -84,6 +92,35 @@ public final class PrimitiveBindings extends BindingHelper {
return context.nextBoolean();
}
+ /**
+ * Try to parse numeric input as either a number or a mathematical expression.
+ *
+ * @param input input
+ * @return a number
+ * @throws ParameterException thrown on parse error
+ */
+ private @Nullable Double parseNumericInput(@Nullable String input) throws ParameterException {
+ if (input == null) {
+ return null;
+ }
+
+ try {
+ return Double.parseDouble(input);
+ } catch (NumberFormatException e1) {
+ try {
+ Expression expression = Expression.compile(input);
+ return expression.evaluate();
+ } catch (EvaluationException e) {
+ throw new ParameterException(String.format(
+ "Expected '%s' to be a valid number (or a valid mathematical expression)", input));
+ } catch (ExpressionException e) {
+ throw new ParameterException(String.format(
+ "Expected '%s' to be a number or valid math expression (error: %s)", input, e.getMessage()));
+ }
+
+ }
+ }
+
/**
* Gets a type from a {@link ArgumentStack}.
*
@@ -96,13 +133,15 @@ public final class PrimitiveBindings extends BindingHelper {
behavior = BindingBehavior.CONSUMES,
consumedCount = 1,
provideModifiers = true)
- public Integer getInteger(ArgumentStack context, Annotation[] modifiers)
- throws ParameterException {
- Integer v = context.nextInt();
+ public Integer getInteger(ArgumentStack context, Annotation[] modifiers) throws ParameterException {
+ Double v = parseNumericInput(context.next());
if (v != null) {
- validate(v, modifiers);
+ int intValue = v.intValue();
+ validate(intValue, modifiers);
+ return intValue;
+ } else {
+ return null;
}
- return v;
}
/**
@@ -117,8 +156,7 @@ public final class PrimitiveBindings extends BindingHelper {
behavior = BindingBehavior.CONSUMES,
consumedCount = 1,
provideModifiers = true)
- public Short getShort(ArgumentStack context, Annotation[] modifiers)
- throws ParameterException {
+ public Short getShort(ArgumentStack context, Annotation[] modifiers) throws ParameterException {
Integer v = getInteger(context, modifiers);
if (v != null) {
return v.shortValue();
@@ -138,13 +176,14 @@ public final class PrimitiveBindings extends BindingHelper {
behavior = BindingBehavior.CONSUMES,
consumedCount = 1,
provideModifiers = true)
- public Double getDouble(ArgumentStack context, Annotation[] modifiers)
- throws ParameterException {
- Double v = context.nextDouble();
+ public Double getDouble(ArgumentStack context, Annotation[] modifiers) throws ParameterException {
+ Double v = parseNumericInput(context.next());
if (v != null) {
validate(v, modifiers);
+ return v;
+ } else {
+ return null;
}
- return v;
}
/**
@@ -159,8 +198,7 @@ public final class PrimitiveBindings extends BindingHelper {
behavior = BindingBehavior.CONSUMES,
consumedCount = 1,
provideModifiers = true)
- public Float getFloat(ArgumentStack context, Annotation[] modifiers)
- throws ParameterException {
+ public Float getFloat(ArgumentStack context, Annotation[] modifiers) throws ParameterException {
Double v = getDouble(context, modifiers);
if (v != null) {
return v.floatValue();
diff --git a/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java b/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java
index dd96c4a2a..c7b94ebde 100644
--- a/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java
+++ b/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricBuilder.java
@@ -27,7 +27,9 @@ import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.util.auth.Authorizer;
import com.sk89q.worldedit.util.auth.NullAuthorizer;
import com.sk89q.worldedit.util.command.CommandCallable;
+import com.sk89q.worldedit.util.command.CommandCompleter;
import com.sk89q.worldedit.util.command.Dispatcher;
+import com.sk89q.worldedit.util.command.NullCompleter;
import com.sk89q.worldedit.util.command.binding.PrimitiveBindings;
import com.sk89q.worldedit.util.command.binding.StandardBindings;
import com.sk89q.worldedit.util.command.binding.Switch;
@@ -57,6 +59,7 @@ public class ParametricBuilder {
private final List invokeListeners = new ArrayList();
private final List exceptionConverters = new ArrayList();
private Authorizer authorizer = new NullAuthorizer();
+ private CommandCompleter defaultCompleter = new NullCompleter();
/**
* Create a new builder.
@@ -225,4 +228,26 @@ public class ParametricBuilder {
checkNotNull(authorizer);
this.authorizer = authorizer;
}
+
+ /**
+ * Get the default command suggestions provider that will be used if
+ * no suggestions are available.
+ *
+ * @return the default command completer
+ */
+ public CommandCompleter getDefaultCompleter() {
+ return defaultCompleter;
+ }
+
+ /**
+ * Set the default command suggestions provider that will be used if
+ * no suggestions are available.
+ *
+ * @param defaultCompleter the default command completer
+ */
+ public void setDefaultCompleter(CommandCompleter defaultCompleter) {
+ checkNotNull(defaultCompleter);
+ this.defaultCompleter = defaultCompleter;
+ }
+
}
diff --git a/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java b/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java
index a96434ac0..5a7836264 100644
--- a/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java
+++ b/src/main/java/com/sk89q/worldedit/util/command/parametric/ParametricCallable.java
@@ -41,7 +41,6 @@ import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -273,8 +272,8 @@ class ParametricCallable implements CommandCallable {
}
@Override
- public List getSuggestions(String stringArguments, CommandLocals locals) throws CommandException {
- return Collections.emptyList();
+ public List getSuggestions(String arguments, CommandLocals locals) throws CommandException {
+ return builder.getDefaultCompleter().getSuggestions(arguments, locals);
}
/**