Archived
0

Changes I made before breaking my local repository. Hoping this works.

This commit is contained in:
Dico Karssiens
2018-11-11 14:06:45 +00:00
parent e55c595e54
commit 0f196f59c6
184 changed files with 17998 additions and 17998 deletions

View File

@@ -1,19 +1,19 @@
[*] [*]
charset=utf-8 charset=utf-8
end_of_line=lf end_of_line=lf
insert_final_newline=false insert_final_newline=false
indent_style=space indent_style=space
indent_size=4 indent_size=4
[{.babelrc,.stylelintrc,jest.config,.eslintrc,*.bowerrc,*.jsb3,*.jsb2,*.json}] [{.babelrc,.stylelintrc,jest.config,.eslintrc,*.bowerrc,*.jsb3,*.jsb2,*.json}]
indent_style=space indent_style=space
indent_size=2 indent_size=2
[{*.ddl,*.sql}] [{*.ddl,*.sql}]
indent_style=space indent_style=space
indent_size=2 indent_size=2
[{*.yml,*.yaml}] [{*.yml,*.yaml}]
indent_style=space indent_style=space
indent_size=2 indent_size=2

3
.gitignore vendored
View File

@@ -6,4 +6,5 @@ build/
/debug/ /debug/
target/ target/
/gradle-output.txt /gradle-output.txt
/*.java /*.java
*.dump

View File

@@ -1,16 +1,16 @@
# Parcels2 # Parcels2
Plot management and world generator plugin inspired by [PlotMe](https://github.com/WorldCretornica/PlotMe-Core). Plot management and world generator plugin inspired by [PlotMe](https://github.com/WorldCretornica/PlotMe-Core).
Newer version of discontinued [Parcels](https://github.com/RedstonerServer/Parcels). Newer version of discontinued [Parcels](https://github.com/RedstonerServer/Parcels).
Written in Kotlin. Written in Kotlin.
This project is WIP. This project is WIP.
![world screenshot](https://i.imgur.com/tpbKrQI.png) ![world screenshot](https://i.imgur.com/tpbKrQI.png)
## Build ## Build
1. Add `worldedit-bukkit-7.0.0-beta-01.jar` to `/debug/plugins` directory 1. Add `worldedit-bukkit-7.0.0-beta-01.jar` to `/debug/plugins` directory
2. Run `gradle releaseJar` 2. Run `gradle releaseJar`
3. Kotlin stdlib classpath is placed in `/debug/lib` directory and artifact can be found in `/debug/plugins` directory 3. Kotlin stdlib classpath is placed in `/debug/lib` directory and artifact can be found in `/debug/plugins` directory

View File

@@ -13,22 +13,22 @@ version = "0.2"
plugins { plugins {
java java
kotlin("jvm") version "1.3.0-rc-57" kotlin("jvm") version "1.3.0-rc-146"
id("com.github.johnrengelman.plugin-shadow") version "2.0.3" id("com.github.johnrengelman.plugin-shadow") version "2.0.3"
} }
allprojects { allprojects {
apply<JavaPlugin>() apply<JavaPlugin>()
apply(plugin = "idea") apply(plugin = "idea")
repositories { repositories {
mavenCentral() mavenCentral()
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots") maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
maven("https://hub.spigotmc.org/nexus/content/repositories/sonatype-nexus-snapshots") maven("https://hub.spigotmc.org/nexus/content/repositories/sonatype-nexus-snapshots/")
maven("https://dl.bintray.com/kotlin/exposed") maven("https://dl.bintray.com/kotlin/exposed/")
maven("https://dl.bintray.com/kotlin/kotlin-eap") maven("https://dl.bintray.com/kotlin/kotlin-dev/")
maven("https://dl.bintray.com/kotlin/kotlin-eap/")
maven("https://dl.bintray.com/kotlin/kotlinx/") maven("https://dl.bintray.com/kotlin/kotlinx/")
} }
@@ -146,11 +146,6 @@ tasks {
val jarUrl = URL("https://yivesmirror.com/files/spigot/spigot-latest.jar") val jarUrl = URL("https://yivesmirror.com/files/spigot/spigot-latest.jar")
val serverJarFile = file("$serverDir/lib/spigot.jar") val serverJarFile = file("$serverDir/lib/spigot.jar")
doFirst {
}
} }
} }
@@ -171,5 +166,8 @@ val ConfigurationContainer.`provided`: Configuration
val ConfigurationContainer.`kotlinStd`: Configuration val ConfigurationContainer.`kotlinStd`: Configuration
get() = findByName("kotlinStd") ?: create("kotlinStd").let { compileClasspath.extendsFrom(it) } get() = findByName("kotlinStd") ?: create("kotlinStd").let { compileClasspath.extendsFrom(it) }
fun Jar.fromFiles(files: Iterable<File>) = fun Jar.fromFiles(files: Iterable<File>) {
return
afterEvaluate { from(*files.map { if (it.isDirectory) it else zipTree(it) }.toTypedArray()) } afterEvaluate { from(*files.map { if (it.isDirectory) it else zipTree(it) }.toTypedArray()) }
}

View File

@@ -1,120 +1,120 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import io.dico.dicore.command.predef.DefaultGroupCommand; import io.dico.dicore.command.predef.DefaultGroupCommand;
import io.dico.dicore.command.predef.HelpCommand; import io.dico.dicore.command.predef.HelpCommand;
import java.util.*; import java.util.*;
public class ChildCommandAddress extends ModifiableCommandAddress { public class ChildCommandAddress extends ModifiableCommandAddress {
ModifiableCommandAddress parent; ModifiableCommandAddress parent;
final List<String> namesModifiable = new ArrayList<>(4); final List<String> namesModifiable = new ArrayList<>(4);
List<String> names = namesModifiable; List<String> names = namesModifiable;
Command command; Command command;
boolean isCommandTrailing; boolean isCommandTrailing;
public ChildCommandAddress() { public ChildCommandAddress() {
} }
public ChildCommandAddress(Command command) { public ChildCommandAddress(Command command) {
this.command = command; this.command = command;
} }
public ChildCommandAddress(Command command, String name, String... aliases) { public ChildCommandAddress(Command command, String name, String... aliases) {
this(command); this(command);
addNameAndAliases(name, aliases); addNameAndAliases(name, aliases);
} }
public static ChildCommandAddress newPlaceHolderCommand(String name, String... aliases) { public static ChildCommandAddress newPlaceHolderCommand(String name, String... aliases) {
ChildCommandAddress rv = new ChildCommandAddress(); ChildCommandAddress rv = new ChildCommandAddress();
rv.setupAsPlaceholder(name, aliases); rv.setupAsPlaceholder(name, aliases);
return rv; return rv;
} }
public void setupAsPlaceholder(String name, String... aliases) { public void setupAsPlaceholder(String name, String... aliases) {
if (!hasCommand()) { if (!hasCommand()) {
setCommand(DefaultGroupCommand.getInstance()); setCommand(DefaultGroupCommand.getInstance());
} }
addNameAndAliases(name, aliases); addNameAndAliases(name, aliases);
HelpCommand.registerAsChild(this); HelpCommand.registerAsChild(this);
} }
@Override @Override
public boolean isRoot() { public boolean isRoot() {
return false; return false;
} }
@Override @Override
public ModifiableCommandAddress getParent() { public ModifiableCommandAddress getParent() {
return parent; return parent;
} }
@Override @Override
public Command getCommand() { public Command getCommand() {
return command; return command;
} }
@Override @Override
public void setCommand(Command command) { public void setCommand(Command command) {
if (hasUserDeclaredCommand()) { if (hasUserDeclaredCommand()) {
throw new IllegalStateException("Command is already set at address \"" + getAddress() + "\""); throw new IllegalStateException("Command is already set at address \"" + getAddress() + "\"");
} }
this.command = command; this.command = command;
} }
@Override @Override
public List<String> getNames() { public List<String> getNames() {
return names; return names;
} }
public void addNameAndAliases(String name, String... aliases) { public void addNameAndAliases(String name, String... aliases) {
names.add(name); names.add(name);
names.addAll(Arrays.asList(aliases)); names.addAll(Arrays.asList(aliases));
} }
@Override @Override
public String getMainKey() { public String getMainKey() {
return namesModifiable.isEmpty() ? null : namesModifiable.get(0); return namesModifiable.isEmpty() ? null : namesModifiable.get(0);
} }
@Override @Override
public String getAddress() { public String getAddress() {
ICommandAddress address = this; ICommandAddress address = this;
int depth = getDepth(); int depth = getDepth();
String[] keys = new String[depth]; String[] keys = new String[depth];
for (int i = depth - 1; i >= 0; i--) { for (int i = depth - 1; i >= 0; i--) {
keys[i] = address.getMainKey(); keys[i] = address.getMainKey();
address = address.getParent(); address = address.getParent();
} }
return String.join(" ", keys); return String.join(" ", keys);
} }
public void finalizeNames() { public void finalizeNames() {
if (names == namesModifiable) { if (names == namesModifiable) {
names = Collections.unmodifiableList(namesModifiable); names = Collections.unmodifiableList(namesModifiable);
} }
} }
Iterator<String> modifiableNamesIterator() { Iterator<String> modifiableNamesIterator() {
return namesModifiable.iterator(); return namesModifiable.iterator();
} }
void setParent(ModifiableCommandAddress parent) { void setParent(ModifiableCommandAddress parent) {
finalizeNames(); finalizeNames();
this.parent = parent; this.parent = parent;
} }
@Override @Override
public boolean isCommandTrailing() { public boolean isCommandTrailing() {
return isCommandTrailing; return isCommandTrailing;
} }
@Override @Override
public void setCommandTrailing(boolean trailing) { public void setCommandTrailing(boolean trailing) {
if (hasChildren()) { if (hasChildren()) {
throw new IllegalStateException("Address already has children, this property can't be modified"); throw new IllegalStateException("Address already has children, this property can't be modified");
} }
isCommandTrailing = trailing; isCommandTrailing = trailing;
} }
} }

View File

@@ -1,158 +1,158 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import io.dico.dicore.command.IContextFilter.Priority; import io.dico.dicore.command.IContextFilter.Priority;
import io.dico.dicore.command.parameter.ArgumentBuffer; import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.parameter.IArgumentPreProcessor; import io.dico.dicore.command.parameter.IArgumentPreProcessor;
import io.dico.dicore.command.parameter.Parameter; import io.dico.dicore.command.parameter.Parameter;
import io.dico.dicore.command.parameter.ParameterList; import io.dico.dicore.command.parameter.ParameterList;
import io.dico.dicore.command.parameter.type.ParameterType; import io.dico.dicore.command.parameter.type.ParameterType;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
public abstract class Command { public abstract class Command {
private static final String[] EMPTY_DESCRIPTION = new String[0]; private static final String[] EMPTY_DESCRIPTION = new String[0];
private final ParameterList parameterList = new ParameterList(); private final ParameterList parameterList = new ParameterList();
private final List<IContextFilter> contextFilters = new ArrayList<>(3); private final List<IContextFilter> contextFilters = new ArrayList<>(3);
private String[] description = EMPTY_DESCRIPTION; private String[] description = EMPTY_DESCRIPTION;
private String shortDescription; private String shortDescription;
public Command addParameter(Parameter<?, ?> parameter) { public Command addParameter(Parameter<?, ?> parameter) {
parameterList.addParameter(parameter); parameterList.addParameter(parameter);
return this; return this;
} }
public <TType> Command addParameter(String name, String description, ParameterType<TType, Void> type) { public <TType> Command addParameter(String name, String description, ParameterType<TType, Void> type) {
return addParameter(new Parameter<>(name, description, type, null, false, null)); return addParameter(new Parameter<>(name, description, type, null, false, null));
} }
public <TType, TParamInfo> Command addParameter(String name, String description, ParameterType<TType, TParamInfo> type, TParamInfo paramInfo) { public <TType, TParamInfo> Command addParameter(String name, String description, ParameterType<TType, TParamInfo> type, TParamInfo paramInfo) {
return addParameter(new Parameter<>(name, description, type, paramInfo, false, null)); return addParameter(new Parameter<>(name, description, type, paramInfo, false, null));
} }
public <TType> Command addFlag(String name, String description, ParameterType<TType, Void> type) { public <TType> Command addFlag(String name, String description, ParameterType<TType, Void> type) {
return addParameter(new Parameter<>('-' + name, description, type, null, true, null)); return addParameter(new Parameter<>('-' + name, description, type, null, true, null));
} }
public <TType, TParamInfo> Command addFlag(String name, String description, ParameterType<TType, TParamInfo> type, TParamInfo paramInfo) { public <TType, TParamInfo> Command addFlag(String name, String description, ParameterType<TType, TParamInfo> type, TParamInfo paramInfo) {
return addParameter(new Parameter<>('-' + name, description, type, paramInfo, true, null)); return addParameter(new Parameter<>('-' + name, description, type, paramInfo, true, null));
} }
public <TType> Command addAuthorizedFlag(String name, String description, ParameterType<TType, Void> type, String permission) { public <TType> Command addAuthorizedFlag(String name, String description, ParameterType<TType, Void> type, String permission) {
return addParameter(new Parameter<>('-' + name, description, type, null, true, permission)); return addParameter(new Parameter<>('-' + name, description, type, null, true, permission));
} }
public <TType, TParamInfo> Command addAuthorizedFlag(String name, String description, ParameterType<TType, TParamInfo> type, TParamInfo paramInfo, String permission) { public <TType, TParamInfo> Command addAuthorizedFlag(String name, String description, ParameterType<TType, TParamInfo> type, TParamInfo paramInfo, String permission) {
return addParameter(new Parameter<>('-' + name, description, type, paramInfo, true, permission)); return addParameter(new Parameter<>('-' + name, description, type, paramInfo, true, permission));
} }
public Command requiredParameters(int requiredParameters) { public Command requiredParameters(int requiredParameters) {
parameterList.setRequiredCount(requiredParameters); parameterList.setRequiredCount(requiredParameters);
return this; return this;
} }
public Command repeatFinalParameter() { public Command repeatFinalParameter() {
parameterList.setRepeatFinalParameter(true); parameterList.setRepeatFinalParameter(true);
return this; return this;
} }
public Command setDescription(String... description) { public Command setDescription(String... description) {
this.description = Objects.requireNonNull(description); this.description = Objects.requireNonNull(description);
return this; return this;
} }
public Command setShortDescription(String shortDescription) { public Command setShortDescription(String shortDescription) {
this.shortDescription = shortDescription; this.shortDescription = shortDescription;
return this; return this;
} }
/* /*
public Command preprocessArguments(IArgumentPreProcessor processor) { public Command preprocessArguments(IArgumentPreProcessor processor) {
parameterList.setArgumentPreProcessor(processor); parameterList.setArgumentPreProcessor(processor);
return this; return this;
}*/ }*/
public final ParameterList getParameterList() { public final ParameterList getParameterList() {
return parameterList; return parameterList;
} }
public final String[] getDescription() { public final String[] getDescription() {
return description.length == 0 ? description : description.clone(); return description.length == 0 ? description : description.clone();
} }
public String getShortDescription() { public String getShortDescription() {
return shortDescription; return shortDescription;
} }
/** /**
* ---- CONTEXT FILTERS ---- * ---- CONTEXT FILTERS ----
* Filter the contexts. For example, if the sender must be a player but it's the console, * Filter the contexts. For example, if the sender must be a player but it's the console,
* throw a CommandException describing the problem. * throw a CommandException describing the problem.
*/ */
private transient int postParameterFilterCount = 0; private transient int postParameterFilterCount = 0;
public Command addContextFilter(IContextFilter contextFilter) { public Command addContextFilter(IContextFilter contextFilter) {
Objects.requireNonNull(contextFilter); Objects.requireNonNull(contextFilter);
if (!contextFilters.contains(contextFilter)) { if (!contextFilters.contains(contextFilter)) {
contextFilters.add(contextFilter); contextFilters.add(contextFilter);
contextFilters.sort(null); contextFilters.sort(null);
if (contextFilter.getPriority().compareTo(Priority.POST_PARAMETERS) >= 0) { if (contextFilter.getPriority().compareTo(Priority.POST_PARAMETERS) >= 0) {
postParameterFilterCount++; postParameterFilterCount++;
} }
} }
return this; return this;
} }
public List<IContextFilter> getContextFilters() { public List<IContextFilter> getContextFilters() {
return Collections.unmodifiableList(contextFilters); return Collections.unmodifiableList(contextFilters);
} }
public Command removeContextFilter(IContextFilter contextFilter) { public Command removeContextFilter(IContextFilter contextFilter) {
boolean ret = contextFilters.remove(contextFilter); boolean ret = contextFilters.remove(contextFilter);
if (ret) { if (ret) {
if (contextFilter.getPriority().compareTo(Priority.POST_PARAMETERS) >= 0) { if (contextFilter.getPriority().compareTo(Priority.POST_PARAMETERS) >= 0) {
postParameterFilterCount--; postParameterFilterCount--;
} }
} }
return this; return this;
} }
// ---- CONTROL FLOW IN COMMAND TREES ---- // ---- CONTROL FLOW IN COMMAND TREES ----
public boolean isVisibleTo(CommandSender sender) { public boolean isVisibleTo(CommandSender sender) {
return true; return true;
} }
public boolean takePrecedenceOverSubcommand(String subCommand, ArgumentBuffer buffer) { public boolean takePrecedenceOverSubcommand(String subCommand, ArgumentBuffer buffer) {
return false; return false;
} }
// ---- EXECUTION ---- // ---- EXECUTION ----
public void initializeAndFilterContext(ExecutionContext context) throws CommandException { public void initializeAndFilterContext(ExecutionContext context) throws CommandException {
int i, n; int i, n;
for (i = 0, n = contextFilters.size() - postParameterFilterCount; i < n; i++) { for (i = 0, n = contextFilters.size() - postParameterFilterCount; i < n; i++) {
contextFilters.get(i).filterContext(context); contextFilters.get(i).filterContext(context);
} }
context.parse(parameterList); context.parse(parameterList);
if (!context.isTabComplete()) { if (!context.isTabComplete()) {
for (n = contextFilters.size(); i < n; i++) { for (n = contextFilters.size(); i < n; i++) {
contextFilters.get(i).filterContext(context); contextFilters.get(i).filterContext(context);
} }
} }
} }
public abstract String execute(CommandSender sender, ExecutionContext context) throws CommandException; public abstract String execute(CommandSender sender, ExecutionContext context) throws CommandException;
public List<String> tabComplete(CommandSender sender, ExecutionContext context, Location location) { public List<String> tabComplete(CommandSender sender, ExecutionContext context, Location location) {
return context.getSuggestedCompletions(location); return context.getSuggestedCompletions(location);
} }
} }

View File

@@ -1,432 +1,432 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import io.dico.dicore.command.chat.IChatHandler; import io.dico.dicore.command.chat.IChatHandler;
import io.dico.dicore.command.parameter.type.IParameterTypeSelector; import io.dico.dicore.command.parameter.type.IParameterTypeSelector;
import io.dico.dicore.command.parameter.type.MapBasedParameterTypeSelector; import io.dico.dicore.command.parameter.type.MapBasedParameterTypeSelector;
import io.dico.dicore.command.parameter.type.ParameterType; import io.dico.dicore.command.parameter.type.ParameterType;
import io.dico.dicore.command.predef.HelpCommand; import io.dico.dicore.command.predef.HelpCommand;
import io.dico.dicore.command.predef.PredefinedCommand; import io.dico.dicore.command.predef.PredefinedCommand;
import io.dico.dicore.command.predef.SyntaxCommand; import io.dico.dicore.command.predef.SyntaxCommand;
import io.dico.dicore.command.registration.reflect.ReflectiveRegistration; import io.dico.dicore.command.registration.reflect.ReflectiveRegistration;
import java.util.HashSet; import java.util.HashSet;
import java.util.Objects; import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
* Mimic of WorldEdit's CommandGraph * Mimic of WorldEdit's CommandGraph
*/ */
public final class CommandBuilder { public final class CommandBuilder {
private final RootCommandAddress root; private final RootCommandAddress root;
private ModifiableCommandAddress cur; private ModifiableCommandAddress cur;
private IParameterTypeSelector selector; private IParameterTypeSelector selector;
/** /**
* Instantiate a new CommandBuilder with a new command root system * Instantiate a new CommandBuilder with a new command root system
* Commands registered to this command builder might interfere with * Commands registered to this command builder might interfere with
* commands registered to other commands builders or by other plugins. * commands registered to other commands builders or by other plugins.
*/ */
public CommandBuilder() { public CommandBuilder() {
this(new RootCommandAddress()); this(new RootCommandAddress());
} }
/** /**
* Instantiate a new CommandBuilder with a specified root address. * Instantiate a new CommandBuilder with a specified root address.
* If the root address is identical to that of another command builder, * If the root address is identical to that of another command builder,
* they will modify the same tree. * they will modify the same tree.
* *
* @param root the root address * @param root the root address
*/ */
public CommandBuilder(RootCommandAddress root) { public CommandBuilder(RootCommandAddress root) {
this.root = Objects.requireNonNull(root); this.root = Objects.requireNonNull(root);
this.cur = root; this.cur = root;
this.selector = new MapBasedParameterTypeSelector(true); this.selector = new MapBasedParameterTypeSelector(true);
} }
/** /**
* Add a sub command at the current address * Add a sub command at the current address
* The current address can be inspected using {@link #getAddress()} * The current address can be inspected using {@link #getAddress()}
* *
* @param name the name of the command * @param name the name of the command
* @param command the command executor * @param command the command executor
* @param aliases any aliases * @param aliases any aliases
* @return this * @return this
*/ */
public CommandBuilder addSubCommand(String name, Command command, String... aliases) { public CommandBuilder addSubCommand(String name, Command command, String... aliases) {
ChildCommandAddress address = new ChildCommandAddress(command); ChildCommandAddress address = new ChildCommandAddress(command);
address.addNameAndAliases(name, aliases); address.addNameAndAliases(name, aliases);
return addSubCommand(address); return addSubCommand(address);
} }
/** /**
* Add a subcommand as an address at the current address * Add a subcommand as an address at the current address
* The result of this call is the same as * The result of this call is the same as
* {@code addSubCommand(address.getMainKey(), address.getCommand(), address.getNames().sublist(1).toArray(new String[0]))} * {@code addSubCommand(address.getMainKey(), address.getCommand(), address.getNames().sublist(1).toArray(new String[0]))}
* *
* @param address the address * @param address the address
* @return this * @return this
* @throws IllegalArgumentException if {@code address.isRoot()} * @throws IllegalArgumentException if {@code address.isRoot()}
*/ */
public CommandBuilder addSubCommand(ICommandAddress address) { public CommandBuilder addSubCommand(ICommandAddress address) {
cur.addChild(address); cur.addChild(address);
return this; return this;
} }
/** /**
* Search the given class for any (static) methods using command annotations * Search the given class for any (static) methods using command annotations
* The class gets a localized parameter type selector if it defines parameter types. * The class gets a localized parameter type selector if it defines parameter types.
* Any commands found are registered as sub commands to the current address. * Any commands found are registered as sub commands to the current address.
* *
* @param clazz the clazz * @param clazz the clazz
* @return this * @return this
* @throws IllegalArgumentException if an exception occurs while parsing the methods of this class * @throws IllegalArgumentException if an exception occurs while parsing the methods of this class
* @see #registerCommands(Class, Object) * @see #registerCommands(Class, Object)
*/ */
public CommandBuilder registerCommands(Class<?> clazz) { public CommandBuilder registerCommands(Class<?> clazz) {
return registerCommands(clazz, null); return registerCommands(clazz, null);
} }
/** /**
* Search the given object's class for methods using command annotations. * Search the given object's class for methods using command annotations.
* If the object is null, only static methods are checked. Otherwise, instance methods are also checked. * If the object is null, only static methods are checked. Otherwise, instance methods are also checked.
* The class gets a localized parameter type selector if it defines parameter types. * The class gets a localized parameter type selector if it defines parameter types.
* Any commands found are registered as sub commands to the current address. * Any commands found are registered as sub commands to the current address.
* *
* @param object the object * @param object the object
* @return this * @return this
* @throws IllegalArgumentException if an exception occurs while parsing the methods of this class * @throws IllegalArgumentException if an exception occurs while parsing the methods of this class
* @see #registerCommands(Class, Object) * @see #registerCommands(Class, Object)
*/ */
public CommandBuilder registerCommands(Object object) { public CommandBuilder registerCommands(Object object) {
return registerCommands(object.getClass(), object); return registerCommands(object.getClass(), object);
} }
/** /**
* Search the given class for methods using command annotations. * Search the given class for methods using command annotations.
* The class gets a localized parameter type selector if it defines parameter types. * The class gets a localized parameter type selector if it defines parameter types.
* Any commands found are registered as sub commands to the current address. * Any commands found are registered as sub commands to the current address.
* The instance is used to invoke non-static methods. * The instance is used to invoke non-static methods.
* *
* @param clazz the class * @param clazz the class
* @param instance the instance, null if only static methods * @param instance the instance, null if only static methods
* @return this * @return this
* @throws IllegalArgumentException if instance is not null and it's not an instance of the class * @throws IllegalArgumentException if instance is not null and it's not an instance of the class
* @throws IllegalArgumentException if another exception occurs while parsing the methods of this class * @throws IllegalArgumentException if another exception occurs while parsing the methods of this class
*/ */
public CommandBuilder registerCommands(Class<?> clazz, Object instance) { public CommandBuilder registerCommands(Class<?> clazz, Object instance) {
try { try {
ReflectiveRegistration.parseCommandGroup(cur, selector, clazz, instance); ReflectiveRegistration.parseCommandGroup(cur, selector, clazz, instance);
return this; return this;
} catch (Exception ex) { } catch (Exception ex) {
throw new IllegalArgumentException(ex); throw new IllegalArgumentException(ex);
} }
} }
/** /**
* register the {@link HelpCommand} as a sub command at the current address * register the {@link HelpCommand} as a sub command at the current address
* *
* @return this * @return this
*/ */
public CommandBuilder registerHelpCommand() { public CommandBuilder registerHelpCommand() {
HelpCommand.registerAsChild(cur); HelpCommand.registerAsChild(cur);
return this; return this;
} }
/** /**
* register the {@link SyntaxCommand} as a sub command a the current address * register the {@link SyntaxCommand} as a sub command a the current address
* *
* @return this * @return this
*/ */
public CommandBuilder registerSyntaxCommand() { public CommandBuilder registerSyntaxCommand() {
SyntaxCommand.registerAsChild(cur); SyntaxCommand.registerAsChild(cur);
return this; return this;
} }
/** /**
* Generate the predefined commands. * Generate the predefined commands.
* These are presets. * These are presets.
* Examples include {@code help} and {@code syntax}. * Examples include {@code help} and {@code syntax}.
* <p> * <p>
* Predefined commands can be registered through {@link PredefinedCommand#registerPredefinedCommandGenerator(String, Consumer)} * Predefined commands can be registered through {@link PredefinedCommand#registerPredefinedCommandGenerator(String, Consumer)}
* *
* @param commands the commands * @param commands the commands
* @return this * @return this
*/ */
public CommandBuilder generatePredefinedCommands(String... commands) { public CommandBuilder generatePredefinedCommands(String... commands) {
ReflectiveRegistration.generateCommands(cur, commands); ReflectiveRegistration.generateCommands(cur, commands);
return this; return this;
} }
/** /**
* Unregister any childs present at the given keys. * Unregister any childs present at the given keys.
* <p> * <p>
* This method can be used to remove unwanted keys, that might have been added * This method can be used to remove unwanted keys, that might have been added
* outside of your control. For example, because you didn't want all commands * outside of your control. For example, because you didn't want all commands
* registered by {@link #registerCommands(Class, Object)}, or because you didn't * registered by {@link #registerCommands(Class, Object)}, or because you didn't
* want the help command registered by {@link #group(String, String...)} * want the help command registered by {@link #group(String, String...)}
* *
* @param removeAliases true if any aliases of the children present at the keys should be removed * @param removeAliases true if any aliases of the children present at the keys should be removed
* @param keys a varargs array containing the keys * @param keys a varargs array containing the keys
* @return this * @return this
* @throws IllegalArgumentException if keys array is empty * @throws IllegalArgumentException if keys array is empty
*/ */
public CommandBuilder unregisterCommands(boolean removeAliases, String... keys) { public CommandBuilder unregisterCommands(boolean removeAliases, String... keys) {
cur.removeChildren(removeAliases, keys); cur.removeChildren(removeAliases, keys);
return this; return this;
} }
/** /**
* Jump to the sub-address with the given name as main key. * Jump to the sub-address with the given name as main key.
* If an address with the exact name as main key exists, * If an address with the exact name as main key exists,
* that address becomes the current address. * that address becomes the current address.
* <p> * <p>
* Otherwise, a new addresses is registered with the name and aliases. * Otherwise, a new addresses is registered with the name and aliases.
* New addresses registered by this command have a HelpCommand added by default. * New addresses registered by this command have a HelpCommand added by default.
* <p> * <p>
* After this call, any registered commands are registered as a sub command * After this call, any registered commands are registered as a sub command
* to the new address. To restore the previous state, a call to {@link #parent()} * to the new address. To restore the previous state, a call to {@link #parent()}
* should be made. * should be made.
* <p> * <p>
* If the address is the target of a command, it will provide information about its sub commands * If the address is the target of a command, it will provide information about its sub commands
* using the HelpCommand. * using the HelpCommand.
* *
* @param name the main key * @param name the main key
* @param aliases the aliases * @param aliases the aliases
* @return this * @return this
*/ */
public CommandBuilder group(String name, String... aliases) { public CommandBuilder group(String name, String... aliases) {
ChildCommandAddress address = cur.getChild(name); ChildCommandAddress address = cur.getChild(name);
if (address == null || !name.equals(address.getMainKey())) { if (address == null || !name.equals(address.getMainKey())) {
address = new ChildCommandAddress(); address = new ChildCommandAddress();
address.setupAsPlaceholder(name, aliases); address.setupAsPlaceholder(name, aliases);
cur.addChild(address); cur.addChild(address);
} }
cur = address; cur = address;
return this; return this;
} }
/** /**
* Similar to {@link #group(String, String[])} but this will force overwrite any present group, * Similar to {@link #group(String, String[])} but this will force overwrite any present group,
* using the address passed. The address MUST be an instance of {@link ChildCommandAddress}. * using the address passed. The address MUST be an instance of {@link ChildCommandAddress}.
* *
* <p>The address must not have a parent or any keys</p> * <p>The address must not have a parent or any keys</p>
* *
* @param address the address object to use * @param address the address object to use
* @param name the main key * @param name the main key
* @param aliases any aliases * @param aliases any aliases
* @return this * @return this
* @throws IllegalArgumentException if any of the requirements set out above aren't met * @throws IllegalArgumentException if any of the requirements set out above aren't met
*/ */
public CommandBuilder group(ICommandAddress address, String name, String... aliases) { public CommandBuilder group(ICommandAddress address, String name, String... aliases) {
if (address.hasParent() || address.getMainKey() != null || !(address instanceof ChildCommandAddress)) { if (address.hasParent() || address.getMainKey() != null || !(address instanceof ChildCommandAddress)) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
ChildCommandAddress asChild = (ChildCommandAddress) address; ChildCommandAddress asChild = (ChildCommandAddress) address;
asChild.setupAsPlaceholder(name, aliases); asChild.setupAsPlaceholder(name, aliases);
cur.addChild(address); cur.addChild(address);
cur = asChild; cur = asChild;
return this; return this;
} }
/** /**
* Sets the description of a group created by {@link #group(String, String...)} * Sets the description of a group created by {@link #group(String, String...)}
* Can be called subsequently to making a call to {@link #group(String, String...)} * Can be called subsequently to making a call to {@link #group(String, String...)}
* *
* @param shortDescription a short description * @param shortDescription a short description
* @param description the lines of a full description. * @param description the lines of a full description.
* @return this * @return this
* @throws IllegalStateException if the current group has no command * @throws IllegalStateException if the current group has no command
*/ */
public CommandBuilder setGroupDescription(String shortDescription, String... description) { public CommandBuilder setGroupDescription(String shortDescription, String... description) {
Command command = cur.getCommand(); Command command = cur.getCommand();
if (command == null) throw new IllegalStateException(); if (command == null) throw new IllegalStateException();
cur.setCommand(command cur.setCommand(command
.setShortDescription(shortDescription) .setShortDescription(shortDescription)
.setDescription(description)); .setDescription(description));
return this; return this;
} }
/** /**
* Add a context filter to the command of the current group * Add a context filter to the command of the current group
* @return this * @return this
* @throws IllegalStateException if the current group has no command * @throws IllegalStateException if the current group has no command
*/ */
public CommandBuilder addContextFilter(IContextFilter contextFilter) { public CommandBuilder addContextFilter(IContextFilter contextFilter) {
Command command = cur.getCommand(); Command command = cur.getCommand();
if (command == null) throw new IllegalStateException(); if (command == null) throw new IllegalStateException();
cur.setCommand(command cur.setCommand(command
.addContextFilter(contextFilter)); .addContextFilter(contextFilter));
return this; return this;
} }
/** /**
* Add a required permission to the command of the current group * Add a required permission to the command of the current group
* @return this * @return this
* @throws IllegalStateException if the current group has no command * @throws IllegalStateException if the current group has no command
*/ */
public CommandBuilder addPermission(String permission) { public CommandBuilder addPermission(String permission) {
return addContextFilter(IContextFilter.permission(permission)); return addContextFilter(IContextFilter.permission(permission));
} }
/** /**
* Add a required permission to the command of the current group, which can be inherited * Add a required permission to the command of the current group, which can be inherited
* @return this * @return this
* @throws IllegalStateException if the current group has no command * @throws IllegalStateException if the current group has no command
*/ */
public CommandBuilder addInheritablePermission(String permission) { public CommandBuilder addInheritablePermission(String permission) {
return addContextFilter(IContextFilter.inheritablePermission(permission)); return addContextFilter(IContextFilter.inheritablePermission(permission));
} }
/** /**
* Jump up a level in the address * Jump up a level in the address
* *
* @return this * @return this
* @throws IllegalStateException if the address is empty * @throws IllegalStateException if the address is empty
* // has a depth of 0 // is at level 0 * // has a depth of 0 // is at level 0
*/ */
public CommandBuilder parent() { public CommandBuilder parent() {
if (cur.hasParent()) { if (cur.hasParent()) {
cur = cur.getParent(); cur = cur.getParent();
return this; return this;
} }
throw new IllegalStateException("No parent exists at this address"); throw new IllegalStateException("No parent exists at this address");
} }
/** /**
* Jump to the root (empty) address, * Jump to the root (empty) address,
* such that a subsequent call to {@link #parent()} * such that a subsequent call to {@link #parent()}
* will throw a {@link IllegalStateException} * will throw a {@link IllegalStateException}
* *
* @return this * @return this
*/ */
public CommandBuilder root() { public CommandBuilder root() {
cur = root; cur = root;
return this; return this;
} }
/** /**
* Get the current address, as a space-separated string * Get the current address, as a space-separated string
* *
* @return the current address * @return the current address
*/ */
public String getAddress() { public String getAddress() {
return cur.getAddress(); return cur.getAddress();
} }
/** /**
* Get the depth of the current address. * Get the depth of the current address.
* This is equivalent to {@code getAddress().split(" ").length}. * This is equivalent to {@code getAddress().split(" ").length}.
* If the address is empty, the depth is 0. * If the address is empty, the depth is 0.
* *
* @return the depth * @return the depth
*/ */
public int getDepth() { public int getDepth() {
return cur.getDepth(); return cur.getDepth();
} }
/** /**
* Set the command at the current group. The command is set * Set the command at the current group. The command is set
* a level higher than it would be if this were a call to {@link #addSubCommand(String, Command, String...)} * a level higher than it would be if this were a call to {@link #addSubCommand(String, Command, String...)}
* <p> * <p>
* If a call to {@link #setGroupDescription(String, String...)} was made at the same address before, * If a call to {@link #setGroupDescription(String, String...)} was made at the same address before,
* the description is copied to the given executor. * the description is copied to the given executor.
* *
* @param command the executor * @param command the executor
* @return this * @return this
* @throws IllegalArgumentException if the command at the address is present and declared by the user, * @throws IllegalArgumentException if the command at the address is present and declared by the user,
* in other words, it's not a {@link PredefinedCommand} * in other words, it's not a {@link PredefinedCommand}
*/ */
public CommandBuilder setCommand(Command command) { public CommandBuilder setCommand(Command command) {
Command current = cur.getCommand(); Command current = cur.getCommand();
if (current instanceof HelpCommand && current != HelpCommand.INSTANCE) { if (current instanceof HelpCommand && current != HelpCommand.INSTANCE) {
command.setShortDescription(current.getShortDescription()); command.setShortDescription(current.getShortDescription());
command.setDescription(current.getDescription()); command.setDescription(current.getDescription());
} }
cur.setCommand(command); cur.setCommand(command);
return this; return this;
} }
/** /**
* Configure the chat handler at this address. The chat handler * Configure the chat handler at this address. The chat handler
* is used for all children down the tree if they don't explicitly have * is used for all children down the tree if they don't explicitly have
* their own chat handler configured. If this isn't configured, * their own chat handler configured. If this isn't configured,
* {@code ChatHandlers.defaultChat()} is used. * {@code ChatHandlers.defaultChat()} is used.
* *
* @param chatHandler the chat handler * @param chatHandler the chat handler
* @return this * @return this
*/ */
public CommandBuilder setChatHandler(IChatHandler chatHandler) { public CommandBuilder setChatHandler(IChatHandler chatHandler) {
cur.setChatHandler(chatHandler); cur.setChatHandler(chatHandler);
return this; return this;
} }
/** /**
* Add the parameter type to this builder's selector. * Add the parameter type to this builder's selector.
* *
* @param type the type * @param type the type
* @param <T> the return type of the parameter type * @param <T> the return type of the parameter type
* @return this * @return this
*/ */
public <T> CommandBuilder addParameterType(ParameterType<T, Void> type) { public <T> CommandBuilder addParameterType(ParameterType<T, Void> type) {
selector.addType(false, type); selector.addType(false, type);
return this; return this;
} }
/** /**
* Add the parameter type to this builder's selector. * Add the parameter type to this builder's selector.
* *
* @param infolessAlias whether to also register the type with an infoless alias. * @param infolessAlias whether to also register the type with an infoless alias.
* this increases the priority assigned to the type if no info object is present. * this increases the priority assigned to the type if no info object is present.
* @param type the type * @param type the type
* @param <T> the return type of the parameter type * @param <T> the return type of the parameter type
* @param <C> the parameter config type (info object) * @param <C> the parameter config type (info object)
* @return this * @return this
*/ */
public <T, C> CommandBuilder addParameterType(boolean infolessAlias, ParameterType<T, C> type) { public <T, C> CommandBuilder addParameterType(boolean infolessAlias, ParameterType<T, C> type) {
selector.addType(infolessAlias, type); selector.addType(infolessAlias, type);
return this; return this;
} }
/** /**
* Get the dispatcher for the root address. * Get the dispatcher for the root address.
* The dispatcher should be used to finally register all commands, * The dispatcher should be used to finally register all commands,
* after they are all declared. * after they are all declared.
* *
* @return the dispatcher * @return the dispatcher
*/ */
public ICommandDispatcher getDispatcher() { public ICommandDispatcher getDispatcher() {
return root; return root;
} }
/** /**
* Print debugging information about the current addresses and commands in this builder * Print debugging information about the current addresses and commands in this builder
* A StackTraceElement indicating where this was called from is also included * A StackTraceElement indicating where this was called from is also included
* *
* @return this * @return this
*/ */
public CommandBuilder printDebugInformation() { public CommandBuilder printDebugInformation() {
String address = cur == root ? "<root>" : cur.getAddress(); String address = cur == root ? "<root>" : cur.getAddress();
StackTraceElement caller = getCallsite(); StackTraceElement caller = getCallsite();
StringBuilder message = new StringBuilder("### CommandBuilder dump ###"); StringBuilder message = new StringBuilder("### CommandBuilder dump ###");
message.append("\nCalled from ").append(caller); message.append("\nCalled from ").append(caller);
message.append("\nPosition: ").append(address); message.append("\nPosition: ").append(address);
cur.appendDebugInformation(message, "", new HashSet<>()); cur.appendDebugInformation(message, "", new HashSet<>());
System.out.println(message); System.out.println(message);
return this; return this;
} }
private static StackTraceElement getCallsite() { private static StackTraceElement getCallsite() {
// [0] Thread.currentThread() // [0] Thread.currentThread()
// [1] CommandBuilder.getCallsite() // [1] CommandBuilder.getCallsite()
// [2] Calling method // [2] Calling method
// [3] Method calling the calling method // [3] Method calling the calling method
StackTraceElement[] trace = Thread.currentThread().getStackTrace(); StackTraceElement[] trace = Thread.currentThread().getStackTrace();
return trace.length > 3 ? trace[3] : null; return trace.length > 3 ? trace[3] : null;
} }
} }

View File

@@ -1,28 +1,28 @@
package io.dico.dicore.command; package io.dico.dicore.command;
public class CommandException extends Exception { public class CommandException extends Exception {
public CommandException() { public CommandException() {
} }
public CommandException(String message) { public CommandException(String message) {
super(message); super(message);
} }
public CommandException(String message, Throwable cause) { public CommandException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
public CommandException(Throwable cause) { public CommandException(Throwable cause) {
super(cause); super(cause);
} }
public static CommandException missingArgument(String parameterName) { public static CommandException missingArgument(String parameterName) {
return new CommandException("Missing argument for " + parameterName); return new CommandException("Missing argument for " + parameterName);
} }
public static CommandException invalidArgument(String parameterName, String syntaxHelp) { public static CommandException invalidArgument(String parameterName, String syntaxHelp) {
return new CommandException("Invalid input for " + parameterName + ", should be " + syntaxHelp); return new CommandException("Invalid input for " + parameterName + ", should be " + syntaxHelp);
} }
} }

View File

@@ -1,19 +1,19 @@
package io.dico.dicore.command; package io.dico.dicore.command;
public enum EMessageType { public enum EMessageType {
GOOD_NEWS, GOOD_NEWS,
BAD_NEWS, BAD_NEWS,
NEUTRAL, NEUTRAL,
INFORMATIVE, INFORMATIVE,
WARNING, WARNING,
INSTRUCTION, INSTRUCTION,
EXCEPTION, EXCEPTION,
RESULT, RESULT,
CUSTOM, CUSTOM,
DESCRIPTION, DESCRIPTION,
SYNTAX, SYNTAX,
HIGHLIGHT, HIGHLIGHT,
SUBCOMMAND, SUBCOMMAND,
NUMBER, NUMBER,
} }

View File

@@ -1,12 +1,12 @@
package io.dico.dicore.command; package io.dico.dicore.command;
/** /**
* Override policies for registering to the command map * Override policies for registering to the command map
*/ */
public enum EOverridePolicy { public enum EOverridePolicy {
OVERRIDE_ALL, OVERRIDE_ALL,
MAIN_KEY_ONLY, MAIN_KEY_ONLY,
MAIN_AND_FALLBACK, MAIN_AND_FALLBACK,
FALLBACK_ONLY, FALLBACK_ONLY,
OVERRIDE_NONE OVERRIDE_NONE
} }

View File

@@ -1,385 +1,385 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import io.dico.dicore.Formatting; import io.dico.dicore.Formatting;
import io.dico.dicore.command.parameter.ArgumentBuffer; import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.parameter.ContextParser; import io.dico.dicore.command.parameter.ContextParser;
import io.dico.dicore.command.parameter.Parameter; import io.dico.dicore.command.parameter.Parameter;
import io.dico.dicore.command.parameter.ParameterList; import io.dico.dicore.command.parameter.ParameterList;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.*; import java.util.*;
/** /**
* The context of execution. * The context of execution.
* <p> * <p>
* This class is responsible for the control flow of parameter parsing, as well as caching and providing the parsed parameter values. * This class is responsible for the control flow of parameter parsing, as well as caching and providing the parsed parameter values.
* It is also responsible for keeping track of the parameter to complete in the case of a tab completion. * It is also responsible for keeping track of the parameter to complete in the case of a tab completion.
*/ */
public class ExecutionContext { public class ExecutionContext {
// Sender of the command // Sender of the command
private final CommandSender sender; private final CommandSender sender;
// Address while parsing parameters with ContextParser // Address while parsing parameters with ContextParser
private ICommandAddress address; private ICommandAddress address;
// Command to execute // Command to execute
private Command command; private Command command;
// if this flag is set, this execution is only for completion purposes. // if this flag is set, this execution is only for completion purposes.
private boolean tabComplete; private boolean tabComplete;
private final ArgumentBuffer buffer; private final ArgumentBuffer buffer;
// private ArgumentBuffer processedBuffer; // private ArgumentBuffer processedBuffer;
// caches the buffer's cursor before parsing. This is needed to provide the original input of the player. // caches the buffer's cursor before parsing. This is needed to provide the original input of the player.
private int cursorStart; private int cursorStart;
// when the context starts parsing parameters, this flag is set, and any subsequent calls to #parseParameters() throw an IllegalStateException. // when the context starts parsing parameters, this flag is set, and any subsequent calls to #parseParameters() throw an IllegalStateException.
//private boolean attemptedToParse; //private boolean attemptedToParse;
// The parsed parameter values, mapped by parameter name. // The parsed parameter values, mapped by parameter name.
// This also includes default values. All parameters from the parameter list are present if parsing was successful. // This also includes default values. All parameters from the parameter list are present if parsing was successful.
private Map<String, Object> parameterValueMap = new HashMap<>(); private Map<String, Object> parameterValueMap = new HashMap<>();
// this set contains the names of the parameters that were present in the command, and not given a default value. // this set contains the names of the parameters that were present in the command, and not given a default value.
private Set<String> parsedParameters = new HashSet<>(); private Set<String> parsedParameters = new HashSet<>();
// these fields store information required to provide completions. // these fields store information required to provide completions.
// the parameter to complete is the parameter that threw an exception when it was parsing. // the parameter to complete is the parameter that threw an exception when it was parsing.
// the exception's message was discarded because it is a completion. // the exception's message was discarded because it is a completion.
private Parameter<?, ?> parameterToComplete; private Parameter<?, ?> parameterToComplete;
// this is the cursor that the ArgumentBuffer is reset to when suggested completions are requested. // this is the cursor that the ArgumentBuffer is reset to when suggested completions are requested.
private int parameterToCompleteCursor = -1; private int parameterToCompleteCursor = -1;
// if this flag is set, any messages sent through the sendMessage methods are discarded. // if this flag is set, any messages sent through the sendMessage methods are discarded.
private boolean muted; private boolean muted;
public ExecutionContext(CommandSender sender, ArgumentBuffer buffer, boolean tabComplete) { public ExecutionContext(CommandSender sender, ArgumentBuffer buffer, boolean tabComplete) {
this.sender = Objects.requireNonNull(sender); this.sender = Objects.requireNonNull(sender);
this.buffer = Objects.requireNonNull(buffer); this.buffer = Objects.requireNonNull(buffer);
this.muted = tabComplete; this.muted = tabComplete;
this.tabComplete = tabComplete; this.tabComplete = tabComplete;
// If its tab completing, keep the empty element that might be at the end of the buffer // If its tab completing, keep the empty element that might be at the end of the buffer
// due to a space at the end of the command. // due to a space at the end of the command.
// This allows the parser to correctly identify the parameter to be completed in this case. // This allows the parser to correctly identify the parameter to be completed in this case.
if (!tabComplete) { if (!tabComplete) {
buffer.dropTrailingEmptyElements(); buffer.dropTrailingEmptyElements();
} }
} }
/** /**
* Construct an execution context that is ready to parse the parameter values. * Construct an execution context that is ready to parse the parameter values.
* *
* @param sender the sender * @param sender the sender
* @param address the address * @param address the address
* @param command the command * @param command the command
* @param buffer the arguments * @param buffer the arguments
* @param tabComplete true if this execution is a tab-completion * @param tabComplete true if this execution is a tab-completion
*/ */
public ExecutionContext(CommandSender sender, ICommandAddress address, Command command, ArgumentBuffer buffer, boolean tabComplete) { public ExecutionContext(CommandSender sender, ICommandAddress address, Command command, ArgumentBuffer buffer, boolean tabComplete) {
this(sender, buffer, tabComplete); this(sender, buffer, tabComplete);
setAddress(address); setAddress(address);
setCommand(command); setCommand(command);
} }
/** /**
* Sender of the command * Sender of the command
* *
* @return the sender of the command * @return the sender of the command
*/ */
public CommandSender getSender() { public CommandSender getSender() {
return sender; return sender;
} }
/** /**
* @return the buffer of arguments * @return the buffer of arguments
*/ */
public ArgumentBuffer getBuffer() { public ArgumentBuffer getBuffer() {
return buffer; return buffer;
} }
/** /**
* Command's address * Command's address
* *
* @return the command's address * @return the command's address
*/ */
public ICommandAddress getAddress() { public ICommandAddress getAddress() {
return address; return address;
} }
/** /**
* Set the address * Set the address
* *
* @param address the new address * @param address the new address
*/ */
public void setAddress(ICommandAddress address) { public void setAddress(ICommandAddress address) {
this.address = address; this.address = address;
} }
/** /**
* The command * The command
* *
* @return the command * @return the command
*/ */
public Command getCommand() { public Command getCommand() {
return command; return command;
} }
/** /**
* Set the command * Set the command
* *
* @param command the new command * @param command the new command
*/ */
public void setCommand(Command command) { public void setCommand(Command command) {
this.command = command; this.command = command;
} }
/** /**
* @return true if this context is for a tab completion. * @return true if this context is for a tab completion.
*/ */
public boolean isTabComplete() { public boolean isTabComplete() {
return tabComplete; return tabComplete;
} }
/** /**
* @return true if this context is muted. * @return true if this context is muted.
*/ */
public boolean isMuted() { public boolean isMuted() {
return muted; return muted;
} }
/** /**
* Parse parameters from the given parameter list, * Parse parameters from the given parameter list,
* adding their values to the cache of this context. * adding their values to the cache of this context.
* *
* @param parameterList the parameterList * @param parameterList the parameterList
* @throws CommandException if the arguments are not valid * @throws CommandException if the arguments are not valid
*/ */
public void parse(ParameterList parameterList) throws CommandException { public void parse(ParameterList parameterList) throws CommandException {
cursorStart = buffer.getCursor(); cursorStart = buffer.getCursor();
ContextParser parser = new ContextParser(this, parameterList, parameterValueMap, parsedParameters); ContextParser parser = new ContextParser(this, parameterList, parameterValueMap, parsedParameters);
try { try {
parser.parse(); parser.parse();
} finally { } finally {
if (tabComplete) { if (tabComplete) {
parameterToComplete = parser.getCompletionTarget(); parameterToComplete = parser.getCompletionTarget();
parameterToCompleteCursor = parser.getCompletionCursor(); parameterToCompleteCursor = parser.getCompletionCursor();
} }
} }
} }
/** /**
* The command's parameter definition. * The command's parameter definition.
* *
* @return the parameter list * @return the parameter list
*/ */
@Deprecated @Deprecated
public ParameterList getParameterList() { public ParameterList getParameterList() {
return null;//command.getParameterList(); return null;//command.getParameterList();
} }
/** /**
* Get the buffer as it was before preprocessing the arguments. * Get the buffer as it was before preprocessing the arguments.
* *
* @return the original buffer * @return the original buffer
*/ */
@Deprecated @Deprecated
public ArgumentBuffer getOriginalBuffer() { public ArgumentBuffer getOriginalBuffer() {
return buffer; return buffer;
} }
/** /**
* The arguments * The arguments
* *
* @return the argument buffer * @return the argument buffer
*/ */
@Deprecated @Deprecated
public ArgumentBuffer getProcessedBuffer() { public ArgumentBuffer getProcessedBuffer() {
return buffer; return buffer;
} }
/** /**
* The cursor start, in other words, the buffer's cursor before parameters were parsed. * The cursor start, in other words, the buffer's cursor before parameters were parsed.
* *
* @return the cursor start * @return the cursor start
*/ */
public int getCursorStart() { public int getCursorStart() {
return cursorStart; return cursorStart;
} }
/** /**
* The original arguments. * The original arguments.
* *
* @return original arguments. * @return original arguments.
*/ */
public String[] getOriginal() { public String[] getOriginal() {
return buffer.getArrayFromIndex(cursorStart); return buffer.getArrayFromIndex(cursorStart);
} }
/** /**
* The path used to access this address. * The path used to access this address.
* *
* @return the path used to access this address. * @return the path used to access this address.
*/ */
public String[] getRoute() { public String[] getRoute() {
return Arrays.copyOf(buffer.toArray(), address.getDepth()); return Arrays.copyOf(buffer.toArray(), address.getDepth());
} }
public Formatting getFormat(EMessageType type) { public Formatting getFormat(EMessageType type) {
return address.getChatHandler().getChatFormatForType(type); return address.getChatHandler().getChatFormatForType(type);
} }
/** /**
* The full command as cached by the buffer. Might be incomplete depending on how it was dispatched. * The full command as cached by the buffer. Might be incomplete depending on how it was dispatched.
* *
* @return the full command * @return the full command
*/ */
public String getRawInput() { public String getRawInput() {
return buffer.getRawInput(); return buffer.getRawInput();
} }
/** /**
* Get the value of the parameter with the given name * Get the value of the parameter with the given name
* *
* @param name the parameter's name * @param name the parameter's name
* @param <T> expected type * @param <T> expected type
* @return the parsed value or the default value * @return the parsed value or the default value
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> T get(String name) { public <T> T get(String name) {
if (!parameterValueMap.containsKey(name)) { if (!parameterValueMap.containsKey(name)) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
try { try {
return (T) parameterValueMap.get(name); return (T) parameterValueMap.get(name);
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
throw new IllegalArgumentException("Invalid type parameter requested for parameter " + name, ex); throw new IllegalArgumentException("Invalid type parameter requested for parameter " + name, ex);
} }
} }
/** /**
* Get the value of the flag with the given name * Get the value of the flag with the given name
* *
* @param flag the flag's name, without preceding "-" * @param flag the flag's name, without preceding "-"
* @param <T> expected type * @param <T> expected type
* @return the parsed value or the default value * @return the parsed value or the default value
*/ */
public <T> T getFlag(String flag) { public <T> T getFlag(String flag) {
return get("-" + flag); return get("-" + flag);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Deprecated @Deprecated
public <T> T get(int index) { public <T> T get(int index) {
return null;//get(getParameterList().getIndexedParameterName(index)); return null;//get(getParameterList().getIndexedParameterName(index));
} }
/** /**
* Checks if the parameter by the name was provided in the command's arguments. * Checks if the parameter by the name was provided in the command's arguments.
* *
* @param name the parameter name * @param name the parameter name
* @return true if it was provided * @return true if it was provided
*/ */
public boolean isProvided(String name) { public boolean isProvided(String name) {
return parsedParameters.contains(name); return parsedParameters.contains(name);
} }
/** /**
* Checks if the parameter by the index was provided in the command's arguments. * Checks if the parameter by the index was provided in the command's arguments.
* *
* @param index the parameter index * @param index the parameter index
* @return true if it was provided * @return true if it was provided
*/ */
@Deprecated @Deprecated
public boolean isProvided(int index) { public boolean isProvided(int index) {
return false;//isProvided(getParameterList().getIndexedParameterName(index)); return false;//isProvided(getParameterList().getIndexedParameterName(index));
} }
/** /**
* The parameter to complete. * The parameter to complete.
* This parameter is requested suggestions * This parameter is requested suggestions
* *
* @return the parameter to complete. * @return the parameter to complete.
*/ */
public Parameter<?, ?> getParameterToComplete() { public Parameter<?, ?> getParameterToComplete() {
return parameterToComplete; return parameterToComplete;
} }
/** /**
* Get suggested completions. * Get suggested completions.
* *
* @param location The location as passed to {link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}, or null if requested in another way. * @param location The location as passed to {link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}, or null if requested in another way.
* @return completions. * @return completions.
*/ */
public List<String> getSuggestedCompletions(Location location) { public List<String> getSuggestedCompletions(Location location) {
if (parameterToComplete != null) { if (parameterToComplete != null) {
return parameterToComplete.complete(this, location, buffer.getUnaffectingCopy().setCursor(parameterToCompleteCursor)); return parameterToComplete.complete(this, location, buffer.getUnaffectingCopy().setCursor(parameterToCompleteCursor));
} }
List<String> result = new ArrayList<>(); List<String> result = new ArrayList<>();
for (String name : parameterValueMap.keySet()) { for (String name : parameterValueMap.keySet()) {
if (name.startsWith("-") && !parsedParameters.contains(name)) { if (name.startsWith("-") && !parsedParameters.contains(name)) {
result.add(name); result.add(name);
} }
} }
return result; return result;
} }
/* /*
Chat handling Chat handling
*/ */
public void sendMessage(String message) { public void sendMessage(String message) {
sendMessage(true, message); sendMessage(true, message);
} }
public void sendMessage(EMessageType messageType, String message) { public void sendMessage(EMessageType messageType, String message) {
sendMessage(messageType, true, message); sendMessage(messageType, true, message);
} }
public void sendMessage(boolean translateColours, String message) { public void sendMessage(boolean translateColours, String message) {
sendMessage(EMessageType.NEUTRAL, translateColours, message); sendMessage(EMessageType.NEUTRAL, translateColours, message);
} }
public void sendMessage(EMessageType messageType, boolean translateColours, String message) { public void sendMessage(EMessageType messageType, boolean translateColours, String message) {
if (!muted) { if (!muted) {
if (translateColours) { if (translateColours) {
message = Formatting.translateChars('&', message); message = Formatting.translateChars('&', message);
} }
address.getChatHandler().sendMessage(this, messageType, message); address.getChatHandler().sendMessage(this, messageType, message);
} }
} }
public void sendMessage(String messageFormat, Object... args) { public void sendMessage(String messageFormat, Object... args) {
sendMessage(true, messageFormat, args); sendMessage(true, messageFormat, args);
} }
public void sendMessage(EMessageType messageType, String messageFormat, Object... args) { public void sendMessage(EMessageType messageType, String messageFormat, Object... args) {
sendMessage(messageType, true, messageFormat, args); sendMessage(messageType, true, messageFormat, args);
} }
public void sendMessage(boolean translateColours, String messageFormat, Object... args) { public void sendMessage(boolean translateColours, String messageFormat, Object... args) {
sendMessage(EMessageType.NEUTRAL, translateColours, messageFormat, args); sendMessage(EMessageType.NEUTRAL, translateColours, messageFormat, args);
} }
public void sendMessage(EMessageType messageType, boolean translateColours, String messageFormat, Object... args) { public void sendMessage(EMessageType messageType, boolean translateColours, String messageFormat, Object... args) {
sendMessage(messageType, translateColours, String.format(messageFormat, args)); sendMessage(messageType, translateColours, String.format(messageFormat, args));
} }
public void sendHelpMessage(int page) { public void sendHelpMessage(int page) {
if (!muted) { if (!muted) {
address.getChatHandler().sendHelpMessage(sender, this, address, page); address.getChatHandler().sendHelpMessage(sender, this, address, page);
} }
} }
public void sendSyntaxMessage() { public void sendSyntaxMessage() {
if (!muted) { if (!muted) {
address.getChatHandler().sendSyntaxMessage(sender, this, address); address.getChatHandler().sendSyntaxMessage(sender, this, address);
} }
} }
} }

View File

@@ -1,64 +1,64 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import io.dico.dicore.command.parameter.IArgumentPreProcessor; import io.dico.dicore.command.parameter.IArgumentPreProcessor;
import io.dico.dicore.command.parameter.Parameter; import io.dico.dicore.command.parameter.Parameter;
import io.dico.dicore.command.parameter.type.ParameterType; import io.dico.dicore.command.parameter.type.ParameterType;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public abstract class ExtendedCommand<T extends ExtendedCommand<T>> extends Command { public abstract class ExtendedCommand<T extends ExtendedCommand<T>> extends Command {
protected boolean modifiable; protected boolean modifiable;
public ExtendedCommand() { public ExtendedCommand() {
this(true); this(true);
} }
public ExtendedCommand(boolean modifiable) { public ExtendedCommand(boolean modifiable) {
this.modifiable = modifiable; this.modifiable = modifiable;
} }
protected T newModifiableInstance() { protected T newModifiableInstance() {
return (T) this; return (T) this;
} }
@Override @Override
public T addParameter(Parameter<?, ?> parameter) { public T addParameter(Parameter<?, ?> parameter) {
return modifiable ? (T) super.addParameter(parameter) : newModifiableInstance().addParameter(parameter); return modifiable ? (T) super.addParameter(parameter) : newModifiableInstance().addParameter(parameter);
} }
@Override @Override
public T addContextFilter(IContextFilter contextFilter) { public T addContextFilter(IContextFilter contextFilter) {
return modifiable ? (T) super.addContextFilter(contextFilter) : newModifiableInstance().addContextFilter(contextFilter); return modifiable ? (T) super.addContextFilter(contextFilter) : newModifiableInstance().addContextFilter(contextFilter);
} }
@Override @Override
public T removeContextFilter(IContextFilter contextFilter) { public T removeContextFilter(IContextFilter contextFilter) {
return modifiable ? (T) super.removeContextFilter(contextFilter) : newModifiableInstance().removeContextFilter(contextFilter); return modifiable ? (T) super.removeContextFilter(contextFilter) : newModifiableInstance().removeContextFilter(contextFilter);
} }
@Override @Override
public T requiredParameters(int requiredParameters) { public T requiredParameters(int requiredParameters) {
return modifiable ? (T) super.requiredParameters(requiredParameters) : newModifiableInstance().requiredParameters(requiredParameters); return modifiable ? (T) super.requiredParameters(requiredParameters) : newModifiableInstance().requiredParameters(requiredParameters);
} }
@Override @Override
public T repeatFinalParameter() { public T repeatFinalParameter() {
return modifiable ? (T) super.repeatFinalParameter() : newModifiableInstance().repeatFinalParameter(); return modifiable ? (T) super.repeatFinalParameter() : newModifiableInstance().repeatFinalParameter();
} }
@Override @Override
public T setDescription(String... description) { public T setDescription(String... description) {
return modifiable ? (T) super.setDescription(description) : newModifiableInstance().setDescription(description); return modifiable ? (T) super.setDescription(description) : newModifiableInstance().setDescription(description);
} }
@Override @Override
public T setShortDescription(String shortDescription) { public T setShortDescription(String shortDescription) {
return modifiable ? (T) super.setShortDescription(shortDescription) : newModifiableInstance().setShortDescription(shortDescription); return modifiable ? (T) super.setShortDescription(shortDescription) : newModifiableInstance().setShortDescription(shortDescription);
} }
/* /*
@Override @Override
public T preprocessArguments(IArgumentPreProcessor processor) { public T preprocessArguments(IArgumentPreProcessor processor) {
return modifiable ? (T) super.preprocessArguments(processor) : newModifiableInstance().preprocessArguments(processor); return modifiable ? (T) super.preprocessArguments(processor) : newModifiableInstance().preprocessArguments(processor);
}*/ }*/
} }

View File

@@ -1,205 +1,205 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import io.dico.dicore.command.chat.IChatHandler; import io.dico.dicore.command.chat.IChatHandler;
import io.dico.dicore.command.parameter.ArgumentBuffer; import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.parameter.ParameterList; import io.dico.dicore.command.parameter.ParameterList;
import io.dico.dicore.command.predef.PredefinedCommand; import io.dico.dicore.command.predef.PredefinedCommand;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* Interface for an address of a command. * Interface for an address of a command.
* <p> * <p>
* The address holds what the name and aliases of a command are. * The address holds what the name and aliases of a command are.
* The address also (optionally) holds a reference to a {@link Command} * The address also (optionally) holds a reference to a {@link Command}
* <p> * <p>
* One instance of {@link Command} can be held by multiple addresses, * One instance of {@link Command} can be held by multiple addresses,
* because the address decides what the command's name and aliases are. * because the address decides what the command's name and aliases are.
* <p> * <p>
* The address holds children by key in a map. This map's keys include aliases for its children. * The address holds children by key in a map. This map's keys include aliases for its children.
* This creates a tree of addresses. If a command is dispatches, the tree is traversed untill a command is found * This creates a tree of addresses. If a command is dispatches, the tree is traversed untill a command is found
* and no children deeper down match the command (there are exceptions to the later as defined by * and no children deeper down match the command (there are exceptions to the later as defined by
* {@link Command#takePrecedenceOverSubcommand(String, ArgumentBuffer)} * {@link Command#takePrecedenceOverSubcommand(String, ArgumentBuffer)}
* and {@link Command#isVisibleTo(CommandSender)} * and {@link Command#isVisibleTo(CommandSender)}
*/ */
public interface ICommandAddress { public interface ICommandAddress {
/** /**
* @return true if this address has a parent. * @return true if this address has a parent.
*/ */
boolean hasParent(); boolean hasParent();
/** /**
* Get the parent of this address * Get the parent of this address
* *
* @return the parent of this address, or null if none exists. * @return the parent of this address, or null if none exists.
*/ */
ICommandAddress getParent(); ICommandAddress getParent();
/** /**
* @return true if this address has a command. * @return true if this address has a command.
*/ */
boolean hasCommand(); boolean hasCommand();
/** /**
* @return true if this address has a command that is not an instance of {@link PredefinedCommand} * @return true if this address has a command that is not an instance of {@link PredefinedCommand}
*/ */
boolean hasUserDeclaredCommand(); boolean hasUserDeclaredCommand();
/** /**
* @return Get the command of this address, or null if none exists. * @return Get the command of this address, or null if none exists.
*/ */
Command getCommand(); Command getCommand();
/** /**
* @return true if this address is an instance of {@link RootCommandAddress} * @return true if this address is an instance of {@link RootCommandAddress}
*/ */
boolean isRoot(); boolean isRoot();
/** /**
* @return the root address of the tree which this address resides in. * @return the root address of the tree which this address resides in.
*/ */
ICommandAddress getRoot(); ICommandAddress getRoot();
/** /**
* A list of the names of this address, at the current level. * A list of the names of this address, at the current level.
* The first entry is the main key, the subsequent ones are aliases. * The first entry is the main key, the subsequent ones are aliases.
* <p> * <p>
* Untill an address is assigned a parent, this list is mutable. * Untill an address is assigned a parent, this list is mutable.
* <p> * <p>
* If {@link #isRoot()}, this returns an immutable, empty list. * If {@link #isRoot()}, this returns an immutable, empty list.
* *
* @return the list of names. * @return the list of names.
*/ */
List<String> getNames(); List<String> getNames();
/** /**
* A list of the aliases of this address. That is, {@link #getNames()} * A list of the aliases of this address. That is, {@link #getNames()}
* without the first entry. * without the first entry.
* *
* @return a list of aliases * @return a list of aliases
*/ */
List<String> getAliases(); List<String> getAliases();
/** /**
* @return The first element of {@link #getNames()} * @return The first element of {@link #getNames()}
*/ */
String getMainKey(); String getMainKey();
/** /**
* Get the address of this command. * Get the address of this command.
* That is, the main keys of all commands leading up to this address, and this address itself, separated by a space. * That is, the main keys of all commands leading up to this address, and this address itself, separated by a space.
* In other words, the command without the / that is required to target the command at this address. * In other words, the command without the / that is required to target the command at this address.
* *
* @return the address of this command. * @return the address of this command.
*/ */
String getAddress(); String getAddress();
/** /**
* Get the amount of addresses that separate this address from the root of the tree, + 1. * Get the amount of addresses that separate this address from the root of the tree, + 1.
* The root of the tree has a depth of 0. Each subsequent child has its depth incremented by 1. * The root of the tree has a depth of 0. Each subsequent child has its depth incremented by 1.
* *
* @return The depth of this address * @return The depth of this address
*/ */
int getDepth(); int getDepth();
/** /**
* @return true if the depth of this address is larger than the argument. * @return true if the depth of this address is larger than the argument.
*/ */
boolean isDepthLargerThan(int depth); boolean isDepthLargerThan(int depth);
/** /**
* @return true if this address has any children. * @return true if this address has any children.
*/ */
boolean hasChildren(); boolean hasChildren();
/** /**
* @return total number of children, not considering any aliases * @return total number of children, not considering any aliases
*/ */
int getNumberOfRealChildren(); int getNumberOfRealChildren();
/** /**
* Get an unmodifiable view of all main keys of the children of this address. * Get an unmodifiable view of all main keys of the children of this address.
* *
* @return the main keys * @return the main keys
*/ */
Collection<String> getChildrenMainKeys(); Collection<String> getChildrenMainKeys();
/** /**
* Get an unmodifiable view of the children of this address. * Get an unmodifiable view of the children of this address.
* Values might be duplicated for aliases. * Values might be duplicated for aliases.
* *
* <p> * <p>
* To iterate children without duplicates, you can do something like this: * To iterate children without duplicates, you can do something like this:
* <pre>{@code * <pre>{@code
* for (String key : address.getChildrenMainKeys()) { * for (String key : address.getChildrenMainKeys()) {
* ICommandAddress child = address.getChild(key); * ICommandAddress child = address.getChild(key);
* // do stuff with child * // do stuff with child
* } * }
* }</pre> * }</pre>
* </p> * </p>
* *
* @return the children of this address. * @return the children of this address.
*/ */
Map<String, ? extends ICommandAddress> getChildren(); Map<String, ? extends ICommandAddress> getChildren();
/** /**
* Query for a child at the given key. * Query for a child at the given key.
* *
* @param key the key. The name or alias of a command. * @param key the key. The name or alias of a command.
* @return the child, or null if it's not found * @return the child, or null if it's not found
*/ */
ICommandAddress getChild(String key); ICommandAddress getChild(String key);
/** /**
* Query for a child using the given buffer, with the given context for reference. * Query for a child using the given buffer, with the given context for reference.
* Can be used to override behaviour of the address tree. * Can be used to override behaviour of the address tree.
* <p> * <p>
* The default implementation is as follows: * The default implementation is as follows:
* <pre>{@code * <pre>{@code
* return buffer.hasNext() ? getChild(buffer.next()) : null; * return buffer.hasNext() ? getChild(buffer.next()) : null;
* }</pre> * }</pre>
* *
* @param context context of a command being executed * @param context context of a command being executed
* @param buffer the buffer. The name or alias of a command. * @param buffer the buffer. The name or alias of a command.
* @return the child, or null if it's not found, altered freely by the implementation * @return the child, or null if it's not found, altered freely by the implementation
*/ */
ICommandAddress getChild(ExecutionContext context, ArgumentBuffer buffer) throws CommandException; ICommandAddress getChild(ExecutionContext context, ArgumentBuffer buffer) throws CommandException;
/** /**
* Get the command dispatcher for this tree * Get the command dispatcher for this tree
* *
* @return the command dispatcher * @return the command dispatcher
*/ */
ICommandDispatcher getDispatcherForTree(); ICommandDispatcher getDispatcherForTree();
/** /**
* @return The desired chathandler for use by commands at this address and any sub-addresses, if they define no explicit chat handler. * @return The desired chathandler for use by commands at this address and any sub-addresses, if they define no explicit chat handler.
*/ */
IChatHandler getChatHandler(); IChatHandler getChatHandler();
/** /**
* Returns if the command attached to this address should be treated as trailing. * Returns if the command attached to this address should be treated as trailing.
* A trailing command is executed whenever the address is scanned for children. * A trailing command is executed whenever the address is scanned for children.
* Its parameters are parsed and added to the context. * Its parameters are parsed and added to the context.
* *
* @return true if the command attached to this address should be treated as trailing. * @return true if the command attached to this address should be treated as trailing.
*/ */
boolean isCommandTrailing(); boolean isCommandTrailing();
static ICommandAddress newChild() { static ICommandAddress newChild() {
return new ChildCommandAddress(); return new ChildCommandAddress();
} }
static ICommandAddress newChild(Command command) { static ICommandAddress newChild(Command command) {
return new ChildCommandAddress(command); return new ChildCommandAddress(command);
} }
static ICommandAddress newRoot() { static ICommandAddress newRoot() {
return new RootCommandAddress(); return new RootCommandAddress();
} }
} }

View File

@@ -1,146 +1,146 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import io.dico.dicore.command.parameter.ArgumentBuffer; import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.registration.CommandMap; import io.dico.dicore.command.registration.CommandMap;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public interface ICommandDispatcher { public interface ICommandDispatcher {
/** /**
* Get a potentially indirect child of the root of this dispatcher * Get a potentially indirect child of the root of this dispatcher
* *
* @param buffer the argument buffer with the subsequent keys to traverse. Any keys beyond the first that isn't found are ignored. * @param buffer the argument buffer with the subsequent keys to traverse. Any keys beyond the first that isn't found are ignored.
* @return the child, or this same instance of no child is found. * @return the child, or this same instance of no child is found.
*/ */
ICommandAddress getDeepChild(ArgumentBuffer buffer); ICommandAddress getDeepChild(ArgumentBuffer buffer);
/** /**
* Similar to {@link #getDeepChild(ArgumentBuffer)}, * Similar to {@link #getDeepChild(ArgumentBuffer)},
* but this method incorporates checks on the command of traversed children: * but this method incorporates checks on the command of traversed children:
* {@link Command#isVisibleTo(CommandSender)} * {@link Command#isVisibleTo(CommandSender)}
* and {@link Command#takePrecedenceOverSubcommand(String, ArgumentBuffer)} * and {@link Command#takePrecedenceOverSubcommand(String, ArgumentBuffer)}
* <p> * <p>
* The target of a command is never null, however, the same instance might be returned, and the returned address might not hold a command. * The target of a command is never null, however, the same instance might be returned, and the returned address might not hold a command.
* *
* @param sender the sender of the command * @param sender the sender of the command
* @param buffer the command itself as a buffer. * @param buffer the command itself as a buffer.
* @return the address that is the target of the command. * @return the address that is the target of the command.
*/ */
@Deprecated @Deprecated
ICommandAddress getCommandTarget(CommandSender sender, ArgumentBuffer buffer); ICommandAddress getCommandTarget(CommandSender sender, ArgumentBuffer buffer);
/** /**
* Similar to {@link #getDeepChild(ArgumentBuffer)}, * Similar to {@link #getDeepChild(ArgumentBuffer)},
* but this method incorporates checks on the command of traversed children: * but this method incorporates checks on the command of traversed children:
* {@link Command#isVisibleTo(CommandSender)} * {@link Command#isVisibleTo(CommandSender)}
* and {@link Command#takePrecedenceOverSubcommand(String, ArgumentBuffer)} * and {@link Command#takePrecedenceOverSubcommand(String, ArgumentBuffer)}
* <p> * <p>
* The target of a command is never null, however, the same instance might be returned, and the returned address might not hold a command. * The target of a command is never null, however, the same instance might be returned, and the returned address might not hold a command.
* *
* @param context the context of the command. The context must not have its address set. * @param context the context of the command. The context must not have its address set.
* @param buffer the command itself as a buffer. * @param buffer the command itself as a buffer.
* @return the address that is the target of the command. * @return the address that is the target of the command.
*/ */
ICommandAddress getCommandTarget(ExecutionContext context, ArgumentBuffer buffer) throws CommandException; ICommandAddress getCommandTarget(ExecutionContext context, ArgumentBuffer buffer) throws CommandException;
/** /**
* dispatch the command * dispatch the command
* *
* @param sender the sender * @param sender the sender
* @param command the command * @param command the command
* @return true if a command has executed * @return true if a command has executed
*/ */
boolean dispatchCommand(CommandSender sender, String[] command); boolean dispatchCommand(CommandSender sender, String[] command);
/** /**
* dispatch the command * dispatch the command
* *
* @param sender the sender * @param sender the sender
* @param usedLabel the label (word after the /) * @param usedLabel the label (word after the /)
* @param args the arguments * @param args the arguments
* @return true if a command has executed * @return true if a command has executed
*/ */
boolean dispatchCommand(CommandSender sender, String usedLabel, String[] args); boolean dispatchCommand(CommandSender sender, String usedLabel, String[] args);
/** /**
* dispatch the command * dispatch the command
* *
* @param sender the sender * @param sender the sender
* @param buffer the command * @param buffer the command
* @return true if a command has executed * @return true if a command has executed
*/ */
boolean dispatchCommand(CommandSender sender, ArgumentBuffer buffer); boolean dispatchCommand(CommandSender sender, ArgumentBuffer buffer);
/** /**
* suggest tab completions * suggest tab completions
* *
* @param sender the sender as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)} * @param sender the sender as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}
* @param location the location as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)} * @param location the location as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}
* @param args the arguments as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)} * @param args the arguments as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}
* args must be sanitized such that it contains no empty elements, particularly at the last index. * args must be sanitized such that it contains no empty elements, particularly at the last index.
* @return tab completions * @return tab completions
*/ */
List<String> getTabCompletions(CommandSender sender, Location location, String[] args); List<String> getTabCompletions(CommandSender sender, Location location, String[] args);
/** /**
* suggest tab completions * suggest tab completions
* *
* @param sender the sender as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)} * @param sender the sender as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}
* @param usedLabel the label as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)} * @param usedLabel the label as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}
* @param location the location as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)} * @param location the location as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}
* @param args the arguments as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)} * @param args the arguments as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}
* @return tab completions * @return tab completions
*/ */
List<String> getTabCompletions(CommandSender sender, String usedLabel, Location location, String[] args); List<String> getTabCompletions(CommandSender sender, String usedLabel, Location location, String[] args);
/** /**
* suggest tab completions * suggest tab completions
* *
* @param sender the sender as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)} * @param sender the sender as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}
* @param location the location as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)} * @param location the location as passed to {@link org.bukkit.command.Command#tabComplete(CommandSender, String, String[], Location)}
* @param buffer the arguments as a buffer * @param buffer the arguments as a buffer
* @return tab completions * @return tab completions
*/ */
List<String> getTabCompletions(CommandSender sender, Location location, ArgumentBuffer buffer); List<String> getTabCompletions(CommandSender sender, Location location, ArgumentBuffer buffer);
/** /**
* Register this dispatcher's commands to the command map * Register this dispatcher's commands to the command map
* *
* @throws UnsupportedOperationException if this dispatcher is not the root of the tree * @throws UnsupportedOperationException if this dispatcher is not the root of the tree
*/ */
default void registerToCommandMap() { default void registerToCommandMap() {
registerToCommandMap(null, CommandMap.getCommandMap(), EOverridePolicy.OVERRIDE_ALL); registerToCommandMap(null, CommandMap.getCommandMap(), EOverridePolicy.OVERRIDE_ALL);
} }
/** /**
* Register this dispatcher's commands to the command map * Register this dispatcher's commands to the command map
* *
* @param fallbackPrefix the fallback prefix to use, null if none * @param fallbackPrefix the fallback prefix to use, null if none
* @param overridePolicy the override policy * @param overridePolicy the override policy
* @throws UnsupportedOperationException if this dispatcher is not the root of the tree * @throws UnsupportedOperationException if this dispatcher is not the root of the tree
*/ */
default void registerToCommandMap(String fallbackPrefix, EOverridePolicy overridePolicy) { default void registerToCommandMap(String fallbackPrefix, EOverridePolicy overridePolicy) {
registerToCommandMap(fallbackPrefix, CommandMap.getCommandMap(), overridePolicy); registerToCommandMap(fallbackPrefix, CommandMap.getCommandMap(), overridePolicy);
} }
/** /**
* Register this dispatcher's commands to the command map * Register this dispatcher's commands to the command map
* *
* @param fallbackPrefix the fallback prefix to use, null if none * @param fallbackPrefix the fallback prefix to use, null if none
* @param map the command map * @param map the command map
* @param overridePolicy the override policy * @param overridePolicy the override policy
* @throws UnsupportedOperationException if this dispatcher is not the root of the tree * @throws UnsupportedOperationException if this dispatcher is not the root of the tree
*/ */
void registerToCommandMap(String fallbackPrefix, Map<String, org.bukkit.command.Command> map, EOverridePolicy overridePolicy); void registerToCommandMap(String fallbackPrefix, Map<String, org.bukkit.command.Command> map, EOverridePolicy overridePolicy);
default void unregisterFromCommandMap() { default void unregisterFromCommandMap() {
unregisterFromCommandMap(CommandMap.getCommandMap()); unregisterFromCommandMap(CommandMap.getCommandMap());
} }
void unregisterFromCommandMap(Map<String, org.bukkit.command.Command> map); void unregisterFromCommandMap(Map<String, org.bukkit.command.Command> map);
} }

View File

@@ -1,201 +1,201 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import io.dico.dicore.exceptions.checkedfunctions.CheckedConsumer; import io.dico.dicore.exceptions.checkedfunctions.CheckedConsumer;
import io.dico.dicore.exceptions.checkedfunctions.CheckedRunnable; import io.dico.dicore.exceptions.checkedfunctions.CheckedRunnable;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public interface IContextFilter extends Comparable<IContextFilter> { public interface IContextFilter extends Comparable<IContextFilter> {
/** /**
* Filter the given context by this filter's criteria. * Filter the given context by this filter's criteria.
* If the context does not match the criteria, an exception is thrown describing the problem. * If the context does not match the criteria, an exception is thrown describing the problem.
* *
* @param context the context to match * @param context the context to match
* @throws CommandException if it doesn't match * @throws CommandException if it doesn't match
*/ */
void filterContext(ExecutionContext context) throws CommandException; void filterContext(ExecutionContext context) throws CommandException;
/** /**
* Filter an execution context for a direct or indirect sub command of the command that registered this filter. * Filter an execution context for a direct or indirect sub command of the command that registered this filter.
* *
* @param subContext the context for the execution * @param subContext the context for the execution
* @param path the path traversed from the command that registered this filter to the executed command * @param path the path traversed from the command that registered this filter to the executed command
*/ */
default void filterSubContext(ExecutionContext subContext, String... path) throws CommandException { default void filterSubContext(ExecutionContext subContext, String... path) throws CommandException {
filterContext(subContext); filterContext(subContext);
} }
/** /**
* Get the priority of this context filter. * Get the priority of this context filter.
* The priorities determine the order in which a command's context filters are executed. * The priorities determine the order in which a command's context filters are executed.
* *
* @return the priority * @return the priority
*/ */
Priority getPriority(); Priority getPriority();
default boolean allowsContext(ExecutionContext context) { default boolean allowsContext(ExecutionContext context) {
try { try {
filterContext(context); filterContext(context);
return true; return true;
} catch (CommandException ex) { } catch (CommandException ex) {
return false; return false;
} }
} }
/** /**
* Used to sort filters in execution order. That is, filters are ordered by {@link #getPriority()} * Used to sort filters in execution order. That is, filters are ordered by {@link #getPriority()}
* *
* @param o compared filter * @param o compared filter
* @return comparison value * @return comparison value
*/ */
@Override @Override
default int compareTo(@NotNull IContextFilter o) { default int compareTo(@NotNull IContextFilter o) {
return getPriority().compareTo(o.getPriority()); return getPriority().compareTo(o.getPriority());
} }
/* /*
default boolean isInheritable() { default boolean isInheritable() {
return false; return false;
} }
default IContextFilter inherit(String... components) { default IContextFilter inherit(String... components) {
if (!isInheritable()) { if (!isInheritable()) {
throw new IllegalStateException("This IContextFilter cannot be inherited"); throw new IllegalStateException("This IContextFilter cannot be inherited");
} }
return this; return this;
}*/ }*/
/** /**
* IContextFilter priorities. Executes from top to bottom. * IContextFilter priorities. Executes from top to bottom.
*/ */
enum Priority { enum Priority {
/** /**
* This priority should have checks on the sender type. * This priority should have checks on the sender type.
* Any filters on this priority are tested before permissions are. * Any filters on this priority are tested before permissions are.
* This is the highest priority. * This is the highest priority.
*/ */
VERY_EARLY, // sender type check VERY_EARLY, // sender type check
/** /**
* This priority is specific to permissions. * This priority is specific to permissions.
*/ */
PERMISSION, PERMISSION,
/** /**
* Early priority. Post permissions, pre parameter-parsing. * Early priority. Post permissions, pre parameter-parsing.
*/ */
EARLY, EARLY,
/** /**
* Normal priority. Post permissions, pre parameter-parsing. * Normal priority. Post permissions, pre parameter-parsing.
*/ */
NORMAL, NORMAL,
/** /**
* Late priority. Post permissions, pre parameter-parsing. * Late priority. Post permissions, pre parameter-parsing.
*/ */
LATE, LATE,
/** /**
* Very late priority. Post permissions, pre parameter-parsing. * Very late priority. Post permissions, pre parameter-parsing.
*/ */
VERY_LATE, VERY_LATE,
/** /**
* Post parameters priority. Post permissions, post parameter-parsing. * Post parameters priority. Post permissions, post parameter-parsing.
* This is the lowest priority. * This is the lowest priority.
*/ */
POST_PARAMETERS; POST_PARAMETERS;
private IContextFilter inheritor; private IContextFilter inheritor;
/** /**
* Get the context filter that inherits context filters from the parent of the same priority. * Get the context filter that inherits context filters from the parent of the same priority.
* If this filter is also present at the parent, it will do the same for the parent's parent, and so on. * If this filter is also present at the parent, it will do the same for the parent's parent, and so on.
* *
* @return the inheritor * @return the inheritor
*/ */
public IContextFilter getInheritor() { public IContextFilter getInheritor() {
if (inheritor == null) { if (inheritor == null) {
inheritor = InheritingContextFilter.inheritingPriority(this); inheritor = InheritingContextFilter.inheritingPriority(this);
} }
return inheritor; return inheritor;
} }
} }
/** /**
* Ensures that only {@link org.bukkit.entity.Player} type senders can execute the command. * Ensures that only {@link org.bukkit.entity.Player} type senders can execute the command.
*/ */
IContextFilter PLAYER_ONLY = filterSender(Priority.VERY_EARLY, Validate::isPlayer); IContextFilter PLAYER_ONLY = filterSender(Priority.VERY_EARLY, Validate::isPlayer);
/** /**
* Ensures that only {@link org.bukkit.command.ConsoleCommandSender} type senders can execute the command. * Ensures that only {@link org.bukkit.command.ConsoleCommandSender} type senders can execute the command.
*/ */
IContextFilter CONSOLE_ONLY = filterSender(Priority.VERY_EARLY, Validate::isConsole); IContextFilter CONSOLE_ONLY = filterSender(Priority.VERY_EARLY, Validate::isConsole);
/** /**
* This filter is not working as intended. * This filter is not working as intended.
* <p> * <p>
* There is supposed to be a permission filter that takes a base, and appends the command's address to the base, and checks that permission. * There is supposed to be a permission filter that takes a base, and appends the command's address to the base, and checks that permission.
*/ */
IContextFilter INHERIT_PERMISSIONS = Priority.PERMISSION.getInheritor(); IContextFilter INHERIT_PERMISSIONS = Priority.PERMISSION.getInheritor();
static IContextFilter fromCheckedRunnable(Priority priority, CheckedRunnable<? extends CommandException> runnable) { static IContextFilter fromCheckedRunnable(Priority priority, CheckedRunnable<? extends CommandException> runnable) {
return new IContextFilter() { return new IContextFilter() {
@Override @Override
public void filterContext(ExecutionContext context) throws CommandException { public void filterContext(ExecutionContext context) throws CommandException {
runnable.checkedRun(); runnable.checkedRun();
} }
@Override @Override
public Priority getPriority() { public Priority getPriority() {
return priority; return priority;
} }
}; };
} }
static IContextFilter filterSender(Priority priority, CheckedConsumer<? super CommandSender, ? extends CommandException> consumer) { static IContextFilter filterSender(Priority priority, CheckedConsumer<? super CommandSender, ? extends CommandException> consumer) {
return new IContextFilter() { return new IContextFilter() {
@Override @Override
public void filterContext(ExecutionContext context) throws CommandException { public void filterContext(ExecutionContext context) throws CommandException {
consumer.checkedAccept(context.getSender()); consumer.checkedAccept(context.getSender());
} }
@Override @Override
public Priority getPriority() { public Priority getPriority() {
return priority; return priority;
} }
}; };
} }
static IContextFilter permission(String permission) { static IContextFilter permission(String permission) {
return new PermissionContextFilter(permission); return new PermissionContextFilter(permission);
} }
static IContextFilter permission(String permission, String failMessage) { static IContextFilter permission(String permission, String failMessage) {
return new PermissionContextFilter(permission, failMessage); return new PermissionContextFilter(permission, failMessage);
} }
static IContextFilter inheritablePermission(String permission) { static IContextFilter inheritablePermission(String permission) {
return new PermissionContextFilter(permission, true); return new PermissionContextFilter(permission, true);
} }
/** /**
* Produce an inheritable permission context filter. * Produce an inheritable permission context filter.
* A permission component is an element in {@code permission.split("\\.")} * A permission component is an element in {@code permission.split("\\.")}
* *
* @param permission The permission that is required for the command that this is directly assigned to * @param permission The permission that is required for the command that this is directly assigned to
* @param componentInsertionIndex the index where any sub-components are inserted. -1 for "at the end". * @param componentInsertionIndex the index where any sub-components are inserted. -1 for "at the end".
* @param failMessage the message to send if the permission is not met * @param failMessage the message to send if the permission is not met
* @return the context filter * @return the context filter
* @throws IllegalArgumentException if componentInsertionIndex is out of range * @throws IllegalArgumentException if componentInsertionIndex is out of range
*/ */
static IContextFilter inheritablePermission(String permission, int componentInsertionIndex, String failMessage) { static IContextFilter inheritablePermission(String permission, int componentInsertionIndex, String failMessage) {
return new PermissionContextFilter(permission, componentInsertionIndex, failMessage); return new PermissionContextFilter(permission, componentInsertionIndex, failMessage);
} }
} }

View File

@@ -1,64 +1,64 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import java.util.List; import java.util.List;
public abstract class InheritingContextFilter implements IContextFilter { public abstract class InheritingContextFilter implements IContextFilter {
private static final String[] emptyStringArray = new String[0]; private static final String[] emptyStringArray = new String[0];
private static String[] addParent(String[] path, String parent) { private static String[] addParent(String[] path, String parent) {
String[] out = new String[path.length + 1]; String[] out = new String[path.length + 1];
System.arraycopy(path, 0, out, 1, path.length); System.arraycopy(path, 0, out, 1, path.length);
out[0] = parent; out[0] = parent;
return out; return out;
} }
protected abstract boolean isInherited(IContextFilter filter); protected abstract boolean isInherited(IContextFilter filter);
@Override @Override
public void filterContext(ExecutionContext context) throws CommandException { public void filterContext(ExecutionContext context) throws CommandException {
ICommandAddress address = context.getAddress(); ICommandAddress address = context.getAddress();
String[] traversedPath = emptyStringArray; String[] traversedPath = emptyStringArray;
do { do {
traversedPath = addParent(traversedPath, address.getMainKey()); traversedPath = addParent(traversedPath, address.getMainKey());
address = address.getParent(); address = address.getParent();
if (address != null && address.hasCommand()) { if (address != null && address.hasCommand()) {
boolean doBreak = true; boolean doBreak = true;
Command command = address.getCommand(); Command command = address.getCommand();
List<IContextFilter> contextFilterList = command.getContextFilters(); List<IContextFilter> contextFilterList = command.getContextFilters();
for (IContextFilter filter : contextFilterList) { for (IContextFilter filter : contextFilterList) {
if (isInherited(filter)) { if (isInherited(filter)) {
if (filter == this) { if (filter == this) {
// do the same for next parent // do the same for next parent
// this method is necessary to keep traversedPath information // this method is necessary to keep traversedPath information
doBreak = false; doBreak = false;
} else { } else {
filter.filterSubContext(context, traversedPath); filter.filterSubContext(context, traversedPath);
} }
} }
} }
if (doBreak) { if (doBreak) {
break; break;
} }
} }
} while (address != null); } while (address != null);
} }
static InheritingContextFilter inheritingPriority(Priority priority) { static InheritingContextFilter inheritingPriority(Priority priority) {
return new InheritingContextFilter() { return new InheritingContextFilter() {
@Override @Override
protected boolean isInherited(IContextFilter filter) { protected boolean isInherited(IContextFilter filter) {
return filter.getPriority() == priority; return filter.getPriority() == priority;
} }
@Override @Override
public Priority getPriority() { public Priority getPriority() {
return priority; return priority;
} }
}; };
} }
} }

View File

@@ -1,35 +1,35 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import io.dico.dicore.exceptions.checkedfunctions.CheckedBiFunction; import io.dico.dicore.exceptions.checkedfunctions.CheckedBiFunction;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.BiFunction; import java.util.function.BiFunction;
public class LambdaCommand extends ExtendedCommand<LambdaCommand> { public class LambdaCommand extends ExtendedCommand<LambdaCommand> {
private CheckedBiFunction<CommandSender, ExecutionContext, String, CommandException> executor; private CheckedBiFunction<CommandSender, ExecutionContext, String, CommandException> executor;
private BiFunction<CommandSender, ExecutionContext, List<String>> completer; private BiFunction<CommandSender, ExecutionContext, List<String>> completer;
public LambdaCommand executor(CheckedBiFunction<CommandSender, ExecutionContext, String, CommandException> executor) { public LambdaCommand executor(CheckedBiFunction<CommandSender, ExecutionContext, String, CommandException> executor) {
this.executor = Objects.requireNonNull(executor); this.executor = Objects.requireNonNull(executor);
return this; return this;
} }
public LambdaCommand completer(BiFunction<CommandSender, ExecutionContext, List<String>> completer) { public LambdaCommand completer(BiFunction<CommandSender, ExecutionContext, List<String>> completer) {
this.completer = Objects.requireNonNull(completer); this.completer = Objects.requireNonNull(completer);
return this; return this;
} }
@Override @Override
public String execute(CommandSender sender, ExecutionContext context) throws CommandException { public String execute(CommandSender sender, ExecutionContext context) throws CommandException {
return executor.checkedApply(sender, context); return executor.checkedApply(sender, context);
} }
@Override @Override
public List<String> tabComplete(CommandSender sender, ExecutionContext context, Location location) { public List<String> tabComplete(CommandSender sender, ExecutionContext context, Location location) {
return completer == null ? super.tabComplete(sender, context, location) : completer.apply(sender, context); return completer == null ? super.tabComplete(sender, context, location) : completer.apply(sender, context);
} }
} }

View File

@@ -1,312 +1,312 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import io.dico.dicore.command.chat.ChatHandlers; import io.dico.dicore.command.chat.ChatHandlers;
import io.dico.dicore.command.chat.IChatHandler; import io.dico.dicore.command.chat.IChatHandler;
import io.dico.dicore.command.parameter.ArgumentBuffer; import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.parameter.ParameterList; import io.dico.dicore.command.parameter.ParameterList;
import io.dico.dicore.command.predef.DefaultGroupCommand; import io.dico.dicore.command.predef.DefaultGroupCommand;
import io.dico.dicore.command.predef.HelpCommand; import io.dico.dicore.command.predef.HelpCommand;
import io.dico.dicore.command.predef.PredefinedCommand; import io.dico.dicore.command.predef.PredefinedCommand;
import java.util.*; import java.util.*;
public abstract class ModifiableCommandAddress implements ICommandAddress { public abstract class ModifiableCommandAddress implements ICommandAddress {
Map<String, ChildCommandAddress> children; Map<String, ChildCommandAddress> children;
Collection<String> childrenMainKeys = Collections.emptyList(); Collection<String> childrenMainKeys = Collections.emptyList();
// the chat handler as configured by the programmer // the chat handler as configured by the programmer
IChatHandler chatHandler; IChatHandler chatHandler;
// cache for the algorithm that finds the first chat handler going up the tree // cache for the algorithm that finds the first chat handler going up the tree
transient IChatHandler cachedChatHandlerFallback; transient IChatHandler cachedChatHandlerFallback;
ModifiableCommandAddress helpChild; ModifiableCommandAddress helpChild;
public ModifiableCommandAddress() { public ModifiableCommandAddress() {
this.children = new LinkedHashMap<>(4); this.children = new LinkedHashMap<>(4);
} }
@Override @Override
public boolean hasParent() { public boolean hasParent() {
return getParent() != null; return getParent() != null;
} }
@Override @Override
public boolean hasCommand() { public boolean hasCommand() {
return getCommand() != null; return getCommand() != null;
} }
@Override @Override
public boolean hasUserDeclaredCommand() { public boolean hasUserDeclaredCommand() {
Command command = getCommand(); Command command = getCommand();
return command != null && !(command instanceof PredefinedCommand); return command != null && !(command instanceof PredefinedCommand);
} }
@Override @Override
public Command getCommand() { public Command getCommand() {
return null; return null;
} }
@Override @Override
public boolean isRoot() { public boolean isRoot() {
return false; return false;
} }
@Override @Override
public List<String> getNames() { public List<String> getNames() {
return null; return null;
} }
@Override @Override
public List<String> getAliases() { public List<String> getAliases() {
List<String> names = getNames(); List<String> names = getNames();
if (names == null) { if (names == null) {
return null; return null;
} }
if (names.isEmpty()) { if (names.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
return names.subList(1, names.size()); return names.subList(1, names.size());
} }
@Override @Override
public String getMainKey() { public String getMainKey() {
return null; return null;
} }
public void setCommand(Command command) { public void setCommand(Command command) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public abstract ModifiableCommandAddress getParent(); public abstract ModifiableCommandAddress getParent();
@Override @Override
public RootCommandAddress getRoot() { public RootCommandAddress getRoot() {
ModifiableCommandAddress out = this; ModifiableCommandAddress out = this;
while (out.hasParent()) { while (out.hasParent()) {
out = out.getParent(); out = out.getParent();
} }
return out.isRoot() ? (RootCommandAddress) out : null; return out.isRoot() ? (RootCommandAddress) out : null;
} }
@Override @Override
public int getDepth() { public int getDepth() {
int depth = 0; int depth = 0;
ICommandAddress address = this; ICommandAddress address = this;
while (address.hasParent()) { while (address.hasParent()) {
address = address.getParent(); address = address.getParent();
depth++; depth++;
} }
return depth; return depth;
} }
@Override @Override
public boolean isDepthLargerThan(int value) { public boolean isDepthLargerThan(int value) {
int depth = 0; int depth = 0;
ICommandAddress address = this; ICommandAddress address = this;
do { do {
if (depth > value) { if (depth > value) {
return true; return true;
} }
address = address.getParent(); address = address.getParent();
depth++; depth++;
} while (address != null); } while (address != null);
return false; return false;
} }
@Override @Override
public boolean hasChildren() { public boolean hasChildren() {
return !children.isEmpty(); return !children.isEmpty();
} }
@Override @Override
public int getNumberOfRealChildren() { public int getNumberOfRealChildren() {
return childrenMainKeys.size(); return childrenMainKeys.size();
} }
@Override @Override
public Collection<String> getChildrenMainKeys() { public Collection<String> getChildrenMainKeys() {
return Collections.unmodifiableCollection(childrenMainKeys); return Collections.unmodifiableCollection(childrenMainKeys);
} }
@Override @Override
public Map<String, ? extends ModifiableCommandAddress> getChildren() { public Map<String, ? extends ModifiableCommandAddress> getChildren() {
return Collections.unmodifiableMap(children); return Collections.unmodifiableMap(children);
} }
@Override @Override
public ChildCommandAddress getChild(String key) { public ChildCommandAddress getChild(String key) {
return children.get(key); return children.get(key);
} }
@Override @Override
public ChildCommandAddress getChild(ExecutionContext context, ArgumentBuffer buffer) throws CommandException { public ChildCommandAddress getChild(ExecutionContext context, ArgumentBuffer buffer) throws CommandException {
return buffer.hasNext() ? getChild(buffer.next()) : null; return buffer.hasNext() ? getChild(buffer.next()) : null;
} }
public void addChild(ICommandAddress child) { public void addChild(ICommandAddress child) {
if (!(child instanceof ChildCommandAddress)) { if (!(child instanceof ChildCommandAddress)) {
throw new IllegalArgumentException("Argument must be a ChildCommandAddress"); throw new IllegalArgumentException("Argument must be a ChildCommandAddress");
} }
ChildCommandAddress mChild = (ChildCommandAddress) child; ChildCommandAddress mChild = (ChildCommandAddress) child;
if (mChild.parent != null) { if (mChild.parent != null) {
throw new IllegalArgumentException("Argument already has a parent"); throw new IllegalArgumentException("Argument already has a parent");
} }
if (mChild.names.isEmpty()) { if (mChild.names.isEmpty()) {
throw new IllegalArgumentException("Argument must have names"); throw new IllegalArgumentException("Argument must have names");
} }
Iterator<String> names = mChild.modifiableNamesIterator(); Iterator<String> names = mChild.modifiableNamesIterator();
String mainKey = names.next(); String mainKey = names.next();
if (!childrenMainKeys.contains(mainKey)) { if (!childrenMainKeys.contains(mainKey)) {
if (!(childrenMainKeys instanceof ArrayList)) { if (!(childrenMainKeys instanceof ArrayList)) {
childrenMainKeys = new ArrayList<>(); childrenMainKeys = new ArrayList<>();
} }
childrenMainKeys.add(mainKey); childrenMainKeys.add(mainKey);
} }
children.put(mainKey, mChild); children.put(mainKey, mChild);
while (names.hasNext()) { while (names.hasNext()) {
String name = names.next(); String name = names.next();
if (children.putIfAbsent(name, mChild) != null) { if (children.putIfAbsent(name, mChild) != null) {
names.remove(); names.remove();
} }
} }
mChild.setParent(this); mChild.setParent(this);
if (mChild.hasCommand() && mChild.getCommand() instanceof HelpCommand) { if (mChild.hasCommand() && mChild.getCommand() instanceof HelpCommand) {
helpChild = mChild; helpChild = mChild;
} }
} }
public void removeChildren(boolean removeAliases, String... keys) { public void removeChildren(boolean removeAliases, String... keys) {
if (keys.length == 0) { if (keys.length == 0) {
throw new IllegalArgumentException("keys is empty"); throw new IllegalArgumentException("keys is empty");
} }
for (String key : keys) { for (String key : keys) {
ChildCommandAddress keyTarget = getChild(key); ChildCommandAddress keyTarget = getChild(key);
if (keyTarget == null) { if (keyTarget == null) {
continue; continue;
} }
if (removeAliases) { if (removeAliases) {
Iterator<String> iterator = keyTarget.namesModifiable.iterator(); Iterator<String> iterator = keyTarget.namesModifiable.iterator();
boolean first = true; boolean first = true;
while (iterator.hasNext()) { while (iterator.hasNext()) {
String alias = iterator.next(); String alias = iterator.next();
ChildCommandAddress aliasTarget = getChild(key); ChildCommandAddress aliasTarget = getChild(key);
if (aliasTarget == keyTarget) { if (aliasTarget == keyTarget) {
if (first) { if (first) {
childrenMainKeys.remove(alias); childrenMainKeys.remove(alias);
} }
children.remove(alias); children.remove(alias);
} }
iterator.remove(); iterator.remove();
first = false; first = false;
} }
} else { } else {
if (key.equals(keyTarget.getMainKey())) { if (key.equals(keyTarget.getMainKey())) {
childrenMainKeys.remove(key); childrenMainKeys.remove(key);
} }
children.remove(key); children.remove(key);
keyTarget.namesModifiable.remove(key); keyTarget.namesModifiable.remove(key);
} }
} }
} }
public boolean hasHelpCommand() { public boolean hasHelpCommand() {
return helpChild != null; return helpChild != null;
} }
public ModifiableCommandAddress getHelpCommand() { public ModifiableCommandAddress getHelpCommand() {
return helpChild; return helpChild;
} }
@Override @Override
public IChatHandler getChatHandler() { public IChatHandler getChatHandler() {
if (cachedChatHandlerFallback == null) { if (cachedChatHandlerFallback == null) {
if (chatHandler != null) { if (chatHandler != null) {
cachedChatHandlerFallback = chatHandler; cachedChatHandlerFallback = chatHandler;
} else if (!hasParent()) { } else if (!hasParent()) {
cachedChatHandlerFallback = ChatHandlers.defaultChat(); cachedChatHandlerFallback = ChatHandlers.defaultChat();
} else { } else {
cachedChatHandlerFallback = getParent().getChatHandler(); cachedChatHandlerFallback = getParent().getChatHandler();
} }
} }
return cachedChatHandlerFallback; return cachedChatHandlerFallback;
} }
public void setChatHandler(IChatHandler chatHandler) { public void setChatHandler(IChatHandler chatHandler) {
this.chatHandler = chatHandler; this.chatHandler = chatHandler;
resetChatHandlerCache(new HashSet<>()); resetChatHandlerCache(new HashSet<>());
} }
void resetChatHandlerCache(Set<ModifiableCommandAddress> dejaVu) { void resetChatHandlerCache(Set<ModifiableCommandAddress> dejaVu) {
if (dejaVu.add(this)) { if (dejaVu.add(this)) {
cachedChatHandlerFallback = chatHandler; cachedChatHandlerFallback = chatHandler;
for (ChildCommandAddress address : children.values()) { for (ChildCommandAddress address : children.values()) {
if (address.chatHandler == null) { if (address.chatHandler == null) {
address.resetChatHandlerCache(dejaVu); address.resetChatHandlerCache(dejaVu);
} }
} }
} }
} }
@Override @Override
public ICommandDispatcher getDispatcherForTree() { public ICommandDispatcher getDispatcherForTree() {
return getRoot(); return getRoot();
} }
@Override @Override
public boolean isCommandTrailing() { public boolean isCommandTrailing() {
return false; return false;
} }
public void setCommandTrailing(boolean trailing) { public void setCommandTrailing(boolean trailing) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
void appendDebugInformation(StringBuilder target, String linePrefix, Set<ICommandAddress> seen) { void appendDebugInformation(StringBuilder target, String linePrefix, Set<ICommandAddress> seen) {
target.append('\n').append(linePrefix); target.append('\n').append(linePrefix);
if (!seen.add(this)) { if (!seen.add(this)) {
target.append("<duplicate of address '").append(getAddress()).append("'>"); target.append("<duplicate of address '").append(getAddress()).append("'>");
return; return;
} }
if (this instanceof ChildCommandAddress) { if (this instanceof ChildCommandAddress) {
List<String> namesModifiable = ((ChildCommandAddress) this).namesModifiable; List<String> namesModifiable = ((ChildCommandAddress) this).namesModifiable;
if (namesModifiable.isEmpty()) { if (namesModifiable.isEmpty()) {
target.append("<no key>"); target.append("<no key>");
} else { } else {
Iterator<String> keys = namesModifiable.iterator(); Iterator<String> keys = namesModifiable.iterator();
target.append(keys.next()).append(' '); target.append(keys.next()).append(' ');
if (keys.hasNext()) { if (keys.hasNext()) {
target.append('(').append(keys.next()); target.append('(').append(keys.next());
while (keys.hasNext()) { while (keys.hasNext()) {
target.append(" ,").append(keys.next()); target.append(" ,").append(keys.next());
} }
target.append(") "); target.append(") ");
} }
} }
} else { } else {
target.append("<root> "); target.append("<root> ");
} }
String commandClass = hasCommand() ? getCommand().getClass().getCanonicalName() : "<no command>"; String commandClass = hasCommand() ? getCommand().getClass().getCanonicalName() : "<no command>";
target.append(commandClass); target.append(commandClass);
for (ChildCommandAddress child : new HashSet<>(children.values())) { for (ChildCommandAddress child : new HashSet<>(children.values())) {
child.appendDebugInformation(target, linePrefix + " ", seen); child.appendDebugInformation(target, linePrefix + " ", seen);
} }
} }
} }

View File

@@ -1,136 +1,136 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
public class PermissionContextFilter implements IContextFilter { public class PermissionContextFilter implements IContextFilter {
private String permission; private String permission;
private String[] permissionComponents; private String[] permissionComponents;
private int componentInsertionIndex; private int componentInsertionIndex;
private String failMessage; private String failMessage;
public PermissionContextFilter(String permission) { public PermissionContextFilter(String permission) {
this.permission = Objects.requireNonNull(permission); this.permission = Objects.requireNonNull(permission);
} }
public PermissionContextFilter(String permission, String failMessage) { public PermissionContextFilter(String permission, String failMessage) {
this(permission); this(permission);
this.failMessage = failMessage; this.failMessage = failMessage;
} }
public PermissionContextFilter(String permission, boolean inheritable) { public PermissionContextFilter(String permission, boolean inheritable) {
this(permission, null, inheritable); this(permission, null, inheritable);
} }
public PermissionContextFilter(String permission, String failMessage, boolean inheritable) { public PermissionContextFilter(String permission, String failMessage, boolean inheritable) {
this(permission, failMessage); this(permission, failMessage);
if (inheritable) { if (inheritable) {
setupInheritability(-1); setupInheritability(-1);
} }
} }
public PermissionContextFilter(String permission, int componentInsertionIndex, String failMessage) { public PermissionContextFilter(String permission, int componentInsertionIndex, String failMessage) {
this(permission, failMessage); this(permission, failMessage);
setupInheritability(componentInsertionIndex); setupInheritability(componentInsertionIndex);
} }
private void setupInheritability(int componentInsertionIndex) { private void setupInheritability(int componentInsertionIndex) {
this.permissionComponents = permission.split("\\."); this.permissionComponents = permission.split("\\.");
this.componentInsertionIndex = componentInsertionIndex < 0 ? permissionComponents.length : componentInsertionIndex; this.componentInsertionIndex = componentInsertionIndex < 0 ? permissionComponents.length : componentInsertionIndex;
if (componentInsertionIndex > permissionComponents.length) throw new IllegalArgumentException(); if (componentInsertionIndex > permissionComponents.length) throw new IllegalArgumentException();
} }
private void doFilter(ExecutionContext context, String permission) throws CommandException { private void doFilter(ExecutionContext context, String permission) throws CommandException {
if (failMessage != null) { if (failMessage != null) {
Validate.isAuthorized(context.getSender(), permission, failMessage); Validate.isAuthorized(context.getSender(), permission, failMessage);
} else { } else {
Validate.isAuthorized(context.getSender(), permission); Validate.isAuthorized(context.getSender(), permission);
} }
} }
@Override @Override
public void filterContext(ExecutionContext context) throws CommandException { public void filterContext(ExecutionContext context) throws CommandException {
doFilter(context, permission); doFilter(context, permission);
} }
public String getInheritedPermission(String[] components) { public String getInheritedPermission(String[] components) {
int insertedAmount = components.length; int insertedAmount = components.length;
String[] currentComponents = permissionComponents; String[] currentComponents = permissionComponents;
int currentAmount = currentComponents.length; int currentAmount = currentComponents.length;
String[] targetArray = new String[currentAmount + insertedAmount]; String[] targetArray = new String[currentAmount + insertedAmount];
int insertionIndex; int insertionIndex;
//int newInsertionIndex; //int newInsertionIndex;
if (componentInsertionIndex == -1) { if (componentInsertionIndex == -1) {
insertionIndex = currentAmount; insertionIndex = currentAmount;
//newInsertionIndex = -1; //newInsertionIndex = -1;
} else { } else {
insertionIndex = componentInsertionIndex; insertionIndex = componentInsertionIndex;
//newInsertionIndex = insertionIndex + insertedAmount; //newInsertionIndex = insertionIndex + insertedAmount;
} }
// copy the current components up to insertionIndex // copy the current components up to insertionIndex
System.arraycopy(currentComponents, 0, targetArray, 0, insertionIndex); System.arraycopy(currentComponents, 0, targetArray, 0, insertionIndex);
// copy the new components into the array at insertionIndex // copy the new components into the array at insertionIndex
System.arraycopy(components, 0, targetArray, insertionIndex, insertedAmount); System.arraycopy(components, 0, targetArray, insertionIndex, insertedAmount);
// copy the current components from insertionIndex + inserted amount // copy the current components from insertionIndex + inserted amount
System.arraycopy(currentComponents, insertionIndex, targetArray, insertionIndex + insertedAmount, currentAmount - insertionIndex); System.arraycopy(currentComponents, insertionIndex, targetArray, insertionIndex + insertedAmount, currentAmount - insertionIndex);
return String.join(".", targetArray); return String.join(".", targetArray);
} }
@Override @Override
public void filterSubContext(ExecutionContext subContext, String... path) throws CommandException { public void filterSubContext(ExecutionContext subContext, String... path) throws CommandException {
if (isInheritable()) { if (isInheritable()) {
doFilter(subContext, getInheritedPermission(path)); doFilter(subContext, getInheritedPermission(path));
} }
} }
@Override @Override
public Priority getPriority() { public Priority getPriority() {
return Priority.PERMISSION; return Priority.PERMISSION;
} }
public boolean isInheritable() { public boolean isInheritable() {
return permissionComponents != null; return permissionComponents != null;
} }
public String getPermission() { public String getPermission() {
return permission; return permission;
} }
public int getComponentInsertionIndex() { public int getComponentInsertionIndex() {
return componentInsertionIndex; return componentInsertionIndex;
} }
public String getFailMessage() { public String getFailMessage() {
return failMessage; return failMessage;
} }
/* /*
private fun getPermissionsOf(address: ICommandAddress) = getPermissionsOf(address, emptyArray(), mutableListOf()) private fun getPermissionsOf(address: ICommandAddress) = getPermissionsOf(address, emptyArray(), mutableListOf())
private fun getPermissionsOf(address: ICommandAddress, path: Array<String>, result: MutableList<String>): List<String> { private fun getPermissionsOf(address: ICommandAddress, path: Array<String>, result: MutableList<String>): List<String> {
val command = address.command ?: return result val command = address.command ?: return result
var inherited = false var inherited = false
for (filter in command.contextFilters) { for (filter in command.contextFilters) {
when (filter) { when (filter) {
is PermissionContextFilter -> { is PermissionContextFilter -> {
if (path.isEmpty()) result.add(filter.permission) if (path.isEmpty()) result.add(filter.permission)
else if (filter.isInheritable) result.add(filter.getInheritedPermission(path)) else if (filter.isInheritable) result.add(filter.getInheritedPermission(path))
} }
is InheritingContextFilter -> { is InheritingContextFilter -> {
if (filter.priority == PERMISSION && address.hasParent() && !inherited) { if (filter.priority == PERMISSION && address.hasParent() && !inherited) {
inherited = true inherited = true
getPermissionsOf(address.parent, arrayOf(address.mainKey, *path), result) getPermissionsOf(address.parent, arrayOf(address.mainKey, *path), result)
} }
} }
} }
} }
return result return result
} }
*/ */
} }

View File

@@ -1,275 +1,275 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import io.dico.dicore.command.parameter.ArgumentBuffer; import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.registration.BukkitCommand; import io.dico.dicore.command.registration.BukkitCommand;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.*; import java.util.*;
public class RootCommandAddress extends ModifiableCommandAddress implements ICommandDispatcher { public class RootCommandAddress extends ModifiableCommandAddress implements ICommandDispatcher {
@Deprecated @Deprecated
public static final RootCommandAddress INSTANCE = new RootCommandAddress(); public static final RootCommandAddress INSTANCE = new RootCommandAddress();
public RootCommandAddress() { public RootCommandAddress() {
} }
@Override @Override
public Command getCommand() { public Command getCommand() {
return null; return null;
} }
@Override @Override
public boolean isRoot() { public boolean isRoot() {
return true; return true;
} }
@Override @Override
public List<String> getNames() { public List<String> getNames() {
return Collections.emptyList(); return Collections.emptyList();
} }
@Override @Override
public ModifiableCommandAddress getParent() { public ModifiableCommandAddress getParent() {
return null; return null;
} }
@Override @Override
public String getMainKey() { public String getMainKey() {
return null; return null;
} }
@Override @Override
public String getAddress() { public String getAddress() {
return ""; return "";
} }
@Override @Override
public void registerToCommandMap(String fallbackPrefix, Map<String, org.bukkit.command.Command> map, EOverridePolicy overridePolicy) { public void registerToCommandMap(String fallbackPrefix, Map<String, org.bukkit.command.Command> map, EOverridePolicy overridePolicy) {
Objects.requireNonNull(overridePolicy); Objects.requireNonNull(overridePolicy);
//debugChildren(this); //debugChildren(this);
Map<String, ChildCommandAddress> children = this.children; Map<String, ChildCommandAddress> children = this.children;
Map<ChildCommandAddress, BukkitCommand> wrappers = new IdentityHashMap<>(); Map<ChildCommandAddress, BukkitCommand> wrappers = new IdentityHashMap<>();
for (ChildCommandAddress address : children.values()) { for (ChildCommandAddress address : children.values()) {
if (!wrappers.containsKey(address)) { if (!wrappers.containsKey(address)) {
wrappers.put(address, new BukkitCommand(address)); wrappers.put(address, new BukkitCommand(address));
} }
} }
for (Map.Entry<String, ChildCommandAddress> entry : children.entrySet()) { for (Map.Entry<String, ChildCommandAddress> entry : children.entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
ChildCommandAddress address = entry.getValue(); ChildCommandAddress address = entry.getValue();
boolean override = overridePolicy == EOverridePolicy.OVERRIDE_ALL; boolean override = overridePolicy == EOverridePolicy.OVERRIDE_ALL;
if (!override && key.equals(address.getMainKey())) { if (!override && key.equals(address.getMainKey())) {
override = overridePolicy == EOverridePolicy.MAIN_KEY_ONLY || overridePolicy == EOverridePolicy.MAIN_AND_FALLBACK; override = overridePolicy == EOverridePolicy.MAIN_KEY_ONLY || overridePolicy == EOverridePolicy.MAIN_AND_FALLBACK;
} }
registerMember(map, key, wrappers.get(address), override); registerMember(map, key, wrappers.get(address), override);
if (fallbackPrefix != null) { if (fallbackPrefix != null) {
key = fallbackPrefix + key; key = fallbackPrefix + key;
override = overridePolicy != EOverridePolicy.OVERRIDE_NONE && overridePolicy != EOverridePolicy.MAIN_KEY_ONLY; override = overridePolicy != EOverridePolicy.OVERRIDE_NONE && overridePolicy != EOverridePolicy.MAIN_KEY_ONLY;
registerMember(map, key, wrappers.get(address), override); registerMember(map, key, wrappers.get(address), override);
} }
} }
} }
private static void debugChildren(ModifiableCommandAddress address) { private static void debugChildren(ModifiableCommandAddress address) {
Collection<String> keys = address.getChildrenMainKeys(); Collection<String> keys = address.getChildrenMainKeys();
for (String key : keys) { for (String key : keys) {
ChildCommandAddress child = address.getChild(key); ChildCommandAddress child = address.getChild(key);
System.out.println(child.getAddress()); System.out.println(child.getAddress());
debugChildren(child); debugChildren(child);
} }
} }
private static void registerMember(Map<String, org.bukkit.command.Command> map, private static void registerMember(Map<String, org.bukkit.command.Command> map,
String key, org.bukkit.command.Command value, boolean override) { String key, org.bukkit.command.Command value, boolean override) {
if (override) { if (override) {
map.put(key, value); map.put(key, value);
} else { } else {
map.putIfAbsent(key, value); map.putIfAbsent(key, value);
} }
} }
@Override @Override
public void unregisterFromCommandMap(Map<String, org.bukkit.command.Command> map) { public void unregisterFromCommandMap(Map<String, org.bukkit.command.Command> map) {
Set<ICommandAddress> children = new HashSet<>(this.children.values()); Set<ICommandAddress> children = new HashSet<>(this.children.values());
Iterator<Map.Entry<String, org.bukkit.command.Command>> iterator = map.entrySet().iterator(); Iterator<Map.Entry<String, org.bukkit.command.Command>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
Map.Entry<String, org.bukkit.command.Command> entry = iterator.next(); Map.Entry<String, org.bukkit.command.Command> entry = iterator.next();
org.bukkit.command.Command cmd = entry.getValue(); org.bukkit.command.Command cmd = entry.getValue();
if (cmd instanceof BukkitCommand && children.contains(((BukkitCommand) cmd).getOrigin())) { if (cmd instanceof BukkitCommand && children.contains(((BukkitCommand) cmd).getOrigin())) {
iterator.remove(); iterator.remove();
} }
} }
} }
@Override @Override
public ModifiableCommandAddress getDeepChild(ArgumentBuffer buffer) { public ModifiableCommandAddress getDeepChild(ArgumentBuffer buffer) {
ModifiableCommandAddress cur = this; ModifiableCommandAddress cur = this;
ChildCommandAddress child; ChildCommandAddress child;
while (buffer.hasNext()) { while (buffer.hasNext()) {
child = cur.getChild(buffer.next()); child = cur.getChild(buffer.next());
if (child == null) { if (child == null) {
buffer.rewind(); buffer.rewind();
return cur; return cur;
} }
cur = child; cur = child;
} }
return cur; return cur;
} }
@Override @Override
public ModifiableCommandAddress getCommandTarget(CommandSender sender, ArgumentBuffer buffer) { public ModifiableCommandAddress getCommandTarget(CommandSender sender, ArgumentBuffer buffer) {
ModifiableCommandAddress cur = this; ModifiableCommandAddress cur = this;
ChildCommandAddress child; ChildCommandAddress child;
while (buffer.hasNext()) { while (buffer.hasNext()) {
child = cur.getChild(buffer.next()); child = cur.getChild(buffer.next());
if (child == null if (child == null
|| (child.hasCommand() && !child.getCommand().isVisibleTo(sender)) || (child.hasCommand() && !child.getCommand().isVisibleTo(sender))
|| (cur.hasCommand() && cur.getCommand().takePrecedenceOverSubcommand(buffer.peekPrevious(), buffer.getUnaffectingCopy()))) { || (cur.hasCommand() && cur.getCommand().takePrecedenceOverSubcommand(buffer.peekPrevious(), buffer.getUnaffectingCopy()))) {
buffer.rewind(); buffer.rewind();
break; break;
} }
cur = child; cur = child;
} }
return cur; return cur;
} }
@Override @Override
public ModifiableCommandAddress getCommandTarget(ExecutionContext context, ArgumentBuffer buffer) throws CommandException { public ModifiableCommandAddress getCommandTarget(ExecutionContext context, ArgumentBuffer buffer) throws CommandException {
CommandSender sender = context.getSender(); CommandSender sender = context.getSender();
ModifiableCommandAddress cur = this; ModifiableCommandAddress cur = this;
ChildCommandAddress child; ChildCommandAddress child;
while (buffer.hasNext()) { while (buffer.hasNext()) {
int cursor = buffer.getCursor(); int cursor = buffer.getCursor();
child = cur.getChild(context, buffer); child = cur.getChild(context, buffer);
if (child == null if (child == null
|| (context.isTabComplete() && !buffer.hasNext()) || (context.isTabComplete() && !buffer.hasNext())
|| (child.hasCommand() && !child.getCommand().isVisibleTo(sender)) || (child.hasCommand() && !child.getCommand().isVisibleTo(sender))
|| (cur.hasCommand() && cur.getCommand().takePrecedenceOverSubcommand(buffer.peekPrevious(), buffer.getUnaffectingCopy()))) { || (cur.hasCommand() && cur.getCommand().takePrecedenceOverSubcommand(buffer.peekPrevious(), buffer.getUnaffectingCopy()))) {
buffer.setCursor(cursor); buffer.setCursor(cursor);
break; break;
} }
cur = child; cur = child;
context.setAddress(child); context.setAddress(child);
if (child.hasCommand() && child.isCommandTrailing()) { if (child.hasCommand() && child.isCommandTrailing()) {
child.getCommand().initializeAndFilterContext(context); child.getCommand().initializeAndFilterContext(context);
child.getCommand().execute(context.getSender(), context); child.getCommand().execute(context.getSender(), context);
} }
} }
return cur; return cur;
} }
@Override @Override
public boolean dispatchCommand(CommandSender sender, String[] command) { public boolean dispatchCommand(CommandSender sender, String[] command) {
return dispatchCommand(sender, new ArgumentBuffer(command)); return dispatchCommand(sender, new ArgumentBuffer(command));
} }
@Override @Override
public boolean dispatchCommand(CommandSender sender, String usedLabel, String[] args) { public boolean dispatchCommand(CommandSender sender, String usedLabel, String[] args) {
return dispatchCommand(sender, new ArgumentBuffer(usedLabel, args)); return dispatchCommand(sender, new ArgumentBuffer(usedLabel, args));
} }
@Override @Override
public boolean dispatchCommand(CommandSender sender, ArgumentBuffer buffer) { public boolean dispatchCommand(CommandSender sender, ArgumentBuffer buffer) {
ExecutionContext context = new ExecutionContext(sender, buffer, false); ExecutionContext context = new ExecutionContext(sender, buffer, false);
ModifiableCommandAddress targetAddress = null; ModifiableCommandAddress targetAddress = null;
try { try {
targetAddress = getCommandTarget(context, buffer); targetAddress = getCommandTarget(context, buffer);
Command target = targetAddress.getCommand(); Command target = targetAddress.getCommand();
if (target == null) { if (target == null) {
if (targetAddress.hasHelpCommand()) { if (targetAddress.hasHelpCommand()) {
target = targetAddress.getHelpCommand().getCommand(); target = targetAddress.getHelpCommand().getCommand();
} else { } else {
return false; return false;
} }
} }
context.setCommand(target); context.setCommand(target);
if (!targetAddress.isCommandTrailing()) { if (!targetAddress.isCommandTrailing()) {
target.initializeAndFilterContext(context); target.initializeAndFilterContext(context);
String message = target.execute(sender, context); String message = target.execute(sender, context);
if (message != null && !message.isEmpty()) { if (message != null && !message.isEmpty()) {
context.sendMessage(EMessageType.RESULT, message); context.sendMessage(EMessageType.RESULT, message);
} }
} }
} catch (Throwable t) { } catch (Throwable t) {
if (targetAddress == null) { if (targetAddress == null) {
targetAddress = this; targetAddress = this;
} }
targetAddress.getChatHandler().handleException(sender, context, t); targetAddress.getChatHandler().handleException(sender, context, t);
} }
return true; return true;
} }
@Override @Override
public List<String> getTabCompletions(CommandSender sender, Location location, String[] args) { public List<String> getTabCompletions(CommandSender sender, Location location, String[] args) {
return getTabCompletions(sender, location, new ArgumentBuffer(args)); return getTabCompletions(sender, location, new ArgumentBuffer(args));
} }
@Override @Override
public List<String> getTabCompletions(CommandSender sender, String usedLabel, Location location, String[] args) { public List<String> getTabCompletions(CommandSender sender, String usedLabel, Location location, String[] args) {
return getTabCompletions(sender, location, new ArgumentBuffer(usedLabel, args)); return getTabCompletions(sender, location, new ArgumentBuffer(usedLabel, args));
} }
@Override @Override
public List<String> getTabCompletions(CommandSender sender, Location location, ArgumentBuffer buffer) { public List<String> getTabCompletions(CommandSender sender, Location location, ArgumentBuffer buffer) {
ExecutionContext context = new ExecutionContext(sender, buffer, true); ExecutionContext context = new ExecutionContext(sender, buffer, true);
try { try {
ICommandAddress target = getCommandTarget(context, buffer); ICommandAddress target = getCommandTarget(context, buffer);
List<String> out; List<String> out;
if (target.hasCommand()) { if (target.hasCommand()) {
context.setCommand(target.getCommand()); context.setCommand(target.getCommand());
target.getCommand().initializeAndFilterContext(context); target.getCommand().initializeAndFilterContext(context);
out = target.getCommand().tabComplete(sender, context, location); out = target.getCommand().tabComplete(sender, context, location);
} else { } else {
out = Collections.emptyList(); out = Collections.emptyList();
} }
int cursor = buffer.getCursor(); int cursor = buffer.getCursor();
String input; String input;
if (cursor >= buffer.size()) { if (cursor >= buffer.size()) {
input = ""; input = "";
} else { } else {
input = buffer.get(cursor).toLowerCase(); input = buffer.get(cursor).toLowerCase();
} }
boolean wrapped = false; boolean wrapped = false;
for (String child : target.getChildrenMainKeys()) { for (String child : target.getChildrenMainKeys()) {
if (child.toLowerCase().startsWith(input)) { if (child.toLowerCase().startsWith(input)) {
if (!wrapped) { if (!wrapped) {
out = new ArrayList<>(out); out = new ArrayList<>(out);
wrapped = true; wrapped = true;
} }
out.add(child); out.add(child);
} }
} }
return out; return out;
} catch (CommandException ex) { } catch (CommandException ex) {
return Collections.emptyList(); return Collections.emptyList();
} }
} }
} }

View File

@@ -1,52 +1,52 @@
package io.dico.dicore.command; package io.dico.dicore.command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.Optional; import java.util.Optional;
public class Validate { public class Validate {
private Validate() { private Validate() {
} }
//@Contract("false, _ -> fail") //@Contract("false, _ -> fail")
public static void isTrue(boolean expression, String failMessage) throws CommandException { public static void isTrue(boolean expression, String failMessage) throws CommandException {
if (!expression) { if (!expression) {
throw new CommandException(failMessage); throw new CommandException(failMessage);
} }
} }
//@Contract("null, _ -> fail") //@Contract("null, _ -> fail")
public static void notNull(Object obj, String failMessage) throws CommandException { public static void notNull(Object obj, String failMessage) throws CommandException {
Validate.isTrue(obj != null, failMessage); Validate.isTrue(obj != null, failMessage);
} }
public static void isAuthorized(CommandSender sender, String permission, String failMessage) throws CommandException { public static void isAuthorized(CommandSender sender, String permission, String failMessage) throws CommandException {
Validate.isTrue(sender.hasPermission(permission), failMessage); Validate.isTrue(sender.hasPermission(permission), failMessage);
} }
public static void isAuthorized(CommandSender sender, String permission) throws CommandException { public static void isAuthorized(CommandSender sender, String permission) throws CommandException {
Validate.isAuthorized(sender, permission, "You do not have permission to use that command"); Validate.isAuthorized(sender, permission, "You do not have permission to use that command");
} }
//@Contract("null -> fail") //@Contract("null -> fail")
public static void isPlayer(CommandSender sender) throws CommandException { public static void isPlayer(CommandSender sender) throws CommandException {
isTrue(sender instanceof Player, "That command can only be used by players"); isTrue(sender instanceof Player, "That command can only be used by players");
} }
//@Contract("null -> fail") //@Contract("null -> fail")
public static void isConsole(CommandSender sender) throws CommandException { public static void isConsole(CommandSender sender) throws CommandException {
isTrue(sender instanceof ConsoleCommandSender, "That command can only be used by the console"); isTrue(sender instanceof ConsoleCommandSender, "That command can only be used by the console");
} }
public static <T> T returnIfPresent(Optional<T> maybe, String failMessage) throws CommandException { public static <T> T returnIfPresent(Optional<T> maybe, String failMessage) throws CommandException {
if (!maybe.isPresent()) { if (!maybe.isPresent()) {
throw new CommandException(failMessage); throw new CommandException(failMessage);
} }
return maybe.get(); return maybe.get();
} }
} }

View File

@@ -1,52 +1,52 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import io.dico.dicore.command.parameter.type.ParameterConfig; import io.dico.dicore.command.parameter.type.ParameterConfig;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER) @Target(ElementType.PARAMETER)
public @interface BigRange { public @interface BigRange {
Class<?> MEMORY_CLASS = Memory.class; Class<?> MEMORY_CLASS = Memory.class;
ParameterConfig<BigRange, Memory> CONFIG = ParameterConfig.getMemoryClassFromField(BigRange.class); ParameterConfig<BigRange, Memory> CONFIG = ParameterConfig.getMemoryClassFromField(BigRange.class);
Memory DEFAULT = new Memory("MIN", "MAX", "0"); Memory DEFAULT = new Memory("MIN", "MAX", "0");
String min() default "MIN"; String min() default "MIN";
String max() default "MAX"; String max() default "MAX";
String defaultValue() default "0"; String defaultValue() default "0";
class Memory { class Memory {
private final String min; private final String min;
private final String max; private final String max;
private final String defaultValue; private final String defaultValue;
public Memory(BigRange range) { public Memory(BigRange range) {
this(range.min(), range.max(), range.defaultValue()); this(range.min(), range.max(), range.defaultValue());
} }
public Memory(String min, String max, String defaultValue) { public Memory(String min, String max, String defaultValue) {
this.min = min; this.min = min;
this.max = max; this.max = max;
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
} }
public String min() { public String min() {
return min; return min;
} }
public String max() { public String max() {
return max; return max;
} }
public String defaultValue() { public String defaultValue() {
return defaultValue; return defaultValue;
} }
} }
} }

View File

@@ -1,16 +1,16 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface Cmd { public @interface Cmd {
String value(); String value();
String[] aliases() default {}; String[] aliases() default {};
} }

View File

@@ -1,27 +1,27 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import io.dico.dicore.command.parameter.type.IParameterTypeSelector; import io.dico.dicore.command.parameter.type.IParameterTypeSelector;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Annotation to mark methods that register a parameter type to the localized selector for use in reflective commands. * Annotation to mark methods that register a parameter type to the localized selector for use in reflective commands.
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface CmdParamType { public @interface CmdParamType {
/** /**
* If this flag is set, the type is registered without its annotation type. * If this flag is set, the type is registered without its annotation type.
* As a result, the {@link IParameterTypeSelector} is more likely to select it (faster). * As a result, the {@link IParameterTypeSelector} is more likely to select it (faster).
* This is irrelevant if there is no annotation type or param config. * This is irrelevant if there is no annotation type or param config.
* *
* @return true if this parameter type should be registered without its annotation type too * @return true if this parameter type should be registered without its annotation type too
*/ */
boolean infolessAlias() default false; boolean infolessAlias() default false;
} }

View File

@@ -1,35 +1,35 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
public class CommandAnnotationUtils { public class CommandAnnotationUtils {
/** /**
* Get the short description from a {@link Desc} annotation. * Get the short description from a {@link Desc} annotation.
* If {@link Desc#shortVersion()} is given, returns that. * If {@link Desc#shortVersion()} is given, returns that.
* Otherwise, returns the first element of {@link Desc#value()} * Otherwise, returns the first element of {@link Desc#value()}
* If neither is available, returns null. * If neither is available, returns null.
* *
* @param desc the annotation * @param desc the annotation
* @return the short description * @return the short description
*/ */
public static String getShortDescription(Desc desc) { public static String getShortDescription(Desc desc) {
String descString; String descString;
if (desc == null) { if (desc == null) {
descString = null; descString = null;
} else if (!desc.shortVersion().isEmpty()) { } else if (!desc.shortVersion().isEmpty()) {
descString = desc.shortVersion(); descString = desc.shortVersion();
} else if (desc.value().length > 0) { } else if (desc.value().length > 0) {
descString = desc.value()[0]; descString = desc.value()[0];
if (desc.value().length > 1) { if (desc.value().length > 1) {
//System.out.println("[Command Warning] Multiline descriptions not supported here. Keep it short for: " + targetIdentifier); //System.out.println("[Command Warning] Multiline descriptions not supported here. Keep it short for: " + targetIdentifier);
} }
if (descString != null && descString.isEmpty()) { if (descString != null && descString.isEmpty()) {
descString = null; descString = null;
} }
} else { } else {
descString = null; descString = null;
} }
return descString; return descString;
} }
} }

View File

@@ -1,27 +1,27 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Desc { public @interface Desc {
/** /**
* Multiline description if {@link #shortVersion} is set. * Multiline description if {@link #shortVersion} is set.
* Otherwise, this should be an array with one element (aka, you don't have to add array brackets). * Otherwise, this should be an array with one element (aka, you don't have to add array brackets).
* *
* @return the multiline description. * @return the multiline description.
* @see CommandAnnotationUtils#getShortDescription(Desc) * @see CommandAnnotationUtils#getShortDescription(Desc)
*/ */
String[] value(); String[] value();
/** /**
* Short description, use if {@link #value} is multi-line. * Short description, use if {@link #value} is multi-line.
* To get a short description from a {@link Desc}, you should use {@link CommandAnnotationUtils#getShortDescription(Desc)} * To get a short description from a {@link Desc}, you should use {@link CommandAnnotationUtils#getShortDescription(Desc)}
* *
* @return short description * @return short description
* @see CommandAnnotationUtils#getShortDescription(Desc) * @see CommandAnnotationUtils#getShortDescription(Desc)
*/ */
String shortVersion() default ""; String shortVersion() default "";
} }

View File

@@ -1,16 +1,16 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER) @Target(ElementType.PARAMETER)
public @interface Flag { public @interface Flag {
String value() default ""; String value() default "";
String permission() default ""; String permission() default "";
} }

View File

@@ -1,14 +1,14 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface GenerateCommands { public @interface GenerateCommands {
String[] value() default {"help"}; String[] value() default {"help"};
} }

View File

@@ -1,68 +1,68 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Annotation to define sub-groups of the group registered reflectively from all methods in a class. * Annotation to define sub-groups of the group registered reflectively from all methods in a class.
* <p> * <p>
* Commands are selected for grouping by matching their method's names to a regular expression. * Commands are selected for grouping by matching their method's names to a regular expression.
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
public @interface GroupMatchedCommands { public @interface GroupMatchedCommands {
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@interface GroupEntry { @interface GroupEntry {
/** /**
* Regular expression to match method names for this group * Regular expression to match method names for this group
* Must be non-empty * Must be non-empty
* *
* @return the regular expression * @return the regular expression
*/ */
String regex(); String regex();
/** /**
* The name or main key of the sub-group or address * The name or main key of the sub-group or address
* Must be non-empty * Must be non-empty
* *
* @return the group name * @return the group name
*/ */
String group(); String group();
/** /**
* The aliases for the sub-group * The aliases for the sub-group
* *
* @return the group aliases * @return the group aliases
*/ */
String[] groupAliases() default {}; String[] groupAliases() default {};
/** /**
* Generated (predefined) commands for the sub-group * Generated (predefined) commands for the sub-group
*/ */
String[] generatedCommands() default {}; String[] generatedCommands() default {};
/** /**
* @see Desc * @see Desc
*/ */
String[] description() default {}; String[] description() default {};
/** /**
* @see Desc * @see Desc
*/ */
String shortDescription() default ""; String shortDescription() default "";
} }
/** /**
* The defined groups. * The defined groups.
* If a method name matches the regex of multiple groups, * If a method name matches the regex of multiple groups,
* groups are prioritized by the order in which they appear in this array. * groups are prioritized by the order in which they appear in this array.
* *
* @return the defined groups * @return the defined groups
*/ */
GroupEntry[] value(); GroupEntry[] value();
} }

View File

@@ -1,14 +1,14 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER) @Target(ElementType.PARAMETER)
public @interface NamedArg { public @interface NamedArg {
String value(); String value();
} }

View File

@@ -1,17 +1,17 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
@Deprecated @Deprecated
public @interface PreprocessArgs { public @interface PreprocessArgs {
String tokens() default "\"\""; String tokens() default "\"\"";
char escapeChar() default '\\'; char escapeChar() default '\\';
} }

View File

@@ -1,67 +1,67 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import io.dico.dicore.command.CommandException; import io.dico.dicore.command.CommandException;
import io.dico.dicore.command.Validate; import io.dico.dicore.command.Validate;
import io.dico.dicore.command.parameter.type.ParameterConfig; import io.dico.dicore.command.parameter.type.ParameterConfig;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER) @Target(ElementType.PARAMETER)
public @interface Range { public @interface Range {
Class<?> MEMORY_CLASS = Memory.class; Class<?> MEMORY_CLASS = Memory.class;
ParameterConfig<Range, Memory> CONFIG = ParameterConfig.getMemoryClassFromField(Range.class); ParameterConfig<Range, Memory> CONFIG = ParameterConfig.getMemoryClassFromField(Range.class);
Memory DEFAULT = new Memory(-Double.MAX_VALUE, Double.MAX_VALUE, 0); Memory DEFAULT = new Memory(-Double.MAX_VALUE, Double.MAX_VALUE, 0);
double min() default -Double.MAX_VALUE; double min() default -Double.MAX_VALUE;
double max() default Double.MAX_VALUE; double max() default Double.MAX_VALUE;
double defaultValue() default 0; double defaultValue() default 0;
class Memory { class Memory {
private final double min; private final double min;
private final double max; private final double max;
private final double defaultValue; private final double defaultValue;
public Memory(Range range) { public Memory(Range range) {
this(range.min(), range.max(), range.defaultValue()); this(range.min(), range.max(), range.defaultValue());
} }
public Memory(double min, double max, double defaultValue) { public Memory(double min, double max, double defaultValue) {
this.min = min; this.min = min;
this.max = max; this.max = max;
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
} }
public double min() { public double min() {
return min; return min;
} }
public double max() { public double max() {
return max; return max;
} }
public double defaultValue() { public double defaultValue() {
return defaultValue; return defaultValue;
} }
public void validate(Number x, String failMessage) throws CommandException { public void validate(Number x, String failMessage) throws CommandException {
Validate.isTrue(valid(x), failMessage); Validate.isTrue(valid(x), failMessage);
} }
public boolean valid(Number x) { public boolean valid(Number x) {
double d = x.doubleValue(); double d = x.doubleValue();
return min <= d && d <= max; return min <= d && d <= max;
} }
public boolean isDefault() { public boolean isDefault() {
return this == DEFAULT || (min == DEFAULT.min && max == DEFAULT.max && defaultValue == DEFAULT.defaultValue); return this == DEFAULT || (min == DEFAULT.min && max == DEFAULT.max && defaultValue == DEFAULT.defaultValue);
} }
} }
} }

View File

@@ -1,11 +1,11 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface RequireConsole { public @interface RequireConsole {
} }

View File

@@ -1,14 +1,14 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface RequireParameters { public @interface RequireParameters {
int value(); int value();
} }

View File

@@ -1,33 +1,33 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import io.dico.dicore.command.IContextFilter; import io.dico.dicore.command.IContextFilter;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* If this annotation is not present, inheriting permissions is default. * If this annotation is not present, inheriting permissions is default.
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface RequirePermissions { public @interface RequirePermissions {
/** /**
* Any permissions that must be present on the sender * Any permissions that must be present on the sender
* *
* @return an array of permission nodes * @return an array of permission nodes
*/ */
String[] value(); String[] value();
/** /**
* Whether permissions should (also) be inherited from the parent. * Whether permissions should (also) be inherited from the parent.
* This uses {@link IContextFilter#INHERIT_PERMISSIONS} * This uses {@link IContextFilter#INHERIT_PERMISSIONS}
* This is true by default. * This is true by default.
* *
* @return true if permissions should be inherited. * @return true if permissions should be inherited.
*/ */
boolean inherit() default true; boolean inherit() default true;
} }

View File

@@ -1,11 +1,11 @@
package io.dico.dicore.command.annotation; package io.dico.dicore.command.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface RequirePlayer { public @interface RequirePlayer {
} }

View File

@@ -1,94 +1,94 @@
package io.dico.dicore.command.chat; package io.dico.dicore.command.chat;
import io.dico.dicore.Formatting; import io.dico.dicore.Formatting;
import io.dico.dicore.command.EMessageType; import io.dico.dicore.command.EMessageType;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.command.chat.help.HelpPages; import io.dico.dicore.command.chat.help.HelpPages;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class AbstractChatHandler implements IChatHandler { public class AbstractChatHandler implements IChatHandler {
private @NotNull HelpPages helpPages; private @NotNull HelpPages helpPages;
public AbstractChatHandler(@NotNull HelpPages helpPages) { public AbstractChatHandler(@NotNull HelpPages helpPages) {
this.helpPages = helpPages; this.helpPages = helpPages;
} }
public AbstractChatHandler() { public AbstractChatHandler() {
this(HelpPages.newDefaultHelpPages()); this(HelpPages.newDefaultHelpPages());
} }
@NotNull @NotNull
public HelpPages getHelpPages() { public HelpPages getHelpPages() {
return helpPages; return helpPages;
} }
public void setHelpPages(@NotNull HelpPages helpPages) { public void setHelpPages(@NotNull HelpPages helpPages) {
this.helpPages = helpPages; this.helpPages = helpPages;
} }
@Override @Override
public Formatting getChatFormatForType(EMessageType type) { public Formatting getChatFormatForType(EMessageType type) {
switch (type) { switch (type) {
case EXCEPTION: case EXCEPTION:
case BAD_NEWS: case BAD_NEWS:
return Formatting.RED; return Formatting.RED;
case INSTRUCTION: case INSTRUCTION:
case NEUTRAL: case NEUTRAL:
return Formatting.GRAY; return Formatting.GRAY;
case CUSTOM: case CUSTOM:
return Formatting.WHITE; return Formatting.WHITE;
case INFORMATIVE: case INFORMATIVE:
return Formatting.AQUA; return Formatting.AQUA;
case RESULT: case RESULT:
default: default:
case GOOD_NEWS: case GOOD_NEWS:
return Formatting.GREEN; return Formatting.GREEN;
case WARNING: case WARNING:
return Formatting.YELLOW; return Formatting.YELLOW;
case DESCRIPTION: case DESCRIPTION:
return Formatting.GREEN; return Formatting.GREEN;
case SYNTAX: case SYNTAX:
return Formatting.AQUA; return Formatting.AQUA;
case HIGHLIGHT: case HIGHLIGHT:
return Formatting.RED; return Formatting.RED;
case SUBCOMMAND: case SUBCOMMAND:
return Formatting.GRAY; return Formatting.GRAY;
case NUMBER: case NUMBER:
return Formatting.YELLOW; return Formatting.YELLOW;
} }
} }
@Override @Override
public String getMessagePrefixForType(EMessageType type) { public String getMessagePrefixForType(EMessageType type) {
return ""; return "";
} }
protected String createMessage(EMessageType type, String message) { protected String createMessage(EMessageType type, String message) {
if (message == null || message.isEmpty()) return null; if (message == null || message.isEmpty()) return null;
return getMessagePrefixForType(type) + getChatFormatForType(type) + message; return getMessagePrefixForType(type) + getChatFormatForType(type) + message;
} }
@Override @Override
public String createMessage(ExecutionContext context, EMessageType type, String message) { public String createMessage(ExecutionContext context, EMessageType type, String message) {
return createMessage(type, message); return createMessage(type, message);
} }
@Override @Override
public String createMessage(CommandSender sender, EMessageType type, String message) { public String createMessage(CommandSender sender, EMessageType type, String message) {
return createMessage(type, message); return createMessage(type, message);
} }
@Override @Override
public String createHelpMessage(CommandSender sender, ExecutionContext context, ICommandAddress address, int page) { public String createHelpMessage(CommandSender sender, ExecutionContext context, ICommandAddress address, int page) {
return helpPages.getHelpPage(sender, context, address, page); return helpPages.getHelpPage(sender, context, address, page);
} }
@Override @Override
public String createSyntaxMessage(CommandSender sender, ExecutionContext context, ICommandAddress address) { public String createSyntaxMessage(CommandSender sender, ExecutionContext context, ICommandAddress address) {
return helpPages.getSyntax(sender, context, address); return helpPages.getSyntax(sender, context, address);
} }
} }

View File

@@ -1,20 +1,20 @@
package io.dico.dicore.command.chat; package io.dico.dicore.command.chat;
/** /**
* Static factory methods for {@link IChatHandler} * Static factory methods for {@link IChatHandler}
*/ */
public class ChatHandlers { public class ChatHandlers {
private static final IChatHandler defaultChat; private static final IChatHandler defaultChat;
private ChatHandlers() { private ChatHandlers() {
} }
public static IChatHandler defaultChat() { public static IChatHandler defaultChat() {
return defaultChat; return defaultChat;
} }
static { static {
defaultChat = new AbstractChatHandler(); defaultChat = new AbstractChatHandler();
} }
} }

View File

@@ -1,60 +1,60 @@
package io.dico.dicore.command.chat; package io.dico.dicore.command.chat;
import io.dico.dicore.Formatting; import io.dico.dicore.Formatting;
import io.dico.dicore.command.CommandException; import io.dico.dicore.command.CommandException;
import io.dico.dicore.command.EMessageType; import io.dico.dicore.command.EMessageType;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
//TODO add methods to send JSON messages //TODO add methods to send JSON messages
public interface IChatHandler { public interface IChatHandler {
default void sendMessage(ExecutionContext context, EMessageType type, String message) { default void sendMessage(ExecutionContext context, EMessageType type, String message) {
message = createMessage(context, type, message); message = createMessage(context, type, message);
if (message != null) { if (message != null) {
context.getSender().sendMessage(message); context.getSender().sendMessage(message);
} }
} }
default void sendMessage(CommandSender sender, EMessageType type, String message) { default void sendMessage(CommandSender sender, EMessageType type, String message) {
message = createMessage(sender, type, message); message = createMessage(sender, type, message);
if (message != null) { if (message != null) {
sender.sendMessage(message); sender.sendMessage(message);
} }
} }
default void handleCommandException(CommandSender sender, ExecutionContext context, CommandException exception) { default void handleCommandException(CommandSender sender, ExecutionContext context, CommandException exception) {
sendMessage(context, EMessageType.EXCEPTION, exception.getMessage()); sendMessage(context, EMessageType.EXCEPTION, exception.getMessage());
} }
default void handleException(CommandSender sender, ExecutionContext context, Throwable exception) { default void handleException(CommandSender sender, ExecutionContext context, Throwable exception) {
if (exception instanceof CommandException) { if (exception instanceof CommandException) {
handleCommandException(sender, context, (CommandException) exception); handleCommandException(sender, context, (CommandException) exception);
} else { } else {
sendMessage(sender, EMessageType.EXCEPTION, "An internal error occurred whilst executing this command"); sendMessage(sender, EMessageType.EXCEPTION, "An internal error occurred whilst executing this command");
exception.printStackTrace(); exception.printStackTrace();
} }
} }
default void sendHelpMessage(CommandSender sender, ExecutionContext context, ICommandAddress address, int page) { default void sendHelpMessage(CommandSender sender, ExecutionContext context, ICommandAddress address, int page) {
sender.sendMessage(createHelpMessage(sender, context, address, page)); sender.sendMessage(createHelpMessage(sender, context, address, page));
} }
default void sendSyntaxMessage(CommandSender sender, ExecutionContext context, ICommandAddress address) { default void sendSyntaxMessage(CommandSender sender, ExecutionContext context, ICommandAddress address) {
sender.sendMessage(createSyntaxMessage(sender, context, address)); sender.sendMessage(createSyntaxMessage(sender, context, address));
} }
Formatting getChatFormatForType(EMessageType type); Formatting getChatFormatForType(EMessageType type);
String getMessagePrefixForType(EMessageType type); String getMessagePrefixForType(EMessageType type);
String createMessage(ExecutionContext context, EMessageType type, String message); String createMessage(ExecutionContext context, EMessageType type, String message);
String createMessage(CommandSender sender, EMessageType type, String message); String createMessage(CommandSender sender, EMessageType type, String message);
String createHelpMessage(CommandSender sender, ExecutionContext context, ICommandAddress address, int page); String createHelpMessage(CommandSender sender, ExecutionContext context, ICommandAddress address, int page);
String createSyntaxMessage(CommandSender sender, ExecutionContext context, ICommandAddress address); String createSyntaxMessage(CommandSender sender, ExecutionContext context, ICommandAddress address);
} }

View File

@@ -1,92 +1,92 @@
package io.dico.dicore.command.chat.help; package io.dico.dicore.command.chat.help;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.command.chat.help.defaults.*; import io.dico.dicore.command.chat.help.defaults.*;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
public class HelpPages { public class HelpPages {
private @NotNull IPageBuilder pageBuilder; private @NotNull IPageBuilder pageBuilder;
private @NotNull IPageLayout pageLayout; private @NotNull IPageLayout pageLayout;
private int pageLength; private int pageLength;
private @NotNull List<IHelpTopic> helpTopics; private @NotNull List<IHelpTopic> helpTopics;
private @NotNull IHelpTopic syntaxTopic; private @NotNull IHelpTopic syntaxTopic;
public HelpPages(@NotNull IPageBuilder pageBuilder, @NotNull IPageLayout pageLayout, int pageLength, @NotNull IHelpTopic syntaxTopic, @NotNull List<IHelpTopic> helpTopics) { public HelpPages(@NotNull IPageBuilder pageBuilder, @NotNull IPageLayout pageLayout, int pageLength, @NotNull IHelpTopic syntaxTopic, @NotNull List<IHelpTopic> helpTopics) {
this.pageBuilder = pageBuilder; this.pageBuilder = pageBuilder;
this.pageLayout = pageLayout; this.pageLayout = pageLayout;
this.pageLength = pageLength; this.pageLength = pageLength;
this.syntaxTopic = syntaxTopic; this.syntaxTopic = syntaxTopic;
this.helpTopics = helpTopics; this.helpTopics = helpTopics;
} }
public HelpPages(IPageBuilder pageBuilder, IPageLayout pageLayout, int pageLength, IHelpTopic syntaxTopic, IHelpTopic... helpTopics) { public HelpPages(IPageBuilder pageBuilder, IPageLayout pageLayout, int pageLength, IHelpTopic syntaxTopic, IHelpTopic... helpTopics) {
this(pageBuilder, pageLayout, pageLength, syntaxTopic, new ArrayList<>(Arrays.asList(helpTopics))); this(pageBuilder, pageLayout, pageLength, syntaxTopic, new ArrayList<>(Arrays.asList(helpTopics)));
} }
@SuppressWarnings("RedundantArrayCreation") @SuppressWarnings("RedundantArrayCreation")
public static HelpPages newDefaultHelpPages() { public static HelpPages newDefaultHelpPages() {
IHelpTopic syntaxTopic = new SyntaxHelpTopic(); IHelpTopic syntaxTopic = new SyntaxHelpTopic();
return new HelpPages(new DefaultPageBuilder(), new DefaultPageLayout(), 12, return new HelpPages(new DefaultPageBuilder(), new DefaultPageLayout(), 12,
syntaxTopic, new IHelpTopic[]{new DescriptionHelpTopic(), syntaxTopic, new SubcommandsHelpTopic()}); syntaxTopic, new IHelpTopic[]{new DescriptionHelpTopic(), syntaxTopic, new SubcommandsHelpTopic()});
} }
public @NotNull IPageBuilder getPageBuilder() { public @NotNull IPageBuilder getPageBuilder() {
return pageBuilder; return pageBuilder;
} }
public void setPageBuilder(@NotNull IPageBuilder pageBuilder) { public void setPageBuilder(@NotNull IPageBuilder pageBuilder) {
this.pageBuilder = pageBuilder; this.pageBuilder = pageBuilder;
} }
public @NotNull IPageLayout getPageLayout() { public @NotNull IPageLayout getPageLayout() {
return pageLayout; return pageLayout;
} }
public void setPageLayout(@NotNull IPageLayout pageLayout) { public void setPageLayout(@NotNull IPageLayout pageLayout) {
this.pageLayout = pageLayout; this.pageLayout = pageLayout;
} }
public int getPageLength() { public int getPageLength() {
return pageLength; return pageLength;
} }
public void setPageLength(int pageLength) { public void setPageLength(int pageLength) {
this.pageLength = pageLength; this.pageLength = pageLength;
} }
public @NotNull IHelpTopic getSyntaxTopic() { public @NotNull IHelpTopic getSyntaxTopic() {
return syntaxTopic; return syntaxTopic;
} }
public void setSyntaxTopic(@NotNull IHelpTopic syntaxTopic) { public void setSyntaxTopic(@NotNull IHelpTopic syntaxTopic) {
this.syntaxTopic = syntaxTopic; this.syntaxTopic = syntaxTopic;
} }
@NotNull @NotNull
public List<IHelpTopic> getHelpTopics() { public List<IHelpTopic> getHelpTopics() {
return helpTopics; return helpTopics;
} }
public void setHelpTopics(@NotNull List<IHelpTopic> helpTopics) { public void setHelpTopics(@NotNull List<IHelpTopic> helpTopics) {
this.helpTopics = helpTopics; this.helpTopics = helpTopics;
} }
public @NotNull String getHelpPage(Permissible viewer, ExecutionContext context, ICommandAddress address, int page) { public @NotNull String getHelpPage(Permissible viewer, ExecutionContext context, ICommandAddress address, int page) {
return pageBuilder.getPage(helpTopics, pageLayout, address, viewer, context, page, pageLength); return pageBuilder.getPage(helpTopics, pageLayout, address, viewer, context, page, pageLength);
} }
public @NotNull String getSyntax(Permissible viewer, ExecutionContext context, ICommandAddress address) { public @NotNull String getSyntax(Permissible viewer, ExecutionContext context, ICommandAddress address) {
List<IHelpComponent> components = syntaxTopic.getComponents(address, viewer, context, false); List<IHelpComponent> components = syntaxTopic.getComponents(address, viewer, context, false);
if (components.isEmpty()) { if (components.isEmpty()) {
return getHelpPage(viewer, context, address, 1); return getHelpPage(viewer, context, address, 1);
} }
return DefaultPageBuilder.combine(components); return DefaultPageBuilder.combine(components);
} }
} }

View File

@@ -1,24 +1,24 @@
package io.dico.dicore.command.chat.help; package io.dico.dicore.command.chat.help;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
public abstract class HelpTopicModifier implements IHelpTopic { public abstract class HelpTopicModifier implements IHelpTopic {
private final IHelpTopic delegate; private final IHelpTopic delegate;
public HelpTopicModifier(IHelpTopic delegate) { public HelpTopicModifier(IHelpTopic delegate) {
this.delegate = Objects.requireNonNull(delegate); this.delegate = Objects.requireNonNull(delegate);
} }
@Override @Override
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) { public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) {
return modify(delegate.getComponents(target, viewer, context, true), target, viewer, context); return modify(delegate.getComponents(target, viewer, context, true), target, viewer, context);
} }
protected abstract List<IHelpComponent> modify(List<IHelpComponent> components, ICommandAddress target, Permissible viewer, ExecutionContext context); protected abstract List<IHelpComponent> modify(List<IHelpComponent> components, ICommandAddress target, Permissible viewer, ExecutionContext context);
} }

View File

@@ -1,9 +1,9 @@
package io.dico.dicore.command.chat.help; package io.dico.dicore.command.chat.help;
public interface IHelpComponent { public interface IHelpComponent {
int lineCount(); int lineCount();
void appendTo(StringBuilder sb); void appendTo(StringBuilder sb);
} }

View File

@@ -1,23 +1,23 @@
package io.dico.dicore.command.chat.help; package io.dico.dicore.command.chat.help;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import java.util.List; import java.util.List;
public interface IHelpTopic { public interface IHelpTopic {
/** /**
* Get the components of this help topic * Get the components of this help topic
* *
* @param target The address of the command to provide help about * @param target The address of the command to provide help about
* @param viewer The permissible that the page will be shown to (null -> choose a default set). * @param viewer The permissible that the page will be shown to (null -> choose a default set).
* @param context Context of the command execution * @param context Context of the command execution
* @param isForPage A boolean indicating if the components are to be used in a page (for help) * @param isForPage A boolean indicating if the components are to be used in a page (for help)
* @return a mutable list of components to include in the help pages * @return a mutable list of components to include in the help pages
*/ */
List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage); List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage);
} }

View File

@@ -1,7 +1,7 @@
package io.dico.dicore.command.chat.help; package io.dico.dicore.command.chat.help;
public interface IPageBorder extends IHelpComponent { public interface IPageBorder extends IHelpComponent {
void setPageCount(int pageCount); void setPageCount(int pageCount);
} }

View File

@@ -1,13 +1,13 @@
package io.dico.dicore.command.chat.help; package io.dico.dicore.command.chat.help;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import java.util.List; import java.util.List;
public interface IPageBuilder { public interface IPageBuilder {
String getPage(List<IHelpTopic> helpTopics, IPageLayout pageLayout, ICommandAddress target, Permissible viewer, ExecutionContext context, int pageNum, int pageLen); String getPage(List<IHelpTopic> helpTopics, IPageLayout pageLayout, ICommandAddress target, Permissible viewer, ExecutionContext context, int pageNum, int pageLen);
} }

View File

@@ -1,20 +1,20 @@
package io.dico.dicore.command.chat.help; package io.dico.dicore.command.chat.help;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
public interface IPageLayout { public interface IPageLayout {
/** /**
* Get the page borders for a help page * Get the page borders for a help page
* *
* @param target the address that help is displayed for * @param target the address that help is displayed for
* @param viewer the viewer of the help page, or null if irrelevant * @param viewer the viewer of the help page, or null if irrelevant
* @param context the context of the execution * @param context the context of the execution
* @param pageNum the page number as displayed in the help page (so it's 1-bound and not 0-bound) * @param pageNum the page number as displayed in the help page (so it's 1-bound and not 0-bound)
* @return the page borders. * @return the page borders.
*/ */
PageBorders getPageBorders(ICommandAddress target, Permissible viewer, ExecutionContext context, int pageNum); PageBorders getPageBorders(ICommandAddress target, Permissible viewer, ExecutionContext context, int pageNum);
} }

View File

@@ -1,76 +1,76 @@
package io.dico.dicore.command.chat.help; package io.dico.dicore.command.chat.help;
import java.util.Arrays; import java.util.Arrays;
public class PageBorders { public class PageBorders {
private final IPageBorder header, footer; private final IPageBorder header, footer;
public PageBorders(IPageBorder header, IPageBorder footer) { public PageBorders(IPageBorder header, IPageBorder footer) {
this.header = header; this.header = header;
this.footer = footer; this.footer = footer;
} }
public IPageBorder getHeader() { public IPageBorder getHeader() {
return header; return header;
} }
public IPageBorder getFooter() { public IPageBorder getFooter() {
return footer; return footer;
} }
public static IPageBorder simpleBorder(String... lines) { public static IPageBorder simpleBorder(String... lines) {
return new SimplePageBorder(lines); return new SimplePageBorder(lines);
} }
public static IPageBorder disappearingBorder(int pageNum, String... lines) { public static IPageBorder disappearingBorder(int pageNum, String... lines) {
return disappearingBorder(pageNum, 0, lines); return disappearingBorder(pageNum, 0, lines);
} }
public static IPageBorder disappearingBorder(int pageNum, int keptLines, String... lines) { public static IPageBorder disappearingBorder(int pageNum, int keptLines, String... lines) {
return new DisappearingPageBorder(pageNum, keptLines, lines); return new DisappearingPageBorder(pageNum, keptLines, lines);
} }
static class SimplePageBorder extends SimpleHelpComponent implements IPageBorder { static class SimplePageBorder extends SimpleHelpComponent implements IPageBorder {
private final String replacedSequence; private final String replacedSequence;
public SimplePageBorder(String replacedSequence, String... lines) { public SimplePageBorder(String replacedSequence, String... lines) {
super(lines); super(lines);
this.replacedSequence = replacedSequence; this.replacedSequence = replacedSequence;
} }
public SimplePageBorder(String... lines) { public SimplePageBorder(String... lines) {
super(lines); super(lines);
this.replacedSequence = "%pageCount%"; this.replacedSequence = "%pageCount%";
} }
@Override @Override
public void setPageCount(int pageCount) { public void setPageCount(int pageCount) {
String[] lines = this.lines; String[] lines = this.lines;
for (int i = 0; i < lines.length; i++) { for (int i = 0; i < lines.length; i++) {
lines[i] = lines[i].replace(replacedSequence, Integer.toString(pageCount)); lines[i] = lines[i].replace(replacedSequence, Integer.toString(pageCount));
} }
} }
} }
static class DisappearingPageBorder extends SimpleHelpComponent implements IPageBorder { static class DisappearingPageBorder extends SimpleHelpComponent implements IPageBorder {
private final int pageNum; private final int pageNum;
private final int keptLines; private final int keptLines;
public DisappearingPageBorder(int pageNum, int keptLines, String... lines) { public DisappearingPageBorder(int pageNum, int keptLines, String... lines) {
super(lines); super(lines);
this.pageNum = pageNum; this.pageNum = pageNum;
this.keptLines = keptLines; this.keptLines = keptLines;
} }
@Override @Override
public void setPageCount(int pageCount) { public void setPageCount(int pageCount) {
if (pageCount == pageNum) { if (pageCount == pageNum) {
String[] lines = this.lines; String[] lines = this.lines;
this.lines = Arrays.copyOfRange(lines, Math.max(0, lines.length - keptLines), lines.length); this.lines = Arrays.copyOfRange(lines, Math.max(0, lines.length - keptLines), lines.length);
} }
} }
} }
} }

View File

@@ -1,27 +1,27 @@
package io.dico.dicore.command.chat.help; package io.dico.dicore.command.chat.help;
public class SimpleHelpComponent implements IHelpComponent { public class SimpleHelpComponent implements IHelpComponent {
String[] lines; String[] lines;
public SimpleHelpComponent(String... lines) { public SimpleHelpComponent(String... lines) {
this.lines = lines; this.lines = lines;
} }
@Override @Override
public int lineCount() { public int lineCount() {
return lines.length; return lines.length;
} }
@Override @Override
public void appendTo(StringBuilder sb) { public void appendTo(StringBuilder sb) {
String[] lines = this.lines; String[] lines = this.lines;
int len = lines.length; int len = lines.length;
if (0 < len) { if (0 < len) {
sb.append(lines[0]); sb.append(lines[0]);
} }
for (int i = 1; i < len; i++) { for (int i = 1; i < len; i++) {
sb.append('\n').append(lines[i]); sb.append('\n').append(lines[i]);
} }
} }
} }

View File

@@ -1,115 +1,115 @@
package io.dico.dicore.command.chat.help.defaults; package io.dico.dicore.command.chat.help.defaults;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.command.chat.help.*; import io.dico.dicore.command.chat.help.*;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
public class DefaultPageBuilder implements IPageBuilder { public class DefaultPageBuilder implements IPageBuilder {
@Override @Override
public String getPage(List<IHelpTopic> helpTopics, IPageLayout pageLayout, ICommandAddress target, public String getPage(List<IHelpTopic> helpTopics, IPageLayout pageLayout, ICommandAddress target,
Permissible viewer, ExecutionContext context, int pageNum, int pageLen) { Permissible viewer, ExecutionContext context, int pageNum, int pageLen) {
if (pageLen <= 0 || pageNum < 0) { if (pageLen <= 0 || pageNum < 0) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
List<IHelpComponent> components = new LinkedList<>(); List<IHelpComponent> components = new LinkedList<>();
for (IHelpTopic topic : helpTopics) { for (IHelpTopic topic : helpTopics) {
components.addAll(topic.getComponents(target, viewer, context, true)); components.addAll(topic.getComponents(target, viewer, context, true));
} }
PageBorders pageBorders = null; PageBorders pageBorders = null;
int componentStartIdx = -1; int componentStartIdx = -1;
int componentEndIdx = -1; int componentEndIdx = -1;
int totalPageCount = 0; int totalPageCount = 0;
int curPageLines = 0; int curPageLines = 0;
ListIterator<IHelpComponent> iterator = components.listIterator(); ListIterator<IHelpComponent> iterator = components.listIterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
if (curPageLines == 0) { if (curPageLines == 0) {
if (pageBorders != null) { if (pageBorders != null) {
iterator.add(pageBorders.getFooter()); iterator.add(pageBorders.getFooter());
} }
if (pageNum == totalPageCount) { if (pageNum == totalPageCount) {
componentStartIdx = iterator.nextIndex(); componentStartIdx = iterator.nextIndex();
} else if (pageNum + 1 == totalPageCount) { } else if (pageNum + 1 == totalPageCount) {
componentEndIdx = iterator.nextIndex(); componentEndIdx = iterator.nextIndex();
} }
pageBorders = pageLayout.getPageBorders(target, viewer, context, totalPageCount + 1); pageBorders = pageLayout.getPageBorders(target, viewer, context, totalPageCount + 1);
if (pageBorders != null) { if (pageBorders != null) {
iterator.add(pageBorders.getHeader()); iterator.add(pageBorders.getHeader());
iterator.previous(); iterator.previous();
curPageLines += pageBorders.getFooter().lineCount(); curPageLines += pageBorders.getFooter().lineCount();
} }
totalPageCount++; totalPageCount++;
} }
IHelpComponent component = iterator.next(); IHelpComponent component = iterator.next();
int lineCount = component.lineCount(); int lineCount = component.lineCount();
curPageLines += lineCount; curPageLines += lineCount;
if (curPageLines >= pageLen) { if (curPageLines >= pageLen) {
curPageLines = 0; curPageLines = 0;
} }
} }
if (componentStartIdx == -1) { if (componentStartIdx == -1) {
// page does not exist // page does not exist
return ""; return "";
} }
if (componentEndIdx == -1) { if (componentEndIdx == -1) {
componentEndIdx = components.size(); componentEndIdx = components.size();
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
iterator = components.listIterator(componentStartIdx); iterator = components.listIterator(componentStartIdx);
int count = componentEndIdx - componentStartIdx; int count = componentEndIdx - componentStartIdx;
boolean first = true; boolean first = true;
while (count-- > 0) { while (count-- > 0) {
IHelpComponent component = iterator.next(); IHelpComponent component = iterator.next();
if (component instanceof IPageBorder) { if (component instanceof IPageBorder) {
((IPageBorder) component).setPageCount(totalPageCount); ((IPageBorder) component).setPageCount(totalPageCount);
} }
if (first) { if (first) {
first = false; first = false;
} else { } else {
sb.append('\n'); sb.append('\n');
} }
component.appendTo(sb); component.appendTo(sb);
} }
return sb.toString(); return sb.toString();
} }
public static String combine(List<IHelpComponent> components) { public static String combine(List<IHelpComponent> components) {
StringBuilder rv = new StringBuilder(); StringBuilder rv = new StringBuilder();
Iterator<IHelpComponent> iterator = components.iterator(); Iterator<IHelpComponent> iterator = components.iterator();
if (iterator.hasNext()) { if (iterator.hasNext()) {
iterator.next().appendTo(rv); iterator.next().appendTo(rv);
} }
while (iterator.hasNext()) { while (iterator.hasNext()) {
rv.append('\n'); rv.append('\n');
iterator.next().appendTo(rv); iterator.next().appendTo(rv);
} }
return rv.toString(); return rv.toString();
} }
} }

View File

@@ -1,40 +1,40 @@
package io.dico.dicore.command.chat.help.defaults; package io.dico.dicore.command.chat.help.defaults;
import io.dico.dicore.command.EMessageType; import io.dico.dicore.command.EMessageType;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.command.ModifiableCommandAddress; import io.dico.dicore.command.ModifiableCommandAddress;
import io.dico.dicore.Formatting; import io.dico.dicore.Formatting;
import io.dico.dicore.command.chat.IChatHandler; import io.dico.dicore.command.chat.IChatHandler;
import io.dico.dicore.command.chat.help.IPageBorder; import io.dico.dicore.command.chat.help.IPageBorder;
import io.dico.dicore.command.chat.help.IPageLayout; import io.dico.dicore.command.chat.help.IPageLayout;
import io.dico.dicore.command.chat.help.PageBorders; import io.dico.dicore.command.chat.help.PageBorders;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
public class DefaultPageLayout implements IPageLayout { public class DefaultPageLayout implements IPageLayout {
@Override @Override
public PageBorders getPageBorders(ICommandAddress target, Permissible viewer, ExecutionContext context, int pageNum) { public PageBorders getPageBorders(ICommandAddress target, Permissible viewer, ExecutionContext context, int pageNum) {
IChatHandler c = context.getAddress().getChatHandler(); IChatHandler c = context.getAddress().getChatHandler();
String prefix = c.getMessagePrefixForType(EMessageType.INFORMATIVE); String prefix = c.getMessagePrefixForType(EMessageType.INFORMATIVE);
Formatting informative = c.getChatFormatForType(EMessageType.INFORMATIVE); Formatting informative = c.getChatFormatForType(EMessageType.INFORMATIVE);
Formatting number = c.getChatFormatForType(EMessageType.NEUTRAL); Formatting number = c.getChatFormatForType(EMessageType.NEUTRAL);
String nextPageCommand; String nextPageCommand;
ICommandAddress executor = context.getAddress(); ICommandAddress executor = context.getAddress();
if (((ModifiableCommandAddress) executor).hasHelpCommand()) { if (((ModifiableCommandAddress) executor).hasHelpCommand()) {
nextPageCommand = ((ModifiableCommandAddress) executor).getHelpCommand().getAddress() + ' ' + (pageNum + 1); nextPageCommand = ((ModifiableCommandAddress) executor).getHelpCommand().getAddress() + ' ' + (pageNum + 1);
} else { } else {
nextPageCommand = executor.getAddress() + ' ' + (pageNum + 1); nextPageCommand = executor.getAddress() + ' ' + (pageNum + 1);
} }
String header = prefix + informative + "Help page " + number + pageNum + informative + String header = prefix + informative + "Help page " + number + pageNum + informative +
'/' + number + "%pageCount%" + informative + " for /" + target.getAddress(); '/' + number + "%pageCount%" + informative + " for /" + target.getAddress();
String footer = informative + "Type /" + nextPageCommand + " for the next page"; String footer = informative + "Type /" + nextPageCommand + " for the next page";
IPageBorder headerBorder = PageBorders.simpleBorder("", header); IPageBorder headerBorder = PageBorders.simpleBorder("", header);
IPageBorder footerBorder = PageBorders.disappearingBorder(pageNum, footer); IPageBorder footerBorder = PageBorders.disappearingBorder(pageNum, footer);
return new PageBorders(headerBorder, footerBorder); return new PageBorders(headerBorder, footerBorder);
} }
} }

View File

@@ -1,45 +1,45 @@
package io.dico.dicore.command.chat.help.defaults; package io.dico.dicore.command.chat.help.defaults;
import io.dico.dicore.command.Command; import io.dico.dicore.command.Command;
import io.dico.dicore.command.EMessageType; import io.dico.dicore.command.EMessageType;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.Formatting; import io.dico.dicore.Formatting;
import io.dico.dicore.command.chat.help.IHelpComponent; import io.dico.dicore.command.chat.help.IHelpComponent;
import io.dico.dicore.command.chat.help.IHelpTopic; import io.dico.dicore.command.chat.help.IHelpTopic;
import io.dico.dicore.command.chat.help.SimpleHelpComponent; import io.dico.dicore.command.chat.help.SimpleHelpComponent;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class DescriptionHelpTopic implements IHelpTopic { public class DescriptionHelpTopic implements IHelpTopic {
@Override @Override
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) { public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) {
List<IHelpComponent> out = new ArrayList<>(); List<IHelpComponent> out = new ArrayList<>();
Formatting format = context.getFormat(EMessageType.DESCRIPTION); Formatting format = context.getFormat(EMessageType.DESCRIPTION);
if (!target.hasCommand()) { if (!target.hasCommand()) {
return out; return out;
} }
Command command = target.getCommand(); Command command = target.getCommand();
String[] description = command.getDescription(); String[] description = command.getDescription();
if (description.length == 0) { if (description.length == 0) {
String shortDescription = command.getShortDescription(); String shortDescription = command.getShortDescription();
if (shortDescription == null) { if (shortDescription == null) {
return out; return out;
} }
description = new String[]{shortDescription}; description = new String[]{shortDescription};
} }
for (int i = 0; i < description.length; i++) { for (int i = 0; i < description.length; i++) {
description[i] = format + description[i]; description[i] = format + description[i];
} }
out.add(new SimpleHelpComponent(description)); out.add(new SimpleHelpComponent(description));
return out; return out;
} }
} }

View File

@@ -1,59 +1,59 @@
package io.dico.dicore.command.chat.help.defaults; package io.dico.dicore.command.chat.help.defaults;
import io.dico.dicore.command.EMessageType; import io.dico.dicore.command.EMessageType;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.Formatting; import io.dico.dicore.Formatting;
import io.dico.dicore.command.chat.help.IHelpComponent; import io.dico.dicore.command.chat.help.IHelpComponent;
import io.dico.dicore.command.chat.help.IHelpTopic; import io.dico.dicore.command.chat.help.IHelpTopic;
import io.dico.dicore.command.chat.help.SimpleHelpComponent; import io.dico.dicore.command.chat.help.SimpleHelpComponent;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import java.util.*; import java.util.*;
public class SubcommandsHelpTopic implements IHelpTopic { public class SubcommandsHelpTopic implements IHelpTopic {
@Override @Override
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) { public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) {
Collection<String> mainKeys = target.getChildrenMainKeys(); Collection<String> mainKeys = target.getChildrenMainKeys();
if (mainKeys.isEmpty()) { if (mainKeys.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<IHelpComponent> result = new ArrayList<>(); List<IHelpComponent> result = new ArrayList<>();
mainKeys = new ArrayList<>(target.getChildrenMainKeys()); mainKeys = new ArrayList<>(target.getChildrenMainKeys());
((ArrayList<String>) mainKeys).sort(null); ((ArrayList<String>) mainKeys).sort(null);
CommandSender sender = viewer instanceof CommandSender ? (CommandSender) viewer : context.getSender(); CommandSender sender = viewer instanceof CommandSender ? (CommandSender) viewer : context.getSender();
for (String key : mainKeys) { for (String key : mainKeys) {
ICommandAddress child = target.getChild(key); ICommandAddress child = target.getChild(key);
if ((child.hasChildren() || child.hasUserDeclaredCommand()) && child.getCommand().isVisibleTo(sender)) { if ((child.hasChildren() || child.hasUserDeclaredCommand()) && child.getCommand().isVisibleTo(sender)) {
result.add(getComponent(child, viewer, context)); result.add(getComponent(child, viewer, context));
} }
} }
return result; return result;
} }
public IHelpComponent getComponent(ICommandAddress child, Permissible viewer, ExecutionContext context) { public IHelpComponent getComponent(ICommandAddress child, Permissible viewer, ExecutionContext context) {
Formatting subcommand = colorOf(context, EMessageType.SUBCOMMAND); Formatting subcommand = colorOf(context, EMessageType.SUBCOMMAND);
Formatting highlight = colorOf(context, EMessageType.HIGHLIGHT); Formatting highlight = colorOf(context, EMessageType.HIGHLIGHT);
String address = subcommand + "/" + child.getParent().getAddress() + ' ' + highlight + child.getMainKey(); String address = subcommand + "/" + child.getParent().getAddress() + ' ' + highlight + child.getMainKey();
String description = child.hasCommand() ? child.getCommand().getShortDescription() : null; String description = child.hasCommand() ? child.getCommand().getShortDescription() : null;
if (description != null) { if (description != null) {
Formatting descriptionFormat = colorOf(context, EMessageType.DESCRIPTION); Formatting descriptionFormat = colorOf(context, EMessageType.DESCRIPTION);
return new SimpleHelpComponent(address, descriptionFormat + description); return new SimpleHelpComponent(address, descriptionFormat + description);
} }
return new SimpleHelpComponent(address); return new SimpleHelpComponent(address);
} }
private static Formatting colorOf(ExecutionContext context, EMessageType type) { private static Formatting colorOf(ExecutionContext context, EMessageType type) {
return context.getAddress().getChatHandler().getChatFormatForType(type); return context.getAddress().getChatHandler().getChatFormatForType(type);
} }
} }

View File

@@ -1,92 +1,92 @@
package io.dico.dicore.command.chat.help.defaults; package io.dico.dicore.command.chat.help.defaults;
import io.dico.dicore.command.Command; import io.dico.dicore.command.Command;
import io.dico.dicore.command.EMessageType; import io.dico.dicore.command.EMessageType;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.Formatting; import io.dico.dicore.Formatting;
import io.dico.dicore.command.chat.help.IHelpComponent; import io.dico.dicore.command.chat.help.IHelpComponent;
import io.dico.dicore.command.chat.help.IHelpTopic; import io.dico.dicore.command.chat.help.IHelpTopic;
import io.dico.dicore.command.chat.help.SimpleHelpComponent; import io.dico.dicore.command.chat.help.SimpleHelpComponent;
import io.dico.dicore.command.parameter.Parameter; import io.dico.dicore.command.parameter.Parameter;
import io.dico.dicore.command.parameter.ParameterList; import io.dico.dicore.command.parameter.ParameterList;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class SyntaxHelpTopic implements IHelpTopic { public class SyntaxHelpTopic implements IHelpTopic {
@Override @Override
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) { public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) {
if (!target.hasCommand()) { if (!target.hasCommand()) {
return Collections.emptyList(); return Collections.emptyList();
} }
if (target.hasChildren()) { if (target.hasChildren()) {
if (!isForPage) { if (!isForPage) {
// HelpPages will send help instead of syntax, which might in turn include syntax as well. // HelpPages will send help instead of syntax, which might in turn include syntax as well.
return Collections.emptyList(); return Collections.emptyList();
} }
if (!target.hasUserDeclaredCommand() && !target.getCommand().getParameterList().hasAnyParameters()) { if (!target.hasUserDeclaredCommand() && !target.getCommand().getParameterList().hasAnyParameters()) {
// no point adding syntax at all // no point adding syntax at all
return Collections.emptyList(); return Collections.emptyList();
} }
} }
StringBuilder line = new StringBuilder(); StringBuilder line = new StringBuilder();
if (isForPage) if (isForPage)
line.append(context.getFormat(EMessageType.SYNTAX)) line.append(context.getFormat(EMessageType.SYNTAX))
.append("Syntax: "); .append("Syntax: ");
line.append('/') line.append('/')
.append(context.getFormat(EMessageType.INSTRUCTION)) .append(context.getFormat(EMessageType.INSTRUCTION))
.append(target.getAddress()) .append(target.getAddress())
.append(' '); .append(' ');
addShortSyntax(line, target, context); addShortSyntax(line, target, context);
return Collections.singletonList(new SimpleHelpComponent(line.toString())); return Collections.singletonList(new SimpleHelpComponent(line.toString()));
} }
private static void addShortSyntax(StringBuilder builder, ICommandAddress address, ExecutionContext ctx) { private static void addShortSyntax(StringBuilder builder, ICommandAddress address, ExecutionContext ctx) {
if (address.hasCommand()) { if (address.hasCommand()) {
Formatting syntaxColor = ctx.getFormat(EMessageType.SYNTAX); Formatting syntaxColor = ctx.getFormat(EMessageType.SYNTAX);
Formatting highlight = ctx.getFormat(EMessageType.HIGHLIGHT); Formatting highlight = ctx.getFormat(EMessageType.HIGHLIGHT);
builder.append(syntaxColor); builder.append(syntaxColor);
Command command = address.getCommand(); Command command = address.getCommand();
ParameterList list = command.getParameterList(); ParameterList list = command.getParameterList();
Parameter<?, ?> repeated = list.getRepeatedParameter(); Parameter<?, ?> repeated = list.getRepeatedParameter();
int requiredCount = list.getRequiredCount(); int requiredCount = list.getRequiredCount();
List<Parameter<?, ?>> indexedParameters = list.getIndexedParameters(); List<Parameter<?, ?>> indexedParameters = list.getIndexedParameters();
for (int i = 0, n = indexedParameters.size(); i < n; i++) { for (int i = 0, n = indexedParameters.size(); i < n; i++) {
builder.append(i < requiredCount ? " <" : " ["); builder.append(i < requiredCount ? " <" : " [");
Parameter<?, ?> param = indexedParameters.get(i); Parameter<?, ?> param = indexedParameters.get(i);
builder.append(param.getName()); builder.append(param.getName());
if (param == repeated) { if (param == repeated) {
builder.append(highlight).append("...").append(syntaxColor); builder.append(highlight).append("...").append(syntaxColor);
} }
builder.append(i < requiredCount ? '>' : ']'); builder.append(i < requiredCount ? '>' : ']');
} }
Map<String, Parameter<?, ?>> parametersByName = list.getParametersByName(); Map<String, Parameter<?, ?>> parametersByName = list.getParametersByName();
for (Parameter<?, ?> param : parametersByName.values()) { for (Parameter<?, ?> param : parametersByName.values()) {
if (param.isFlag()) { if (param.isFlag()) {
builder.append(" [").append(param.getName()); builder.append(" [").append(param.getName());
if (param.expectsInput()) { if (param.expectsInput()) {
builder.append(" <").append(param.getName()).append(">"); builder.append(" <").append(param.getName()).append(">");
} }
builder.append(']'); builder.append(']');
} }
} }
} else { } else {
builder.append(' '); builder.append(' ');
} }
} }
} }

View File

@@ -1,29 +1,29 @@
package io.dico.dicore.command.chat.help.insertion; package io.dico.dicore.command.chat.help.insertion;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.command.chat.help.IHelpComponent; import io.dico.dicore.command.chat.help.IHelpComponent;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import java.util.List; import java.util.List;
public enum EInsertionStage implements IInsertionFunction { public enum EInsertionStage implements IInsertionFunction {
START { START {
@Override @Override
public int insertionIndex(List<IHelpComponent> current, ICommandAddress target, Permissible viewer, ExecutionContext context) { public int insertionIndex(List<IHelpComponent> current, ICommandAddress target, Permissible viewer, ExecutionContext context) {
return 0; return 0;
} }
}, },
CENTER { CENTER {
@Override @Override
public int insertionIndex(List<IHelpComponent> current, ICommandAddress target, Permissible viewer, ExecutionContext context) { public int insertionIndex(List<IHelpComponent> current, ICommandAddress target, Permissible viewer, ExecutionContext context) {
return current.size() / 2; return current.size() / 2;
} }
}, },
END { END {
@Override @Override
public int insertionIndex(List<IHelpComponent> current, ICommandAddress target, Permissible viewer, ExecutionContext context) { public int insertionIndex(List<IHelpComponent> current, ICommandAddress target, Permissible viewer, ExecutionContext context) {
return current.size(); return current.size();
} }
} }
} }

View File

@@ -1,43 +1,43 @@
package io.dico.dicore.command.chat.help.insertion; package io.dico.dicore.command.chat.help.insertion;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.command.chat.help.HelpTopicModifier; import io.dico.dicore.command.chat.help.HelpTopicModifier;
import io.dico.dicore.command.chat.help.IHelpComponent; import io.dico.dicore.command.chat.help.IHelpComponent;
import io.dico.dicore.command.chat.help.IHelpTopic; import io.dico.dicore.command.chat.help.IHelpTopic;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class HelpComponentInserter extends HelpTopicModifier { public class HelpComponentInserter extends HelpTopicModifier {
private List<IInsertion> insertions = new ArrayList<>(); private List<IInsertion> insertions = new ArrayList<>();
public HelpComponentInserter(IHelpTopic delegate) { public HelpComponentInserter(IHelpTopic delegate) {
super(delegate); super(delegate);
} }
@Override @Override
protected List<IHelpComponent> modify(List<IHelpComponent> components, ICommandAddress target, Permissible viewer, ExecutionContext context) { protected List<IHelpComponent> modify(List<IHelpComponent> components, ICommandAddress target, Permissible viewer, ExecutionContext context) {
// int componentCount = components.size(); // int componentCount = components.size();
for (int i = insertions.size() - 1; i >= 0; i--) { for (int i = insertions.size() - 1; i >= 0; i--) {
IInsertion insertion = insertions.get(i); IInsertion insertion = insertions.get(i);
int idx = insertion.insertionIndex(components, target, viewer, context); int idx = insertion.insertionIndex(components, target, viewer, context);
List<IHelpComponent> inserted = insertion.getComponents(target, viewer, context, true); List<IHelpComponent> inserted = insertion.getComponents(target, viewer, context, true);
components.addAll(idx, inserted); components.addAll(idx, inserted);
} }
return components; return components;
} }
public HelpComponentInserter insert(IInsertionFunction insertionFunction, IHelpTopic helpTopic) { public HelpComponentInserter insert(IInsertionFunction insertionFunction, IHelpTopic helpTopic) {
return insert(Insertions.combine(helpTopic, insertionFunction)); return insert(Insertions.combine(helpTopic, insertionFunction));
} }
public HelpComponentInserter insert(IInsertion insertion) { public HelpComponentInserter insert(IInsertion insertion) {
insertions.add(insertion); insertions.add(insertion);
return this; return this;
} }
} }

View File

@@ -1,7 +1,7 @@
package io.dico.dicore.command.chat.help.insertion; package io.dico.dicore.command.chat.help.insertion;
import io.dico.dicore.command.chat.help.IHelpTopic; import io.dico.dicore.command.chat.help.IHelpTopic;
interface IInsertion extends IHelpTopic, IInsertionFunction { interface IInsertion extends IHelpTopic, IInsertionFunction {
} }

View File

@@ -1,14 +1,14 @@
package io.dico.dicore.command.chat.help.insertion; package io.dico.dicore.command.chat.help.insertion;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.command.chat.help.IHelpComponent; import io.dico.dicore.command.chat.help.IHelpComponent;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import java.util.List; import java.util.List;
public interface IInsertionFunction { public interface IInsertionFunction {
int insertionIndex(List<IHelpComponent> current, ICommandAddress target, Permissible viewer, ExecutionContext context); int insertionIndex(List<IHelpComponent> current, ICommandAddress target, Permissible viewer, ExecutionContext context);
} }

View File

@@ -1,31 +1,31 @@
package io.dico.dicore.command.chat.help.insertion; package io.dico.dicore.command.chat.help.insertion;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.command.chat.help.IHelpComponent; import io.dico.dicore.command.chat.help.IHelpComponent;
import io.dico.dicore.command.chat.help.IHelpTopic; import io.dico.dicore.command.chat.help.IHelpTopic;
import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permissible;
import java.util.List; import java.util.List;
public class Insertions { public class Insertions {
private Insertions() { private Insertions() {
} }
public static IInsertion combine(IHelpTopic topic, IInsertionFunction function) { public static IInsertion combine(IHelpTopic topic, IInsertionFunction function) {
return new IInsertion() { return new IInsertion() {
@Override @Override
public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) { public List<IHelpComponent> getComponents(ICommandAddress target, Permissible viewer, ExecutionContext context, boolean isForPage) {
return topic.getComponents(target, viewer, context, true); return topic.getComponents(target, viewer, context, true);
} }
@Override @Override
public int insertionIndex(List<IHelpComponent> current, ICommandAddress target, Permissible viewer, ExecutionContext context) { public int insertionIndex(List<IHelpComponent> current, ICommandAddress target, Permissible viewer, ExecutionContext context) {
return function.insertionIndex(current, target, viewer, context); return function.insertionIndex(current, target, viewer, context);
} }
}; };
} }
} }

View File

@@ -1,295 +1,295 @@
package io.dico.dicore.command.parameter; package io.dico.dicore.command.parameter;
import io.dico.dicore.command.CommandException; import io.dico.dicore.command.CommandException;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
/** /**
* Buffer for the arguments. * Buffer for the arguments.
* Easy to traverse for the parser. * Easy to traverse for the parser.
*/ */
public class ArgumentBuffer extends AbstractList<String> implements Iterator<String>, RandomAccess { public class ArgumentBuffer extends AbstractList<String> implements Iterator<String>, RandomAccess {
private String[] array; private String[] array;
private int cursor = 0; // index of the next return value private int cursor = 0; // index of the next return value
private transient ArgumentBuffer unaffectingCopy = null; // see #getUnaffectingCopy() private transient ArgumentBuffer unaffectingCopy = null; // see #getUnaffectingCopy()
public ArgumentBuffer(String label, String[] args) { public ArgumentBuffer(String label, String[] args) {
this(combine(label, args)); this(combine(label, args));
} }
private static String[] combine(String label, String[] args) { private static String[] combine(String label, String[] args) {
String[] result; String[] result;
//if (args.length > 0 && "".equals(args[args.length - 1])) { //if (args.length > 0 && "".equals(args[args.length - 1])) {
// // drop the last element of args if it is empty // // drop the last element of args if it is empty
// result = args; // result = args;
//} else { //} else {
result = new String[args.length + 1]; result = new String[args.length + 1];
//} //}
System.arraycopy(args, 0, result, 1, result.length - 1); System.arraycopy(args, 0, result, 1, result.length - 1);
result[0] = Objects.requireNonNull(label); result[0] = Objects.requireNonNull(label);
return result; return result;
} }
/** /**
* Constructs a new ArgumentBuffer using the given array, without copying it first. * Constructs a new ArgumentBuffer using the given array, without copying it first.
* None of the array its elements should be empty. * None of the array its elements should be empty.
* *
* @param array the array * @param array the array
* @throws NullPointerException if the array or any of its elements are null * @throws NullPointerException if the array or any of its elements are null
*/ */
public ArgumentBuffer(String[] array) { public ArgumentBuffer(String[] array) {
for (String elem : array) { for (String elem : array) {
if (elem == null) throw new NullPointerException("ArgumentBuffer array element"); if (elem == null) throw new NullPointerException("ArgumentBuffer array element");
} }
this.array = array; this.array = array;
} }
public int getCursor() { public int getCursor() {
return cursor; return cursor;
} }
public @NotNull ArgumentBuffer setCursor(int cursor) { public @NotNull ArgumentBuffer setCursor(int cursor) {
if (cursor <= 0) { if (cursor <= 0) {
cursor = 0; cursor = 0;
} else if (size() <= cursor) { } else if (size() <= cursor) {
cursor = size(); cursor = size();
} }
this.cursor = cursor; this.cursor = cursor;
return this; return this;
} }
@Override @Override
public int size() { public int size() {
return array.length; return array.length;
} }
@Override @Override
public @NotNull String get(int index) { public @NotNull String get(int index) {
return array[index]; return array[index];
} }
public int nextIndex() { public int nextIndex() {
return cursor; return cursor;
} }
public int previousIndex() { public int previousIndex() {
return cursor - 1; return cursor - 1;
} }
public int remainingElements() { public int remainingElements() {
return size() - nextIndex() - 1; return size() - nextIndex() - 1;
} }
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return nextIndex() < size(); return nextIndex() < size();
} }
public boolean hasPrevious() { public boolean hasPrevious() {
return 0 <= previousIndex(); return 0 <= previousIndex();
} }
/** /**
* Unlike conventional ListIterator implementations, this returns null if there is no next element * Unlike conventional ListIterator implementations, this returns null if there is no next element
* *
* @return the next value, or null * @return the next value, or null
*/ */
@Override @Override
public @Nullable String next() { public @Nullable String next() {
return hasNext() ? get(cursor++) : null; return hasNext() ? get(cursor++) : null;
} }
public @NotNull String requireNext(String parameterName) throws CommandException { public @NotNull String requireNext(String parameterName) throws CommandException {
String next = next(); String next = next();
if (next == null) { if (next == null) {
throw CommandException.missingArgument(parameterName); throw CommandException.missingArgument(parameterName);
} }
return next; return next;
} }
// useful for completion code // useful for completion code
public @NotNull String nextOrEmpty() { public @NotNull String nextOrEmpty() {
return hasNext() ? get(cursor++) : ""; return hasNext() ? get(cursor++) : "";
} }
/** /**
* Unlike conventional ListIterator implementations, this returns null if there is no previous element * Unlike conventional ListIterator implementations, this returns null if there is no previous element
* *
* @return the previous value, or null * @return the previous value, or null
*/ */
public @Nullable String previous() { public @Nullable String previous() {
return hasPrevious() ? get(--cursor) : null; return hasPrevious() ? get(--cursor) : null;
} }
public @Nullable String peekNext() { public @Nullable String peekNext() {
return hasNext() ? get(cursor) : null; return hasNext() ? get(cursor) : null;
} }
public @Nullable String peekPrevious() { public @Nullable String peekPrevious() {
return hasPrevious() ? get(cursor - 1) : null; return hasPrevious() ? get(cursor - 1) : null;
} }
public @NotNull ArgumentBuffer advance() { public @NotNull ArgumentBuffer advance() {
return advance(1); return advance(1);
} }
public @NotNull ArgumentBuffer advance(int amount) { public @NotNull ArgumentBuffer advance(int amount) {
cursor = Math.min(Math.max(0, cursor + amount), size()); cursor = Math.min(Math.max(0, cursor + amount), size());
return this; return this;
} }
public @NotNull ArgumentBuffer rewind() { public @NotNull ArgumentBuffer rewind() {
return rewind(1); return rewind(1);
} }
public @NotNull ArgumentBuffer rewind(int amount) { public @NotNull ArgumentBuffer rewind(int amount) {
return advance(-amount); return advance(-amount);
} }
@NotNull String[] getArray() { @NotNull String[] getArray() {
return array; return array;
} }
public @NotNull String[] getArrayFromCursor() { public @NotNull String[] getArrayFromCursor() {
return getArrayFromIndex(cursor); return getArrayFromIndex(cursor);
} }
public @NotNull String[] getArrayFromIndex(int index) { public @NotNull String[] getArrayFromIndex(int index) {
return Arrays.copyOfRange(array, index, array.length); return Arrays.copyOfRange(array, index, array.length);
} }
public @NotNull String getRawInput() { public @NotNull String getRawInput() {
return String.join(" ", array); return String.join(" ", array);
} }
public @NotNull String[] toArray() { public @NotNull String[] toArray() {
return array.clone(); return array.clone();
} }
@Override @Override
public @NotNull Iterator<String> iterator() { public @NotNull Iterator<String> iterator() {
return this; return this;
} }
@Override @Override
public @NotNull ListIterator<String> listIterator() { public @NotNull ListIterator<String> listIterator() {
return new ListIterator<String>() { return new ListIterator<String>() {
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return ArgumentBuffer.this.hasNext(); return ArgumentBuffer.this.hasNext();
} }
@Override @Override
public String next() { public String next() {
if (!hasNext()) { if (!hasNext()) {
throw new NoSuchElementException(); throw new NoSuchElementException();
} }
return ArgumentBuffer.this.next(); return ArgumentBuffer.this.next();
} }
@Override @Override
public boolean hasPrevious() { public boolean hasPrevious() {
return ArgumentBuffer.this.hasPrevious(); return ArgumentBuffer.this.hasPrevious();
} }
@Override @Override
public String previous() { public String previous() {
if (!hasPrevious()) { if (!hasPrevious()) {
throw new NoSuchElementException(); throw new NoSuchElementException();
} }
return ArgumentBuffer.this.previous(); return ArgumentBuffer.this.previous();
} }
@Override @Override
public int nextIndex() { public int nextIndex() {
return ArgumentBuffer.this.nextIndex(); return ArgumentBuffer.this.nextIndex();
} }
@Override @Override
public int previousIndex() { public int previousIndex() {
return ArgumentBuffer.this.previousIndex(); return ArgumentBuffer.this.previousIndex();
} }
@Override @Override
public void remove() { public void remove() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void set(String s) { public void set(String s) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void add(String s) { public void add(String s) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
}; };
} }
public void dropTrailingEmptyElements() { public void dropTrailingEmptyElements() {
int removeCount = 0; int removeCount = 0;
String[] array = this.array; String[] array = this.array;
for (int i = array.length - 1; i >= 0; i--) { for (int i = array.length - 1; i >= 0; i--) {
if ("".equals(array[i])) { if ("".equals(array[i])) {
removeCount++; removeCount++;
} }
} }
if (removeCount > 0) { if (removeCount > 0) {
String[] newArray = new String[array.length - removeCount]; String[] newArray = new String[array.length - removeCount];
System.arraycopy(array, 0, newArray, 0, newArray.length); System.arraycopy(array, 0, newArray, 0, newArray.length);
this.array = newArray; this.array = newArray;
if (cursor > newArray.length) { if (cursor > newArray.length) {
cursor = newArray.length; cursor = newArray.length;
} }
} }
} }
/** /**
* Preprocess this argument buffer with the given preprocessor * Preprocess this argument buffer with the given preprocessor
* *
* @param preProcessor preprocessor * @param preProcessor preprocessor
* @return a new ArgumentBuffer with processed contents. Might be this buffer if nothing changed. * @return a new ArgumentBuffer with processed contents. Might be this buffer if nothing changed.
*/ */
public @NotNull ArgumentBuffer preprocessArguments(IArgumentPreProcessor preProcessor) { public @NotNull ArgumentBuffer preprocessArguments(IArgumentPreProcessor preProcessor) {
return preProcessor.process(this, -1); return preProcessor.process(this, -1);
} }
/** /**
* Allows a piece of code to traverse this buffer without modifying its cursor. * Allows a piece of code to traverse this buffer without modifying its cursor.
* After this method has been called for the first time on this instance, if this method * After this method has been called for the first time on this instance, if this method
* or the {@link #clone()} method are called, the operation carried out on the prior result has finished. * or the {@link #clone()} method are called, the operation carried out on the prior result has finished.
* As such, the same instance might be returned again. * As such, the same instance might be returned again.
* *
* @return A view of this buffer that doesn't affect this buffer's cursor. * @return A view of this buffer that doesn't affect this buffer's cursor.
*/ */
public ArgumentBuffer getUnaffectingCopy() { public ArgumentBuffer getUnaffectingCopy() {
// the copy doesn't alter the cursor of this ArgumentBuffer when moved, but traverses the same array reference. // the copy doesn't alter the cursor of this ArgumentBuffer when moved, but traverses the same array reference.
// there is only ever one copy of an ArgumentBuffer, the cursor of which is updated on every call to this method. // there is only ever one copy of an ArgumentBuffer, the cursor of which is updated on every call to this method.
ArgumentBuffer unaffectingCopy = this.unaffectingCopy; ArgumentBuffer unaffectingCopy = this.unaffectingCopy;
if (unaffectingCopy == null) { if (unaffectingCopy == null) {
this.unaffectingCopy = unaffectingCopy = new ArgumentBuffer(array); this.unaffectingCopy = unaffectingCopy = new ArgumentBuffer(array);
} }
unaffectingCopy.cursor = this.cursor; unaffectingCopy.cursor = this.cursor;
return unaffectingCopy; return unaffectingCopy;
} }
@SuppressWarnings("MethodDoesntCallSuperMethod") @SuppressWarnings("MethodDoesntCallSuperMethod")
public @NotNull ArgumentBuffer clone() { public @NotNull ArgumentBuffer clone() {
ArgumentBuffer result = getUnaffectingCopy(); ArgumentBuffer result = getUnaffectingCopy();
this.unaffectingCopy = null; this.unaffectingCopy = null;
return result; return result;
} }
@Override @Override
public String toString() { public String toString() {
return String.format("ArgumentBuffer(size = %d, cursor = %d)", size(), getCursor()); return String.format("ArgumentBuffer(size = %d, cursor = %d)", size(), getCursor());
} }
} }

View File

@@ -1,177 +1,177 @@
package io.dico.dicore.command.parameter; package io.dico.dicore.command.parameter;
public class ArgumentMergingPreProcessor implements IArgumentPreProcessor { public class ArgumentMergingPreProcessor implements IArgumentPreProcessor {
private final String tokens; private final String tokens;
private final char escapeChar; private final char escapeChar;
public ArgumentMergingPreProcessor(String tokens, char escapeChar) { public ArgumentMergingPreProcessor(String tokens, char escapeChar) {
if ((tokens.length() & 1) != 0 || tokens.isEmpty()) throw new IllegalArgumentException(); if ((tokens.length() & 1) != 0 || tokens.isEmpty()) throw new IllegalArgumentException();
this.tokens = tokens; this.tokens = tokens;
this.escapeChar = escapeChar; this.escapeChar = escapeChar;
} }
@Override @Override
public ArgumentBuffer process(ArgumentBuffer buffer, int count) { public ArgumentBuffer process(ArgumentBuffer buffer, int count) {
Parser parser = new Parser(buffer.getArray().clone(), buffer.getCursor(), count); Parser parser = new Parser(buffer.getArray().clone(), buffer.getCursor(), count);
String[] array = parser.doProcess(); String[] array = parser.doProcess();
ArgumentBuffer result = new ArgumentBuffer(array); ArgumentBuffer result = new ArgumentBuffer(array);
parser.updateBuffer(result); parser.updateBuffer(result);
return result; return result;
} }
private class Parser { private class Parser {
private final String[] args; private final String[] args;
private final int start; private final int start;
private final int count; private final int count;
private int foundSectionCount; private int foundSectionCount;
private int currentIndex; private int currentIndex;
private int sectionStart; private int sectionStart;
private char closingToken; private char closingToken;
private int sectionEnd; private int sectionEnd;
private int removeCount; private int removeCount;
Parser(String[] args, int start, int count) { Parser(String[] args, int start, int count) {
this.start = start; this.start = start;
this.args = args; this.args = args;
this.count = count; this.count = count;
} }
private void reset() { private void reset() {
foundSectionCount = 0; foundSectionCount = 0;
currentIndex = start; currentIndex = start;
sectionStart = -1; sectionStart = -1;
closingToken = 0; closingToken = 0;
sectionEnd = -1; sectionEnd = -1;
removeCount = 0; removeCount = 0;
} }
private boolean findNextSectionStart() { private boolean findNextSectionStart() {
if (count >= 0 && foundSectionCount >= count) return false; if (count >= 0 && foundSectionCount >= count) return false;
while (currentIndex < args.length) { while (currentIndex < args.length) {
String arg = args[currentIndex]; String arg = args[currentIndex];
if (arg == null) { if (arg == null) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
if (arg.isEmpty()) { if (arg.isEmpty()) {
++currentIndex; ++currentIndex;
continue; continue;
} }
int openingTokenIndex = tokens.indexOf(arg.charAt(0)); int openingTokenIndex = tokens.indexOf(arg.charAt(0));
if (openingTokenIndex == -1 || (openingTokenIndex & 1) != 0) { if (openingTokenIndex == -1 || (openingTokenIndex & 1) != 0) {
++currentIndex; ++currentIndex;
continue; continue;
} }
// found // found
closingToken = tokens.charAt(openingTokenIndex | 1); closingToken = tokens.charAt(openingTokenIndex | 1);
sectionStart = currentIndex; sectionStart = currentIndex;
return true; return true;
} }
return false; return false;
} }
private boolean findNextSectionEnd() { private boolean findNextSectionEnd() {
while (currentIndex < args.length) { while (currentIndex < args.length) {
String arg = args[currentIndex]; String arg = args[currentIndex];
if (arg == null) { if (arg == null) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
if (arg.isEmpty() if (arg.isEmpty()
|| arg.charAt(arg.length() - 1) != closingToken || arg.charAt(arg.length() - 1) != closingToken
|| (sectionStart == currentIndex && arg.length() == 1)) { || (sectionStart == currentIndex && arg.length() == 1)) {
++currentIndex; ++currentIndex;
continue; continue;
} }
if (escapeChar != 0 if (escapeChar != 0
&& arg.length() > 1 && arg.length() > 1
&& arg.charAt(arg.length() - 2) == escapeChar) { && arg.charAt(arg.length() - 2) == escapeChar) {
// escaped // escaped
++currentIndex; ++currentIndex;
continue; continue;
} }
// found // found
closingToken = 0; closingToken = 0;
sectionEnd = currentIndex; sectionEnd = currentIndex;
++currentIndex; ++currentIndex;
return true; return true;
} }
return false; return false;
} }
private void processFoundSection() { private void processFoundSection() {
if (sectionStart == sectionEnd) { if (sectionStart == sectionEnd) {
String arg = args[sectionStart]; String arg = args[sectionStart];
args[sectionStart] = arg.substring(1, arg.length() - 1); args[sectionStart] = arg.substring(1, arg.length() - 1);
return; return;
} }
removeCount += sectionEnd - sectionStart; removeCount += sectionEnd - sectionStart;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(args[sectionStart].substring(1)); sb.append(args[sectionStart].substring(1));
for (int i = sectionStart + 1; i < sectionEnd; i++) { for (int i = sectionStart + 1; i < sectionEnd; i++) {
sb.append(' '); sb.append(' ');
sb.append(args[i]); sb.append(args[i]);
args[i] = null; args[i] = null;
} }
sb.append(' '); sb.append(' ');
sb.append(args[sectionEnd].substring(0, args[sectionEnd].length() - 1)); sb.append(args[sectionEnd].substring(0, args[sectionEnd].length() - 1));
args[sectionEnd] = null; args[sectionEnd] = null;
args[sectionStart] = sb.toString(); args[sectionStart] = sb.toString();
sectionStart = -1; sectionStart = -1;
sectionEnd = -1; sectionEnd = -1;
++foundSectionCount; ++foundSectionCount;
} }
String[] doProcess() { String[] doProcess() {
reset(); reset();
while (findNextSectionStart()) { while (findNextSectionStart()) {
if (findNextSectionEnd()) { if (findNextSectionEnd()) {
processFoundSection(); processFoundSection();
} else { } else {
currentIndex = sectionStart + 1; currentIndex = sectionStart + 1;
} }
} }
if (removeCount == 0) { if (removeCount == 0) {
return args; return args;
} }
String[] result = new String[args.length - removeCount]; String[] result = new String[args.length - removeCount];
int i = 0; int i = 0;
for (String arg : args) { for (String arg : args) {
if (arg != null) { if (arg != null) {
result[i++] = arg; result[i++] = arg;
} }
} }
return result; return result;
} }
void updateBuffer(ArgumentBuffer buffer) { void updateBuffer(ArgumentBuffer buffer) {
if (count < 0) { if (count < 0) {
buffer.setCursor(start); buffer.setCursor(start);
} else { } else {
buffer.setCursor(currentIndex); buffer.setCursor(currentIndex);
} }
} }
} }
} }

View File

@@ -1,276 +1,276 @@
package io.dico.dicore.command.parameter; package io.dico.dicore.command.parameter;
import io.dico.dicore.command.CommandException; import io.dico.dicore.command.CommandException;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.util.*; import java.util.*;
public class ContextParser { public class ContextParser {
private final ExecutionContext m_context; private final ExecutionContext m_context;
private final ArgumentBuffer m_buffer; private final ArgumentBuffer m_buffer;
private final ParameterList m_paramList; private final ParameterList m_paramList;
private final Parameter<?, ?> m_repeatedParam; private final Parameter<?, ?> m_repeatedParam;
private final List<Parameter<?, ?>> m_indexedParams; private final List<Parameter<?, ?>> m_indexedParams;
private final int m_maxIndex; private final int m_maxIndex;
private final int m_maxRequiredIndex; private final int m_maxRequiredIndex;
private Map<String, Object> m_valueMap; private Map<String, Object> m_valueMap;
private Set<String> m_parsedKeys; private Set<String> m_parsedKeys;
private int m_completionCursor = -1; private int m_completionCursor = -1;
private Parameter<?, ?> m_completionTarget = null; private Parameter<?, ?> m_completionTarget = null;
public ContextParser(ExecutionContext context, public ContextParser(ExecutionContext context,
ParameterList parameterList, ParameterList parameterList,
Map<String, Object> valueMap, Map<String, Object> valueMap,
Set<String> keySet) { Set<String> keySet) {
m_context = context; m_context = context;
m_paramList = parameterList; m_paramList = parameterList;
m_valueMap = valueMap; m_valueMap = valueMap;
m_parsedKeys = keySet; m_parsedKeys = keySet;
m_buffer = context.getBuffer(); m_buffer = context.getBuffer();
m_repeatedParam = m_paramList.getRepeatedParameter(); m_repeatedParam = m_paramList.getRepeatedParameter();
m_indexedParams = m_paramList.getIndexedParameters(); m_indexedParams = m_paramList.getIndexedParameters();
m_maxIndex = m_indexedParams.size() - 1; m_maxIndex = m_indexedParams.size() - 1;
m_maxRequiredIndex = m_paramList.getRequiredCount() - 1; m_maxRequiredIndex = m_paramList.getRequiredCount() - 1;
} }
public ExecutionContext getContext() { public ExecutionContext getContext() {
return m_context; return m_context;
} }
public Map<String, Object> getValueMap() { public Map<String, Object> getValueMap() {
return m_valueMap; return m_valueMap;
} }
public Set<String> getParsedKeys() { public Set<String> getParsedKeys() {
return m_parsedKeys; return m_parsedKeys;
} }
public void parse() throws CommandException { public void parse() throws CommandException {
parseAllParameters(); parseAllParameters();
} }
public int getCompletionCursor() { public int getCompletionCursor() {
if (!m_done) { if (!m_done) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
return m_completionCursor; return m_completionCursor;
} }
public Parameter<?, ?> getCompletionTarget() { public Parameter<?, ?> getCompletionTarget() {
if (!m_done) { if (!m_done) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
return m_completionTarget; return m_completionTarget;
} }
// ################################ // ################################
// # PARSING METHODS # // # PARSING METHODS #
// ################################ // ################################
private boolean m_repeating = false; private boolean m_repeating = false;
private boolean m_done = false; private boolean m_done = false;
private int m_curParamIndex = -1; private int m_curParamIndex = -1;
private Parameter<?, ?> m_curParam = null; private Parameter<?, ?> m_curParam = null;
private List<Object> m_curRepeatingList = null; private List<Object> m_curRepeatingList = null;
private void parseAllParameters() throws CommandException { private void parseAllParameters() throws CommandException {
try { try {
do { do {
prepareStateToParseParam(); prepareStateToParseParam();
if (m_done) break; if (m_done) break;
parseCurParam(); parseCurParam();
} while (!m_done); } while (!m_done);
} finally { } finally {
m_curParam = null; m_curParam = null;
m_curRepeatingList = null; m_curRepeatingList = null;
assignDefaultValuesToUncomputedParams(); assignDefaultValuesToUncomputedParams();
arrayifyRepeatedParamValue(); arrayifyRepeatedParamValue();
} }
} }
private void prepareStateToParseParam() throws CommandException { private void prepareStateToParseParam() throws CommandException {
boolean requireInput; boolean requireInput;
if (identifyFlag()) { if (identifyFlag()) {
m_buffer.advance(); m_buffer.advance();
prepareRepeatedParameterIfSet(); prepareRepeatedParameterIfSet();
requireInput = false; requireInput = false;
} else if (m_repeating) { } else if (m_repeating) {
m_curParam = m_repeatedParam; m_curParam = m_repeatedParam;
requireInput = false; requireInput = false;
} else if (m_curParamIndex < m_maxIndex) { } else if (m_curParamIndex < m_maxIndex) {
m_curParamIndex++; m_curParamIndex++;
m_curParam = m_indexedParams.get(m_curParamIndex); m_curParam = m_indexedParams.get(m_curParamIndex);
prepareRepeatedParameterIfSet(); prepareRepeatedParameterIfSet();
requireInput = m_curParamIndex <= m_maxRequiredIndex; requireInput = m_curParamIndex <= m_maxRequiredIndex;
} else if (m_buffer.hasNext()) { } else if (m_buffer.hasNext()) {
throw new CommandException("Too many arguments for /" + m_context.getAddress().getAddress()); throw new CommandException("Too many arguments for /" + m_context.getAddress().getAddress());
} else { } else {
m_done = true; m_done = true;
return; return;
} }
if (!m_buffer.hasNext()) { if (!m_buffer.hasNext()) {
if (requireInput) { if (requireInput) {
reportParameterRequired(m_curParam); reportParameterRequired(m_curParam);
} }
if (m_repeating) { if (m_repeating) {
m_done = true; m_done = true;
} }
} }
} }
private boolean identifyFlag() { private boolean identifyFlag() {
String potentialFlag = m_buffer.peekNext(); String potentialFlag = m_buffer.peekNext();
Parameter<?, ?> target; Parameter<?, ?> target;
if (potentialFlag != null if (potentialFlag != null
&& potentialFlag.startsWith("-") && potentialFlag.startsWith("-")
&& (target = m_paramList.getParameterByName(potentialFlag)) != null && (target = m_paramList.getParameterByName(potentialFlag)) != null
&& target.isFlag() && target.isFlag()
&& !m_valueMap.containsKey(potentialFlag) && !m_valueMap.containsKey(potentialFlag)
// Disabled because it's checked by {@link Parameter#parse(ExecutionContext, ArgumentBuffer)} // Disabled because it's checked by {@link Parameter#parse(ExecutionContext, ArgumentBuffer)}
// && (target.getFlagPermission() == null || m_context.getSender().hasPermission(target.getFlagPermission())) // && (target.getFlagPermission() == null || m_context.getSender().hasPermission(target.getFlagPermission()))
) { ) {
m_curParam = target; m_curParam = target;
return true; return true;
} }
return false; return false;
} }
private void prepareRepeatedParameterIfSet() throws CommandException { private void prepareRepeatedParameterIfSet() throws CommandException {
if (m_curParam != null && m_curParam == m_repeatedParam) { if (m_curParam != null && m_curParam == m_repeatedParam) {
if (m_curParam.isFlag() && m_curParamIndex < m_maxRequiredIndex) { if (m_curParam.isFlag() && m_curParamIndex < m_maxRequiredIndex) {
Parameter<?, ?> requiredParam = m_indexedParams.get(m_curParamIndex + 1); Parameter<?, ?> requiredParam = m_indexedParams.get(m_curParamIndex + 1);
reportParameterRequired(requiredParam); reportParameterRequired(requiredParam);
} }
m_curRepeatingList = new ArrayList<>(); m_curRepeatingList = new ArrayList<>();
assignValue(m_curRepeatingList); assignValue(m_curRepeatingList);
m_repeating = true; m_repeating = true;
} }
} }
private void reportParameterRequired(Parameter<?, ?> param) throws CommandException { private void reportParameterRequired(Parameter<?, ?> param) throws CommandException {
throw new CommandException("The argument '" + param.getName() + "' is required"); throw new CommandException("The argument '" + param.getName() + "' is required");
} }
private void parseCurParam() throws CommandException { private void parseCurParam() throws CommandException {
if (!m_buffer.hasNext() && !m_curParam.isFlag()) { if (!m_buffer.hasNext() && !m_curParam.isFlag()) {
assignDefaultValue(); assignDefaultValue();
return; return;
} }
int cursorStart = m_buffer.getCursor(); int cursorStart = m_buffer.getCursor();
if (m_context.isTabComplete() && "".equals(m_buffer.peekNext())) { if (m_context.isTabComplete() && "".equals(m_buffer.peekNext())) {
assignAsCompletionTarget(cursorStart); assignAsCompletionTarget(cursorStart);
return; return;
} }
Object parseResult; Object parseResult;
try { try {
parseResult = m_curParam.parse(m_context, m_buffer); parseResult = m_curParam.parse(m_context, m_buffer);
} catch (CommandException e) { } catch (CommandException e) {
assignAsCompletionTarget(cursorStart); assignAsCompletionTarget(cursorStart);
throw e; throw e;
} }
assignValue(parseResult); assignValue(parseResult);
m_parsedKeys.add(m_curParam.getName()); m_parsedKeys.add(m_curParam.getName());
} }
private void assignDefaultValue() throws CommandException { private void assignDefaultValue() throws CommandException {
assignValue(m_curParam.getDefaultValue(m_context, m_buffer)); assignValue(m_curParam.getDefaultValue(m_context, m_buffer));
} }
private void assignAsCompletionTarget(int cursor) { private void assignAsCompletionTarget(int cursor) {
m_completionCursor = cursor; m_completionCursor = cursor;
m_completionTarget = m_curParam; m_completionTarget = m_curParam;
m_done = true; m_done = true;
} }
private void assignValue(Object value) { private void assignValue(Object value) {
if (m_repeating) { if (m_repeating) {
m_curRepeatingList.add(value); m_curRepeatingList.add(value);
} else { } else {
m_valueMap.put(m_curParam.getName(), value); m_valueMap.put(m_curParam.getName(), value);
} }
} }
private void assignDefaultValuesToUncomputedParams() throws CommandException { private void assignDefaultValuesToUncomputedParams() throws CommandException {
// add default values for unset parameters // add default values for unset parameters
for (Map.Entry<String, Parameter<?, ?>> entry : m_paramList.getParametersByName().entrySet()) { for (Map.Entry<String, Parameter<?, ?>> entry : m_paramList.getParametersByName().entrySet()) {
String name = entry.getKey(); String name = entry.getKey();
if (!m_valueMap.containsKey(name)) { if (!m_valueMap.containsKey(name)) {
if (m_repeatedParam == entry.getValue()) { if (m_repeatedParam == entry.getValue()) {
// below value will be turned into an array later // below value will be turned into an array later
m_valueMap.put(name, Collections.emptyList()); m_valueMap.put(name, Collections.emptyList());
} else { } else {
m_valueMap.put(name, entry.getValue().getDefaultValue(m_context, m_buffer)); m_valueMap.put(name, entry.getValue().getDefaultValue(m_context, m_buffer));
} }
} }
} }
} }
private void arrayifyRepeatedParamValue() { private void arrayifyRepeatedParamValue() {
if (m_repeatedParam != null) { if (m_repeatedParam != null) {
m_valueMap.computeIfPresent(m_repeatedParam.getName(), (k, v) -> { m_valueMap.computeIfPresent(m_repeatedParam.getName(), (k, v) -> {
List list = (List) v; List list = (List) v;
Class<?> returnType = m_repeatedParam.getType().getReturnType(); Class<?> returnType = m_repeatedParam.getType().getReturnType();
Object array = Array.newInstance(returnType, list.size()); Object array = Array.newInstance(returnType, list.size());
ArraySetter setter = ArraySetter.getSetter(returnType); ArraySetter setter = ArraySetter.getSetter(returnType);
for (int i = 0, n = list.size(); i < n; i++) { for (int i = 0, n = list.size(); i < n; i++) {
setter.set(array, i, list.get(i)); setter.set(array, i, list.get(i));
} }
return array; return array;
}); });
} }
} }
private interface ArraySetter { private interface ArraySetter {
void set(Object array, int index, Object value); void set(Object array, int index, Object value);
static ArraySetter getSetter(Class<?> clazz) { static ArraySetter getSetter(Class<?> clazz) {
if (!clazz.isPrimitive()) { if (!clazz.isPrimitive()) {
return (array, index, value) -> ((Object[]) array)[index] = value; return (array, index, value) -> ((Object[]) array)[index] = value;
} }
switch (clazz.getSimpleName()) { switch (clazz.getSimpleName()) {
case "boolean": case "boolean":
return (array, index, value) -> ((boolean[]) array)[index] = (boolean) value; return (array, index, value) -> ((boolean[]) array)[index] = (boolean) value;
case "int": case "int":
return (array, index, value) -> ((int[]) array)[index] = (int) value; return (array, index, value) -> ((int[]) array)[index] = (int) value;
case "double": case "double":
return (array, index, value) -> ((double[]) array)[index] = (double) value; return (array, index, value) -> ((double[]) array)[index] = (double) value;
case "long": case "long":
return (array, index, value) -> ((long[]) array)[index] = (long) value; return (array, index, value) -> ((long[]) array)[index] = (long) value;
case "short": case "short":
return (array, index, value) -> ((short[]) array)[index] = (short) value; return (array, index, value) -> ((short[]) array)[index] = (short) value;
case "byte": case "byte":
return (array, index, value) -> ((byte[]) array)[index] = (byte) value; return (array, index, value) -> ((byte[]) array)[index] = (byte) value;
case "float": case "float":
return (array, index, value) -> ((float[]) array)[index] = (float) value; return (array, index, value) -> ((float[]) array)[index] = (float) value;
case "char": case "char":
return (array, index, value) -> ((char[]) array)[index] = (char) value; return (array, index, value) -> ((char[]) array)[index] = (char) value;
case "void": case "void":
default: default:
throw new InternalError("This should not happen"); throw new InternalError("This should not happen");
} }
} }
} }
} }

View File

@@ -1,41 +1,41 @@
package io.dico.dicore.command.parameter; package io.dico.dicore.command.parameter;
/** /**
* An interface to process tokens such as quotes * An interface to process tokens such as quotes
*/ */
@Deprecated @Deprecated
public interface IArgumentPreProcessor { public interface IArgumentPreProcessor {
/** /**
* Preprocess the arguments contained within the given ArgumentBuffer. * Preprocess the arguments contained within the given ArgumentBuffer.
* If no changes are made, this might return the same buffer. * If no changes are made, this might return the same buffer.
* Any arguments preceding {@code buffer.getCursor()} will not be affected. * Any arguments preceding {@code buffer.getCursor()} will not be affected.
* *
* <p> * <p>
* If {@code count} is non-negative, it declares a limit on the number of arguments after preprocessing. * If {@code count} is non-negative, it declares a limit on the number of arguments after preprocessing.
* In that case, the buffer's cursor is set to the index of the first argument following processed arguments. * In that case, the buffer's cursor is set to the index of the first argument following processed arguments.
* </p> * </p>
* *
* @param buffer the argument buffer * @param buffer the argument buffer
* @param count the maximum number of (processed) arguments * @param count the maximum number of (processed) arguments
* @return the arguments after preprocessing * @return the arguments after preprocessing
*/ */
ArgumentBuffer process(ArgumentBuffer buffer, int count); ArgumentBuffer process(ArgumentBuffer buffer, int count);
IArgumentPreProcessor NONE = (buffer, count) -> buffer; IArgumentPreProcessor NONE = (buffer, count) -> buffer;
/** /**
* Get an IArgumentPreProcessor that merges arguments between any two tokens * Get an IArgumentPreProcessor that merges arguments between any two tokens
* *
* @param tokens The tokens that the merged arguments should be enclosed by, in subsequent pairs. * @param tokens The tokens that the merged arguments should be enclosed by, in subsequent pairs.
* Example: []{}"" * Example: []{}""
* This would mean the following would be merged: [ hello this is a merged argument] * This would mean the following would be merged: [ hello this is a merged argument]
* @param escapeChar the char that can be used to escape the given tokens * @param escapeChar the char that can be used to escape the given tokens
* @return The IArgumentPreProcessor * @return The IArgumentPreProcessor
*/ */
static IArgumentPreProcessor mergeOnTokens(String tokens, char escapeChar) { static IArgumentPreProcessor mergeOnTokens(String tokens, char escapeChar) {
return new ArgumentMergingPreProcessor(tokens, escapeChar); return new ArgumentMergingPreProcessor(tokens, escapeChar);
} }
} }

View File

@@ -1,148 +1,148 @@
package io.dico.dicore.command.parameter; package io.dico.dicore.command.parameter;
import java.util.*; import java.util.*;
/** /**
* IParameter definition for a command * IParameter definition for a command
*/ */
@SuppressWarnings("UnusedReturnValue") @SuppressWarnings("UnusedReturnValue")
public class ParameterList { public class ParameterList {
//private ParameterList parent; //private ParameterList parent;
private List<Parameter<?, ?>> indexedParameters; private List<Parameter<?, ?>> indexedParameters;
private Map<String, Parameter<?, ?>> byName; private Map<String, Parameter<?, ?>> byName;
//private IArgumentPreProcessor argumentPreProcessor = IArgumentPreProcessor.NONE; //private IArgumentPreProcessor argumentPreProcessor = IArgumentPreProcessor.NONE;
private int requiredCount = -1; private int requiredCount = -1;
private boolean repeatFinalParameter; private boolean repeatFinalParameter;
// if the final parameter is repeated and the command is implemented through reflection, // if the final parameter is repeated and the command is implemented through reflection,
// the repeated parameter is simply the last parameter of the method, rather than the last // the repeated parameter is simply the last parameter of the method, rather than the last
// indexed parameter. This might be a flag. As such, this field exists to ensure the correct // indexed parameter. This might be a flag. As such, this field exists to ensure the correct
// parameter is taken for repeating // parameter is taken for repeating
private boolean finalParameterMayBeFlag; private boolean finalParameterMayBeFlag;
/* /*
public ParameterList(ParameterList parent) { public ParameterList(ParameterList parent) {
this(); this();
if (parent.repeatFinalParameter) { if (parent.repeatFinalParameter) {
throw new IllegalArgumentException("Parent may not have repeating parameters"); throw new IllegalArgumentException("Parent may not have repeating parameters");
} }
this.parent = parent; this.parent = parent;
}*/ }*/
public ParameterList() { public ParameterList() {
this.indexedParameters = new ArrayList<>(); this.indexedParameters = new ArrayList<>();
this.byName = new LinkedHashMap<>(); this.byName = new LinkedHashMap<>();
this.repeatFinalParameter = false; this.repeatFinalParameter = false;
} }
/* /*
public IArgumentPreProcessor getArgumentPreProcessor() { public IArgumentPreProcessor getArgumentPreProcessor() {
return argumentPreProcessor; return argumentPreProcessor;
} }
public ParameterList setArgumentPreProcessor(IArgumentPreProcessor argumentPreProcessor) { public ParameterList setArgumentPreProcessor(IArgumentPreProcessor argumentPreProcessor) {
this.argumentPreProcessor = argumentPreProcessor == null ? IArgumentPreProcessor.NONE : argumentPreProcessor; this.argumentPreProcessor = argumentPreProcessor == null ? IArgumentPreProcessor.NONE : argumentPreProcessor;
return this; return this;
}*/ }*/
public boolean repeatFinalParameter() { public boolean repeatFinalParameter() {
return repeatFinalParameter; return repeatFinalParameter;
} }
public ParameterList setRepeatFinalParameter(boolean repeatFinalParameter) { public ParameterList setRepeatFinalParameter(boolean repeatFinalParameter) {
this.repeatFinalParameter = repeatFinalParameter; this.repeatFinalParameter = repeatFinalParameter;
return this; return this;
} }
public boolean finalParameterMayBeFlag() { public boolean finalParameterMayBeFlag() {
return finalParameterMayBeFlag; return finalParameterMayBeFlag;
} }
public ParameterList setFinalParameterMayBeFlag(boolean finalParameterMayBeFlag) { public ParameterList setFinalParameterMayBeFlag(boolean finalParameterMayBeFlag) {
this.finalParameterMayBeFlag = finalParameterMayBeFlag; this.finalParameterMayBeFlag = finalParameterMayBeFlag;
return this; return this;
} }
public int getRequiredCount() { public int getRequiredCount() {
return requiredCount == -1 ? indexedParameters.size() : requiredCount; return requiredCount == -1 ? indexedParameters.size() : requiredCount;
} }
public ParameterList setRequiredCount(int requiredCount) { public ParameterList setRequiredCount(int requiredCount) {
this.requiredCount = requiredCount; this.requiredCount = requiredCount;
return this; return this;
} }
public boolean hasAnyParameters() { public boolean hasAnyParameters() {
return !byName.isEmpty(); return !byName.isEmpty();
} }
public int getIndexedParameterCount() { public int getIndexedParameterCount() {
return indexedParameters.size(); return indexedParameters.size();
} }
public List<Parameter<?, ?>> getIndexedParameters() { public List<Parameter<?, ?>> getIndexedParameters() {
return Collections.unmodifiableList(indexedParameters); return Collections.unmodifiableList(indexedParameters);
} }
public Parameter<?, ?> getParameterByName(String name) { public Parameter<?, ?> getParameterByName(String name) {
return byName.get(name); return byName.get(name);
} }
public String getIndexedParameterName(int index) { public String getIndexedParameterName(int index) {
return indexedParameters.get(index).getName(); return indexedParameters.get(index).getName();
} }
public Map<String, Parameter<?, ?>> getParametersByName() { public Map<String, Parameter<?, ?>> getParametersByName() {
return Collections.unmodifiableMap(byName); return Collections.unmodifiableMap(byName);
} }
/** /**
* Add the given parameter to the end of this parameter list * Add the given parameter to the end of this parameter list
* Can be a flag * Can be a flag
* *
* @param parameter the parameter * @param parameter the parameter
* @return this * @return this
*/ */
public ParameterList addParameter(Parameter<?, ?> parameter) { public ParameterList addParameter(Parameter<?, ?> parameter) {
return addParameter(-1, parameter); return addParameter(-1, parameter);
} }
/** /**
* Add the given parameter to this parameter list * Add the given parameter to this parameter list
* If the parameter is a flag, the index is ignored * If the parameter is a flag, the index is ignored
* *
* @param index parameter index number, -1 if end * @param index parameter index number, -1 if end
* @param parameter the parameter * @param parameter the parameter
* @return this * @return this
* @throws NullPointerException if parameter is null * @throws NullPointerException if parameter is null
*/ */
public ParameterList addParameter(int index, Parameter<?, ?> parameter) { public ParameterList addParameter(int index, Parameter<?, ?> parameter) {
//System.out.println("Added parameter " + parameter.getName() + ", flag: " + parameter.isFlag()); //System.out.println("Added parameter " + parameter.getName() + ", flag: " + parameter.isFlag());
byName.put(parameter.getName(), parameter); byName.put(parameter.getName(), parameter);
if (!parameter.isFlag()) { if (!parameter.isFlag()) {
indexedParameters.add(index == -1 ? indexedParameters.size() : index, parameter); indexedParameters.add(index == -1 ? indexedParameters.size() : index, parameter);
} }
return this; return this;
} }
public Parameter<?, ?> getRepeatedParameter() { public Parameter<?, ?> getRepeatedParameter() {
if (!repeatFinalParameter) { if (!repeatFinalParameter) {
return null; return null;
} }
if (finalParameterMayBeFlag) { if (finalParameterMayBeFlag) {
Iterator<Parameter<?, ?>> iterator = byName.values().iterator(); Iterator<Parameter<?, ?>> iterator = byName.values().iterator();
Parameter<?, ?> result = null; Parameter<?, ?> result = null;
while (iterator.hasNext()) { while (iterator.hasNext()) {
result = iterator.next(); result = iterator.next();
} }
return result; return result;
} }
if (indexedParameters.isEmpty()) { if (indexedParameters.isEmpty()) {
return null; return null;
} }
return indexedParameters.get(indexedParameters.size() - 1); return indexedParameters.get(indexedParameters.size() - 1);
} }
} }

View File

@@ -1,46 +1,46 @@
package io.dico.dicore.command.parameter.type; package io.dico.dicore.command.parameter.type;
import io.dico.dicore.command.CommandException; import io.dico.dicore.command.CommandException;
import io.dico.dicore.command.parameter.ArgumentBuffer; import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.parameter.Parameter; import io.dico.dicore.command.parameter.Parameter;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class EnumParameterType<E extends Enum> extends SimpleParameterType<E, Void> { public class EnumParameterType<E extends Enum> extends SimpleParameterType<E, Void> {
private final E[] universe; private final E[] universe;
public EnumParameterType(Class<E> returnType) { public EnumParameterType(Class<E> returnType) {
super(returnType); super(returnType);
universe = returnType.getEnumConstants(); universe = returnType.getEnumConstants();
if (universe == null) { if (universe == null) {
throw new IllegalArgumentException("returnType must be an enum"); throw new IllegalArgumentException("returnType must be an enum");
} }
} }
@Override @Override
protected E parse(Parameter<E, Void> parameter, CommandSender sender, String input) throws CommandException { protected E parse(Parameter<E, Void> parameter, CommandSender sender, String input) throws CommandException {
for (E constant : universe) { for (E constant : universe) {
if (constant.name().equalsIgnoreCase(input)) { if (constant.name().equalsIgnoreCase(input)) {
return constant; return constant;
} }
} }
throw CommandException.invalidArgument(parameter.getName(), "the enum value does not exist"); throw CommandException.invalidArgument(parameter.getName(), "the enum value does not exist");
} }
@Override @Override
public List<String> complete(Parameter<E, Void> parameter, CommandSender sender, Location location, ArgumentBuffer buffer) { public List<String> complete(Parameter<E, Void> parameter, CommandSender sender, Location location, ArgumentBuffer buffer) {
String input = buffer.next().toUpperCase(); String input = buffer.next().toUpperCase();
List<String> result = new ArrayList<>(); List<String> result = new ArrayList<>();
for (E constant : universe) { for (E constant : universe) {
if (constant.name().toUpperCase().startsWith(input.toUpperCase())) { if (constant.name().toUpperCase().startsWith(input.toUpperCase())) {
result.add(constant.name().toLowerCase()); result.add(constant.name().toLowerCase());
} }
} }
return result; return result;
} }
} }

View File

@@ -1,44 +1,44 @@
package io.dico.dicore.command.parameter.type; package io.dico.dicore.command.parameter.type;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
/** /**
* An interface for an object that stores parameter types by {@link ParameterKey} and finds appropriate types for {@link ParameterKey parameterKeys} * An interface for an object that stores parameter types by {@link ParameterKey} and finds appropriate types for {@link ParameterKey parameterKeys}
*/ */
public interface IParameterTypeSelector { public interface IParameterTypeSelector {
<TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExact(ParameterKey key); <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExact(ParameterKey key);
//<TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExactOrSubclass(ParameterKey key); //<TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExactOrSubclass(ParameterKey key);
<TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectAny(ParameterKey key); <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectAny(ParameterKey key);
default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExact(Class<?> returnType) { default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExact(Class<?> returnType) {
return selectExact(returnType, null); return selectExact(returnType, null);
} }
default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExact(Class<?> returnType, Class<? extends Annotation> annotationClass) { default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExact(Class<?> returnType, Class<? extends Annotation> annotationClass) {
return selectExact(new ParameterKey(returnType, annotationClass)); return selectExact(new ParameterKey(returnType, annotationClass));
} }
/* /*
default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExactOrSubclass(Class<?> returnType) { default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExactOrSubclass(Class<?> returnType) {
return selectExactOrSubclass(returnType, null); return selectExactOrSubclass(returnType, null);
} }
default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExactOrSubclass(Class<?> returnType, Class<? extends Annotation> annotationClass) { default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExactOrSubclass(Class<?> returnType, Class<? extends Annotation> annotationClass) {
return selectExactOrSubclass(new ParameterKey(returnType, annotationClass)); return selectExactOrSubclass(new ParameterKey(returnType, annotationClass));
} }
*/ */
default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectAny(Class<?> returnType) { default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectAny(Class<?> returnType) {
return selectAny(returnType, null); return selectAny(returnType, null);
} }
default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectAny(Class<?> returnType, Class<? extends Annotation> annotationClass) { default <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectAny(Class<?> returnType, Class<? extends Annotation> annotationClass) {
return selectAny(new ParameterKey(returnType, annotationClass)); return selectAny(new ParameterKey(returnType, annotationClass));
} }
void addType(boolean infolessAlias, ParameterType<?, ?> type); void addType(boolean infolessAlias, ParameterType<?, ?> type);
} }

View File

@@ -1,114 +1,114 @@
package io.dico.dicore.command.parameter.type; package io.dico.dicore.command.parameter.type;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* Map based implementation of {@link IParameterTypeSelector} * Map based implementation of {@link IParameterTypeSelector}
*/ */
public class MapBasedParameterTypeSelector implements IParameterTypeSelector { public class MapBasedParameterTypeSelector implements IParameterTypeSelector {
static final MapBasedParameterTypeSelector defaultSelector = new MapBasedParameterTypeSelector(false); static final MapBasedParameterTypeSelector defaultSelector = new MapBasedParameterTypeSelector(false);
private final Map<ParameterKey, ParameterType<?, ?>> parameterTypeMap; private final Map<ParameterKey, ParameterType<?, ?>> parameterTypeMap;
private final boolean useDefault; private final boolean useDefault;
public MapBasedParameterTypeSelector(boolean useDefault) { public MapBasedParameterTypeSelector(boolean useDefault) {
this.parameterTypeMap = new HashMap<>(); this.parameterTypeMap = new HashMap<>();
this.useDefault = useDefault; this.useDefault = useDefault;
} }
@Override @Override
public <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExact(ParameterKey key) { public <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectExact(ParameterKey key) {
ParameterType<?, ?> out = parameterTypeMap.get(key); ParameterType<?, ?> out = parameterTypeMap.get(key);
if (useDefault && out == null) { if (useDefault && out == null) {
out = defaultSelector.selectExact(key); out = defaultSelector.selectExact(key);
} }
if (out == null && key.getReturnType().isEnum()) { if (out == null && key.getReturnType().isEnum()) {
//noinspection unchecked //noinspection unchecked
out = new EnumParameterType(key.getReturnType()); out = new EnumParameterType(key.getReturnType());
addType(false, out); addType(false, out);
} }
return cast(out); return cast(out);
} }
@Override @Override
public <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectAny(ParameterKey key) { public <TReturn, TParamInfo> ParameterType<TReturn, TParamInfo> selectAny(ParameterKey key) {
ParameterType<TReturn, TParamInfo> exact = selectExact(key); ParameterType<TReturn, TParamInfo> exact = selectExact(key);
if (exact != null) { if (exact != null) {
return exact; return exact;
} }
if (key.getAnnotationClass() != null) { if (key.getAnnotationClass() != null) {
exact = selectExact(new ParameterKey(key.getReturnType())); exact = selectExact(new ParameterKey(key.getReturnType()));
if (exact != null) { if (exact != null) {
return exact; return exact;
} }
} }
Class<?> returnType = key.getReturnType(); Class<?> returnType = key.getReturnType();
Class<? extends Annotation> annotationClass = key.getAnnotationClass(); Class<? extends Annotation> annotationClass = key.getAnnotationClass();
ParameterType<?, ?> out = selectByReturnType(parameterTypeMap, returnType, annotationClass, false); ParameterType<?, ?> out = selectByReturnType(parameterTypeMap, returnType, annotationClass, false);
if (out == null && useDefault) { if (out == null && useDefault) {
out = selectByReturnType(defaultSelector.parameterTypeMap, returnType, annotationClass, false); out = selectByReturnType(defaultSelector.parameterTypeMap, returnType, annotationClass, false);
} }
if (out == null) { if (out == null) {
out = selectByReturnType(parameterTypeMap, returnType, annotationClass, true); out = selectByReturnType(parameterTypeMap, returnType, annotationClass, true);
} }
if (out == null && useDefault) { if (out == null && useDefault) {
out = selectByReturnType(defaultSelector.parameterTypeMap, returnType, annotationClass, true); out = selectByReturnType(defaultSelector.parameterTypeMap, returnType, annotationClass, true);
} }
return cast(out); return cast(out);
} }
private static ParameterType<?, ?> selectByReturnType(Map<ParameterKey, ParameterType<?, ?>> map, Class<?> returnType, private static ParameterType<?, ?> selectByReturnType(Map<ParameterKey, ParameterType<?, ?>> map, Class<?> returnType,
Class<? extends Annotation> annotationClass, boolean allowSubclass) { Class<? extends Annotation> annotationClass, boolean allowSubclass) {
ParameterType<?, ?> out = null; ParameterType<?, ?> out = null;
if (allowSubclass) { if (allowSubclass) {
for (ParameterType<?, ?> type : map.values()) { for (ParameterType<?, ?> type : map.values()) {
if (returnType.isAssignableFrom(type.getReturnType())) { if (returnType.isAssignableFrom(type.getReturnType())) {
if (annotationClass == type.getAnnotationClass()) { if (annotationClass == type.getAnnotationClass()) {
out = type; out = type;
break; break;
} }
if (out == null) { if (out == null) {
out = type; out = type;
} }
} }
} }
} else { } else {
for (ParameterType<?, ?> type : map.values()) { for (ParameterType<?, ?> type : map.values()) {
if (returnType == type.getReturnType()) { if (returnType == type.getReturnType()) {
if (annotationClass == type.getAnnotationClass()) { if (annotationClass == type.getAnnotationClass()) {
out = type; out = type;
break; break;
} }
if (out == null) { if (out == null) {
out = type; out = type;
} }
} }
} }
} }
return out; return out;
} }
private static <T> T cast(Object o) { private static <T> T cast(Object o) {
//noinspection unchecked //noinspection unchecked
return (T) o; return (T) o;
} }
@Override @Override
public void addType(boolean infolessAlias, ParameterType<?, ?> type) { public void addType(boolean infolessAlias, ParameterType<?, ?> type) {
parameterTypeMap.put(type.getTypeKey(), type); parameterTypeMap.put(type.getTypeKey(), type);
if (infolessAlias) { if (infolessAlias) {
parameterTypeMap.putIfAbsent(type.getInfolessTypeKey(), type); parameterTypeMap.putIfAbsent(type.getInfolessTypeKey(), type);
} }
} }
static { static {
// registers default parameter types // registers default parameter types
ParameterTypes.clinit(); ParameterTypes.clinit();
} }
} }

View File

@@ -1,80 +1,80 @@
package io.dico.dicore.command.parameter.type; package io.dico.dicore.command.parameter.type;
import io.dico.dicore.Reflection; import io.dico.dicore.Reflection;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
/** /**
* This class serves the purpose of having annotated parameter configurations (such as ranges for number parameters). * This class serves the purpose of having annotated parameter configurations (such as ranges for number parameters).
* Such configurations must be possible to obtain without using annotations, and as such, there should be a class conveying the information * Such configurations must be possible to obtain without using annotations, and as such, there should be a class conveying the information
* that is separate from the annotation itself. This class acts as a bridge from the annotation to said class conveying the information. * that is separate from the annotation itself. This class acts as a bridge from the annotation to said class conveying the information.
* *
* @param <TAnnotation> the annotation type for parameters * @param <TAnnotation> the annotation type for parameters
* @param <TParamInfo> the object type that holds the information required in memory * @param <TParamInfo> the object type that holds the information required in memory
*/ */
public abstract class ParameterConfig<TAnnotation extends Annotation, TParamInfo> implements Comparable<ParameterConfig<?, ?>> { public abstract class ParameterConfig<TAnnotation extends Annotation, TParamInfo> implements Comparable<ParameterConfig<?, ?>> {
private final Class<TAnnotation> annotationClass; private final Class<TAnnotation> annotationClass;
// protected final TParamInfo defaultValue; // protected final TParamInfo defaultValue;
public ParameterConfig(Class<TAnnotation> annotationClass/*, TParamInfo defaultValue*/) { public ParameterConfig(Class<TAnnotation> annotationClass/*, TParamInfo defaultValue*/) {
this.annotationClass = annotationClass; this.annotationClass = annotationClass;
//this.defaultValue = defaultValue; //this.defaultValue = defaultValue;
} }
public final Class<TAnnotation> getAnnotationClass() { public final Class<TAnnotation> getAnnotationClass() {
return annotationClass; return annotationClass;
} }
/* /*
public TParamInfo getDefaultValue() { public TParamInfo getDefaultValue() {
return defaultValue; return defaultValue;
}*/ }*/
protected abstract TParamInfo toParameterInfo(TAnnotation annotation); protected abstract TParamInfo toParameterInfo(TAnnotation annotation);
public TParamInfo getParameterInfo(Annotation annotation) { public TParamInfo getParameterInfo(Annotation annotation) {
//noinspection unchecked //noinspection unchecked
return toParameterInfo((TAnnotation) annotation); return toParameterInfo((TAnnotation) annotation);
} }
public static <TAnnotation extends Annotation, TParamInfo> ParameterConfig<TAnnotation, TParamInfo> public static <TAnnotation extends Annotation, TParamInfo> ParameterConfig<TAnnotation, TParamInfo>
includeMemoryClass(Class<TAnnotation> annotationClass, Class<TParamInfo> memoryClass) { includeMemoryClass(Class<TAnnotation> annotationClass, Class<TParamInfo> memoryClass) {
Constructor<TParamInfo> constructor; Constructor<TParamInfo> constructor;
//TParamInfo defaultValue; //TParamInfo defaultValue;
try { try {
constructor = memoryClass.getConstructor(annotationClass); constructor = memoryClass.getConstructor(annotationClass);
//defaultValue = Reflection.getStaticFieldValue(annotationClass, "DEFAULT"); //defaultValue = Reflection.getStaticFieldValue(annotationClass, "DEFAULT");
} catch (NoSuchMethodException | IllegalArgumentException ex) { } catch (NoSuchMethodException | IllegalArgumentException ex) {
throw new IllegalArgumentException(ex); throw new IllegalArgumentException(ex);
} }
/* /*
if (defaultValue == null) try { if (defaultValue == null) try {
defaultValue = memoryClass.newInstance(); defaultValue = memoryClass.newInstance();
} catch (IllegalAccessException | InstantiationException ex) { } catch (IllegalAccessException | InstantiationException ex) {
throw new IllegalArgumentException("Failed to get a default value for the param info", ex); throw new IllegalArgumentException("Failed to get a default value for the param info", ex);
}*/ }*/
return new ParameterConfig<TAnnotation, TParamInfo>(annotationClass/*, defaultValue*/) { return new ParameterConfig<TAnnotation, TParamInfo>(annotationClass/*, defaultValue*/) {
@Override @Override
public TParamInfo toParameterInfo(TAnnotation annotation) { public TParamInfo toParameterInfo(TAnnotation annotation) {
try { try {
return constructor.newInstance(annotation); return constructor.newInstance(annotation);
} catch (Exception ex) { } catch (Exception ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
} }
}; };
} }
public static <TAnnotation extends Annotation, TParamInfo> ParameterConfig<TAnnotation, TParamInfo> getMemoryClassFromField(Class<TAnnotation> annotationClass) { public static <TAnnotation extends Annotation, TParamInfo> ParameterConfig<TAnnotation, TParamInfo> getMemoryClassFromField(Class<TAnnotation> annotationClass) {
return ParameterConfig.includeMemoryClass(annotationClass, Reflection.getStaticFieldValue(annotationClass, "MEMORY_CLASS")); return ParameterConfig.includeMemoryClass(annotationClass, Reflection.getStaticFieldValue(annotationClass, "MEMORY_CLASS"));
} }
@Override @Override
public int compareTo(ParameterConfig<?, ?> o) { public int compareTo(ParameterConfig<?, ?> o) {
return 0; return 0;
} }
} }

View File

@@ -1,149 +1,149 @@
package io.dico.dicore.command.parameter.type; package io.dico.dicore.command.parameter.type;
import io.dico.dicore.Reflection; import io.dico.dicore.Reflection;
import io.dico.dicore.command.CommandException; import io.dico.dicore.command.CommandException;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.annotation.Range; import io.dico.dicore.command.annotation.Range;
import io.dico.dicore.command.parameter.ArgumentBuffer; import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.parameter.Parameter; import io.dico.dicore.command.parameter.Parameter;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
/** /**
* A parameter type. * A parameter type.
* Takes care of parsing, default values as well as completions. * Takes care of parsing, default values as well as completions.
* *
* @param <TReturn> type of the parameter * @param <TReturn> type of the parameter
* @param <TParamInfo> the info object type for the parameter (Example: {@link Range.Memory} * @param <TParamInfo> the info object type for the parameter (Example: {@link Range.Memory}
*/ */
public abstract class ParameterType<TReturn, TParamInfo> { public abstract class ParameterType<TReturn, TParamInfo> {
private final Class<TReturn> returnType; private final Class<TReturn> returnType;
private final ParameterConfig<?, TParamInfo> parameterConfig; private final ParameterConfig<?, TParamInfo> parameterConfig;
protected final ParameterType<TReturn, TParamInfo> otherType; // flag or non-flag, depending on current protected final ParameterType<TReturn, TParamInfo> otherType; // flag or non-flag, depending on current
public ParameterType(Class<TReturn> returnType) { public ParameterType(Class<TReturn> returnType) {
this(returnType, null); this(returnType, null);
} }
public ParameterType(Class<TReturn> returnType, ParameterConfig<?, TParamInfo> paramConfig) { public ParameterType(Class<TReturn> returnType, ParameterConfig<?, TParamInfo> paramConfig) {
this.returnType = Objects.requireNonNull(returnType); this.returnType = Objects.requireNonNull(returnType);
this.parameterConfig = paramConfig; this.parameterConfig = paramConfig;
ParameterType<TReturn, TParamInfo> otherType = flagTypeParameter(); ParameterType<TReturn, TParamInfo> otherType = flagTypeParameter();
this.otherType = otherType == null ? this : otherType; this.otherType = otherType == null ? this : otherType;
} }
protected ParameterType(Class<TReturn> returnType, ParameterConfig<?, TParamInfo> parameterConfig, ParameterType<TReturn, TParamInfo> otherType) { protected ParameterType(Class<TReturn> returnType, ParameterConfig<?, TParamInfo> parameterConfig, ParameterType<TReturn, TParamInfo> otherType) {
this.returnType = returnType; this.returnType = returnType;
this.parameterConfig = parameterConfig; this.parameterConfig = parameterConfig;
this.otherType = otherType; this.otherType = otherType;
} }
public int getExpectedAmountOfConsumedArguments() { public int getExpectedAmountOfConsumedArguments() {
return 1; return 1;
} }
public boolean canBeFlag() { public boolean canBeFlag() {
return this == otherType; return this == otherType;
} }
public boolean isFlagExplicitly() { public boolean isFlagExplicitly() {
return this instanceof FlagParameterType; return this instanceof FlagParameterType;
} }
/** /**
* @return The return type * @return The return type
*/ */
public final Class<TReturn> getReturnType() { public final Class<TReturn> getReturnType() {
return returnType; return returnType;
} }
public final Class<?> getAnnotationClass() { public final Class<?> getAnnotationClass() {
return parameterConfig == null ? null : parameterConfig.getAnnotationClass(); return parameterConfig == null ? null : parameterConfig.getAnnotationClass();
} }
public final ParameterConfig<?, TParamInfo> getParameterConfig() { public final ParameterConfig<?, TParamInfo> getParameterConfig() {
return parameterConfig; return parameterConfig;
} }
public ParameterKey getTypeKey() { public ParameterKey getTypeKey() {
return new ParameterKey(returnType, parameterConfig != null ? parameterConfig.getAnnotationClass() : null); return new ParameterKey(returnType, parameterConfig != null ? parameterConfig.getAnnotationClass() : null);
} }
public ParameterKey getInfolessTypeKey() { public ParameterKey getInfolessTypeKey() {
return new ParameterKey(returnType, null); return new ParameterKey(returnType, null);
} }
protected FlagParameterType<TReturn, TParamInfo> flagTypeParameter() { protected FlagParameterType<TReturn, TParamInfo> flagTypeParameter() {
return null; return null;
} }
public ParameterType<TReturn, TParamInfo> asFlagParameter() { public ParameterType<TReturn, TParamInfo> asFlagParameter() {
return canBeFlag() ? this : otherType; return canBeFlag() ? this : otherType;
} }
public ParameterType<TReturn, TParamInfo> asNormalParameter() { public ParameterType<TReturn, TParamInfo> asNormalParameter() {
return isFlagExplicitly() ? otherType : this; return isFlagExplicitly() ? otherType : this;
} }
public abstract TReturn parse(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, ArgumentBuffer buffer) throws CommandException; public abstract TReturn parse(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, ArgumentBuffer buffer) throws CommandException;
public TReturn parseForContext(Parameter<TReturn, TParamInfo> parameter, ExecutionContext context, ArgumentBuffer buffer) throws CommandException { public TReturn parseForContext(Parameter<TReturn, TParamInfo> parameter, ExecutionContext context, ArgumentBuffer buffer) throws CommandException {
return parse(parameter, context.getSender(), buffer); return parse(parameter, context.getSender(), buffer);
} }
public TReturn getDefaultValue(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, ArgumentBuffer buffer) throws CommandException { public TReturn getDefaultValue(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, ArgumentBuffer buffer) throws CommandException {
return null; return null;
} }
public TReturn getDefaultValueForContext(Parameter<TReturn, TParamInfo> parameter, ExecutionContext context, ArgumentBuffer buffer) throws CommandException { public TReturn getDefaultValueForContext(Parameter<TReturn, TParamInfo> parameter, ExecutionContext context, ArgumentBuffer buffer) throws CommandException {
return getDefaultValue(parameter, context.getSender(), buffer); return getDefaultValue(parameter, context.getSender(), buffer);
} }
public List<String> complete(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, Location location, ArgumentBuffer buffer) { public List<String> complete(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, Location location, ArgumentBuffer buffer) {
return Collections.emptyList(); return Collections.emptyList();
} }
public List<String> completeForContext(Parameter<TReturn, TParamInfo> parameter, ExecutionContext context, Location location, ArgumentBuffer buffer) { public List<String> completeForContext(Parameter<TReturn, TParamInfo> parameter, ExecutionContext context, Location location, ArgumentBuffer buffer) {
return complete(parameter, context.getSender(), location, buffer); return complete(parameter, context.getSender(), location, buffer);
} }
protected static abstract class FlagParameterType<TResult, TParamInfo> extends ParameterType<TResult, TParamInfo> { protected static abstract class FlagParameterType<TResult, TParamInfo> extends ParameterType<TResult, TParamInfo> {
protected FlagParameterType(ParameterType<TResult, TParamInfo> otherType) { protected FlagParameterType(ParameterType<TResult, TParamInfo> otherType) {
super(otherType.returnType, otherType.parameterConfig, otherType); super(otherType.returnType, otherType.parameterConfig, otherType);
} }
@Override @Override
public int getExpectedAmountOfConsumedArguments() { public int getExpectedAmountOfConsumedArguments() {
return otherType.getExpectedAmountOfConsumedArguments(); return otherType.getExpectedAmountOfConsumedArguments();
} }
@Override @Override
public boolean canBeFlag() { public boolean canBeFlag() {
return true; return true;
} }
@Override @Override
protected final FlagParameterType<TResult, TParamInfo> flagTypeParameter() { protected final FlagParameterType<TResult, TParamInfo> flagTypeParameter() {
return this; return this;
} }
@Override @Override
public ParameterType<TResult, TParamInfo> asFlagParameter() { public ParameterType<TResult, TParamInfo> asFlagParameter() {
return this; return this;
} }
@Override @Override
public ParameterType<TResult, TParamInfo> asNormalParameter() { public ParameterType<TResult, TParamInfo> asNormalParameter() {
return otherType; return otherType;
} }
} }
} }

View File

@@ -1,31 +1,31 @@
package io.dico.dicore.command.parameter.type; package io.dico.dicore.command.parameter.type;
import io.dico.dicore.command.CommandException; import io.dico.dicore.command.CommandException;
import io.dico.dicore.command.parameter.ArgumentBuffer; import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.parameter.Parameter; import io.dico.dicore.command.parameter.Parameter;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
/** /**
* An abstraction for parameter types that only parse a single argument * An abstraction for parameter types that only parse a single argument
* *
* @param <TReturn> the parameter type * @param <TReturn> the parameter type
* @param <TParamInfo> parameter info object type * @param <TParamInfo> parameter info object type
*/ */
public abstract class SimpleParameterType<TReturn, TParamInfo> extends ParameterType<TReturn, TParamInfo> { public abstract class SimpleParameterType<TReturn, TParamInfo> extends ParameterType<TReturn, TParamInfo> {
public SimpleParameterType(Class<TReturn> returnType) { public SimpleParameterType(Class<TReturn> returnType) {
super(returnType); super(returnType);
} }
public SimpleParameterType(Class<TReturn> returnType, ParameterConfig<?, TParamInfo> paramConfig) { public SimpleParameterType(Class<TReturn> returnType, ParameterConfig<?, TParamInfo> paramConfig) {
super(returnType, paramConfig); super(returnType, paramConfig);
} }
protected abstract TReturn parse(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, String input) throws CommandException; protected abstract TReturn parse(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, String input) throws CommandException;
@Override @Override
public TReturn parse(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, ArgumentBuffer buffer) throws CommandException { public TReturn parse(Parameter<TReturn, TParamInfo> parameter, CommandSender sender, ArgumentBuffer buffer) throws CommandException {
return parse(parameter, sender, buffer.requireNext(parameter.getName())); return parse(parameter, sender, buffer.requireNext(parameter.getName()));
} }
} }

View File

@@ -1,56 +1,56 @@
package io.dico.dicore.command.predef; package io.dico.dicore.command.predef;
import io.dico.dicore.command.CommandException; import io.dico.dicore.command.CommandException;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import io.dico.dicore.command.IContextFilter; import io.dico.dicore.command.IContextFilter;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
public class DefaultGroupCommand extends PredefinedCommand<DefaultGroupCommand> { public class DefaultGroupCommand extends PredefinedCommand<DefaultGroupCommand> {
private static final DefaultGroupCommand instance; private static final DefaultGroupCommand instance;
private static final IContextFilter noArgumentFilter; private static final IContextFilter noArgumentFilter;
public static DefaultGroupCommand getInstance() { public static DefaultGroupCommand getInstance() {
return instance; return instance;
} }
private DefaultGroupCommand(boolean modifiable) { private DefaultGroupCommand(boolean modifiable) {
addContextFilter(IContextFilter.INHERIT_PERMISSIONS); addContextFilter(IContextFilter.INHERIT_PERMISSIONS);
addContextFilter(noArgumentFilter); addContextFilter(noArgumentFilter);
this.modifiable = modifiable; this.modifiable = modifiable;
} }
public DefaultGroupCommand() { public DefaultGroupCommand() {
this(true); this(true);
} }
@Override @Override
protected DefaultGroupCommand newModifiableInstance() { protected DefaultGroupCommand newModifiableInstance() {
return new DefaultGroupCommand(true); return new DefaultGroupCommand(true);
} }
@Override @Override
public String execute(CommandSender sender, ExecutionContext context) throws CommandException { public String execute(CommandSender sender, ExecutionContext context) throws CommandException {
context.getAddress().getChatHandler().sendHelpMessage(sender, context, context.getAddress(), 1); context.getAddress().getChatHandler().sendHelpMessage(sender, context, context.getAddress(), 1);
return null; return null;
} }
static { static {
noArgumentFilter = new IContextFilter() { noArgumentFilter = new IContextFilter() {
@Override @Override
public void filterContext(ExecutionContext context) throws CommandException { public void filterContext(ExecutionContext context) throws CommandException {
if (context.getBuffer().hasNext()) { if (context.getBuffer().hasNext()) {
throw new CommandException("No such command: /" + context.getAddress().getAddress() throw new CommandException("No such command: /" + context.getAddress().getAddress()
+ " " + context.getBuffer().next()); + " " + context.getBuffer().next());
} }
} }
@Override @Override
public Priority getPriority() { public Priority getPriority() {
return Priority.EARLY; return Priority.EARLY;
} }
}; };
instance = new DefaultGroupCommand(false); instance = new DefaultGroupCommand(false);
} }
} }

View File

@@ -1,76 +1,76 @@
package io.dico.dicore.command.predef; package io.dico.dicore.command.predef;
import io.dico.dicore.command.*; import io.dico.dicore.command.*;
import io.dico.dicore.command.annotation.Range; import io.dico.dicore.command.annotation.Range;
import io.dico.dicore.command.parameter.ArgumentBuffer; import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.parameter.Parameter; import io.dico.dicore.command.parameter.Parameter;
import io.dico.dicore.command.parameter.type.NumberParameterType; import io.dico.dicore.command.parameter.type.NumberParameterType;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
/** /**
* The help command * The help command
*/ */
public class HelpCommand extends PredefinedCommand<HelpCommand> { public class HelpCommand extends PredefinedCommand<HelpCommand> {
private static final Parameter<Integer, Range.Memory> pageParameter; private static final Parameter<Integer, Range.Memory> pageParameter;
public static final HelpCommand INSTANCE; public static final HelpCommand INSTANCE;
private HelpCommand(boolean modifiable) { private HelpCommand(boolean modifiable) {
super(modifiable); super(modifiable);
getParameterList().addParameter(pageParameter); getParameterList().addParameter(pageParameter);
getParameterList().setRequiredCount(0); getParameterList().setRequiredCount(0);
setDescription("Shows this help page"); setDescription("Shows this help page");
} }
@Override @Override
protected HelpCommand newModifiableInstance() { protected HelpCommand newModifiableInstance() {
return new HelpCommand(true); return new HelpCommand(true);
} }
@Override @Override
public String execute(CommandSender sender, ExecutionContext context) throws CommandException { public String execute(CommandSender sender, ExecutionContext context) throws CommandException {
ICommandAddress target = context.getAddress(); ICommandAddress target = context.getAddress();
if (context.getAddress().getCommand() == this) { if (context.getAddress().getCommand() == this) {
target = target.getParent(); target = target.getParent();
} }
context.getAddress().getChatHandler().sendHelpMessage(sender, context, target, context.<Integer>get("page") - 1); context.getAddress().getChatHandler().sendHelpMessage(sender, context, target, context.<Integer>get("page") - 1);
return null; return null;
} }
public static void registerAsChild(ICommandAddress address) { public static void registerAsChild(ICommandAddress address) {
registerAsChild(address, "help"); registerAsChild(address, "help");
} }
public static void registerAsChild(ICommandAddress address, String main, String... aliases) { public static void registerAsChild(ICommandAddress address, String main, String... aliases) {
((ModifiableCommandAddress) address).addChild(new ChildCommandAddress(INSTANCE, main, aliases)); ((ModifiableCommandAddress) address).addChild(new ChildCommandAddress(INSTANCE, main, aliases));
} }
static { static {
pageParameter = new Parameter<>("page", "the page number", pageParameter = new Parameter<>("page", "the page number",
new NumberParameterType<Integer>(Integer.TYPE) { new NumberParameterType<Integer>(Integer.TYPE) {
@Override @Override
protected Integer parse(String input) throws NumberFormatException { protected Integer parse(String input) throws NumberFormatException {
return Integer.parseInt(input); return Integer.parseInt(input);
} }
@Override @Override
protected Integer select(Number number) { protected Integer select(Number number) {
return number.intValue(); return number.intValue();
} }
@Override @Override
public Integer parseForContext(Parameter<Integer, Range.Memory> parameter, ExecutionContext context, ArgumentBuffer buffer) throws CommandException { public Integer parseForContext(Parameter<Integer, Range.Memory> parameter, ExecutionContext context, ArgumentBuffer buffer) throws CommandException {
if (context.getAddress().getCommand() == null || context.getAddress().getCommand().getClass() != HelpCommand.class) { if (context.getAddress().getCommand() == null || context.getAddress().getCommand().getClass() != HelpCommand.class) {
// An address was executed with its help command as target // An address was executed with its help command as target
buffer.next(); buffer.next();
return 1; return 1;
} }
return parse(parameter, context.getSender(), buffer); return parse(parameter, context.getSender(), buffer);
} }
}, },
new Range.Memory(1, Integer.MAX_VALUE, 1)); new Range.Memory(1, Integer.MAX_VALUE, 1));
INSTANCE = new HelpCommand(false); INSTANCE = new HelpCommand(false);
} }
} }

View File

@@ -1,50 +1,50 @@
package io.dico.dicore.command.predef; package io.dico.dicore.command.predef;
import io.dico.dicore.command.CommandBuilder; import io.dico.dicore.command.CommandBuilder;
import io.dico.dicore.command.ExtendedCommand; import io.dico.dicore.command.ExtendedCommand;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
* Marker class for commands that are generated. These commands can be replaced using methods in {@link CommandBuilder} * Marker class for commands that are generated. These commands can be replaced using methods in {@link CommandBuilder}
*/ */
public abstract class PredefinedCommand<T extends PredefinedCommand<T>> extends ExtendedCommand<T> { public abstract class PredefinedCommand<T extends PredefinedCommand<T>> extends ExtendedCommand<T> {
static final Map<String, Consumer<ICommandAddress>> predefinedCommandGenerators = new HashMap<>(); static final Map<String, Consumer<ICommandAddress>> predefinedCommandGenerators = new HashMap<>();
/** /**
* Get a predefined command * Get a predefined command
* *
* @param name the name * @param name the name
* @return the subscriber * @return the subscriber
*/ */
public static Consumer<ICommandAddress> getPredefinedCommandGenerator(String name) { public static Consumer<ICommandAddress> getPredefinedCommandGenerator(String name) {
return predefinedCommandGenerators.get(name); return predefinedCommandGenerators.get(name);
} }
/** /**
* Register a predefined command * Register a predefined command
* *
* @param name the name * @param name the name
* @param consumer the generator which adds the child to the address * @param consumer the generator which adds the child to the address
* @return true if and only if the subscriber was registered (false if the name exists) * @return true if and only if the subscriber was registered (false if the name exists)
*/ */
public static boolean registerPredefinedCommandGenerator(String name, Consumer<ICommandAddress> consumer) { public static boolean registerPredefinedCommandGenerator(String name, Consumer<ICommandAddress> consumer) {
return predefinedCommandGenerators.putIfAbsent(name, consumer) == null; return predefinedCommandGenerators.putIfAbsent(name, consumer) == null;
} }
static { static {
registerPredefinedCommandGenerator("help", HelpCommand::registerAsChild); registerPredefinedCommandGenerator("help", HelpCommand::registerAsChild);
//noinspection StaticInitializerReferencesSubClass //noinspection StaticInitializerReferencesSubClass
registerPredefinedCommandGenerator("syntax", SyntaxCommand::registerAsChild); registerPredefinedCommandGenerator("syntax", SyntaxCommand::registerAsChild);
} }
public PredefinedCommand() { public PredefinedCommand() {
} }
public PredefinedCommand(boolean modifiable) { public PredefinedCommand(boolean modifiable) {
super(modifiable); super(modifiable);
} }
} }

View File

@@ -1,36 +1,36 @@
package io.dico.dicore.command.predef; package io.dico.dicore.command.predef;
import io.dico.dicore.command.*; import io.dico.dicore.command.*;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
/** /**
* The syntax command * The syntax command
*/ */
public class SyntaxCommand extends PredefinedCommand<SyntaxCommand> { public class SyntaxCommand extends PredefinedCommand<SyntaxCommand> {
public static final SyntaxCommand INSTANCE = new SyntaxCommand(false); public static final SyntaxCommand INSTANCE = new SyntaxCommand(false);
private SyntaxCommand(boolean modifiable) { private SyntaxCommand(boolean modifiable) {
super(modifiable); super(modifiable);
setDescription("Describes how to use the command"); setDescription("Describes how to use the command");
} }
@Override @Override
protected SyntaxCommand newModifiableInstance() { protected SyntaxCommand newModifiableInstance() {
return new SyntaxCommand(true); return new SyntaxCommand(true);
} }
@Override @Override
public String execute(CommandSender sender, ExecutionContext context) throws CommandException { public String execute(CommandSender sender, ExecutionContext context) throws CommandException {
context.getAddress().getChatHandler().sendSyntaxMessage(sender, context, context.getAddress().getParent()); context.getAddress().getChatHandler().sendSyntaxMessage(sender, context, context.getAddress().getParent());
return null; return null;
} }
public static void registerAsChild(ICommandAddress address) { public static void registerAsChild(ICommandAddress address) {
registerAsChild(address, "syntax"); registerAsChild(address, "syntax");
} }
public static void registerAsChild(ICommandAddress address, String main, String... aliases) { public static void registerAsChild(ICommandAddress address, String main, String... aliases) {
((ModifiableCommandAddress) address).addChild(new ChildCommandAddress(INSTANCE, main, aliases)); ((ModifiableCommandAddress) address).addChild(new ChildCommandAddress(INSTANCE, main, aliases));
} }
} }

View File

@@ -1,122 +1,122 @@
package io.dico.dicore.command.registration; package io.dico.dicore.command.registration;
import io.dico.dicore.command.ICommandAddress; import io.dico.dicore.command.ICommandAddress;
import io.dico.dicore.command.ICommandDispatcher; import io.dico.dicore.command.ICommandDispatcher;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.List; import java.util.List;
/** /**
* This class extends the bukkit's command class. * This class extends the bukkit's command class.
* Instances are injected into the command map. * Instances are injected into the command map.
*/ */
public class BukkitCommand extends Command { public class BukkitCommand extends Command {
private ICommandDispatcher dispatcher; private ICommandDispatcher dispatcher;
private ICommandAddress origin; private ICommandAddress origin;
public BukkitCommand(ICommandAddress address) { public BukkitCommand(ICommandAddress address) {
super(validateTree(address).getNames().get(0), "", "", address.getNames().subList(1, address.getNames().size())); super(validateTree(address).getNames().get(0), "", "", address.getNames().subList(1, address.getNames().size()));
this.dispatcher = address.getDispatcherForTree(); this.dispatcher = address.getDispatcherForTree();
this.origin = address; this.origin = address;
setTimingsIfNecessary(this); setTimingsIfNecessary(this);
} }
private static ICommandAddress validateTree(ICommandAddress tree) { private static ICommandAddress validateTree(ICommandAddress tree) {
if (!tree.hasParent()) { if (!tree.hasParent()) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
if (tree.getNames().isEmpty()) { if (tree.getNames().isEmpty()) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
return tree; return tree;
} }
public ICommandAddress getOrigin() { public ICommandAddress getOrigin() {
return origin; return origin;
} }
@Override @Override
public boolean execute(CommandSender sender, String label, String[] args) { public boolean execute(CommandSender sender, String label, String[] args) {
if (!dispatcher.dispatchCommand(sender, label, args)) { if (!dispatcher.dispatchCommand(sender, label, args)) {
//System.out.println("failed to dispatch command"); //System.out.println("failed to dispatch command");
// target command not found, send a message in the future TODO // target command not found, send a message in the future TODO
} }
return true; return true;
} }
@Override @Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
return this.tabComplete(sender, alias, args, null); return this.tabComplete(sender, alias, args, null);
} }
//@Override //@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException { public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
return dispatcher.getTabCompletions(sender, alias, location, args); return dispatcher.getTabCompletions(sender, alias, location, args);
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
BukkitCommand that = (BukkitCommand) o; BukkitCommand that = (BukkitCommand) o;
return getName().equals(that.getName()) && dispatcher == that.dispatcher; return getName().equals(that.getName()) && dispatcher == that.dispatcher;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return dispatcher.hashCode() | getName().hashCode(); return dispatcher.hashCode() | getName().hashCode();
} }
private static void setTimingsIfNecessary(Command object) { private static void setTimingsIfNecessary(Command object) {
// with paper spigot, the timings are not set by super constructor but by CommandMap.register(), which is not invoked for this system // with paper spigot, the timings are not set by super constructor but by CommandMap.register(), which is not invoked for this system
// I use reflection so that the project does not require paper spigot to build // I use reflection so that the project does not require paper spigot to build
try { try {
// public field // public field
Field field = Command.class.getDeclaredField("timings"); Field field = Command.class.getDeclaredField("timings");
if (field.get(object) != null) return; if (field.get(object) != null) return;
Class<?> clazz = Class.forName("co.aikar.timings.TimingsManager"); Class<?> clazz = Class.forName("co.aikar.timings.TimingsManager");
// public method // public method
Method method = clazz.getDeclaredMethod("getCommandTiming", String.class, Command.class); Method method = clazz.getDeclaredMethod("getCommandTiming", String.class, Command.class);
Object timings = method.invoke(null, "", object); Object timings = method.invoke(null, "", object);
field.set(object, timings); field.set(object, timings);
} catch (Throwable ignored) { } catch (Throwable ignored) {
} }
} }
/* /*
public static void registerToMap(ICommandAddress tree, Map<String, Command> map) { public static void registerToMap(ICommandAddress tree, Map<String, Command> map) {
BukkitCommand command = new BukkitCommand(tree); BukkitCommand command = new BukkitCommand(tree);
Iterator<String> iterator = tree.getNames().iterator(); Iterator<String> iterator = tree.getNames().iterator();
map.put(iterator.next(), command); map.put(iterator.next(), command);
while (iterator.hasNext()) { while (iterator.hasNext()) {
map.putIfAbsent(iterator.next(), command); map.putIfAbsent(iterator.next(), command);
} }
} }
public static void unregisterFromMap(ICommandAddress tree, Map<String, Command> map) { public static void unregisterFromMap(ICommandAddress tree, Map<String, Command> map) {
map.values().remove(new BukkitCommand(tree)); map.values().remove(new BukkitCommand(tree));
} }
public static void registerChildrenToMap(ICommandAddress tree, Map<String, Command> map) { public static void registerChildrenToMap(ICommandAddress tree, Map<String, Command> map) {
for (Map.Entry<String, ? extends ICommandAddress> entry : tree.getChildren().entrySet()) { for (Map.Entry<String, ? extends ICommandAddress> entry : tree.getChildren().entrySet()) {
ICommandAddress child = entry.getValue(); ICommandAddress child = entry.getValue();
registerToMap(child, map); registerToMap(child, map);
} }
} }
public static void unregisterChildenFromMap(ICommandAddress tree, Map<String, Command> map) { public static void unregisterChildenFromMap(ICommandAddress tree, Map<String, Command> map) {
for (Map.Entry<String, ? extends ICommandAddress> entry : tree.getChildren().entrySet()) { for (Map.Entry<String, ? extends ICommandAddress> entry : tree.getChildren().entrySet()) {
ICommandAddress child = entry.getValue(); ICommandAddress child = entry.getValue();
unregisterFromMap(child, map); unregisterFromMap(child, map);
} }
} }
*/ */
} }

View File

@@ -1,59 +1,59 @@
package io.dico.dicore.command.registration; package io.dico.dicore.command.registration;
import io.dico.dicore.Reflection; import io.dico.dicore.Reflection;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.SimpleCommandMap; import org.bukkit.command.SimpleCommandMap;
import org.bukkit.plugin.SimplePluginManager; import org.bukkit.plugin.SimplePluginManager;
import java.util.*; import java.util.*;
/** /**
* Provides access to bukkit's {@code Map<String, org.bukkit.command.Command>} command map. * Provides access to bukkit's {@code Map<String, org.bukkit.command.Command>} command map.
*/ */
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
public class CommandMap { public class CommandMap {
private static final Map<String, Command> commandMap = findCommandMap(); private static final Map<String, Command> commandMap = findCommandMap();
private CommandMap() { private CommandMap() {
} }
public static Map<String, Command> getCommandMap() { public static Map<String, Command> getCommandMap() {
return Objects.requireNonNull(commandMap); return Objects.requireNonNull(commandMap);
} }
public static boolean isAvailable() { public static boolean isAvailable() {
return commandMap != null; return commandMap != null;
} }
public static Command get(String key) { public static Command get(String key) {
return commandMap.get(key); return commandMap.get(key);
} }
public static void put(String key, Command command) { public static void put(String key, Command command) {
commandMap.put(key, command); commandMap.put(key, command);
} }
public static Collection<String> replace(Command command, Command replacement) { public static Collection<String> replace(Command command, Command replacement) {
List<String> result = new ArrayList<>(); List<String> result = new ArrayList<>();
for (Map.Entry<String, Command> entry : commandMap.entrySet()) { for (Map.Entry<String, Command> entry : commandMap.entrySet()) {
if (entry.getValue() == command) { if (entry.getValue() == command) {
entry.setValue(replacement); entry.setValue(replacement);
result.add(entry.getKey()); result.add(entry.getKey());
} }
} }
return result; return result;
} }
private static Map<String, Command> findCommandMap() { private static Map<String, Command> findCommandMap() {
try { try {
return Reflection.getFieldValue(SimpleCommandMap.class, "knownCommands", return Reflection.getFieldValue(SimpleCommandMap.class, "knownCommands",
Reflection.getFieldValue(SimplePluginManager.class, "commandMap", Bukkit.getPluginManager())); Reflection.getFieldValue(SimplePluginManager.class, "commandMap", Bukkit.getPluginManager()));
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
return null; return null;
} }
} }
} }

View File

@@ -1,27 +1,27 @@
package io.dico.dicore.command.registration.reflect; package io.dico.dicore.command.registration.reflect;
/** /**
* Thrown if an error occurs while 'parsing' a reflection command method * Thrown if an error occurs while 'parsing' a reflection command method
* Other errors can be thrown too in there that may not be directly relevant to a parsing error. * Other errors can be thrown too in there that may not be directly relevant to a parsing error.
*/ */
public class CommandParseException extends Exception { public class CommandParseException extends Exception {
public CommandParseException() { public CommandParseException() {
} }
public CommandParseException(String message) { public CommandParseException(String message) {
super(message); super(message);
} }
public CommandParseException(String message, Throwable cause) { public CommandParseException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
public CommandParseException(Throwable cause) { public CommandParseException(Throwable cause) {
super(cause); super(cause);
} }
public CommandParseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { public CommandParseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace); super(message, cause, enableSuppression, writableStackTrace);
} }
} }

View File

@@ -1,36 +1,36 @@
package io.dico.dicore.command.registration.reflect; package io.dico.dicore.command.registration.reflect;
import io.dico.dicore.command.ExecutionContext; import io.dico.dicore.command.ExecutionContext;
import java.lang.reflect.Method; import java.lang.reflect.Method;
public interface ICommandInterceptor { public interface ICommandInterceptor {
/** /**
* Get the receiver of the command, if applicable. * Get the receiver of the command, if applicable.
* A command has a receiver if its first parameter implements {@link ICommandReceiver} * A command has a receiver if its first parameter implements {@link ICommandReceiver}
* and its instance object implements this interface. * and its instance object implements this interface.
* *
* @param context the context of execution * @param context the context of execution
* @param target the method of the command * @param target the method of the command
* @param cmdName the name of the command * @param cmdName the name of the command
* @return the receiver * @return the receiver
*/ */
default ICommandReceiver getReceiver(ExecutionContext context, Method target, String cmdName) { default ICommandReceiver getReceiver(ExecutionContext context, Method target, String cmdName) {
return null; return null;
} }
/** /**
* If applicable, get the coroutine context to use in suspend functions (Kotlin only). * If applicable, get the coroutine context to use in suspend functions (Kotlin only).
* The return type is object to avoid depending on the kotlin runtime. * The return type is object to avoid depending on the kotlin runtime.
* *
* @param context the context of execution * @param context the context of execution
* @param target the method of the command * @param target the method of the command
* @param cmdName the name of the command * @param cmdName the name of the command
* @return the coroutine context * @return the coroutine context
*/ */
default Object getCoroutineContext(ExecutionContext context, Method target, String cmdName) { default Object getCoroutineContext(ExecutionContext context, Method target, String cmdName) {
return null; return null;
} }
} }

View File

@@ -1,5 +1,5 @@
package io.dico.dicore.command.registration.reflect; package io.dico.dicore.command.registration.reflect;
public interface ICommandReceiver { public interface ICommandReceiver {
} }

View File

@@ -1,187 +1,187 @@
package io.dico.dicore.command.registration.reflect; package io.dico.dicore.command.registration.reflect;
import io.dico.dicore.command.*; import io.dico.dicore.command.*;
import io.dico.dicore.command.annotation.Cmd; import io.dico.dicore.command.annotation.Cmd;
import io.dico.dicore.command.annotation.GenerateCommands; import io.dico.dicore.command.annotation.GenerateCommands;
import io.dico.dicore.command.parameter.type.IParameterTypeSelector; import io.dico.dicore.command.parameter.type.IParameterTypeSelector;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
public final class ReflectiveCommand extends Command { public final class ReflectiveCommand extends Command {
private static final int continuationMask = 1 << 3; private static final int continuationMask = 1 << 3;
private final Cmd cmdAnnotation; private final Cmd cmdAnnotation;
private final Method method; private final Method method;
private final Object instance; private final Object instance;
private String[] parameterOrder; private String[] parameterOrder;
// hasContinuation | hasContext | hasSender | hasReceiver // hasContinuation | hasContext | hasSender | hasReceiver
private final int flags; private final int flags;
ReflectiveCommand(IParameterTypeSelector selector, Method method, Object instance) throws CommandParseException { ReflectiveCommand(IParameterTypeSelector selector, Method method, Object instance) throws CommandParseException {
if (!method.isAnnotationPresent(Cmd.class)) { if (!method.isAnnotationPresent(Cmd.class)) {
throw new CommandParseException("No @Cmd present for the method " + method.toGenericString()); throw new CommandParseException("No @Cmd present for the method " + method.toGenericString());
} }
cmdAnnotation = method.getAnnotation(Cmd.class); cmdAnnotation = method.getAnnotation(Cmd.class);
java.lang.reflect.Parameter[] parameters = method.getParameters(); java.lang.reflect.Parameter[] parameters = method.getParameters();
if (!method.isAccessible()) try { if (!method.isAccessible()) try {
method.setAccessible(true); method.setAccessible(true);
} catch (Exception ex) { } catch (Exception ex) {
throw new CommandParseException("Failed to make method accessible"); throw new CommandParseException("Failed to make method accessible");
} }
if (!Modifier.isStatic(method.getModifiers())) { if (!Modifier.isStatic(method.getModifiers())) {
if (instance == null) { if (instance == null) {
try { try {
instance = method.getDeclaringClass().newInstance(); instance = method.getDeclaringClass().newInstance();
} catch (Exception ex) { } catch (Exception ex) {
throw new CommandParseException("No instance given for instance method, and failed to create new instance", ex); throw new CommandParseException("No instance given for instance method, and failed to create new instance", ex);
} }
} else if (!method.getDeclaringClass().isInstance(instance)) { } else if (!method.getDeclaringClass().isInstance(instance)) {
throw new CommandParseException("Given instance is not an instance of the method's declaring class"); throw new CommandParseException("Given instance is not an instance of the method's declaring class");
} }
} }
this.method = method; this.method = method;
this.instance = instance; this.instance = instance;
this.flags = ReflectiveRegistration.parseCommandAttributes(selector, method, this, parameters); this.flags = ReflectiveRegistration.parseCommandAttributes(selector, method, this, parameters);
} }
public Method getMethod() { public Method getMethod() {
return method; return method;
} }
public Object getInstance() { public Object getInstance() {
return instance; return instance;
} }
public String getCmdName() { return cmdAnnotation.value(); } public String getCmdName() { return cmdAnnotation.value(); }
void setParameterOrder(String[] parameterOrder) { void setParameterOrder(String[] parameterOrder) {
this.parameterOrder = parameterOrder; this.parameterOrder = parameterOrder;
} }
ICommandAddress getAddress() { ICommandAddress getAddress() {
ChildCommandAddress result = new ChildCommandAddress(); ChildCommandAddress result = new ChildCommandAddress();
result.setCommand(this); result.setCommand(this);
Cmd cmd = cmdAnnotation; Cmd cmd = cmdAnnotation;
result.getNames().add(cmd.value()); result.getNames().add(cmd.value());
for (String alias : cmd.aliases()) { for (String alias : cmd.aliases()) {
result.getNames().add(alias); result.getNames().add(alias);
} }
result.finalizeNames(); result.finalizeNames();
GenerateCommands generateCommands = method.getAnnotation(GenerateCommands.class); GenerateCommands generateCommands = method.getAnnotation(GenerateCommands.class);
if (generateCommands != null) { if (generateCommands != null) {
ReflectiveRegistration.generateCommands(result, generateCommands.value()); ReflectiveRegistration.generateCommands(result, generateCommands.value());
} }
return result; return result;
} }
@Override @Override
public String execute(CommandSender sender, ExecutionContext context) throws CommandException { public String execute(CommandSender sender, ExecutionContext context) throws CommandException {
String[] parameterOrder = this.parameterOrder; String[] parameterOrder = this.parameterOrder;
int extraArgumentCount = Integer.bitCount(flags); int extraArgumentCount = Integer.bitCount(flags);
int parameterStartIndex = Integer.bitCount(flags & ~continuationMask); int parameterStartIndex = Integer.bitCount(flags & ~continuationMask);
Object[] args = new Object[parameterOrder.length + extraArgumentCount]; Object[] args = new Object[parameterOrder.length + extraArgumentCount];
int i = 0; int i = 0;
int mask = 1; int mask = 1;
if ((flags & mask) != 0) { if ((flags & mask) != 0) {
// Has receiver // Has receiver
try { try {
args[i++] = ((ICommandInterceptor) instance).getReceiver(context, method, getCmdName()); args[i++] = ((ICommandInterceptor) instance).getReceiver(context, method, getCmdName());
} catch (Exception ex) { } catch (Exception ex) {
handleException(ex); handleException(ex);
return null; // unreachable return null; // unreachable
} }
} }
mask <<= 1; mask <<= 1;
if ((flags & mask) != 0) { if ((flags & mask) != 0) {
// Has sender // Has sender
args[i++] = sender; args[i++] = sender;
} }
mask <<= 1; mask <<= 1;
if ((flags & mask) != 0) { if ((flags & mask) != 0) {
// Has context // Has context
args[i++] = context; args[i++] = context;
} }
mask <<= 1; mask <<= 1;
if ((flags & mask) != 0) { if ((flags & mask) != 0) {
// Has continuation // Has continuation
extraArgumentCount--; extraArgumentCount--;
} }
for (int n = args.length; i < n; i++) { for (int n = args.length; i < n; i++) {
args[i] = context.get(parameterOrder[i - extraArgumentCount]); args[i] = context.get(parameterOrder[i - extraArgumentCount]);
} }
if ((flags & mask) != 0) { if ((flags & mask) != 0) {
// Since it has continuation, call as coroutine // Since it has continuation, call as coroutine
return callAsCoroutine(context, args); return callAsCoroutine(context, args);
} }
return callSynchronously(args); return callSynchronously(args);
} }
private boolean isSuspendFunction() { private boolean isSuspendFunction() {
try { try {
return KotlinReflectiveRegistrationKt.isSuspendFunction(method); return KotlinReflectiveRegistrationKt.isSuspendFunction(method);
} catch (Throwable ex) { } catch (Throwable ex) {
return false; return false;
} }
} }
public String callSynchronously(Object[] args) throws CommandException { public String callSynchronously(Object[] args) throws CommandException {
try { try {
return getResult(method.invoke(instance, args), null); return getResult(method.invoke(instance, args), null);
} catch (Exception ex) { } catch (Exception ex) {
return getResult(null, ex); return getResult(null, ex);
} }
} }
public static String getResult(Object returned, Exception ex) throws CommandException { public static String getResult(Object returned, Exception ex) throws CommandException {
if (ex != null) { if (ex != null) {
handleException(ex); handleException(ex);
return null; // unreachable return null; // unreachable
} }
if (returned instanceof String) { if (returned instanceof String) {
return (String) returned; return (String) returned;
} }
return null; return null;
} }
public static void handleException(Exception ex) throws CommandException { public static void handleException(Exception ex) throws CommandException {
if (ex instanceof InvocationTargetException) { if (ex instanceof InvocationTargetException) {
if (ex.getCause() instanceof CommandException) { if (ex.getCause() instanceof CommandException) {
throw (CommandException) ex.getCause(); throw (CommandException) ex.getCause();
} }
ex.printStackTrace(); ex.printStackTrace();
throw new CommandException("An internal error occurred while executing this command.", ex); throw new CommandException("An internal error occurred while executing this command.", ex);
} }
if (ex instanceof CommandException) { if (ex instanceof CommandException) {
throw (CommandException) ex; throw (CommandException) ex;
} }
ex.printStackTrace(); ex.printStackTrace();
throw new CommandException("An internal error occurred while executing this command.", ex); throw new CommandException("An internal error occurred while executing this command.", ex);
} }
private String callAsCoroutine(ExecutionContext context, Object[] args) { private String callAsCoroutine(ExecutionContext context, Object[] args) {
return KotlinReflectiveRegistrationKt.callAsCoroutine(this, (ICommandInterceptor) instance, context, args); return KotlinReflectiveRegistrationKt.callAsCoroutine(this, (ICommandInterceptor) instance, context, args);
} }
} }

View File

@@ -1,415 +1,415 @@
package io.dico.dicore.command.registration.reflect; package io.dico.dicore.command.registration.reflect;
import io.dico.dicore.command.*; import io.dico.dicore.command.*;
import io.dico.dicore.command.annotation.*; import io.dico.dicore.command.annotation.*;
import io.dico.dicore.command.annotation.GroupMatchedCommands.GroupEntry; import io.dico.dicore.command.annotation.GroupMatchedCommands.GroupEntry;
import io.dico.dicore.command.parameter.Parameter; import io.dico.dicore.command.parameter.Parameter;
import io.dico.dicore.command.parameter.ParameterList; import io.dico.dicore.command.parameter.ParameterList;
import io.dico.dicore.command.parameter.type.IParameterTypeSelector; import io.dico.dicore.command.parameter.type.IParameterTypeSelector;
import io.dico.dicore.command.parameter.type.MapBasedParameterTypeSelector; import io.dico.dicore.command.parameter.type.MapBasedParameterTypeSelector;
import io.dico.dicore.command.parameter.type.ParameterType; import io.dico.dicore.command.parameter.type.ParameterType;
import io.dico.dicore.command.parameter.type.ParameterTypes; import io.dico.dicore.command.parameter.type.ParameterTypes;
import io.dico.dicore.command.predef.PredefinedCommand; import io.dico.dicore.command.predef.PredefinedCommand;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
/** /**
* Takes care of turning a reflection {@link Method} into a command and more. * Takes care of turning a reflection {@link Method} into a command and more.
*/ */
public class ReflectiveRegistration { public class ReflectiveRegistration {
/** /**
* This object provides names of the parameters. * This object provides names of the parameters.
* Oddly, the AnnotationParanamer extensions require a 'fallback' paranamer to function properly without * Oddly, the AnnotationParanamer extensions require a 'fallback' paranamer to function properly without
* requiring ALL parameters to have that flag. This is weird because it should just use the AdaptiveParanamer on an upper level to * requiring ALL parameters to have that flag. This is weird because it should just use the AdaptiveParanamer on an upper level to
* determine the name of each individual flag. Oddly this isn't how it works, so the fallback works the same way as the AdaptiveParanamer does. * determine the name of each individual flag. Oddly this isn't how it works, so the fallback works the same way as the AdaptiveParanamer does.
* It's just linked instead of using an array for that part. Then we can use an AdaptiveParanamer for the latest fallback, to get bytecode names * It's just linked instead of using an array for that part. Then we can use an AdaptiveParanamer for the latest fallback, to get bytecode names
* or, finally, to get the Jvm-provided parameter names. * or, finally, to get the Jvm-provided parameter names.
*/ */
//private static final Paranamer paranamer = new CachingParanamer(new BytecodeReadingParanamer()); //private static final Paranamer paranamer = new CachingParanamer(new BytecodeReadingParanamer());
@SuppressWarnings("StatementWithEmptyBody") @SuppressWarnings("StatementWithEmptyBody")
private static String[] lookupParameterNames(Method method, java.lang.reflect.Parameter[] parameters, int start) { private static String[] lookupParameterNames(Method method, java.lang.reflect.Parameter[] parameters, int start) {
int n = parameters.length; int n = parameters.length;
String[] out = new String[n - start]; String[] out = new String[n - start];
//String[] bytecode; //String[] bytecode;
//try { //try {
// bytecode = paranamer.lookupParameterNames(method, false); // bytecode = paranamer.lookupParameterNames(method, false);
//} catch (Exception ex) { //} catch (Exception ex) {
// bytecode = new String[0]; // bytecode = new String[0];
// System.err.println("ReflectiveRegistration.lookupParameterNames failed to read bytecode"); // System.err.println("ReflectiveRegistration.lookupParameterNames failed to read bytecode");
// //ex.printStackTrace(); // //ex.printStackTrace();
//} //}
//int bn = bytecode.length; //int bn = bytecode.length;
for (int i = start; i < n; i++) { for (int i = start; i < n; i++) {
java.lang.reflect.Parameter parameter = parameters[i]; java.lang.reflect.Parameter parameter = parameters[i];
Flag flag = parameter.getAnnotation(Flag.class); Flag flag = parameter.getAnnotation(Flag.class);
NamedArg namedArg = parameter.getAnnotation(NamedArg.class); NamedArg namedArg = parameter.getAnnotation(NamedArg.class);
boolean isFlag = flag != null; boolean isFlag = flag != null;
String name; String name;
if (namedArg != null && !(name = namedArg.value()).isEmpty()) { if (namedArg != null && !(name = namedArg.value()).isEmpty()) {
} else if (isFlag && !(name = flag.value()).isEmpty()) { } else if (isFlag && !(name = flag.value()).isEmpty()) {
//} else if (i < bn && (name = bytecode[i]) != null && !name.isEmpty()) { //} else if (i < bn && (name = bytecode[i]) != null && !name.isEmpty()) {
} else { } else {
name = parameter.getName(); name = parameter.getName();
} }
if (isFlag) { if (isFlag) {
name = '-' + name; name = '-' + name;
} else { } else {
int idx = 0; int idx = 0;
while (name.startsWith("-", idx)) { while (name.startsWith("-", idx)) {
idx++; idx++;
} }
name = name.substring(idx); name = name.substring(idx);
} }
out[i - start] = name; out[i - start] = name;
} }
return out; return out;
} }
public static void parseCommandGroup(ICommandAddress address, Class<?> clazz, Object instance) throws CommandParseException { public static void parseCommandGroup(ICommandAddress address, Class<?> clazz, Object instance) throws CommandParseException {
parseCommandGroup(address, ParameterTypes.getSelector(), clazz, instance); parseCommandGroup(address, ParameterTypes.getSelector(), clazz, instance);
} }
public static void parseCommandGroup(ICommandAddress address, IParameterTypeSelector selector, Class<?> clazz, Object instance) throws CommandParseException { public static void parseCommandGroup(ICommandAddress address, IParameterTypeSelector selector, Class<?> clazz, Object instance) throws CommandParseException {
boolean requireStatic = instance == null; boolean requireStatic = instance == null;
if (!requireStatic && !clazz.isInstance(instance)) { if (!requireStatic && !clazz.isInstance(instance)) {
throw new CommandParseException(); throw new CommandParseException();
} }
List<Method> methods = new LinkedList<>(Arrays.asList(clazz.getDeclaredMethods())); List<Method> methods = new LinkedList<>(Arrays.asList(clazz.getDeclaredMethods()));
Iterator<Method> it = methods.iterator(); Iterator<Method> it = methods.iterator();
for (Method method; it.hasNext(); ) { for (Method method; it.hasNext(); ) {
method = it.next(); method = it.next();
if (requireStatic && !Modifier.isStatic(method.getModifiers())) { if (requireStatic && !Modifier.isStatic(method.getModifiers())) {
it.remove(); it.remove();
continue; continue;
} }
if (method.isAnnotationPresent(CmdParamType.class)) { if (method.isAnnotationPresent(CmdParamType.class)) {
it.remove(); it.remove();
if (method.getReturnType() != ParameterType.class || method.getParameterCount() != 0) { if (method.getReturnType() != ParameterType.class || method.getParameterCount() != 0) {
throw new CommandParseException("Invalid CmdParamType method: must return ParameterType and take no arguments"); throw new CommandParseException("Invalid CmdParamType method: must return ParameterType and take no arguments");
} }
ParameterType<?, ?> type; ParameterType<?, ?> type;
try { try {
Object inst = Modifier.isStatic(method.getModifiers()) ? null : instance; Object inst = Modifier.isStatic(method.getModifiers()) ? null : instance;
type = (ParameterType<?, ?>) method.invoke(inst); type = (ParameterType<?, ?>) method.invoke(inst);
Objects.requireNonNull(type, "ParameterType returned is null"); Objects.requireNonNull(type, "ParameterType returned is null");
} catch (Exception ex) { } catch (Exception ex) {
throw new CommandParseException("Error occurred whilst getting ParameterType from CmdParamType method '" + method.toGenericString() + "'", ex); throw new CommandParseException("Error occurred whilst getting ParameterType from CmdParamType method '" + method.toGenericString() + "'", ex);
} }
if (selector == ParameterTypes.getSelector()) { if (selector == ParameterTypes.getSelector()) {
selector = new MapBasedParameterTypeSelector(true); selector = new MapBasedParameterTypeSelector(true);
} }
selector.addType(method.getAnnotation(CmdParamType.class).infolessAlias(), type); selector.addType(method.getAnnotation(CmdParamType.class).infolessAlias(), type);
} }
} }
GroupMatcherCache groupMatcherCache = new GroupMatcherCache(clazz, address); GroupMatcherCache groupMatcherCache = new GroupMatcherCache(clazz, address);
for (Method method : methods) { for (Method method : methods) {
if (method.isAnnotationPresent(Cmd.class)) { if (method.isAnnotationPresent(Cmd.class)) {
ICommandAddress parsed = parseCommandMethod(selector, method, instance); ICommandAddress parsed = parseCommandMethod(selector, method, instance);
groupMatcherCache.getGroupFor(method).addChild(parsed); groupMatcherCache.getGroupFor(method).addChild(parsed);
} }
} }
} }
private static final class GroupMatcherCache { private static final class GroupMatcherCache {
private ModifiableCommandAddress groupRootAddress; private ModifiableCommandAddress groupRootAddress;
private GroupEntry[] matchEntries; private GroupEntry[] matchEntries;
private Pattern[] patterns; private Pattern[] patterns;
private ModifiableCommandAddress[] addresses; private ModifiableCommandAddress[] addresses;
GroupMatcherCache(Class<?> clazz, ICommandAddress groupRootAddress) throws CommandParseException { GroupMatcherCache(Class<?> clazz, ICommandAddress groupRootAddress) throws CommandParseException {
this.groupRootAddress = (ModifiableCommandAddress) groupRootAddress; this.groupRootAddress = (ModifiableCommandAddress) groupRootAddress;
GroupMatchedCommands groupMatchedCommands = clazz.getAnnotation(GroupMatchedCommands.class); GroupMatchedCommands groupMatchedCommands = clazz.getAnnotation(GroupMatchedCommands.class);
GroupEntry[] matchEntries = groupMatchedCommands == null ? new GroupEntry[0] : groupMatchedCommands.value(); GroupEntry[] matchEntries = groupMatchedCommands == null ? new GroupEntry[0] : groupMatchedCommands.value();
Pattern[] patterns = new Pattern[matchEntries.length]; Pattern[] patterns = new Pattern[matchEntries.length];
for (int i = 0; i < matchEntries.length; i++) { for (int i = 0; i < matchEntries.length; i++) {
GroupEntry matchEntry = matchEntries[i]; GroupEntry matchEntry = matchEntries[i];
if (matchEntry.group().isEmpty() || matchEntry.regex().isEmpty()) { if (matchEntry.group().isEmpty() || matchEntry.regex().isEmpty()) {
throw new CommandParseException("Empty group or regex in GroupMatchedCommands entry"); throw new CommandParseException("Empty group or regex in GroupMatchedCommands entry");
} }
try { try {
patterns[i] = Pattern.compile(matchEntry.regex()); patterns[i] = Pattern.compile(matchEntry.regex());
} catch (PatternSyntaxException ex) { } catch (PatternSyntaxException ex) {
throw new CommandParseException(ex); throw new CommandParseException(ex);
} }
} }
this.matchEntries = matchEntries; this.matchEntries = matchEntries;
this.patterns = patterns; this.patterns = patterns;
this.addresses = new ModifiableCommandAddress[this.matchEntries.length]; this.addresses = new ModifiableCommandAddress[this.matchEntries.length];
} }
ModifiableCommandAddress getGroupFor(Method method) { ModifiableCommandAddress getGroupFor(Method method) {
String name = method.getName(); String name = method.getName();
GroupEntry[] matchEntries = this.matchEntries; GroupEntry[] matchEntries = this.matchEntries;
Pattern[] patterns = this.patterns; Pattern[] patterns = this.patterns;
ModifiableCommandAddress[] addresses = this.addresses; ModifiableCommandAddress[] addresses = this.addresses;
for (int i = 0; i < matchEntries.length; i++) { for (int i = 0; i < matchEntries.length; i++) {
GroupEntry matchEntry = matchEntries[i]; GroupEntry matchEntry = matchEntries[i];
if (patterns[i].matcher(name).matches()) { if (patterns[i].matcher(name).matches()) {
if (addresses[i] == null) { if (addresses[i] == null) {
ChildCommandAddress placeholder = new ChildCommandAddress(); ChildCommandAddress placeholder = new ChildCommandAddress();
placeholder.setupAsPlaceholder(matchEntry.group(), matchEntry.groupAliases()); placeholder.setupAsPlaceholder(matchEntry.group(), matchEntry.groupAliases());
addresses[i] = placeholder; addresses[i] = placeholder;
groupRootAddress.addChild(placeholder); groupRootAddress.addChild(placeholder);
generateCommands(placeholder, matchEntry.generatedCommands()); generateCommands(placeholder, matchEntry.generatedCommands());
setDescription(placeholder, matchEntry.description(), matchEntry.shortDescription()); setDescription(placeholder, matchEntry.description(), matchEntry.shortDescription());
} }
return addresses[i]; return addresses[i];
} }
} }
return groupRootAddress; return groupRootAddress;
} }
} }
public static ICommandAddress parseCommandMethod(IParameterTypeSelector selector, Method method, Object instance) throws CommandParseException { public static ICommandAddress parseCommandMethod(IParameterTypeSelector selector, Method method, Object instance) throws CommandParseException {
return new ReflectiveCommand(selector, method, instance).getAddress(); return new ReflectiveCommand(selector, method, instance).getAddress();
} }
static int parseCommandAttributes(IParameterTypeSelector selector, Method method, ReflectiveCommand command, java.lang.reflect.Parameter[] parameters) throws CommandParseException { static int parseCommandAttributes(IParameterTypeSelector selector, Method method, ReflectiveCommand command, java.lang.reflect.Parameter[] parameters) throws CommandParseException {
ParameterList list = command.getParameterList(); ParameterList list = command.getParameterList();
boolean hasReceiverParameter = false; boolean hasReceiverParameter = false;
boolean hasSenderParameter = false; boolean hasSenderParameter = false;
boolean hasContextParameter = false; boolean hasContextParameter = false;
boolean hasContinuationParameter = false; boolean hasContinuationParameter = false;
int start = 0; int start = 0;
int end = parameters.length; int end = parameters.length;
Class<?> senderParameterType = null; Class<?> senderParameterType = null;
if (parameters.length > start if (parameters.length > start
&& command.getInstance() instanceof ICommandInterceptor && command.getInstance() instanceof ICommandInterceptor
&& ICommandReceiver.class.isAssignableFrom(parameters[start].getType())) { && ICommandReceiver.class.isAssignableFrom(parameters[start].getType())) {
hasReceiverParameter = true; hasReceiverParameter = true;
start++; start++;
} }
if (parameters.length > start && CommandSender.class.isAssignableFrom(senderParameterType = parameters[start].getType())) { if (parameters.length > start && CommandSender.class.isAssignableFrom(senderParameterType = parameters[start].getType())) {
hasSenderParameter = true; hasSenderParameter = true;
start++; start++;
} }
if (parameters.length > start && parameters[start].getType() == ExecutionContext.class) { if (parameters.length > start && parameters[start].getType() == ExecutionContext.class) {
hasContextParameter = true; hasContextParameter = true;
start++; start++;
} }
if (parameters.length > start && parameters[end - 1].getType().getName().equals("kotlin.coroutines.Continuation")) { if (parameters.length > start && parameters[end - 1].getType().getName().equals("kotlin.coroutines.Continuation")) {
hasContinuationParameter = true; hasContinuationParameter = true;
end--; end--;
} }
String[] parameterNames = lookupParameterNames(method, parameters, start); String[] parameterNames = lookupParameterNames(method, parameters, start);
for (int i = start, n = end; i < n; i++) { for (int i = start, n = end; i < n; i++) {
Parameter<?, ?> parameter = parseParameter(selector, method, parameters[i], parameterNames[i - start]); Parameter<?, ?> parameter = parseParameter(selector, method, parameters[i], parameterNames[i - start]);
list.addParameter(parameter); list.addParameter(parameter);
} }
command.setParameterOrder(hasContinuationParameter ? Arrays.copyOfRange(parameterNames, 0, parameterNames.length - 1) : parameterNames); command.setParameterOrder(hasContinuationParameter ? Arrays.copyOfRange(parameterNames, 0, parameterNames.length - 1) : parameterNames);
RequirePermissions cmdPermissions = method.getAnnotation(RequirePermissions.class); RequirePermissions cmdPermissions = method.getAnnotation(RequirePermissions.class);
if (cmdPermissions != null) { if (cmdPermissions != null) {
for (String permission : cmdPermissions.value()) { for (String permission : cmdPermissions.value()) {
command.addContextFilter(IContextFilter.permission(permission)); command.addContextFilter(IContextFilter.permission(permission));
} }
if (cmdPermissions.inherit()) { if (cmdPermissions.inherit()) {
command.addContextFilter(IContextFilter.INHERIT_PERMISSIONS); command.addContextFilter(IContextFilter.INHERIT_PERMISSIONS);
} }
} else { } else {
command.addContextFilter(IContextFilter.INHERIT_PERMISSIONS); command.addContextFilter(IContextFilter.INHERIT_PERMISSIONS);
} }
RequireParameters reqPar = method.getAnnotation(RequireParameters.class); RequireParameters reqPar = method.getAnnotation(RequireParameters.class);
if (reqPar != null) { if (reqPar != null) {
list.setRequiredCount(reqPar.value() < 0 ? Integer.MAX_VALUE : reqPar.value()); list.setRequiredCount(reqPar.value() < 0 ? Integer.MAX_VALUE : reqPar.value());
} else { } else {
list.setRequiredCount(list.getIndexedParameters().size()); list.setRequiredCount(list.getIndexedParameters().size());
} }
/* /*
PreprocessArgs preprocessArgs = method.getAnnotation(PreprocessArgs.class); PreprocessArgs preprocessArgs = method.getAnnotation(PreprocessArgs.class);
if (preprocessArgs != null) { if (preprocessArgs != null) {
IArgumentPreProcessor preProcessor = IArgumentPreProcessor.mergeOnTokens(preprocessArgs.tokens(), preprocessArgs.escapeChar()); IArgumentPreProcessor preProcessor = IArgumentPreProcessor.mergeOnTokens(preprocessArgs.tokens(), preprocessArgs.escapeChar());
list.setArgumentPreProcessor(preProcessor); list.setArgumentPreProcessor(preProcessor);
}*/ }*/
Desc desc = method.getAnnotation(Desc.class); Desc desc = method.getAnnotation(Desc.class);
if (desc != null) { if (desc != null) {
String[] array = desc.value(); String[] array = desc.value();
if (array.length == 0) { if (array.length == 0) {
command.setDescription(desc.shortVersion()); command.setDescription(desc.shortVersion());
} else { } else {
command.setDescription(array); command.setDescription(array);
} }
} else { } else {
command.setDescription(); command.setDescription();
} }
if (hasSenderParameter && Player.class.isAssignableFrom(senderParameterType)) { if (hasSenderParameter && Player.class.isAssignableFrom(senderParameterType)) {
command.addContextFilter(IContextFilter.PLAYER_ONLY); command.addContextFilter(IContextFilter.PLAYER_ONLY);
} else if (hasSenderParameter && ConsoleCommandSender.class.isAssignableFrom(senderParameterType)) { } else if (hasSenderParameter && ConsoleCommandSender.class.isAssignableFrom(senderParameterType)) {
command.addContextFilter(IContextFilter.CONSOLE_ONLY); command.addContextFilter(IContextFilter.CONSOLE_ONLY);
} else if (method.isAnnotationPresent(RequirePlayer.class)) { } else if (method.isAnnotationPresent(RequirePlayer.class)) {
command.addContextFilter(IContextFilter.PLAYER_ONLY); command.addContextFilter(IContextFilter.PLAYER_ONLY);
} else if (method.isAnnotationPresent(RequireConsole.class)) { } else if (method.isAnnotationPresent(RequireConsole.class)) {
command.addContextFilter(IContextFilter.CONSOLE_ONLY); command.addContextFilter(IContextFilter.CONSOLE_ONLY);
} }
list.setRepeatFinalParameter(parameters.length > start && parameters[parameters.length - 1].isVarArgs()); list.setRepeatFinalParameter(parameters.length > start && parameters[parameters.length - 1].isVarArgs());
list.setFinalParameterMayBeFlag(true); list.setFinalParameterMayBeFlag(true);
int flags = 0; int flags = 0;
if (hasContinuationParameter) flags |= 1; if (hasContinuationParameter) flags |= 1;
flags <<= 1; flags <<= 1;
if (hasContextParameter) flags |= 1; if (hasContextParameter) flags |= 1;
flags <<= 1; flags <<= 1;
if (hasSenderParameter) flags |= 1; if (hasSenderParameter) flags |= 1;
flags <<= 1; flags <<= 1;
if (hasReceiverParameter) flags |= 1; if (hasReceiverParameter) flags |= 1;
return flags; return flags;
} }
public static int parseCommandAttributes(IParameterTypeSelector selector, Method method, ReflectiveCommand command) throws CommandParseException { public static int parseCommandAttributes(IParameterTypeSelector selector, Method method, ReflectiveCommand command) throws CommandParseException {
return parseCommandAttributes(selector, method, command, method.getParameters()); return parseCommandAttributes(selector, method, command, method.getParameters());
} }
public static Parameter<?, ?> parseParameter(IParameterTypeSelector selector, Method method, java.lang.reflect.Parameter parameter, String name) throws CommandParseException { public static Parameter<?, ?> parseParameter(IParameterTypeSelector selector, Method method, java.lang.reflect.Parameter parameter, String name) throws CommandParseException {
Class<?> type = parameter.getType(); Class<?> type = parameter.getType();
if (parameter.isVarArgs()) { if (parameter.isVarArgs()) {
type = type.getComponentType(); type = type.getComponentType();
} }
Annotation[] annotations = parameter.getAnnotations(); Annotation[] annotations = parameter.getAnnotations();
Flag flag = null; Flag flag = null;
Annotation typeAnnotation = null; Annotation typeAnnotation = null;
Desc desc = null; Desc desc = null;
for (Annotation annotation : annotations) { for (Annotation annotation : annotations) {
//noinspection StatementWithEmptyBody //noinspection StatementWithEmptyBody
if (annotation instanceof NamedArg) { if (annotation instanceof NamedArg) {
// do nothing // do nothing
} else if (annotation instanceof Flag) { } else if (annotation instanceof Flag) {
if (flag != null) { if (flag != null) {
throw new CommandParseException("Multiple flags for the same parameter"); throw new CommandParseException("Multiple flags for the same parameter");
} }
flag = (Flag) annotation; flag = (Flag) annotation;
} else if (annotation instanceof Desc) { } else if (annotation instanceof Desc) {
if (desc != null) { if (desc != null) {
throw new CommandParseException("Multiple descriptions for the same parameter"); throw new CommandParseException("Multiple descriptions for the same parameter");
} }
desc = (Desc) annotation; desc = (Desc) annotation;
} else { } else {
if (typeAnnotation != null) { if (typeAnnotation != null) {
throw new CommandParseException("Multiple parameter type annotations for the same parameter"); throw new CommandParseException("Multiple parameter type annotations for the same parameter");
} }
typeAnnotation = annotation; typeAnnotation = annotation;
} }
} }
if (flag == null && name.startsWith("-")) { if (flag == null && name.startsWith("-")) {
throw new CommandParseException("Non-flag parameter's name starts with -"); throw new CommandParseException("Non-flag parameter's name starts with -");
} else if (flag != null && !name.startsWith("-")) { } else if (flag != null && !name.startsWith("-")) {
throw new CommandParseException("Flag parameter's name doesn't start with -"); throw new CommandParseException("Flag parameter's name doesn't start with -");
} }
ParameterType<Object, Object> parameterType = selector.selectAny(type, typeAnnotation == null ? null : typeAnnotation.getClass()); ParameterType<Object, Object> parameterType = selector.selectAny(type, typeAnnotation == null ? null : typeAnnotation.getClass());
if (parameterType == null) { if (parameterType == null) {
throw new CommandParseException("IParameter type not found for parameter " + name + " in method " + method.toString()); throw new CommandParseException("IParameter type not found for parameter " + name + " in method " + method.toString());
} }
Object parameterInfo; Object parameterInfo;
if (typeAnnotation == null) { if (typeAnnotation == null) {
parameterInfo = null; parameterInfo = null;
} else try { } else try {
parameterInfo = parameterType.getParameterConfig() == null ? null : parameterType.getParameterConfig().getParameterInfo(typeAnnotation); parameterInfo = parameterType.getParameterConfig() == null ? null : parameterType.getParameterConfig().getParameterInfo(typeAnnotation);
} catch (Exception ex) { } catch (Exception ex) {
throw new CommandParseException("Invalid parameter config", ex); throw new CommandParseException("Invalid parameter config", ex);
} }
String descString = desc == null ? null : CommandAnnotationUtils.getShortDescription(desc); String descString = desc == null ? null : CommandAnnotationUtils.getShortDescription(desc);
try { try {
//noinspection unchecked //noinspection unchecked
String flagPermission = flag == null || flag.permission().isEmpty() ? null : flag.permission(); String flagPermission = flag == null || flag.permission().isEmpty() ? null : flag.permission();
return new Parameter<>(name, descString, parameterType, parameterInfo, type.isPrimitive(), name.startsWith("-"), flagPermission); return new Parameter<>(name, descString, parameterType, parameterInfo, type.isPrimitive(), name.startsWith("-"), flagPermission);
} catch (Exception ex) { } catch (Exception ex) {
throw new CommandParseException("Invalid parameter", ex); throw new CommandParseException("Invalid parameter", ex);
} }
} }
public static void generateCommands(ICommandAddress address, String[] input) { public static void generateCommands(ICommandAddress address, String[] input) {
for (String value : input) { for (String value : input) {
Consumer<ICommandAddress> consumer = PredefinedCommand.getPredefinedCommandGenerator(value); Consumer<ICommandAddress> consumer = PredefinedCommand.getPredefinedCommandGenerator(value);
if (consumer == null) { if (consumer == null) {
System.out.println("[Command Warning] generated command '" + value + "' could not be found"); System.out.println("[Command Warning] generated command '" + value + "' could not be found");
} else { } else {
consumer.accept(address); consumer.accept(address);
} }
} }
} }
/* /*
Desired format Desired format
@Cmd({"tp", "tpto"}) @Cmd({"tp", "tpto"})
@RequirePermissions("teleport.self") @RequirePermissions("teleport.self")
public (static) String|void onCommand(Player sender, Player target, @Flag("force", permission = "teleport.self.force") boolean force) { public (static) String|void onCommand(Player sender, Player target, @Flag("force", permission = "teleport.self.force") boolean force) {
Validate.isTrue(force || !hasTpToggledOff(target), "Target has teleportation disabled. Use -force to ignore"); Validate.isTrue(force || !hasTpToggledOff(target), "Target has teleportation disabled. Use -force to ignore");
sender.teleport(target); sender.teleport(target);
//return //return
} }
parser needs to: parser needs to:
- see the @Cmd and create a CommandTree for it - see the @Cmd and create a CommandTree for it
- see that it must be a Player executing the command - see that it must be a Player executing the command
- add an indexed IParameter for a Player type - add an indexed IParameter for a Player type
- add a flag parameter named force, that consumes no arguments. - add a flag parameter named force, that consumes no arguments.
- see that setting the force flag requires a permission - see that setting the force flag requires a permission
*/ */
private static void setDescription(ICommandAddress address, String[] array, String shortVersion) { private static void setDescription(ICommandAddress address, String[] array, String shortVersion) {
if (!address.hasCommand()) { if (!address.hasCommand()) {
return; return;
} }
if (array.length == 0) { if (array.length == 0) {
address.getCommand().setDescription(shortVersion); address.getCommand().setDescription(shortVersion);
} else { } else {
address.getCommand().setDescription(array); address.getCommand().setDescription(array);
} }
} }
} }

View File

@@ -1,66 +1,66 @@
package io.dico.dicore.command.registration.reflect package io.dico.dicore.command.registration.reflect
import io.dico.dicore.command.* import io.dico.dicore.command.*
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
import kotlinx.coroutines.Deferred import kotlinx.coroutines.Deferred
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async import kotlinx.coroutines.async
import java.lang.reflect.Method import java.lang.reflect.Method
import java.util.concurrent.CancellationException import java.util.concurrent.CancellationException
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.intrinsics.intercepted import kotlin.coroutines.intrinsics.intercepted
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
import kotlin.reflect.jvm.kotlinFunction import kotlin.reflect.jvm.kotlinFunction
fun isSuspendFunction(method: Method): Boolean { fun isSuspendFunction(method: Method): Boolean {
val func = method.kotlinFunction ?: return false val func = method.kotlinFunction ?: return false
return func.isSuspend return func.isSuspend
} }
fun callAsCoroutine( fun callAsCoroutine(
command: ReflectiveCommand, command: ReflectiveCommand,
factory: ICommandInterceptor, factory: ICommandInterceptor,
context: ExecutionContext, context: ExecutionContext,
args: Array<Any?> args: Array<Any?>
): String? { ): String? {
val coroutineContext = factory.getCoroutineContext(context, command.method, command.cmdName) as CoroutineContext val coroutineContext = factory.getCoroutineContext(context, command.method, command.cmdName) as CoroutineContext
// UNDISPATCHED causes the handler to run until the first suspension point on the current thread, // UNDISPATCHED causes the handler to run until the first suspension point on the current thread,
// meaning command handlers that don't have suspension points will run completely synchronously. // meaning command handlers that don't have suspension points will run completely synchronously.
// Tasks that take time to compute should suspend the coroutine and resume on another thread. // Tasks that take time to compute should suspend the coroutine and resume on another thread.
val job = GlobalScope.async(context = coroutineContext, start = UNDISPATCHED) { val job = GlobalScope.async(context = coroutineContext, start = UNDISPATCHED) {
suspendCoroutineUninterceptedOrReturn<Any?> { cont -> suspendCoroutineUninterceptedOrReturn<Any?> { cont ->
command.method.invoke(command.instance, *args, cont.intercepted()) command.method.invoke(command.instance, *args, cont.intercepted())
} }
} }
if (job.isCompleted) { if (job.isCompleted) {
return job.getResult() return job.getResult()
} }
job.invokeOnCompletion { job.invokeOnCompletion {
val chatHandler = context.address.chatHandler val chatHandler = context.address.chatHandler
try { try {
val result = job.getResult() val result = job.getResult()
chatHandler.sendMessage(context.sender, EMessageType.RESULT, result) chatHandler.sendMessage(context.sender, EMessageType.RESULT, result)
} catch (ex: Throwable) { } catch (ex: Throwable) {
chatHandler.handleException(context.sender, context, ex) chatHandler.handleException(context.sender, context, ex)
} }
} }
return null return null
} }
@Throws(CommandException::class) @Throws(CommandException::class)
private fun Deferred<Any?>.getResult(): String? { private fun Deferred<Any?>.getResult(): String? {
getCompletionExceptionOrNull()?.let { ex -> getCompletionExceptionOrNull()?.let { ex ->
if (ex is CancellationException) { if (ex is CancellationException) {
System.err.println("An asynchronously dispatched command was cancelled unexpectedly") System.err.println("An asynchronously dispatched command was cancelled unexpectedly")
ex.printStackTrace() ex.printStackTrace()
throw CommandException("The command was cancelled unexpectedly (see console)") throw CommandException("The command was cancelled unexpectedly (see console)")
} }
if (ex is Exception) return ReflectiveCommand.getResult(null, ex) if (ex is Exception) return ReflectiveCommand.getResult(null, ex)
throw ex throw ex
} }
return ReflectiveCommand.getResult(getCompleted(), null) return ReflectiveCommand.getResult(getCompleted(), null)
} }

View File

@@ -1,73 +1,73 @@
package io.dico.dicore.command.example; package io.dico.dicore.command.example;
import io.dico.dicore.command.CommandBuilder; import io.dico.dicore.command.CommandBuilder;
import io.dico.dicore.command.CommandException; import io.dico.dicore.command.CommandException;
import io.dico.dicore.command.Validate; import io.dico.dicore.command.Validate;
import io.dico.dicore.command.annotation.Cmd; import io.dico.dicore.command.annotation.Cmd;
import io.dico.dicore.command.parameter.ArgumentBuffer; import io.dico.dicore.command.parameter.ArgumentBuffer;
import io.dico.dicore.command.parameter.Parameter; import io.dico.dicore.command.parameter.Parameter;
import io.dico.dicore.command.parameter.type.ParameterConfig; import io.dico.dicore.command.parameter.type.ParameterConfig;
import io.dico.dicore.command.parameter.type.ParameterType; import io.dico.dicore.command.parameter.type.ParameterType;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
public class ParameterInfoObjectExample { public class ParameterInfoObjectExample {
private @interface ParentPermission { private @interface ParentPermission {
String value(); String value();
} }
static class MyInfoObject { static class MyInfoObject {
public static final ParameterConfig<ParentPermission, MyInfoObject> config = new ParameterConfig<ParentPermission, MyInfoObject>() { public static final ParameterConfig<ParentPermission, MyInfoObject> config = new ParameterConfig<ParentPermission, MyInfoObject>() {
@Override @Override
protected MyInfoObject toParameterInfo(ParentPermission annotation) { protected MyInfoObject toParameterInfo(ParentPermission annotation) {
return new MyInfoObject(annotation.value()); return new MyInfoObject(annotation.value());
} }
}; };
private String permissionParent; private String permissionParent;
MyInfoObject(String permissionParent) { MyInfoObject(String permissionParent) {
this.permissionParent = permissionParent; this.permissionParent = permissionParent;
} }
public String getPermissionParent() { public String getPermissionParent() {
return permissionParent; return permissionParent;
} }
} }
static class MyParameterType extends ParameterType<String, MyInfoObject> { static class MyParameterType extends ParameterType<String, MyInfoObject> {
public MyParameterType() { public MyParameterType() {
super(String.class, MyInfoObject.config); super(String.class, MyInfoObject.config);
} }
@Override @Override
public String parse(Parameter<String, MyInfoObject> parameter, CommandSender sender, ArgumentBuffer buffer) throws CommandException { public String parse(Parameter<String, MyInfoObject> parameter, CommandSender sender, ArgumentBuffer buffer) throws CommandException {
String value = buffer.next(); String value = buffer.next();
MyInfoObject mio = parameter.getParamInfo(); MyInfoObject mio = parameter.getParamInfo();
if (mio != null) { if (mio != null) {
String permission = mio.permissionParent + "." + value; String permission = mio.permissionParent + "." + value;
Validate.isAuthorized(sender, permission); Validate.isAuthorized(sender, permission);
} }
return value; return value;
} }
} }
static class MyCommands { static class MyCommands {
@Cmd("test") @Cmd("test")
Object cmdTest(@ParentPermission("test.permission") String value) { Object cmdTest(@ParentPermission("test.permission") String value) {
return "You have permission to use the argument '" + value + "'!"; return "You have permission to use the argument '" + value + "'!";
} }
} }
static void main(String[] args) { static void main(String[] args) {
new CommandBuilder() new CommandBuilder()
.addParameterType(false, new MyParameterType()) .addParameterType(false, new MyParameterType())
.registerCommands(new MyCommands()); .registerCommands(new MyCommands());
} }
} }

View File

@@ -1,182 +1,182 @@
package io.dico.dicore; package io.dico.dicore;
public interface BitModifier { public interface BitModifier {
long mask(); long mask();
long get(long x); long get(long x);
long set(long x, long value); long set(long x, long value);
default int lowerBound() { default int lowerBound() {
return Long.numberOfTrailingZeros(mask()); return Long.numberOfTrailingZeros(mask());
} }
default int upperBound() { default int upperBound() {
return 64 - Long.numberOfLeadingZeros(mask()); return 64 - Long.numberOfLeadingZeros(mask());
} }
default int bitCount() { default int bitCount() {
return Long.bitCount(mask()); return Long.bitCount(mask());
} }
default boolean getBoolean(long x) { default boolean getBoolean(long x) {
return get(x) == 1; return get(x) == 1;
} }
default long setBoolean(long x, boolean value) { default long setBoolean(long x, boolean value) {
return set(x, value ? 1 : 0); return set(x, value ? 1 : 0);
} }
default int getInt(long x) { default int getInt(long x) {
return (int) (get(x) & 0xFFFFFFFFL); return (int) (get(x) & 0xFFFFFFFFL);
} }
default long setInt(long x, int value) { default long setInt(long x, int value) {
return set(x, value & 0xFFFFFFFFL); return set(x, value & 0xFFFFFFFFL);
} }
default short getShort(long x) { default short getShort(long x) {
return (short) (get(x) & 0xFFFFL); return (short) (get(x) & 0xFFFFL);
} }
default long setShort(long x, int value) { default long setShort(long x, int value) {
return set(x, value & 0xFFFFL); return set(x, value & 0xFFFFL);
} }
default byte getByte(long x) { default byte getByte(long x) {
return (byte) (get(x) & 0xFFL); return (byte) (get(x) & 0xFFL);
} }
default long setByte(long x, int value) { default long setByte(long x, int value) {
return set(x, value & 0xFFL); return set(x, value & 0xFFL);
} }
final class OfSingle implements BitModifier { final class OfSingle implements BitModifier {
private final long mask; private final long mask;
public OfSingle(int bit) { public OfSingle(int bit) {
if (bit < 0 || bit >= 64) { if (bit < 0 || bit >= 64) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
this.mask = 1L << bit; this.mask = 1L << bit;
} }
@Override @Override
public int bitCount() { public int bitCount() {
return 1; return 1;
} }
@Override @Override
public long mask() { public long mask() {
return mask; return mask;
} }
public boolean getBoolean(long x) { public boolean getBoolean(long x) {
return (x & mask) != 0; return (x & mask) != 0;
} }
public long setBoolean(long x, boolean value) { public long setBoolean(long x, boolean value) {
return value ? (x | mask) : (x & ~mask); return value ? (x | mask) : (x & ~mask);
} }
@Override @Override
public long get(long x) { public long get(long x) {
return getBoolean(x) ? 1 : 0; return getBoolean(x) ? 1 : 0;
} }
@Override @Override
public long set(long x, long value) { public long set(long x, long value) {
if (value < 0 || value > 1) { if (value < 0 || value > 1) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
return setBoolean(x, value == 1); return setBoolean(x, value == 1);
} }
} }
final class OfMultiple implements BitModifier { final class OfMultiple implements BitModifier {
private final int lowerBound; private final int lowerBound;
private final int bitCount; private final int bitCount;
private final long mask; private final long mask;
public OfMultiple(int lowerBound, int bitCount) { public OfMultiple(int lowerBound, int bitCount) {
int upperBound = lowerBound + bitCount; int upperBound = lowerBound + bitCount;
if (lowerBound < 0 || lowerBound >= 64 || upperBound < 1 || upperBound > 64 || upperBound < lowerBound) { if (lowerBound < 0 || lowerBound >= 64 || upperBound < 1 || upperBound > 64 || upperBound < lowerBound) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
this.lowerBound = lowerBound; this.lowerBound = lowerBound;
this.bitCount = bitCount; this.bitCount = bitCount;
this.mask = (Long.MIN_VALUE >> (bitCount - 1)) >>> (64 - bitCount - lowerBound); this.mask = (Long.MIN_VALUE >> (bitCount - 1)) >>> (64 - bitCount - lowerBound);
} }
@Override @Override
public int lowerBound() { public int lowerBound() {
return lowerBound; return lowerBound;
} }
@Override @Override
public int bitCount() { public int bitCount() {
return bitCount; return bitCount;
} }
@Override @Override
public int upperBound() { public int upperBound() {
return lowerBound + bitCount; return lowerBound + bitCount;
} }
@Override @Override
public long mask() { public long mask() {
return mask; return mask;
} }
@Override @Override
public long get(long x) { public long get(long x) {
return (x & mask) >>> lowerBound; return (x & mask) >>> lowerBound;
} }
@Override @Override
public long set(long x, long value) { public long set(long x, long value) {
return (x & ~mask) | ((value << lowerBound) & mask); return (x & ~mask) | ((value << lowerBound) & mask);
} }
} }
class Builder { class Builder {
int currentIndex; int currentIndex;
public int getCurrentIndex() { public int getCurrentIndex() {
return currentIndex; return currentIndex;
} }
public int getRemaining() { public int getRemaining() {
return 64 - currentIndex; return 64 - currentIndex;
} }
public OfSingle single() { public OfSingle single() {
checkAvailable(1); checkAvailable(1);
return new OfSingle(currentIndex++); return new OfSingle(currentIndex++);
} }
public BitModifier size(int size) { public BitModifier size(int size) {
if (size == 1) { if (size == 1) {
return single(); return single();
} }
checkAvailable(size); checkAvailable(size);
BitModifier result = new OfMultiple(currentIndex, size); BitModifier result = new OfMultiple(currentIndex, size);
currentIndex += size; currentIndex += size;
return result; return result;
} }
public BitModifier remaining() { public BitModifier remaining() {
return size(getRemaining()); return size(getRemaining());
} }
private void checkAvailable(int size) { private void checkAvailable(int size) {
if (size <= 0 || currentIndex + size > 64) { if (size <= 0 || currentIndex + size > 64) {
throw new IllegalStateException("Exceeding bit count of a long"); throw new IllegalStateException("Exceeding bit count of a long");
} }
} }
} }
} }

View File

@@ -1,295 +1,295 @@
/* /*
* Copyright (c) 2017 ProjectOreville * Copyright (c) 2017 ProjectOreville
* *
* All rights reserved. * All rights reserved.
* *
* Author(s): * Author(s):
* Dico Karssiens * Dico Karssiens
*/ */
package io.dico.dicore; package io.dico.dicore;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public final class Formatting implements CharSequence { public final class Formatting implements CharSequence {
public static final char FORMAT_CHAR = '\u00a7'; public static final char FORMAT_CHAR = '\u00a7';
private static final String CACHED_CHARS = "0123456789abcdefklmnor"; private static final String CACHED_CHARS = "0123456789abcdefklmnor";
private static final Formatting[] singleCharInstances = new Formatting[CACHED_CHARS.length()]; private static final Formatting[] singleCharInstances = new Formatting[CACHED_CHARS.length()];
@NotNull @NotNull
public static final Formatting public static final Formatting
BLACK = from('0'), BLACK = from('0'),
DARK_BLUE = from('1'), DARK_BLUE = from('1'),
DARL_GREEN = from('2'), DARL_GREEN = from('2'),
CYAN = from('3'), CYAN = from('3'),
DARK_RED = from('4'), DARK_RED = from('4'),
PURPLE = from('5'), PURPLE = from('5'),
ORANGE = from('6'), ORANGE = from('6'),
GRAY = from('7'), GRAY = from('7'),
DARK_GRAY = from('8'), DARK_GRAY = from('8'),
BLUE = from('9'), BLUE = from('9'),
GREEN = from('a'), GREEN = from('a'),
AQUA = from('b'), AQUA = from('b'),
RED = from('c'), RED = from('c'),
PINK = from('d'), PINK = from('d'),
YELLOW = from('e'), YELLOW = from('e'),
WHITE = from('f'), WHITE = from('f'),
BOLD = from('l'), BOLD = from('l'),
STRIKETHROUGH = from('m'), STRIKETHROUGH = from('m'),
UNDERLINE = from('n'), UNDERLINE = from('n'),
ITALIC = from('o'), ITALIC = from('o'),
MAGIC = from('k'), MAGIC = from('k'),
RESET = from('r'), RESET = from('r'),
EMPTY = from('\0'); EMPTY = from('\0');
public static String stripAll(String value) { public static String stripAll(String value) {
return stripAll(FORMAT_CHAR, value); return stripAll(FORMAT_CHAR, value);
} }
public static String stripAll(char alternateChar, String value) { public static String stripAll(char alternateChar, String value) {
int index = value.indexOf(alternateChar); int index = value.indexOf(alternateChar);
int max; int max;
if (index == -1 || index == (max = value.length() - 1)) { if (index == -1 || index == (max = value.length() - 1)) {
return value; return value;
} }
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
int from = 0; int from = 0;
do { do {
if (isRecognizedChar(value.charAt(index + 1))) { if (isRecognizedChar(value.charAt(index + 1))) {
result.append(value, from, index); result.append(value, from, index);
from = index + 2; from = index + 2;
} else { } else {
result.append(value, from, from = index + 2); result.append(value, from, from = index + 2);
} }
index = value.indexOf(alternateChar, index + 1); index = value.indexOf(alternateChar, index + 1);
} while (index != -1 && index != max && from <= max); } while (index != -1 && index != max && from <= max);
if (from <= max) { if (from <= max) {
result.append(value, from, value.length()); result.append(value, from, value.length());
} }
return result.toString(); return result.toString();
} }
public static String stripFirst(String value) { public static String stripFirst(String value) {
return stripFirst(FORMAT_CHAR, value); return stripFirst(FORMAT_CHAR, value);
} }
public static String stripFirst(char alternateChar, String value) { public static String stripFirst(char alternateChar, String value) {
int index = value.indexOf(alternateChar); int index = value.indexOf(alternateChar);
int max; int max;
if (index == -1 || index == (max = value.length() - 1)) { if (index == -1 || index == (max = value.length() - 1)) {
return value; return value;
} }
StringBuilder result = new StringBuilder(value.length()); StringBuilder result = new StringBuilder(value.length());
int from = 0; int from = 0;
if (isRecognizedChar(value.charAt(index + 1))) { if (isRecognizedChar(value.charAt(index + 1))) {
result.append(value, from, index); result.append(value, from, index);
from = index + 2; from = index + 2;
} else { } else {
result.append(value, from, from = index + 2); result.append(value, from, from = index + 2);
} }
if (from < max) { if (from < max) {
result.append(value, from, value.length()); result.append(value, from, value.length());
} }
return result.toString(); return result.toString();
} }
public static Formatting from(char c) { public static Formatting from(char c) {
if (isRecognizedChar(c)) { if (isRecognizedChar(c)) {
c = Character.toLowerCase(c); c = Character.toLowerCase(c);
int index = CACHED_CHARS.indexOf(c); int index = CACHED_CHARS.indexOf(c);
if (index == -1) return EMPTY; if (index == -1) return EMPTY;
Formatting res = singleCharInstances[index]; Formatting res = singleCharInstances[index];
if (res == null) { if (res == null) {
singleCharInstances[index] = res = new Formatting(c); singleCharInstances[index] = res = new Formatting(c);
} }
return res; return res;
} }
return EMPTY; return EMPTY;
} }
public static Formatting from(String chars) { public static Formatting from(String chars) {
return chars.length() == 1 ? from(chars.charAt(0)) : getFormats(chars, '\0'); return chars.length() == 1 ? from(chars.charAt(0)) : getFormats(chars, '\0');
} }
public static Formatting getFormats(String input) { public static Formatting getFormats(String input) {
return getFormats(input, FORMAT_CHAR); return getFormats(input, FORMAT_CHAR);
} }
public static Formatting getFormats(String input, char formatChar) { public static Formatting getFormats(String input, char formatChar) {
return getFormats(input, 0, input.length(), formatChar); return getFormats(input, 0, input.length(), formatChar);
} }
public static Formatting getFormats(String input, int start, int end, char formatChar) { public static Formatting getFormats(String input, int start, int end, char formatChar) {
if ((start < 0) || (start > end) || (end > input.length())) { if ((start < 0) || (start > end) || (end > input.length())) {
throw new IndexOutOfBoundsException("start " + start + ", end " + end + ", input.length() " + input.length()); throw new IndexOutOfBoundsException("start " + start + ", end " + end + ", input.length() " + input.length());
} }
boolean needsFormatChar = formatChar != '\0'; boolean needsFormatChar = formatChar != '\0';
char[] formats = new char[6]; char[] formats = new char[6];
// just make sure it's not the same as formatChar // just make sure it's not the same as formatChar
char previous = (char) (formatChar + 1); char previous = (char) (formatChar + 1);
for (int i = start; i < end; i++) { for (int i = start; i < end; i++) {
char c = input.charAt(i); char c = input.charAt(i);
if (previous == formatChar || !needsFormatChar) { if (previous == formatChar || !needsFormatChar) {
if (isColourChar(c) || isResetChar(c)) { if (isColourChar(c) || isResetChar(c)) {
formats = new char[6]; formats = new char[6];
formats[0] = Character.toLowerCase(c); formats[0] = Character.toLowerCase(c);
} else if (isFormatChar(c)) { } else if (isFormatChar(c)) {
char format = Character.toLowerCase(c); char format = Character.toLowerCase(c);
for (int j = 0; j < 6; j++) { for (int j = 0; j < 6; j++) {
if (formats[j] == '\0') { if (formats[j] == '\0') {
formats[j] = format; formats[j] = format;
break; break;
} else if (formats[j] == format) { } else if (formats[j] == format) {
break; break;
} }
} }
} }
} }
previous = c; previous = c;
} }
return formats[1] == '\0' ? from(formats[0]) : new Formatting(formats); return formats[1] == '\0' ? from(formats[0]) : new Formatting(formats);
} }
public static String translate(String input) { public static String translate(String input) {
return translateChars('&', input); return translateChars('&', input);
} }
public static String translateChars(char alternateChar, String input) { public static String translateChars(char alternateChar, String input) {
return translateFormat(alternateChar, FORMAT_CHAR, input); return translateFormat(alternateChar, FORMAT_CHAR, input);
} }
public static String revert(String input) { public static String revert(String input) {
return revertChars('&', input); return revertChars('&', input);
} }
public static String revertChars(char alternateChar, String input) { public static String revertChars(char alternateChar, String input) {
return translateFormat(FORMAT_CHAR, alternateChar, input); return translateFormat(FORMAT_CHAR, alternateChar, input);
} }
public static String translateFormat(char fromChar, char toChar, String input) { public static String translateFormat(char fromChar, char toChar, String input) {
if (input == null) { if (input == null) {
return null; return null;
} }
int n = input.length(); int n = input.length();
if (n < 2) { if (n < 2) {
return input; return input;
} }
char[] result = null; char[] result = null;
char previous = input.charAt(0); char previous = input.charAt(0);
for (int i = 1; i < n; i++) { for (int i = 1; i < n; i++) {
char c = input.charAt(i); char c = input.charAt(i);
if (previous == fromChar && isRecognizedChar(c)) { if (previous == fromChar && isRecognizedChar(c)) {
if (result == null) { if (result == null) {
result = input.toCharArray(); result = input.toCharArray();
} }
result[i - 1] = toChar; result[i - 1] = toChar;
} }
previous = c; previous = c;
} }
return result == null ? input : String.valueOf(result); return result == null ? input : String.valueOf(result);
} }
public static void translate(StringBuilder input) { public static void translate(StringBuilder input) {
translateChars('&', input); translateChars('&', input);
} }
public static void translateChars(char alternateChar, StringBuilder input) { public static void translateChars(char alternateChar, StringBuilder input) {
translateFormat(alternateChar, FORMAT_CHAR, input); translateFormat(alternateChar, FORMAT_CHAR, input);
} }
public static void revert(StringBuilder input) { public static void revert(StringBuilder input) {
revertChars('&', input); revertChars('&', input);
} }
public static void revertChars(char alternateChar, StringBuilder input) { public static void revertChars(char alternateChar, StringBuilder input) {
translateFormat(FORMAT_CHAR, alternateChar, input); translateFormat(FORMAT_CHAR, alternateChar, input);
} }
public static void translateFormat(char fromChar, char toChar, StringBuilder input) { public static void translateFormat(char fromChar, char toChar, StringBuilder input) {
if (input == null) { if (input == null) {
return; return;
} }
int n = input.length(); int n = input.length();
if (n < 2) { if (n < 2) {
return; return;
} }
char previous = input.charAt(0); char previous = input.charAt(0);
for (int i = 1; i < n; i++) { for (int i = 1; i < n; i++) {
char c = input.charAt(i); char c = input.charAt(i);
if (previous == fromChar && isRecognizedChar(c)) { if (previous == fromChar && isRecognizedChar(c)) {
input.setCharAt(i -1, toChar); input.setCharAt(i -1, toChar);
} }
previous = c; previous = c;
} }
} }
private static boolean isRecognizedChar(char c) { private static boolean isRecognizedChar(char c) {
return isColourChar(c) || isFormatChar(c) || isResetChar(c); return isColourChar(c) || isFormatChar(c) || isResetChar(c);
} }
private static boolean isColourChar(char c) { private static boolean isColourChar(char c) {
return "0123456789abcdefABCDEF".indexOf(c) >= 0; return "0123456789abcdefABCDEF".indexOf(c) >= 0;
} }
private static boolean isResetChar(char c) { private static boolean isResetChar(char c) {
return c == 'r' || c == 'R'; return c == 'r' || c == 'R';
} }
private static boolean isFormatChar(char c) { private static boolean isFormatChar(char c) {
return "klmnoKLMNO".indexOf(c) >= 0; return "klmnoKLMNO".indexOf(c) >= 0;
} }
private final String format; private final String format;
private Formatting(char[] formats) { private Formatting(char[] formats) {
StringBuilder format = new StringBuilder(12); StringBuilder format = new StringBuilder(12);
for (char c : formats) { for (char c : formats) {
if (c != '\0') { if (c != '\0') {
format.append(FORMAT_CHAR).append(c); format.append(FORMAT_CHAR).append(c);
} else { } else {
break; break;
} }
} }
this.format = format.toString(); this.format = format.toString();
} }
private Formatting(char c) { private Formatting(char c) {
this.format = (c != '\0') ? String.valueOf(new char[]{FORMAT_CHAR, c}) : ""; this.format = (c != '\0') ? String.valueOf(new char[]{FORMAT_CHAR, c}) : "";
} }
@Override @Override
public int length() { public int length() {
return format.length(); return format.length();
} }
@Override @Override
public char charAt(int index) { public char charAt(int index) {
return format.charAt(index); return format.charAt(index);
} }
@Override @Override
public String subSequence(int start, int end) { public String subSequence(int start, int end) {
return format.substring(start, end); return format.substring(start, end);
} }
@Override @Override
public String toString() { public String toString() {
return format; return format;
} }
public String toString(char formatChar) { public String toString(char formatChar) {
return format.replace(FORMAT_CHAR, formatChar); return format.replace(FORMAT_CHAR, formatChar);
} }
} }

View File

@@ -1,173 +1,173 @@
package io.dico.dicore; package io.dico.dicore;
/** /**
* A chainable object * A chainable object
* <p> * <p>
* It is not possible to declare another upper bound for type parameter Subtype. * It is not possible to declare another upper bound for type parameter Subtype.
* However, it is required that it also extends the type parameter Element. * However, it is required that it also extends the type parameter Element.
* *
* @param <Subtype> the interface that is chainable * @param <Subtype> the interface that is chainable
* @param <Element> the element of the chain, this is a supertype of the subtype * @param <Element> the element of the chain, this is a supertype of the subtype
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public interface InterfaceChain<Element, Subtype extends InterfaceChain<Element, Subtype>> { public interface InterfaceChain<Element, Subtype extends InterfaceChain<Element, Subtype>> {
/** /**
* returns the empty InterfaceChain instance. * returns the empty InterfaceChain instance.
* *
* @return the empty InterfaceChain instance * @return the empty InterfaceChain instance
*/ */
Subtype getEmptyInstance(); Subtype getEmptyInstance();
/** /**
* returns a InterfaceChain with the last added element detached. * returns a InterfaceChain with the last added element detached.
* <p> * <p>
* if this InterfaceChain is the empty instance, the empty instance is returned. * if this InterfaceChain is the empty instance, the empty instance is returned.
* *
* @return a InterfaceChain with the last added element detached * @return a InterfaceChain with the last added element detached
* @implNote for the purpose of lambdas, the default implementation also returns the empty instance. * @implNote for the purpose of lambdas, the default implementation also returns the empty instance.
*/ */
default Subtype withoutLastNode() { default Subtype withoutLastNode() {
return getEmptyInstance(); return getEmptyInstance();
} }
/** /**
* returns the element that was inserted as the last element * returns the element that was inserted as the last element
* <p> * <p>
* For instance, calling this method on the result of calling {@link InterfaceChain#withElement(Object)} * For instance, calling this method on the result of calling {@link InterfaceChain#withElement(Object)}
* would return the given element. * would return the given element.
* *
* @return the element that was inserted as the last element * @return the element that was inserted as the last element
* @implNote for the purpose of lambdas, the default implementation returns this object, * @implNote for the purpose of lambdas, the default implementation returns this object,
* which is required to implement the Element type parameter. * which is required to implement the Element type parameter.
*/ */
default Element getDelegateOfLastNode() { default Element getDelegateOfLastNode() {
//noinspection unchecked //noinspection unchecked
return (Element) this; return (Element) this;
} }
/** /**
* @return The number of elements chained from this InterfaceChain. * @return The number of elements chained from this InterfaceChain.
* @implNote for the purpose of lambdas, the default implementation returns 1. * @implNote for the purpose of lambdas, the default implementation returns 1.
*/ */
default int getElementCount() { default int getElementCount() {
return 1; return 1;
} }
/** /**
* Get a new InterfaceChain that includes the given Element. * Get a new InterfaceChain that includes the given Element.
* <p> * <p>
* The default implementation of the Subtype should look like this: * The default implementation of the Subtype should look like this:
* <pre> {@code * <pre> {@code
* if (element == null) { * if (element == null) {
* return this; * return this;
* } * }
* *
* int count = getElementCount() + 1; * int count = getElementCount() + 1;
* return new Subtype() { * return new Subtype() {
* \@Override * \@Override
* public void exampleElementMethod() { * public void exampleElementMethod() {
* try { * try {
* Subtype.this.exampleElementMethod(); * Subtype.this.exampleElementMethod();
* } finally { * } finally {
* element.exampleElementMethod(); * element.exampleElementMethod();
* } * }
* } * }
* *
* \@Override * \@Override
* public Subtype withoutLastNode() { * public Subtype withoutLastNode() {
* return Subtype.this; * return Subtype.this;
* } * }
* *
* \@Override * \@Override
* public Element getDelegateOfLastNode() { * public Element getDelegateOfLastNode() {
* return element; * return element;
* } * }
* *
* \@Override * \@Override
* public int getElementCount() { * public int getElementCount() {
* return count; * return count;
* } * }
* }; * };
* } * }
* </pre> * </pre>
* *
* @param element A new element to insert at the end of this InterfaceChain. * @param element A new element to insert at the end of this InterfaceChain.
* @return a new InterfaceChain that includes the given Element. * @return a new InterfaceChain that includes the given Element.
*/ */
Subtype withElement(Element element); Subtype withElement(Element element);
/** /**
* Append each of the elements to this InterfaceChain * Append each of the elements to this InterfaceChain
* *
* @param elements the elements to append * @param elements the elements to append
* @return a new InterfaceChain with the elements appended * @return a new InterfaceChain with the elements appended
*/ */
default Subtype withElements(Element... elements) { default Subtype withElements(Element... elements) {
Subtype result = (Subtype) this; Subtype result = (Subtype) this;
for (Element element : elements) { for (Element element : elements) {
result = result.withElement(element); result = result.withElement(element);
} }
return result; return result;
} }
/* /*
Example Subtypes implementation Example Subtypes implementation
public class Subtypes { public class Subtypes {
private Subtypes() { private Subtypes() {
} }
private static final Subtype empty = new Subtype() { private static final Subtype empty = new Subtype() {
@Override @Override
public void exampleElementMethod() { public void exampleElementMethod() {
} }
@Override @Override
public Subtype withElement(Element other) { public Subtype withElement(Element other) {
return Subtypes.singleton(other); return Subtypes.singleton(other);
} }
@Override @Override
public int getElementCount() { public int getElementCount() {
return 0; return 0;
} }
@Override @Override
public Element getDelegateOfLastNode() { public Element getDelegateOfLastNode() {
return null; return null;
} }
}; };
public static Subtype empty() { public static Subtype empty() {
return empty; return empty;
} }
public static Subtype singleton(Element element) { public static Subtype singleton(Element element) {
if (element instanceof Subtype) { if (element instanceof Subtype) {
return (Subtype) element; return (Subtype) element;
} }
if (element == null) { if (element == null) {
return empty(); return empty();
} }
return new Subtype() { return new Subtype() {
@Override @Override
public void exampleElementMethod() { public void exampleElementMethod() {
element.exampleElementMethod(); element.exampleElementMethod();
} }
@Override @Override
public Element getDelegateOfLastNode() { public Element getDelegateOfLastNode() {
return element; return element;
} }
}; };
} }
} }
*/ */
} }

View File

@@ -1,120 +1,120 @@
package io.dico.dicore; package io.dico.dicore;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.PlayerInventory;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
public class InventoryEventUtil { public class InventoryEventUtil {
private InventoryEventUtil() { private InventoryEventUtil() {
} }
public static ItemStack getNewItem(InventoryClickEvent event) { public static ItemStack getNewItem(InventoryClickEvent event) {
Inventory clicked = event.getInventory(); Inventory clicked = event.getInventory();
switch (event.getAction()) { switch (event.getAction()) {
case SWAP_WITH_CURSOR: case SWAP_WITH_CURSOR:
case PLACE_ALL: case PLACE_ALL:
return event.getCursor(); return event.getCursor();
case PICKUP_ALL: case PICKUP_ALL:
case HOTBAR_MOVE_AND_READD: case HOTBAR_MOVE_AND_READD:
case MOVE_TO_OTHER_INVENTORY: case MOVE_TO_OTHER_INVENTORY:
case DROP_ALL_SLOT: case DROP_ALL_SLOT:
case COLLECT_TO_CURSOR: case COLLECT_TO_CURSOR:
return null; return null;
case PICKUP_HALF: case PICKUP_HALF:
case PICKUP_SOME: case PICKUP_SOME:
ItemStack item = clicked.getItem(event.getSlot()).clone(); ItemStack item = clicked.getItem(event.getSlot()).clone();
item.setAmount(item.getAmount() / 2); item.setAmount(item.getAmount() / 2);
return item; return item;
case PICKUP_ONE: case PICKUP_ONE:
case DROP_ONE_SLOT: case DROP_ONE_SLOT:
item = clicked.getItem(event.getSlot()).clone(); item = clicked.getItem(event.getSlot()).clone();
item.setAmount(Math.max(0, item.getAmount() - 1)); item.setAmount(Math.max(0, item.getAmount() - 1));
return item; return item;
case PLACE_ONE: case PLACE_ONE:
item = event.getView().getCursor().clone(); item = event.getView().getCursor().clone();
item.setAmount(1); item.setAmount(1);
return item; return item;
case PLACE_SOME: case PLACE_SOME:
item = event.getView().getCursor().clone(); item = event.getView().getCursor().clone();
item.setAmount(item.getAmount() / 2); item.setAmount(item.getAmount() / 2);
return item; return item;
case HOTBAR_SWAP: case HOTBAR_SWAP:
return event.getView().getBottomInventory().getItem(event.getHotbarButton()); return event.getView().getBottomInventory().getItem(event.getHotbarButton());
default: default:
return clicked.getItem(event.getSlot()); return clicked.getItem(event.getSlot());
} }
} }
public static Map<Integer, ItemStack> deduceChangesIfItemAdded(Inventory inventory, ItemStack added, boolean computeNewItem) { public static Map<Integer, ItemStack> deduceChangesIfItemAdded(Inventory inventory, ItemStack added, boolean computeNewItem) {
int addedAmount = added.getAmount(); int addedAmount = added.getAmount();
Map<Integer, ItemStack> rv = Collections.emptyMap(); Map<Integer, ItemStack> rv = Collections.emptyMap();
for (int n = inventory.getSize(), i = 0; i < n; i++) { for (int n = inventory.getSize(), i = 0; i < n; i++) {
if (addedAmount <= 0) break; if (addedAmount <= 0) break;
ItemStack current = inventory.getItem(i); ItemStack current = inventory.getItem(i);
if (current == null || current.getType() == Material.AIR || current.isSimilar(added)) { if (current == null || current.getType() == Material.AIR || current.isSimilar(added)) {
int count = current == null ? 0 : current.getAmount(); int count = current == null ? 0 : current.getAmount();
int max = (current == null ? added : current).getType().getMaxStackSize(); int max = (current == null ? added : current).getType().getMaxStackSize();
if (count < max) { if (count < max) {
int diff = max - count; int diff = max - count;
if (diff > addedAmount) { if (diff > addedAmount) {
diff = addedAmount; diff = addedAmount;
} }
addedAmount -= diff; addedAmount -= diff;
if (rv.isEmpty()) rv = new LinkedHashMap<>(); if (rv.isEmpty()) rv = new LinkedHashMap<>();
if (computeNewItem) { if (computeNewItem) {
current = (current == null ? added : current).clone(); current = (current == null ? added : current).clone();
current.setAmount(count + diff); current.setAmount(count + diff);
rv.put(i, current); rv.put(i, current);
} else { } else {
rv.put(i, null); rv.put(i, null);
} }
} }
} }
} }
return rv; return rv;
} }
public static ItemStack getNewHeldItemIfPickedUp(PlayerInventory inventory, ItemStack added) { public static ItemStack getNewHeldItemIfPickedUp(PlayerInventory inventory, ItemStack added) {
int heldItemSlot = inventory.getHeldItemSlot(); int heldItemSlot = inventory.getHeldItemSlot();
ItemStack heldItem = inventory.getItem(heldItemSlot); ItemStack heldItem = inventory.getItem(heldItemSlot);
if (SpigotUtil.isItemPresent(heldItem) && !added.isSimilar(heldItem)) { if (SpigotUtil.isItemPresent(heldItem) && !added.isSimilar(heldItem)) {
return null; return null;
} }
int amt = added.getAmount(); int amt = added.getAmount();
for (int i = 0; i < heldItemSlot; i++) { for (int i = 0; i < heldItemSlot; i++) {
ItemStack item = inventory.getItem(i); ItemStack item = inventory.getItem(i);
if (!SpigotUtil.isItemPresent(item)) { if (!SpigotUtil.isItemPresent(item)) {
return null; return null;
} }
if (item.isSimilar(item)) { if (item.isSimilar(item)) {
amt -= Math.max(0, item.getMaxStackSize() - item.getAmount()); amt -= Math.max(0, item.getMaxStackSize() - item.getAmount());
if (amt <= 0) { if (amt <= 0) {
return null; return null;
} }
} }
} }
added = added.clone(); added = added.clone();
added.setAmount(amt + Math.max(0, heldItem == null ? 0 : heldItem.getAmount())); added.setAmount(amt + Math.max(0, heldItem == null ? 0 : heldItem.getAmount()));
return added; return added;
} }
} }

View File

@@ -1,116 +1,116 @@
package io.dico.dicore; package io.dico.dicore;
import java.util.logging.Logger; import java.util.logging.Logger;
public interface Logging { public interface Logging {
void info(Object o); void info(Object o);
void warn(Object o); void warn(Object o);
void error(Object o); void error(Object o);
void debug(Object o); void debug(Object o);
void setDebugging(boolean debugging); void setDebugging(boolean debugging);
boolean isDebugging(); boolean isDebugging();
class RootLogging implements Logging { class RootLogging implements Logging {
private final String prefix; private final String prefix;
private final Logger root; private final Logger root;
private boolean debugging; private boolean debugging;
public RootLogging(String prefix, Logger root, boolean debugging) { public RootLogging(String prefix, Logger root, boolean debugging) {
this.root = root; this.root = root;
this.prefix = prefix; this.prefix = prefix;
this.debugging = debugging; this.debugging = debugging;
} }
@Override @Override
public void info(Object o) { public void info(Object o) {
root.info(prefix(o)); root.info(prefix(o));
} }
@Override @Override
public void warn(Object o) { public void warn(Object o) {
root.warning(prefix(o)); root.warning(prefix(o));
} }
@Override @Override
public void error(Object o) { public void error(Object o) {
root.severe(prefix(o)); root.severe(prefix(o));
} }
@Override @Override
public void debug(Object o) { public void debug(Object o) {
if (debugging) { if (debugging) {
root.info(String.format("[DEBUG] %s", prefix(o))); root.info(String.format("[DEBUG] %s", prefix(o)));
} }
} }
@Override @Override
public boolean isDebugging() { public boolean isDebugging() {
return debugging; return debugging;
} }
@Override @Override
public void setDebugging(boolean debugging) { public void setDebugging(boolean debugging) {
this.debugging = debugging; this.debugging = debugging;
} }
private String prefix(Object o) { private String prefix(Object o) {
return String.format("[%s] %s", prefix, String.valueOf(o)); return String.format("[%s] %s", prefix, String.valueOf(o));
} }
} }
class SubLogging implements Logging { class SubLogging implements Logging {
protected String prefix; protected String prefix;
private final Logging superLogger; private final Logging superLogger;
private boolean debugging; private boolean debugging;
public SubLogging(String prefix, Logging superLogger, boolean debugging) { public SubLogging(String prefix, Logging superLogger, boolean debugging) {
this.superLogger = superLogger; this.superLogger = superLogger;
this.prefix = prefix; this.prefix = prefix;
this.debugging = debugging; this.debugging = debugging;
} }
@Override @Override
public void info(Object o) { public void info(Object o) {
superLogger.info(prefix(o)); superLogger.info(prefix(o));
} }
@Override @Override
public void warn(Object o) { public void warn(Object o) {
superLogger.warn(prefix(o)); superLogger.warn(prefix(o));
} }
@Override @Override
public void error(Object o) { public void error(Object o) {
superLogger.error(prefix(o)); superLogger.error(prefix(o));
} }
@Override @Override
public void debug(Object o) { public void debug(Object o) {
if (debugging) { if (debugging) {
superLogger.info(String.format("[DEBUG] %s", prefix(o))); superLogger.info(String.format("[DEBUG] %s", prefix(o)));
} }
} }
@Override @Override
public boolean isDebugging() { public boolean isDebugging() {
return debugging; return debugging;
} }
@Override @Override
public void setDebugging(boolean debugging) { public void setDebugging(boolean debugging) {
this.debugging = debugging; this.debugging = debugging;
} }
private String prefix(Object o) { private String prefix(Object o) {
return String.format("[%s] %s", prefix, String.valueOf(o)); return String.format("[%s] %s", prefix, String.valueOf(o));
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,59 +1,59 @@
package io.dico.dicore; package io.dico.dicore;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class SetBasedWhitelist implements Whitelist { public class SetBasedWhitelist implements Whitelist {
private final Set set; private final Set set;
private final boolean blacklist; private final boolean blacklist;
public SetBasedWhitelist(Object[] array, boolean blacklist) { public SetBasedWhitelist(Object[] array, boolean blacklist) {
this(Arrays.asList(array), blacklist); this(Arrays.asList(array), blacklist);
} }
public SetBasedWhitelist(ConfigurationSection section, Function<String, ?> parser) { public SetBasedWhitelist(ConfigurationSection section, Function<String, ?> parser) {
this(section.getStringList("listed").stream().map(parser).filter(Objects::nonNull).collect(Collectors.toList()), this(section.getStringList("listed").stream().map(parser).filter(Objects::nonNull).collect(Collectors.toList()),
section.getBoolean("blacklist", false)); section.getBoolean("blacklist", false));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public SetBasedWhitelist(Collection collection, boolean blacklist) { public SetBasedWhitelist(Collection collection, boolean blacklist) {
Set set; Set set;
if (collection.isEmpty()) { if (collection.isEmpty()) {
set = Collections.emptySet(); set = Collections.emptySet();
} else if (collection.iterator().next() instanceof Enum) { } else if (collection.iterator().next() instanceof Enum) {
set = EnumSet.copyOf(collection); set = EnumSet.copyOf(collection);
} else if (collection instanceof Set) { } else if (collection instanceof Set) {
set = (Set) collection; set = (Set) collection;
} else { } else {
set = new HashSet<>(collection); set = new HashSet<>(collection);
} }
this.set = set; this.set = set;
this.blacklist = blacklist; this.blacklist = blacklist;
} }
@Override @Override
public boolean isWhitelisted(Object o) { public boolean isWhitelisted(Object o) {
return blacklist != set.contains(o); return blacklist != set.contains(o);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public String toString() { public String toString() {
return (blacklist ? "Blacklist" : "Whitelist") + "{" return (blacklist ? "Blacklist" : "Whitelist") + "{"
+ String.join(", ", (CharSequence[]) set.stream().map(String::valueOf).toArray(String[]::new)) + "}"; + String.join(", ", (CharSequence[]) set.stream().map(String::valueOf).toArray(String[]::new)) + "}";
} }
public Set getSet() { public Set getSet() {
return set; return set;
} }
public boolean isBlacklist() { public boolean isBlacklist() {
return blacklist; return blacklist;
} }
} }

View File

@@ -1,408 +1,408 @@
package io.dico.dicore; package io.dico.dicore;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.entity.*; import org.bukkit.entity.*;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.material.Attachable; import org.bukkit.material.Attachable;
import org.bukkit.material.MaterialData; import org.bukkit.material.MaterialData;
import org.bukkit.projectiles.ProjectileSource; import org.bukkit.projectiles.ProjectileSource;
import java.util.*; import java.util.*;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
public class SpigotUtil { public class SpigotUtil {
private SpigotUtil() { private SpigotUtil() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public static World matchWorld(String input) { public static World matchWorld(String input) {
try { try {
UUID uid = UUID.fromString(input); UUID uid = UUID.fromString(input);
World world = Bukkit.getWorld(uid); World world = Bukkit.getWorld(uid);
if (world != null) { if (world != null) {
return world; return world;
} }
} catch (IllegalArgumentException ignored) { } catch (IllegalArgumentException ignored) {
} }
World result = Bukkit.getWorld(input); World result = Bukkit.getWorld(input);
if (result == null) { if (result == null) {
input = input.toLowerCase().replace("_", "").replaceAll("[-_]", ""); input = input.toLowerCase().replace("_", "").replaceAll("[-_]", "");
for (World world : Bukkit.getWorlds()) { for (World world : Bukkit.getWorlds()) {
if (world.getName().toLowerCase().equals(input)) { if (world.getName().toLowerCase().equals(input)) {
result = world; result = world;
break; break;
} }
} }
} }
return result; return result;
} }
public static Block getSupportingBlock(Block block) { public static Block getSupportingBlock(Block block) {
MaterialData data = block.getState().getData(); MaterialData data = block.getState().getData();
if (data instanceof Attachable) { if (data instanceof Attachable) {
BlockFace attachedOn = ((Attachable) data).getAttachedFace(); BlockFace attachedOn = ((Attachable) data).getAttachedFace();
return block.getRelative(attachedOn); return block.getRelative(attachedOn);
} }
return null; return null;
} }
public static boolean isItemPresent(ItemStack stack) { public static boolean isItemPresent(ItemStack stack) {
return stack != null && stack.getType() != Material.AIR && stack.getAmount() > 0; return stack != null && stack.getType() != Material.AIR && stack.getAmount() > 0;
} }
public static boolean removeItems(Inventory from, ItemStack item, int amount) { public static boolean removeItems(Inventory from, ItemStack item, int amount) {
for (Map.Entry<Integer, ? extends ItemStack> entry : from.all(item.getType()).entrySet()) { for (Map.Entry<Integer, ? extends ItemStack> entry : from.all(item.getType()).entrySet()) {
ItemStack stack = entry.getValue(); ItemStack stack = entry.getValue();
if (item.isSimilar(stack)) { if (item.isSimilar(stack)) {
amount -= stack.getAmount(); amount -= stack.getAmount();
int stackAmount = -Math.min(0, amount); int stackAmount = -Math.min(0, amount);
if (stackAmount == 0) { if (stackAmount == 0) {
from.setItem(entry.getKey(), null); from.setItem(entry.getKey(), null);
} else { } else {
stack.setAmount(stackAmount); stack.setAmount(stackAmount);
} }
} }
} }
return amount <= 0; return amount <= 0;
} }
public static BlockFace yawToFace(float yaw) { public static BlockFace yawToFace(float yaw) {
if ((yaw %= 360) < 0) if ((yaw %= 360) < 0)
yaw += 360; yaw += 360;
if (45 <= yaw && yaw < 135) if (45 <= yaw && yaw < 135)
return BlockFace.WEST; return BlockFace.WEST;
if (135 <= yaw && yaw < 225) if (135 <= yaw && yaw < 225)
return BlockFace.NORTH; return BlockFace.NORTH;
if (225 <= yaw && yaw < 315) if (225 <= yaw && yaw < 315)
return BlockFace.EAST; return BlockFace.EAST;
return BlockFace.SOUTH; return BlockFace.SOUTH;
} }
public static void addItems(InventoryHolder entity, ItemStack... items) { public static void addItems(InventoryHolder entity, ItemStack... items) {
Location dropLocation; Location dropLocation;
if (entity instanceof Entity) { if (entity instanceof Entity) {
dropLocation = ((Entity) entity).getLocation(); dropLocation = ((Entity) entity).getLocation();
} else if (entity instanceof BlockState) { } else if (entity instanceof BlockState) {
dropLocation = ((BlockState) entity).getLocation().add(0.5, 1, 0.5); dropLocation = ((BlockState) entity).getLocation().add(0.5, 1, 0.5);
} else { } else {
throw new IllegalArgumentException("Can't find location of this InventoryHolder: " + entity); throw new IllegalArgumentException("Can't find location of this InventoryHolder: " + entity);
} }
World world = dropLocation.getWorld(); World world = dropLocation.getWorld();
for (ItemStack toDrop : entity.getInventory().addItem(items).values()) { for (ItemStack toDrop : entity.getInventory().addItem(items).values()) {
world.dropItemNaturally(dropLocation, toDrop); world.dropItemNaturally(dropLocation, toDrop);
} }
} }
public static String asJsonString(Object object) { public static String asJsonString(Object object) {
return asJsonString(null, object, 0); return asJsonString(null, object, 0);
} }
public static String asJsonString(String key, Object object, int indentation) { public static String asJsonString(String key, Object object, int indentation) {
String indent = new String(new char[indentation * 2]).replace('\0', ' '); String indent = new String(new char[indentation * 2]).replace('\0', ' ');
StringBuilder builder = new StringBuilder(indent); StringBuilder builder = new StringBuilder(indent);
if (key != null) { if (key != null) {
builder.append(key).append(": "); builder.append(key).append(": ");
} }
if (object instanceof ConfigurationSerializable) { if (object instanceof ConfigurationSerializable) {
object = ((ConfigurationSerializable) object).serialize(); object = ((ConfigurationSerializable) object).serialize();
} }
if (object instanceof Map) { if (object instanceof Map) {
builder.append("{\n"); builder.append("{\n");
Map<?, ?> map = (Map) object; Map<?, ?> map = (Map) object;
for (Map.Entry entry : map.entrySet()) { for (Map.Entry entry : map.entrySet()) {
builder.append(asJsonString(String.valueOf(entry.getKey()), entry.getValue(), indentation + 1)); builder.append(asJsonString(String.valueOf(entry.getKey()), entry.getValue(), indentation + 1));
} }
builder.append(indent).append("}"); builder.append(indent).append("}");
} else if (object instanceof List) { } else if (object instanceof List) {
builder.append("[\n"); builder.append("[\n");
List list = (List) object; List list = (List) object;
for (Object entry : list) { for (Object entry : list) {
builder.append(asJsonString(null, entry, indentation + 1)); builder.append(asJsonString(null, entry, indentation + 1));
} }
builder.append(indent).append("]"); builder.append(indent).append("]");
} else { } else {
builder.append(String.valueOf(object)); builder.append(String.valueOf(object));
} }
return builder.append(",\n").toString(); return builder.append(",\n").toString();
} }
public static String asJsonString(String key, Object object, int indentation, BiConsumer<List<?>, StringBuilder> listHeader) { public static String asJsonString(String key, Object object, int indentation, BiConsumer<List<?>, StringBuilder> listHeader) {
String indent = new String(new char[indentation * 2]).replace('\0', ' '); String indent = new String(new char[indentation * 2]).replace('\0', ' ');
StringBuilder builder = new StringBuilder(indent); StringBuilder builder = new StringBuilder(indent);
if (key != null) { if (key != null) {
builder.append(key).append(": "); builder.append(key).append(": ");
} }
if (object instanceof ConfigurationSerializable) { if (object instanceof ConfigurationSerializable) {
object = ((ConfigurationSerializable) object).serialize(); object = ((ConfigurationSerializable) object).serialize();
} }
if (object instanceof Map) { if (object instanceof Map) {
builder.append("{\n"); builder.append("{\n");
Map<?, ?> map = (Map) object; Map<?, ?> map = (Map) object;
for (Map.Entry entry : map.entrySet()) { for (Map.Entry entry : map.entrySet()) {
builder.append(asJsonString(String.valueOf(entry.getKey()), entry.getValue(), indentation + 1, listHeader)); builder.append(asJsonString(String.valueOf(entry.getKey()), entry.getValue(), indentation + 1, listHeader));
} }
builder.append(indent).append("}"); builder.append(indent).append("}");
} else if (object instanceof List) { } else if (object instanceof List) {
builder.append("["); builder.append("[");
List list = (List) object; List list = (List) object;
listHeader.accept(list, builder); listHeader.accept(list, builder);
builder.append("\n"); builder.append("\n");
for (Object entry : list) { for (Object entry : list) {
builder.append(asJsonString(null, entry, indentation + 1, listHeader)); builder.append(asJsonString(null, entry, indentation + 1, listHeader));
} }
builder.append(indent).append("]"); builder.append(indent).append("]");
} else { } else {
builder.append(String.valueOf(object)); builder.append(String.valueOf(object));
} }
return builder.append(",\n").toString(); return builder.append(",\n").toString();
} }
public static BlockFace estimateDirectionTo(Location from, Location to) { public static BlockFace estimateDirectionTo(Location from, Location to) {
double dx = from.getX() - to.getX(); double dx = from.getX() - to.getX();
double dz = from.getZ() - to.getZ(); double dz = from.getZ() - to.getZ();
boolean xGreater = Math.abs(dx) - Math.abs(dz) > 0; boolean xGreater = Math.abs(dx) - Math.abs(dz) > 0;
double f = xGreater ? 2 / Math.abs(dx) : 2 / Math.abs(dz); double f = xGreater ? 2 / Math.abs(dx) : 2 / Math.abs(dz);
dx *= f; dx *= f;
dz *= f; dz *= f;
double other = Math.abs(xGreater ? dz : dx); double other = Math.abs(xGreater ? dz : dx);
if (other <= .5) { if (other <= .5) {
return xGreater ? (dx < 0 ? BlockFace.WEST : BlockFace.EAST) : (dz < 0 ? BlockFace.NORTH : BlockFace.SOUTH); return xGreater ? (dx < 0 ? BlockFace.WEST : BlockFace.EAST) : (dz < 0 ? BlockFace.NORTH : BlockFace.SOUTH);
} }
if (other < 1.5) { if (other < 1.5) {
if (xGreater) { if (xGreater) {
return dx < 0 ? (dz < 0 ? BlockFace.WEST_NORTH_WEST : BlockFace.WEST_SOUTH_WEST) : (dz < 0 ? BlockFace.EAST_NORTH_EAST : BlockFace.EAST_SOUTH_EAST); return dx < 0 ? (dz < 0 ? BlockFace.WEST_NORTH_WEST : BlockFace.WEST_SOUTH_WEST) : (dz < 0 ? BlockFace.EAST_NORTH_EAST : BlockFace.EAST_SOUTH_EAST);
} }
return dx < 0 ? (dz < 0 ? BlockFace.NORTH_NORTH_WEST : BlockFace.SOUTH_SOUTH_WEST) : (dz < 0 ? BlockFace.NORTH_NORTH_EAST : BlockFace.SOUTH_SOUTH_EAST); return dx < 0 ? (dz < 0 ? BlockFace.NORTH_NORTH_WEST : BlockFace.SOUTH_SOUTH_WEST) : (dz < 0 ? BlockFace.NORTH_NORTH_EAST : BlockFace.SOUTH_SOUTH_EAST);
} }
return dx < 0 ? (dz < 0 ? BlockFace.NORTH_WEST : BlockFace.SOUTH_WEST) : (dz < 0 ? BlockFace.NORTH_EAST : BlockFace.SOUTH_EAST); return dx < 0 ? (dz < 0 ? BlockFace.NORTH_WEST : BlockFace.SOUTH_WEST) : (dz < 0 ? BlockFace.NORTH_EAST : BlockFace.SOUTH_EAST);
} }
public static Entity findEntityFromDamager(Entity damager, EntityType searched) { public static Entity findEntityFromDamager(Entity damager, EntityType searched) {
if (damager.getType() == searched) { if (damager.getType() == searched) {
return damager; return damager;
} }
if (damager instanceof Projectile) { if (damager instanceof Projectile) {
ProjectileSource shooter = ((Projectile) damager).getShooter(); ProjectileSource shooter = ((Projectile) damager).getShooter();
if (shooter instanceof Entity && ((Entity) shooter).getType() == searched) { if (shooter instanceof Entity && ((Entity) shooter).getType() == searched) {
return (Entity) shooter; return (Entity) shooter;
} }
return null; return null;
} }
if (damager.getType() == EntityType.PRIMED_TNT) { if (damager.getType() == EntityType.PRIMED_TNT) {
Entity source = ((TNTPrimed) damager).getSource(); Entity source = ((TNTPrimed) damager).getSource();
if (source.getType() == searched) { if (source.getType() == searched) {
return source; return source;
} }
} }
return null; return null;
} }
public static int xpForNextLevel(int currentLevel) { public static int xpForNextLevel(int currentLevel) {
if (currentLevel >= 30) { if (currentLevel >= 30) {
return 112 + (currentLevel - 30) * 9; return 112 + (currentLevel - 30) * 9;
} }
if (currentLevel >= 15) { if (currentLevel >= 15) {
return 37 + (currentLevel - 15) * 5; return 37 + (currentLevel - 15) * 5;
} }
return 7 + currentLevel * 2; return 7 + currentLevel * 2;
} }
public static int removeExp(Player entity, int xp) { public static int removeExp(Player entity, int xp) {
int total = entity.getTotalExperience(); int total = entity.getTotalExperience();
if (xp > total) { if (xp > total) {
xp = total; xp = total;
} }
int level = entity.getLevel(); int level = entity.getLevel();
if (level < 0) { if (level < 0) {
return 0; return 0;
} }
int removed = 0; int removed = 0;
int xpForNextLevel = xpForNextLevel(level); int xpForNextLevel = xpForNextLevel(level);
int current = (int) entity.getExp() * xpForNextLevel; int current = (int) entity.getExp() * xpForNextLevel;
if (xp > current) { if (xp > current) {
xp -= current; xp -= current;
total -= current; total -= current;
removed += current; removed += current;
if (level == 0) { if (level == 0) {
entity.setExp(0F); entity.setExp(0F);
entity.setTotalExperience(total); entity.setTotalExperience(total);
return removed; return removed;
} }
} else { } else {
current -= xp; current -= xp;
total -= xp; total -= xp;
removed += xp; removed += xp;
entity.setExp((float) current / xpForNextLevel); entity.setExp((float) current / xpForNextLevel);
entity.setTotalExperience(total); entity.setTotalExperience(total);
return removed; return removed;
} }
do { do {
xpForNextLevel = xpForNextLevel(--level); xpForNextLevel = xpForNextLevel(--level);
if (xpForNextLevel >= xp) { if (xpForNextLevel >= xp) {
total -= xp; total -= xp;
removed += xp; removed += xp;
entity.setExp(1F / xpForNextLevel * (xpForNextLevel - xp)); entity.setExp(1F / xpForNextLevel * (xpForNextLevel - xp));
entity.setTotalExperience(total); entity.setTotalExperience(total);
entity.setLevel(level); entity.setLevel(level);
return removed; return removed;
} }
xp -= xpForNextLevel; xp -= xpForNextLevel;
total -= xpForNextLevel; total -= xpForNextLevel;
removed += xpForNextLevel; removed += xpForNextLevel;
} while (level > 0); } while (level > 0);
entity.setExp(0F); entity.setExp(0F);
entity.setTotalExperience(0); entity.setTotalExperience(0);
entity.setLevel(0); entity.setLevel(0);
return removed; return removed;
} }
public static int getTotalExp(Player entity) { public static int getTotalExp(Player entity) {
int rv = 0; int rv = 0;
int level = Math.min(entity.getLevel(), 20000); int level = Math.min(entity.getLevel(), 20000);
for (int i = 0; i < level; i++) { for (int i = 0; i < level; i++) {
rv += xpForNextLevel(i); rv += xpForNextLevel(i);
} }
rv += Math.min(1F, Math.max(0F, entity.getExp())) * xpForNextLevel(level); rv += Math.min(1F, Math.max(0F, entity.getExp())) * xpForNextLevel(level);
return rv; return rv;
} }
public static double getTotalExpLevels(Player entity) { public static double getTotalExpLevels(Player entity) {
int xp = entity.getTotalExperience(); int xp = entity.getTotalExperience();
int level = 0; int level = 0;
while (xp > 0 && level < 20000) { while (xp > 0 && level < 20000) {
int needed = xpForNextLevel(level); int needed = xpForNextLevel(level);
if (needed > xp) { if (needed > xp) {
return level + ((double) xp / needed); return level + ((double) xp / needed);
} }
xp -= needed; xp -= needed;
level++; level++;
} }
return level; return level;
} }
public static int getNearbyPlayerCount(Player origin, double range, Predicate<Player> predicate) { public static int getNearbyPlayerCount(Player origin, double range, Predicate<Player> predicate) {
List<Entity> entities = origin.getNearbyEntities(range, range, range); List<Entity> entities = origin.getNearbyEntities(range, range, range);
int result = 0; int result = 0;
for (Entity entity : entities) { for (Entity entity : entities) {
if (entity.getType() == EntityType.PLAYER && predicate.test((Player) entity)) { if (entity.getType() == EntityType.PLAYER && predicate.test((Player) entity)) {
result++; result++;
} }
} }
return result; return result;
} }
public static void getNearbyPlayers(Player origin, double range, Collection<Player> collection, Predicate<Player> predicate) { public static void getNearbyPlayers(Player origin, double range, Collection<Player> collection, Predicate<Player> predicate) {
List<Entity> entities = origin.getNearbyEntities(range, range, range); List<Entity> entities = origin.getNearbyEntities(range, range, range);
for (Entity entity : entities) { for (Entity entity : entities) {
if (entity.getType() == EntityType.PLAYER && predicate.test((Player) entity)) { if (entity.getType() == EntityType.PLAYER && predicate.test((Player) entity)) {
collection.add((Player) entity); collection.add((Player) entity);
} }
} }
} }
public static void forEachNearbyPlayer(Player origin, double range, Consumer<Player> action) { public static void forEachNearbyPlayer(Player origin, double range, Consumer<Player> action) {
List<Entity> entities = origin.getNearbyEntities(range, range, range); List<Entity> entities = origin.getNearbyEntities(range, range, range);
for (Entity entity : entities) { for (Entity entity : entities) {
if (entity.getType() == EntityType.PLAYER) { if (entity.getType() == EntityType.PLAYER) {
action.accept((Player) entity); action.accept((Player) entity);
} }
} }
} }
public static double distanceSquared(Location first, Location second) { public static double distanceSquared(Location first, Location second) {
double dx = first.getX() - second.getX(); double dx = first.getX() - second.getX();
double dy = first.getY() - second.getY(); double dy = first.getY() - second.getY();
double dz = first.getZ() - second.getZ(); double dz = first.getZ() - second.getZ();
return dx * dx + dy * dy + dz * dz; return dx * dx + dy * dy + dz * dz;
} }
public static <T extends Entity> Iterator<T> findNearbyEntities(Entity origin, boolean includeSelf, Predicate<Entity> predicate, double horizontalRange, double verticalRange) { public static <T extends Entity> Iterator<T> findNearbyEntities(Entity origin, boolean includeSelf, Predicate<Entity> predicate, double horizontalRange, double verticalRange) {
Objects.requireNonNull(origin); Objects.requireNonNull(origin);
return new Iterator<T>() { return new Iterator<T>() {
Entity next; Entity next;
List<Entity> nearby; List<Entity> nearby;
int index = 0; int index = 0;
int size; int size;
{ {
if (includeSelf) { if (includeSelf) {
next = origin; next = origin;
} else { } else {
next = findNext(); next = findNext();
} }
} }
Entity findNext() { Entity findNext() {
if (nearby == null) { if (nearby == null) {
nearby = origin.getNearbyEntities(horizontalRange, verticalRange, horizontalRange); nearby = origin.getNearbyEntities(horizontalRange, verticalRange, horizontalRange);
size = nearby.size(); size = nearby.size();
} }
while (index < size) { while (index < size) {
Entity e = nearby.get(index++); Entity e = nearby.get(index++);
if (predicate.test(e)) { if (predicate.test(e)) {
return e; return e;
} }
} }
return null; return null;
} }
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return next != null; return next != null;
} }
@Override @Override
public T next() { public T next() {
if (next == null) { if (next == null) {
throw new NoSuchElementException(); throw new NoSuchElementException();
} }
Entity result = next; Entity result = next;
next = findNext(); next = findNext();
//noinspection unchecked //noinspection unchecked
return (T) result; return (T) result;
} }
}; };
} }
} }

View File

@@ -1,473 +1,473 @@
package io.dico.dicore; package io.dico.dicore;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream; import java.util.stream.IntStream;
public class StringUtil { public class StringUtil {
public static String capitalize(String input) { public static String capitalize(String input) {
if (input.length() > 0) { if (input.length() > 0) {
char first = input.charAt(0); char first = input.charAt(0);
if (first != (first = Character.toUpperCase(first))) { if (first != (first = Character.toUpperCase(first))) {
char[] result = input.toCharArray(); char[] result = input.toCharArray();
result[0] = first; result[0] = first;
return String.valueOf(result); return String.valueOf(result);
} }
} }
return input; return input;
} }
/** /**
* Capitalizes the first character of the string or the first character of each word * Capitalizes the first character of the string or the first character of each word
* *
* @param input the string to capitalize * @param input the string to capitalize
* @param spaceChar the character separating each word. If @code '\0' is passed, only the first character of * @param spaceChar the character separating each word. If @code '\0' is passed, only the first character of
* the input is capitalized. * the input is capitalized.
* @return the capitalized string * @return the capitalized string
*/ */
public static String capitalize(String input, char spaceChar) { public static String capitalize(String input, char spaceChar) {
if (spaceChar == '\0') { if (spaceChar == '\0') {
return capitalize(input); return capitalize(input);
} }
char[] result = null; char[] result = null;
boolean capitalize = true; boolean capitalize = true;
for (int n = input.length(), i = 0; i < n; i++) { for (int n = input.length(), i = 0; i < n; i++) {
char c = input.charAt(i); char c = input.charAt(i);
if (capitalize && c != (c = Character.toUpperCase(c))) { if (capitalize && c != (c = Character.toUpperCase(c))) {
if (result == null) result = input.toCharArray(); if (result == null) result = input.toCharArray();
result[i] = c; result[i] = c;
} }
capitalize = c == spaceChar; capitalize = c == spaceChar;
} }
return result != null ? String.valueOf(result) : input; return result != null ? String.valueOf(result) : input;
} }
public static String capitalize(String input, char spaceChar, char newSpaceChar) { public static String capitalize(String input, char spaceChar, char newSpaceChar) {
if (newSpaceChar == '\0') { if (newSpaceChar == '\0') {
return capitalize(input, spaceChar); return capitalize(input, spaceChar);
} }
char[] result = null; char[] result = null;
boolean capitalize = true; boolean capitalize = true;
for (int n = input.length(), i = 0; i < n; i++) { for (int n = input.length(), i = 0; i < n; i++) {
char c = input.charAt(i); char c = input.charAt(i);
if (capitalize && c != (c = Character.toUpperCase(c))) { if (capitalize && c != (c = Character.toUpperCase(c))) {
if (result == null) result = input.toCharArray(); if (result == null) result = input.toCharArray();
result[i] = c; result[i] = c;
} }
if (capitalize = c == spaceChar) { if (capitalize = c == spaceChar) {
if (result == null) result = input.toCharArray(); if (result == null) result = input.toCharArray();
result[i] = newSpaceChar; result[i] = newSpaceChar;
} }
} }
return result != null ? String.valueOf(result) : input; return result != null ? String.valueOf(result) : input;
} }
/** /**
* Returns a lowercase version of the input with _ replaced with a space. * Returns a lowercase version of the input with _ replaced with a space.
* Mainly used for making names of enum constants readable. * Mainly used for making names of enum constants readable.
* *
* @param input * @param input
* @return a humanified version of @code input * @return a humanified version of @code input
*/ */
public static String humanify(String input) { public static String humanify(String input) {
return input == null ? null : input.toLowerCase().replace('_', ' '); return input == null ? null : input.toLowerCase().replace('_', ' ');
} }
/** /**
* Enumerate the given items, separating them by ", " and finally by " and " * Enumerate the given items, separating them by ", " and finally by " and "
* *
* @param words the items to enumerate (it's not really enumerating....) * @param words the items to enumerate (it's not really enumerating....)
* @return the enumerated string * @return the enumerated string
*/ */
public static String enumerate(String... words) { public static String enumerate(String... words) {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
int size = words.length; int size = words.length;
int secondLastIndex = size - 2; int secondLastIndex = size - 2;
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
String word = words[i]; String word = words[i];
if (word.isEmpty()) if (word.isEmpty())
continue; continue;
result.append(word); result.append(word);
if (i < secondLastIndex) if (i < secondLastIndex)
result.append(", "); result.append(", ");
else if (i == secondLastIndex) else if (i == secondLastIndex)
result.append(" and "); result.append(" and ");
} }
return result.toString(); return result.toString();
} }
public static String enumerate(String list, String regex) { public static String enumerate(String list, String regex) {
return enumerate(list.split(regex)); return enumerate(list.split(regex));
} }
/** /**
* Return a formatted string of the length in millis, containing days, hours and minutes. * Return a formatted string of the length in millis, containing days, hours and minutes.
* *
* @param length The delay in milliseconds * @param length The delay in milliseconds
* @return the formatted string * @return the formatted string
*/ */
public static String getTimeLength(long length) { public static String getTimeLength(long length) {
int minute = 60000; // in millis int minute = 60000; // in millis
int hour = 60 * minute; int hour = 60 * minute;
int day = 24 * hour; int day = 24 * hour;
int minutes = (int) ((length / minute) % 60); int minutes = (int) ((length / minute) % 60);
int hours = (int) ((length / hour) % 24); int hours = (int) ((length / hour) % 24);
int days = (int) (length / day); //returns floor int days = (int) (length / day); //returns floor
String result = ""; // It will be splitted at "|" String result = ""; // It will be splitted at "|"
if (days != 0) if (days != 0)
result += days + " days|"; result += days + " days|";
if (hours != 0) if (hours != 0)
result += hours + " hours|"; result += hours + " hours|";
if (minutes != 0) if (minutes != 0)
result += minutes + " minutes|"; result += minutes + " minutes|";
return enumerate(result.split("\\|")); return enumerate(result.split("\\|"));
} }
/** /**
* Return a formatted String to represent the given time length, in the given units * Return a formatted String to represent the given time length, in the given units
* *
* @param sourceAmount Amount of delay * @param sourceAmount Amount of delay
* @param sourceUnit Unit of delay * @param sourceUnit Unit of delay
* @param ifEmpty the String to return if the * @param ifEmpty the String to return if the
* @param displayedUnits units displayed * @param displayedUnits units displayed
* @return the formatted string * @return the formatted string
* @throws IllegalArgumentException if there are no displayed units * @throws IllegalArgumentException if there are no displayed units
*/ */
public static String getTimeLength(long sourceAmount, TimeUnit sourceUnit, String ifEmpty, TimeUnit... displayedUnits) { public static String getTimeLength(long sourceAmount, TimeUnit sourceUnit, String ifEmpty, TimeUnit... displayedUnits) {
if (displayedUnits.length == 0) { if (displayedUnits.length == 0) {
throw new IllegalArgumentException("No displayed units"); throw new IllegalArgumentException("No displayed units");
} }
Arrays.sort(displayedUnits, Collections.reverseOrder(TimeUnit::compareTo)); // sort by opposite of enum declaration order (largest -> smallest) Arrays.sort(displayedUnits, Collections.reverseOrder(TimeUnit::compareTo)); // sort by opposite of enum declaration order (largest -> smallest)
List<String> segments = new ArrayList<>(displayedUnits.length); List<String> segments = new ArrayList<>(displayedUnits.length);
for (TimeUnit unit : displayedUnits) { for (TimeUnit unit : displayedUnits) {
long displayedAmount = unit.convert(sourceAmount, sourceUnit); long displayedAmount = unit.convert(sourceAmount, sourceUnit);
sourceAmount -= sourceUnit.convert(displayedAmount, unit); sourceAmount -= sourceUnit.convert(displayedAmount, unit);
if (displayedAmount > 0) { if (displayedAmount > 0) {
String unitWord = unit.name().toLowerCase(); // plural String unitWord = unit.name().toLowerCase(); // plural
if (displayedAmount == 1) { if (displayedAmount == 1) {
unitWord = unitWord.substring(0, unitWord.length() - 1); // remove s at the end unitWord = unitWord.substring(0, unitWord.length() - 1); // remove s at the end
} }
segments.add(displayedAmount + " " + unitWord); segments.add(displayedAmount + " " + unitWord);
} }
} }
return segments.isEmpty() ? ifEmpty : enumerate(segments.toArray(new String[segments.size()])); return segments.isEmpty() ? ifEmpty : enumerate(segments.toArray(new String[segments.size()]));
} }
/** /**
* Returns the delay represented by a ban-like delay representation, in milliseconds * Returns the delay represented by a ban-like delay representation, in milliseconds
* Example: "5d2h5m3s" for 5 days, 2 hours, 5 minutes and 3 seconds. * Example: "5d2h5m3s" for 5 days, 2 hours, 5 minutes and 3 seconds.
* <p> * <p>
* Supported characters are s, m, h, d, w. * Supported characters are s, m, h, d, w.
* Negative numbers are supported. * Negative numbers are supported.
* *
* @param input The input string * @param input The input string
* @return The delay in milliseconds * @return The delay in milliseconds
* @throws IllegalArgumentException if the input string isn't properly formatted, or any non-digit character isn't recognized (capitals are not recognized). * @throws IllegalArgumentException if the input string isn't properly formatted, or any non-digit character isn't recognized (capitals are not recognized).
*/ */
public static long getTimeLength(String input) { //if -1: error public static long getTimeLength(String input) { //if -1: error
long count = 0; long count = 0;
int i = 0; int i = 0;
while (i < input.length()) { while (i < input.length()) {
int num = 0; int num = 0;
char unit = '\0'; char unit = '\0';
boolean negate; boolean negate;
if (negate = input.charAt(i) == '-') { if (negate = input.charAt(i) == '-') {
i++; i++;
} }
do { do {
char c = input.charAt(i); char c = input.charAt(i);
int digit = c - '0'; int digit = c - '0';
if (0 <= digit && digit < 10) { if (0 <= digit && digit < 10) {
num = 10 * num + digit; num = 10 * num + digit;
} else { } else {
unit = c; unit = c;
break; break;
} }
} while (i < input.length()); } while (i < input.length());
long unitTime = getUnitTime(unit); long unitTime = getUnitTime(unit);
if (unitTime == -1) if (unitTime == -1)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if (negate) { if (negate) {
unitTime = -unitTime; unitTime = -unitTime;
} }
count += (num * unitTime); count += (num * unitTime);
} }
return count; return count;
} }
/** /**
* Returns the time represented by the given unit character in milliseconds. * Returns the time represented by the given unit character in milliseconds.
* <p> * <p>
* 's' -> 1000 * 's' -> 1000
* 'm' -> 1000 * 60 * 'm' -> 1000 * 60
* 'h' -> 1000 * 60 * 60 * 'h' -> 1000 * 60 * 60
* 'd' -> 1000 * 60 * 60 * 24 * 'd' -> 1000 * 60 * 60 * 24
* 'w' -> 1000 * 60 * 60 * 24 * 7 * 'w' -> 1000 * 60 * 60 * 24 * 7
* anything else -> -1 * anything else -> -1
* *
* @param unit The unit character, as shown above * @param unit The unit character, as shown above
* @return the millisecond delay represented by the unit * @return the millisecond delay represented by the unit
*/ */
public static long getUnitTime(char unit) { //if -1: no value found public static long getUnitTime(char unit) { //if -1: no value found
switch (Character.toLowerCase(unit)) { switch (Character.toLowerCase(unit)) {
case 's': case 's':
return 1000; return 1000;
case 'm': case 'm':
return 1000 * 60; return 1000 * 60;
case 'h': case 'h':
return 1000 * 60 * 60; return 1000 * 60 * 60;
case 'd': case 'd':
return 1000 * 60 * 60 * 24; return 1000 * 60 * 60 * 24;
case 'w': case 'w':
return 1000 * 60 * 60 * 24 * 7; return 1000 * 60 * 60 * 24 * 7;
default: default:
return -1; return -1;
} }
} }
/** /**
* Computes a binary representation of the value. * Computes a binary representation of the value.
* The returned representation always displays 64 bits. * The returned representation always displays 64 bits.
* Every 8 bits, the digits are seperated by an _ * Every 8 bits, the digits are seperated by an _
* The representation is prefixed by 0b. * The representation is prefixed by 0b.
* <p> * <p>
* Example: 0b00000000_11111111_00000001_11110000_00001111_11001100_00001111_10111010 * Example: 0b00000000_11111111_00000001_11110000_00001111_11001100_00001111_10111010
* *
* @param entry the value to represent in binary * @param entry the value to represent in binary
* @return A binary representation of the long value * @return A binary representation of the long value
*/ */
public static String toBinaryString(long entry) { public static String toBinaryString(long entry) {
String binary = Long.toBinaryString(entry); String binary = Long.toBinaryString(entry);
String binary64 = String.valueOf(new char[64 - binary.length()]).replace('\0', '0') + binary; String binary64 = String.valueOf(new char[64 - binary.length()]).replace('\0', '0') + binary;
String withUnderscores = String.join("_", IntStream.range(0, 8).mapToObj(x -> binary64.substring(x * 8, x * 8 + 8)).toArray(String[]::new)); String withUnderscores = String.join("_", IntStream.range(0, 8).mapToObj(x -> binary64.substring(x * 8, x * 8 + 8)).toArray(String[]::new));
return "0b" + withUnderscores; return "0b" + withUnderscores;
} }
/** /**
* Turns a generic java classname into a name formatted properly to be an enum constant. * Turns a generic java classname into a name formatted properly to be an enum constant.
* *
* @param name The string value I'd describe as a generic java classname (so we have CapitalCase) * @param name The string value I'd describe as a generic java classname (so we have CapitalCase)
* @return An enum constant version of it (ENUM_FORMAT: CAPITAL_CASE) * @return An enum constant version of it (ENUM_FORMAT: CAPITAL_CASE)
*/ */
public static String toEnumFormat(String name) { public static String toEnumFormat(String name) {
StringBuilder result = new StringBuilder(name.length() + 2); StringBuilder result = new StringBuilder(name.length() + 2);
boolean capital = true; boolean capital = true;
for (int i = 0, n = name.length(); i < n; i++) { for (int i = 0, n = name.length(); i < n; i++) {
char c = name.charAt(i); char c = name.charAt(i);
if (capital) { if (capital) {
capital = Character.isUpperCase(c); capital = Character.isUpperCase(c);
} else if (Character.isUpperCase(c)) { } else if (Character.isUpperCase(c)) {
capital = true; capital = true;
result.append('_'); result.append('_');
} }
result.append(capital ? c : Character.toUpperCase(c)); result.append(capital ? c : Character.toUpperCase(c));
} }
return result.toString(); return result.toString();
} }
/** /**
* Replaces any occurrence of toReplace with another string. * Replaces any occurrence of toReplace with another string.
* Any colours that occured before the occurence of toReplace, are copied to the end of the replacement. * Any colours that occured before the occurence of toReplace, are copied to the end of the replacement.
* *
* @param target The String to query * @param target The String to query
* @param toReplace The sequence to replace * @param toReplace The sequence to replace
* @param with the replacing sequence * @param with the replacing sequence
* @return the result * @return the result
*/ */
public static String replaceKeepColours(String target, String toReplace, String with) { public static String replaceKeepColours(String target, String toReplace, String with) {
int index = -toReplace.length(); int index = -toReplace.length();
while ((index = target.indexOf(toReplace, index + toReplace.length())) != -1) { while ((index = target.indexOf(toReplace, index + toReplace.length())) != -1) {
String start = target.substring(0, index); String start = target.substring(0, index);
Formatting coloursBefore = Formatting.getFormats(start); Formatting coloursBefore = Formatting.getFormats(start);
String after; String after;
try { try {
after = target.substring(index + toReplace.length()); after = target.substring(index + toReplace.length());
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
after = ""; after = "";
} }
target = start + with + coloursBefore + after; target = start + with + coloursBefore + after;
} }
return target; return target;
} }
public static String replParam(String target, String param, Object repl) { public static String replParam(String target, String param, Object repl) {
return replParam(target, param, repl, false); return replParam(target, param, repl, false);
} }
public static String replParams(String target, String[] params, Object[] repls) { public static String replParams(String target, String[] params, Object[] repls) {
return replParams(target, params, repls, false, false); return replParams(target, params, repls, false, false);
} }
public static boolean replParams(String[] target, String[] params, Object[] repls) { public static boolean replParams(String[] target, String[] params, Object[] repls) {
return replParams(target, 0, target.length, params, repls); return replParams(target, 0, target.length, params, repls);
} }
public static boolean replParams(String[] target, int from, int to, String[] params, Object[] repls) { public static boolean replParams(String[] target, int from, int to, String[] params, Object[] repls) {
return replParams(target, from, to, params, repls, false); return replParams(target, from, to, params, repls, false);
} }
public static boolean replParams(List<String> target, String[] params, Object[] repls) { public static boolean replParams(List<String> target, String[] params, Object[] repls) {
return replParams(target, 0, target.size(), params, repls); return replParams(target, 0, target.size(), params, repls);
} }
public static boolean replParams(List<String> target, int from, int to, String[] params, Object[] repls) { public static boolean replParams(List<String> target, int from, int to, String[] params, Object[] repls) {
return replParams(target, from, to, params, repls, false); return replParams(target, from, to, params, repls, false);
} }
public static String replParamAndTranslate(String target, String param, Object repl) { public static String replParamAndTranslate(String target, String param, Object repl) {
return replParam(target, param, repl, true); return replParam(target, param, repl, true);
} }
public static String replParamsAndTranslate(String target, String[] params, Object[] repls) { public static String replParamsAndTranslate(String target, String[] params, Object[] repls) {
return replParams(target, params, repls, false, true); return replParams(target, params, repls, false, true);
} }
public static boolean replParamsAndTranslate(String[] target, String[] params, Object[] repls) { public static boolean replParamsAndTranslate(String[] target, String[] params, Object[] repls) {
return replParamsAndTranslate(target, 0, target.length, params, repls); return replParamsAndTranslate(target, 0, target.length, params, repls);
} }
public static boolean replParamsAndTranslate(String[] target, int from, int to, String[] params, Object[] repls) { public static boolean replParamsAndTranslate(String[] target, int from, int to, String[] params, Object[] repls) {
return replParams(target, from, to, params, repls, true); return replParams(target, from, to, params, repls, true);
} }
public static boolean replParamsAndTranslate(List<String> target, String[] params, Object[] repls) { public static boolean replParamsAndTranslate(List<String> target, String[] params, Object[] repls) {
return replParamsAndTranslate(target, 0, target.size(), params, repls); return replParamsAndTranslate(target, 0, target.size(), params, repls);
} }
public static boolean replParamsAndTranslate(List<String> target, int from, int to, String[] params, Object[] repls) { public static boolean replParamsAndTranslate(List<String> target, int from, int to, String[] params, Object[] repls) {
return replParams(target, from, to, params, repls, true); return replParams(target, from, to, params, repls, true);
} }
private static String replParam(String target, String param, Object replacementObj, boolean translate) { private static String replParam(String target, String param, Object replacementObj, boolean translate) {
int idx = target.indexOf(param, 0); int idx = target.indexOf(param, 0);
if (idx == -1) { if (idx == -1) {
return translate ? Formatting.translate(target) : target; return translate ? Formatting.translate(target) : target;
} }
String rep = replacementObj.toString(); String rep = replacementObj.toString();
StringBuilder builder = new StringBuilder(target); StringBuilder builder = new StringBuilder(target);
do { do {
builder.replace(idx, idx + param.length(), rep); builder.replace(idx, idx + param.length(), rep);
idx = builder.indexOf(param, idx + rep.length()); idx = builder.indexOf(param, idx + rep.length());
} while (idx != -1); } while (idx != -1);
if (translate) { if (translate) {
Formatting.translate(builder); Formatting.translate(builder);
} }
return builder.toString(); return builder.toString();
} }
@SuppressWarnings("StringEquality") @SuppressWarnings("StringEquality")
private static boolean replParams(String[] target, int from, int to, String[] params, Object[] repls, boolean translate) { private static boolean replParams(String[] target, int from, int to, String[] params, Object[] repls, boolean translate) {
if (from < 0 || to < from || to > target.length) { if (from < 0 || to < from || to > target.length) {
throw new IllegalArgumentException("Invalid from-to for array size " + target.length + ": " + from + "-" + to); throw new IllegalArgumentException("Invalid from-to for array size " + target.length + ": " + from + "-" + to);
} }
boolean change = false; boolean change = false;
for (int i = from; i < to; i++) { for (int i = from; i < to; i++) {
String val = target[i]; String val = target[i];
if (val != (val = replParams(val, params, repls, true, translate))) { if (val != (val = replParams(val, params, repls, true, translate))) {
target[i] = val; target[i] = val;
change = true; change = true;
} }
} }
return change; return change;
} }
@SuppressWarnings("StringEquality") @SuppressWarnings("StringEquality")
private static boolean replParams(List<String> target, int from, int to, String[] params, Object[] repls, boolean translate) { private static boolean replParams(List<String> target, int from, int to, String[] params, Object[] repls, boolean translate) {
if (from < 0 || to < from || to > target.size()) { if (from < 0 || to < from || to > target.size()) {
throw new IllegalArgumentException("Invalid from-to for list size " + target.size() + ": " + from + "-" + to); throw new IllegalArgumentException("Invalid from-to for list size " + target.size() + ": " + from + "-" + to);
} }
boolean change = false; boolean change = false;
if (target instanceof RandomAccess) { if (target instanceof RandomAccess) {
for (int i = from; i < to; i++) { for (int i = from; i < to; i++) {
String val = target.get(i); String val = target.get(i);
if (val != (val = replParams(val, params, repls, true, translate))) { if (val != (val = replParams(val, params, repls, true, translate))) {
target.set(i, val); target.set(i, val);
change = true; change = true;
} }
} }
} else { } else {
ListIterator<String> itr = target.listIterator(from); ListIterator<String> itr = target.listIterator(from);
for (int n = to - from, i = 0; i < n && itr.hasNext(); i++) { for (int n = to - from, i = 0; i < n && itr.hasNext(); i++) {
String val = itr.next(); String val = itr.next();
if (val != (val = replParams(val, params, repls, true, translate))) { if (val != (val = replParams(val, params, repls, true, translate))) {
itr.set(val); itr.set(val);
change = true; change = true;
} }
} }
} }
return change; return change;
} }
private static String replParams(String target, String[] params, Object[] repls, boolean updateRepls, boolean translate) { private static String replParams(String target, String[] params, Object[] repls, boolean updateRepls, boolean translate) {
int n = params.length; int n = params.length;
if (n != repls.length) { if (n != repls.length) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
String param = null; String param = null;
int idx = -1; int idx = -1;
int i; int i;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
param = params[i]; param = params[i];
if (param == null) { if (param == null) {
continue; continue;
} }
idx = target.indexOf(param, 0); idx = target.indexOf(param, 0);
if (idx != -1) { if (idx != -1) {
break; break;
} }
} }
if (idx == -1) { if (idx == -1) {
return translate ? Formatting.translate(target) : target; return translate ? Formatting.translate(target) : target;
} }
String repl = repls[i].toString(); String repl = repls[i].toString();
if (updateRepls) { if (updateRepls) {
repls[i] = repl; repls[i] = repl;
} }
StringBuilder builder = new StringBuilder(target); StringBuilder builder = new StringBuilder(target);
do { do {
builder.replace(idx, idx + param.length(), repl); builder.replace(idx, idx + param.length(), repl);
idx = builder.indexOf(param, idx + repl.length()); idx = builder.indexOf(param, idx + repl.length());
} while (idx != -1); } while (idx != -1);
for (i++; i < n; i++) { for (i++; i < n; i++) {
param = params[i]; param = params[i];
if (param == null || (idx = builder.indexOf(param, 0)) == -1) { if (param == null || (idx = builder.indexOf(param, 0)) == -1) {
continue; continue;
} }
repl = repls[i].toString(); repl = repls[i].toString();
if (updateRepls) { if (updateRepls) {
repls[i] = repl; repls[i] = repl;
} }
do { do {
builder.replace(idx, idx + param.length(), repl); builder.replace(idx, idx + param.length(), repl);
idx = builder.indexOf(param, idx + repl.length()); idx = builder.indexOf(param, idx + repl.length());
} while (idx != -1); } while (idx != -1);
} }
if (translate) { if (translate) {
Formatting.translate(builder); Formatting.translate(builder);
} }
return builder.toString(); return builder.toString();
} }
} }

View File

@@ -1,91 +1,91 @@
package io.dico.dicore; package io.dico.dicore;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@FunctionalInterface @FunctionalInterface
public interface Whitelist extends Predicate { public interface Whitelist extends Predicate {
Whitelist EVERYTHING = item -> true; Whitelist EVERYTHING = item -> true;
Whitelist NOTHING = item -> false; Whitelist NOTHING = item -> false;
Whitelist NOT_NULL = Objects::nonNull; Whitelist NOT_NULL = Objects::nonNull;
static <T> Predicate<T> everythingAsPredicate() { static <T> Predicate<T> everythingAsPredicate() {
return (Predicate<T>) EVERYTHING; return (Predicate<T>) EVERYTHING;
} }
static <T> Predicate<T> nothingAsPredicate() { static <T> Predicate<T> nothingAsPredicate() {
return (Predicate<T>) NOTHING; return (Predicate<T>) NOTHING;
} }
static <T> Predicate<T> notNullAsPredicate() { static <T> Predicate<T> notNullAsPredicate() {
return (Predicate<T>) NOT_NULL; return (Predicate<T>) NOT_NULL;
} }
static Whitelist only(Object item) { static Whitelist only(Object item) {
return item::equals; return item::equals;
} }
static Whitelist not(Object item) { static Whitelist not(Object item) {
return o -> !item.equals(o); return o -> !item.equals(o);
} }
static Whitelist only(Object item1, Object item2) { static Whitelist only(Object item1, Object item2) {
return item -> item1.equals(item) || item2.equals(item); return item -> item1.equals(item) || item2.equals(item);
} }
static Whitelist not(Object item1, Object item2) { static Whitelist not(Object item1, Object item2) {
return item -> !(item1.equals(item) || item2.equals(item)); return item -> !(item1.equals(item) || item2.equals(item));
} }
static Whitelist only(Object[] objects) { static Whitelist only(Object[] objects) {
return new SetBasedWhitelist(objects, false); return new SetBasedWhitelist(objects, false);
} }
static Whitelist not(Object[] objects) { static Whitelist not(Object[] objects) {
return new SetBasedWhitelist(objects, true); return new SetBasedWhitelist(objects, true);
} }
static Whitelist fromConfig(ConfigurationSection section, Function<String, ?> parser) { static Whitelist fromConfig(ConfigurationSection section, Function<String, ?> parser) {
if (section == null) { if (section == null) {
return NOTHING; return NOTHING;
} }
boolean blacklist = section.getBoolean("blacklist", false); boolean blacklist = section.getBoolean("blacklist", false);
Set list = section.getStringList("listed").stream().map(parser).filter(Objects::nonNull).collect(Collectors.toSet()); Set list = section.getStringList("listed").stream().map(parser).filter(Objects::nonNull).collect(Collectors.toSet());
switch (list.size()) { switch (list.size()) {
case 0: case 0:
return blacklist ? EVERYTHING : NOTHING; return blacklist ? EVERYTHING : NOTHING;
case 1: { case 1: {
Iterator iterator = list.iterator(); Iterator iterator = list.iterator();
return blacklist ? not(iterator.next()) : only(iterator.next()); return blacklist ? not(iterator.next()) : only(iterator.next());
} }
case 2: { case 2: {
Iterator iterator = list.iterator(); Iterator iterator = list.iterator();
return blacklist ? not(iterator.next(), iterator.next()) : only(iterator.next(), iterator.next()); return blacklist ? not(iterator.next(), iterator.next()) : only(iterator.next(), iterator.next());
} }
default: default:
Object item = list.iterator().next(); Object item = list.iterator().next();
if (item instanceof Enum) { if (item instanceof Enum) {
list = EnumSet.copyOf(list); list = EnumSet.copyOf(list);
} }
return new SetBasedWhitelist(list, blacklist); return new SetBasedWhitelist(list, blacklist);
} }
} }
static void copyIntoConfig(ConfigurationSection target, Function<Object, String> mapper, boolean blacklist, Object... objects) { static void copyIntoConfig(ConfigurationSection target, Function<Object, String> mapper, boolean blacklist, Object... objects) {
target.set("blacklist", blacklist); target.set("blacklist", blacklist);
target.set("listed", Arrays.stream(objects).map(mapper).unordered().distinct().collect(Collectors.toList())); target.set("listed", Arrays.stream(objects).map(mapper).unordered().distinct().collect(Collectors.toList()));
} }
@Override @Override
default boolean test(Object o) { default boolean test(Object o) {
return isWhitelisted(o); return isWhitelisted(o);
} }
boolean isWhitelisted(Object o); boolean isWhitelisted(Object o);
} }

View File

@@ -1,46 +1,46 @@
package io.dico.dicore.event; package io.dico.dicore.event;
import io.dico.dicore.InterfaceChain; import io.dico.dicore.InterfaceChain;
public interface ChainedListener<T> extends InterfaceChain<SimpleListener<T>, ChainedListener<T>>, SimpleListener<T> { public interface ChainedListener<T> extends InterfaceChain<SimpleListener<T>, ChainedListener<T>>, SimpleListener<T> {
@Override @Override
default ChainedListener<T> getEmptyInstance() { default ChainedListener<T> getEmptyInstance() {
return ChainedListeners.empty(); return ChainedListeners.empty();
} }
@Override @Override
default ChainedListener<T> withElement(SimpleListener<T> element) { default ChainedListener<T> withElement(SimpleListener<T> element) {
if (element == null) { if (element == null) {
return this; return this;
} }
int count = getElementCount() + 1; int count = getElementCount() + 1;
return new ChainedListener<T>() { return new ChainedListener<T>() {
@Override @Override
public void accept(T event) { public void accept(T event) {
try { try {
ChainedListener.this.accept(event); ChainedListener.this.accept(event);
} finally { } finally {
element.accept(event); element.accept(event);
} }
} }
@Override @Override
public ChainedListener<T> withoutLastNode() { public ChainedListener<T> withoutLastNode() {
return ChainedListener.this; return ChainedListener.this;
} }
@Override @Override
public SimpleListener<T> getDelegateOfLastNode() { public SimpleListener<T> getDelegateOfLastNode() {
return element; return element;
} }
@Override @Override
public int getElementCount() { public int getElementCount() {
return count; return count;
} }
}; };
} }
} }

View File

@@ -1,55 +1,55 @@
package io.dico.dicore.event; package io.dico.dicore.event;
import io.dico.dicore.InterfaceChain; import io.dico.dicore.InterfaceChain;
public interface ChainedListenerHandle extends InterfaceChain<ListenerHandle, ChainedListenerHandle>, ListenerHandle { public interface ChainedListenerHandle extends InterfaceChain<ListenerHandle, ChainedListenerHandle>, ListenerHandle {
@Override @Override
default ChainedListenerHandle getEmptyInstance() { default ChainedListenerHandle getEmptyInstance() {
return ChainedListenerHandles.empty(); return ChainedListenerHandles.empty();
} }
@Override @Override
default ChainedListenerHandle withElement(ListenerHandle element) { default ChainedListenerHandle withElement(ListenerHandle element) {
if (element == null) { if (element == null) {
return this; return this;
} }
int count = getElementCount() + 1; int count = getElementCount() + 1;
return new ChainedListenerHandle() { return new ChainedListenerHandle() {
@Override @Override
public void register() { public void register() {
try { try {
ChainedListenerHandle.this.register(); ChainedListenerHandle.this.register();
} finally { } finally {
element.register(); element.register();
} }
} }
@Override @Override
public void unregister() { public void unregister() {
try { try {
ChainedListenerHandle.this.unregister(); ChainedListenerHandle.this.unregister();
} finally { } finally {
element.unregister(); element.unregister();
} }
} }
@Override @Override
public ChainedListenerHandle withoutLastNode() { public ChainedListenerHandle withoutLastNode() {
return ChainedListenerHandle.this; return ChainedListenerHandle.this;
} }
@Override @Override
public ListenerHandle getDelegateOfLastNode() { public ListenerHandle getDelegateOfLastNode() {
return element; return element;
} }
@Override @Override
public int getElementCount() { public int getElementCount() {
return count; return count;
} }
}; };
} }
} }

View File

@@ -1,63 +1,63 @@
package io.dico.dicore.event; package io.dico.dicore.event;
public class ChainedListenerHandles { public class ChainedListenerHandles {
private ChainedListenerHandles() { private ChainedListenerHandles() {
} }
private static final ChainedListenerHandle empty = new ChainedListenerHandle() { private static final ChainedListenerHandle empty = new ChainedListenerHandle() {
@Override @Override
public void register() { public void register() {
} }
public void unregister() { public void unregister() {
} }
@Override @Override
public ChainedListenerHandle withElement(ListenerHandle other) { public ChainedListenerHandle withElement(ListenerHandle other) {
return ChainedListenerHandles.singleton(other); return ChainedListenerHandles.singleton(other);
} }
@Override @Override
public int getElementCount() { public int getElementCount() {
return 0; return 0;
} }
@Override @Override
public ListenerHandle getDelegateOfLastNode() { public ListenerHandle getDelegateOfLastNode() {
return null; return null;
} }
}; };
public static ChainedListenerHandle empty() { public static ChainedListenerHandle empty() {
return empty; return empty;
} }
public static ChainedListenerHandle singleton(ListenerHandle element) { public static ChainedListenerHandle singleton(ListenerHandle element) {
if (element instanceof ChainedListenerHandle) { if (element instanceof ChainedListenerHandle) {
return (ChainedListenerHandle) element; return (ChainedListenerHandle) element;
} }
if (element == null) { if (element == null) {
return empty(); return empty();
} }
return new ChainedListenerHandle() { return new ChainedListenerHandle() {
@Override @Override
public void register() { public void register() {
element.register(); element.register();
} }
public void unregister() { public void unregister() {
element.unregister(); element.unregister();
} }
@Override @Override
public ListenerHandle getDelegateOfLastNode() { public ListenerHandle getDelegateOfLastNode() {
return element; return element;
} }
}; };
} }
} }

View File

@@ -1,56 +1,56 @@
package io.dico.dicore.event; package io.dico.dicore.event;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class ChainedListeners { public class ChainedListeners {
private static final ChainedListener<?> empty = new ChainedListener<Object>() { private static final ChainedListener<?> empty = new ChainedListener<Object>() {
@Override @Override
public void accept(Object event) { public void accept(Object event) {
} }
@Override @Override
public ChainedListener<Object> withElement(SimpleListener other) { public ChainedListener<Object> withElement(SimpleListener other) {
return ChainedListeners.singleton(other); return ChainedListeners.singleton(other);
} }
@Override @Override
public int getElementCount() { public int getElementCount() {
return 0; return 0;
} }
@Override @Override
public SimpleListener<Object> getDelegateOfLastNode() { public SimpleListener<Object> getDelegateOfLastNode() {
return null; return null;
} }
}; };
private ChainedListeners() { private ChainedListeners() {
} }
public static <T> ChainedListener<T> empty() { public static <T> ChainedListener<T> empty() {
return (ChainedListener<T>) empty; return (ChainedListener<T>) empty;
} }
public static <T> ChainedListener<T> singleton(SimpleListener<T> element) { public static <T> ChainedListener<T> singleton(SimpleListener<T> element) {
if (element instanceof ChainedListener) { if (element instanceof ChainedListener) {
return (ChainedListener<T>) element; return (ChainedListener<T>) element;
} }
if (element == null) { if (element == null) {
return empty(); return empty();
} }
return new ChainedListener<T>() { return new ChainedListener<T>() {
@Override @Override
public void accept(T event) { public void accept(T event) {
element.accept(event); element.accept(event);
} }
@Override @Override
public SimpleListener getDelegateOfLastNode() { public SimpleListener getDelegateOfLastNode() {
return element; return element;
} }
}; };
} }
} }

View File

@@ -1,91 +1,91 @@
package io.dico.dicore.event; package io.dico.dicore.event;
import org.bukkit.event.Cancellable; import org.bukkit.event.Cancellable;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
public final class HandlerList<T> { public final class HandlerList<T> {
private final List<Listener<T>> source = new ArrayList<>(); private final List<Listener<T>> source = new ArrayList<>();
private Listener<T>[] listeners = newArray(0); private Listener<T>[] listeners = newArray(0);
public void refresh() { public void refresh() {
source.sort(Comparator.comparingInt(l -> l.getPriority().ordinal())); source.sort(Comparator.comparingInt(l -> l.getPriority().ordinal()));
listeners = source.toArray(newArray(source.size())); listeners = source.toArray(newArray(source.size()));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static <T> Listener<T>[] newArray(int length) { private static <T> Listener<T>[] newArray(int length) {
return new Listener[length]; return new Listener[length];
} }
public void register(Listener<T> listener) { public void register(Listener<T> listener) {
if (!source.contains(listener) && source.add(listener)) { if (!source.contains(listener) && source.add(listener)) {
refresh(); refresh();
} }
} }
public ListenerHandle getListenerHandle(Listener<T> listener) { public ListenerHandle getListenerHandle(Listener<T> listener) {
return new ListenerHandle() { return new ListenerHandle() {
@Override @Override
public void register() { public void register() {
HandlerList.this.register(listener); HandlerList.this.register(listener);
} }
@Override @Override
public void unregister() { public void unregister() {
HandlerList.this.unregister(listener); HandlerList.this.unregister(listener);
} }
}; };
} }
public void register(EventPriority priority, Consumer<T> listener) { public void register(EventPriority priority, Consumer<T> listener) {
register(new Listener<T>() { register(new Listener<T>() {
@Override @Override
public EventPriority getPriority() { public EventPriority getPriority() {
return priority; return priority;
} }
@Override @Override
public void accept(T event) { public void accept(T event) {
listener.accept(event); listener.accept(event);
} }
}); });
} }
public List<Listener<T>> getRegistrations() { public List<Listener<T>> getRegistrations() {
return Collections.unmodifiableList(source); return Collections.unmodifiableList(source);
} }
public void unregister(Listener<T> listener) { public void unregister(Listener<T> listener) {
if (source.remove(listener)) { if (source.remove(listener)) {
refresh(); refresh();
} }
} }
public void callEvent(T event) { public void callEvent(T event) {
if (event instanceof Cancellable) { if (event instanceof Cancellable) {
Cancellable c = (Cancellable) event; Cancellable c = (Cancellable) event;
boolean cancelled = c.isCancelled(); boolean cancelled = c.isCancelled();
for (Listener<T> listener : listeners) { for (Listener<T> listener : listeners) {
if (listener.listensToCancelledState(cancelled)) { if (listener.listensToCancelledState(cancelled)) {
//EnchantsPlugin.getInstance().debug("Listener acceptance: " + listener.getClass().getSimpleName()); //EnchantsPlugin.getInstance().debug("Listener acceptance: " + listener.getClass().getSimpleName());
listener.accept(event); listener.accept(event);
cancelled = c.isCancelled(); cancelled = c.isCancelled();
} /*else { } /*else {
EnchantsPlugin.getInstance().debug("Listener does not listen to cancelled state of " + cancelled + ": " + listener.getClass().getSimpleName()); EnchantsPlugin.getInstance().debug("Listener does not listen to cancelled state of " + cancelled + ": " + listener.getClass().getSimpleName());
}*/ }*/
} }
} else { } else {
for (Listener<T> listener : listeners) { for (Listener<T> listener : listeners) {
//EnchantsPlugin.getInstance().debug("Listener acceptance: " + listener.getClass().getSimpleName()); //EnchantsPlugin.getInstance().debug("Listener acceptance: " + listener.getClass().getSimpleName());
listener.accept(event); listener.accept(event);
} }
} }
} }
} }

View File

@@ -1,17 +1,17 @@
package io.dico.dicore.event; package io.dico.dicore.event;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
public interface Listener<T> { public interface Listener<T> {
default EventPriority getPriority() { default EventPriority getPriority() {
return EventPriority.NORMAL; return EventPriority.NORMAL;
} }
default boolean listensToCancelledState(boolean cancelled) { default boolean listensToCancelledState(boolean cancelled) {
return !cancelled; return !cancelled;
} }
void accept(T event); void accept(T event);
} }

View File

@@ -1,9 +1,9 @@
package io.dico.dicore.event; package io.dico.dicore.event;
public interface ListenerHandle { public interface ListenerHandle {
void register(); void register();
void unregister(); void unregister();
} }

View File

@@ -1,7 +1,7 @@
package io.dico.dicore.event; package io.dico.dicore.event;
public interface SimpleListener<T> { public interface SimpleListener<T> {
void accept(T event); void accept(T event);
} }

Some files were not shown because too many files have changed in this diff Show More