mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-07 00:06:12 +00:00
Merge pull request #89 from PolyhedralDev/dev/commands
Platform-agnostic command API
This commit is contained in:
@@ -49,4 +49,19 @@ public interface TerraPlugin extends LoaderRegistrar {
|
||||
DebugLogger getDebugLogger();
|
||||
|
||||
EventManager getEventManager();
|
||||
|
||||
default String getVersion() {
|
||||
return "@VERSION@";
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a task that may or may not be thread safe, depending on platform.
|
||||
* <p>
|
||||
* Allows platforms to define what code is safe to be run asynchronously.
|
||||
*
|
||||
* @param task Task to be run.
|
||||
*/
|
||||
default void runPossiblyUnsafeTask(Runnable task) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.dfsek.terra.api.command;
|
||||
|
||||
import com.dfsek.terra.api.command.exception.CommandException;
|
||||
import com.dfsek.terra.api.command.exception.MalformedCommandException;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CommandManager {
|
||||
void execute(String command, CommandSender sender, List<String> args) throws CommandException;
|
||||
|
||||
void register(String name, Class<? extends CommandTemplate> clazz) throws MalformedCommandException;
|
||||
|
||||
List<String> tabComplete(String command, CommandSender sender, List<String> args) throws CommandException;
|
||||
|
||||
int getMaxArgumentDepth();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dfsek.terra.api.command;
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
public interface CommandTemplate {
|
||||
void execute(CommandSender sender);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.dfsek.terra.api.command;
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public final class ExecutionState {
|
||||
private final Set<String> switches = new HashSet<>();
|
||||
private final Map<String, String> args = new HashMap<>();
|
||||
private final CommandSender sender;
|
||||
|
||||
protected ExecutionState(CommandSender sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
protected void addSwitch(String flag) {
|
||||
switches.add(flag);
|
||||
}
|
||||
|
||||
protected void addArgument(String arg, String value) {
|
||||
args.put(arg, value);
|
||||
}
|
||||
|
||||
public String getArgument(String argument) {
|
||||
return args.get(argument);
|
||||
}
|
||||
|
||||
public boolean hasSwitch(String flag) {
|
||||
return switches.contains(flag);
|
||||
}
|
||||
|
||||
public CommandSender getSender() {
|
||||
return sender;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
package com.dfsek.terra.api.command;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.annotation.Argument;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.Subcommand;
|
||||
import com.dfsek.terra.api.command.annotation.Switch;
|
||||
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||
import com.dfsek.terra.api.command.annotation.inject.SwitchTarget;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.command.arg.ArgumentParser;
|
||||
import com.dfsek.terra.api.command.exception.CommandException;
|
||||
import com.dfsek.terra.api.command.exception.ExecutionException;
|
||||
import com.dfsek.terra.api.command.exception.InvalidArgumentsException;
|
||||
import com.dfsek.terra.api.command.exception.MalformedCommandException;
|
||||
import com.dfsek.terra.api.command.exception.SwitchFormatException;
|
||||
import com.dfsek.terra.api.command.tab.TabCompleter;
|
||||
import com.dfsek.terra.api.injection.Injector;
|
||||
import com.dfsek.terra.api.injection.exception.InjectionException;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.util.ReflectionUtil;
|
||||
import com.dfsek.terra.world.TerraWorld;
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TerraCommandManager implements CommandManager {
|
||||
private final Map<String, CommandHolder> commands = new HashMap<>();
|
||||
private final Injector<TerraPlugin> pluginInjector;
|
||||
private final TerraPlugin main;
|
||||
|
||||
public TerraCommandManager(TerraPlugin main) {
|
||||
this.main = main;
|
||||
this.pluginInjector = new Injector<>(main);
|
||||
pluginInjector.addExplicitTarget(TerraPlugin.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String commandName, CommandSender sender, List<String> argsIn) throws CommandException {
|
||||
if(!commands.containsKey(commandName)) throw new InvalidArgumentsException("No such command \"" + commandName + "\"");
|
||||
execute(commands.get(commandName), sender, new ArrayList<>(argsIn));
|
||||
}
|
||||
|
||||
private void execute(CommandHolder commandHolder, CommandSender sender, List<String> args) throws CommandException {
|
||||
Class<? extends CommandTemplate> commandClass = commandHolder.clazz;
|
||||
|
||||
if(commandClass.isAnnotationPresent(DebugCommand.class) && !main.isDebug()) {
|
||||
sender.sendMessage("Command must be executed with debug mode enabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(commandClass.isAnnotationPresent(PlayerCommand.class) && !(sender instanceof Player)) {
|
||||
sender.sendMessage("Command must be executed by player.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(commandClass.isAnnotationPresent(WorldCommand.class) && (!(sender instanceof Player) || !TerraWorld.isTerraWorld(((Player) sender).getWorld()))) {
|
||||
sender.sendMessage("Command must be executed in a Terra world.");
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> ogArgs = new ArrayList<>(args);
|
||||
|
||||
ExecutionState state = new ExecutionState(sender);
|
||||
|
||||
if(!commandClass.isAnnotationPresent(Command.class)) {
|
||||
invoke(commandClass, state, commandHolder);
|
||||
return;
|
||||
}
|
||||
|
||||
Command command = commandClass.getAnnotation(Command.class);
|
||||
|
||||
if(command.arguments().length == 0 && command.subcommands().length == 0) {
|
||||
if(args.isEmpty()) {
|
||||
invoke(commandClass, state, commandHolder);
|
||||
return;
|
||||
} else throw new InvalidArgumentsException("Expected 0 arguments, found " + args.size());
|
||||
}
|
||||
|
||||
if(!args.isEmpty() && commandHolder.subcommands.containsKey(args.get(0))) {
|
||||
String c = args.get(0);
|
||||
args.remove(0);
|
||||
execute(commandHolder.subcommands.get(c), sender, args);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean req = true;
|
||||
for(Argument argument : command.arguments()) {
|
||||
if(!req && argument.required()) {
|
||||
throw new MalformedCommandException("Required arguments must come first! Arguments: " + Arrays.toString(command.arguments()));
|
||||
}
|
||||
req = argument.required();
|
||||
|
||||
if(args.isEmpty()) {
|
||||
if(req) throw new InvalidArgumentsException("Invalid arguments: " + ogArgs + ", usage: " + command.usage());
|
||||
break;
|
||||
}
|
||||
|
||||
String arg = args.get(0);
|
||||
|
||||
if(arg.startsWith("-")) { // switches have started.
|
||||
if(req) throw new InvalidArgumentsException("Switches must come after arguments.");
|
||||
break;
|
||||
}
|
||||
|
||||
state.addArgument(argument.value(), args.remove(0));
|
||||
}
|
||||
|
||||
while(!args.isEmpty()) {
|
||||
String aSwitch = args.remove(0);
|
||||
if(!aSwitch.startsWith("-")) throw new SwitchFormatException("Invalid switch \"" + aSwitch + "\"");
|
||||
|
||||
String val = aSwitch.substring(1); // remove dash
|
||||
|
||||
if(!commandHolder.switches.containsKey(val)) throw new SwitchFormatException("No such switch \"" + aSwitch + "\"");
|
||||
|
||||
state.addSwitch(commandHolder.switches.get(val));
|
||||
}
|
||||
|
||||
invoke(commandClass, state, commandHolder);
|
||||
}
|
||||
|
||||
private void invoke(Class<? extends CommandTemplate> clazz, ExecutionState state, CommandHolder holder) throws CommandException {
|
||||
try {
|
||||
CommandTemplate template = clazz.getConstructor().newInstance();
|
||||
|
||||
pluginInjector.inject(template);
|
||||
|
||||
for(Field field : ReflectionUtil.getFields(clazz)) {
|
||||
if(field.isAnnotationPresent(ArgumentTarget.class)) {
|
||||
ArgumentTarget argumentTarget = field.getAnnotation(ArgumentTarget.class);
|
||||
if(!holder.argumentMap.containsKey(argumentTarget.value())) {
|
||||
throw new MalformedCommandException("Argument Target specifies nonexistent argument \"" + argumentTarget.value() + "\"");
|
||||
}
|
||||
|
||||
String argument = argumentTarget.value();
|
||||
|
||||
ArgumentParser<?> argumentParser = holder.argumentMap.get(argumentTarget.value()).argumentParser().getConstructor().newInstance();
|
||||
|
||||
pluginInjector.inject(argumentParser);
|
||||
|
||||
field.setAccessible(true);
|
||||
String value = state.getArgument(argument);
|
||||
|
||||
if(value == null) value = holder.argumentMap.get(argumentTarget.value()).defaultValue();
|
||||
|
||||
field.set(template, argumentParser.parse(state.getSender(), value));
|
||||
}
|
||||
if(field.isAnnotationPresent(SwitchTarget.class)) {
|
||||
SwitchTarget switchTarget = field.getAnnotation(SwitchTarget.class);
|
||||
if(!holder.switches.containsValue(switchTarget.value())) {
|
||||
System.out.println(holder.switches);
|
||||
throw new MalformedCommandException("Switch Target specifies nonexistent switch \"" + switchTarget.value() + "\"");
|
||||
}
|
||||
|
||||
if(!(field.getType() == boolean.class)) {
|
||||
throw new MalformedCommandException("Switch Target must be of type boolean.");
|
||||
}
|
||||
|
||||
field.setAccessible(true);
|
||||
field.setBoolean(template, state.hasSwitch(switchTarget.value()));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
template.execute(state.getSender());
|
||||
} catch(Throwable e) {
|
||||
throw new ExecutionException("Failed to execute command: " + e.getMessage(), e);
|
||||
}
|
||||
} catch(InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | InjectionException e) {
|
||||
throw new MalformedCommandException("Unable to reflectively instantiate command: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(String name, Class<? extends CommandTemplate> clazz) throws MalformedCommandException {
|
||||
commands.put(name, new CommandHolder(clazz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> tabComplete(String command, CommandSender sender, List<String> args) throws CommandException {
|
||||
if(args.isEmpty()) return new ArrayList<>(commands.keySet()).stream().sorted(String::compareTo).collect(Collectors.toList());
|
||||
if(!commands.containsKey(command)) return Collections.emptyList();
|
||||
return tabComplete(commands.get(command), sender, new ArrayList<>(args)).stream().filter(s -> s.toLowerCase().startsWith(args.get(args.size() - 1).toLowerCase())).sorted(String::compareTo).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxArgumentDepth() {
|
||||
int max = 0;
|
||||
for(CommandHolder value : commands.values()) {
|
||||
max = FastMath.max(getMaxArgumentDepth(value), max);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
private int getMaxArgumentDepth(CommandHolder holder) {
|
||||
int max = 0;
|
||||
max = FastMath.max(holder.arguments.size() + holder.switchList.size(), max);
|
||||
for(CommandHolder value : holder.subcommands.values()) {
|
||||
max = FastMath.max(max, getMaxArgumentDepth(value) + 1);
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
private List<String> tabComplete(CommandHolder holder, CommandSender sender, List<String> args) throws CommandException {
|
||||
if(args.isEmpty()) return Collections.emptyList();
|
||||
List<String> completions = new ArrayList<>();
|
||||
|
||||
if(args.size() == 1) {
|
||||
completions.addAll(holder.subcommands.keySet());
|
||||
}
|
||||
|
||||
if(holder.subcommands.containsKey(args.get(0))) {
|
||||
List<String> newArgs = new ArrayList<>(args);
|
||||
newArgs.remove(0);
|
||||
completions.addAll(tabComplete(holder.subcommands.get(args.get(0)), sender, newArgs));
|
||||
}
|
||||
try {
|
||||
if(args.size() <= holder.arguments.size()) {
|
||||
TabCompleter completer = holder.arguments.get(args.size() - 1).tabCompleter().getConstructor().newInstance();
|
||||
pluginInjector.inject(completer);
|
||||
completions.addAll(completer.complete(sender));
|
||||
}
|
||||
} catch(InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | InjectionException e) {
|
||||
throw new MalformedCommandException("Unable to reflectively instantiate tab-completer: ", e);
|
||||
}
|
||||
return completions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-processes command metadata.
|
||||
*/
|
||||
private static final class CommandHolder {
|
||||
private final Class<? extends CommandTemplate> clazz;
|
||||
private final Map<String, CommandHolder> subcommands = new HashMap<>();
|
||||
private final Map<String, String> switches = new HashMap<>();
|
||||
private final List<Argument> arguments;
|
||||
private final List<Switch> switchList;
|
||||
private final Map<String, Argument> argumentMap = new HashMap<>();
|
||||
|
||||
private CommandHolder(Class<? extends CommandTemplate> clazz) throws MalformedCommandException {
|
||||
this.clazz = clazz;
|
||||
if(clazz.isAnnotationPresent(Command.class)) {
|
||||
Command command = clazz.getAnnotation(Command.class);
|
||||
for(Subcommand subcommand : command.subcommands()) {
|
||||
if(subcommands.containsKey(subcommand.value()))
|
||||
throw new MalformedCommandException("Duplicate subcommand: " + subcommand);
|
||||
CommandHolder holder = new CommandHolder(subcommand.clazz());
|
||||
subcommands.put(subcommand.value(), holder);
|
||||
for(String alias : subcommand.aliases()) {
|
||||
subcommands.put(alias, holder);
|
||||
}
|
||||
}
|
||||
for(Switch aSwitch : command.switches()) {
|
||||
if(switches.containsKey(aSwitch.value())) throw new MalformedCommandException("Duplicate switch: " + aSwitch);
|
||||
switches.put(aSwitch.value(), aSwitch.value());
|
||||
for(String alias : aSwitch.aliases()) {
|
||||
switches.put(alias, aSwitch.value());
|
||||
}
|
||||
}
|
||||
for(Argument argument : command.arguments()) {
|
||||
if(argumentMap.containsKey(argument.value())) throw new MalformedCommandException("Duplicate argument: " + argument);
|
||||
argumentMap.put(argument.value(), argument);
|
||||
}
|
||||
arguments = Arrays.asList(command.arguments());
|
||||
switchList = Arrays.asList(command.switches());
|
||||
} else {
|
||||
arguments = Collections.emptyList();
|
||||
switchList = Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.dfsek.terra.api.command.annotation;
|
||||
|
||||
import com.dfsek.terra.api.command.arg.ArgumentParser;
|
||||
import com.dfsek.terra.api.command.arg.StringArgumentParser;
|
||||
import com.dfsek.terra.api.command.tab.NothingCompleter;
|
||||
import com.dfsek.terra.api.command.tab.TabCompleter;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Argument {
|
||||
String value();
|
||||
|
||||
boolean required() default true;
|
||||
|
||||
Class<? extends TabCompleter> tabCompleter() default NothingCompleter.class;
|
||||
|
||||
Class<? extends ArgumentParser<?>> argumentParser() default StringArgumentParser.class;
|
||||
|
||||
String defaultValue() default "";
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.dfsek.terra.api.command.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Command {
|
||||
Argument[] arguments() default {};
|
||||
|
||||
Switch[] switches() default {};
|
||||
|
||||
Subcommand[] subcommands() default {};
|
||||
|
||||
String usage() default "";
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.dfsek.terra.api.command.annotation;
|
||||
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
public @interface Subcommand {
|
||||
String value();
|
||||
|
||||
String[] aliases() default {};
|
||||
|
||||
Class<? extends CommandTemplate> clazz();
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.api.command.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
public @interface Switch {
|
||||
String value();
|
||||
|
||||
String[] aliases() default {};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.dfsek.terra.api.command.annotation.inject;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface ArgumentTarget {
|
||||
String value();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.dfsek.terra.api.command.annotation.inject;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface SwitchTarget {
|
||||
String value();
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.api.command.annotation.type;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Command may only be executed with debug mode enabled.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DebugCommand {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.api.command.annotation.type;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Marks command as player-only
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PlayerCommand {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.api.command.annotation.type;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Command may only be executed in a Terra world.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WorldCommand {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.dfsek.terra.api.command.arg;
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
public interface ArgumentParser<T> {
|
||||
T parse(CommandSender sender, String arg);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.dfsek.terra.api.command.arg;
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
public class DoubleArgumentParser implements ArgumentParser<Double> {
|
||||
@Override
|
||||
public Double parse(CommandSender sender, String arg) {
|
||||
return arg == null ? null : Double.parseDouble(arg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.dfsek.terra.api.command.arg;
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
public class IntegerArgumentParser implements ArgumentParser<Integer> {
|
||||
@Override
|
||||
public Integer parse(CommandSender sender, String arg) {
|
||||
return arg == null ? null : Integer.parseInt(arg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.dfsek.terra.api.command.arg;
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
public class StringArgumentParser implements ArgumentParser<String> {
|
||||
@Override
|
||||
public String parse(CommandSender sender, String arg) {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.dfsek.terra.api.command.exception;
|
||||
|
||||
public abstract class CommandException extends Exception {
|
||||
private static final long serialVersionUID = -2955328495045879822L;
|
||||
|
||||
public CommandException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public CommandException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.dfsek.terra.api.command.exception;
|
||||
|
||||
public class ExecutionException extends CommandException {
|
||||
private static final long serialVersionUID = -6345523475880607959L;
|
||||
|
||||
public ExecutionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ExecutionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.dfsek.terra.api.command.exception;
|
||||
|
||||
public class InvalidArgumentsException extends CommandException {
|
||||
private static final long serialVersionUID = 7563619667472569824L;
|
||||
|
||||
public InvalidArgumentsException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidArgumentsException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.dfsek.terra.api.command.exception;
|
||||
|
||||
/**
|
||||
* Thrown when command is incorrectly defined.
|
||||
*/
|
||||
public class MalformedCommandException extends CommandException {
|
||||
private static final long serialVersionUID = -5417760860407895496L;
|
||||
|
||||
public MalformedCommandException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public MalformedCommandException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.dfsek.terra.api.command.exception;
|
||||
|
||||
public class SwitchFormatException extends CommandException {
|
||||
private static final long serialVersionUID = -965858989317844628L;
|
||||
|
||||
public SwitchFormatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SwitchFormatException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.dfsek.terra.api.command.tab;
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class NothingCompleter implements TabCompleter {
|
||||
@Override
|
||||
public List<String> complete(CommandSender sender) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.dfsek.terra.api.command.tab;
|
||||
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface TabCompleter {
|
||||
List<String> complete(CommandSender sender);
|
||||
}
|
||||
@@ -170,4 +170,9 @@ public class Location implements Cloneable {
|
||||
public String toString() {
|
||||
return "[" + world + ": (" + getX() + ", " + getY() + ", " + getZ() + ")]";
|
||||
}
|
||||
|
||||
public Location multiply(double v) {
|
||||
vector.multiply(v);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,4 +13,6 @@ public interface BlockData extends Cloneable, Handle {
|
||||
String getAsString();
|
||||
|
||||
boolean isAir();
|
||||
|
||||
boolean isStructureVoid();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,12 @@ package com.dfsek.terra.api.platform.entity;
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.Handle;
|
||||
import com.dfsek.terra.api.platform.world.World;
|
||||
|
||||
public interface Entity extends Handle, CommandSender {
|
||||
Location getLocation();
|
||||
|
||||
void setLocation(Location location);
|
||||
|
||||
World getWorld();
|
||||
}
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
package com.dfsek.terra.api.platform.handle;
|
||||
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.entity.EntityType;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
/**
|
||||
* Interface to be implemented for world manipulation.
|
||||
*/
|
||||
public interface WorldHandle {
|
||||
default void setBlockData(Block block, BlockData data, boolean physics) {
|
||||
block.setBlockData(data, physics);
|
||||
}
|
||||
|
||||
default BlockData getBlockData(Block block) {
|
||||
return block.getBlockData();
|
||||
}
|
||||
|
||||
BlockData createBlockData(String data);
|
||||
|
||||
EntityType getEntity(String id);
|
||||
|
||||
/**
|
||||
* Get the locations selected by a player. (Usually via WorldEdit)
|
||||
*
|
||||
* @param player Player to get locations for
|
||||
* @return Pair of locations.
|
||||
*/
|
||||
default Pair<Location, Location> getSelectedLocation(Player player) {
|
||||
throw new UnsupportedOperationException("Cannot get selection on this platform.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,17 @@ public interface World extends Handle {
|
||||
|
||||
Chunk getChunkAt(int x, int z);
|
||||
|
||||
default Chunk getChunkAt(Location location) {
|
||||
return getChunkAt(location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
}
|
||||
|
||||
File getWorldFolder();
|
||||
|
||||
Block getBlockAt(int x, int y, int z);
|
||||
|
||||
Block getBlockAt(Location l);
|
||||
default Block getBlockAt(Location l) {
|
||||
return getBlockAt(l.getBlockX(), l.getBlockY(), l.getBlockZ());
|
||||
}
|
||||
|
||||
Entity spawnEntity(Location location, EntityType entityType);
|
||||
|
||||
|
||||
@@ -2,9 +2,12 @@ package com.dfsek.terra.api.util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ReflectionUtil {
|
||||
@@ -25,4 +28,9 @@ public class ReflectionUtil {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T extends Annotation> void ifAnnotationPresent(AnnotatedElement element, Class<? extends T> annotation, Consumer<T> operation) {
|
||||
T a = element.getAnnotation(annotation);
|
||||
if(a != null) operation.accept(a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.dfsek.terra.api.util.generic.either;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class Either<L, R> {
|
||||
private final L left;
|
||||
private final R right;
|
||||
private final boolean leftPresent;
|
||||
|
||||
private Either(L left, R right, boolean leftPresent) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.leftPresent = leftPresent;
|
||||
}
|
||||
|
||||
public static <L1, R1> Either<L1, R1> left(L1 left) {
|
||||
return new Either<>(left, null, true);
|
||||
}
|
||||
|
||||
public static <L1, R1> Either<L1, R1> right(R1 right) {
|
||||
return new Either<>(null, right, false);
|
||||
}
|
||||
|
||||
public Optional<L> getLeft() {
|
||||
if(leftPresent) return Optional.of(left);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<R> getRight() {
|
||||
if(!leftPresent) return Optional.of(right);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Either<L, R> ifLeft(Consumer<L> action) {
|
||||
if(leftPresent) action.accept(left);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Either<L, R> ifRight(Consumer<R> action) {
|
||||
if(!leftPresent) action.accept(right);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasLeft() {
|
||||
return leftPresent;
|
||||
}
|
||||
|
||||
public boolean hasRight() {
|
||||
return !leftPresent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.dfsek.terra.api.util.generic.pair;
|
||||
|
||||
public class ImmutablePair<L, R> {
|
||||
private final L left;
|
||||
private final R right;
|
||||
|
||||
public ImmutablePair(L left, R right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public static <L1, R1> ImmutablePair<L1, R1> of(L1 left, R1 right) {
|
||||
return new ImmutablePair<>(left, right);
|
||||
}
|
||||
|
||||
public R getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
public L getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public Pair<L, R> mutable() {
|
||||
return new Pair<>(left, right);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.dfsek.terra.api.util.generic.pair;
|
||||
|
||||
public class Pair<L, R> {
|
||||
private L left;
|
||||
private R right;
|
||||
|
||||
public Pair(L left, R right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public static <L1, R1> Pair<L1, R1> of(L1 left, R1 right) {
|
||||
return new Pair<>(left, right);
|
||||
}
|
||||
|
||||
public L getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public void setLeft(L left) {
|
||||
this.left = left;
|
||||
}
|
||||
|
||||
public R getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
public void setRight(R right) {
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public ImmutablePair<L, R> immutable() {
|
||||
return new ImmutablePair<>(left, right);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.dfsek.terra.commands;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
@Command(
|
||||
usage = "/terra addons"
|
||||
)
|
||||
public class AddonsCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
sender.sendMessage("Installed Addons:");
|
||||
main.getAddons().forEach(addon -> sender.sendMessage(" - " + addon.getName() + " v" + addon.getVersion() + " by " + addon.getAuthor()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.dfsek.terra.commands;
|
||||
|
||||
import com.dfsek.terra.api.command.CommandManager;
|
||||
import com.dfsek.terra.api.command.exception.MalformedCommandException;
|
||||
import com.dfsek.terra.commands.biome.BiomeCommand;
|
||||
import com.dfsek.terra.commands.geometry.GeometryCommand;
|
||||
import com.dfsek.terra.commands.profiler.ProfileCommand;
|
||||
import com.dfsek.terra.commands.structure.StructureCommand;
|
||||
|
||||
public final class CommandUtil {
|
||||
public static void registerAll(CommandManager manager) throws MalformedCommandException {
|
||||
manager.register("structure", StructureCommand.class);
|
||||
manager.register("profile", ProfileCommand.class);
|
||||
manager.register("reload", ReloadCommand.class);
|
||||
manager.register("addons", AddonsCommand.class);
|
||||
manager.register("version", VersionCommand.class);
|
||||
manager.register("getblock", GetBlockCommand.class);
|
||||
manager.register("packs", PacksCommand.class);
|
||||
manager.register("biome", BiomeCommand.class);
|
||||
manager.register("geometry", GeometryCommand.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.dfsek.terra.commands;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
|
||||
@WorldCommand
|
||||
@DebugCommand
|
||||
@PlayerCommand
|
||||
@Command(
|
||||
usage = "/terra getblock"
|
||||
)
|
||||
public class GetBlockCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
sender.sendMessage("Block: " + main.getWorld(player.getWorld()).getUngeneratedBlock(player.getLocation()).getAsString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.dfsek.terra.commands;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.registry.CheckedRegistry;
|
||||
import com.dfsek.terra.config.lang.LangUtil;
|
||||
import com.dfsek.terra.config.pack.ConfigPack;
|
||||
import com.dfsek.terra.config.pack.ConfigPackTemplate;
|
||||
|
||||
@Command(
|
||||
usage = "/terra packs"
|
||||
)
|
||||
public class PacksCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
CheckedRegistry<ConfigPack> registry = main.getConfigRegistry();
|
||||
|
||||
if(registry.entries().size() == 0) {
|
||||
LangUtil.send("command.packs.none", sender);
|
||||
return;
|
||||
}
|
||||
|
||||
LangUtil.send("command.packs.main", sender);
|
||||
registry.entries().forEach(entry -> {
|
||||
ConfigPackTemplate template = entry.getTemplate();
|
||||
LangUtil.send("command.packs.pack", sender, template.getID(), template.getAuthor(), template.getVersion());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.dfsek.terra.commands;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.config.lang.LangUtil;
|
||||
|
||||
@Command(
|
||||
usage = "/terra reload"
|
||||
)
|
||||
public class ReloadCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
if(!main.reload()) {
|
||||
LangUtil.send("command.reload-error", sender);
|
||||
} else {
|
||||
LangUtil.send("command.reload", sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.dfsek.terra.commands;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.config.lang.LangUtil;
|
||||
|
||||
@Command(
|
||||
usage = "/terra version"
|
||||
)
|
||||
public class VersionCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
String terraVersion = main.getVersion();
|
||||
LangUtil.send("command.version", sender, terraVersion, main.platformName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.dfsek.terra.commands.biome;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.Subcommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
|
||||
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
|
||||
import com.dfsek.terra.config.lang.LangUtil;
|
||||
|
||||
@Command(
|
||||
subcommands = {
|
||||
@Subcommand(
|
||||
value = "info",
|
||||
aliases = {"i"},
|
||||
clazz = BiomeInfoCommand.class
|
||||
),
|
||||
@Subcommand(
|
||||
value = "locate",
|
||||
aliases = {"l"},
|
||||
clazz = BiomeLocateCommand.class
|
||||
)
|
||||
},
|
||||
usage = "/terra biome"
|
||||
)
|
||||
@WorldCommand
|
||||
@PlayerCommand
|
||||
public class BiomeCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
|
||||
BiomeProvider provider = main.getWorld(player.getWorld()).getBiomeProvider();
|
||||
UserDefinedBiome biome = (UserDefinedBiome) provider.getBiome(player.getLocation());
|
||||
LangUtil.send("command.biome.in", sender, biome.getID());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.dfsek.terra.commands.biome;
|
||||
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Argument;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.world.biome.TerraBiome;
|
||||
import com.dfsek.terra.api.world.biome.UserDefinedBiome;
|
||||
import com.dfsek.terra.commands.biome.arg.BiomeArgumentParser;
|
||||
import com.dfsek.terra.commands.biome.tab.BiomeTabCompleter;
|
||||
import com.dfsek.terra.config.templates.BiomeTemplate;
|
||||
import com.dfsek.terra.world.population.items.TerraStructure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(
|
||||
value = "biome",
|
||||
tabCompleter = BiomeTabCompleter.class,
|
||||
argumentParser = BiomeArgumentParser.class
|
||||
)
|
||||
}
|
||||
)
|
||||
public class BiomeInfoCommand implements CommandTemplate {
|
||||
@ArgumentTarget("biome")
|
||||
private TerraBiome biome;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
|
||||
sender.sendMessage("Biome info for \"" + biome.getID() + "\".");
|
||||
sender.sendMessage("Vanilla biome: " + biome.getVanillaBiomes());
|
||||
|
||||
if(biome instanceof UserDefinedBiome) {
|
||||
BiomeTemplate bio = ((UserDefinedBiome) biome).getConfig();
|
||||
|
||||
if(bio.getExtend() != null) sender.sendMessage("Extends: " + bio.getExtend());
|
||||
|
||||
List<TerraStructure> structureConfigs = bio.getStructures();
|
||||
|
||||
if(structureConfigs.size() == 0) sender.sendMessage("No Structures");
|
||||
else {
|
||||
sender.sendMessage("-------Structures-------");
|
||||
for(TerraStructure c : structureConfigs) {
|
||||
sender.sendMessage(" - " + c.getTemplate().getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.dfsek.terra.commands.biome;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Argument;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.Switch;
|
||||
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||
import com.dfsek.terra.api.command.annotation.inject.SwitchTarget;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.command.arg.IntegerArgumentParser;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.world.biome.TerraBiome;
|
||||
import com.dfsek.terra.api.world.locate.AsyncBiomeFinder;
|
||||
import com.dfsek.terra.commands.biome.arg.BiomeArgumentParser;
|
||||
import com.dfsek.terra.commands.biome.tab.BiomeTabCompleter;
|
||||
import com.dfsek.terra.config.lang.LangUtil;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@PlayerCommand
|
||||
@WorldCommand
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(
|
||||
value = "biome",
|
||||
tabCompleter = BiomeTabCompleter.class,
|
||||
argumentParser = BiomeArgumentParser.class
|
||||
),
|
||||
@Argument(
|
||||
value = "radius",
|
||||
required = false,
|
||||
defaultValue = "1000",
|
||||
argumentParser = IntegerArgumentParser.class
|
||||
)
|
||||
},
|
||||
switches = {
|
||||
@Switch(
|
||||
value = "teleport",
|
||||
aliases = {"t", "tp"}
|
||||
)
|
||||
}
|
||||
)
|
||||
public class BiomeLocateCommand implements CommandTemplate {
|
||||
|
||||
@ArgumentTarget("radius")
|
||||
private Integer radius;
|
||||
|
||||
@ArgumentTarget("biome")
|
||||
private TerraBiome biome;
|
||||
|
||||
@SwitchTarget("teleport")
|
||||
private boolean teleport;
|
||||
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
|
||||
Player player = (Player) sender;
|
||||
|
||||
new Thread(new AsyncBiomeFinder(main.getWorld(player.getWorld()).getBiomeProvider(), biome, player.getLocation().clone().multiply((1D / main.getTerraConfig().getBiomeSearchResolution())), 0, radius, location -> {
|
||||
if(location != null) {
|
||||
sender.sendMessage(String.format("The nearest %s is at [%d, ~, %d] (%.1f blocks away)", biome.getID().toLowerCase(Locale.ROOT), location.getBlockX(), location.getBlockZ(), location.add(new Vector3(0, player.getLocation().getY(), 0)).distance(player.getLocation().toVector())));
|
||||
if(teleport) {
|
||||
main.runPossiblyUnsafeTask(() -> player.setLocation(new Location(player.getWorld(), location.getX(), player.getLocation().getY(), location.getZ())));
|
||||
}
|
||||
} else LangUtil.send("command.biome.unable-to-locate", sender);
|
||||
}, main), "Biome Location Thread").start();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.dfsek.terra.commands.biome.arg;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.arg.ArgumentParser;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.world.biome.TerraBiome;
|
||||
|
||||
public class BiomeArgumentParser implements ArgumentParser<TerraBiome> {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public TerraBiome parse(CommandSender sender, String arg) {
|
||||
Player player = (Player) sender;
|
||||
return main.getWorld(player.getWorld()).getConfig().getBiomeRegistry().get(arg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.dfsek.terra.commands.biome.tab;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.tab.TabCompleter;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.world.biome.TerraBiome;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BiomeTabCompleter implements TabCompleter {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public List<String> complete(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
return main.getWorld(player.getWorld()).getConfig().getBiomeRegistry().entries().stream().map(TerraBiome::getID).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.dfsek.terra.commands.geometry;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Argument;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.arg.DoubleArgumentParser;
|
||||
import com.dfsek.terra.api.command.arg.IntegerArgumentParser;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.math.noise.samplers.noise.simplex.OpenSimplex2Sampler;
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
import com.dfsek.terra.api.math.voxel.DeformedSphere;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@DebugCommand
|
||||
@PlayerCommand
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(
|
||||
value = "radius",
|
||||
argumentParser = IntegerArgumentParser.class
|
||||
),
|
||||
@Argument(
|
||||
value = "deform",
|
||||
argumentParser = DoubleArgumentParser.class
|
||||
),
|
||||
@Argument(
|
||||
value = "frequency",
|
||||
argumentParser = DoubleArgumentParser.class
|
||||
)
|
||||
},
|
||||
usage = "/terra geometry deformedsphere <RADIUS> <DEFORM> <FREQUENCY>"
|
||||
)
|
||||
public class DeformedSphereCommand implements CommandTemplate {
|
||||
@ArgumentTarget("radius")
|
||||
private Integer radius;
|
||||
|
||||
@ArgumentTarget("deform")
|
||||
private Double deform;
|
||||
|
||||
@ArgumentTarget("frequency")
|
||||
private Double frequency;
|
||||
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
|
||||
OpenSimplex2Sampler noise = new OpenSimplex2Sampler(ThreadLocalRandom.current().nextInt());
|
||||
noise.setFrequency(frequency);
|
||||
|
||||
DeformedSphere sphere = new DeformedSphere(player.getLocation().toVector(), radius, deform, noise);
|
||||
for(Vector3 v : sphere.getGeometry()) {
|
||||
v.toLocation(player.getWorld()).getBlock().setBlockData(main.getWorldHandle().createBlockData("minecraft:stone"), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.dfsek.terra.commands.geometry;
|
||||
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.Subcommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.config.lang.LangUtil;
|
||||
|
||||
|
||||
@DebugCommand
|
||||
@PlayerCommand
|
||||
@Command(
|
||||
subcommands = {
|
||||
@Subcommand(
|
||||
value = "sphere",
|
||||
clazz = SphereCommand.class,
|
||||
aliases = {"s"}
|
||||
),
|
||||
@Subcommand(
|
||||
value = "deformedsphere",
|
||||
clazz = DeformedSphereCommand.class,
|
||||
aliases = {"df"}
|
||||
),
|
||||
@Subcommand(
|
||||
value = "tube",
|
||||
clazz = TubeCommand.class,
|
||||
aliases = {"t"}
|
||||
)
|
||||
},
|
||||
usage = "/terra geometry"
|
||||
)
|
||||
public class GeometryCommand implements CommandTemplate {
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
LangUtil.send("command.geometry.main-menu", sender);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.dfsek.terra.commands.geometry;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Argument;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.arg.IntegerArgumentParser;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
import com.dfsek.terra.api.math.voxel.Sphere;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
|
||||
@DebugCommand
|
||||
@PlayerCommand
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(
|
||||
value = "radius",
|
||||
argumentParser = IntegerArgumentParser.class
|
||||
)
|
||||
},
|
||||
usage = "/terra geometry sphere <RADIUS>"
|
||||
)
|
||||
public class SphereCommand implements CommandTemplate {
|
||||
@ArgumentTarget("radius")
|
||||
private Integer radius;
|
||||
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
|
||||
Sphere sphere = new Sphere(player.getLocation().toVector(), radius);
|
||||
for(Vector3 v : sphere.getGeometry()) {
|
||||
v.toLocation(player.getWorld()).getBlock().setBlockData(main.getWorldHandle().createBlockData("minecraft:stone"), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.dfsek.terra.commands.geometry;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Argument;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.arg.IntegerArgumentParser;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.math.vector.Vector3;
|
||||
import com.dfsek.terra.api.math.voxel.Tube;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
@DebugCommand
|
||||
@PlayerCommand
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(
|
||||
value = "radius",
|
||||
argumentParser = IntegerArgumentParser.class
|
||||
)
|
||||
},
|
||||
usage = "/terra geometry tube <RADIUS>"
|
||||
)
|
||||
public class TubeCommand implements CommandTemplate {
|
||||
@ArgumentTarget("radius")
|
||||
private Integer radius;
|
||||
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
|
||||
Pair<Location, Location> locations = main.getWorldHandle().getSelectedLocation(player);
|
||||
|
||||
Tube tube = new Tube(locations.getLeft().toVector(), locations.getRight().toVector(), radius);
|
||||
|
||||
for(Vector3 v : tube.getGeometry()) {
|
||||
v.toLocation(player.getWorld()).getBlock().setBlockData(main.getWorldHandle().createBlockData("minecraft:stone"), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.dfsek.terra.commands.profiler;
|
||||
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.Subcommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.config.lang.LangUtil;
|
||||
|
||||
@Command(
|
||||
subcommands = {
|
||||
@Subcommand(value = "query", aliases = {"q"}, clazz = ProfileQueryCommand.class),
|
||||
@Subcommand(value = "start", aliases = {"s"}, clazz = ProfileStartCommand.class),
|
||||
@Subcommand(value = "stop", aliases = {"st"}, clazz = ProfileStopCommand.class),
|
||||
@Subcommand(value = "reset", aliases = {"r"}, clazz = ProfileResetCommand.class)
|
||||
},
|
||||
usage = "Commands to enable/disable/query/reset the profiler."
|
||||
)
|
||||
@WorldCommand
|
||||
@PlayerCommand
|
||||
@DebugCommand
|
||||
public class ProfileCommand implements CommandTemplate {
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
LangUtil.send("command.profile.main-menu", sender);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.dfsek.terra.commands.profiler;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.world.TerraWorld;
|
||||
|
||||
@Command
|
||||
@WorldCommand
|
||||
@PlayerCommand
|
||||
@DebugCommand
|
||||
public class ProfileQueryCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
TerraWorld world = main.getWorld(player.getWorld());
|
||||
player.sendMessage(world.getProfiler().getResultsFormatted());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.dfsek.terra.commands.profiler;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.world.TerraWorld;
|
||||
|
||||
@Command
|
||||
@WorldCommand
|
||||
@PlayerCommand
|
||||
@DebugCommand
|
||||
public class ProfileResetCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
TerraWorld world = main.getWorld(player.getWorld());
|
||||
world.getProfiler().reset();
|
||||
player.sendMessage("Profiler reset.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.dfsek.terra.commands.profiler;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.world.TerraWorld;
|
||||
|
||||
@Command
|
||||
@WorldCommand
|
||||
@PlayerCommand
|
||||
@DebugCommand
|
||||
public class ProfileStartCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
TerraWorld world = main.getWorld(player.getWorld());
|
||||
world.getProfiler().setProfiling(true);
|
||||
player.sendMessage("Profiling enabled.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.dfsek.terra.commands.profiler;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.world.TerraWorld;
|
||||
|
||||
@Command
|
||||
@WorldCommand
|
||||
@PlayerCommand
|
||||
@DebugCommand
|
||||
public class ProfileStopCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
TerraWorld world = main.getWorld(player.getWorld());
|
||||
world.getProfiler().setProfiling(false);
|
||||
player.sendMessage("Profiling disabled.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.dfsek.terra.commands.structure;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.structures.parser.lang.constants.NumericConstant;
|
||||
import com.dfsek.terra.api.structures.script.TerraImplementationArguments;
|
||||
import com.dfsek.terra.api.structures.script.functions.CheckFunction;
|
||||
import com.dfsek.terra.api.structures.structure.Rotation;
|
||||
import com.dfsek.terra.api.structures.structure.buffer.StructureBuffer;
|
||||
import com.dfsek.terra.api.structures.tokenizer.Position;
|
||||
import com.dfsek.terra.api.util.FastRandom;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@DebugCommand
|
||||
@PlayerCommand
|
||||
@WorldCommand
|
||||
@Command(
|
||||
usage = "/terra spawn"
|
||||
)
|
||||
public class SpawnCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
Location p = player.getLocation();
|
||||
int x = p.getBlockX();
|
||||
int y = p.getBlockY();
|
||||
int z = p.getBlockZ();
|
||||
Position dummy = new Position(0, 0);
|
||||
|
||||
String check = new CheckFunction(main, new NumericConstant(0, dummy), new NumericConstant(0, dummy), new NumericConstant(0, dummy), dummy).apply(new TerraImplementationArguments(new StructureBuffer(
|
||||
new com.dfsek.terra.api.math.vector.Location(player.getWorld(), x, y, z)
|
||||
), Rotation.NONE, new FastRandom(), 0), new HashMap<>());
|
||||
|
||||
sender.sendMessage("Found: " + check);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.dfsek.terra.commands.structure;
|
||||
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.Subcommand;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.config.lang.LangUtil;
|
||||
|
||||
@Command(
|
||||
subcommands = {
|
||||
@Subcommand(
|
||||
clazz = StructureExportCommand.class,
|
||||
value = "export",
|
||||
aliases = "ex"
|
||||
),
|
||||
@Subcommand(
|
||||
clazz = StructureLoadCommand.class,
|
||||
value = "load",
|
||||
aliases = "ld"
|
||||
),
|
||||
@Subcommand(
|
||||
clazz = SpawnCommand.class,
|
||||
value = "spawn",
|
||||
aliases = "s"
|
||||
)
|
||||
},
|
||||
usage = "/te structure"
|
||||
)
|
||||
public class StructureCommand implements CommandTemplate {
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
LangUtil.send("command.structure.main-menu", sender);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package com.dfsek.terra.commands.structure;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Argument;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.math.vector.Location;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.block.Block;
|
||||
import com.dfsek.terra.api.platform.block.BlockData;
|
||||
import com.dfsek.terra.api.platform.block.state.BlockState;
|
||||
import com.dfsek.terra.api.platform.block.state.Sign;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
@PlayerCommand
|
||||
@WorldCommand
|
||||
@DebugCommand
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(
|
||||
value = "id"
|
||||
)
|
||||
},
|
||||
usage = "/terra structure export <ID>"
|
||||
)
|
||||
public class StructureExportCommand implements CommandTemplate {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@ArgumentTarget("id")
|
||||
private String id;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
Player player = (Player) sender;
|
||||
|
||||
Pair<Location, Location> l = main.getWorldHandle().getSelectedLocation(player);
|
||||
|
||||
Location l1 = l.getLeft();
|
||||
Location l2 = l.getRight();
|
||||
|
||||
StringBuilder scriptBuilder = new StringBuilder("id \"" + id + "\";\nnum y = 0;\n");
|
||||
|
||||
int centerX = 0;
|
||||
int centerY = 0;
|
||||
int centerZ = 0;
|
||||
|
||||
for(int x = l1.getBlockX(); x <= l2.getBlockX(); x++) {
|
||||
for(int y = l1.getBlockY(); y <= l2.getBlockY(); y++) {
|
||||
for(int z = l1.getBlockZ(); z <= l2.getBlockZ(); z++) {
|
||||
Block block = new Location(l1.getWorld(), x, y, z).getBlock();
|
||||
BlockState state = block.getState();
|
||||
if(state instanceof Sign) {
|
||||
Sign sign = (Sign) state;
|
||||
if(sign.getLine(0).equals("[TERRA]") && sign.getLine(1).equals("[CENTER]")) {
|
||||
centerX = x - l1.getBlockX();
|
||||
centerY = y - l1.getBlockY();
|
||||
centerZ = z - l1.getBlockZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int x = l1.getBlockX(); x <= l2.getBlockX(); x++) {
|
||||
for(int y = l1.getBlockY(); y <= l2.getBlockY(); y++) {
|
||||
for(int z = l1.getBlockZ(); z <= l2.getBlockZ(); z++) {
|
||||
|
||||
Block block = new Location(l1.getWorld(), x, y, z).getBlock();
|
||||
BlockData data = block.getBlockData();
|
||||
if(block.getBlockData().isStructureVoid()) continue;
|
||||
BlockState state = block.getState();
|
||||
if(state instanceof Sign) {
|
||||
Sign sign = (Sign) state;
|
||||
if(sign.getLine(0).equals("[TERRA]")) {
|
||||
data = main.getWorldHandle().createBlockData(sign.getLine(2) + sign.getLine(3));
|
||||
}
|
||||
}
|
||||
if(!data.isStructureVoid()) {
|
||||
scriptBuilder.append("block(").append(x - l1.getBlockX() - centerX).append(", y + ").append(y - l1.getBlockY() - centerY).append(", ").append(z - l1.getBlockZ() - centerZ).append(", ")
|
||||
.append("\"");
|
||||
scriptBuilder.append(data.getAsString()).append("\");\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File file = new File(main.getDataFolder() + File.separator + "export" + File.separator + "structures", id + ".tesf");
|
||||
try {
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
} catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try(BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||
writer.write(scriptBuilder.toString());
|
||||
} catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
sender.sendMessage("Exported structure to " + file.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.dfsek.terra.commands.structure;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.annotation.Argument;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.Switch;
|
||||
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||
import com.dfsek.terra.api.command.annotation.inject.SwitchTarget;
|
||||
import com.dfsek.terra.api.command.annotation.type.DebugCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.PlayerCommand;
|
||||
import com.dfsek.terra.api.command.annotation.type.WorldCommand;
|
||||
import com.dfsek.terra.api.command.arg.IntegerArgumentParser;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.structures.script.StructureScript;
|
||||
import com.dfsek.terra.api.structures.structure.Rotation;
|
||||
import com.dfsek.terra.api.util.FastRandom;
|
||||
import com.dfsek.terra.commands.structure.argument.ScriptArgumentParser;
|
||||
import com.dfsek.terra.commands.structure.completer.RotationCompleter;
|
||||
import com.dfsek.terra.commands.structure.completer.ScriptCompleter;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@PlayerCommand
|
||||
@DebugCommand
|
||||
@WorldCommand
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(
|
||||
value = "structure",
|
||||
tabCompleter = ScriptCompleter.class,
|
||||
argumentParser = ScriptArgumentParser.class
|
||||
),
|
||||
@Argument(
|
||||
value = "rotation",
|
||||
required = false,
|
||||
tabCompleter = RotationCompleter.class,
|
||||
argumentParser = IntegerArgumentParser.class,
|
||||
defaultValue = "0"
|
||||
)
|
||||
},
|
||||
switches = {
|
||||
@Switch(value = "chunk",
|
||||
aliases = "c"
|
||||
)
|
||||
},
|
||||
usage = "/terra structure load [ROTATION] [-c]"
|
||||
)
|
||||
public class StructureLoadCommand implements CommandTemplate {
|
||||
@ArgumentTarget("rotation")
|
||||
private Integer rotation = 0;
|
||||
|
||||
@SwitchTarget("chunk")
|
||||
private boolean chunk;
|
||||
|
||||
@ArgumentTarget("structure")
|
||||
private StructureScript script;
|
||||
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
System.out.println(rotation);
|
||||
|
||||
Player player = (Player) sender;
|
||||
|
||||
long t = System.nanoTime();
|
||||
FastRandom random = new FastRandom(ThreadLocalRandom.current().nextLong());
|
||||
Rotation r;
|
||||
try {
|
||||
r = Rotation.fromDegrees(rotation);
|
||||
} catch(Exception e) {
|
||||
sender.sendMessage("Invalid rotation: " + rotation);
|
||||
return;
|
||||
}
|
||||
if(script == null) {
|
||||
sender.sendMessage("Invalid structure.");
|
||||
return;
|
||||
}
|
||||
if(this.chunk) {
|
||||
script.execute(player.getLocation(), player.getWorld().getChunkAt(player.getLocation()), random, r);
|
||||
} else {
|
||||
script.execute(player.getLocation(), random, r);
|
||||
}
|
||||
long l = System.nanoTime() - t;
|
||||
|
||||
sender.sendMessage("Took " + ((double) l) / 1000000 + "ms");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.dfsek.terra.commands.structure.argument;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.arg.ArgumentParser;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.structures.script.StructureScript;
|
||||
|
||||
public class ScriptArgumentParser implements ArgumentParser<StructureScript> {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public StructureScript parse(CommandSender sender, String arg) {
|
||||
return main.getWorld(((Player) sender).getWorld()).getConfig().getScriptRegistry().get(arg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.commands.structure.completer;
|
||||
|
||||
import com.dfsek.terra.api.command.tab.TabCompleter;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class RotationCompleter implements TabCompleter {
|
||||
@Override
|
||||
public List<String> complete(CommandSender sender) {
|
||||
return Arrays.asList("0", "90", "180", "270");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.dfsek.terra.commands.structure.completer;
|
||||
|
||||
import com.dfsek.terra.api.TerraPlugin;
|
||||
import com.dfsek.terra.api.command.tab.TabCompleter;
|
||||
import com.dfsek.terra.api.injection.annotations.Inject;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import com.dfsek.terra.api.platform.entity.Player;
|
||||
import com.dfsek.terra.api.structures.script.StructureScript;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ScriptCompleter implements TabCompleter {
|
||||
@Inject
|
||||
private TerraPlugin main;
|
||||
|
||||
@Override
|
||||
public List<String> complete(CommandSender sender) {
|
||||
return main.getWorld(((Player) sender).getWorld()).getConfig().getScriptRegistry().entries().stream().map(StructureScript::getId).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -63,11 +63,6 @@ public class DummyWorld implements World {
|
||||
throw new UnsupportedOperationException("Cannot get block in DummyWorld");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getBlockAt(Location l) {
|
||||
throw new UnsupportedOperationException("Cannot get block in DummyWorld");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity spawnEntity(Location location, EntityType entityType) {
|
||||
throw new UnsupportedOperationException("Cannot spawn entity in DummyWorld");
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package com.dfsek.terra.config.loaders.config.biome.templates.provider;
|
||||
|
||||
import com.dfsek.tectonic.annotations.Value;
|
||||
import com.dfsek.terra.api.world.biome.TerraBiome;
|
||||
import com.dfsek.terra.api.world.biome.provider.BiomeProvider;
|
||||
import com.dfsek.terra.api.world.biome.provider.SingleBiomeProvider;
|
||||
import com.dfsek.terra.config.builder.BiomeBuilder;
|
||||
|
||||
public class SingleBiomeProviderTemplate extends BiomeProviderTemplate {
|
||||
@Value("biome")
|
||||
private TerraBiome biome;
|
||||
private BiomeBuilder biome;
|
||||
|
||||
public SingleBiomeProviderTemplate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeProvider build(long seed) {
|
||||
return new SingleBiomeProvider(biome);
|
||||
return new SingleBiomeProvider(biome.apply(seed));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,6 +274,7 @@ public class ConfigPack implements LoaderRegistrar {
|
||||
.registerLoader(NoiseSeeded.class, new NoiseSamplerBuilderLoader(noiseRegistry))
|
||||
.registerLoader(SingleBiomeProviderTemplate.class, SingleBiomeProviderTemplate::new)
|
||||
.registerLoader(BiomePipelineTemplate.class, () -> new BiomePipelineTemplate(main))
|
||||
.registerLoader(ImageProviderTemplate.class, () -> new ImageProviderTemplate(biomeRegistry))
|
||||
.registerLoader(ImageSamplerTemplate.class, () -> new ImageProviderTemplate(biomeRegistry));
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import com.dfsek.terra.api.platform.world.World;
|
||||
import com.dfsek.terra.api.util.world.PopulationUtil;
|
||||
import com.dfsek.terra.api.world.generation.TerraBlockPopulator;
|
||||
import com.dfsek.terra.carving.UserDefinedCarver;
|
||||
import com.dfsek.terra.config.pack.ConfigPack;
|
||||
import com.dfsek.terra.config.pack.WorldConfig;
|
||||
import com.dfsek.terra.config.templates.CarverTemplate;
|
||||
import com.dfsek.terra.profiler.ProfileFuture;
|
||||
@@ -49,7 +48,7 @@ public class CavePopulator implements TerraBlockPopulator {
|
||||
Set<Block> updateNeeded = new HashSet<>();
|
||||
c.carve(chunk.getX(), chunk.getZ(), world, (v, type) -> {
|
||||
Block b = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
|
||||
BlockData m = handle.getBlockData(b);
|
||||
BlockData m = b.getBlockData();
|
||||
BlockType re = m.getBlockType();
|
||||
switch(type) {
|
||||
case CENTER:
|
||||
@@ -85,18 +84,18 @@ public class CavePopulator implements TerraBlockPopulator {
|
||||
for(Map.Entry<Location, BlockData> entry : shiftCandidate.entrySet()) {
|
||||
Location l = entry.getKey();
|
||||
Location mut = l.clone();
|
||||
BlockData orig = handle.getBlockData(l.getBlock());
|
||||
BlockData orig = l.getBlock().getBlockData();
|
||||
do mut.subtract(0, 1, 0);
|
||||
while(mut.getY() > 0 && handle.getBlockData(mut.getBlock()).matches(orig));
|
||||
while(mut.getY() > 0 && mut.getBlock().getBlockData().matches(orig));
|
||||
try {
|
||||
if(template.getShift().get(entry.getValue().getBlockType()).contains(mut.getBlock().getBlockData().getBlockType())) {
|
||||
handle.setBlockData(mut.getBlock(), shiftStorage.computeIfAbsent(entry.getValue().getBlockType(), BlockType::getDefaultData), false);
|
||||
mut.getBlock().setBlockData(shiftStorage.computeIfAbsent(entry.getValue().getBlockType(), BlockType::getDefaultData), false);
|
||||
}
|
||||
} catch(NullPointerException ignore) {
|
||||
}
|
||||
}
|
||||
for(Block b : updateNeeded) {
|
||||
BlockData orig = handle.getBlockData(b);
|
||||
BlockData orig = b.getBlockData();
|
||||
b.setBlockData(AIR, false);
|
||||
b.setBlockData(orig, true);
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ public class TerraFlora implements Flora {
|
||||
((Rotatable) data).setRotation(oneFace);
|
||||
}
|
||||
}
|
||||
handle.setBlockData(location.clone().add(0, i + c, 0).getBlock(), data, physics);
|
||||
location.clone().add(0, i + c, 0).getBlock().setBlockData(data, physics);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public class DeformedSphereOre extends Ore {
|
||||
if(oreLoc.distance(origin) < (rad + 0.5) * ((ore.getNoise(x, y, z) + 1) * deform)) {
|
||||
Block b = c.getBlock(oreLoc.getBlockX(), oreLoc.getBlockY(), oreLoc.getBlockZ());
|
||||
if(getReplaceable().contains(b.getType()) && b.getLocation().getY() >= 0)
|
||||
handle.setBlockData(b, getMaterial(), isApplyGravity());
|
||||
b.setBlockData(getMaterial(), isApplyGravity());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ public class VanillaOre extends Ore {
|
||||
if(x > 15 || z > 15 || y > 255 || x < 0 || z < 0 || y < 0) continue;
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
if((d13 * d13 + d14 * d14 + d15 * d15 < 1.0D) && getReplaceable().contains(block.getType())) {
|
||||
handle.setBlockData(block, getMaterial(), isApplyGravity());
|
||||
block.setBlockData(getMaterial(), isApplyGravity());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ warning:
|
||||
error:
|
||||
severe-config: "A severe configuration error has prevented Terra from properly generating terrain at coordinates: %1$s, %2$s. Please check your configuration for errors. Any config errors will have been reported above."
|
||||
debug:
|
||||
data-save: "Saved population data for world \"%s\""
|
||||
data-save : "Saved population data."
|
||||
use-paper:
|
||||
- "You appear to be using Spigot/CraftBukkit."
|
||||
- "While Terra &odoes&r work on Spigot, some functionality will be lost. (Terra is untested on CraftBukkit; no support will be given for CraftBukkit)."
|
||||
|
||||
236
common/src/test/java/command/CommandTest.java
Normal file
236
common/src/test/java/command/CommandTest.java
Normal file
@@ -0,0 +1,236 @@
|
||||
package command;
|
||||
|
||||
import com.dfsek.terra.api.command.CommandManager;
|
||||
import com.dfsek.terra.api.command.CommandTemplate;
|
||||
import com.dfsek.terra.api.command.TerraCommandManager;
|
||||
import com.dfsek.terra.api.command.annotation.Argument;
|
||||
import com.dfsek.terra.api.command.annotation.Command;
|
||||
import com.dfsek.terra.api.command.annotation.Subcommand;
|
||||
import com.dfsek.terra.api.command.annotation.Switch;
|
||||
import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget;
|
||||
import com.dfsek.terra.api.command.annotation.inject.SwitchTarget;
|
||||
import com.dfsek.terra.api.command.arg.DoubleArgumentParser;
|
||||
import com.dfsek.terra.api.command.arg.IntegerArgumentParser;
|
||||
import com.dfsek.terra.api.command.exception.CommandException;
|
||||
import com.dfsek.terra.api.command.exception.InvalidArgumentsException;
|
||||
import com.dfsek.terra.api.command.exception.MalformedCommandException;
|
||||
import com.dfsek.terra.api.platform.CommandSender;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class CommandTest {
|
||||
@Test
|
||||
public void subcommand() throws CommandException {
|
||||
CommandManager manager = new TerraCommandManager(null);
|
||||
manager.register("test", DemoParentCommand.class);
|
||||
|
||||
manager.execute("test", null, Arrays.asList("subcommand1", "first", "2"));
|
||||
manager.execute("test", null, Arrays.asList("subcommand2", "first", "2"));
|
||||
manager.execute("test", null, Arrays.asList("s1", "first", "2", "3.4"));
|
||||
manager.execute("test", null, Arrays.asList("s2", "first", "2"));
|
||||
manager.execute("test", null, Arrays.asList("sub1", "first", "2", "3.4"));
|
||||
manager.execute("test", null, Arrays.asList("sub2", "first", "2"));
|
||||
manager.execute("test", null, Arrays.asList("first", "2")); // Parent command args
|
||||
|
||||
System.out.println("ARGS: " + manager.getMaxArgumentDepth());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void args() throws CommandException {
|
||||
CommandManager manager = new TerraCommandManager(null);
|
||||
manager.register("test", DemoCommand.class);
|
||||
|
||||
manager.execute("test", null, Arrays.asList("first", "2"));
|
||||
manager.execute("test", null, Arrays.asList("first", "2", "3.4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void argsBeforeFlags() throws CommandException {
|
||||
CommandManager manager = new TerraCommandManager(null);
|
||||
manager.register("test", DemoCommand.class);
|
||||
|
||||
try {
|
||||
manager.execute("test", null, Arrays.asList("first", "-flag", "2"));
|
||||
fail();
|
||||
} catch(InvalidArgumentsException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requiredArgsFirst() throws CommandException {
|
||||
CommandManager manager = new TerraCommandManager(null);
|
||||
manager.register("test", DemoInvalidCommand.class);
|
||||
|
||||
try {
|
||||
manager.execute("test", null, Arrays.asList("first", "2"));
|
||||
fail();
|
||||
} catch(MalformedCommandException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void switches() throws CommandException {
|
||||
CommandManager manager = new TerraCommandManager(null);
|
||||
manager.register("test", DemoSwitchCommand.class);
|
||||
|
||||
manager.execute("test", null, Arrays.asList("first", "2"));
|
||||
manager.execute("test", null, Arrays.asList("first", "2", "3.4"));
|
||||
|
||||
manager.execute("test", null, Arrays.asList("first", "2", "-a"));
|
||||
manager.execute("test", null, Arrays.asList("first", "2", "3.4", "-b"));
|
||||
|
||||
manager.execute("test", null, Arrays.asList("first", "2", "-aSwitch"));
|
||||
manager.execute("test", null, Arrays.asList("first", "2", "3.4", "-bSwitch"));
|
||||
|
||||
manager.execute("test", null, Arrays.asList("first", "2", "-aSwitch", "-b"));
|
||||
manager.execute("test", null, Arrays.asList("first", "2", "3.4", "-bSwitch", "-a"));
|
||||
}
|
||||
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(value = "arg0"),
|
||||
@Argument(value = "arg1", argumentParser = IntegerArgumentParser.class),
|
||||
@Argument(value = "arg2", required = false, argumentParser = DoubleArgumentParser.class)
|
||||
}
|
||||
)
|
||||
public static final class DemoCommand implements CommandTemplate {
|
||||
|
||||
@ArgumentTarget("arg0")
|
||||
private String arg0;
|
||||
|
||||
@ArgumentTarget("arg1")
|
||||
private Integer arg1;
|
||||
|
||||
@ArgumentTarget("arg2")
|
||||
private Double arg2;
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
System.out.println(arg0);
|
||||
System.out.println(arg1);
|
||||
System.out.println(arg2);
|
||||
}
|
||||
}
|
||||
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(value = "arg0"),
|
||||
@Argument(value = "arg1"),
|
||||
@Argument(value = "arg2", required = false)
|
||||
},
|
||||
switches = {
|
||||
@Switch(value = "a", aliases = {"aSwitch"}),
|
||||
@Switch(value = "b", aliases = {"bSwitch"})
|
||||
}
|
||||
)
|
||||
public static final class DemoSwitchCommand implements CommandTemplate {
|
||||
@ArgumentTarget("arg0")
|
||||
private String arg0;
|
||||
|
||||
@ArgumentTarget("arg1")
|
||||
private String arg1;
|
||||
|
||||
@ArgumentTarget("arg2")
|
||||
private String arg2;
|
||||
|
||||
@SwitchTarget("a")
|
||||
private boolean a;
|
||||
|
||||
@SwitchTarget("b")
|
||||
private boolean b;
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
System.out.println(arg0);
|
||||
System.out.println(arg1);
|
||||
System.out.println(arg2);
|
||||
|
||||
System.out.println("A: " + a);
|
||||
System.out.println("B: " + b);
|
||||
}
|
||||
}
|
||||
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(value = "arg0"),
|
||||
@Argument(value = "arg2", required = false), // optional arguments must be last. this command is invalid.
|
||||
@Argument(value = "arg1")
|
||||
}
|
||||
)
|
||||
public static final class DemoInvalidCommand implements CommandTemplate {
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
throw new Error("this should never be reached");
|
||||
}
|
||||
}
|
||||
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(value = "arg0"),
|
||||
@Argument(value = "arg1"),
|
||||
@Argument(value = "arg2", required = false),
|
||||
},
|
||||
subcommands = {
|
||||
@Subcommand(
|
||||
value = "subcommand1",
|
||||
aliases = {"s1", "sub1"},
|
||||
clazz = DemoChildCommand.class
|
||||
),
|
||||
@Subcommand(
|
||||
value = "subcommand2",
|
||||
aliases = {"s2", "sub2"},
|
||||
clazz = DemoChildCommand.class // Duplicate command intentional.
|
||||
)
|
||||
}
|
||||
)
|
||||
public static final class DemoParentCommand implements CommandTemplate {
|
||||
@ArgumentTarget("arg0")
|
||||
private String arg0;
|
||||
|
||||
@ArgumentTarget("arg1")
|
||||
private String arg1;
|
||||
|
||||
@ArgumentTarget("arg2")
|
||||
private String arg2;
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
System.out.println(arg0);
|
||||
System.out.println(arg1);
|
||||
System.out.println(arg2);
|
||||
}
|
||||
}
|
||||
|
||||
@Command(
|
||||
arguments = {
|
||||
@Argument(value = "arg0"),
|
||||
@Argument(value = "arg1"),
|
||||
@Argument(value = "arg2", required = false),
|
||||
}
|
||||
)
|
||||
public static final class DemoChildCommand implements CommandTemplate {
|
||||
@ArgumentTarget("arg0")
|
||||
private String arg0;
|
||||
|
||||
@ArgumentTarget("arg1")
|
||||
private String arg1;
|
||||
|
||||
@ArgumentTarget("arg2")
|
||||
private String arg2;
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender) {
|
||||
System.out.println(arg0);
|
||||
System.out.println(arg1);
|
||||
System.out.println(arg2);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user