Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-05 02:50:05 +01:00
Binding improvements
WIP towards deprecating parsers and unifying the command bindings Allow registering dynamic bindings - Supports nesting bindings
Dieser Commit ist enthalten in:
Ursprung
6e6a3f9035
Commit
ff67f6343f
@ -1,13 +1,12 @@
|
||||
package com.boydti.fawe.command;
|
||||
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.internal.command.WorldEditBinding;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingHelper;
|
||||
|
||||
public class FaweBinding extends WorldEditBinding {
|
||||
public class FaweBinding extends BindingHelper {
|
||||
private final WorldEdit worldEdit;
|
||||
|
||||
public FaweBinding(WorldEdit worldEdit) {
|
||||
super(worldEdit);
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ import java.net.URI;
|
||||
import java.net.URL;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FawePrimitiveBinding extends BindingHelper {
|
||||
public class FawePrimitiveBinding {
|
||||
@BindingMatch(type = {Long.class, long.class},
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1,
|
||||
|
@ -4,8 +4,6 @@ import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterData;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -35,4 +35,4 @@ public class CircleBrush implements Brush {
|
||||
Vector3 random = affine.apply(normal);
|
||||
return random.cross(normal).normalize();
|
||||
}
|
||||
}
|
||||
}
|
@ -98,7 +98,6 @@ public class FaweSchematicHandler extends SchematicHandler {
|
||||
if (tag instanceof CompressedCompoundTag) {
|
||||
CompressedCompoundTag cTag = (CompressedCompoundTag) tag;
|
||||
if (cTag instanceof CompressedSchematicTag) {
|
||||
System.out.println("Write directly");
|
||||
Clipboard clipboard = (Clipboard) cTag.getSource();
|
||||
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new BufferedOutputStream(new PGZIPOutputStream(stream)))) {
|
||||
new SpongeSchematicWriter(output).write(clipboard);
|
||||
|
@ -19,7 +19,6 @@ public class CompressedSchematicTag extends CompressedCompoundTag<Clipboard> {
|
||||
|
||||
@Override
|
||||
public DataInputStream adapt(Clipboard src) throws IOException {
|
||||
System.out.println("Decompress");
|
||||
FastByteArrayOutputStream blocksOut = new FastByteArrayOutputStream();
|
||||
try (LZ4BlockOutputStream lz4out = new LZ4BlockOutputStream(blocksOut)) {
|
||||
NBTOutputStream nbtOut = new NBTOutputStream(lz4out);
|
||||
|
@ -64,7 +64,7 @@ import java.util.List;
|
||||
/**
|
||||
* Binds standard WorldEdit classes such as {@link Player} and {@link LocalSession}.
|
||||
*/
|
||||
public class WorldEditBinding extends BindingHelper {
|
||||
public class WorldEditBinding {
|
||||
|
||||
private final WorldEdit worldEdit;
|
||||
|
||||
|
@ -32,12 +32,14 @@ import java.lang.annotation.Annotation;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.sk89q.worldedit.util.command.parametric.BindingHelper.validate;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
public final class PrimitiveBindings {
|
||||
|
||||
/**
|
||||
* Gets a type from a {@link ArgumentStack}.
|
||||
@ -206,89 +208,4 @@ public final class PrimitiveBindings extends BindingHelper {
|
||||
}
|
||||
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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -24,11 +24,17 @@ import com.sk89q.worldedit.util.command.parametric.ArgumentStack;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingBehavior;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingHelper;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingMatch;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterException;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import static com.sk89q.worldedit.util.command.parametric.BindingHelper.validate;
|
||||
|
||||
/**
|
||||
* Standard bindings that should be available to most configurations.
|
||||
*/
|
||||
public final class StandardBindings extends BindingHelper {
|
||||
public final class StandardBindings {
|
||||
|
||||
/**
|
||||
* Gets a {@link CommandContext} from a {@link ArgumentStack}.
|
||||
@ -42,5 +48,48 @@ public final class StandardBindings extends BindingHelper {
|
||||
context.markConsumed(); // Consume entire stack
|
||||
return context.getContext();
|
||||
}
|
||||
|
||||
@BindingMatch(
|
||||
type = Annotation[].class,
|
||||
behavior = BindingBehavior.PROVIDES,
|
||||
consumedCount = 0,
|
||||
provideModifiers = true,
|
||||
provideType = true)
|
||||
public Annotation[] getModifiers(ArgumentStack context, Annotation[] modifiers, Type type) throws ParameterException {
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
@BindingMatch(
|
||||
type = Type.class,
|
||||
behavior = BindingBehavior.PROVIDES,
|
||||
consumedCount = 0,
|
||||
provideModifiers = true,
|
||||
provideType = true)
|
||||
public Type getType(ArgumentStack context, Annotation[] modifiers, Type type) throws ParameterException {
|
||||
return type;
|
||||
}
|
||||
|
||||
@BindingMatch(
|
||||
type = Enum.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1,
|
||||
provideModifiers = true,
|
||||
provideType = true)
|
||||
public Enum getEnum(ArgumentStack context, Annotation[] modifiers, Type type) throws ParameterException {
|
||||
String input = context.next();
|
||||
Enum value;
|
||||
try {
|
||||
value = Enum.valueOf((Class<Enum>) type, input);
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
try {
|
||||
value = Enum.valueOf((Class<Enum>) type, input.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ParameterException("Invalid input " + input + " for type " + type);
|
||||
}
|
||||
}
|
||||
validate(value.ordinal(), modifiers);
|
||||
validate(input, modifiers);
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ package com.sk89q.worldedit.util.command.parametric;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.worldedit.util.command.binding.Range;
|
||||
import com.sk89q.worldedit.util.command.binding.Validate;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -48,16 +49,17 @@ import java.util.List;
|
||||
* <p>Methods may throw any exception. Exceptions may be converted using a
|
||||
* {@link ExceptionConverter} registered with the {@link ParametricBuilder}.</p>
|
||||
*/
|
||||
@Deprecated
|
||||
public class BindingHelper implements Binding {
|
||||
|
||||
private final List<BoundMethod> bindings;
|
||||
private final List<BindingMap.BoundMethod> bindings;
|
||||
private final Type[] types;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*/
|
||||
public BindingHelper() {
|
||||
List<BoundMethod> bindings = new ArrayList<>();
|
||||
List<BindingMap.BoundMethod> bindings = new ArrayList<>();
|
||||
List<Type> types = new ArrayList<>();
|
||||
|
||||
for (Method method : this.getClass().getMethods()) {
|
||||
@ -88,7 +90,7 @@ public class BindingHelper implements Binding {
|
||||
"A @BindingMatch needs either a type or classifier set");
|
||||
}
|
||||
|
||||
BoundMethod handler = new BoundMethod(info, type, classifier, method);
|
||||
BindingMap.BoundMethod handler = new BindingMap.BoundMethod(info, type, classifier, method, this);
|
||||
bindings.add(handler);
|
||||
}
|
||||
}
|
||||
@ -110,8 +112,8 @@ public class BindingHelper implements Binding {
|
||||
* @param parameter the parameter
|
||||
* @return a binding
|
||||
*/
|
||||
private BoundMethod match(ParameterData parameter) {
|
||||
for (BoundMethod binding : bindings) {
|
||||
private BindingMap.BoundMethod match(ParameterData parameter) {
|
||||
for (BindingMap.BoundMethod binding : bindings) {
|
||||
Annotation classifer = parameter.getClassifier();
|
||||
Type type = parameter.getType();
|
||||
|
||||
@ -147,7 +149,7 @@ public class BindingHelper implements Binding {
|
||||
@Override
|
||||
public Object bind(ParameterData parameter, ArgumentStack scoped,
|
||||
boolean onlyConsume) throws ParameterException, CommandException, InvocationTargetException {
|
||||
BoundMethod binding = match(parameter);
|
||||
BindingMap.BoundMethod binding = match(parameter);
|
||||
List<Object> args = new ArrayList<>();
|
||||
args.add(scoped);
|
||||
|
||||
@ -212,39 +214,88 @@ public class BindingHelper implements Binding {
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
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;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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));
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public 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
|
||||
*/
|
||||
public 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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,304 @@
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.boydti.fawe.util.ArrayUtil;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.CommandLocals;
|
||||
import com.sk89q.worldedit.util.command.CommandMapping;
|
||||
import com.sk89q.worldedit.util.command.MissingParameterException;
|
||||
import com.sk89q.worldedit.util.command.SimpleDispatcher;
|
||||
import com.sk89q.worldedit.util.command.binding.Range;
|
||||
import com.sk89q.worldedit.util.command.parametric.ArgumentStack;
|
||||
import com.sk89q.worldedit.util.command.parametric.Binding;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingBehavior;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingMatch;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterData;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterException;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParametricBuilder;
|
||||
|
||||
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.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 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 BindingMap implements Binding {
|
||||
|
||||
private final Set<Type> types;
|
||||
private final Map<Type, Binding> legacy;
|
||||
private final Map<Type, List<BoundMethod>> bindings;
|
||||
private final Map<Type, SimpleDispatcher> dynamicBindings;
|
||||
private final ParametricBuilder builder;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
* @param builder
|
||||
*/
|
||||
public BindingMap(ParametricBuilder builder) {
|
||||
this.dynamicBindings = new HashMap<>();
|
||||
this.legacy = new HashMap<>();
|
||||
this.bindings = new HashMap<>();
|
||||
this.builder = builder;
|
||||
this.types = new HashSet<>();
|
||||
|
||||
}
|
||||
|
||||
public void add(Object object, Type... requiredTypes) {
|
||||
Method[] methods = object.getClass().getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
method.setAccessible(true);
|
||||
BindingMatch info = method.getAnnotation(BindingMatch.class);
|
||||
if (info != null) {
|
||||
Class<? extends Annotation> classifier = null;
|
||||
|
||||
// Set classifier
|
||||
if (!info.classifier().equals(Annotation.class)) {
|
||||
classifier = info.classifier();
|
||||
}
|
||||
|
||||
for (Type type : info.type()) {
|
||||
if (type == Void.class) {
|
||||
type = method.getReturnType();
|
||||
}
|
||||
BoundMethod handler = new BoundMethod(info, type, classifier, method, object);
|
||||
List<BoundMethod> list = bindings.get(type);
|
||||
if (list == null) bindings.put(type, list = new ArrayList<>());
|
||||
list.add(handler);
|
||||
types.add(type);
|
||||
}
|
||||
}
|
||||
Command definition = method.getAnnotation(Command.class);
|
||||
Class<?> type = method.getReturnType();
|
||||
if (definition != null && type != null) {
|
||||
SimpleDispatcher dispatcher = dynamicBindings.get(type);
|
||||
if (dispatcher == null) dynamicBindings.put(type, dispatcher = new SimpleDispatcher());
|
||||
builder.registerMethodAsCommands(method, dispatcher, object, null);
|
||||
types.add(type);
|
||||
}
|
||||
}
|
||||
if (requiredTypes != null && requiredTypes.length > 0) {
|
||||
for (Type type : requiredTypes) {
|
||||
legacy.put(type, (Binding) object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Match a {@link BindingMatch} according to the given parameter.
|
||||
*
|
||||
* @param pd the parameter
|
||||
* @return a binding
|
||||
*/
|
||||
private BoundMethod match(ParameterData pd) {
|
||||
Type type = pd.getType();
|
||||
while (type != null) {
|
||||
List<BoundMethod> methods = bindings.get(type);
|
||||
if (methods != null) {
|
||||
for (BoundMethod binding : methods) {
|
||||
if (binding.classifier != null) {
|
||||
if (pd.getClassifier() != null && pd.getClassifier().annotationType().equals(binding.classifier)) {
|
||||
if (binding.type == null || binding.type.equals(type)) {
|
||||
return binding;
|
||||
}
|
||||
}
|
||||
} else if (binding.type.equals(type)) {
|
||||
return binding;
|
||||
}
|
||||
}
|
||||
}
|
||||
type = (type instanceof Class) ? ((Class) type).getSuperclass() : null;
|
||||
}
|
||||
throw new RuntimeException("Unknown type " + pd.getType());
|
||||
}
|
||||
|
||||
private SimpleDispatcher matchDynamic(ParameterData pd) {
|
||||
return dynamicBindings.get(pd.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getConsumedCount(ParameterData parameter) {
|
||||
return match(parameter).annotation.consumedCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BindingBehavior getBehavior(ParameterData parameter) {
|
||||
BoundMethod matched = match(parameter);
|
||||
if (matched != null) return matched.annotation.behavior();
|
||||
SimpleDispatcher dynamic = matchDynamic(parameter);
|
||||
return dynamic != null ? BindingBehavior.CONSUMES : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type[] getTypes() {
|
||||
return types.toArray(new Type[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object bind(ParameterData parameter, ArgumentStack scoped, boolean onlyConsume) throws ParameterException, CommandException, InvocationTargetException {
|
||||
BoundMethod binding = match(parameter);
|
||||
List<Object> args = new ArrayList<>();
|
||||
args.add(scoped);
|
||||
|
||||
if (binding.classifier != null) {
|
||||
args.add(parameter.getClassifier());
|
||||
}
|
||||
|
||||
if (binding.annotation.provideModifiers()) {
|
||||
args.add(parameter.getModifiers());
|
||||
}
|
||||
|
||||
if (binding.annotation.provideType()) {
|
||||
args.add(parameter.getType());
|
||||
}
|
||||
|
||||
if (onlyConsume && binding.annotation.behavior() == BindingBehavior.PROVIDES) {
|
||||
return null; // Nothing to consume, nothing to do
|
||||
}
|
||||
|
||||
if (binding.annotation.behavior() != BindingBehavior.PROVIDES) {
|
||||
SimpleDispatcher dynamic = matchDynamic(parameter);
|
||||
if (dynamic != null) {
|
||||
scoped.mark();
|
||||
String rest = scoped.remaining();
|
||||
scoped.reset();
|
||||
int start = rest.indexOf('{');
|
||||
if (start > 0) {
|
||||
int end = StringMan.findMatchingBracket(rest, start);
|
||||
if (end > start) {
|
||||
String alias = rest.substring(0, start);
|
||||
CommandMapping cmd = dynamic.get(alias);
|
||||
if (cmd != null) {
|
||||
String arguments = rest.substring(start + 1, end);
|
||||
CommandLocals locals = scoped.getContext().getLocals();
|
||||
Object result = cmd.getCallable().call(arguments, locals, new String[0]);
|
||||
int remaining = rest.length() - end;
|
||||
while (rest.length() > remaining) {
|
||||
scoped.next();
|
||||
try {
|
||||
scoped.mark();
|
||||
rest = scoped.remaining();
|
||||
scoped.reset();
|
||||
} catch (MissingParameterException ignore) { rest = ""; }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Object[] argsArray = new Object[args.size()];
|
||||
args.toArray(argsArray);
|
||||
|
||||
try {
|
||||
return binding.method.invoke(binding.object, 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 e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions(ParameterData parameter, String prefix) {
|
||||
Binding legacySuggestions = legacy.get(parameter.getType());
|
||||
if (legacySuggestions != null) {
|
||||
List<String> result = legacySuggestions.getSuggestions(parameter, prefix);
|
||||
if (result != null) return result;
|
||||
}
|
||||
if (prefix.isEmpty()) {
|
||||
char bracket = parameter.isOptional() ? '[' : '<';
|
||||
char endBracket = StringMan.getMatchingBracket(bracket);
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append("\u00A75");
|
||||
result.append(bracket);
|
||||
result.append("\u00A7r");
|
||||
if (parameter.getFlag() != null) {
|
||||
result.append('-').append(parameter.getFlag()).append("\u00A75 \u00A7r");
|
||||
}
|
||||
result.append(parameter.getName());
|
||||
if (parameter.getDefaultValue() != null) {
|
||||
result.append('=').append(StringMan.join(parameter.getDefaultValue(), " "));
|
||||
}
|
||||
Range range = parameter.getModifier(Range.class);
|
||||
if (range != null) {
|
||||
result.append('|').append(StringMan.prettyFormat(range.min())).append(",").append(StringMan.prettyFormat(range.max()));
|
||||
}
|
||||
result.append("\u00A75");
|
||||
result.append(endBracket);
|
||||
result.append("\u00A7r");
|
||||
return Collections.singletonList(result.toString());
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
protected static class BoundMethod implements Comparable<BoundMethod> {
|
||||
protected final BindingMatch annotation;
|
||||
protected final Type type;
|
||||
protected final Class<? extends Annotation> classifier;
|
||||
protected final Method method;
|
||||
protected final Object object;
|
||||
|
||||
BoundMethod(BindingMatch annotation, Type type,
|
||||
Class<? extends Annotation> classifier, Method method, Object object) {
|
||||
this.annotation = annotation;
|
||||
this.type = type;
|
||||
this.classifier = classifier;
|
||||
this.method = method;
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public @interface BindingMatch {
|
||||
* @return the type, or {@link Class} if not set
|
||||
*/
|
||||
Class<?>[] type() default Class.class;
|
||||
|
||||
|
||||
/**
|
||||
* The binding behavior.
|
||||
*
|
||||
@ -68,4 +68,9 @@ public @interface BindingMatch {
|
||||
*/
|
||||
boolean provideModifiers() default false;
|
||||
|
||||
/**
|
||||
* If the type should be passed to the method
|
||||
*/
|
||||
boolean provideType() default false;
|
||||
|
||||
}
|
||||
|
@ -33,10 +33,8 @@ public class FunctionParametricCallable extends AParametricCallable {
|
||||
|
||||
List<Object[]> paramParsables = new ArrayList<>();
|
||||
{
|
||||
Map<Type, Binding> bindings = builder.getBindings();
|
||||
Map<String, Type> unqualified = new HashMap<>();
|
||||
for (Map.Entry<Type, Binding> entry : bindings.entrySet()) {
|
||||
Type type = entry.getKey();
|
||||
for (Type type : builder.getBindings().getTypes()) {
|
||||
String typeStr = type.getTypeName();
|
||||
unqualified.put(typeStr, type);
|
||||
unqualified.put(typeStr.substring(typeStr.lastIndexOf('.') + 1), type);
|
||||
@ -117,7 +115,7 @@ public class FunctionParametricCallable extends AParametricCallable {
|
||||
|
||||
// No special @annotation binding... let's check for the type
|
||||
if (parameter.getBinding() == null) {
|
||||
parameter.setBinding(builder.getBindings().get(type));
|
||||
parameter.setBinding(builder.getBindings());
|
||||
|
||||
// Don't know how to parse for this type of value
|
||||
if (parameter.getBinding() == null) {
|
||||
|
@ -65,7 +65,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
*/
|
||||
public class ParametricBuilder {
|
||||
|
||||
private final Map<Type, Binding> bindings = new HashMap<>();
|
||||
private final BindingMap bindings;
|
||||
private final Paranamer paranamer = new FaweParanamer();
|
||||
private final List<InvokeListener> invokeListeners = new ArrayList<>();
|
||||
private final List<ExceptionConverter> exceptionConverters = new ArrayList<>();
|
||||
@ -79,8 +79,9 @@ public class ParametricBuilder {
|
||||
* {@link StandardBindings} and default bindings.</p>
|
||||
*/
|
||||
public ParametricBuilder() {
|
||||
addBinding(new FawePrimitiveBinding());
|
||||
addBinding(new StandardBindings());
|
||||
this.bindings = new BindingMap(this);
|
||||
this.bindings.add(new FawePrimitiveBinding());
|
||||
this.bindings.add(new StandardBindings());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,14 +104,17 @@ public class ParametricBuilder {
|
||||
* @param binding the binding
|
||||
* @param type a list of types (if specified) to override the binding's types
|
||||
*/
|
||||
@Deprecated
|
||||
public void addBinding(Binding binding, Type... type) {
|
||||
if (type == null || type.length == 0) {
|
||||
type = binding.getTypes();
|
||||
}
|
||||
this.bindings.add(binding);
|
||||
}
|
||||
|
||||
for (Type t : type) {
|
||||
bindings.put(t, binding);
|
||||
}
|
||||
/**
|
||||
* Add a binding (accepts @Command or @BindingMatch methods)
|
||||
* @param binding
|
||||
*/
|
||||
public void addBinding(Object binding) {
|
||||
this.bindings.add(binding);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,21 +179,22 @@ public class ParametricBuilder {
|
||||
*/
|
||||
public void registerMethodsAsCommands(Dispatcher dispatcher, Object object, CallableProcessor processor) throws ParametricException {
|
||||
for (Method method : object.getClass().getDeclaredMethods()) {
|
||||
Command definition = method.getAnnotation(Command.class);
|
||||
if (definition != null) {
|
||||
definition = Commands.translate(method.getDeclaringClass(), definition);
|
||||
CommandCallable callable = build(object, method, definition);
|
||||
if (processor != null) {
|
||||
callable = new ProcessedCallable(callable, processor);
|
||||
}
|
||||
else if (object instanceof CallableProcessor) {
|
||||
callable = new ProcessedCallable(callable, (CallableProcessor) object);
|
||||
}
|
||||
if (object instanceof MethodCommands) {
|
||||
((MethodCommands) object).register(method, callable, dispatcher);
|
||||
}
|
||||
dispatcher.registerCommand(callable, definition.aliases());
|
||||
registerMethodAsCommands(method, dispatcher, object, processor);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerMethodAsCommands(Method method, Dispatcher dispatcher, Object object, CallableProcessor processor) throws ParametricException {
|
||||
Command definition = method.getAnnotation(Command.class);
|
||||
if (definition != null) {
|
||||
definition = Commands.translate(method.getDeclaringClass(), definition);
|
||||
CommandCallable callable = build(object, method, definition);
|
||||
if (processor != null) {
|
||||
callable = new ProcessedCallable(callable, processor);
|
||||
}
|
||||
else if (object instanceof CallableProcessor) {
|
||||
callable = new ProcessedCallable(callable, (CallableProcessor) object);
|
||||
}
|
||||
dispatcher.registerCommand(callable, definition.aliases());
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,7 +235,7 @@ public class ParametricBuilder {
|
||||
*
|
||||
* @return the map of bindings
|
||||
*/
|
||||
public Map<Type, Binding> getBindings() {
|
||||
public BindingMap getBindings() {
|
||||
return bindings;
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ public class ParametricCallable extends AParametricCallable {
|
||||
}
|
||||
// Special annotation bindings
|
||||
} else if (parameter.getBinding() == null) {
|
||||
parameter.setBinding(builder.getBindings().get(annotation.annotationType()));
|
||||
parameter.setBinding(builder.getBindings());
|
||||
parameter.setClassifier(annotation);
|
||||
}
|
||||
}
|
||||
@ -127,7 +127,7 @@ public class ParametricCallable extends AParametricCallable {
|
||||
|
||||
// No special @annotation binding... let's check for the type
|
||||
if (parameter.getBinding() == null) {
|
||||
parameter.setBinding(builder.getBindings().get(type));
|
||||
parameter.setBinding(builder.getBindings());
|
||||
|
||||
// Don't know how to parse for this type of value
|
||||
if (parameter.getBinding() == null) {
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren