mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-06 04:46:40 +00:00
Switch to Gradle. Use git log --follow for history.
This converts the project into a multi-module Gradle build. By default, Git does not show history past a rename, so use git log --follow to see further history.
This commit is contained in:
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* This annotation indicates a command. Methods should be marked with this
|
||||
* annotation to tell {@link CommandsManager} that the method is a command.
|
||||
* Note that the method name can actually be anything.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Command {
|
||||
|
||||
/**
|
||||
* A list of aliases for the command. The first alias is the most
|
||||
* important -- it is the main name of the command. (The method name
|
||||
* is never used for anything).
|
||||
*
|
||||
* @return Aliases for a command
|
||||
*/
|
||||
String[] aliases();
|
||||
|
||||
/**
|
||||
* Usage instruction. Example text for usage could be
|
||||
* {@code [-h harps] [name] [message]}.
|
||||
*
|
||||
* @return Usage instructions for a command
|
||||
*/
|
||||
String usage() default "";
|
||||
|
||||
/**
|
||||
* @return A short description for the command.
|
||||
*/
|
||||
String desc();
|
||||
|
||||
/**
|
||||
* The minimum number of arguments. This should be 0 or above.
|
||||
*
|
||||
* @return the minimum number of arguments
|
||||
*/
|
||||
int min() default 0;
|
||||
|
||||
/**
|
||||
* The maximum number of arguments. Use -1 for an unlimited number
|
||||
* of arguments.
|
||||
*
|
||||
* @return the maximum number of arguments
|
||||
*/
|
||||
int max() default -1;
|
||||
|
||||
/**
|
||||
* Flags allow special processing for flags such as -h in the command,
|
||||
* allowing users to easily turn on a flag. This is a string with
|
||||
* each character being a flag. Use A-Z and a-z as possible flags.
|
||||
* Appending a flag with a : makes the flag character before a value flag,
|
||||
* meaning that if it is given it must have a value
|
||||
*
|
||||
* @return Flags matching a-zA-Z
|
||||
*/
|
||||
String flags() default "";
|
||||
|
||||
/**
|
||||
* @return A long description for the command.
|
||||
*/
|
||||
String help() default "";
|
||||
|
||||
/**
|
||||
* Get whether any flag can be used.
|
||||
*
|
||||
* @return true if so
|
||||
*/
|
||||
boolean anyFlags() default false;
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Any command with this annotation will run the raw command as shown in the
|
||||
* thing, as long as it is registered in the current {@link CommandsManager}.
|
||||
* Mostly to move commands around without breaking things.
|
||||
*/
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CommandAlias {
|
||||
|
||||
/**
|
||||
* Get the raw {@link CommandsManager}-formatted command arg array to run
|
||||
*
|
||||
* @return the command
|
||||
*/
|
||||
String[] value();
|
||||
}
|
@ -0,0 +1,339 @@
|
||||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
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(" ", -1), null);
|
||||
}
|
||||
|
||||
public CommandContext(String[] args) throws CommandException {
|
||||
this(args, null);
|
||||
}
|
||||
|
||||
public CommandContext(String args, Set<Character> valueFlags) throws CommandException {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
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.isEmpty()) {
|
||||
isHanging = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
argIndexList.add(i);
|
||||
|
||||
switch (arg.charAt(0)) {
|
||||
case '\'':
|
||||
case '"':
|
||||
final StringBuilder build = new StringBuilder();
|
||||
final char quotedChar = arg.charAt(0);
|
||||
|
||||
int endIndex;
|
||||
for (endIndex = i; endIndex < args.length; ++endIndex) {
|
||||
final String arg2 = args[endIndex];
|
||||
if (arg2.charAt(arg2.length() - 1) == quotedChar && arg2.length() > 1) {
|
||||
if (endIndex != i) build.append(' ');
|
||||
build.append(arg2.substring(endIndex == i ? 1 : 0, arg2.length() - 1));
|
||||
break;
|
||||
} else if (endIndex == i) {
|
||||
build.append(arg2.substring(1));
|
||||
} else {
|
||||
build.append(' ').append(arg2);
|
||||
}
|
||||
}
|
||||
|
||||
if (endIndex < args.length) {
|
||||
arg = build.toString();
|
||||
i = endIndex;
|
||||
}
|
||||
|
||||
// In case there is an empty quoted string
|
||||
if (arg.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// else raise exception about hanging quotes?
|
||||
}
|
||||
argList.add(arg);
|
||||
}
|
||||
|
||||
// Then flags
|
||||
|
||||
this.originalArgIndices = new ArrayList<Integer>(argIndexList.size());
|
||||
this.parsedArgs = new ArrayList<String>(argList.size());
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Handle flag parsing terminator --
|
||||
if (arg.equals("--")) {
|
||||
while (nextArg < argList.size()) {
|
||||
originalArgIndices.add(argIndexList.get(nextArg));
|
||||
parsedArgs.add(argList.get(nextArg++));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Go through the flag characters
|
||||
for (int i = 1; i < arg.length(); ++i) {
|
||||
char flagName = arg.charAt(i);
|
||||
|
||||
if (valueFlags.contains(flagName)) {
|
||||
if (this.valueFlags.containsKey(flagName)) {
|
||||
throw new CommandException("Value flag '" + flagName + "' already given");
|
||||
}
|
||||
|
||||
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() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public boolean matches(String command) {
|
||||
return this.command.equalsIgnoreCase(command);
|
||||
}
|
||||
|
||||
public String getString(int index) {
|
||||
return parsedArgs.get(index);
|
||||
}
|
||||
|
||||
public String getString(int index, String def) {
|
||||
return index < parsedArgs.size() ? parsedArgs.get(index) : def;
|
||||
}
|
||||
|
||||
public String getJoinedStrings(int initialIndex) {
|
||||
initialIndex = originalArgIndices.get(initialIndex);
|
||||
StringBuilder buffer = new StringBuilder(originalArgs[initialIndex]);
|
||||
for (int i = initialIndex + 1; i < originalArgs.length; ++i) {
|
||||
buffer.append(" ").append(originalArgs[i]);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
public int getInteger(int index, int def) throws NumberFormatException {
|
||||
return index < parsedArgs.size() ? Integer.parseInt(parsedArgs.get(index)) : def;
|
||||
}
|
||||
|
||||
public double getDouble(int index) throws NumberFormatException {
|
||||
return Double.parseDouble(parsedArgs.get(index));
|
||||
}
|
||||
|
||||
public double getDouble(int index, double def) throws NumberFormatException {
|
||||
return index < parsedArgs.size() ? Double.parseDouble(parsedArgs.get(index)) : def;
|
||||
}
|
||||
|
||||
public String[] getSlice(int index) {
|
||||
String[] slice = new String[originalArgs.length - index];
|
||||
System.arraycopy(originalArgs, index, slice, 0, originalArgs.length - index);
|
||||
return slice;
|
||||
}
|
||||
|
||||
public String[] getPaddedSlice(int index, int padding) {
|
||||
String[] slice = new String[originalArgs.length - index + padding];
|
||||
System.arraycopy(originalArgs, index, slice, padding, originalArgs.length - index);
|
||||
return slice;
|
||||
}
|
||||
|
||||
public String[] getParsedSlice(int index) {
|
||||
String[] slice = new String[parsedArgs.size() - index];
|
||||
System.arraycopy(parsedArgs.toArray(new String[parsedArgs.size()]), index, slice, 0, parsedArgs.size() - index);
|
||||
return slice;
|
||||
}
|
||||
|
||||
public String[] getParsedPaddedSlice(int index, int padding) {
|
||||
String[] slice = new String[parsedArgs.size() - index + padding];
|
||||
System.arraycopy(parsedArgs.toArray(new String[parsedArgs.size()]), index, slice, padding, parsedArgs.size() - index);
|
||||
return slice;
|
||||
}
|
||||
|
||||
public boolean hasFlag(char ch) {
|
||||
return booleanFlags.contains(ch) || valueFlags.containsKey(ch);
|
||||
}
|
||||
|
||||
public Set<Character> getFlags() {
|
||||
return booleanFlags;
|
||||
}
|
||||
|
||||
public Map<Character, String> getValueFlags() {
|
||||
return valueFlags;
|
||||
}
|
||||
|
||||
public String getFlag(char ch) {
|
||||
return valueFlags.get(ch);
|
||||
}
|
||||
|
||||
public String getFlag(char ch, String def) {
|
||||
final String value = valueFlags.get(ch);
|
||||
if (value == null) {
|
||||
return def;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public int getFlagInteger(char ch) throws NumberFormatException {
|
||||
return Integer.parseInt(valueFlags.get(ch));
|
||||
}
|
||||
|
||||
public int getFlagInteger(char ch, int def) throws NumberFormatException {
|
||||
final String value = valueFlags.get(ch);
|
||||
if (value == null) {
|
||||
return def;
|
||||
}
|
||||
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
public double getFlagDouble(char ch) throws NumberFormatException {
|
||||
return Double.parseDouble(valueFlags.get(ch));
|
||||
}
|
||||
|
||||
public double getFlagDouble(char ch, double def) throws NumberFormatException {
|
||||
final String value = valueFlags.get(ch);
|
||||
if (value == null) {
|
||||
return def;
|
||||
}
|
||||
|
||||
return Double.parseDouble(value);
|
||||
}
|
||||
|
||||
public int argsLength() {
|
||||
return parsedArgs.size();
|
||||
}
|
||||
|
||||
public CommandLocals getLocals() {
|
||||
return locals;
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class CommandException extends Exception {
|
||||
|
||||
private List<String> commandStack = new ArrayList<String>();
|
||||
|
||||
public CommandException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public CommandException(String message) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command that was called, which will include the sub-command
|
||||
* (i.e. "/br sphere").
|
||||
*
|
||||
* @param prefix the command shebang character (such as "/") -- may be empty
|
||||
* @param spacedSuffix a suffix to put at the end (optional) -- may be null
|
||||
* @return the command that was used
|
||||
*/
|
||||
public String getCommandUsed(String prefix, @Nullable String spacedSuffix) {
|
||||
checkNotNull(prefix);
|
||||
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().trim();
|
||||
}
|
||||
|
||||
}
|
@ -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,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.minecraft.util.commands;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Indicates a list of permissions that should be checked.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CommandPermissions {
|
||||
|
||||
/**
|
||||
* A list of permissions. Only one permission has to be met
|
||||
* for the command to be permitted.
|
||||
*
|
||||
* @return a list of permissions strings
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Thrown when not enough permissions are satisfied.
|
||||
*/
|
||||
public class CommandPermissionsException extends CommandException {
|
||||
|
||||
}
|
@ -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.minecraft.util.commands;
|
||||
|
||||
public class CommandUsageException extends CommandException {
|
||||
|
||||
protected String usage;
|
||||
|
||||
public CommandUsageException(String message, String usage) {
|
||||
super(message);
|
||||
this.usage = usage;
|
||||
}
|
||||
|
||||
public String getUsage() {
|
||||
return usage;
|
||||
}
|
||||
}
|
@ -0,0 +1,591 @@
|
||||
/*
|
||||
* 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 com.sk89q.util.StringUtil;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Manager for handling commands. This allows you to easily process commands,
|
||||
* including nested commands, by correctly annotating methods of a class.
|
||||
*
|
||||
* <p>To use this, it is merely a matter of registering classes containing
|
||||
* the commands (as methods with the proper annotations) with the
|
||||
* manager. When you want to process a command, use one of the
|
||||
* {@code execute} methods. If something is wrong, such as incorrect
|
||||
* usage, insufficient permissions, or a missing command altogether, an
|
||||
* exception will be raised for upstream handling.</p>
|
||||
*
|
||||
* <p>Methods of a class to be registered can be static, but if an injector
|
||||
* is registered with the class, the instances of the command classes
|
||||
* will be created automatically and methods will be called non-statically.</p>
|
||||
*
|
||||
* <p>To mark a method as a command, use {@link Command}. For nested commands,
|
||||
* see {@link NestedCommand}. To handle permissions, use
|
||||
* {@link CommandPermissions}.</p>
|
||||
*
|
||||
* <p>This uses Java reflection extensively, but to reduce the overhead of
|
||||
* reflection, command lookups are completely cached on registration. This
|
||||
* allows for fast command handling. Method invocation still has to be done
|
||||
* with reflection, but this is quite fast in that of itself.</p>
|
||||
*
|
||||
* @param <T> command sender class
|
||||
*/
|
||||
@SuppressWarnings("ProtectedField")
|
||||
public abstract class CommandsManager<T> {
|
||||
|
||||
protected static final Logger logger =
|
||||
Logger.getLogger(CommandsManager.class.getCanonicalName());
|
||||
|
||||
/**
|
||||
* Mapping of commands (including aliases) with a description. Root
|
||||
* commands are stored under a key of null, whereas child commands are
|
||||
* cached under their respective {@link Method}. The child map has
|
||||
* the key of the command name (one for each alias) with the
|
||||
* method.
|
||||
*/
|
||||
protected Map<Method, Map<String, Method>> commands = new HashMap<Method, Map<String, Method>>();
|
||||
|
||||
/**
|
||||
* Used to store the instances associated with a method.
|
||||
*/
|
||||
protected Map<Method, Object> instances = new HashMap<Method, Object>();
|
||||
|
||||
/**
|
||||
* Mapping of commands (not including aliases) with a description. This
|
||||
* is only for top level commands.
|
||||
*/
|
||||
protected Map<String, String> descs = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Stores the injector used to getInstance.
|
||||
*/
|
||||
protected Injector injector;
|
||||
|
||||
/**
|
||||
* Mapping of commands (not including aliases) with a description. This
|
||||
* is only for top level commands.
|
||||
*/
|
||||
protected Map<String, String> helpMessages = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Register an class that contains commands (denoted by {@link Command}.
|
||||
* If no dependency injector is specified, then the methods of the
|
||||
* class will be registered to be called statically. Otherwise, new
|
||||
* instances will be created of the command classes and methods will
|
||||
* not be called statically.
|
||||
*
|
||||
* @param cls the class to register
|
||||
*/
|
||||
public void register(Class<?> cls) {
|
||||
registerMethods(cls, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an class that contains commands (denoted by {@link Command}.
|
||||
* If no dependency injector is specified, then the methods of the
|
||||
* class will be registered to be called statically. Otherwise, new
|
||||
* instances will be created of the command classes and methods will
|
||||
* not be called statically. A List of {@link Command} annotations from
|
||||
* registered commands is returned.
|
||||
*
|
||||
* @param cls the class to register
|
||||
* @return A List of {@link Command} annotations from registered commands,
|
||||
* for use in eg. a dynamic command registration system.
|
||||
*/
|
||||
public List<Command> registerAndReturn(Class<?> cls) {
|
||||
return registerMethods(cls, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the methods of a class. This will automatically construct
|
||||
* instances as necessary.
|
||||
*
|
||||
* @param cls the class to register
|
||||
* @param parent the parent method
|
||||
* @return Commands Registered
|
||||
*/
|
||||
public List<Command> registerMethods(Class<?> cls, Method parent) {
|
||||
try {
|
||||
if (getInjector() == null) {
|
||||
return registerMethods(cls, parent, null);
|
||||
} else {
|
||||
Object obj = getInjector().getInstance(cls);
|
||||
return registerMethods(cls, parent, obj);
|
||||
}
|
||||
} catch (InvocationTargetException e) {
|
||||
logger.log(Level.SEVERE, "Failed to register commands", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.log(Level.SEVERE, "Failed to register commands", e);
|
||||
} catch (InstantiationException e) {
|
||||
logger.log(Level.SEVERE, "Failed to register commands", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the methods of a class.
|
||||
*
|
||||
* @param cls the class to register
|
||||
* @param parent the parent method
|
||||
* @param obj the object whose methods will become commands if they are annotated
|
||||
* @return a list of commands
|
||||
*/
|
||||
private List<Command> registerMethods(Class<?> cls, Method parent, Object obj) {
|
||||
Map<String, Method> map;
|
||||
List<Command> registered = new ArrayList<Command>();
|
||||
|
||||
// Make a new hash map to cache the commands for this class
|
||||
// as looking up methods via reflection is fairly slow
|
||||
if (commands.containsKey(parent)) {
|
||||
map = commands.get(parent);
|
||||
} else {
|
||||
map = new HashMap<String, Method>();
|
||||
commands.put(parent, map);
|
||||
}
|
||||
|
||||
for (Method method : cls.getMethods()) {
|
||||
if (!method.isAnnotationPresent(Command.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean isStatic = Modifier.isStatic(method.getModifiers());
|
||||
|
||||
Command cmd = method.getAnnotation(Command.class);
|
||||
|
||||
// Cache the aliases too
|
||||
for (String alias : cmd.aliases()) {
|
||||
map.put(alias, method);
|
||||
}
|
||||
|
||||
// We want to be able invoke with an instance
|
||||
if (!isStatic) {
|
||||
// Can't register this command if we don't have an instance
|
||||
if (obj == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
instances.put(method, obj);
|
||||
}
|
||||
|
||||
// Build a list of commands and their usage details, at least for
|
||||
// root level commands
|
||||
if (parent == null) {
|
||||
final String commandName = cmd.aliases()[0];
|
||||
final String desc = cmd.desc();
|
||||
|
||||
final String usage = cmd.usage();
|
||||
if (usage.isEmpty()) {
|
||||
descs.put(commandName, desc);
|
||||
} else {
|
||||
descs.put(commandName, usage + " - " + desc);
|
||||
}
|
||||
|
||||
String help = cmd.help();
|
||||
if (help.isEmpty()) {
|
||||
help = desc;
|
||||
}
|
||||
|
||||
final CharSequence arguments = getArguments(cmd);
|
||||
for (String alias : cmd.aliases()) {
|
||||
final String helpMessage = "/" + alias + " " + arguments + "\n\n" + help;
|
||||
final String key = alias.replaceAll("/", "");
|
||||
String previous = helpMessages.put(key, helpMessage);
|
||||
|
||||
if (previous != null && !previous.replaceAll("^/[^ ]+ ", "").equals(helpMessage.replaceAll("^/[^ ]+ ", ""))) {
|
||||
helpMessages.put(key, previous + "\n\n" + helpMessage);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add the command to the registered command list for return
|
||||
registered.add(cmd);
|
||||
|
||||
// Look for nested commands -- if there are any, those have
|
||||
// to be cached too so that they can be quickly looked
|
||||
// up when processing commands
|
||||
if (method.isAnnotationPresent(NestedCommand.class)) {
|
||||
NestedCommand nestedCmd = method.getAnnotation(NestedCommand.class);
|
||||
|
||||
for (Class<?> nestedCls : nestedCmd.value()) {
|
||||
registerMethods(nestedCls, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cls.getSuperclass() != null) {
|
||||
registerMethods(cls.getSuperclass(), parent, obj);
|
||||
}
|
||||
|
||||
return registered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see whether there is a command named such at the root level.
|
||||
* This will check aliases as well.
|
||||
*
|
||||
* @param command the command
|
||||
* @return true if the command exists
|
||||
*/
|
||||
public boolean hasCommand(String command) {
|
||||
return commands.get(null).containsKey(command.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of command descriptions. This is only for root commands.
|
||||
*
|
||||
* @return a map of commands
|
||||
*/
|
||||
public Map<String, String> getCommands() {
|
||||
return descs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mapping of methods under a parent command.
|
||||
*
|
||||
* @return the mapping
|
||||
*/
|
||||
public Map<Method, Map<String, Method>> getMethods() {
|
||||
return commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map from command name to help message. This is only for root commands.
|
||||
*
|
||||
* @return a map of help messages for each command
|
||||
*/
|
||||
public Map<String, String> getHelpMessages() {
|
||||
return helpMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the usage string for a command.
|
||||
*
|
||||
* @param args the arguments
|
||||
* @param level the depth of the command
|
||||
* @param cmd the command annotation
|
||||
* @return the usage string
|
||||
*/
|
||||
protected String getUsage(String[] args, int level, Command cmd) {
|
||||
final StringBuilder command = new StringBuilder();
|
||||
|
||||
command.append('/');
|
||||
|
||||
for (int i = 0; i <= level; ++i) {
|
||||
command.append(args[i]);
|
||||
command.append(' ');
|
||||
}
|
||||
command.append(getArguments(cmd));
|
||||
|
||||
final String help = cmd.help();
|
||||
if (!help.isEmpty()) {
|
||||
command.append("\n\n");
|
||||
command.append(help);
|
||||
}
|
||||
|
||||
return command.toString();
|
||||
}
|
||||
|
||||
protected CharSequence getArguments(Command cmd) {
|
||||
final String flags = cmd.flags();
|
||||
|
||||
final StringBuilder command2 = new StringBuilder();
|
||||
if (!flags.isEmpty()) {
|
||||
String flagString = flags.replaceAll(".:", "");
|
||||
if (!flagString.isEmpty()) {
|
||||
command2.append("[-");
|
||||
for (int i = 0; i < flagString.length(); ++i) {
|
||||
command2.append(flagString.charAt(i));
|
||||
}
|
||||
command2.append("] ");
|
||||
}
|
||||
}
|
||||
|
||||
command2.append(cmd.usage());
|
||||
|
||||
return command2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the usage string for a nested command.
|
||||
*
|
||||
* @param args the arguments
|
||||
* @param level the depth of the command
|
||||
* @param method the parent method
|
||||
* @param player the player
|
||||
* @return the usage string
|
||||
* @throws CommandException on some error
|
||||
*/
|
||||
protected String getNestedUsage(String[] args, int level, Method method, T player) throws CommandException {
|
||||
StringBuilder command = new StringBuilder();
|
||||
|
||||
command.append("/");
|
||||
|
||||
for (int i = 0; i <= level; ++i) {
|
||||
command.append(args[i]).append(" ");
|
||||
}
|
||||
|
||||
Map<String, Method> map = commands.get(method);
|
||||
boolean found = false;
|
||||
|
||||
command.append("<");
|
||||
|
||||
Set<String> allowedCommands = new HashSet<String>();
|
||||
|
||||
for (Map.Entry<String, Method> entry : map.entrySet()) {
|
||||
Method childMethod = entry.getValue();
|
||||
found = true;
|
||||
|
||||
if (hasPermission(childMethod, player)) {
|
||||
Command childCmd = childMethod.getAnnotation(Command.class);
|
||||
|
||||
allowedCommands.add(childCmd.aliases()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!allowedCommands.isEmpty()) {
|
||||
command.append(StringUtil.joinString(allowedCommands, "|", 0));
|
||||
} else {
|
||||
if (!found) {
|
||||
command.append("?");
|
||||
} else {
|
||||
//command.append("action");
|
||||
throw new CommandPermissionsException();
|
||||
}
|
||||
}
|
||||
|
||||
command.append(">");
|
||||
|
||||
return command.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to execute a command. This version takes a separate command
|
||||
* name (for the root command) and then a list of following arguments.
|
||||
*
|
||||
* @param cmd command to run
|
||||
* @param args arguments
|
||||
* @param player command source
|
||||
* @param methodArgs method arguments
|
||||
* @throws CommandException thrown when the command throws an error
|
||||
*/
|
||||
public void execute(String cmd, String[] args, T player, Object... methodArgs) throws CommandException {
|
||||
|
||||
String[] newArgs = new String[args.length + 1];
|
||||
System.arraycopy(args, 0, newArgs, 1, args.length);
|
||||
newArgs[0] = cmd;
|
||||
Object[] newMethodArgs = new Object[methodArgs.length + 1];
|
||||
System.arraycopy(methodArgs, 0, newMethodArgs, 1, methodArgs.length);
|
||||
|
||||
executeMethod(null, newArgs, player, newMethodArgs, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to execute a command.
|
||||
*
|
||||
* @param args the arguments
|
||||
* @param player the player
|
||||
* @param methodArgs the arguments for the method
|
||||
* @throws CommandException thrown on command error
|
||||
*/
|
||||
public void execute(String[] args, T player, Object... methodArgs) throws CommandException {
|
||||
Object[] newMethodArgs = new Object[methodArgs.length + 1];
|
||||
System.arraycopy(methodArgs, 0, newMethodArgs, 1, methodArgs.length);
|
||||
executeMethod(null, args, player, newMethodArgs, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to execute a command.
|
||||
*
|
||||
* @param parent the parent method
|
||||
* @param args an array of arguments
|
||||
* @param player the player
|
||||
* @param methodArgs the array of method arguments
|
||||
* @param level the depth of the command
|
||||
* @throws CommandException thrown on a command error
|
||||
*/
|
||||
public void executeMethod(Method parent, String[] args, T player, Object[] methodArgs, int level) throws CommandException {
|
||||
String cmdName = args[level];
|
||||
|
||||
Map<String, Method> map = commands.get(parent);
|
||||
Method method = map.get(cmdName.toLowerCase());
|
||||
|
||||
if (method == null) {
|
||||
if (parent == null) { // Root
|
||||
throw new UnhandledCommandException();
|
||||
} else {
|
||||
throw new MissingNestedCommandException("Unknown command: " + cmdName,
|
||||
getNestedUsage(args, level - 1, parent, player));
|
||||
}
|
||||
}
|
||||
|
||||
checkPermission(player, method);
|
||||
|
||||
int argsCount = args.length - 1 - level;
|
||||
|
||||
// checks if we need to execute the body of the nested command method (false)
|
||||
// or display the help what commands are available (true)
|
||||
// this is all for an args count of 0 if it is > 0 and a NestedCommand Annotation is present
|
||||
// it will always handle the methods that NestedCommand points to
|
||||
// e.g.:
|
||||
// - /cmd - @NestedCommand(executeBody = true) will go into the else loop and execute code in that method
|
||||
// - /cmd <arg1> <arg2> - @NestedCommand(executeBody = true) will always go to the nested command class
|
||||
// - /cmd <arg1> - @NestedCommand(executeBody = false) will always go to the nested command class not matter the args
|
||||
boolean executeNested = method.isAnnotationPresent(NestedCommand.class)
|
||||
&& (argsCount > 0 || !method.getAnnotation(NestedCommand.class).executeBody());
|
||||
|
||||
if (executeNested) {
|
||||
if (argsCount == 0) {
|
||||
throw new MissingNestedCommandException("Sub-command required.",
|
||||
getNestedUsage(args, level, method, player));
|
||||
} else {
|
||||
executeMethod(method, args, player, methodArgs, level + 1);
|
||||
}
|
||||
} else if (method.isAnnotationPresent(CommandAlias.class)) {
|
||||
CommandAlias aCmd = method.getAnnotation(CommandAlias.class);
|
||||
executeMethod(parent, aCmd.value(), player, methodArgs, level);
|
||||
} else {
|
||||
Command cmd = method.getAnnotation(Command.class);
|
||||
|
||||
String[] newArgs = new String[args.length - level];
|
||||
System.arraycopy(args, level, newArgs, 0, args.length - level);
|
||||
|
||||
final Set<Character> valueFlags = new HashSet<Character>();
|
||||
|
||||
char[] flags = cmd.flags().toCharArray();
|
||||
Set<Character> newFlags = new HashSet<Character>();
|
||||
for (int i = 0; i < flags.length; ++i) {
|
||||
if (flags.length > i + 1 && flags[i + 1] == ':') {
|
||||
valueFlags.add(flags[i]);
|
||||
++i;
|
||||
}
|
||||
newFlags.add(flags[i]);
|
||||
}
|
||||
|
||||
CommandContext context = new CommandContext(newArgs, valueFlags);
|
||||
|
||||
if (context.argsLength() < cmd.min()) {
|
||||
throw new CommandUsageException("Too few arguments.", getUsage(args, level, cmd));
|
||||
}
|
||||
|
||||
if (cmd.max() != -1 && context.argsLength() > cmd.max()) {
|
||||
throw new CommandUsageException("Too many arguments.", getUsage(args, level, cmd));
|
||||
}
|
||||
|
||||
if (!cmd.anyFlags()) {
|
||||
for (char flag : context.getFlags()) {
|
||||
if (!newFlags.contains(flag)) {
|
||||
throw new CommandUsageException("Unknown flag: " + flag, getUsage(args, level, cmd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
methodArgs[0] = context;
|
||||
|
||||
Object instance = instances.get(method);
|
||||
|
||||
invokeMethod(parent, args, player, method, instance, methodArgs, argsCount);
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkPermission(T player, Method method) throws CommandException {
|
||||
if (!hasPermission(method, player)) {
|
||||
throw new CommandPermissionsException();
|
||||
}
|
||||
}
|
||||
|
||||
public void invokeMethod(Method parent, String[] args, T player, Method method, Object instance, Object[] methodArgs, int level) throws CommandException {
|
||||
try {
|
||||
method.invoke(instance, methodArgs);
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.log(Level.SEVERE, "Failed to execute command", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
logger.log(Level.SEVERE, "Failed to execute command", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof CommandException) {
|
||||
throw (CommandException) e.getCause();
|
||||
}
|
||||
|
||||
throw new WrappedCommandException(e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a player has access to a command.
|
||||
*
|
||||
* @param method the method
|
||||
* @param player the player
|
||||
* @return true if permission is granted
|
||||
*/
|
||||
protected boolean hasPermission(Method method, T player) {
|
||||
CommandPermissions perms = method.getAnnotation(CommandPermissions.class);
|
||||
if (perms == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (String perm : perms.value()) {
|
||||
if (hasPermission(player, perm)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a player permission..
|
||||
*
|
||||
* @param player the player
|
||||
* @param permission the permission
|
||||
* @return true if permission is granted
|
||||
*/
|
||||
public abstract boolean hasPermission(T player, String permission);
|
||||
|
||||
/**
|
||||
* Get the injector used to create new instances. This can be
|
||||
* null, in which case only classes will be registered statically.
|
||||
*
|
||||
* @return an injector instance
|
||||
*/
|
||||
public Injector getInjector() {
|
||||
return injector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the injector for creating new instances.
|
||||
*
|
||||
* @param injector injector or null
|
||||
*/
|
||||
public void setInjector(Injector injector) {
|
||||
this.injector = injector;
|
||||
}
|
||||
}
|
@ -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.minecraft.util.commands;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* This annotation indicates that a command can be used from the console.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Console {
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* Constructs new instances.
|
||||
*/
|
||||
public interface Injector {
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the given class.
|
||||
*
|
||||
* @param cls class
|
||||
* @return object
|
||||
* @throws IllegalAccessException thrown on injection fault
|
||||
* @throws InstantiationException thrown on injection fault
|
||||
* @throws InvocationTargetException thrown on injection fault
|
||||
*/
|
||||
public Object getInstance(Class<?> cls) throws InvocationTargetException, IllegalAccessException, InstantiationException;
|
||||
|
||||
}
|
@ -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/>.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
|
||||
package com.sk89q.minecraft.util.commands;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Indicates how the affected blocks should be hinted at in the log.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Logging {
|
||||
|
||||
public enum LogMode {
|
||||
/**
|
||||
* Player position
|
||||
*/
|
||||
POSITION,
|
||||
|
||||
/**
|
||||
* Region selection
|
||||
*/
|
||||
REGION,
|
||||
|
||||
/**
|
||||
* Player orientation and region selection
|
||||
*/
|
||||
ORIENTATION_REGION,
|
||||
|
||||
/**
|
||||
* Either the player position or pos1, depending on the placeAtPos1 flag
|
||||
*/
|
||||
PLACEMENT,
|
||||
|
||||
/**
|
||||
* Log all information available
|
||||
*/
|
||||
ALL
|
||||
}
|
||||
|
||||
/**
|
||||
* Log mode.
|
||||
*
|
||||
* @return either POSITION, REGION, ORIENTATION_REGION, PLACEMENT or ALL
|
||||
*/
|
||||
LogMode value();
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 MissingNestedCommandException extends CommandUsageException {
|
||||
|
||||
public MissingNestedCommandException(String message, String usage) {
|
||||
super(message, usage);
|
||||
}
|
||||
|
||||
}
|
@ -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.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Indicates a nested command. Mark methods with this annotation to tell
|
||||
* {@link CommandsManager} that a method is merely a shell for child
|
||||
* commands. Note that the body of a method marked with this annotation
|
||||
* will never called. Additionally, not all fields of {@link Command} apply
|
||||
* when it is used in conjunction with this annotation, although both
|
||||
* are still required.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NestedCommand {
|
||||
|
||||
/**
|
||||
* A list of classes with the child commands.
|
||||
*
|
||||
* @return a list of classes
|
||||
*/
|
||||
Class<?>[] value();
|
||||
|
||||
/**
|
||||
* If set to true it will execute the body of the tagged method.
|
||||
*
|
||||
* @return true to execute the body of the annotated method
|
||||
*/
|
||||
boolean executeBody() default false;
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class SimpleInjector implements Injector {
|
||||
|
||||
private static final Logger log = Logger.getLogger(SimpleInjector.class.getCanonicalName());
|
||||
private Object[] args;
|
||||
private Class<?>[] argClasses;
|
||||
|
||||
public SimpleInjector(Object... args) {
|
||||
this.args = args;
|
||||
argClasses = new Class[args.length];
|
||||
for (int i = 0; i < args.length; ++i) {
|
||||
argClasses[i] = args[i].getClass();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getInstance(Class<?> clazz) {
|
||||
try {
|
||||
Constructor<?> ctr = clazz.getConstructor(argClasses);
|
||||
ctr.setAccessible(true);
|
||||
return ctr.newInstance(args);
|
||||
} catch (NoSuchMethodException e) {
|
||||
log.log(Level.SEVERE, "Error initializing commands class " + clazz, e);
|
||||
return null;
|
||||
} catch (InvocationTargetException e) {
|
||||
log.log(Level.SEVERE, "Error initializing commands class " + clazz, e);
|
||||
return null;
|
||||
} catch (InstantiationException e) {
|
||||
log.log(Level.SEVERE, "Error initializing commands class " + clazz, e);
|
||||
return null;
|
||||
} catch (IllegalAccessException e) {
|
||||
log.log(Level.SEVERE, "Error initializing commands class " + clazz, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 UnhandledCommandException extends CommandException {
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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 WrappedCommandException extends CommandException {
|
||||
|
||||
public WrappedCommandException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user