Added support for cmd tabcomplete

This commit is contained in:
Norbi Peti 2019-07-08 01:56:25 +02:00
parent db8dfa79bc
commit a39fd083be
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
7 changed files with 135 additions and 8 deletions

View file

@ -20,6 +20,8 @@
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
<orderEntry type="module" module-name="ButtonCore (1) (com.github.TBMCPlugins.ButtonCore)" />
<orderEntry type="library" name="Maven: org.reflections:reflections:0.9.10" level="project" />
<orderEntry type="library" name="Maven: com.google.code.findbugs:annotations:2.0.1" level="project" />
<orderEntry type="library" name="Maven: org.javassist:javassist:3.20.0-GA" level="project" />

View file

@ -111,7 +111,7 @@
</repository> -->
<repository>
<id>ess-repo</id>
<url>http://repo.ess3.net/content/repositories/essrel/</url>
<url>https://ci.ender.zone/plugin/repository/everything/</url>
</repository>
<repository>
<id>Votifier</id>
@ -209,4 +209,4 @@
<connection>scm:git:https://github.com/TBMCPlugins/mvn-repo.git</connection>
<developerConnection>scm:git:https://github.com/TBMCPlugins/mvn-repo.git</developerConnection>
</scm>
</project>
</project>

View file

@ -97,6 +97,7 @@ public class MainPlugin extends ButtonPlugin {
getCommand2MC().registerCommand(new ComponentCommand());
getCommand2MC().registerCommand(new ThorpeCommand());
TBMCCoreAPI.RegisterEventsForExceptions(new PlayerListener(), this);
TBMCCoreAPI.RegisterEventsForExceptions(getCommand2MC(), this);
ChromaGamerBase.addConverter(commandSender -> Optional.ofNullable(commandSender instanceof ConsoleCommandSender || commandSender instanceof BlockCommandSender
? TBMCPlayer.getPlayer(new UUID(0, 0), TBMCPlayer.class) : null)); //Console & cmdblocks
ChromaGamerBase.addConverter(sender -> Optional.ofNullable(sender instanceof Player

View file

@ -1,6 +1,7 @@
package buttondevteam.lib;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
@ -22,7 +23,7 @@ public class TBMCExceptionEvent extends Event {
@java.beans.ConstructorProperties({"sourceMessage", "exception"})
public TBMCExceptionEvent(String sourceMessage, Throwable exception) {
super(true);
super(!Bukkit.isPrimaryThread());
this.sourceMessage = sourceMessage;
this.exception = exception;
}

View file

@ -109,7 +109,7 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
public final String errormsg;
}
private HashMap<String, SubcommandData<TC>> subcommands = new HashMap<>();
protected HashMap<String, SubcommandData<TC>> subcommands = new HashMap<>();
private HashMap<Class<?>, ParamConverter<?>> paramConverters = new HashMap<>();
private ArrayList<String> commandHelp = new ArrayList<>(); //Mainly needed by Discord
@ -321,4 +321,8 @@ public abstract class Command2<TC extends ICommand2, TP extends Command2Sender>
if (scmd == null) return null;
return scmd.helpText;
}
/*public Set<String> getAllSubcommands() {
return Collections.unmodifiableSet(subcommands.keySet());
}*/
}

View file

@ -5,16 +5,22 @@ import lombok.experimental.var;
import lombok.val;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.TabCompleteEvent;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionDefault;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.UUID;
import java.util.function.Function;
public class Command2MC extends Command2<ICommand2MC, Command2MCSender> {
public class Command2MC extends Command2<ICommand2MC, Command2MCSender> implements Listener {
@Override
public void registerCommand(ICommand2MC command) {
super.registerCommand(command, '/');
@ -36,7 +42,11 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> {
@Override
public boolean hasPermission(Command2MCSender sender, ICommand2MC command, Method method) {
if (sender.getSender() instanceof ConsoleCommandSender) return true; //Always allow the console
return hasPermission(sender.getSender(), command, method);
}
public boolean hasPermission(CommandSender sender, ICommand2MC command, Method method) {
if (sender instanceof ConsoleCommandSender) return true; //Always allow the console
String pg;
boolean p = true;
String[] perms = {
@ -47,8 +57,8 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> {
for (String perm : perms) {
if (perm != null) {
if (p) { //Use OfflinePlayer to avoid fetching player data
if (sender.getSender() instanceof OfflinePlayer)
p = MainPlugin.permission.playerHas(null, (OfflinePlayer) sender.getSender(), perm);
if (sender instanceof OfflinePlayer)
p = MainPlugin.permission.playerHas(null, (OfflinePlayer) sender, perm);
else
p = MainPlugin.permission.playerHas(null, Bukkit.getOfflinePlayer(new UUID(0, 0)), perm);
} else break; //If any of the permissions aren't granted then don't allow
@ -109,4 +119,112 @@ public class Command2MC extends Command2<ICommand2MC, Command2MCSender> {
public <T> void addParamConverter(Class<T> cl, Function<String, T> converter, String errormsg) {
super.addParamConverter(cl, converter, "§c" + errormsg);
}
@EventHandler
private void handleTabComplete(TabCompleteEvent event) {
String commandline = event.getBuffer();
CommandSender sender = event.getSender();
//System.out.println("tab");
for (int i = commandline.length(); i != -1; i = commandline.lastIndexOf(' ', i - 1)) {
String subcommand = commandline.substring(0, i).toLowerCase();
if (subcommand.charAt(0) != '/') subcommand = '/' + subcommand; //Console
//System.out.println("Subcommand: " + subcommand);
SubcommandData<ICommand2MC> sd = subcommands.get(subcommand); //O(1)
if (sd == null) continue;
//System.out.println("ht: " + Arrays.toString(sd.helpText));
Arrays.stream(sd.helpText).skip(1).map(ht -> new HashMap.SimpleEntry<>(ht, subcommands.get(ht))).filter(e -> e.getValue() != null)
.filter(kv -> kv.getKey().startsWith(commandline))
.filter(kv -> hasPermission(sender, kv.getValue().command, kv.getValue().method))
.forEach(kv -> event.getCompletions().add((kv.getKey()).substring(kv.getKey().lastIndexOf(' ', commandline.length()) + 1)));
if (sd.method == null || sd.command == null)
return;
/*if (!hasPermission(sender, sd.command, sd.method)) { - TODO: Arguments
sender.sendMessage("§cYou don't have permission to use this command");
return true;
}
val params = new ArrayList<Object>(sd.method.getParameterCount());
int j = subcommand.length(), pj;
Class<?>[] parameterTypes = sd.method.getParameterTypes();
if (parameterTypes.length == 0)
throw new Exception("No sender parameter for method '" + sd.method + "'");
val sendertype = parameterTypes[0];
final ChromaGamerBase cg;
if (sendertype.isAssignableFrom(sender.getClass()))
params.add(sender); //The command either expects a CommandSender or it is a Player, or some other expected type
else if (sender instanceof Command2MCSender
&& sendertype.isAssignableFrom(((Command2MCSender) sender).getSender().getClass()))
params.add(((Command2MCSender) sender).getSender());
else if (ChromaGamerBase.class.isAssignableFrom(sendertype)
&& sender instanceof Command2MCSender
&& (cg = ChromaGamerBase.getFromSender(((Command2MCSender) sender).getSender())) != null
&& cg.getClass() == sendertype) //The command expects a user of our system
params.add(cg);
else {
sender.sendMessage("§cYou need to be a " + sendertype.getSimpleName() + " to use this command.");
return true;
}
val paramArr = sd.method.getParameters();
for (int i1 = 1; i1 < parameterTypes.length; i1++) {
Class<?> cl = parameterTypes[i1];
pj = j + 1; //Start index
if (pj == commandline.length() + 1) { //No param given
if (paramArr[i1].isAnnotationPresent(OptionalArg.class)) {
if (cl.isPrimitive())
params.add(Defaults.defaultValue(cl));
else if (Number.class.isAssignableFrom(cl)
|| Number.class.isAssignableFrom(cl))
params.add(Defaults.defaultValue(Primitives.unwrap(cl)));
else
params.add(null);
continue; //Fill the remaining params with nulls
} else {
sender.sendMessage(sd.helpText); //Required param missing
return true;
}
}
if (paramArr[i1].isVarArgs()) {
params.add(commandline.substring(j + 1).split(" +"));
continue;
}
j = commandline.indexOf(' ', j + 1); //End index
if (j == -1 || paramArr[i1].isAnnotationPresent(TextArg.class)) //Last parameter
j = commandline.length();
String param = commandline.substring(pj, j);
if (cl == String.class) {
params.add(param);
continue;
} else if (Number.class.isAssignableFrom(cl) || cl.isPrimitive()) {
try {
//noinspection unchecked
Number n = ThorpeUtils.convertNumber(NumberFormat.getInstance().parse(param), (Class<? extends Number>) cl);
params.add(n);
} catch (ParseException e) {
sender.sendMessage("§c'" + param + "' is not a number.");
return true;
}
continue;
}
val conv = paramConverters.get(cl);
if (conv == null)
throw new Exception("No suitable converter found for parameter type '" + cl.getCanonicalName() + "' for command '" + sd.method.toString() + "'");
val cparam = conv.converter.apply(param);
if (cparam == null) {
sender.sendMessage(conv.errormsg); //Param conversion failed - ex. plugin not found
return true;
}
params.add(cparam);
}
try {
val ret = sd.method.invoke(sd.command, params.toArray()); //I FORGOT TO TURN IT INTO AN ARRAY (for a long time)
if (ret instanceof Boolean) {
if (!(boolean) ret) //Show usage
sender.sendMessage(sd.helpText);
} else if (ret != null)
throw new Exception("Wrong return type! Must return a boolean or void. Return value: " + ret);
return true; //We found a method
} catch (InvocationTargetException e) {
TBMCCoreAPI.SendException("An error occurred in a command handler!", e.getCause());
}*/
}
}
}

View file

@ -24,6 +24,7 @@ public class TBMCPlayerGetInfoEvent extends Event {
private final InfoTarget target;
TBMCPlayerGetInfoEvent(ChromaGamerBase player, InfoTarget target) {
super(true);
this.player = player;
infolines = new ArrayList<>();
this.target = target;