COMMANDS WORK - YE

#29
This commit is contained in:
Norbi Peti 2017-05-14 01:13:34 +02:00
parent acebf37359
commit 4a5479b027
5 changed files with 104 additions and 65 deletions

View file

@ -13,42 +13,36 @@ import buttondevteam.lib.chat.TBMCCommandBase;
public class CommandCaller implements CommandExecutor { public class CommandCaller implements CommandExecutor {
private static final String REGISTER_ERROR_MSG = "An error occured while registering commands";
private CommandCaller() { private CommandCaller() {
} }
private static CommandCaller instance; private static CommandCaller instance;
public static void RegisterCommand(TBMCCommandBase cmd) { public static void RegisterCommand(TBMCCommandBase cmd) throws Exception {
if (instance == null) if (instance == null)
instance = new CommandCaller(); instance = new CommandCaller();
if (cmd.GetCommandPath() == null) { String topcmd = cmd.GetCommandPath();
TBMCCoreAPI.SendException(REGISTER_ERROR_MSG, if (topcmd == null)
new Exception("Command " + cmd.getClass().getSimpleName() + " has no command path!")); throw new Exception("Command " + cmd.getClass().getSimpleName() + " has no command path!");
return; if (cmd.getPlugin() == null)
} throw new Exception("Command " + cmd.GetCommandPath() + " has no plugin!");
if (cmd.getPlugin() == null) {
TBMCCoreAPI.SendException(REGISTER_ERROR_MSG,
new Exception("Command " + cmd.GetCommandPath() + " has no plugin!"));
return;
}
int i; int i;
String topcmd; if ((i = topcmd.indexOf(' ')) != -1) // Get top-level command
if ((i = (topcmd = cmd.GetCommandPath()).indexOf(' ')) != -1) // Get top-level command topcmd = topcmd.substring(0, i);
topcmd = cmd.GetCommandPath().substring(0, i);
{ {
PluginCommand pc = ((JavaPlugin) cmd.getPlugin()).getCommand(topcmd); PluginCommand pc = ((JavaPlugin) cmd.getPlugin()).getCommand(topcmd);
if (pc == null) if (pc == null)
TBMCCoreAPI.SendException(REGISTER_ERROR_MSG, new Exception("Top level command " + topcmd throw new Exception("Top level command " + topcmd + " not registered in plugin.yml for plugin: "
+ " not registered in plugin.yml for plugin: " + cmd.getPlugin().getName())); + cmd.getPlugin().getName());
else else
pc.setExecutor(instance); pc.setExecutor(instance);
System.out.println("Executor set");
} }
} }
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String alias, String[] args) { public boolean onCommand(CommandSender sender, Command command, String alias, String[] args) {
System.out.println("onCommand called");
String path = command.getName().toLowerCase(); String path = command.getName().toLowerCase();
for (String arg : args) for (String arg : args)
path += " " + arg; path += " " + arg;

View file

@ -201,8 +201,10 @@ public class TBMCCoreAPI {
SendUnsentExceptions(); SendUnsentExceptions();
TBMCExceptionEvent event = new TBMCExceptionEvent(sourcemsg, e); TBMCExceptionEvent event = new TBMCExceptionEvent(sourcemsg, e);
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (!event.isHandled()) synchronized (exceptionsToSend) {
exceptionsToSend.put(sourcemsg, e); if (!event.isHandled())
exceptionsToSend.put(sourcemsg, e);
}
Bukkit.getLogger().warning(sourcemsg); Bukkit.getLogger().warning(sourcemsg);
e.printStackTrace(); e.printStackTrace();
if (debugPotato) { if (debugPotato) {
@ -212,7 +214,6 @@ public class TBMCCoreAPI {
devsOnline.add(player); devsOnline.add(player);
} }
} }
;
if (!devsOnline.isEmpty()) { if (!devsOnline.isEmpty()) {
DebugPotato potato = new DebugPotato() DebugPotato potato = new DebugPotato()
.setMessage(new String[] { // .setMessage(new String[] { //
@ -234,8 +235,10 @@ public class TBMCCoreAPI {
SendUnsentDebugMessages(); SendUnsentDebugMessages();
TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(debugMessage); TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(debugMessage);
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (!event.isSent()) synchronized (debugMessagesToSend) {
debugMessagesToSend.add(debugMessage); if (!event.isSent())
debugMessagesToSend.add(debugMessage);
}
} }
/** /**
@ -258,28 +261,32 @@ public class TBMCCoreAPI {
* Send exceptions that haven't been sent (their events didn't get handled). This method is used by the DiscordPlugin's ready event * Send exceptions that haven't been sent (their events didn't get handled). This method is used by the DiscordPlugin's ready event
*/ */
public static void SendUnsentExceptions() { public static void SendUnsentExceptions() {
if (exceptionsToSend.size() > 20) { synchronized (exceptionsToSend) {
exceptionsToSend.clear(); // Don't call more and more events if all the handler plugins are unloaded if (exceptionsToSend.size() > 20) {
Bukkit.getLogger().warning("Unhandled exception list is over 20! Clearing!"); exceptionsToSend.clear(); // Don't call more and more events if all the handler plugins are unloaded
} Bukkit.getLogger().warning("Unhandled exception list is over 20! Clearing!");
for (Entry<String, Throwable> entry : exceptionsToSend.entrySet()) { }
TBMCExceptionEvent event = new TBMCExceptionEvent(entry.getKey(), entry.getValue()); for (Entry<String, Throwable> entry : exceptionsToSend.entrySet()) {
Bukkit.getPluginManager().callEvent(event); TBMCExceptionEvent event = new TBMCExceptionEvent(entry.getKey(), entry.getValue());
if (event.isHandled()) Bukkit.getPluginManager().callEvent(event);
exceptionsToSend.remove(entry.getKey()); if (event.isHandled())
exceptionsToSend.remove(entry.getKey());
}
} }
} }
public static void SendUnsentDebugMessages() { public static void SendUnsentDebugMessages() {
if (debugMessagesToSend.size() > 20) { synchronized (debugMessagesToSend) {
debugMessagesToSend.clear(); // Don't call more and more DebugMessages if all the handler plugins are unloaded if (debugMessagesToSend.size() > 20) {
Bukkit.getLogger().warning("Unhandled Debug Message list is over 20! Clearing!"); debugMessagesToSend.clear(); // Don't call more and more DebugMessages if all the handler plugins are unloaded
} Bukkit.getLogger().warning("Unhandled Debug Message list is over 20! Clearing!");
for (String message : debugMessagesToSend) { }
TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(message); for (String message : debugMessagesToSend) {
Bukkit.getPluginManager().callEvent(event); TBMCDebugMessageEvent event = new TBMCDebugMessageEvent(message);
if (event.isSent()) Bukkit.getPluginManager().callEvent(event);
debugMessagesToSend.remove(message); if (event.isSent())
debugMessagesToSend.remove(message);
}
} }
} }

View file

@ -6,6 +6,13 @@ 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;
/**
* <b>Abstract classes with no {@link CommandClass} annotations will be ignored.</b> Classes that are not abstract or have the annotation will be included in the command path unless
* {@link #excludeFromPath()} is true.
*
* @author NorbiPeti
*
*/
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Inherited @Inherited
@ -26,4 +33,9 @@ public @interface CommandClass {
* @return The command path, <i>which is the command class name by default</i> (removing any "command" from it) * @return The command path, <i>which is the command class name by default</i> (removing any "command" from it)
*/ */
public String path() default ""; public String path() default "";
/**
* Exclude this class from the path. Useful if more commands share some property but aren't subcommands of a common command. See {@link CommandClass} for more details.
*/
public boolean excludeFromPath() default false;
} }

View file

@ -4,6 +4,7 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -61,20 +62,20 @@ public class TBMCChatAPI {
cmds.add("§6---- Subcommands ----"); cmds.add("§6---- Subcommands ----");
cmds.add(cmd); cmds.add(cmd);
}; };
for (TBMCCommandBase cmd : TBMCChatAPI.GetCommands().values()) { for (Entry<String, TBMCCommandBase> cmd : TBMCChatAPI.GetCommands().entrySet()) {
if (cmd.GetCommandPath().startsWith(command + " ")) { if (cmd.getKey().startsWith(command + " ")) {
if (cmd.isPlayerOnly() && !(sender instanceof Player)) if (cmd.getValue().isPlayerOnly() && !(sender instanceof Player))
continue; continue;
if (cmd.getClass().getAnnotation(CommandClass.class).modOnly() if (cmd.getClass().getAnnotation(CommandClass.class).modOnly()
&& !MainPlugin.permission.has(sender, "tbmc.admin")) && !MainPlugin.permission.has(sender, "tbmc.admin"))
continue; continue;
int ind = cmd.GetCommandPath().indexOf(' ', command.length() + 2); int ind = cmd.getKey().indexOf(' ', command.length() + 2);
if (ind >= 0) { if (ind >= 0) {
String newcmd = cmd.GetCommandPath().substring(0, ind); String newcmd = cmd.getKey().substring(0, ind);
if (!cmds.contains("/" + newcmd)) if (!cmds.contains("/" + newcmd))
addToCmds.accept("/" + newcmd); addToCmds.accept("/" + newcmd);
} else } else
addToCmds.accept("/" + cmd.GetCommandPath()); addToCmds.accept("/" + cmd.getKey());
} }
} }
return cmds.toArray(new String[cmds.size()]); return cmds.toArray(new String[cmds.size()]);
@ -99,15 +100,22 @@ public class TBMCChatAPI {
* @param acmdclass * @param acmdclass
* A command's class to get the package name for commands. The provided class's package and subpackages are scanned for commands. * A command's class to get the package name for commands. The provided class's package and subpackages are scanned for commands.
*/ */
public static void AddCommands(JavaPlugin plugin, Class<? extends TBMCCommandBase> acmdclass) { public static synchronized void AddCommands(JavaPlugin plugin, Class<? extends TBMCCommandBase> acmdclass) {
plugin.getLogger().info("Registering commands for " + plugin.getName()); plugin.getLogger().info("Registering commands from " + acmdclass.getPackage().getName());
Reflections rf = new Reflections(new ConfigurationBuilder() Reflections rf = new Reflections(new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage(acmdclass.getPackage().getName(), .setUrls(ClasspathHelper.forPackage(acmdclass.getPackage().getName(),
plugin.getClass().getClassLoader())) plugin.getClass().getClassLoader()))
.addUrls(
ClasspathHelper.forClass(OptionallyPlayerCommandBase.class,
OptionallyPlayerCommandBase.class.getClassLoader()),
ClasspathHelper.forClass(PlayerCommandBase.class, PlayerCommandBase.class.getClassLoader())) // http://stackoverflow.com/questions/12917417/using-reflections-for-finding-the-transitive-subtypes-of-a-class-when-not-all
.addClassLoader(plugin.getClass().getClassLoader()).addScanners(new SubTypesScanner())); .addClassLoader(plugin.getClass().getClassLoader()).addScanners(new SubTypesScanner()));
Set<Class<? extends TBMCCommandBase>> cmds = rf.getSubTypesOf(TBMCCommandBase.class); Set<Class<? extends TBMCCommandBase>> cmds = rf.getSubTypesOf(TBMCCommandBase.class);
for (Class<? extends TBMCCommandBase> cmd : cmds) { for (Class<? extends TBMCCommandBase> cmd : cmds) {
try { try {
if (!cmd.getPackage().getName().startsWith(acmdclass.getPackage().getName()))
continue; // It keeps including the commands from here
//System.out.println("Class found: " + cmd.getName());
if (Modifier.isAbstract(cmd.getModifiers())) if (Modifier.isAbstract(cmd.getModifiers()))
continue; continue;
TBMCCommandBase c = cmd.newInstance(); TBMCCommandBase c = cmd.newInstance();
@ -116,9 +124,7 @@ public class TBMCChatAPI {
continue; continue;
commands.put(c.GetCommandPath(), c); commands.put(c.GetCommandPath(), c);
CommandCaller.RegisterCommand(c); CommandCaller.RegisterCommand(c);
} catch (InstantiationException e) { } catch (Exception e) {
TBMCCoreAPI.SendException("An error occured while registering command " + cmd.getName(), e);
} catch (IllegalAccessException e) {
TBMCCoreAPI.SendException("An error occured while registering command " + cmd.getName(), e); TBMCCoreAPI.SendException("An error occured while registering command " + cmd.getName(), e);
} }
} }

View file

@ -5,9 +5,11 @@ import java.util.function.Function;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import javassist.Modifier;
/** /**
* Extend this class to create new TBMCCommand and use {@link TBMCChatAPI#AddCommand(org.bukkit.plugin.java.JavaPlugin, TBMCCommandBase)} to add it. <u><b>Note:</b></u> The command path (command name * Extend this class to create new TBMCCommand and use {@link TBMCChatAPI#AddCommand(org.bukkit.plugin.java.JavaPlugin, TBMCCommandBase)} to add it. <u><b>Note:</b></u> The command path (command name
* and subcommand arguments) will be the class name by default, removing any "command" from it. To change it (especially for subcommands), override {@link #GetCommandPath()}. * and subcommand arguments) will be the class name by default, removing any "command" from it. To change it (especially for subcommands), use the path field in the {@link CommandClass} annotation.
* *
* @author Norbi * @author Norbi
* *
@ -15,36 +17,54 @@ import org.bukkit.plugin.Plugin;
public abstract class TBMCCommandBase { public abstract class TBMCCommandBase {
public TBMCCommandBase() { public TBMCCommandBase() {
path = getcmdpath();
} }
public abstract boolean OnCommand(CommandSender sender, String alias, String[] args); public abstract boolean OnCommand(CommandSender sender, String alias, String[] args);
public abstract String[] GetHelpText(String alias); public abstract String[] GetHelpText(String alias);
private String path = null;
/** /**
* The command's path, or name if top-level command.<br> * The command's path, or name if top-level command.<br>
* For example:<br> * For example:<br>
* "u admin updateplugin" or "u" for the top level one<br> * "u admin updateplugin" or "u" for the top level one<br>
* <u>The path must be lowercase!</u><br> * <u>The path must be lowercase!</u><br>
* <b>Abstract classes with no {@link CommandClass} annotations will be ignored.</b>
* *
* @return The command path, <i>which is the command class name by default</i> (removing any "command" from it) * @return The command path, <i>which is the command class name by default</i> (removing any "command" from it) - Change via the {@link CommandClass} annotation
*/ */
public final String GetCommandPath() { public final String GetCommandPath() {
return path;
}
private final String getcmdpath() {
if (!getClass().isAnnotationPresent(CommandClass.class)) if (!getClass().isAnnotationPresent(CommandClass.class))
throw new RuntimeException("No @Command annotation on command class " + getClass().getSimpleName() + "!"); throw new RuntimeException(
Function<Class<?>, String> getFromClass = cl -> getClass().getSimpleName().toLowerCase() "No @CommandClass annotation on command class " + getClass().getSimpleName() + "!");
.replace("commandbase", "").replace("command", ""); Function<Class<?>, String> getFromClass = cl -> cl.getSimpleName().toLowerCase().replace("commandbase", "") // <-- ...
String path = getClass().getAnnotation(CommandClass.class).path(), prevpath = path; // TODO: Check if annotation exists (No @Inherited?) .replace("command", "");
String path = getClass().getAnnotation(CommandClass.class).path(),
prevpath = path = path.length() == 0 ? getFromClass.apply(getClass()) : path;
// System.out.println("Path: " + (path.length() == 0 ? getFromClass.apply(getClass()) : path))
for (Class<?> cl = getClass().getSuperclass(); cl != null for (Class<?> cl = getClass().getSuperclass(); cl != null
&& !cl.getName().equals(TBMCCommandBase.class.getName()); cl = cl.getSuperclass()) { && !cl.getPackage().getName().equals(TBMCCommandBase.class.getPackage().getName()); cl = cl
//com.sun.xml.internal.bind.v2.TODO.prototype(); .getSuperclass()) { //
String newpath = cl.getAnnotation(CommandClass.class).path(); String newpath;
if (newpath.length() == 0) if (!cl.isAnnotationPresent(CommandClass.class)
|| (newpath = cl.getAnnotation(CommandClass.class).path()).length() == 0
|| newpath.equals(prevpath)) {
if (Modifier.isAbstract(cl.getModifiers()) && (!cl.isAnnotationPresent(CommandClass.class))
|| cl.getAnnotation(CommandClass.class).excludeFromPath()) // <--
continue;
newpath = getFromClass.apply(cl); newpath = getFromClass.apply(cl);
if (!newpath.equals(prevpath)) }
path = (prevpath = newpath) + " " + path; path = (prevpath = newpath) + " " + path;
// System.out.println("Path: " + (path.length() == 0 ? getFromClass.apply(cl) : path));
} }
return path.length() == 0 ? getFromClass.apply(getClass()) : path; //System.out.println("Path: " + path);
return path;
} }
Plugin plugin; // Used By TBMCChatAPI Plugin plugin; // Used By TBMCChatAPI