diff --git a/src/main/java/com/volmit/iris/core/decrees/DecreeIris.java b/src/main/java/com/volmit/iris/core/decrees/DecreeIris.java
new file mode 100644
index 000000000..f7ec71182
--- /dev/null
+++ b/src/main/java/com/volmit/iris/core/decrees/DecreeIris.java
@@ -0,0 +1,32 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 Arcane Arts (Volmit Software)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.core.decrees;
+
+import com.volmit.iris.util.decree.DecreeExecutor;
+import com.volmit.iris.util.decree.annotations.Decree;
+
+@Decree(name = "irisd", aliases = {"ird"}, description = "Basic Command")
+public class DecreeIris implements DecreeExecutor
+{
+ @Decree(description = "Ping self", aliases = "p")
+ public void ping()
+ {
+ sender().sendMessage("Pong!");
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/collection/KList.java b/src/main/java/com/volmit/iris/util/collection/KList.java
index 40bab0cd2..cf6baac33 100644
--- a/src/main/java/com/volmit/iris/util/collection/KList.java
+++ b/src/main/java/com/volmit/iris/util/collection/KList.java
@@ -696,4 +696,9 @@ public class KList extends ArrayList implements List {
t.shuffle(rng);
return t;
}
+
+ public KList qdrop() {
+ pop();
+ return this;
+ }
}
diff --git a/src/main/java/com/volmit/iris/util/decree/DecreeCategory.java b/src/main/java/com/volmit/iris/util/decree/DecreeCategory.java
deleted file mode 100644
index 3971aa86e..000000000
--- a/src/main/java/com/volmit/iris/util/decree/DecreeCategory.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Iris is a World Generator for Minecraft Bukkit Servers
- * Copyright (c) 2021 Arcane Arts (Volmit Software)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package com.volmit.iris.util.decree;
-
-import com.volmit.iris.util.collection.KList;
-import com.volmit.iris.util.decree.annotations.Decree;
-import com.volmit.iris.util.decree.annotations.Param;
-import com.volmit.iris.util.decree.exceptions.DecreeInstanceException;
-
-import java.lang.reflect.*;
-import java.util.Arrays;
-
-public class DecreeCategory {
- private final Class> clazz;
- private final Decree decree;
-
- public DecreeCategory(Class> clazz) throws DecreeInstanceException {
- this.clazz = clazz;
- this.decree = clazz.getDeclaredAnnotation(Decree.class);
- if (decree == null){
- throw new DecreeInstanceException("Cannot instantiate DecreeCategory on class not annotated by @Decree");
- }
- }
-
- /**
- * Get the subcommands of this decree category
- * @return The list of subcommands if ALL are only classes implementing DecreeCommand, else null
- */
- public KList getCommands() {
- KList c = new KList<>();
-
- for(Field i : clazz.getFields())
- {
- try {
- i.setAccessible(true);
- if (DecreeCommand.class.isAssignableFrom(i.getType())) {
- c.add((DecreeCommand) i.getType().getConstructor().newInstance());
- }
- } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) {
- e.printStackTrace();
- }
- }
-
- return c;
- }
-
- public String getName() {
- return decree.name().equals(Decree.METHOD_NAME) ? clazz.getName() : decree.name();
- }
-
- public DecreeOrigin getOrigin() {
- return decree.origin();
- }
-
- public String getDescription() {
- return decree.description().isEmpty() ? Decree.DEFAULT_DESCRIPTION : decree.description();
- }
-
- public KList getAliases() {
- KList d = new KList<>();
-
- if (Arrays.equals(decree.aliases(), new String[]{Decree.NO_ALIASES})){
- return d;
- }
-
- for(String i : decree.aliases())
- {
- if(i.isEmpty())
- {
- continue;
- }
-
- d.add(i);
- }
-
- return d;
- }
-}
diff --git a/src/main/java/com/volmit/iris/util/decree/DecreeExecutor.java b/src/main/java/com/volmit/iris/util/decree/DecreeExecutor.java
new file mode 100644
index 000000000..57c73514d
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/decree/DecreeExecutor.java
@@ -0,0 +1,33 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 Arcane Arts (Volmit Software)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.decree;
+
+import com.volmit.iris.util.plugin.VolmitSender;
+
+public interface DecreeExecutor {
+ default VolmitSender sender()
+ {
+ return DecreeContext.get();
+ }
+
+ default T get(T v, T ifUndefined)
+ {
+ return v == null ? ifUndefined : v;
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/decree/DecreeNode.java b/src/main/java/com/volmit/iris/util/decree/DecreeNode.java
index 6e11a33c2..e1d02713e 100644
--- a/src/main/java/com/volmit/iris/util/decree/DecreeNode.java
+++ b/src/main/java/com/volmit/iris/util/decree/DecreeNode.java
@@ -21,21 +21,24 @@ package com.volmit.iris.util.decree;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
-import com.volmit.iris.util.decree.exceptions.DecreeInstanceException;
+import lombok.Data;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
+@Data
public class DecreeNode {
private final Method method;
+ private final Object instance;
private final Decree decree;
- public DecreeNode(Method method) throws DecreeInstanceException {
+ public DecreeNode(Object instance, Method method) {
+ this.instance = instance;
this.method = method;
this.decree = method.getDeclaredAnnotation(Decree.class);
if (decree == null){
- throw new DecreeInstanceException("Cannot instantiate DecreeNode on method not annotated by @Decree");
+ throw new RuntimeException("Cannot instantiate DecreeNode on method " + method.getName() + " in " + method.getDeclaringClass().getCanonicalName() + " not annotated by @Decree");
}
}
@@ -48,18 +51,14 @@ public class DecreeNode {
for(Parameter i : method.getParameters())
{
- try {
- p.add(new DecreeParameter(i));
- } catch (DecreeInstanceException ignored) {
- return null;
- }
+ p.add(new DecreeParameter(i));
}
return p;
}
public String getName() {
- return decree.name().equals(Decree.METHOD_NAME) ? method.getName() : decree.name();
+ return decree.name().isEmpty() ? method.getName() : decree.name();
}
public DecreeOrigin getOrigin() {
@@ -70,13 +69,9 @@ public class DecreeNode {
return decree.description().isEmpty() ? Decree.DEFAULT_DESCRIPTION : decree.description();
}
- public KList getAliases() {
+ public KList getNames() {
KList d = new KList<>();
- if (Arrays.equals(decree.aliases(), new String[]{Decree.NO_ALIASES})){
- return d;
- }
-
for(String i : decree.aliases())
{
if(i.isEmpty())
@@ -87,6 +82,13 @@ public class DecreeNode {
d.add(i);
}
+
+ d.add(getName());
+ d.removeDuplicates();
return d;
}
+
+ public boolean isSync() {
+ return decree.sync();
+ }
}
diff --git a/src/main/java/com/volmit/iris/util/decree/DecreeParameter.java b/src/main/java/com/volmit/iris/util/decree/DecreeParameter.java
index de55ba881..4993e5ab1 100644
--- a/src/main/java/com/volmit/iris/util/decree/DecreeParameter.java
+++ b/src/main/java/com/volmit/iris/util/decree/DecreeParameter.java
@@ -20,7 +20,6 @@ package com.volmit.iris.util.decree;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.decree.annotations.Param;
-import com.volmit.iris.util.decree.exceptions.DecreeInstanceException;
import java.lang.reflect.Parameter;
import java.util.Arrays;
@@ -29,11 +28,11 @@ public class DecreeParameter {
private final Parameter parameter;
private final Param param;
- public DecreeParameter(Parameter parameter) throws DecreeInstanceException {
+ public DecreeParameter(Parameter parameter) {
this.parameter = parameter;
this.param = parameter.getDeclaredAnnotation(Param.class);
if (param == null){
- throw new DecreeInstanceException("Cannot instantiate DecreeParameter on parameter not annotated by @Param");
+ throw new RuntimeException("Cannot instantiate DecreeParameter on " + parameter.getName() + " in method " + parameter.getDeclaringExecutable().getName() + "(...) in class " + parameter.getDeclaringExecutable().getDeclaringClass().getCanonicalName() + " not annotated by @Param");
}
}
@@ -57,7 +56,7 @@ public class DecreeParameter {
return param.value().equals(Param.REQUIRED);
}
- public KList getAliases() {
+ public KList getNames() {
KList d = new KList<>();
if (Arrays.equals(param.aliases(), new String[]{Param.NO_ALIAS})){
@@ -74,6 +73,9 @@ public class DecreeParameter {
d.add(i);
}
+ d.add(getName());
+ d.removeDuplicates();
+
return d;
}
}
diff --git a/src/main/java/com/volmit/iris/util/decree/DecreeParameterHandler.java b/src/main/java/com/volmit/iris/util/decree/DecreeParameterHandler.java
index 7929f0163..7aae1b91d 100644
--- a/src/main/java/com/volmit/iris/util/decree/DecreeParameterHandler.java
+++ b/src/main/java/com/volmit/iris/util/decree/DecreeParameterHandler.java
@@ -48,19 +48,10 @@ public interface DecreeParameterHandler {
/**
* Returns whether a certain type is supported by this handler
- * By default, this checks if the {@link #parse(String) parse} method returns the corresponding type.
- * Hence, this should only be overwritten if multiple types, outside the designated one, are supported.
* @param type The type to check
* @return True if supported, false if not
*/
- default boolean supports(Class> type){
- try {
- if (this.getClass().getMethod("parse", String.class).getReturnType().equals(type)){
- return true;
- }
- } catch (NoSuchMethodException ignored){}
- return false;
- }
+ boolean supports(Class> type);
/**
* The possible entries for the inputted string (support for autocomplete on partial entries)
diff --git a/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java b/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java
index 55f6d09a2..7cf9e79fd 100644
--- a/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java
+++ b/src/main/java/com/volmit/iris/util/decree/DecreeSystem.java
@@ -20,24 +20,124 @@ package com.volmit.iris.util.decree;
import com.volmit.iris.Iris;
import com.volmit.iris.util.collection.KList;
-import com.volmit.iris.util.decree.annotations.Decree;
-import com.volmit.iris.util.math.M;
-import org.checkerframework.checker.units.qual.K;
+import com.volmit.iris.util.decree.virtual.VirtualDecreeCommand;
+import com.volmit.iris.util.plugin.VolmitSender;
+import com.volmit.iris.util.scheduling.J;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import java.util.List;
-public interface DecreeSystem {
+public interface DecreeSystem extends CommandExecutor, TabCompleter {
KList> handlers = Iris.initialize("com.volmit.iris.util.decree.handlers", null).convert((i) -> (DecreeParameterHandler>) i);
- /**
- * Should return the root command
- * Root must extend {@link DecreeCommand}
- *
- * @return The root command class (this#getClass)
- */
- Class extends DecreeCommand> getRoot();
+ VirtualDecreeCommand getRoot();
+
+ default boolean call(VolmitSender sender, String[] args)
+ {
+ DecreeContext.touch(sender);
+ return getRoot().invoke(sender, enhanceArgs(args));
+ }
+
+ @Nullable
+ @Override
+ default List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
+ return new KList<>();
+ }
+
+ @Override
+ default boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
+ J.aBukkit(() -> call(new VolmitSender(sender), args));
+ return true;
+ }
+
+ static KList enhanceArgs(String[] args)
+ {
+ KList a = new KList<>();
+
+ if(args.length == 0)
+ {
+ return a;
+ }
+
+ StringBuilder flat = new StringBuilder();
+ for(String i : args)
+ {
+ if(i.trim().isEmpty())
+ {
+ continue;
+ }
+
+ flat.append(" ").append(i.trim());
+ }
+
+ flat = new StringBuilder(flat.substring(1).trim());
+ StringBuilder arg = new StringBuilder();
+ boolean quoting = false;
+
+ for(int x = 0; x < flat.length(); x++)
+ {
+ char i = flat.charAt(x);
+ char j = x < flat.length() - 1 ? flat.charAt(x + 1) : i;
+ boolean hasNext = x < flat.length();
+
+ if(i == ' ' && !quoting)
+ {
+ if(!arg.toString().trim().isEmpty())
+ {
+ a.add(arg.toString().trim());
+ arg = new StringBuilder();
+ }
+ }
+
+ else if(i == '"')
+ {
+ if(!quoting && (arg.length() == 0))
+ {
+ quoting = true;
+ }
+
+ else if(quoting)
+ {
+ quoting = false;
+
+ if(hasNext && j == ' ')
+ {
+ if(!arg.toString().trim().isEmpty())
+ {
+ a.add(arg.toString().trim());
+ arg = new StringBuilder();
+ }
+ }
+
+ else if(!hasNext)
+ {
+ if(!arg.toString().trim().isEmpty())
+ {
+ a.add(arg.toString().trim());
+ arg = new StringBuilder();
+ }
+ }
+ }
+ }
+
+ else
+ {
+ arg.append(i);
+ }
+ }
+
+ if(!arg.toString().trim().isEmpty())
+ {
+ a.add(arg.toString().trim());
+ }
+
+ return a;
+ }
/**
* Get the handler for the specified type
@@ -55,18 +155,4 @@ public interface DecreeSystem {
}
return null;
}
-
- /**
- * Gets the method command to from the raw command parameters
- * @param command The raw command parameters
- * @return The @{@link Decree} method
- */
- default Method getRootCommandFrom(String[] command){
- return getCommandFrom(new KList<>(command), getRoot());
- }
-
-
- default Method getCommandFrom(KList command, Class extends DecreeCommand> decree){
- return null;
- }
}
diff --git a/src/main/java/com/volmit/iris/util/decree/Example.java b/src/main/java/com/volmit/iris/util/decree/Example.java
deleted file mode 100644
index a888050cf..000000000
--- a/src/main/java/com/volmit/iris/util/decree/Example.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Iris is a World Generator for Minecraft Bukkit Servers
- * Copyright (c) 2021 Arcane Arts (Volmit Software)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package com.volmit.iris.util.decree;
-
-import com.volmit.iris.util.decree.annotations.Decree;
-import com.volmit.iris.util.decree.annotations.Param;
-import org.bukkit.entity.Player;
-
-@Decree(description = "Description goes here!", aliases = {"ex", "e"})
-// The description here is shown when hovering over elements in the chat
-// The parameter `name` is undefined, which means it defaults to the name of the class, lowercase, so "example"
-// The aliases defined give alternate options for calling this category
-// You can also define "origin" which gives who can send the command.
-// By default, if omitted, this is DecreeOrigin.BOTH, but it can be .PLAYER & .CONSOLE
-public class Example implements DecreeCommand {
-
- // This subcommand, given that it implements DecreeCommand, is automatically indexed and recognised by Decree.
- // The way this command is called isn't defined from here.
- // Since subCommand can have another name than in /iris example subCommand.
- SubExample subCommand;
-
- @Decree(description = "Kick a player", aliases = "k", origin = DecreeOrigin.CONSOLE)
- public void kick(
- @Param(name = "player", description = "The Player to kick from the server", aliases = "p")
- Player player,
- @Param(name = "reason", description = "A reason to kick the player for", value = "No reason!", aliases = "k")
- String reason)
- {
- player.kickPlayer(reason);
- DecreeContext.get().sendMessage("Kicked " + player.getName());
- }
-}
diff --git a/src/main/java/com/volmit/iris/util/decree/annotations/Decree.java b/src/main/java/com/volmit/iris/util/decree/annotations/Decree.java
index 4d447d66d..02987adec 100644
--- a/src/main/java/com/volmit/iris/util/decree/annotations/Decree.java
+++ b/src/main/java/com/volmit/iris/util/decree/annotations/Decree.java
@@ -29,16 +29,14 @@ import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Decree {
- String METHOD_NAME = "Default Method Name";
-
String DEFAULT_DESCRIPTION = "No Description Provided";
- String NO_ALIASES = "No Aliases";
-
/**
* The name of this command, which is the Method's name by default
*/
- String name() default METHOD_NAME;
+ String name() default "";
+
+ boolean sync() default false;
/**
* The description of this command.
@@ -58,5 +56,5 @@ public @interface Decree {
* Can be initialized as just a string (ex. "alias") or as an array (ex. {"alias1", "alias2"})
* If someone uses /plugin foo and you specify alias="f" here, /plugin f will do the exact same.
*/
- String[] aliases() default {NO_ALIASES};
+ String[] aliases() default "";
}
diff --git a/src/main/java/com/volmit/iris/util/decree/annotations/Param.java b/src/main/java/com/volmit/iris/util/decree/annotations/Param.java
index 79b682a7c..022934464 100644
--- a/src/main/java/com/volmit/iris/util/decree/annotations/Param.java
+++ b/src/main/java/com/volmit/iris/util/decree/annotations/Param.java
@@ -28,7 +28,7 @@ import java.lang.annotation.Target;
public @interface Param {
String REQUIRED = "REQUIRED";
- String NO_ALIAS = "No Aliases Provided";
+ String NO_ALIAS = "";
String DEFAULT_DESCRIPTION = "No Description Provided";
diff --git a/src/main/java/com/volmit/iris/util/decree/exceptions/DecreeInstanceException.java b/src/main/java/com/volmit/iris/util/decree/exceptions/DecreeInstanceException.java
deleted file mode 100644
index f15bd3720..000000000
--- a/src/main/java/com/volmit/iris/util/decree/exceptions/DecreeInstanceException.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.volmit.iris.util.decree.exceptions;
-
-/**
- * Thrown when classes are instantiated that fail because of a missing or faulty decree component
- */
-public class DecreeInstanceException extends Exception {
- public DecreeInstanceException(String message){
- super(message);
- }
-}
diff --git a/src/main/java/com/volmit/iris/util/decree/exceptions/DecreeWhichException.java b/src/main/java/com/volmit/iris/util/decree/exceptions/DecreeWhichException.java
index 3401fdd9a..1a34ec754 100644
--- a/src/main/java/com/volmit/iris/util/decree/exceptions/DecreeWhichException.java
+++ b/src/main/java/com/volmit/iris/util/decree/exceptions/DecreeWhichException.java
@@ -18,12 +18,14 @@
package com.volmit.iris.util.decree.exceptions;
+import com.volmit.iris.util.collection.KList;
+
/**
* Thrown when more than one option is available for a singular mapping
* Like having a hashmap where one input maps to two outputs.
*/
public class DecreeWhichException extends Exception{
public DecreeWhichException() {
- super("More than one option for the entered input");
+ super();
}
}
diff --git a/src/main/java/com/volmit/iris/util/decree/virtual/VirtualDecreeCommand.java b/src/main/java/com/volmit/iris/util/decree/virtual/VirtualDecreeCommand.java
new file mode 100644
index 000000000..2640fa832
--- /dev/null
+++ b/src/main/java/com/volmit/iris/util/decree/virtual/VirtualDecreeCommand.java
@@ -0,0 +1,429 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2021 Arcane Arts (Volmit Software)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.decree.virtual;
+
+import com.volmit.iris.Iris;
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.collection.KMap;
+import com.volmit.iris.util.decree.DecreeContext;
+import com.volmit.iris.util.decree.DecreeNode;
+import com.volmit.iris.util.decree.DecreeParameter;
+import com.volmit.iris.util.decree.DecreeSystem;
+import com.volmit.iris.util.decree.annotations.Decree;
+import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
+import com.volmit.iris.util.decree.exceptions.DecreeWhichException;
+import com.volmit.iris.util.format.C;
+import com.volmit.iris.util.plugin.VolmitSender;
+import com.volmit.iris.util.scheduling.J;
+import lombok.Data;
+import lombok.Getter;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Objects;
+
+@Data
+public class VirtualDecreeCommand {
+ private final Class> type;
+ private final VirtualDecreeCommand parent;
+ private final KList nodes;
+ private final DecreeNode node;
+
+ private VirtualDecreeCommand(Class> type, VirtualDecreeCommand parent, KList nodes, DecreeNode node)
+ {
+ this.parent = parent;
+ this.type = type;
+ this.nodes = nodes;
+ this.node = node;
+ }
+
+ public static VirtualDecreeCommand createRoot(Object v) throws Throwable {
+ return createRoot(null, v);
+ }
+
+ public static VirtualDecreeCommand createRoot(VirtualDecreeCommand parent, Object v) throws Throwable {
+ VirtualDecreeCommand c = new VirtualDecreeCommand(v.getClass(), parent, new KList<>(), null);
+
+ for(Field i : v.getClass().getDeclaredFields())
+ {
+ if(Modifier.isStatic(i.getModifiers()) || Modifier.isFinal(i.getModifiers())|| Modifier.isTransient(i.getModifiers())|| Modifier.isVolatile(i.getModifiers()))
+ {
+ continue;
+ }
+
+ if(!i.getType().isAnnotationPresent(Decree.class))
+ {
+ continue;
+ }
+
+ i.setAccessible(true);
+ Object childRoot = i.get(v);
+
+ if(childRoot == null)
+ {
+ i.set(v, i.getType().getConstructor().newInstance());
+ }
+
+ c.getNodes().add(createRoot(c, v));
+ }
+
+ for(Method i : v.getClass().getDeclaredMethods())
+ {
+ if(Modifier.isStatic(i.getModifiers()) || Modifier.isFinal(i.getModifiers()) || Modifier.isPrivate(i.getModifiers()))
+ {
+ continue;
+ }
+
+ if(!i.isAnnotationPresent(Decree.class))
+ {
+ continue;
+ }
+
+ c.getNodes().add(new VirtualDecreeCommand(v.getClass(), c, new KList<>(), new DecreeNode(v, i)));
+ }
+
+ return c;
+ }
+
+ public String getPath()
+ {
+ KList n = new KList<>();
+ VirtualDecreeCommand cursor = this;
+
+ while(cursor.getParent() != null)
+ {
+ cursor = cursor.getParent();
+ n.add(cursor.getName());
+ }
+
+ return "/" + n.reverse().qadd(getName()).toString(" ");
+ }
+
+ public String getName()
+ {
+ return isNode() ? getNode().getName() : getType().getDeclaredAnnotation(Decree.class).name();
+ }
+
+ public String getDescription()
+ {
+ return isNode() ? getNode().getDescription() : getType().getDeclaredAnnotation(Decree.class).description();
+ }
+
+ public KList getNames()
+ {
+ if(isNode())
+ {
+ return getNode().getNames();
+ }
+
+ KList d = new KList<>();
+ Decree dc = getType().getDeclaredAnnotation(Decree.class);
+ for(String i : dc.aliases())
+ {
+ if(i.isEmpty())
+ {
+ continue;
+ }
+
+ d.add(i);
+ }
+
+ d.add(dc.name());
+ d.removeDuplicates();
+
+ return d;
+ }
+
+ public boolean isNode()
+ {
+ return node != null;
+ }
+
+ private KMap map(VolmitSender sender, KList in)
+ {
+ KMap data = new KMap<>();
+
+ for(int ix = 0; ix < in.size(); ix++)
+ {
+ String i = in.get(ix);
+ if(i.contains("="))
+ {
+ String[] v = i.split("\\Q=\\E");
+ String key = v[0];
+ String value = v[1];
+ DecreeParameter param = null;
+
+ for(DecreeParameter j : getNode().getParameters())
+ {
+ for(String k : j.getNames())
+ {
+ if(k.equalsIgnoreCase(key))
+ {
+ param = j;
+ break;
+ }
+ }
+ }
+
+ if(param == null)
+ {
+ for(DecreeParameter j : getNode().getParameters())
+ {
+ for(String k : j.getNames())
+ {
+ if(k.toLowerCase().contains(key.toLowerCase()) || key.toLowerCase().contains(k.toLowerCase()))
+ {
+ param = j;
+ break;
+ }
+ }
+ }
+ }
+
+ if(param == null)
+ {
+ Iris.debug("Can't find parameter key for " + key + "=" + value + " in " + getPath());
+ // TODO: WARN UNKNOWN PARAMETER
+ continue;
+ }
+
+ key = param.getName();
+
+ try {
+ data.put(key, param.getHandler().parse(value));
+ } catch (DecreeParsingException e) {
+ Iris.debug("Can't parse parameter value for " + key + "=" + value + " in " + getPath() + " using handler " + param.getHandler().getClass().getSimpleName());
+ // TODO: WARN BAD PARAM
+ return null;
+ } catch (DecreeWhichException e) {
+ KList> validOptions = param.getHandler().getPossibilities(value);
+ Iris.debug("Found multiple results for " + key + "=" + value + " in " + getPath() + " using the handler " + param.getHandler().getClass().getSimpleName() + " with potential matches [" + validOptions.toString(",") + "]. Asking client to define one");
+ String update = null; // TODO: PICK ONE
+ Iris.debug("Client chose " + update + " for " + key + "=" + value + " (old) in " + getPath());
+ in.set(ix--, update);
+ }
+ }
+
+ else
+ {
+ try
+ {
+ DecreeParameter par = getNode().getParameters().get(ix);
+ try {
+ data.put(par.getName(), par.getHandler().parse(i));
+ } catch (DecreeParsingException e) {
+ Iris.debug("Can't parse parameter value for " + par.getNames() + "=" + i + " in " + getPath() + " using handler " + par.getHandler().getClass().getSimpleName());
+ // TODO: WARN BAD PARAM
+ return null;
+ } catch (DecreeWhichException e) {
+ Iris.debug("Can't parse parameter value for " + par.getNames() + "=" + i + " in " + getPath() + " using handler " + par.getHandler().getClass().getSimpleName());
+ KList> validOptions = par.getHandler().getPossibilities(i);
+ String update = null;
+ Iris.debug("Client chose " + update + " for " + par.getNames() + "=" + i + " (old) in " + getPath());
+ in.set(ix--, update);
+ }
+ }
+
+ catch(ArrayIndexOutOfBoundsException e)
+ {
+ // TODO: Ignoring parameter (not in method anywhere
+ }
+ }
+ }
+
+ return data;
+ }
+
+ public boolean invoke(VolmitSender sender, KList realArgs)
+ {
+ return invoke(sender, realArgs, new KList<>());
+ }
+
+ public boolean invoke(VolmitSender sender, KList args, KList skip)
+ {
+ Iris.debug("@ " + getPath() + " with " + args.toString(", "));
+ if(isNode())
+ {
+ Iris.debug("Invoke " +getPath() + "(" + args.toString(",") + ") at ");
+ if(invokeNode(sender, map(sender, args)))
+ {
+ return true;
+ }
+
+ skip.add(hashCode());
+ return false;
+ }
+
+ if(args.isEmpty())
+ {
+ int m = getNodes().size();
+
+ if(getNodes().isNotEmpty())
+ {
+ for(VirtualDecreeCommand i : getNodes())
+ {
+ sender.sendMessage(i.getPath() + " - " + i.getDescription());
+ }
+ }
+
+ else
+ {
+ sender.sendMessage(C.RED + "There are no subcommands in this group! Contact support, this is a command design issue!");
+ }
+
+ return true;
+ }
+
+ String head = args.get(0);
+ VirtualDecreeCommand match = matchNode(head, skip);
+
+ if(match != null)
+ {
+ args.pop();
+ return match.invoke(sender, args, skip);
+ }
+
+ skip.add(hashCode());
+
+ return false;
+ }
+
+ private boolean invokeNode(VolmitSender sender, KMap map) {
+ if(map == null)
+ {
+ return false;
+ }
+
+ Object[] params = new Object[getNode().getMethod().getParameterCount()];
+ int vm = 0;
+ for(DecreeParameter i : getNode().getParameters())
+ {
+ Object value = map.get(i.getName());
+
+ if(value == null)
+ {
+ if(i.isRequired())
+ {
+ // TODO: REQUIRED... UNDEFINED
+ return false;
+ }
+ }
+
+ params[vm] = value;
+ vm++;
+ }
+
+ Runnable rx = () -> {
+ try
+ {
+ DecreeContext.touch(sender);
+ getNode().getMethod().setAccessible(true);
+ getNode().getMethod().invoke(getNode().getInstance(), params);
+ }
+
+ catch(Throwable e)
+ {
+ e.printStackTrace();
+ throw new RuntimeException("Failed to execute "); // TODO:
+ }
+ };
+
+ if(getNode().isSync())
+ {
+ J.s(rx);
+ }
+
+ else
+ {
+ rx.run();
+ }
+
+ return true;
+ }
+
+ public VirtualDecreeCommand matchNode(String in, KList skip)
+ {
+ for(VirtualDecreeCommand i : nodes)
+ {
+ if(skip.contains(i.hashCode()))
+ {
+ continue;
+ }
+
+ if(i.matches(in))
+ {
+ return i;
+ }
+ }
+
+ for(VirtualDecreeCommand i : nodes)
+ {
+ if(skip.contains(i.hashCode()))
+ {
+ continue;
+ }
+
+ if(i.deepMatches(in))
+ {
+ return i;
+ }
+ }
+
+ return null;
+ }
+
+ public boolean deepMatches(String in)
+ {
+ KList a = getNames();
+
+ for(String i : a)
+ {
+ if(i.toLowerCase().contains(in.toLowerCase()) || in.toLowerCase().contains(i.toLowerCase()))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode(){
+ return Objects.hash(getName(), getDescription(), getType(), getPath());
+ }
+
+ public boolean matches(String in)
+ {
+ KList a = getNames();
+
+ for(String i : a)
+ {
+ if(i.equalsIgnoreCase(in))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/com/volmit/iris/util/scheduling/J.java b/src/main/java/com/volmit/iris/util/scheduling/J.java
index 1f3c10c33..3ecda344d 100644
--- a/src/main/java/com/volmit/iris/util/scheduling/J.java
+++ b/src/main/java/com/volmit/iris/util/scheduling/J.java
@@ -83,6 +83,10 @@ public class J {
});
}
+ public static void aBukkit(Runnable a) {
+ Bukkit.getScheduler().scheduleAsyncDelayedTask(Iris.instance, a);
+ }
+
public static Future a(Callable a) {
return MultiBurst.burst.lazySubmit(a);
}