geforkt von Mirrors/FastAsyncWorldEdit
Merge commit '142f5c8e5c889ee5098c05ba2fde20b52467c1df' into feature/platform-caps
Dieser Commit ist enthalten in:
Commit
8f1943fd84
@ -44,6 +44,7 @@ dependencies {
|
||||
compile group: 'com.google.guava', name: 'guava', version:'10.0.1'
|
||||
compile group: 'com.sk89q', name: 'jchronic', version:'0.2.4a'
|
||||
compile group: 'com.google.code.findbugs', name: 'jsr305', version: '1.3.9'
|
||||
compile group: 'com.thoughtworks.paranamer', name: 'paranamer', version: '2.6'
|
||||
testCompile group: 'org.mockito', name: 'mockito-core', version:'1.9.0-rc1'
|
||||
}
|
||||
|
||||
@ -87,6 +88,7 @@ shadow {
|
||||
destinationDir "${buildDir}/libs/"
|
||||
artifactSet {
|
||||
include '*:jchronic:jar:'
|
||||
include '*:paranamer:jar:'
|
||||
}
|
||||
}
|
||||
|
||||
|
37
pom.xml
37
pom.xml
@ -97,6 +97,13 @@
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>sk89q-repo</id>
|
||||
<url>http://maven.sk89q.com/repo/</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Used for snapshots -->
|
||||
<dependency>
|
||||
@ -151,6 +158,15 @@
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
|
||||
<!-- Method names for the command framework -->
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.paranamer</groupId>
|
||||
<artifactId>paranamer</artifactId>
|
||||
<version>2.6</version>
|
||||
<scope>compile</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
|
||||
<!-- Unit tests -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
@ -297,6 +313,26 @@
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Stores parameter information -->
|
||||
<plugin>
|
||||
<groupId>com.thoughtworks.paranamer</groupId>
|
||||
<artifactId>paranamer-maven-plugin-largestack</artifactId>
|
||||
<version>2.5.5-SNAPSHOT</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>run</id>
|
||||
<phase>compile</phase>
|
||||
<configuration>
|
||||
<sourceDirectory>${project.build.sourceDirectory}</sourceDirectory>
|
||||
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>generate</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- JAR plugin -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@ -352,6 +388,7 @@
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>com.sk89q:jchronic</include>
|
||||
<include>com.thoughtworks.paranamer:paranamer</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
|
@ -21,13 +21,16 @@ package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.sk89q.bukkit.util.CommandInfo;
|
||||
import com.sk89q.bukkit.util.CommandRegistration;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
import com.sk89q.minecraft.util.commands.CommandsManager;
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.BiomeTypes;
|
||||
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.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Preference;
|
||||
import com.sk89q.worldedit.util.command.CommandMapping;
|
||||
import com.sk89q.worldedit.util.command.Description;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
@ -35,8 +38,10 @@ import org.bukkit.World;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BukkitServerInterface extends ServerInterface {
|
||||
public Server server;
|
||||
@ -118,25 +123,17 @@ public class BukkitServerInterface extends ServerInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommandRegistration(List<Command> commands, CommandsManager<LocalPlayer> manager) {
|
||||
public void registerCommands(Dispatcher dispatcher) {
|
||||
List<CommandInfo> toRegister = new ArrayList<CommandInfo>();
|
||||
for (Command command : commands) {
|
||||
List<String> permissions = null;
|
||||
Method cmdMethod = manager.getMethods().get(null).get(command.aliases()[0]);
|
||||
Map<String, Method> childMethods = manager.getMethods().get(cmdMethod);
|
||||
for (CommandMapping command : dispatcher.getCommands()) {
|
||||
Description description = command.getDescription();
|
||||
List<String> permissions = description.getPermissions();
|
||||
String[] permissionsArray = new String[permissions.size()];
|
||||
permissions.toArray(permissionsArray);
|
||||
|
||||
if (cmdMethod != null && cmdMethod.isAnnotationPresent(CommandPermissions.class)) {
|
||||
permissions = Arrays.asList(cmdMethod.getAnnotation(CommandPermissions.class).value());
|
||||
} else if (cmdMethod != null && childMethods != null && childMethods.size() > 0) {
|
||||
permissions = new ArrayList<String>();
|
||||
for (Method m : childMethods.values()) {
|
||||
if (m.isAnnotationPresent(CommandPermissions.class)) {
|
||||
permissions.addAll(Arrays.asList(m.getAnnotation(CommandPermissions.class).value()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toRegister.add(new CommandInfo(command.usage(), command.desc(), command.aliases(), commands, permissions == null ? null : permissions.toArray(new String[permissions.size()])));
|
||||
toRegister.add(new CommandInfo(
|
||||
description.getUsage(), description.getDescription(),
|
||||
command.getAllAliases(), dispatcher, permissionsArray));
|
||||
}
|
||||
|
||||
dynamicCommands.register(toRegister);
|
||||
|
@ -19,13 +19,15 @@
|
||||
|
||||
package com.sk89q.worldedit.forge;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
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.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Preference;
|
||||
import com.sk89q.worldedit.util.command.CommandMapping;
|
||||
import com.sk89q.worldedit.util.command.Description;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import net.minecraft.command.CommandBase;
|
||||
@ -133,19 +135,22 @@ class ForgePlatform extends ServerInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommandRegistration(List<Command> commands) {
|
||||
public void registerCommands(Dispatcher dispatcher) {
|
||||
if (server == null) return;
|
||||
ServerCommandManager mcMan = (ServerCommandManager) server.getCommandManager();
|
||||
for (final Command cmd : commands) {
|
||||
|
||||
for (final CommandMapping command : dispatcher.getCommands()) {
|
||||
final Description description = command.getDescription();
|
||||
|
||||
mcMan.registerCommand(new CommandBase() {
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return cmd.aliases()[0];
|
||||
return command.getPrimaryAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getCommandAliases() {
|
||||
return Arrays.asList(cmd.aliases());
|
||||
return Arrays.asList(command.getAllAliases());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -153,12 +158,14 @@ class ForgePlatform extends ServerInterface {
|
||||
|
||||
@Override
|
||||
public String getCommandUsage(ICommandSender icommandsender) {
|
||||
return "/" + cmd.aliases()[0] + " " + cmd.usage();
|
||||
return "/" + command.getPrimaryAlias() + " " + description.getUsage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object o) {
|
||||
if (o instanceof ICommand) {
|
||||
public int compareTo(@Nullable Object o) {
|
||||
if (o == null) {
|
||||
return -1;
|
||||
} else if (o instanceof ICommand) {
|
||||
return super.compareTo((ICommand) o);
|
||||
} else {
|
||||
return -1;
|
||||
|
@ -9,6 +9,7 @@
|
||||
<allow pkg="org.mockito"/>
|
||||
<allow pkg="com.sk89q"/>
|
||||
<allow pkg="com.google.common"/>
|
||||
<allow pkg="com.thoughtworks.paranamer"/>
|
||||
|
||||
<subpackage name="util.yaml">
|
||||
<allow pkg="org.yaml.snakeyaml"/>
|
||||
|
@ -28,15 +28,22 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class CommandContext {
|
||||
|
||||
protected final String command;
|
||||
protected final List<String> parsedArgs;
|
||||
protected final List<Integer> originalArgIndices;
|
||||
protected final String[] originalArgs;
|
||||
protected final Set<Character> booleanFlags = new HashSet<Character>();
|
||||
protected final Map<Character, String> valueFlags = new HashMap<Character, String>();
|
||||
protected final SuggestionContext suggestionContext;
|
||||
protected final CommandLocals locals;
|
||||
|
||||
public static String[] split(String args) {
|
||||
return args.split(" ", -1);
|
||||
}
|
||||
|
||||
public CommandContext(String args) throws CommandException {
|
||||
this(args.split(" "), null);
|
||||
this(args.split(" ", -1), null);
|
||||
}
|
||||
|
||||
public CommandContext(String[] args) throws CommandException {
|
||||
@ -44,28 +51,50 @@ public class CommandContext {
|
||||
}
|
||||
|
||||
public CommandContext(String args, Set<Character> valueFlags) throws CommandException {
|
||||
this(args.split(" "), valueFlags);
|
||||
this(args.split(" ", -1), valueFlags);
|
||||
}
|
||||
|
||||
public CommandContext(String args, Set<Character> valueFlags, boolean allowHangingFlag)
|
||||
throws CommandException {
|
||||
this(args.split(" ", -1), valueFlags, allowHangingFlag, new CommandLocals());
|
||||
}
|
||||
|
||||
public CommandContext(String[] args, Set<Character> valueFlags) throws CommandException {
|
||||
this(args, valueFlags, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args An array with arguments. Empty strings outside quotes will be removed.
|
||||
* @param valueFlags A set containing all value flags. Pass null to disable value flag parsing.
|
||||
* @throws CommandException This is thrown if flag fails for some reason.
|
||||
* Parse the given array of arguments.
|
||||
*
|
||||
* <p>Empty arguments are removed from the list of arguments.</p>
|
||||
*
|
||||
* @param args an array with arguments
|
||||
* @param valueFlags a set containing all value flags (pass null to disable value flag parsing)
|
||||
* @param allowHangingFlag true if hanging flags are allowed
|
||||
* @param locals the locals, null to create empty one
|
||||
* @throws CommandException thrown on a parsing error
|
||||
*/
|
||||
public CommandContext(String[] args, Set<Character> valueFlags) throws CommandException {
|
||||
public CommandContext(String[] args, Set<Character> valueFlags,
|
||||
boolean allowHangingFlag, CommandLocals locals) throws CommandException {
|
||||
if (valueFlags == null) {
|
||||
valueFlags = Collections.emptySet();
|
||||
}
|
||||
|
||||
originalArgs = args;
|
||||
command = args[0];
|
||||
this.locals = locals != null ? locals : new CommandLocals();
|
||||
boolean isHanging = false;
|
||||
SuggestionContext suggestionContext = SuggestionContext.hangingValue();
|
||||
|
||||
// Eliminate empty args and combine multiword args first
|
||||
List<Integer> argIndexList = new ArrayList<Integer>(args.length);
|
||||
List<String> argList = new ArrayList<String>(args.length);
|
||||
for (int i = 1; i < args.length; ++i) {
|
||||
isHanging = false;
|
||||
|
||||
String arg = args[i];
|
||||
if (arg.length() == 0) {
|
||||
isHanging = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -113,9 +142,14 @@ public class CommandContext {
|
||||
for (int nextArg = 0; nextArg < argList.size(); ) {
|
||||
// Fetch argument
|
||||
String arg = argList.get(nextArg++);
|
||||
suggestionContext = SuggestionContext.hangingValue();
|
||||
|
||||
// Not a flag?
|
||||
if (arg.charAt(0) != '-' || arg.length() == 1 || !arg.matches("^-[a-zA-Z]+$")) {
|
||||
if (!isHanging) {
|
||||
suggestionContext = SuggestionContext.lastValue();
|
||||
}
|
||||
|
||||
originalArgIndices.add(argIndexList.get(nextArg - 1));
|
||||
parsedArgs.add(arg);
|
||||
continue;
|
||||
@ -140,16 +174,30 @@ public class CommandContext {
|
||||
}
|
||||
|
||||
if (nextArg >= argList.size()) {
|
||||
if (allowHangingFlag) {
|
||||
suggestionContext = SuggestionContext.flag(flagName);
|
||||
break;
|
||||
} else {
|
||||
throw new CommandException("No value specified for the '-" + flagName + "' flag.");
|
||||
}
|
||||
}
|
||||
|
||||
// If it is a value flag, read another argument and add it
|
||||
this.valueFlags.put(flagName, argList.get(nextArg++));
|
||||
if (!isHanging) {
|
||||
suggestionContext = SuggestionContext.flag(flagName);
|
||||
}
|
||||
} else {
|
||||
booleanFlags.add(flagName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.suggestionContext = suggestionContext;
|
||||
}
|
||||
|
||||
public SuggestionContext getSuggestionContext() {
|
||||
return suggestionContext;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
@ -177,6 +225,18 @@ public class CommandContext {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public String getRemainingString(int start) {
|
||||
return getString(start, parsedArgs.size() - 1);
|
||||
}
|
||||
|
||||
public String getString(int start, int end) {
|
||||
StringBuilder buffer = new StringBuilder(parsedArgs.get(start));
|
||||
for (int i = start + 1; i < end + 1; ++i) {
|
||||
buffer.append(" ").append(parsedArgs.get(i));
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public int getInteger(int index) throws NumberFormatException {
|
||||
return Integer.parseInt(parsedArgs.get(index));
|
||||
}
|
||||
@ -271,4 +331,8 @@ public class CommandContext {
|
||||
public int argsLength() {
|
||||
return parsedArgs.size();
|
||||
}
|
||||
|
||||
public CommandLocals getLocals() {
|
||||
return locals;
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,14 @@
|
||||
|
||||
package com.sk89q.minecraft.util.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
public class CommandException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 870638193072101739L;
|
||||
private List<String> commandStack = new ArrayList<String>();
|
||||
|
||||
public CommandException() {
|
||||
super();
|
||||
@ -30,8 +36,37 @@ public class CommandException extends Exception {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CommandException(String message, Throwable t) {
|
||||
super(message, t);
|
||||
}
|
||||
|
||||
public CommandException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
public void prependStack(String name) {
|
||||
commandStack.add(name);
|
||||
}
|
||||
|
||||
public String toStackString(String prefix, String spacedSuffix) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (prefix != null) {
|
||||
builder.append(prefix);
|
||||
}
|
||||
ListIterator<String> li = commandStack.listIterator(commandStack.size());
|
||||
while (li.hasPrevious()) {
|
||||
if (li.previousIndex() != commandStack.size() - 1) {
|
||||
builder.append(" ");
|
||||
}
|
||||
builder.append(li.previous());
|
||||
}
|
||||
if (spacedSuffix != null) {
|
||||
if (builder.length() > 0) {
|
||||
builder.append(" ");
|
||||
}
|
||||
builder.append(spacedSuffix);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
50
src/main/java/com/sk89q/minecraft/util/commands/CommandLocals.java
Normale Datei
50
src/main/java/com/sk89q/minecraft/util/commands/CommandLocals.java
Normale Datei
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.minecraft.util.commands;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CommandLocals {
|
||||
|
||||
private final Map<Object, Object> locals = new HashMap<Object, Object>();
|
||||
|
||||
public boolean containsKey(Object key) {
|
||||
return locals.containsKey(key);
|
||||
}
|
||||
|
||||
public boolean containsValue(Object value) {
|
||||
return locals.containsValue(value);
|
||||
}
|
||||
|
||||
public Object get(Object key) {
|
||||
return locals.get(key);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(Class<T> key) {
|
||||
return (T) locals.get(key);
|
||||
}
|
||||
|
||||
public Object put(Object key, Object value) {
|
||||
return locals.put(key, value);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.minecraft.util.commands;
|
||||
|
||||
public class SuggestionContext {
|
||||
|
||||
private static final SuggestionContext FOR_LAST = new SuggestionContext(null, true);
|
||||
private static final SuggestionContext FOR_HANGING = new SuggestionContext(null, false);
|
||||
|
||||
private final Character flag;
|
||||
private final boolean forLast;
|
||||
|
||||
private SuggestionContext(Character flag, boolean forLast) {
|
||||
this.flag = flag;
|
||||
this.forLast = forLast;
|
||||
}
|
||||
|
||||
public boolean forHangingValue() {
|
||||
return flag == null && !forLast;
|
||||
}
|
||||
|
||||
public boolean forLastValue() {
|
||||
return flag == null && forLast;
|
||||
}
|
||||
|
||||
public boolean forFlag() {
|
||||
return flag != null;
|
||||
}
|
||||
|
||||
public Character getFlag() {
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return forFlag() ? ("-" + getFlag()) : (forHangingValue() ? "hanging" : "last");
|
||||
}
|
||||
|
||||
public static SuggestionContext flag(Character flag) {
|
||||
return new SuggestionContext(flag, false);
|
||||
}
|
||||
|
||||
public static SuggestionContext lastValue() {
|
||||
return FOR_LAST;
|
||||
}
|
||||
|
||||
public static SuggestionContext hangingValue() {
|
||||
return FOR_HANGING;
|
||||
}
|
||||
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit;
|
||||
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.event.extent.EditSessionEvent;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.util.eventbus.EventBus;
|
||||
@ -63,7 +64,7 @@ public class EditSessionFactory {
|
||||
* @param maxBlocks the maximum number of blocks that can be changed, or -1 to use no limit
|
||||
* @param player the player that the {@link EditSession} is for
|
||||
*/
|
||||
public EditSession getEditSession(World world, int maxBlocks, LocalPlayer player) {
|
||||
public EditSession getEditSession(World world, int maxBlocks, Player player) {
|
||||
throw new IllegalArgumentException("This class is being removed");
|
||||
}
|
||||
|
||||
@ -96,7 +97,7 @@ public class EditSessionFactory {
|
||||
* @param blockBag an optional {@link BlockBag} to use, otherwise null
|
||||
* @param player the player that the {@link EditSession} is for
|
||||
*/
|
||||
public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, LocalPlayer player) {
|
||||
public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Player player) {
|
||||
throw new IllegalArgumentException("This class is being removed");
|
||||
}
|
||||
|
||||
@ -123,7 +124,7 @@ public class EditSessionFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EditSession getEditSession(World world, int maxBlocks, LocalPlayer player) {
|
||||
public EditSession getEditSession(World world, int maxBlocks, Player player) {
|
||||
return new EditSession(eventBus, world, maxBlocks, null, new EditSessionEvent(world, player, maxBlocks, null));
|
||||
}
|
||||
|
||||
@ -133,7 +134,7 @@ public class EditSessionFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, LocalPlayer player) {
|
||||
public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Player player) {
|
||||
return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, player, maxBlocks, null));
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import com.sk89q.worldedit.command.tool.BlockTool;
|
||||
import com.sk89q.worldedit.command.tool.BrushTool;
|
||||
import com.sk89q.worldedit.command.tool.SinglePickaxe;
|
||||
import com.sk89q.worldedit.command.tool.Tool;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||
import com.sk89q.worldedit.internal.cui.CUIEvent;
|
||||
@ -419,7 +420,7 @@ public class LocalSession {
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
public BlockBag getBlockBag(LocalPlayer player) {
|
||||
public BlockBag getBlockBag(Player player) {
|
||||
if (!useInventory) {
|
||||
return null;
|
||||
}
|
||||
@ -550,7 +551,7 @@ public class LocalSession {
|
||||
*
|
||||
* @param player
|
||||
*/
|
||||
public void tellVersion(LocalPlayer player) {
|
||||
public void tellVersion(Actor player) {
|
||||
if (config.showFirstUseVersion) {
|
||||
if (!beenToldVersion) {
|
||||
player.printRaw("\u00A78WorldEdit ver. " + WorldEdit.getVersion()
|
||||
@ -713,6 +714,17 @@ public class LocalSession {
|
||||
* @return
|
||||
*/
|
||||
public EditSession createEditSession(LocalPlayer player) {
|
||||
return createEditSession((Player) player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new edit session.
|
||||
*
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public EditSession createEditSession(Player player) {
|
||||
BlockBag blockBag = getBlockBag(player);
|
||||
|
||||
// Create an edit session
|
||||
@ -721,8 +733,8 @@ public class LocalSession {
|
||||
getBlockChangeLimit(), blockBag, player);
|
||||
editSession.setFastMode(fastMode);
|
||||
Request.request().setEditSession(editSession);
|
||||
if (mask != null) {
|
||||
mask.prepare(this, player, null);
|
||||
if (mask != null && player instanceof LocalPlayer) {
|
||||
mask.prepare(this, (LocalPlayer) player, null);
|
||||
}
|
||||
editSession.setMask(mask);
|
||||
|
||||
|
@ -19,12 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandsManager;
|
||||
import com.sk89q.worldedit.CuboidClipboard.FlipDirection;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.blocks.BlockType;
|
||||
import com.sk89q.worldedit.event.platform.BlockInteractEvent;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.event.extent.EditSessionEvent;
|
||||
import com.sk89q.worldedit.event.platform.BlockInteractEvent;
|
||||
import com.sk89q.worldedit.event.platform.CommandEvent;
|
||||
import com.sk89q.worldedit.event.platform.InputType;
|
||||
import com.sk89q.worldedit.event.platform.PlayerInputEvent;
|
||||
@ -483,7 +483,7 @@ public class WorldEdit {
|
||||
* @return a direction vector
|
||||
* @throws UnknownDirectionException thrown if the direction is not known
|
||||
*/
|
||||
public Vector getDirection(LocalPlayer player, String dirStr) throws UnknownDirectionException {
|
||||
public Vector getDirection(Player player, String dirStr) throws UnknownDirectionException {
|
||||
dirStr = dirStr.toLowerCase();
|
||||
|
||||
final PlayerDirection dir = getPlayerDirection(player, dirStr);
|
||||
@ -511,7 +511,7 @@ public class WorldEdit {
|
||||
* @return a direction enum value
|
||||
* @throws UnknownDirectionException thrown if the direction is not known
|
||||
*/
|
||||
private PlayerDirection getPlayerDirection(LocalPlayer player, String dirStr) throws UnknownDirectionException {
|
||||
private PlayerDirection getPlayerDirection(Player player, String dirStr) throws UnknownDirectionException {
|
||||
final PlayerDirection dir;
|
||||
|
||||
switch (dirStr.charAt(0)) {
|
||||
@ -661,24 +661,6 @@ public class WorldEdit {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map of commands (internal usage only).
|
||||
*
|
||||
* @return the commands
|
||||
*/
|
||||
public Map<String, String> getCommands() {
|
||||
return getCommandsManager().getCommands();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the commands manager (internal usage only).
|
||||
*
|
||||
* @return the commands
|
||||
*/
|
||||
public CommandsManager<LocalPlayer> getCommandsManager() {
|
||||
return getPlatformManager().getCommandManager().getCommands();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a disconnection.
|
||||
*
|
||||
|
@ -260,13 +260,6 @@ public class ClipboardCommands {
|
||||
player.printError("This command is no longer used. See //schematic save.");
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "/schematic", "/schem"},
|
||||
desc = "Schematic-related commands"
|
||||
)
|
||||
@NestedCommand(SchematicCommands.class)
|
||||
public void schematic() {}
|
||||
|
||||
@Command(
|
||||
aliases = { "clearclipboard" },
|
||||
usage = "",
|
||||
|
@ -23,13 +23,7 @@ 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.Console;
|
||||
import com.sk89q.minecraft.util.commands.NestedCommand;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.LocalPlayer;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.blocks.ItemType;
|
||||
import com.sk89q.worldedit.masks.Mask;
|
||||
|
||||
@ -226,13 +220,4 @@ public class GeneralCommands {
|
||||
}
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "we", "worldedit" },
|
||||
desc = "WorldEdit commands"
|
||||
)
|
||||
@NestedCommand(WorldEditCommands.class)
|
||||
@Console
|
||||
public void we(CommandContext args, LocalSession session, LocalPlayer player,
|
||||
EditSession editSession) throws WorldEditException {
|
||||
}
|
||||
}
|
||||
|
@ -54,15 +54,6 @@ public class SnapshotUtilCommands {
|
||||
this.we = we;
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "snapshot", "snap" },
|
||||
desc = "Snapshot commands"
|
||||
)
|
||||
@NestedCommand(SnapshotCommands.class)
|
||||
public void snapshot(CommandContext args, LocalSession session, LocalPlayer player,
|
||||
EditSession editSession) throws WorldEditException {
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "restore", "/restore" },
|
||||
usage = "[snapshot]",
|
||||
|
@ -151,15 +151,6 @@ public class ToolCommands {
|
||||
+ ItemType.toHeldName(player.getItemInHand()) + ".");
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "brush", "br" },
|
||||
desc = "Brush tool"
|
||||
)
|
||||
@NestedCommand(BrushCommands.class)
|
||||
public void brush(CommandContext args, LocalSession session, LocalPlayer player,
|
||||
EditSession editSession) throws WorldEditException {
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "deltree" },
|
||||
usage = "",
|
||||
|
@ -22,7 +22,6 @@ package com.sk89q.worldedit.command;
|
||||
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.NestedCommand;
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.masks.Mask;
|
||||
import com.sk89q.worldedit.patterns.Pattern;
|
||||
@ -70,24 +69,6 @@ public class ToolUtilCommands {
|
||||
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "superpickaxe", "pickaxe", "sp" },
|
||||
desc = "Select super pickaxe mode"
|
||||
)
|
||||
@NestedCommand(SuperPickaxeCommands.class)
|
||||
public void pickaxe(CommandContext args, LocalSession session, LocalPlayer player,
|
||||
EditSession editSession) throws WorldEditException {
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = {"tool"},
|
||||
desc = "Select a tool to bind"
|
||||
)
|
||||
@NestedCommand(ToolCommands.class)
|
||||
public void tool(CommandContext args, LocalSession session, LocalPlayer player,
|
||||
EditSession editSession) throws WorldEditException {
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "mask" },
|
||||
usage = "[mask]",
|
||||
|
@ -27,6 +27,9 @@ import com.sk89q.worldedit.patterns.Pattern;
|
||||
import com.sk89q.worldedit.patterns.SingleBlockPattern;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.command.CommandMapping;
|
||||
import com.sk89q.worldedit.util.command.Description;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import java.util.Comparator;
|
||||
@ -512,7 +515,7 @@ public class UtilityCommands {
|
||||
}
|
||||
|
||||
public static void help(CommandContext args, WorldEdit we, LocalSession session, LocalPlayer player, EditSession editSession) {
|
||||
final CommandsManager<LocalPlayer> commandsManager = we.getCommandsManager();
|
||||
final Dispatcher dispatcher = we.getPlatformManager().getCommandManager().getDispatcher();
|
||||
|
||||
if (args.argsLength() == 0) {
|
||||
SortedSet<String> commands = new TreeSet<String>(new Comparator<String>() {
|
||||
@ -525,7 +528,7 @@ public class UtilityCommands {
|
||||
return ret;
|
||||
}
|
||||
});
|
||||
commands.addAll(commandsManager.getCommands().keySet());
|
||||
commands.addAll(dispatcher.getPrimaryAliases());
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean first = true;
|
||||
@ -544,14 +547,26 @@ public class UtilityCommands {
|
||||
return;
|
||||
}
|
||||
|
||||
String command = args.getJoinedStrings(0).toLowerCase().replaceAll("/", "");
|
||||
String command = args.getJoinedStrings(0).toLowerCase().replaceAll("^/", "");
|
||||
CommandMapping mapping = dispatcher.get(command);
|
||||
|
||||
String helpMessage = commandsManager.getHelpMessages().get(command);
|
||||
if (helpMessage == null) {
|
||||
if (mapping == null) {
|
||||
player.printError("Unknown command '" + command + "'.");
|
||||
return;
|
||||
}
|
||||
|
||||
player.print(helpMessage);
|
||||
Description description = mapping.getDescription();
|
||||
|
||||
if (description.getUsage() != null) {
|
||||
player.printDebug("Usage: " + description.getUsage());
|
||||
}
|
||||
|
||||
if (description.getHelp() != null) {
|
||||
player.print(description.getHelp());
|
||||
} else if (description.getDescription() != null) {
|
||||
player.print(description.getDescription());
|
||||
} else {
|
||||
player.print("No further help is available.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,15 +42,4 @@ public abstract class AbstractPlatform implements Platform {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void onCommandRegistration(List<Command> commands) {
|
||||
// Do nothing :)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommandRegistration(List<Command> commands, CommandsManager<LocalPlayer> manager) {
|
||||
onCommandRegistration(commands);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,22 +19,35 @@
|
||||
|
||||
package com.sk89q.worldedit.extension.platform;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.*;
|
||||
import com.sk89q.util.StringUtil;
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.blocks.ItemType;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.CommandLocals;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
|
||||
import com.sk89q.minecraft.util.commands.WrappedCommandException;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.command.*;
|
||||
import com.sk89q.worldedit.event.platform.CommandEvent;
|
||||
import com.sk89q.worldedit.session.request.Request;
|
||||
import com.sk89q.worldedit.util.logging.LogFormat;
|
||||
import com.sk89q.worldedit.util.CommandLoggingHandler;
|
||||
import com.sk89q.worldedit.util.CommandPermissionsHandler;
|
||||
import com.sk89q.worldedit.util.WorldEditBinding;
|
||||
import com.sk89q.worldedit.util.WorldEditExceptionConverter;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import com.sk89q.worldedit.util.command.InvalidUsageException;
|
||||
import com.sk89q.worldedit.util.command.fluent.CommandGraph;
|
||||
import com.sk89q.worldedit.util.command.parametric.LegacyCommandsHandler;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
|
||||
import com.sk89q.worldedit.util.eventbus.Subscribe;
|
||||
import com.sk89q.worldedit.util.logging.DynamicStreamHandler;
|
||||
import com.sk89q.worldedit.util.logging.LogFormat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.logging.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -49,7 +62,7 @@ public final class CommandManager {
|
||||
private static final java.util.regex.Pattern numberFormatExceptionPattern = java.util.regex.Pattern.compile("^For input string: \"(.*)\"$");
|
||||
|
||||
private final WorldEdit worldEdit;
|
||||
private final CommandsManager<LocalPlayer> commands;
|
||||
private final Dispatcher dispatcher;
|
||||
private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler();
|
||||
|
||||
/**
|
||||
@ -69,8 +82,56 @@ public final class CommandManager {
|
||||
dynamicHandler.setFormatter(new LogFormat());
|
||||
|
||||
// Set up the commands manager
|
||||
commands = new CommandsManagerImpl();
|
||||
commands.setInjector(new SimpleInjector(worldEdit));
|
||||
ParametricBuilder builder = new ParametricBuilder();
|
||||
builder.addBinding(new WorldEditBinding(worldEdit));
|
||||
builder.attach(new CommandPermissionsHandler());
|
||||
builder.attach(new WorldEditExceptionConverter(worldEdit));
|
||||
builder.attach(new LegacyCommandsHandler());
|
||||
builder.attach(new CommandLoggingHandler(worldEdit, logger));
|
||||
|
||||
dispatcher = new CommandGraph()
|
||||
.builder(builder)
|
||||
.commands()
|
||||
.build(new BiomeCommands(worldEdit))
|
||||
.build(new ChunkCommands(worldEdit))
|
||||
.build(new ClipboardCommands(worldEdit))
|
||||
.build(new GeneralCommands(worldEdit))
|
||||
.build(new GenerationCommands(worldEdit))
|
||||
.build(new HistoryCommands(worldEdit))
|
||||
.build(new NavigationCommands(worldEdit))
|
||||
.build(new RegionCommands(worldEdit))
|
||||
.build(new ScriptingCommands(worldEdit))
|
||||
.build(new SelectionCommands(worldEdit))
|
||||
.build(new SnapshotUtilCommands(worldEdit))
|
||||
.build(new ToolUtilCommands(worldEdit))
|
||||
.build(new ToolCommands(worldEdit))
|
||||
.build(new UtilityCommands(worldEdit))
|
||||
.group("worldedit", "we")
|
||||
.describe("WorldEdit commands")
|
||||
.build(new WorldEditCommands(worldEdit))
|
||||
.parent()
|
||||
.group("schematic", "schem", "/schematic", "/schem")
|
||||
.describe("Schematic commands for saving/loading areas")
|
||||
.build(new SchematicCommands(worldEdit))
|
||||
.parent()
|
||||
.group("snapshot", "snap")
|
||||
.describe("Schematic commands for saving/loading areas")
|
||||
.build(new SnapshotCommands(worldEdit))
|
||||
.parent()
|
||||
.group("brush", "br")
|
||||
.describe("Brushing commands")
|
||||
.build(new BrushCommands(worldEdit))
|
||||
.parent()
|
||||
.group("superpickaxe", "pickaxe", "sp")
|
||||
.describe("Super-pickaxe commands")
|
||||
.build(new SuperPickaxeCommands(worldEdit))
|
||||
.parent()
|
||||
.group("tool")
|
||||
.describe("Bind functions to held items")
|
||||
.build(new ToolCommands(worldEdit))
|
||||
.parent()
|
||||
.graph()
|
||||
.getDispatcher();
|
||||
}
|
||||
|
||||
void register(Platform platform) {
|
||||
@ -95,37 +156,14 @@ public final class CommandManager {
|
||||
}
|
||||
}
|
||||
|
||||
register(platform, BiomeCommands.class);
|
||||
register(platform, ChunkCommands.class);
|
||||
register(platform, ClipboardCommands.class);
|
||||
register(platform, GeneralCommands.class);
|
||||
register(platform, GenerationCommands.class);
|
||||
register(platform, HistoryCommands.class);
|
||||
register(platform, NavigationCommands.class);
|
||||
register(platform, RegionCommands.class);
|
||||
register(platform, ScriptingCommands.class);
|
||||
register(platform, SelectionCommands.class);
|
||||
register(platform, SnapshotUtilCommands.class);
|
||||
register(platform, ToolUtilCommands.class);
|
||||
register(platform, ToolCommands.class);
|
||||
register(platform, UtilityCommands.class);
|
||||
platform.registerCommands(dispatcher);
|
||||
}
|
||||
|
||||
void unregister() {
|
||||
dynamicHandler.setHandler(null);
|
||||
}
|
||||
|
||||
private void register(Platform platform, Class<?> clazz) {
|
||||
platform.onCommandRegistration(commands.registerAndReturn(clazz), commands);
|
||||
}
|
||||
|
||||
public CommandsManager<LocalPlayer> getCommands() {
|
||||
return commands;
|
||||
}
|
||||
|
||||
public String[] commandDetection(String[] split) {
|
||||
Request.reset();
|
||||
|
||||
split[0] = split[0].substring(1);
|
||||
|
||||
// Quick script shortcut
|
||||
@ -140,14 +178,13 @@ public final class CommandManager {
|
||||
String searchCmd = split[0].toLowerCase();
|
||||
|
||||
// Try to detect the command
|
||||
if (commands.hasCommand(searchCmd)) {
|
||||
} else if (worldEdit.getConfiguration().noDoubleSlash && commands.hasCommand("/" + searchCmd)) {
|
||||
if (dispatcher.contains(searchCmd)) {
|
||||
} else if (worldEdit.getConfiguration().noDoubleSlash && dispatcher.contains("/" + searchCmd)) {
|
||||
split[0] = "/" + split[0];
|
||||
} else if (split[0].length() >= 2 && split[0].charAt(0) == '/'
|
||||
&& commands.hasCommand(searchCmd.substring(1))) {
|
||||
&& dispatcher.contains(searchCmd.substring(1))) {
|
||||
split[0] = split[0].substring(1);
|
||||
}
|
||||
|
||||
return split;
|
||||
}
|
||||
|
||||
@ -155,185 +192,69 @@ public final class CommandManager {
|
||||
public void handleCommand(CommandEvent event) {
|
||||
Request.reset();
|
||||
|
||||
LocalPlayer player = event.getPlayer();
|
||||
String[] split = event.getArguments();
|
||||
|
||||
try {
|
||||
split = commandDetection(split);
|
||||
Actor actor = event.getPlayer();
|
||||
String split[] = commandDetection(event.getArguments());
|
||||
|
||||
// No command found!
|
||||
if (!commands.hasCommand(split[0])) {
|
||||
if (!dispatcher.contains(split[0])) {
|
||||
return;
|
||||
}
|
||||
|
||||
LocalSession session = worldEdit.getSession(player);
|
||||
EditSession editSession = session.createEditSession(player);
|
||||
editSession.enableQueue();
|
||||
LocalSession session = worldEdit.getSessionManager().get(actor);
|
||||
LocalConfiguration config = worldEdit.getConfiguration();
|
||||
|
||||
session.tellVersion(player);
|
||||
CommandLocals locals = new CommandLocals();
|
||||
locals.put(Actor.class, actor);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
commands.execute(split, player, session, player, editSession);
|
||||
dispatcher.call(split, locals);
|
||||
} catch (CommandPermissionsException e) {
|
||||
player.printError("You don't have permission to do this.");
|
||||
} catch (MissingNestedCommandException e) {
|
||||
player.printError(e.getUsage());
|
||||
} catch (CommandUsageException e) {
|
||||
player.printError(e.getMessage());
|
||||
player.printError(e.getUsage());
|
||||
} catch (PlayerNeededException e) {
|
||||
player.printError(e.getMessage());
|
||||
actor.printError("You don't have permission to do this.");
|
||||
} catch (InvalidUsageException e) {
|
||||
actor.printError(e.getMessage() + "\nUsage: " + e.getUsage("/"));
|
||||
} catch (WrappedCommandException e) {
|
||||
throw e.getCause();
|
||||
} catch (UnhandledCommandException e) {
|
||||
player.printError("Command could not be handled; invalid sender!");
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
Throwable t = e.getCause();
|
||||
actor.printError("Please report this error: [See console]");
|
||||
actor.printRaw(t.getClass().getName() + ": " + t.getMessage());
|
||||
t.printStackTrace();
|
||||
} catch (CommandException e) {
|
||||
actor.printError(e.getMessage());
|
||||
} finally {
|
||||
EditSession editSession = locals.get(EditSession.class);
|
||||
|
||||
if (editSession != null) {
|
||||
session.remember(editSession);
|
||||
editSession.flushQueue();
|
||||
|
||||
if (worldEdit.getConfiguration().profile) {
|
||||
if (config.profile) {
|
||||
long time = System.currentTimeMillis() - start;
|
||||
int changed = editSession.getBlockChangeCount();
|
||||
if (time > 0) {
|
||||
double throughput = changed / (time / 1000.0);
|
||||
player.printDebug((time / 1000.0) + "s elapsed (history: "
|
||||
actor.printDebug((time / 1000.0) + "s elapsed (history: "
|
||||
+ changed + " changed; "
|
||||
+ Math.round(throughput) + " blocks/sec).");
|
||||
} else {
|
||||
player.printDebug((time / 1000.0) + "s elapsed.");
|
||||
actor.printDebug((time / 1000.0) + "s elapsed.");
|
||||
}
|
||||
}
|
||||
|
||||
worldEdit.flushBlockBag(player, editSession);
|
||||
worldEdit.flushBlockBag(event.getPlayer(), editSession);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
final Matcher matcher = numberFormatExceptionPattern.matcher(e.getMessage());
|
||||
|
||||
if (matcher.matches()) {
|
||||
player.printError("Number expected; string \"" + matcher.group(1) + "\" given.");
|
||||
} else {
|
||||
player.printError("Number expected; string given.");
|
||||
}
|
||||
} catch (IncompleteRegionException e) {
|
||||
player.printError("Make a region selection first.");
|
||||
} catch (UnknownItemException e) {
|
||||
player.printError("Block name '" + e.getID() + "' was not recognized.");
|
||||
} catch (InvalidItemException e) {
|
||||
player.printError(e.getMessage());
|
||||
} catch (DisallowedItemException e) {
|
||||
player.printError("Block '" + e.getID() + "' not allowed (see WorldEdit configuration).");
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
player.printError("Max blocks changed in an operation reached ("
|
||||
+ e.getBlockLimit() + ").");
|
||||
} catch (MaxBrushRadiusException e) {
|
||||
player.printError("Maximum allowed brush size: " + worldEdit.getConfiguration().maxBrushRadius);
|
||||
} catch (MaxRadiusException e) {
|
||||
player.printError("Maximum allowed size: " + worldEdit.getConfiguration().maxRadius);
|
||||
} catch (UnknownDirectionException e) {
|
||||
player.printError("Unknown direction: " + e.getDirection());
|
||||
} catch (InsufficientArgumentsException e) {
|
||||
player.printError(e.getMessage());
|
||||
} catch (EmptyClipboardException e) {
|
||||
player.printError("Your clipboard is empty. Use //copy first.");
|
||||
} catch (InvalidFilenameException e) {
|
||||
player.printError("Filename '" + e.getFilename() + "' invalid: "
|
||||
+ e.getMessage());
|
||||
} catch (FilenameResolutionException e) {
|
||||
player.printError("File '" + e.getFilename() + "' resolution error: "
|
||||
+ e.getMessage());
|
||||
} catch (InvalidToolBindException e) {
|
||||
player.printError("Can't bind tool to "
|
||||
+ ItemType.toHeldName(e.getItemId()) + ": " + e.getMessage());
|
||||
} catch (FileSelectionAbortedException e) {
|
||||
player.printError("File selection aborted.");
|
||||
} catch (WorldEditException e) {
|
||||
player.printError(e.getMessage());
|
||||
} catch (Throwable excp) {
|
||||
player.printError("Please report this error: [See console]");
|
||||
player.printRaw(excp.getClass().getName() + ": " + excp.getMessage());
|
||||
excp.printStackTrace();
|
||||
}
|
||||
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
private class CommandsManagerImpl extends CommandsManager<LocalPlayer> {
|
||||
@Override
|
||||
protected void checkPermission(LocalPlayer player, Method method) throws CommandException {
|
||||
if (!player.isPlayer() && !method.isAnnotationPresent(Console.class)) {
|
||||
throw new UnhandledCommandException();
|
||||
}
|
||||
|
||||
super.checkPermission(player, method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(LocalPlayer player, String perm) {
|
||||
return player.hasPermission(perm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invokeMethod(Method parent, String[] args,
|
||||
LocalPlayer player, Method method, Object instance,
|
||||
Object[] methodArgs, int level) throws CommandException {
|
||||
if (worldEdit.getConfiguration().logCommands) {
|
||||
final Logging loggingAnnotation = method.getAnnotation(Logging.class);
|
||||
|
||||
final Logging.LogMode logMode;
|
||||
if (loggingAnnotation == null) {
|
||||
logMode = null;
|
||||
} else {
|
||||
logMode = loggingAnnotation.value();
|
||||
}
|
||||
|
||||
String msg = "WorldEdit: " + player.getName();
|
||||
if (player.isPlayer()) {
|
||||
msg += " (in \"" + player.getWorld().getName() + "\")";
|
||||
}
|
||||
msg += ": " + StringUtil.joinString(args, " ");
|
||||
if (logMode != null && player.isPlayer()) {
|
||||
Vector position = player.getPosition();
|
||||
final LocalSession session = worldEdit.getSessionManager().get(player);
|
||||
|
||||
switch (logMode) {
|
||||
case PLACEMENT:
|
||||
try {
|
||||
position = session.getPlacementPosition(player);
|
||||
} catch (IncompleteRegionException e) {
|
||||
break;
|
||||
}
|
||||
/* FALL-THROUGH */
|
||||
|
||||
case POSITION:
|
||||
msg += " - Position: " + position;
|
||||
break;
|
||||
|
||||
case ALL:
|
||||
msg += " - Position: " + position;
|
||||
/* FALL-THROUGH */
|
||||
|
||||
case ORIENTATION_REGION:
|
||||
msg += " - Orientation: " + player.getCardinalDirection().name();
|
||||
/* FALL-THROUGH */
|
||||
|
||||
case REGION:
|
||||
try {
|
||||
msg += " - Region: " + session.getSelection(player.getWorld());
|
||||
} catch (IncompleteRegionException e) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
getLogger().info(msg);
|
||||
}
|
||||
super.invokeMethod(parent, args, player, method, instance, methodArgs, level);
|
||||
}
|
||||
/**
|
||||
* Get the command dispatcher instance.
|
||||
*
|
||||
* @return the command dispatcher
|
||||
*/
|
||||
public Dispatcher getDispatcher() {
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
public static Logger getLogger() {
|
||||
|
@ -19,12 +19,10 @@
|
||||
|
||||
package com.sk89q.worldedit.extension.platform;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandsManager;
|
||||
import com.sk89q.worldedit.BiomeTypes;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.LocalPlayer;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -100,10 +98,12 @@ public interface Platform {
|
||||
*/
|
||||
@Nullable World matchWorld(World world);
|
||||
|
||||
@Deprecated
|
||||
void onCommandRegistration(List<Command> commands);
|
||||
|
||||
void onCommandRegistration(List<Command> commands, CommandsManager<LocalPlayer> manager);
|
||||
/**
|
||||
* Register the commands contained within the given command dispatcher.
|
||||
*
|
||||
* @param dispatcher the dispatcher
|
||||
*/
|
||||
void registerCommands(Dispatcher dispatcher);
|
||||
|
||||
/**
|
||||
* Register game hooks.
|
||||
|
@ -19,16 +19,14 @@
|
||||
|
||||
package com.sk89q.worldedit.internal;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandsManager;
|
||||
import com.sk89q.worldedit.BiomeTypes;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.LocalPlayer;
|
||||
import com.sk89q.worldedit.ServerInterface;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extension.platform.Preference;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -97,14 +95,8 @@ public class ServerInterfaceAdapter extends ServerInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void onCommandRegistration(List<Command> commands) {
|
||||
platform.onCommandRegistration(commands);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommandRegistration(List<Command> commands, CommandsManager<LocalPlayer> manager) {
|
||||
platform.onCommandRegistration(commands, manager);
|
||||
public void registerCommands(Dispatcher dispatcher) {
|
||||
platform.registerCommands(dispatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
39
src/main/java/com/sk89q/worldedit/internal/annotation/Direction.java
Normale Datei
39
src/main/java/com/sk89q/worldedit/internal/annotation/Direction.java
Normale Datei
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package com.sk89q.worldedit.internal.annotation;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotates a {@link Vector} parameter to inject a direction.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface Direction {
|
||||
|
||||
public static final String AIM = "me";
|
||||
|
||||
}
|
34
src/main/java/com/sk89q/worldedit/internal/annotation/Selection.java
Normale Datei
34
src/main/java/com/sk89q/worldedit/internal/annotation/Selection.java
Normale Datei
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that this value should come from the current selection.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface Selection {
|
||||
|
||||
}
|
147
src/main/java/com/sk89q/worldedit/util/CommandLoggingHandler.java
Normale Datei
147
src/main/java/com/sk89q/worldedit/util/CommandLoggingHandler.java
Normale Datei
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.Logging;
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.util.command.parametric.AbstractInvokeListener;
|
||||
import com.sk89q.worldedit.util.command.parametric.InvokeHandler;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterData;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterException;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Logs called commands to a logger.
|
||||
*/
|
||||
public class CommandLoggingHandler extends AbstractInvokeListener implements InvokeHandler, Closeable {
|
||||
|
||||
private final WorldEdit worldEdit;
|
||||
private final Logger logger;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param worldEdit an instance of WorldEdit
|
||||
* @param logger the logger to send messages to
|
||||
*/
|
||||
public CommandLoggingHandler(WorldEdit worldEdit, Logger logger) {
|
||||
checkNotNull(worldEdit);
|
||||
checkNotNull(logger);
|
||||
this.worldEdit = worldEdit;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preProcess(Object object, Method method, ParameterData[] parameters, CommandContext context) throws CommandException, ParameterException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preInvoke(Object object, Method method, ParameterData[] parameters, Object[] args, CommandContext context) throws CommandException {
|
||||
Logging loggingAnnotation = method.getAnnotation(Logging.class);
|
||||
Logging.LogMode logMode;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (loggingAnnotation == null) {
|
||||
logMode = null;
|
||||
} else {
|
||||
logMode = loggingAnnotation.value();
|
||||
}
|
||||
|
||||
LocalPlayer sender = context.getLocals().get(LocalPlayer.class);
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
builder.append("WorldEdit: ").append(sender.getName());
|
||||
if (sender.isPlayer()) {
|
||||
builder.append(" (in \"" + sender.getWorld().getName() + "\")");
|
||||
}
|
||||
|
||||
builder.append(": ").append(context.getCommand());
|
||||
|
||||
if (context.argsLength() > 0) {
|
||||
builder.append(" ").append(context.getJoinedStrings(0));
|
||||
}
|
||||
|
||||
if (logMode != null && sender.isPlayer()) {
|
||||
Vector position = sender.getPosition();
|
||||
LocalSession session = worldEdit.getSession(sender);
|
||||
|
||||
switch (logMode) {
|
||||
case PLACEMENT:
|
||||
try {
|
||||
position = session.getPlacementPosition(sender);
|
||||
} catch (IncompleteRegionException e) {
|
||||
break;
|
||||
}
|
||||
/* FALL-THROUGH */
|
||||
|
||||
case POSITION:
|
||||
builder.append(" - Position: " + position);
|
||||
break;
|
||||
|
||||
case ALL:
|
||||
builder.append(" - Position: " + position);
|
||||
/* FALL-THROUGH */
|
||||
|
||||
case ORIENTATION_REGION:
|
||||
builder.append(" - Orientation: "
|
||||
+ sender.getCardinalDirection().name());
|
||||
/* FALL-THROUGH */
|
||||
|
||||
case REGION:
|
||||
try {
|
||||
builder.append(" - Region: ")
|
||||
.append(session.getSelection(sender.getWorld()));
|
||||
} catch (IncompleteRegionException e) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(builder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInvoke(Object object, Method method, ParameterData[] parameters, Object[] args, CommandContext context) throws CommandException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InvokeHandler createInvokeHandler() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for (Handler h : logger.getHandlers()) {
|
||||
h.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.worldedit.util.command.parametric.PermissionsHandler;
|
||||
import com.sk89q.worldedit.LocalPlayer;
|
||||
|
||||
public class CommandPermissionsHandler extends PermissionsHandler {
|
||||
|
||||
public CommandPermissionsHandler() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasPermission(CommandContext context, String permission) {
|
||||
LocalPlayer sender = context.getLocals().get(LocalPlayer.class);
|
||||
if (sender == null) {
|
||||
return true;
|
||||
} else {
|
||||
return sender.hasPermission(permission);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
198
src/main/java/com/sk89q/worldedit/util/WorldEditBinding.java
Normale Datei
198
src/main/java/com/sk89q/worldedit/util/WorldEditBinding.java
Normale Datei
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util;
|
||||
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.internal.annotation.Direction;
|
||||
import com.sk89q.worldedit.internal.annotation.Selection;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.command.parametric.*;
|
||||
|
||||
/**
|
||||
* Binds standard WorldEdit classes such as {@link Player} and {@link LocalSession}.
|
||||
*/
|
||||
public class WorldEditBinding extends BindingHelper {
|
||||
|
||||
private final WorldEdit worldEdit;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param worldEdit the WorldEdit instance to bind to
|
||||
*/
|
||||
public WorldEditBinding(WorldEdit worldEdit) {
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a selection from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @param selection the annotation
|
||||
* @return a selection
|
||||
* @throws IncompleteRegionException if no selection is available
|
||||
* @throws ParameterException on other error
|
||||
*/
|
||||
@BindingMatch(classifier = Selection.class,
|
||||
type = Region.class,
|
||||
behavior = BindingBehavior.PROVIDES)
|
||||
public Object getSelection(ArgumentStack context, Selection selection) throws IncompleteRegionException, ParameterException {
|
||||
Player sender = getPlayer(context);
|
||||
LocalSession session = worldEdit.getSessionManager().get(sender);
|
||||
return session.getSelection(sender.getWorld());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link EditSession} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return an edit session
|
||||
* @throws ParameterException on other error
|
||||
*/
|
||||
@BindingMatch(type = EditSession.class,
|
||||
behavior = BindingBehavior.PROVIDES)
|
||||
public EditSession getEditSession(ArgumentStack context) throws ParameterException {
|
||||
Player sender = getPlayer(context);
|
||||
LocalSession session = worldEdit.getSessionManager().get(sender);
|
||||
EditSession editSession = session.createEditSession(sender);
|
||||
editSession.enableQueue();
|
||||
context.getContext().getLocals().put(EditSession.class, editSession);
|
||||
session.tellVersion(sender);
|
||||
return editSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link LocalSession} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a local session
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(type = LocalSession.class,
|
||||
behavior = BindingBehavior.PROVIDES)
|
||||
public LocalSession getLocalSession(ArgumentStack context) throws ParameterException {
|
||||
Player sender = getPlayer(context);
|
||||
return worldEdit.getSessionManager().get(sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link Player} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a local player
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(type = Player.class,
|
||||
behavior = BindingBehavior.PROVIDES)
|
||||
public Player getPlayer(ArgumentStack context) throws ParameterException {
|
||||
Actor sender = context.getContext().getLocals().get(Actor.class);
|
||||
if (sender == null) {
|
||||
throw new ParameterException("No player to get a session for");
|
||||
} else if (sender instanceof Player) {
|
||||
return (Player) sender;
|
||||
} else {
|
||||
throw new ParameterException("Caller is not a player");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link Player} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a local player
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@BindingMatch(type = LocalPlayer.class,
|
||||
behavior = BindingBehavior.PROVIDES)
|
||||
public Player getLocalPlayer(ArgumentStack context) throws ParameterException {
|
||||
Player player = getPlayer(context);
|
||||
if (player instanceof LocalPlayer) {
|
||||
return (LocalPlayer) player;
|
||||
} else {
|
||||
throw new ParameterException("This command/function needs to be updated to take 'Player' rather than 'LocalPlayer'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link Pattern} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a pattern
|
||||
* @throws ParameterException on error
|
||||
* @throws WorldEditException on error
|
||||
*/
|
||||
@BindingMatch(type = Pattern.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1)
|
||||
public Pattern getPattern(ArgumentStack context) throws ParameterException, WorldEditException {
|
||||
Actor actor = context.getContext().getLocals().get(Actor.class);
|
||||
ParserContext parserContext = new ParserContext();
|
||||
parserContext.setActor(context.getContext().getLocals().get(Actor.class));
|
||||
parserContext.setWorld(actor.getWorld());
|
||||
parserContext.setSession(worldEdit.getSessionManager().get(actor));
|
||||
return worldEdit.getPatternRegistry().parseFromInput(context.next(), parserContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link Mask} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a pattern
|
||||
* @throws ParameterException on error
|
||||
* @throws WorldEditException on error
|
||||
*/
|
||||
@BindingMatch(type = Mask.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1)
|
||||
public Mask getMask(ArgumentStack context) throws ParameterException, WorldEditException {
|
||||
Actor actor = context.getContext().getLocals().get(Actor.class);
|
||||
ParserContext parserContext = new ParserContext();
|
||||
parserContext.setActor(context.getContext().getLocals().get(Actor.class));
|
||||
parserContext.setWorld(actor.getWorld());
|
||||
parserContext.setSession(worldEdit.getSessionManager().get(actor));
|
||||
return worldEdit.getMaskRegistry().parseFromInput(context.next(), parserContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a direction from the player.
|
||||
*
|
||||
* @param context the context
|
||||
* @param direction the direction annotation
|
||||
* @return a pattern
|
||||
* @throws ParameterException on error
|
||||
* @throws UnknownDirectionException on an unknown direction
|
||||
*/
|
||||
@BindingMatch(classifier = Direction.class,
|
||||
type = Vector.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1)
|
||||
public Vector getDirection(ArgumentStack context, Direction direction)
|
||||
throws ParameterException, UnknownDirectionException {
|
||||
Player sender = getPlayer(context);
|
||||
return worldEdit.getDirection(sender, context.next());
|
||||
}
|
||||
|
||||
}
|
151
src/main/java/com/sk89q/worldedit/util/WorldEditExceptionConverter.java
Normale Datei
151
src/main/java/com/sk89q/worldedit/util/WorldEditExceptionConverter.java
Normale Datei
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.blocks.ItemType;
|
||||
import com.sk89q.worldedit.command.InsufficientArgumentsException;
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
import com.sk89q.worldedit.regions.RegionOperationException;
|
||||
import com.sk89q.worldedit.util.command.parametric.ExceptionConverterHelper;
|
||||
import com.sk89q.worldedit.util.command.parametric.ExceptionMatch;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* converts WorldEdit exceptions and converts them into {@link CommandException}s.
|
||||
*/
|
||||
public class WorldEditExceptionConverter extends ExceptionConverterHelper {
|
||||
|
||||
private static final Pattern numberFormat = Pattern.compile("^For input string: \"(.*)\"$");
|
||||
private final WorldEdit worldEdit;
|
||||
|
||||
public WorldEditExceptionConverter(WorldEdit worldEdit) {
|
||||
checkNotNull(worldEdit);
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(PlayerNeededException e) throws CommandException {
|
||||
throw new CommandException(e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(NumberFormatException e) throws CommandException {
|
||||
final Matcher matcher = numberFormat.matcher(e.getMessage());
|
||||
|
||||
if (matcher.matches()) {
|
||||
throw new CommandException("Number expected; string \"" + matcher.group(1)
|
||||
+ "\" given.");
|
||||
} else {
|
||||
throw new CommandException("Number expected; string given.");
|
||||
}
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(IncompleteRegionException e) throws CommandException {
|
||||
throw new CommandException("Make a region selection first.");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(UnknownItemException e) throws CommandException {
|
||||
throw new CommandException("Block name '" + e.getID() + "' was not recognized.");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(InvalidItemException e) throws CommandException {
|
||||
throw new CommandException(e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(DisallowedItemException e) throws CommandException {
|
||||
throw new CommandException("Block '" + e.getID()
|
||||
+ "' not allowed (see WorldEdit configuration).");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(MaxChangedBlocksException e) throws CommandException {
|
||||
throw new CommandException("Max blocks changed in an operation reached ("
|
||||
+ e.getBlockLimit() + ").");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(MaxRadiusException e) throws CommandException {
|
||||
throw new CommandException("Maximum radius: " + worldEdit.getConfiguration().maxRadius);
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(UnknownDirectionException e) throws CommandException {
|
||||
throw new CommandException("Unknown direction: " + e.getDirection());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(InsufficientArgumentsException e) throws CommandException {
|
||||
throw new CommandException(e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(RegionOperationException e) throws CommandException {
|
||||
throw new CommandException(e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(ExpressionException e) throws CommandException {
|
||||
throw new CommandException(e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(EmptyClipboardException e) throws CommandException {
|
||||
throw new CommandException("Your clipboard is empty. Use //copy first.");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(InvalidFilenameException e) throws CommandException {
|
||||
throw new CommandException("Filename '" + e.getFilename() + "' invalid: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(FilenameResolutionException e) throws CommandException {
|
||||
throw new CommandException(
|
||||
"File '" + e.getFilename() + "' resolution error: " + e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(InvalidToolBindException e) throws CommandException {
|
||||
throw new CommandException("Can't bind tool to "
|
||||
+ ItemType.toHeldName(e.getItemId()) + ": " + e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(FileSelectionAbortedException e) throws CommandException {
|
||||
throw new CommandException("File selection aborted.");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(WorldEditException e) throws CommandException {
|
||||
throw new CommandException(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
64
src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java
Normale Datei
64
src/main/java/com/sk89q/worldedit/util/command/CommandCallable.java
Normale Datei
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A command that can be executed.
|
||||
*/
|
||||
public interface CommandCallable {
|
||||
|
||||
/**
|
||||
* Get a list of value flags used by this command.
|
||||
*
|
||||
* @return a list of value flags
|
||||
*/
|
||||
Set<Character> getValueFlags();
|
||||
|
||||
/**
|
||||
* Execute the command.
|
||||
*
|
||||
* @param context the user input
|
||||
* @throws CommandException thrown on any sort of command exception
|
||||
*/
|
||||
void call(CommandContext context) throws CommandException;
|
||||
|
||||
/**
|
||||
* Get a list of suggestions.
|
||||
*
|
||||
* @param context the user input
|
||||
* @return a list of suggestions
|
||||
* @throws CommandException
|
||||
*/
|
||||
Collection<String> getSuggestions(CommandContext context) throws CommandException;
|
||||
|
||||
/**
|
||||
* Get an object describing this command.
|
||||
*
|
||||
* @return the command description
|
||||
*/
|
||||
Description getDescription();
|
||||
|
||||
}
|
79
src/main/java/com/sk89q/worldedit/util/command/CommandMapping.java
Normale Datei
79
src/main/java/com/sk89q/worldedit/util/command/CommandMapping.java
Normale Datei
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
|
||||
/**
|
||||
* Tracks a command registration.
|
||||
*/
|
||||
public class CommandMapping {
|
||||
|
||||
private final String[] aliases;
|
||||
private final CommandCallable callable;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param callable the command callable
|
||||
* @param alias a list of all aliases, where the first one is the primary one
|
||||
*/
|
||||
public CommandMapping(CommandCallable callable, String... alias) {
|
||||
super();
|
||||
this.aliases = alias;
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the primary alias.
|
||||
*
|
||||
* @return the primary alias
|
||||
*/
|
||||
public String getPrimaryAlias() {
|
||||
return aliases[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all aliases.
|
||||
*
|
||||
* @return aliases
|
||||
*/
|
||||
public String[] getAllAliases() {
|
||||
return aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the callable
|
||||
*
|
||||
* @return the callable
|
||||
*/
|
||||
public CommandCallable getCallable() {
|
||||
return callable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link Description} form the callable.
|
||||
*
|
||||
* @return the description
|
||||
*/
|
||||
public Description getDescription() {
|
||||
return getCallable().getDescription();
|
||||
}
|
||||
|
||||
}
|
70
src/main/java/com/sk89q/worldedit/util/command/Description.java
Normale Datei
70
src/main/java/com/sk89q/worldedit/util/command/Description.java
Normale Datei
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A description of a command.
|
||||
*/
|
||||
public interface Description {
|
||||
|
||||
/**
|
||||
* Get the list of parameters for this command.
|
||||
*
|
||||
* @return a list of parameters
|
||||
*/
|
||||
List<Parameter> getParameters();
|
||||
|
||||
/**
|
||||
* Get a short one-line description of this command.
|
||||
*
|
||||
* @return a description, or null if no description is available
|
||||
*/
|
||||
String getDescription();
|
||||
|
||||
/**
|
||||
* Get a longer help text about this command.
|
||||
*
|
||||
* @return a help text, or null if no help is available
|
||||
*/
|
||||
String getHelp();
|
||||
|
||||
/**
|
||||
* Get the usage string of this command.
|
||||
*
|
||||
* <p>A usage string may look like
|
||||
* <code>[-w <world>] <var1> <var2></code>.</p>
|
||||
*
|
||||
* @return a usage string
|
||||
*/
|
||||
String getUsage();
|
||||
|
||||
/**
|
||||
* Get a list of permissions that the player may have to have permission.
|
||||
*
|
||||
* <p>Permission data may or may not be available. This is only useful as a
|
||||
* potential hint.</p>
|
||||
*
|
||||
* @return the list of permissions
|
||||
*/
|
||||
List<String> getPermissions();
|
||||
|
||||
}
|
113
src/main/java/com/sk89q/worldedit/util/command/Dispatcher.java
Normale Datei
113
src/main/java/com/sk89q/worldedit/util/command/Dispatcher.java
Normale Datei
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.CommandLocals;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Executes a command based on user input.
|
||||
*/
|
||||
public interface Dispatcher {
|
||||
|
||||
/**
|
||||
* Register a command with this dispatcher.
|
||||
*
|
||||
* @param callable the command executor
|
||||
* @param alias a list of aliases, where the first alias is the primary name
|
||||
*/
|
||||
void register(CommandCallable callable, String... alias);
|
||||
|
||||
/**
|
||||
* Get a list of command registrations.
|
||||
*
|
||||
* <p>The returned collection cannot be modified.</p>
|
||||
*
|
||||
* @return a list of registrations
|
||||
*/
|
||||
Collection<CommandMapping> getCommands();
|
||||
|
||||
/**
|
||||
* Get a list of primary aliases.
|
||||
*
|
||||
* <p>The returned collection cannot be modified.</p>
|
||||
*
|
||||
* @return a list of aliases
|
||||
*/
|
||||
Collection<String> getPrimaryAliases();
|
||||
|
||||
/**
|
||||
* Get a list of all the command aliases.
|
||||
*
|
||||
* <p>A command may have more than one alias assigned to it. The returned
|
||||
* collection cannot be modified.</p>
|
||||
*
|
||||
* @return a list of aliases
|
||||
*/
|
||||
Collection<String> getAllAliases();
|
||||
|
||||
/**
|
||||
* Get the {@link CommandCallable} associated with an alias.
|
||||
*
|
||||
* @param alias the alias
|
||||
* @return the command mapping
|
||||
*/
|
||||
CommandMapping get(String alias);
|
||||
|
||||
/**
|
||||
* Returns whether the dispatcher contains a registered command for the given alias.
|
||||
*
|
||||
* @param alias the alias
|
||||
* @return true if a registered command exists
|
||||
*/
|
||||
boolean contains(String alias);
|
||||
|
||||
/**
|
||||
* Execute the correct command based on the input.
|
||||
*
|
||||
* @param arguments the arguments
|
||||
* @param locals the locals
|
||||
* @return the called command, or null if there was no command found
|
||||
* @throws CommandException thrown on a command error
|
||||
*/
|
||||
CommandMapping call(String arguments, CommandLocals locals) throws CommandException;
|
||||
|
||||
/**
|
||||
* Execute the correct command based on the input.
|
||||
*
|
||||
* @param arguments the arguments
|
||||
* @param locals the locals
|
||||
* @return the called command, or null if there was no command found
|
||||
* @throws CommandException thrown on a command error
|
||||
*/
|
||||
CommandMapping call(String[] arguments, CommandLocals locals) throws CommandException;
|
||||
|
||||
/**
|
||||
* Get a list of suggestions based on input.
|
||||
*
|
||||
* @param arguments the arguments entered up to this point
|
||||
* @return a list of suggestions
|
||||
* @throws CommandException thrown if there was a parsing error
|
||||
*/
|
||||
Collection<String> getSuggestions(String arguments) throws CommandException;
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
|
||||
/**
|
||||
* Thrown when a command is not used properly.
|
||||
*/
|
||||
public class InvalidUsageException extends CommandException {
|
||||
|
||||
private static final long serialVersionUID = -3222004168669490390L;
|
||||
private final Description description;
|
||||
|
||||
public InvalidUsageException(Description description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public InvalidUsageException(String message, Description description) {
|
||||
super(message);
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Description getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getUsage(String prefix) {
|
||||
return toStackString(prefix, getDescription().getUsage());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterException;
|
||||
|
||||
/**
|
||||
* Thrown when there is a missing parameter.
|
||||
*/
|
||||
public class MissingParameterException extends ParameterException {
|
||||
|
||||
private static final long serialVersionUID = 2169299987926950535L;
|
||||
|
||||
}
|
66
src/main/java/com/sk89q/worldedit/util/command/Parameter.java
Normale Datei
66
src/main/java/com/sk89q/worldedit/util/command/Parameter.java
Normale Datei
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
/**
|
||||
* Describes a parameter.
|
||||
*
|
||||
* @see Description
|
||||
*/
|
||||
public interface Parameter {
|
||||
|
||||
/**
|
||||
* The name of the parameter.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Get the flag associated with this parameter.
|
||||
*
|
||||
* @return the flag, or null if there is no flag associated
|
||||
* @see #isValueFlag()
|
||||
*/
|
||||
Character getFlag();
|
||||
|
||||
/**
|
||||
* Return whether the flag is a value flag.
|
||||
*
|
||||
* @return true if the flag is a value flag
|
||||
* @see #getFlag()
|
||||
*/
|
||||
boolean isValueFlag();
|
||||
|
||||
/**
|
||||
* Get whether this parameter is optional.
|
||||
*
|
||||
* @return true if the parameter does not have to be specified
|
||||
*/
|
||||
boolean isOptional();
|
||||
|
||||
/**
|
||||
* Get the default value as a string to be parsed by the binding.
|
||||
*
|
||||
* @return a default value, or null if none is set
|
||||
*/
|
||||
public String[] getDefaultValue();
|
||||
|
||||
}
|
129
src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java
Normale Datei
129
src/main/java/com/sk89q/worldedit/util/command/SimpleDescription.java
Normale Datei
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A simple implementation of {@link Description} which has setters.
|
||||
*/
|
||||
public class SimpleDescription implements Description {
|
||||
|
||||
private List<Parameter> parameters = Collections.emptyList();
|
||||
private List<String> permissions = Collections.emptyList();
|
||||
private String description;
|
||||
private String help;
|
||||
private String overrideUsage;
|
||||
|
||||
@Override
|
||||
public List<Parameter> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of parameters.
|
||||
*
|
||||
* @param parameters the list of parameters
|
||||
* @see #getParameters()
|
||||
*/
|
||||
public void setParameters(List<Parameter> parameters) {
|
||||
this.parameters = Collections.unmodifiableList(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the description of the command.
|
||||
*
|
||||
* @param description the description
|
||||
* @see #getDescription()
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelp() {
|
||||
return help;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the help text of the command.
|
||||
*
|
||||
* @param help the help text
|
||||
* @see #getHelp()
|
||||
*/
|
||||
public void setHelp(String help) {
|
||||
this.help = help;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPermissions() {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the permissions of this command.
|
||||
*
|
||||
* @param permissions the permissions
|
||||
*/
|
||||
public void setPermissions(List<String> permissions) {
|
||||
this.permissions = Collections.unmodifiableList(permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the usage string returned with a given one.
|
||||
*
|
||||
* @param usage usage string, or null
|
||||
*/
|
||||
public void overrideUsage(String usage) {
|
||||
this.overrideUsage = usage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage() {
|
||||
if (overrideUsage != null) {
|
||||
return overrideUsage;
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
boolean first = true;
|
||||
|
||||
for (Parameter parameter : parameters) {
|
||||
if (!first) {
|
||||
builder.append(" ");
|
||||
}
|
||||
builder.append(parameter.toString());
|
||||
first = false;
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getUsage();
|
||||
}
|
||||
|
||||
}
|
122
src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java
Normale Datei
122
src/main/java/com/sk89q/worldedit/util/command/SimpleDispatcher.java
Normale Datei
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.CommandLocals;
|
||||
import com.sk89q.minecraft.util.commands.WrappedCommandException;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A simple implementation of {@link Dispatcher}.
|
||||
*/
|
||||
public class SimpleDispatcher implements Dispatcher {
|
||||
|
||||
private final Map<String, CommandMapping> commands = new HashMap<String, CommandMapping>();
|
||||
|
||||
@Override
|
||||
public void register(CommandCallable callable, String... alias) {
|
||||
CommandMapping mapping = new CommandMapping(callable, alias);
|
||||
|
||||
// Check for replacements
|
||||
for (String a : alias) {
|
||||
String lower = a.toLowerCase();
|
||||
if (commands.containsKey(lower)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Replacing commands is currently undefined behavior");
|
||||
}
|
||||
}
|
||||
|
||||
for (String a : alias) {
|
||||
String lower = a.toLowerCase();
|
||||
commands.put(lower, mapping);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CommandMapping> getCommands() {
|
||||
return Collections.unmodifiableCollection(commands.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAllAliases() {
|
||||
return Collections.unmodifiableSet(commands.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getPrimaryAliases() {
|
||||
Set<String> aliases = new HashSet<String>();
|
||||
for (CommandMapping mapping : getCommands()) {
|
||||
aliases.add(mapping.getPrimaryAlias());
|
||||
}
|
||||
return Collections.unmodifiableSet(aliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(String alias) {
|
||||
return commands.containsKey(alias.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandMapping get(String alias) {
|
||||
return commands.get(alias.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandMapping call(String arguments, CommandLocals locals) throws CommandException {
|
||||
return call(CommandContext.split(arguments), locals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandMapping call(String[] arguments, CommandLocals locals) throws CommandException {
|
||||
CommandContext dummyContext = new CommandContext(arguments);
|
||||
CommandMapping mapping = get(dummyContext.getCommand());
|
||||
if (mapping != null) {
|
||||
CommandCallable c = mapping.getCallable();
|
||||
CommandContext context =
|
||||
new CommandContext(arguments, c.getValueFlags(), false, locals);
|
||||
try {
|
||||
c.call(context);
|
||||
} catch (CommandException e) {
|
||||
e.prependStack(context.getCommand());
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
throw new WrappedCommandException(t);
|
||||
}
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getSuggestions(String arguments) throws CommandException {
|
||||
CommandContext dummyContext = new CommandContext(arguments);
|
||||
CommandMapping mapping = get(dummyContext.getCommand());
|
||||
if (mapping != null) {
|
||||
CommandCallable c = mapping.getCallable();
|
||||
CommandContext context =
|
||||
new CommandContext(arguments, c.getValueFlags(), true);
|
||||
return c.getSuggestions(context);
|
||||
}
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A combination {@link Dispatcher} and {@link CommandCallable} that is backed by
|
||||
* a {@link SimpleDispatcher}.
|
||||
*
|
||||
* <p>The primary use of this is to make nested commands.</p>
|
||||
*/
|
||||
public class SimpleDispatcherCommand extends SimpleDispatcher implements CommandCallable {
|
||||
|
||||
private final SimpleDescription description = new SimpleDescription();
|
||||
|
||||
@Override
|
||||
public Set<Character> getValueFlags() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(CommandContext context) throws CommandException {
|
||||
if (context.argsLength() >= 1) {
|
||||
super.call(context.getRemainingString(0), context.getLocals());
|
||||
} else {
|
||||
Set<String> aliases = getPrimaryAliases();
|
||||
|
||||
if (aliases.size() == 0) {
|
||||
throw new InvalidUsageException(
|
||||
"This command is supposed to have sub-commands, " +
|
||||
"but it has no sub-commands.",
|
||||
getDescription());
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String alias : getPrimaryAliases()) {
|
||||
builder.append("\n- ").append(alias);
|
||||
}
|
||||
|
||||
if (aliases.size() == 1) {
|
||||
builder.append(" (there is only one)");
|
||||
}
|
||||
|
||||
throw new InvalidUsageException(
|
||||
"Select one of these subcommand(s):" + builder.toString(),
|
||||
getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleDescription getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getSuggestions(CommandContext context) throws CommandException {
|
||||
if (context.argsLength() == 0) {
|
||||
return super.getAllAliases();
|
||||
} else if (context.argsLength() == 1 &&
|
||||
context.getSuggestionContext().forLastValue()) {
|
||||
String prefix = context.getString(0).toLowerCase();
|
||||
List<String> suggestions = new ArrayList<String>();
|
||||
for (String alias : super.getAllAliases()) {
|
||||
if (alias.startsWith(prefix)) {
|
||||
suggestions.add(alias);
|
||||
}
|
||||
}
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
return super.getSuggestions(
|
||||
context.argsLength() > 1 ? context.getRemainingString(1) : "");
|
||||
}
|
||||
|
||||
}
|
131
src/main/java/com/sk89q/worldedit/util/command/SimpleParameter.java
Normale Datei
131
src/main/java/com/sk89q/worldedit/util/command/SimpleParameter.java
Normale Datei
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
/**
|
||||
* A simple implementation of {@link Parameter} that has setters.
|
||||
*/
|
||||
public class SimpleParameter implements Parameter {
|
||||
|
||||
private String name;
|
||||
private Character flag;
|
||||
private boolean isValue;
|
||||
private boolean isOptional;
|
||||
private String[] defaultValue;
|
||||
|
||||
/**
|
||||
* Create a new parameter with no name defined yet.
|
||||
*/
|
||||
public SimpleParameter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new parameter of the given name.
|
||||
*
|
||||
* @param name the name
|
||||
*/
|
||||
public SimpleParameter(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the parameter.
|
||||
*
|
||||
* @param name the parameter name
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Character getFlag() {
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueFlag() {
|
||||
return flag != null && isValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag used by this parameter.
|
||||
*
|
||||
* @param flag the flag, or null if there is no flag
|
||||
* @param isValue true if the flag is a value flag
|
||||
*/
|
||||
public void setFlag(Character flag, boolean isValue) {
|
||||
this.flag = flag;
|
||||
this.isValue = isValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOptional() {
|
||||
return isOptional || getFlag() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this parameter is optional.
|
||||
*
|
||||
* @param isOptional true if this parameter is optional
|
||||
*/
|
||||
public void setOptional(boolean isOptional) {
|
||||
this.isOptional = isOptional;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default value.
|
||||
*
|
||||
* @param defaultValue a default value, or null if none
|
||||
*/
|
||||
public void setDefaultValue(String[] defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (getFlag() != null) {
|
||||
if (isValueFlag()) {
|
||||
builder.append("[-")
|
||||
.append(getFlag()).append(" <").append(getName()).append(">]");
|
||||
} else {
|
||||
builder.append("[-").append(getFlag()).append("]");
|
||||
}
|
||||
} else {
|
||||
if (isOptional()) {
|
||||
builder.append("[<").append(getName()).append(">]");
|
||||
} else {
|
||||
builder.append("<").append(getName()).append(">");
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command;
|
||||
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterException;
|
||||
|
||||
/**
|
||||
* Thrown when there are leftover parameters that were not consumed, particular in the
|
||||
* case of the user providing too many parameters.
|
||||
*/
|
||||
public class UnconsumedParameterException extends ParameterException {
|
||||
|
||||
private static final long serialVersionUID = 4449104854894946023L;
|
||||
|
||||
private String unconsumed;
|
||||
|
||||
public UnconsumedParameterException(String unconsumed) {
|
||||
this.unconsumed = unconsumed;
|
||||
}
|
||||
|
||||
public String getUnconsumed() {
|
||||
return unconsumed;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.binding;
|
||||
|
||||
import com.sk89q.worldedit.util.command.parametric.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
* Handles basic Java types such as {@link String}s, {@link Byte}s, etc.
|
||||
*
|
||||
* <p>Handles both the object and primitive types.</p>
|
||||
*/
|
||||
public final class PrimitiveBindings extends BindingHelper {
|
||||
|
||||
/**
|
||||
* Gets a type from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @param text the text annotation
|
||||
* @param modifiers a list of modifiers
|
||||
* @return the requested type
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(classifier = Text.class,
|
||||
type = String.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = -1,
|
||||
provideModifiers = true)
|
||||
public String getText(ArgumentStack context, Text text, Annotation[] modifiers)
|
||||
throws ParameterException {
|
||||
String v = context.remaining();
|
||||
validate(v, modifiers);
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a type from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @param modifiers a list of modifiers
|
||||
* @return the requested type
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(type = String.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1,
|
||||
provideModifiers = true)
|
||||
public String getString(ArgumentStack context, Annotation[] modifiers)
|
||||
throws ParameterException {
|
||||
String v = context.next();
|
||||
validate(v, modifiers);
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a type from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return the requested type
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(type = { Boolean.class, boolean.class },
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1)
|
||||
public Boolean getBoolean(ArgumentStack context) throws ParameterException {
|
||||
return context.nextBoolean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a type from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @param modifiers a list of modifiers
|
||||
* @return the requested type
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(type = { Integer.class, int.class },
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1,
|
||||
provideModifiers = true)
|
||||
public Integer getInteger(ArgumentStack context, Annotation[] modifiers)
|
||||
throws ParameterException {
|
||||
Integer v = context.nextInt();
|
||||
if (v != null) {
|
||||
validate(v, modifiers);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a type from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @param modifiers a list of modifiers
|
||||
* @return the requested type
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(type = { Short.class, short.class },
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1,
|
||||
provideModifiers = true)
|
||||
public Short getShort(ArgumentStack context, Annotation[] modifiers)
|
||||
throws ParameterException {
|
||||
Integer v = getInteger(context, modifiers);
|
||||
if (v != null) {
|
||||
return v.shortValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a type from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @param modifiers a list of modifiers
|
||||
* @return the requested type
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(type = { Double.class, double.class },
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1,
|
||||
provideModifiers = true)
|
||||
public Double getDouble(ArgumentStack context, Annotation[] modifiers)
|
||||
throws ParameterException {
|
||||
Double v = context.nextDouble();
|
||||
if (v != null) {
|
||||
validate(v, modifiers);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a type from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @param modifiers a list of modifiers
|
||||
* @return the requested type
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(type = { Float.class, float.class },
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1,
|
||||
provideModifiers = true)
|
||||
public Float getFloat(ArgumentStack context, Annotation[] modifiers)
|
||||
throws ParameterException {
|
||||
Double v = getDouble(context, modifiers);
|
||||
if (v != null) {
|
||||
return v.floatValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a number value using relevant modifiers.
|
||||
*
|
||||
* @param number the number
|
||||
* @param modifiers the list of modifiers to scan
|
||||
* @throws ParameterException on a validation error
|
||||
*/
|
||||
private static void validate(double number, Annotation[] modifiers)
|
||||
throws ParameterException {
|
||||
for (Annotation modifier : modifiers) {
|
||||
if (modifier instanceof Range) {
|
||||
Range range = (Range) modifier;
|
||||
if (number < range.min()) {
|
||||
throw new ParameterException(
|
||||
String.format(
|
||||
"A valid value is greater than or equal to %s " +
|
||||
"(you entered %s)", range.min(), number));
|
||||
} else if (number > range.max()) {
|
||||
throw new ParameterException(
|
||||
String.format(
|
||||
"A valid value is less than or equal to %s " +
|
||||
"(you entered %s)", range.max(), number));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a number value using relevant modifiers.
|
||||
*
|
||||
* @param number the number
|
||||
* @param modifiers the list of modifiers to scan
|
||||
* @throws ParameterException on a validation error
|
||||
*/
|
||||
private static void validate(int number, Annotation[] modifiers)
|
||||
throws ParameterException {
|
||||
for (Annotation modifier : modifiers) {
|
||||
if (modifier instanceof Range) {
|
||||
Range range = (Range) modifier;
|
||||
if (number < range.min()) {
|
||||
throw new ParameterException(
|
||||
String.format(
|
||||
"A valid value is greater than or equal to %s " +
|
||||
"(you entered %s)", range.min(), number));
|
||||
} else if (number > range.max()) {
|
||||
throw new ParameterException(
|
||||
String.format(
|
||||
"A valid value is less than or equal to %s " +
|
||||
"(you entered %s)", range.max(), number));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a string value using relevant modifiers.
|
||||
*
|
||||
* @param string the string
|
||||
* @param modifiers the list of modifiers to scan
|
||||
* @throws ParameterException on a validation error
|
||||
*/
|
||||
private static void validate(String string, Annotation[] modifiers)
|
||||
throws ParameterException {
|
||||
if (string == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Annotation modifier : modifiers) {
|
||||
if (modifier instanceof Validate) {
|
||||
Validate validate = (Validate) modifier;
|
||||
|
||||
if (!validate.regex().isEmpty()) {
|
||||
if (!string.matches(validate.regex())) {
|
||||
throw new ParameterException(
|
||||
String.format(
|
||||
"The given text doesn't match the right " +
|
||||
"format (technically speaking, the 'format' is %s)",
|
||||
validate.regex()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
50
src/main/java/com/sk89q/worldedit/util/command/binding/Range.java
Normale Datei
50
src/main/java/com/sk89q/worldedit/util/command/binding/Range.java
Normale Datei
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.binding;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Specifies a range of values for numbers.
|
||||
*
|
||||
* @see PrimitiveBindings a user of this annotation as a modifier
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface Range {
|
||||
|
||||
/**
|
||||
* The minimum value that the number can be at, inclusive.
|
||||
*
|
||||
* @return the minimum value
|
||||
*/
|
||||
double min() default Double.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* The maximum value that the number can be at, inclusive.
|
||||
*
|
||||
* @return the maximum value
|
||||
*/
|
||||
double max() default Double.MAX_VALUE;
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.binding;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
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.ArgumentStack;
|
||||
|
||||
/**
|
||||
* Standard bindings that should be available to most configurations.
|
||||
*/
|
||||
public final class StandardBindings extends BindingHelper {
|
||||
|
||||
/**
|
||||
* Gets a {@link CommandContext} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a selection
|
||||
*/
|
||||
@BindingMatch(type = CommandContext.class,
|
||||
behavior = BindingBehavior.PROVIDES)
|
||||
public CommandContext getCommandContext(ArgumentStack context) {
|
||||
context.markConsumed(); // Consume entire stack
|
||||
return context.getContext();
|
||||
}
|
||||
|
||||
}
|
44
src/main/java/com/sk89q/worldedit/util/command/binding/Switch.java
Normale Datei
44
src/main/java/com/sk89q/worldedit/util/command/binding/Switch.java
Normale Datei
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.binding;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates a command flag, such as <code>/command -f</code>.
|
||||
*
|
||||
* <p>If used on a boolean type, then the flag will be a non-value flag. If
|
||||
* used on any other type, then the flag will be a value flag.</p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface Switch {
|
||||
|
||||
/**
|
||||
* The flag character.
|
||||
*
|
||||
* @return the flag character (A-Z a-z 0-9 is acceptable)
|
||||
*/
|
||||
char value();
|
||||
|
||||
}
|
41
src/main/java/com/sk89q/worldedit/util/command/binding/Text.java
Normale Datei
41
src/main/java/com/sk89q/worldedit/util/command/binding/Text.java
Normale Datei
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.binding;
|
||||
|
||||
import com.sk89q.worldedit.util.command.parametric.ArgumentStack;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates a {@link String} parameter will call {@link ArgumentStack#remaining()} and
|
||||
* therefore consume all remaining arguments.
|
||||
*
|
||||
* <p>This should only be used at the end of a list of parameters (of parameters that
|
||||
* need to consume from the stack of arguments), otherwise following parameters will
|
||||
* have no values left to consume.</p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface Text {
|
||||
|
||||
}
|
45
src/main/java/com/sk89q/worldedit/util/command/binding/Validate.java
Normale Datei
45
src/main/java/com/sk89q/worldedit/util/command/binding/Validate.java
Normale Datei
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.binding;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Used to validate a string.
|
||||
*
|
||||
* @see PrimitiveBindings where this validation is used
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface Validate {
|
||||
|
||||
/**
|
||||
* An optional regular expression that must match the string.
|
||||
*
|
||||
* @see Pattern regular expression class
|
||||
* @return the pattern
|
||||
*/
|
||||
String regex() default "";
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.fluent;
|
||||
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import com.sk89q.worldedit.util.command.SimpleDispatcher;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
|
||||
|
||||
/**
|
||||
* A fluent interface to creating a command graph.
|
||||
*
|
||||
* <p>A command graph may have multiple commands, and multiple sub-commands below that,
|
||||
* and possibly below that.</p>
|
||||
*/
|
||||
public class CommandGraph {
|
||||
|
||||
private final DispatcherNode rootDispatcher;
|
||||
private ParametricBuilder builder;
|
||||
|
||||
/**
|
||||
* Create a new command graph.
|
||||
*/
|
||||
public CommandGraph() {
|
||||
SimpleDispatcher dispatcher = new SimpleDispatcher();
|
||||
rootDispatcher = new DispatcherNode(this, null, dispatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root dispatcher node.
|
||||
*
|
||||
* @return the root dispatcher node
|
||||
*/
|
||||
public DispatcherNode commands() {
|
||||
return rootDispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ParametricBuilder}.
|
||||
*
|
||||
* @return the builder, or null.
|
||||
*/
|
||||
public ParametricBuilder getBuilder() {
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ParametricBuilder} used for calls to
|
||||
* {@link DispatcherNode#build(Object)}.
|
||||
*
|
||||
* @param builder the builder, or null
|
||||
* @return this object
|
||||
*/
|
||||
public CommandGraph builder(ParametricBuilder builder) {
|
||||
this.builder = builder;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root dispatcher.
|
||||
*
|
||||
* @return the root dispatcher
|
||||
*/
|
||||
public Dispatcher getDispatcher() {
|
||||
return rootDispatcher.getDispatcher();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.fluent;
|
||||
|
||||
import com.sk89q.worldedit.util.command.CommandCallable;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import com.sk89q.worldedit.util.command.SimpleDispatcher;
|
||||
import com.sk89q.worldedit.util.command.SimpleDispatcherCommand;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
|
||||
|
||||
/**
|
||||
* A collection of commands.
|
||||
*/
|
||||
public class DispatcherNode {
|
||||
|
||||
private final CommandGraph graph;
|
||||
private final DispatcherNode parent;
|
||||
private final SimpleDispatcher dispatcher;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param graph the root fluent graph object
|
||||
* @param parent the parent node, or null
|
||||
* @param dispatcher the dispatcher for this node
|
||||
*/
|
||||
DispatcherNode(CommandGraph graph, DispatcherNode parent,
|
||||
SimpleDispatcher dispatcher) {
|
||||
this.graph = graph;
|
||||
this.parent = parent;
|
||||
this.dispatcher = dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the description.
|
||||
*
|
||||
* <p>This can only be used on {@link DispatcherNode}s returned by
|
||||
* {@link #group(String...)}.</p>
|
||||
*
|
||||
* @param description the description
|
||||
* @return this object
|
||||
*/
|
||||
public DispatcherNode describe(String description) {
|
||||
if (dispatcher instanceof SimpleDispatcherCommand) {
|
||||
((SimpleDispatcherCommand) dispatcher).getDescription()
|
||||
.setDescription(description);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a command with this dispatcher.
|
||||
*
|
||||
* @param callable the executor
|
||||
* @param alias the list of aliases, where the first alias is the primary one
|
||||
*/
|
||||
public void register(CommandCallable callable, String... alias) {
|
||||
dispatcher.register(callable, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and register a command with this dispatcher using the
|
||||
* {@link ParametricBuilder} assigned on the root {@link CommandGraph}.
|
||||
*
|
||||
* @param object the object provided to the {@link ParametricBuilder}
|
||||
* @return this object
|
||||
* @see ParametricBuilder#register(com.sk89q.worldedit.util.command.Dispatcher, Object)
|
||||
*/
|
||||
public DispatcherNode build(Object object) {
|
||||
ParametricBuilder builder = graph.getBuilder();
|
||||
if (builder == null) {
|
||||
throw new RuntimeException("No ParametricBuilder set");
|
||||
}
|
||||
builder.register(getDispatcher(), object);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new command that will contain sub-commands.
|
||||
*
|
||||
* <p>The object returned by this method can be used to add sub-commands. To
|
||||
* return to this "parent" context, use {@link DispatcherNode#graph()}.</p>
|
||||
*
|
||||
* @param alias the list of aliases, where the first alias is the primary one
|
||||
* @return an object to place sub-commands
|
||||
*/
|
||||
public DispatcherNode group(String... alias) {
|
||||
SimpleDispatcherCommand command = new SimpleDispatcherCommand();
|
||||
getDispatcher().register(command, alias);
|
||||
return new DispatcherNode(graph, this, command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent node.
|
||||
*
|
||||
* @return the parent node
|
||||
* @throws RuntimeException if there is no parent node.
|
||||
*/
|
||||
public DispatcherNode parent() {
|
||||
if (parent != null) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
throw new RuntimeException("This node does not have a parent");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root command graph.
|
||||
*
|
||||
* @return the root command graph
|
||||
*/
|
||||
public CommandGraph graph() {
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying dispatcher of this object.
|
||||
*
|
||||
* @return the dispatcher
|
||||
*/
|
||||
public Dispatcher getDispatcher() {
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.worldedit.util.command.SimpleDescription;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* An abstract listener.
|
||||
*/
|
||||
public abstract class AbstractInvokeListener implements InvokeListener {
|
||||
|
||||
@Override
|
||||
public void updateDescription(Object object, Method method,
|
||||
ParameterData[] parameters, SimpleDescription description) {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
|
||||
public interface ArgumentStack {
|
||||
|
||||
/**
|
||||
* Get the next string, which may come from the stack or a value flag.
|
||||
*
|
||||
* @return the value
|
||||
* @throws ParameterException on a parameter error
|
||||
*/
|
||||
String next() throws ParameterException;
|
||||
|
||||
/**
|
||||
* Get the next integer, which may come from the stack or a value flag.
|
||||
*
|
||||
* @return the value
|
||||
* @throws ParameterException on a parameter error
|
||||
*/
|
||||
Integer nextInt() throws ParameterException;
|
||||
|
||||
/**
|
||||
* Get the next double, which may come from the stack or a value flag.
|
||||
*
|
||||
* @return the value
|
||||
* @throws ParameterException on a parameter error
|
||||
*/
|
||||
Double nextDouble() throws ParameterException;
|
||||
|
||||
/**
|
||||
* Get the next boolean, which may come from the stack or a value flag.
|
||||
*
|
||||
* @return the value
|
||||
* @throws ParameterException on a parameter error
|
||||
*/
|
||||
Boolean nextBoolean() throws ParameterException;
|
||||
|
||||
/**
|
||||
* Get all remaining string values, which will consume the rest of the stack.
|
||||
*
|
||||
* @return the value
|
||||
* @throws ParameterException on a parameter error
|
||||
*/
|
||||
String remaining() throws ParameterException;
|
||||
|
||||
/**
|
||||
* Set as completely consumed.
|
||||
*/
|
||||
void markConsumed();
|
||||
|
||||
/**
|
||||
* Get the underlying context.
|
||||
*
|
||||
* @return the context
|
||||
*/
|
||||
CommandContext getContext();
|
||||
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.worldedit.util.command.binding.PrimitiveBindings;
|
||||
import com.sk89q.worldedit.util.command.binding.StandardBindings;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Used to parse user input for a command, based on available method types
|
||||
* and annotations.
|
||||
*
|
||||
* <p>A binding can be used to handle several types at once. For a binding to be
|
||||
* called, it must be registered with a {@link ParametricBuilder} with
|
||||
* {@link ParametricBuilder#addBinding(Binding, java.lang.reflect.Type...)}.</p>
|
||||
*
|
||||
* @see PrimitiveBindings an example of primitive bindings
|
||||
* @see StandardBindings standard bindings
|
||||
*/
|
||||
public interface Binding {
|
||||
|
||||
/**
|
||||
* Get the types that this binding handles.
|
||||
*
|
||||
* @return the types
|
||||
*/
|
||||
Type[] getTypes();
|
||||
|
||||
/**
|
||||
* Get how this binding consumes from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param parameter information about the parameter
|
||||
* @return the behavior
|
||||
*/
|
||||
BindingBehavior getBehavior(ParameterData parameter);
|
||||
|
||||
/**
|
||||
* Get the number of arguments that this binding will consume, if this
|
||||
* information is available.
|
||||
*
|
||||
* <p>This method must return -1 for binding behavior types that are not
|
||||
* {@link BindingBehavior#CONSUMES}.</p>
|
||||
*
|
||||
* @param parameter information about the parameter
|
||||
* @return the number of consumed arguments, or -1 if unknown or irrelevant
|
||||
*/
|
||||
int getConsumedCount(ParameterData parameter);
|
||||
|
||||
/**
|
||||
* Attempt to consume values (if required) from the given {@link ArgumentStack}
|
||||
* in order to instantiate an object for the given parameter.
|
||||
*
|
||||
* @param parameter information about the parameter
|
||||
* @param scoped the arguments the user has input
|
||||
* @param onlyConsume true to only consume arguments
|
||||
* @return an object parsed for the given parameter
|
||||
* @throws ParameterException thrown if the parameter could not be formulated
|
||||
* @throws CommandException on a command exception
|
||||
*/
|
||||
Object bind(ParameterData parameter, ArgumentStack scoped, boolean onlyConsume)
|
||||
throws ParameterException, CommandException;
|
||||
|
||||
/**
|
||||
* Get a list of suggestions for the given parameter and user arguments.
|
||||
*
|
||||
* @param parameter information about the parameter
|
||||
* @param prefix what the user has typed so far (may be an empty string)
|
||||
* @return a list of suggestions
|
||||
*/
|
||||
List<String> getSuggestions(ParameterData parameter, String prefix);
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandLocals;
|
||||
import com.sk89q.worldedit.util.command.binding.Switch;
|
||||
|
||||
/**
|
||||
* Determines the type of binding.
|
||||
*/
|
||||
public enum BindingBehavior {
|
||||
|
||||
/**
|
||||
* Always consumes from a {@link ArgumentStack}.
|
||||
*/
|
||||
CONSUMES,
|
||||
|
||||
/**
|
||||
* Sometimes consumes from a {@link ArgumentStack}.
|
||||
*
|
||||
* <p>Bindings that exhibit this behavior must be defined as a {@link Switch}
|
||||
* by commands utilizing the given binding.</p>
|
||||
*/
|
||||
INDETERMINATE,
|
||||
|
||||
/**
|
||||
* Never consumes from a {@link ArgumentStack}.
|
||||
*
|
||||
* <p>Bindings that exhibit this behavior generate objects from other sources,
|
||||
* such as from a {@link CommandLocals}. These are "magic" bindings that inject
|
||||
* variables.</p>
|
||||
*/
|
||||
PROVIDES;
|
||||
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A binding helper that uses the {@link BindingMatch} annotation to make
|
||||
* writing bindings extremely easy.
|
||||
*
|
||||
* <p>Methods must have the following and only the following parameters:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>A {@link ArgumentStack}</li>
|
||||
* <li>A {@link Annotation} <strong>if there is a classifier set</strong></li>
|
||||
* <li>A {@link Annotation}[]
|
||||
* <strong>if there {@link BindingMatch#provideModifiers()} is true</strong></li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Methods may throw any exception. Exceptions may be converted using a
|
||||
* {@link ExceptionConverter} registered with the {@link ParametricBuilder}.</p>
|
||||
*/
|
||||
public class BindingHelper implements Binding {
|
||||
|
||||
private final List<BoundMethod> bindings;
|
||||
private final Type[] types;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*/
|
||||
public BindingHelper() {
|
||||
List<BoundMethod> bindings = new ArrayList<BoundMethod>();
|
||||
List<Type> types = new ArrayList<Type>();
|
||||
|
||||
for (Method method : this.getClass().getMethods()) {
|
||||
BindingMatch info = method.getAnnotation(BindingMatch.class);
|
||||
if (info != null) {
|
||||
Class<? extends Annotation> classifier = null;
|
||||
|
||||
// Set classifier
|
||||
if (!info.classifier().equals(Annotation.class)) {
|
||||
classifier = (Class<? extends Annotation>) info.classifier();
|
||||
types.add(classifier);
|
||||
}
|
||||
|
||||
for (Type t : info.type()) {
|
||||
Type type = null;
|
||||
|
||||
// Set type
|
||||
if (!t.equals(Class.class)) {
|
||||
type = t;
|
||||
if (classifier == null) {
|
||||
types.add(type); // Only if there is no classifier set!
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if at least one is set
|
||||
if (type == null && classifier == null) {
|
||||
throw new RuntimeException(
|
||||
"A @BindingMatch needs either a type or classifier set");
|
||||
}
|
||||
|
||||
BoundMethod handler = new BoundMethod(info, type, classifier, method);
|
||||
bindings.add(handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(bindings);
|
||||
|
||||
this.bindings = bindings;
|
||||
|
||||
Type[] typesArray = new Type[types.size()];
|
||||
types.toArray(typesArray);
|
||||
this.types = typesArray;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a {@link BindingMatch} according to the given parameter.
|
||||
*
|
||||
* @param parameter the parameter
|
||||
* @return a binding
|
||||
*/
|
||||
private BoundMethod match(ParameterData parameter) {
|
||||
for (BoundMethod binding : bindings) {
|
||||
Annotation classifer = parameter.getClassifier();
|
||||
Type type = parameter.getType();
|
||||
|
||||
if (binding.classifier != null) {
|
||||
if (classifer != null && classifer.annotationType().equals(binding.classifier)) {
|
||||
if (binding.type == null || binding.type.equals(type)) {
|
||||
return binding;
|
||||
}
|
||||
}
|
||||
} else if (binding.type.equals(type)) {
|
||||
return binding;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("Unknown type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type[] getTypes() {
|
||||
return types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConsumedCount(ParameterData parameter) {
|
||||
return match(parameter).annotation.consumedCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BindingBehavior getBehavior(ParameterData parameter) {
|
||||
return match(parameter).annotation.behavior();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object bind(ParameterData parameter, ArgumentStack scoped,
|
||||
boolean onlyConsume) throws ParameterException, CommandException {
|
||||
BoundMethod binding = match(parameter);
|
||||
List<Object> args = new ArrayList<Object>();
|
||||
args.add(scoped);
|
||||
|
||||
if (binding.classifier != null) {
|
||||
args.add(parameter.getClassifier());
|
||||
}
|
||||
|
||||
if (binding.annotation.provideModifiers()) {
|
||||
args.add(parameter.getModifiers());
|
||||
}
|
||||
|
||||
if (onlyConsume && binding.annotation.behavior() == BindingBehavior.PROVIDES) {
|
||||
return null; // Nothing to consume, nothing to do
|
||||
}
|
||||
|
||||
Object[] argsArray = new Object[args.size()];
|
||||
args.toArray(argsArray);
|
||||
|
||||
try {
|
||||
return binding.method.invoke(this, argsArray);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(
|
||||
"Processing of classifier " + parameter.getClassifier() +
|
||||
" and type " + parameter.getType() + " failed for method\n" +
|
||||
binding.method + "\nbecause the parameters for that method are wrong", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof ParameterException) {
|
||||
throw (ParameterException) e.getCause();
|
||||
} else if (e.getCause() instanceof CommandException) {
|
||||
throw (CommandException) e.getCause();
|
||||
}
|
||||
throw new ParameterException(e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions(ParameterData parameter, String prefix) {
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
|
||||
private static class BoundMethod implements Comparable<BoundMethod> {
|
||||
private final BindingMatch annotation;
|
||||
private final Type type;
|
||||
private final Class<? extends Annotation> classifier;
|
||||
private final Method method;
|
||||
|
||||
BoundMethod(BindingMatch annotation, Type type,
|
||||
Class<? extends Annotation> classifier, Method method) {
|
||||
this.annotation = annotation;
|
||||
this.type = type;
|
||||
this.classifier = classifier;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(BoundMethod o) {
|
||||
if (classifier != null && o.classifier == null) {
|
||||
return -1;
|
||||
} else if (classifier == null && o.classifier != null) {
|
||||
return 1;
|
||||
} else if (classifier != null && o.classifier != null) {
|
||||
if (type != null && o.type == null) {
|
||||
return -1;
|
||||
} else if (type == null && o.type != null) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a match of a binding.
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface BindingMatch {
|
||||
|
||||
/**
|
||||
* The classifier.
|
||||
*
|
||||
* @return the classifier, or {@link Annotation} if not set
|
||||
*/
|
||||
Class<? extends Annotation> classifier() default Annotation.class;
|
||||
|
||||
/**
|
||||
* The type.
|
||||
*
|
||||
* @return the type, or {@link Class} if not set
|
||||
*/
|
||||
Class<?>[] type() default Class.class;
|
||||
|
||||
/**
|
||||
* The binding behavior.
|
||||
*
|
||||
* @return the behavior
|
||||
*/
|
||||
BindingBehavior behavior();
|
||||
|
||||
/**
|
||||
* Get the number of arguments that this binding consumes.
|
||||
*
|
||||
* @return -1 if unknown or irrelevant
|
||||
*/
|
||||
int consumedCount() default -1;
|
||||
|
||||
/**
|
||||
* Set whether an array of modifier annotations is provided in the list of
|
||||
* arguments.
|
||||
*
|
||||
* @return true to provide modifiers
|
||||
*/
|
||||
boolean provideModifiers() default false;
|
||||
|
||||
}
|
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.worldedit.util.command.MissingParameterException;
|
||||
|
||||
/**
|
||||
* Makes an instance of a {@link CommandContext} into a stack of arguments
|
||||
* that can be consumed.
|
||||
*
|
||||
* @see ParametricBuilder a user of this class
|
||||
*/
|
||||
public class ContextArgumentStack implements ArgumentStack {
|
||||
|
||||
private final CommandContext context;
|
||||
private int index = 0;
|
||||
private int markedIndex = 0;
|
||||
|
||||
/**
|
||||
* Create a new instance using the given context.
|
||||
*
|
||||
* @param context the context
|
||||
*/
|
||||
public ContextArgumentStack(CommandContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next() throws ParameterException {
|
||||
try {
|
||||
return context.getString(index++);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new MissingParameterException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer nextInt() throws ParameterException {
|
||||
try {
|
||||
return Integer.parseInt(next());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ParameterException(
|
||||
"Expected a number, got '" + context.getString(index - 1) + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double nextDouble() throws ParameterException {
|
||||
try {
|
||||
return Double.parseDouble(next());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ParameterException(
|
||||
"Expected a number, got '" + context.getString(index - 1) + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean nextBoolean() throws ParameterException {
|
||||
try {
|
||||
return next().equalsIgnoreCase("true");
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new MissingParameterException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String remaining() throws ParameterException {
|
||||
try {
|
||||
String value = context.getJoinedStrings(index);
|
||||
index = context.argsLength();
|
||||
return value;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new MissingParameterException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unconsumed arguments left over, without touching the stack.
|
||||
*
|
||||
* @return the unconsumed arguments
|
||||
*/
|
||||
public String getUnconsumed() {
|
||||
if (index >= context.argsLength()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return context.getJoinedStrings(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markConsumed() {
|
||||
index = context.argsLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current position.
|
||||
*
|
||||
* @return the position
|
||||
*/
|
||||
public int position() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the current position of the stack.
|
||||
*
|
||||
* <p>The marked position initially starts at 0.</p>
|
||||
*/
|
||||
public void mark() {
|
||||
markedIndex = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset to the previously {@link #mark()}ed position of the stack, and return
|
||||
* the arguments that were consumed between this point and that previous point.
|
||||
*
|
||||
* <p>The marked position initially starts at 0.</p>
|
||||
*
|
||||
* @return the consumed arguments
|
||||
*/
|
||||
public String reset() {
|
||||
String value = context.getString(markedIndex, index);
|
||||
index = markedIndex;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether any arguments were consumed between the marked position
|
||||
* and the current position.
|
||||
*
|
||||
* <p>The marked position initially starts at 0.</p>
|
||||
*
|
||||
* @return true if values were consumed.
|
||||
*/
|
||||
public boolean wasConsumed() {
|
||||
return markedIndex != index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the arguments that were consumed between this point and that marked point.
|
||||
*
|
||||
* <p>The marked position initially starts at 0.</p>
|
||||
*
|
||||
* @return the consumed arguments
|
||||
*/
|
||||
public String getConsumed() {
|
||||
return context.getString(markedIndex, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying context.
|
||||
*
|
||||
* @return the context
|
||||
*/
|
||||
@Override
|
||||
public CommandContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.WrappedCommandException;
|
||||
|
||||
/**
|
||||
* Used to convert a recognized {@link Throwable} into an appropriate
|
||||
* {@link CommandException}.
|
||||
*
|
||||
* <p>Methods (when invoked by a {@link ParametricBuilder}-created command) may throw
|
||||
* relevant exceptions that are not caught by the command manager, but translate
|
||||
* into reasonable exceptions for an application. However, unknown exceptions are
|
||||
* normally simply wrapped in a {@link WrappedCommandException} and bubbled up. Only
|
||||
* normal {@link CommandException}s will be printed correctly, so a converter translates
|
||||
* one of these unknown exceptions into an appropriate {@link CommandException}.</p>
|
||||
*
|
||||
* <p>This also allows the code calling the command to not need be aware of these
|
||||
* application-specific exceptions, as they will all be converted to
|
||||
* {@link CommandException}s that are handled normally.</p>
|
||||
*/
|
||||
public interface ExceptionConverter {
|
||||
|
||||
/**
|
||||
* Attempt to convert the given throwable into a {@link CommandException}.
|
||||
*
|
||||
* <p>If the exception is not recognized, then nothing should be thrown.</p>
|
||||
*
|
||||
* @param t the throwable
|
||||
* @throws CommandException a command exception
|
||||
*/
|
||||
void convert(Throwable t) throws CommandException;
|
||||
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.WrappedCommandException;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An implementation of an {@link ExceptionConverter} that automatically calls
|
||||
* the correct method defined on this object.
|
||||
*
|
||||
* <p>Only public methods will be used. Methods will be called in order of decreasing
|
||||
* levels of inheritance (between classes where one inherits the other). For two
|
||||
* different inheritance branches, the order between them is undefined.</p>
|
||||
*/
|
||||
public abstract class ExceptionConverterHelper implements ExceptionConverter {
|
||||
|
||||
private final List<ExceptionHandler> handlers;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ExceptionConverterHelper() {
|
||||
List<ExceptionHandler> handlers = new ArrayList<ExceptionHandler>();
|
||||
|
||||
for (Method method : this.getClass().getMethods()) {
|
||||
if (method.getAnnotation(ExceptionMatch.class) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Class<?>[] parameters = method.getParameterTypes();
|
||||
if (parameters.length == 1) {
|
||||
Class<?> cls = parameters[0];
|
||||
if (Throwable.class.isAssignableFrom(cls)) {
|
||||
handlers.add(new ExceptionHandler(
|
||||
(Class<? extends Throwable>) cls, method));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(handlers);
|
||||
|
||||
this.handlers = handlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void convert(Throwable t) throws CommandException {
|
||||
Class<?> throwableClass = t.getClass();
|
||||
for (ExceptionHandler handler : handlers) {
|
||||
if (handler.cls.isAssignableFrom(throwableClass)) {
|
||||
try {
|
||||
handler.method.invoke(this, t);
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof CommandException) {
|
||||
throw (CommandException) e.getCause();
|
||||
}
|
||||
throw new WrappedCommandException(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new WrappedCommandException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new WrappedCommandException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ExceptionHandler implements Comparable<ExceptionHandler> {
|
||||
final Class<? extends Throwable> cls;
|
||||
final Method method;
|
||||
|
||||
public ExceptionHandler(Class<? extends Throwable> cls, Method method) {
|
||||
this.cls = cls;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ExceptionHandler o) {
|
||||
if (cls.equals(o.cls)) {
|
||||
return 0;
|
||||
} else if (cls.isAssignableFrom(o.cls)) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Denotes a match of an exception.
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ExceptionMatch {
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Called before and after a command is invoked for commands executed by a command
|
||||
* created using {@link ParametricBuilder}.
|
||||
*
|
||||
* <p>Invocation handlers are created by {@link InvokeListener}s. Multiple
|
||||
* listeners and handlers can be registered, and all be run. However, if one handler
|
||||
* throws an exception, future handlers will not execute and the command will
|
||||
* not execute (if thrown in
|
||||
* {@link #preInvoke(Object, Method, ParameterData[], Object[], CommandContext)}).</p>
|
||||
*
|
||||
* @see InvokeListener the factory
|
||||
*/
|
||||
public interface InvokeHandler {
|
||||
|
||||
/**
|
||||
* Called before parameters are processed.
|
||||
*
|
||||
* @param object the object
|
||||
* @param method the method
|
||||
* @param parameters the list of parameters
|
||||
* @param context the context
|
||||
* @throws CommandException can be thrown for an error, which will stop invocation
|
||||
* @throws ParameterException on parameter error
|
||||
*/
|
||||
void preProcess(Object object, Method method, ParameterData[] parameters,
|
||||
CommandContext context) throws CommandException, ParameterException;
|
||||
|
||||
/**
|
||||
* Called before the parameter is invoked.
|
||||
*
|
||||
* @param object the object
|
||||
* @param method the method
|
||||
* @param parameters the list of parameters
|
||||
* @param args the arguments to be given to the method
|
||||
* @param context the context
|
||||
* @throws CommandException can be thrown for an error, which will stop invocation
|
||||
* @throws ParameterException on parameter error
|
||||
*/
|
||||
void preInvoke(Object object, Method method, ParameterData[] parameters,
|
||||
Object[] args, CommandContext context) throws CommandException, ParameterException;
|
||||
|
||||
/**
|
||||
* Called after the parameter is invoked.
|
||||
*
|
||||
* @param object the object
|
||||
* @param method the method
|
||||
* @param parameters the list of parameters
|
||||
* @param args the arguments to be given to the method
|
||||
* @param context the context
|
||||
* @throws CommandException can be thrown for an error
|
||||
* @throws ParameterException on parameter error
|
||||
*/
|
||||
void postInvoke(Object object, Method method, ParameterData[] parameters,
|
||||
Object[] args, CommandContext context) throws CommandException, ParameterException;
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
import com.sk89q.worldedit.util.command.CommandCallable;
|
||||
import com.sk89q.worldedit.util.command.SimpleDescription;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Listens to events related to {@link ParametricBuilder}.
|
||||
*/
|
||||
public interface InvokeListener {
|
||||
|
||||
/**
|
||||
* Create a new invocation handler.
|
||||
*
|
||||
* <p>An example use of an {@link InvokeHandler} would be to verify permissions
|
||||
* added by the {@link CommandPermissions} annotation.</p>
|
||||
*
|
||||
* <p>For simple {@link InvokeHandler}, an object can implement both this
|
||||
* interface and {@link InvokeHandler}.</p>
|
||||
*
|
||||
* @return a new invocation handler
|
||||
*/
|
||||
InvokeHandler createInvokeHandler();
|
||||
|
||||
/**
|
||||
* During creation of a {@link CommandCallable} by a {@link ParametricBuilder},
|
||||
* this will be called in case the description needs to be updated.
|
||||
*
|
||||
* @param object the object
|
||||
* @param method the method
|
||||
* @param parameters a list of parameters
|
||||
* @param description the description to be updated
|
||||
*/
|
||||
void updateDescription(Object object, Method method, ParameterData[] parameters,
|
||||
SimpleDescription description);
|
||||
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.worldedit.util.command.MissingParameterException;
|
||||
import com.sk89q.worldedit.util.command.SimpleDescription;
|
||||
import com.sk89q.worldedit.util.command.UnconsumedParameterException;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Handles legacy properties on {@link Command} such as {@link Command#min()} and
|
||||
* {@link Command#max()}.
|
||||
*/
|
||||
public class LegacyCommandsHandler extends AbstractInvokeListener implements InvokeHandler {
|
||||
|
||||
@Override
|
||||
public InvokeHandler createInvokeHandler() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preProcess(Object object, Method method,
|
||||
ParameterData[] parameters, CommandContext context)
|
||||
throws CommandException, ParameterException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preInvoke(Object object, Method method,
|
||||
ParameterData[] parameters, Object[] args, CommandContext context)
|
||||
throws ParameterException {
|
||||
Command annotation = method.getAnnotation(Command.class);
|
||||
|
||||
if (annotation != null) {
|
||||
if (context.argsLength() < annotation.min()) {
|
||||
throw new MissingParameterException();
|
||||
}
|
||||
|
||||
if (annotation.max() != -1 && context.argsLength() > annotation.max()) {
|
||||
throw new UnconsumedParameterException(
|
||||
context.getRemainingString(annotation.max()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInvoke(Object object, Method method,
|
||||
ParameterData[] parameters, Object[] args, CommandContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDescription(Object object, Method method,
|
||||
ParameterData[] parameters, SimpleDescription description) {
|
||||
Command annotation = method.getAnnotation(Command.class);
|
||||
|
||||
// Handle the case for old commands where no usage is set and all of its
|
||||
// parameters are provider bindings, so its usage information would
|
||||
// be blank and would imply that there were no accepted parameters
|
||||
if (annotation != null && annotation.usage().isEmpty()
|
||||
&& (annotation.min() > 0 || annotation.max() > 0)) {
|
||||
boolean hasUserParameters = false;
|
||||
|
||||
for (ParameterData parameter : parameters) {
|
||||
if (parameter.getBinding().getBehavior(parameter) != BindingBehavior.PROVIDES) {
|
||||
hasUserParameters = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasUserParameters) {
|
||||
description.overrideUsage("(unknown usage information)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates an optional parameter.
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Optional {
|
||||
|
||||
/**
|
||||
* The default value to use if no value is set.
|
||||
*
|
||||
* @return a string value, or an empty list
|
||||
*/
|
||||
String[] value() default {};
|
||||
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.worldedit.util.command.SimpleParameter;
|
||||
import com.sk89q.worldedit.util.command.binding.PrimitiveBindings;
|
||||
import com.sk89q.worldedit.util.command.binding.Range;
|
||||
import com.sk89q.worldedit.util.command.binding.Text;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Describes a parameter in detail.
|
||||
*/
|
||||
public class ParameterData extends SimpleParameter {
|
||||
|
||||
private Binding binding;
|
||||
private Annotation classifier;
|
||||
private Annotation[] modifiers;
|
||||
private Type type;
|
||||
|
||||
/**
|
||||
* Get the binding associated with this parameter.
|
||||
*
|
||||
* @return the binding
|
||||
*/
|
||||
public Binding getBinding() {
|
||||
return binding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the binding associated with this parameter.
|
||||
*
|
||||
* @param binding the binding
|
||||
*/
|
||||
void setBinding(Binding binding) {
|
||||
this.binding = binding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the main type of this parameter.
|
||||
*
|
||||
* <p>The type is normally that is used to determine which binding is used
|
||||
* for a particular method's parameter.</p>
|
||||
*
|
||||
* @return the main type
|
||||
* @see #getClassifier() which can override the type
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the main type of this parameter.
|
||||
*
|
||||
* @param type the main type
|
||||
*/
|
||||
void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the classifier annotation.
|
||||
*
|
||||
* <p>Normally, the type determines what binding is called, but classifiers
|
||||
* take precedence if one is found (and registered with
|
||||
* {@link ParametricBuilder#addBinding(Binding, Type...)}).
|
||||
* An example of a classifier annotation is {@link Text}.</p>
|
||||
*
|
||||
* @return the classifier annotation, null is possible
|
||||
*/
|
||||
public Annotation getClassifier() {
|
||||
return classifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the classifier annotation.
|
||||
*
|
||||
* @param classifier the classifier annotation, null is possible
|
||||
*/
|
||||
void setClassifier(Annotation classifier) {
|
||||
this.classifier = classifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of modifier annotations.
|
||||
*
|
||||
* <p>Modifier annotations are not considered in the process of choosing a binding
|
||||
* for a method parameter, but they can be used to modify the behavior of a binding.
|
||||
* An example of a modifier annotation is {@link Range}, which can restrict
|
||||
* numeric values handled by {@link PrimitiveBindings} to be within a range. The list
|
||||
* of annotations may contain a classifier and other unrelated annotations.</p>
|
||||
*
|
||||
* @return a list of annotations
|
||||
*/
|
||||
public Annotation[] getModifiers() {
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of modifiers.
|
||||
*
|
||||
* @param modifiers a list of annotations
|
||||
*/
|
||||
void setModifiers(Annotation[] modifiers) {
|
||||
this.modifiers = modifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of arguments this binding consumes.
|
||||
*
|
||||
* @return -1 if unknown or unavailable
|
||||
*/
|
||||
int getConsumedCount() {
|
||||
return getBinding().getConsumedCount(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether this parameter is entered by the user.
|
||||
*
|
||||
* @return true if this parameter is entered by the user.
|
||||
*/
|
||||
boolean isUserInput() {
|
||||
return getBinding().getBehavior(this) != BindingBehavior.PROVIDES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether this parameter consumes non-flag arguments.
|
||||
*
|
||||
* @return true if this parameter consumes non-flag arguments
|
||||
*/
|
||||
boolean isNonFlagConsumer() {
|
||||
return getBinding().getBehavior(this) != BindingBehavior.PROVIDES && !isValueFlag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate this parameter and its binding.
|
||||
*/
|
||||
void validate(Method method, int parameterIndex) throws ParametricException {
|
||||
// We can't have indeterminate consumers without @Switches otherwise
|
||||
// it may screw up parameter processing for later bindings
|
||||
BindingBehavior behavior = getBinding().getBehavior(this);
|
||||
boolean indeterminate = (behavior == BindingBehavior.INDETERMINATE);
|
||||
if (!isValueFlag() && indeterminate) {
|
||||
throw new ParametricException(
|
||||
"@Switch missing for indeterminate consumer\n\n" +
|
||||
"Notably:\nFor the type " + type + ", the binding " +
|
||||
getBinding().getClass().getCanonicalName() +
|
||||
"\nmay or may not consume parameters (isIndeterminateConsumer(" + type + ") = true)" +
|
||||
"\nand therefore @Switch(flag) is required for parameter #" + parameterIndex + " of \n" +
|
||||
method.toGenericString());
|
||||
}
|
||||
|
||||
// getConsumedCount() better return -1 if the BindingBehavior is not CONSUMES
|
||||
if (behavior != BindingBehavior.CONSUMES && binding.getConsumedCount(this) != -1) {
|
||||
throw new ParametricException(
|
||||
"getConsumedCount() does not return -1 for binding " +
|
||||
getBinding().getClass().getCanonicalName() +
|
||||
"\neven though its behavior type is " + behavior.name() +
|
||||
"\nfor parameter #" + parameterIndex + " of \n" +
|
||||
method.toGenericString());
|
||||
}
|
||||
|
||||
// getConsumedCount() should not return 0 if the BindingBehavior is not PROVIDES
|
||||
if (behavior != BindingBehavior.PROVIDES && binding.getConsumedCount(this) == 0) {
|
||||
throw new ParametricException(
|
||||
"getConsumedCount() must not return 0 for binding " +
|
||||
getBinding().getClass().getCanonicalName() +
|
||||
"\nwhen its behavior type is " + behavior.name() + " and not PROVIDES " +
|
||||
"\nfor parameter #" + parameterIndex + " of \n" +
|
||||
method.toGenericString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
/**
|
||||
* Thrown if there is an error with a parameter.
|
||||
*/
|
||||
public class ParameterException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = -8255175019708245673L;
|
||||
|
||||
public ParameterException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ParameterException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ParameterException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public ParameterException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap.Builder;
|
||||
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.worldedit.util.command.CommandCallable;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import com.sk89q.worldedit.util.command.binding.PrimitiveBindings;
|
||||
import com.sk89q.worldedit.util.command.binding.StandardBindings;
|
||||
import com.sk89q.worldedit.util.command.binding.Switch;
|
||||
import com.thoughtworks.paranamer.CachingParanamer;
|
||||
import com.thoughtworks.paranamer.Paranamer;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Creates commands using annotations placed on methods and individual parameters of
|
||||
* such methods.
|
||||
*
|
||||
* @see Command defines a command
|
||||
* @see Switch defines a flag
|
||||
*/
|
||||
public class ParametricBuilder {
|
||||
|
||||
private final Map<Type, Binding> bindings = new HashMap<Type, Binding>();
|
||||
private final Paranamer paranamer = new CachingParanamer();
|
||||
private final List<InvokeListener> invokeListeners = new ArrayList<InvokeListener>();
|
||||
private final List<ExceptionConverter> exceptionConverters = new ArrayList<ExceptionConverter>();
|
||||
|
||||
/**
|
||||
* Create a new builder.
|
||||
*
|
||||
* <p>This method will install {@link PrimitiveBindings} and
|
||||
* {@link StandardBindings} and default bindings.</p>
|
||||
*/
|
||||
public ParametricBuilder() {
|
||||
addBinding(new PrimitiveBindings());
|
||||
addBinding(new StandardBindings());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a binding for a given type or classifier (annotation).
|
||||
*
|
||||
* <p>Whenever a method parameter is encountered, a binding must be found for it
|
||||
* so that it can be called later to consume the stack of arguments provided by
|
||||
* the user and return an object that is later passed to
|
||||
* {@link Method#invoke(Object, Object...)}.</p>
|
||||
*
|
||||
* <p>Normally, a {@link Type} is used to discern between different bindings, but
|
||||
* if this is not specific enough, an annotation can be defined and used. This
|
||||
* makes it a "classifier" and it will take precedence over the base type. For
|
||||
* example, even if there is a binding that handles {@link String} parameters,
|
||||
* a special <code>@MyArg</code> annotation can be assigned to a {@link String}
|
||||
* parameter, which will cause the {@link Builder} to consult the {@link Binding}
|
||||
* associated with <code>@MyArg</code> rather than with the binding for
|
||||
* the {@link String} type.</p>
|
||||
*
|
||||
* @param binding the binding
|
||||
* @param type a list of types (if specified) to override the binding's types
|
||||
*/
|
||||
public void addBinding(Binding binding, Type... type) {
|
||||
if (type == null || type.length == 0) {
|
||||
type = binding.getTypes();
|
||||
}
|
||||
|
||||
for (Type t : type) {
|
||||
bindings.put(t, binding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach an invocation listener.
|
||||
*
|
||||
* <p>Invocation handlers are called in order that their listeners are
|
||||
* registered with a {@link ParametricBuilder}. It is not guaranteed that
|
||||
* a listener may be called, in the case of a {@link CommandException} being
|
||||
* thrown at any time before the appropriate listener or handler is called.
|
||||
* It is possible for a
|
||||
* {@link InvokeHandler#preInvoke(Object, Method, ParameterData[], Object[], CommandContext)} to
|
||||
* be called for a invocation handler, but not the associated
|
||||
* {@link InvokeHandler#postInvoke(Object, Method, ParameterData[], Object[], CommandContext)}.</p>
|
||||
*
|
||||
* <p>An example of an invocation listener is one to handle
|
||||
* {@link CommandPermissions}, by first checking to see if permission is available
|
||||
* in a {@link InvokeHandler#preInvoke(Object, Method, ParameterData[], Object[], CommandContext)}
|
||||
* call. If permission is not found, then an appropriate {@link CommandException}
|
||||
* can be thrown to cease invocation.</p>
|
||||
*
|
||||
* @param listener the listener
|
||||
* @see InvokeHandler the handler
|
||||
*/
|
||||
public void attach(InvokeListener listener) {
|
||||
invokeListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach an exception converter to this builder in order to wrap unknown
|
||||
* {@link Throwable}s into known {@link CommandException}s.
|
||||
*
|
||||
* <p>Exception converters are called in order that they are registered.</p>
|
||||
*
|
||||
* @param converter the converter
|
||||
* @see ExceptionConverter for an explanation
|
||||
*/
|
||||
public void attach(ExceptionConverter converter) {
|
||||
exceptionConverters.add(converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a list of commands from methods specially annotated with {@link Command}
|
||||
* (and other relevant annotations) and register them all with the given
|
||||
* {@link Dispatcher}.
|
||||
*
|
||||
* @param dispatcher the dispatcher to register commands with
|
||||
* @param object the object contain the methods
|
||||
* @throws ParametricException thrown if the commands cannot be registered
|
||||
*/
|
||||
public void register(Dispatcher dispatcher, Object object) throws ParametricException {
|
||||
for (Method method : object.getClass().getDeclaredMethods()) {
|
||||
Command definition = method.getAnnotation(Command.class);
|
||||
if (definition != null) {
|
||||
CommandCallable callable = build(object, method, definition);
|
||||
dispatcher.register(callable, definition.aliases());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a {@link CommandCallable} for the given method.
|
||||
*
|
||||
* @param object the object to be invoked on
|
||||
* @param method the method to invoke
|
||||
* @param definition the command definition annotation
|
||||
* @return the command executor
|
||||
* @throws ParametricException thrown on an error
|
||||
*/
|
||||
private CommandCallable build(Object object, Method method, Command definition)
|
||||
throws ParametricException {
|
||||
return new ParametricCallable(this, object, method, definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object used to get method names on Java versions before 8 (assuming
|
||||
* that Java 8 is given the ability to reliably reflect method names at runtime).
|
||||
*
|
||||
* @return the paranamer
|
||||
*/
|
||||
Paranamer getParanamer() {
|
||||
return paranamer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map of bindings.
|
||||
*
|
||||
* @return the map of bindings
|
||||
*/
|
||||
Map<Type, Binding> getBindings() {
|
||||
return bindings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of invocation listeners.
|
||||
*
|
||||
* @return a list of invocation listeners
|
||||
*/
|
||||
List<InvokeListener> getInvokeListeners() {
|
||||
return invokeListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of exception converters.
|
||||
*
|
||||
* @return a list of exception converters
|
||||
*/
|
||||
List<ExceptionConverter> getExceptionConverters() {
|
||||
return exceptionConverters;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,538 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
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.SuggestionContext;
|
||||
import com.sk89q.minecraft.util.commands.WrappedCommandException;
|
||||
import com.sk89q.worldedit.util.command.CommandCallable;
|
||||
import com.sk89q.worldedit.util.command.InvalidUsageException;
|
||||
import com.sk89q.worldedit.util.command.MissingParameterException;
|
||||
import com.sk89q.worldedit.util.command.Parameter;
|
||||
import com.sk89q.worldedit.util.command.SimpleDescription;
|
||||
import com.sk89q.worldedit.util.command.UnconsumedParameterException;
|
||||
import com.sk89q.worldedit.util.command.binding.Switch;
|
||||
|
||||
/**
|
||||
* The implementation of a {@link CommandCallable} for the {@link ParametricBuilder}.
|
||||
*/
|
||||
class ParametricCallable implements CommandCallable {
|
||||
|
||||
private final ParametricBuilder builder;
|
||||
private final Object object;
|
||||
private final Method method;
|
||||
private final ParameterData[] parameters;
|
||||
private final Set<Character> valueFlags = new HashSet<Character>();
|
||||
private final SimpleDescription description = new SimpleDescription();
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param builder the parametric builder
|
||||
* @param object the object to invoke on
|
||||
* @param method the method to invoke
|
||||
* @param definition the command definition annotation
|
||||
* @throws ParametricException thrown on an error
|
||||
*/
|
||||
ParametricCallable(
|
||||
ParametricBuilder builder,
|
||||
Object object, Method method,
|
||||
Command definition) throws ParametricException {
|
||||
|
||||
this.builder = builder;
|
||||
this.object = object;
|
||||
this.method = method;
|
||||
|
||||
Annotation[][] annotations = method.getParameterAnnotations();
|
||||
String[] names = builder.getParanamer().lookupParameterNames(method, false);
|
||||
Type[] types = method.getGenericParameterTypes();
|
||||
parameters = new ParameterData[types.length];
|
||||
List<Parameter> userParameters = new ArrayList<Parameter>();
|
||||
|
||||
// This helps keep tracks of @Nullables that appear in the middle of a list
|
||||
// of parameters
|
||||
int numOptional = 0;
|
||||
|
||||
// Set permission hint
|
||||
CommandPermissions permHint = method.getAnnotation(CommandPermissions.class);
|
||||
if (permHint != null) {
|
||||
description.setPermissions(Arrays.asList(permHint.value()));
|
||||
}
|
||||
|
||||
// Go through each parameter
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
Type type = types[i];
|
||||
|
||||
ParameterData parameter = new ParameterData();
|
||||
parameter.setType(type);
|
||||
parameter.setModifiers(annotations[i]);
|
||||
|
||||
// Search for annotations
|
||||
for (Annotation annotation : annotations[i]) {
|
||||
if (annotation instanceof Switch) {
|
||||
parameter.setFlag(((Switch) annotation).value(), type != boolean.class);
|
||||
} else if (annotation instanceof Nullable) {
|
||||
parameter.setOptional(true);
|
||||
} else if (annotation instanceof Optional) {
|
||||
parameter.setOptional(true);
|
||||
String[] value = ((Optional) annotation).value();
|
||||
if (value.length > 0) {
|
||||
parameter.setDefaultValue(value);
|
||||
}
|
||||
// Special annotation bindings
|
||||
} else if (parameter.getBinding() == null) {
|
||||
parameter.setBinding(builder.getBindings().get(
|
||||
annotation.annotationType()));
|
||||
parameter.setClassifier(annotation);
|
||||
}
|
||||
}
|
||||
|
||||
parameter.setName(names.length > 0 ?
|
||||
names[i] : generateName(type, parameter.getClassifier(), i));
|
||||
|
||||
// Track all value flags
|
||||
if (parameter.isValueFlag()) {
|
||||
valueFlags.add(parameter.getFlag());
|
||||
}
|
||||
|
||||
// No special @annotation binding... let's check for the type
|
||||
if (parameter.getBinding() == null) {
|
||||
parameter.setBinding(builder.getBindings().get(type));
|
||||
|
||||
// Don't know how to parse for this type of value
|
||||
if (parameter.getBinding() == null) {
|
||||
throw new ParametricException(
|
||||
"Don't know how to handle the parameter type '" + type + "' in\n" +
|
||||
method.toGenericString());
|
||||
}
|
||||
}
|
||||
|
||||
// Do some validation of this parameter
|
||||
parameter.validate(method, i + 1);
|
||||
|
||||
// Keep track of optional parameters
|
||||
if (parameter.isOptional() && parameter.getFlag() == null) {
|
||||
numOptional++;
|
||||
} else {
|
||||
if (numOptional > 0 && parameter.isNonFlagConsumer()) {
|
||||
if (parameter.getConsumedCount() < 0) {
|
||||
throw new ParametricException(
|
||||
"Found an parameter using the binding " +
|
||||
parameter.getBinding().getClass().getCanonicalName() +
|
||||
"\nthat does not know how many arguments it consumes, but " +
|
||||
"it follows an optional parameter\nMethod: " +
|
||||
method.toGenericString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parameters[i] = parameter;
|
||||
|
||||
// Make a list of "real" parameters
|
||||
if (parameter.isUserInput()) {
|
||||
userParameters.add(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
// Finish description
|
||||
description.setDescription(!definition.desc().isEmpty() ? definition.desc() : null);
|
||||
description.setHelp(!definition.help().isEmpty() ? definition.help() : null);
|
||||
description.overrideUsage(!definition.usage().isEmpty() ? definition.usage() : null);
|
||||
|
||||
for (InvokeListener listener : builder.getInvokeListeners()) {
|
||||
listener.updateDescription(object, method, parameters, description);
|
||||
}
|
||||
|
||||
// Set parameters
|
||||
description.setParameters(userParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(CommandContext context) throws CommandException {
|
||||
Object[] args = new Object[parameters.length];
|
||||
ContextArgumentStack arguments = new ContextArgumentStack(context);
|
||||
ParameterData parameter = null;
|
||||
|
||||
try {
|
||||
// preProcess handlers
|
||||
List<InvokeHandler> handlers = new ArrayList<InvokeHandler>();
|
||||
for (InvokeListener listener : builder.getInvokeListeners()) {
|
||||
InvokeHandler handler = listener.createInvokeHandler();
|
||||
handlers.add(handler);
|
||||
handler.preProcess(object, method, parameters, context);
|
||||
}
|
||||
|
||||
// Collect parameters
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
parameter = parameters[i];
|
||||
|
||||
if (mayConsumeArguments(i, arguments)) {
|
||||
// Parse the user input into a method argument
|
||||
ArgumentStack usedArguments = getScopedContext(parameter, arguments);
|
||||
|
||||
try {
|
||||
args[i] = parameter.getBinding().bind(parameter, usedArguments, false);
|
||||
} catch (MissingParameterException e) {
|
||||
// Not optional? Then we can't execute this command
|
||||
if (!parameter.isOptional()) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
args[i] = getDefaultValue(i, arguments);
|
||||
}
|
||||
} else {
|
||||
args[i] = getDefaultValue(i, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for unused arguments
|
||||
checkUnconsumed(arguments);
|
||||
|
||||
// preInvoke handlers
|
||||
for (InvokeHandler handler : handlers) {
|
||||
handler.preInvoke(object, method, parameters, args, context);
|
||||
}
|
||||
|
||||
// Execute!
|
||||
method.invoke(object, args);
|
||||
|
||||
// postInvoke handlers
|
||||
for (InvokeHandler handler : handlers) {
|
||||
handler.postInvoke(handler, method, parameters, args, context);
|
||||
}
|
||||
} catch (MissingParameterException e) {
|
||||
throw new InvalidUsageException(
|
||||
"Too few parameters!", getDescription());
|
||||
} catch (UnconsumedParameterException e) {
|
||||
throw new InvalidUsageException(
|
||||
"Too many parameters! Unused parameters: "
|
||||
+ e.getUnconsumed(), getDescription());
|
||||
} catch (ParameterException e) {
|
||||
if (e.getCause() != null) {
|
||||
for (ExceptionConverter converter : builder.getExceptionConverters()) {
|
||||
converter.convert(e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
String name = parameter.getName();
|
||||
|
||||
throw new InvalidUsageException("For parameter '" + name + "': "
|
||||
+ e.getMessage(), getDescription());
|
||||
} catch (InvocationTargetException e) {
|
||||
for (ExceptionConverter converter : builder.getExceptionConverters()) {
|
||||
converter.convert(e.getCause());
|
||||
}
|
||||
throw new WrappedCommandException(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new WrappedCommandException(e);
|
||||
} catch (CommandException e) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
throw new WrappedCommandException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions(CommandContext context) throws CommandException {
|
||||
ContextArgumentStack scoped = new ContextArgumentStack(context);
|
||||
SuggestionContext suggestable = context.getSuggestionContext();
|
||||
|
||||
// For /command -f |
|
||||
// For /command -f flag|
|
||||
if (suggestable.forFlag()) {
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
ParameterData parameter = parameters[i];
|
||||
|
||||
if (parameter.getFlag() == suggestable.getFlag()) {
|
||||
String prefix = context.getFlag(parameter.getFlag());
|
||||
if (prefix == null) {
|
||||
prefix = "";
|
||||
}
|
||||
|
||||
return parameter.getBinding().getSuggestions(parameter, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
// This should not happen
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
|
||||
int consumerIndex = 0;
|
||||
ParameterData lastConsumer = null;
|
||||
String lastConsumed = null;
|
||||
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
ParameterData parameter = parameters[i];
|
||||
|
||||
if (parameter.getFlag() != null) {
|
||||
continue; // We already handled flags
|
||||
}
|
||||
|
||||
try {
|
||||
scoped.mark();
|
||||
parameter.getBinding().bind(parameter, scoped, true);
|
||||
if (scoped.wasConsumed()) {
|
||||
lastConsumer = parameter;
|
||||
lastConsumed = scoped.getConsumed();
|
||||
consumerIndex++;
|
||||
}
|
||||
} catch (MissingParameterException e) {
|
||||
// For /command value1 |value2
|
||||
// For /command |value1 value2
|
||||
if (suggestable.forHangingValue()) {
|
||||
return parameter.getBinding().getSuggestions(parameter, "");
|
||||
} else {
|
||||
// For /command value1| value2
|
||||
if (lastConsumer != null) {
|
||||
return lastConsumer.getBinding()
|
||||
.getSuggestions(lastConsumer, lastConsumed);
|
||||
// For /command| value1 value2
|
||||
// This should never occur
|
||||
} else {
|
||||
throw new RuntimeException("Invalid suggestion context");
|
||||
}
|
||||
}
|
||||
} catch (ParameterException e) {
|
||||
if (suggestable.forHangingValue()) {
|
||||
String name = getDescription().getParameters()
|
||||
.get(consumerIndex).getName();
|
||||
|
||||
throw new InvalidUsageException("For parameter '" + name + "': "
|
||||
+ e.getMessage(), getDescription());
|
||||
} else {
|
||||
return parameter.getBinding().getSuggestions(parameter, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For /command value1 value2 |
|
||||
if (suggestable.forHangingValue()) {
|
||||
// There's nothing that we can suggest because there's no more parameters
|
||||
// to add on, and we can't change the previous parameter
|
||||
return new ArrayList<String>();
|
||||
} else {
|
||||
// For /command value1 value2|
|
||||
if (lastConsumer != null) {
|
||||
return lastConsumer.getBinding()
|
||||
.getSuggestions(lastConsumer, lastConsumed);
|
||||
// This should never occur
|
||||
} else {
|
||||
throw new RuntimeException("Invalid suggestion context");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Character> getValueFlags() {
|
||||
return valueFlags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleDescription getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the right {@link ArgumentStack}.
|
||||
*
|
||||
* @param parameter the parameter
|
||||
* @param existing the existing scoped context
|
||||
* @return the context to use
|
||||
*/
|
||||
private static ArgumentStack getScopedContext(Parameter parameter, ArgumentStack existing) {
|
||||
if (parameter.getFlag() != null) {
|
||||
CommandContext context = existing.getContext();
|
||||
|
||||
if (parameter.isValueFlag()) {
|
||||
return new StringArgumentStack(
|
||||
context, context.getFlag(parameter.getFlag()), false);
|
||||
} else {
|
||||
String v = context.hasFlag(parameter.getFlag()) ? "true" : "false";
|
||||
return new StringArgumentStack(context, v, true);
|
||||
}
|
||||
}
|
||||
|
||||
return existing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether a parameter is allowed to consume arguments.
|
||||
*
|
||||
* @param i the index of the parameter
|
||||
* @param scoped the scoped context
|
||||
* @return true if arguments may be consumed
|
||||
*/
|
||||
private boolean mayConsumeArguments(int i, ContextArgumentStack scoped) {
|
||||
CommandContext context = scoped.getContext();
|
||||
ParameterData parameter = parameters[i];
|
||||
|
||||
// Flag parameters: Always consume
|
||||
// Required non-flag parameters: Always consume
|
||||
// Optional non-flag parameters:
|
||||
// - Before required parameters: Consume if there are 'left over' args
|
||||
// - At the end: Always consumes
|
||||
|
||||
if (parameter.isOptional() && parameter.getFlag() == null) {
|
||||
int numberFree = context.argsLength() - scoped.position();
|
||||
for (int j = i; j < parameters.length; j++) {
|
||||
if (parameters[j].isNonFlagConsumer() && !parameters[j].isOptional()) {
|
||||
// We already checked if the consumed count was > -1
|
||||
// when we created this object
|
||||
numberFree -= parameters[j].getConsumedCount();
|
||||
}
|
||||
}
|
||||
|
||||
// Skip this optional parameter
|
||||
if (numberFree < 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default value for a parameter.
|
||||
*
|
||||
* @param i the index of the parameter
|
||||
* @param scoped the scoped context
|
||||
* @return a value
|
||||
* @throws ParameterException on an error
|
||||
* @throws CommandException on an error
|
||||
*/
|
||||
private Object getDefaultValue(int i, ContextArgumentStack scoped)
|
||||
throws ParameterException, CommandException {
|
||||
CommandContext context = scoped.getContext();
|
||||
ParameterData parameter = parameters[i];
|
||||
|
||||
String[] defaultValue = parameter.getDefaultValue();
|
||||
if (defaultValue != null) {
|
||||
try {
|
||||
return parameter.getBinding().bind(
|
||||
parameter, new StringArgumentStack(
|
||||
context, defaultValue, false), false);
|
||||
} catch (MissingParameterException e) {
|
||||
throw new ParametricException(
|
||||
"The default value of the parameter using the binding " +
|
||||
parameter.getBinding().getClass() + " in the method\n" +
|
||||
method.toGenericString() + "\nis invalid");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check to see if all arguments, including flag arguments, were consumed.
|
||||
*
|
||||
* @param scoped the argument scope
|
||||
* @throws UnconsumedParameterException thrown if parameters were not consumed
|
||||
*/
|
||||
private void checkUnconsumed(ContextArgumentStack scoped)
|
||||
throws UnconsumedParameterException {
|
||||
CommandContext context = scoped.getContext();
|
||||
String unconsumed;
|
||||
String unconsumedFlags = getUnusedFlags(context);
|
||||
|
||||
if ((unconsumed = scoped.getUnconsumed()) != null) {
|
||||
throw new UnconsumedParameterException(unconsumed + " " + unconsumedFlags);
|
||||
}
|
||||
|
||||
if (unconsumedFlags != null) {
|
||||
throw new UnconsumedParameterException(unconsumedFlags);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any unused flag arguments.
|
||||
*
|
||||
* @param context the command context
|
||||
* @param parameters the list of parameters
|
||||
*/
|
||||
private String getUnusedFlags(CommandContext context) {
|
||||
Set<Character> unusedFlags = null;
|
||||
for (char flag : context.getFlags()) {
|
||||
boolean found = false;
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
Character paramFlag = parameters[i].getFlag();
|
||||
if (paramFlag != null && flag == paramFlag) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
if (unusedFlags == null) {
|
||||
unusedFlags = new HashSet<Character>();
|
||||
}
|
||||
unusedFlags.add(flag);
|
||||
}
|
||||
}
|
||||
|
||||
if (unusedFlags != null) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Character flag : unusedFlags) {
|
||||
builder.append("-").append(flag).append(" ");
|
||||
}
|
||||
|
||||
return builder.toString().trim();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a name for a parameter.
|
||||
*
|
||||
* @param type the type
|
||||
* @param classifier the classifier
|
||||
* @param index the index
|
||||
* @return a generated name
|
||||
*/
|
||||
private static String generateName(Type type, Annotation classifier, int index) {
|
||||
if (classifier != null) {
|
||||
return classifier.annotationType().getSimpleName().toLowerCase();
|
||||
} else {
|
||||
if (type instanceof Class<?>) {
|
||||
return ((Class<?>) type).getSimpleName().toLowerCase();
|
||||
} else {
|
||||
return "unknown" + index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
/**
|
||||
* Thrown if the {@link ParametricBuilder} can't build commands from
|
||||
* an object for whatever reason.
|
||||
*/
|
||||
public class ParametricException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -5426219576099680971L;
|
||||
|
||||
public ParametricException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ParametricException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ParametricException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ParametricException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
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.CommandPermissionsException;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* A handler for the {@link CommandPermissions} annotation.
|
||||
*/
|
||||
public abstract class PermissionsHandler extends AbstractInvokeListener implements InvokeHandler {
|
||||
|
||||
@Override
|
||||
public InvokeHandler createInvokeHandler() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preProcess(Object object, Method method,
|
||||
ParameterData[] parameters, CommandContext context)
|
||||
throws CommandException, ParameterException {
|
||||
CommandPermissions annotation = method.getAnnotation(CommandPermissions.class);
|
||||
if (annotation != null) {
|
||||
for (String perm : annotation.value()) {
|
||||
if (hasPermission(context, perm)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new CommandPermissionsException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preInvoke(Object object, Method method, ParameterData[] parameters,
|
||||
Object[] args, CommandContext context) throws CommandException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInvoke(Object object, Method method, ParameterData[] parameters,
|
||||
Object[] args, CommandContext context) throws CommandException {
|
||||
}
|
||||
|
||||
protected abstract boolean hasPermission(CommandContext context, String permission);
|
||||
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.worldedit.util.command.MissingParameterException;
|
||||
import com.sk89q.util.StringUtil;
|
||||
|
||||
/**
|
||||
* A virtual scope that does not actually read from the underlying
|
||||
* {@link CommandContext}.
|
||||
*/
|
||||
public class StringArgumentStack implements ArgumentStack {
|
||||
|
||||
private final boolean nonNullBoolean;
|
||||
private final CommandContext context;
|
||||
private final String[] arguments;
|
||||
private int index = 0;
|
||||
|
||||
/**
|
||||
* Create a new instance using the given context.
|
||||
*
|
||||
* @param context the context
|
||||
* @param arguments a list of arguments
|
||||
* @param nonNullBoolean true to have {@link #nextBoolean()} return false instead of null
|
||||
*/
|
||||
public StringArgumentStack(
|
||||
CommandContext context, String[] arguments, boolean nonNullBoolean) {
|
||||
this.context = context;
|
||||
this.arguments = arguments;
|
||||
this.nonNullBoolean = nonNullBoolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance using the given context.
|
||||
*
|
||||
* @param context the context
|
||||
* @param arguments an argument string to be parsed
|
||||
* @param nonNullBoolean true to have {@link #nextBoolean()} return false instead of null
|
||||
*/
|
||||
public StringArgumentStack(
|
||||
CommandContext context, String arguments, boolean nonNullBoolean) {
|
||||
this.context = context;
|
||||
this.arguments = CommandContext.split(arguments);
|
||||
this.nonNullBoolean = nonNullBoolean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next() throws ParameterException {
|
||||
try {
|
||||
return arguments[index++];
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new MissingParameterException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer nextInt() throws ParameterException {
|
||||
try {
|
||||
return Integer.parseInt(next());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ParameterException(
|
||||
"Expected a number, got '" + context.getString(index - 1) + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double nextDouble() throws ParameterException {
|
||||
try {
|
||||
return Double.parseDouble(next());
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ParameterException(
|
||||
"Expected a number, got '" + context.getString(index - 1) + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean nextBoolean() throws ParameterException {
|
||||
try {
|
||||
return next().equalsIgnoreCase("true");
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
if (nonNullBoolean) { // Special case
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new MissingParameterException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String remaining() throws ParameterException {
|
||||
try {
|
||||
String value = StringUtil.joinString(arguments, " ", index);
|
||||
markConsumed();
|
||||
return value;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new MissingParameterException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markConsumed() {
|
||||
index = arguments.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren