Util Easy external lib and command management

Discussion in 'Resources' started by elancha98, Mar 14, 2017.

Thread Status:
Not open for further replies.
  1. Offline

    elancha98

    PRE-MADE CLASSES
    Here, I provide some premade classes that I think are very helpful to Bukkit plugin development, they are capable of loading an external library and setting up all your commands and some other "random funcionallities".
    LibLoader class
    This class is capable of:
    • Loading libraries
      Code (open)

      PHP:
      LibLoader.loadLib("your-library.jar")
      Note: all the libraries you include must be packed inside youplugin.jar
    • Get classes inside a package
      Code (open)
      PHP:
      Set<Class<?>> classes LibLoader.getClasses(packageName);
    CommandExec class
    This class is capable of:
    • Register all your CommandExecutor classes
      How it works (open)
      Just add "CommandExec.setCommands(this);" in your onEnable. What this will do is it will look in your commands package, then loop through every class that extends CommandExecutor, then check if that class has a static String[] COMMANDS field and set that class as executor for the commands specified. So an example class would look like this
      PHP:
      public class MyCommandExecutor implements CommandExecutor {

          static final 
      String[] COMMANDS = {"mycommand""anothercommand"};
         
          @
      Override
          
      public boolean onCommand(CommandSender arg0Command arg1String arg2String[] arg3) {
              ...
              return 
      false;
          }

      }
      This class will be set as Executor for the "mycommand" and for "anothercommand" commands
    • Register all your TabCompleter classes
      How it works (open)
      Just add "CommandExec.setCommands(this);" in your onEnable. What this will do is it will look in your commands package, then loop through every class that extends TabCompleter, then check if that class has a static String[] COMMANDS field and set that class as executor for the commands specified. So an example class would look like this
      PHP:
      public class MyCommandExecutor implements TabCompleter {

          static final 
      String[] COMMANDS = {"mycommand""anothercommand"};

          @
      Override
          
      public List<StringonTabComplete(CommandSender arg0Command arg1,
                  
      String arg2String[] arg3) {
              ...
              return 
      null;
          }
      }
      This class will be set as TabCompleter for the "mycommand" and for "anothercommand" commands
    • Register all your TabExecutor classes
      How it works (open)
      Just add "CommandExec.setCommands(this);" in your onEnable. What this will do is it will look in your commands package, then loop through every class that extends TabExecutor, then check if that class has a static String[] COMMANDS field and set that class as executor for the commands specified. So an example class would look like this
      PHP:
      public class MyCommandExecutor implements TabExecutor {

          static final 
      String[] COMMANDS = {"mycommand""anothercommand"};

          @
      Override
          
      public List<StringonTabComplete(CommandSender arg0Command arg1,
                  
      String arg2String[] arg3) {
              ...
              return 
      null;
          }

          @
      Override
          
      public boolean onCommand(CommandSender arg0Command arg1String arg2,
                  
      String[] arg3) {
              ...
              return 
      false;
          }

      }
      This class will be set as TabCompleter and as CommandExecutor for the "mycommand" and for "anothercommand" commands
    • get a list of entities from a selector
      Code (open)
      PHP:
      List ent CommandExec.getEntities(senderselector);
      Note: the selector cannot be concrete player, must be something like "@a[r=10]"
    Note that this class requires LibLoader in order to work.

    SOURCE

    LibLoader
    Code (open)

    PHP:
    import java.io.BufferedInputStream;

    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.lang.reflect.Method;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLClassLoader;
    import java.net.URLDecoder;
    import java.util.Enumeration;
    import java.util.HashSet;
    import java.util.Set;
    import java.util.jar.JarEntry;
    import java.util.jar.JarFile;

    import org.apache.commons.io.IOUtils;
    import org.bukkit.Bukkit;
    import org.bukkit.configuration.file.YamlConfiguration;
    import org.bukkit.plugin.Plugin;

    @SuppressWarnings("deprecation")
    public class LibLoader {
     
        private static boolean RUNNING_FROM_JAR = false;
        private static String PLUGIN_NAME;
     
        static {
            final URL resource = LibLoader.class.getClassLoader().getResource("plugin.yml");
            if (resource != null) {
                RUNNING_FROM_JAR = true;
                try {
                    PLUGIN_NAME = YamlConfiguration.loadConfiguration(resource.openStream()).getString("name");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        public static void loadLib(String libr) throws Exception {
            Plugin plugin = Bukkit.getPluginManager().getPlugin(PLUGIN_NAME);
            final File lib = new File(plugin.getDataFolder(), libr);
            if (!lib.exists()) extractFromJar(lib.getName(), lib.getAbsolutePath());
            addClassPath(getJarUrl(lib)); 
        }
     
        private static void addClassPath(URL url) throws Exception {
            URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
            Class<URLClassLoader> sysclass = URLClassLoader.class;
            Method method = sysclass.getDeclaredMethod("addURL", URL.class);
            method.setAccessible(true);
            method.invoke(sysloader, url);
        }
     
        private static URL getJarUrl(File file) throws MalformedURLException {
            return new URL("jar:" + file.toURI().toURL().toExternalForm() + "!/");
        }
     
        private static boolean extractFromJar(String origin, String destination) throws Exception {
            JarFile jar = getRunningJar();
            if (jar == null) return false;
            File dest = new File(destination);
            if (dest.isDirectory()) return false;
            if (!dest.exists()) dest.getParentFile().mkdirs();
            Enumeration<JarEntry> e = jar.entries();
            while (e.hasMoreElements()) {
                JarEntry jarEntry = (JarEntry) e.nextElement();
                if (!jarEntry.getName().contains(origin)) continue;
                InputStream iStream = new BufferedInputStream(jar.getInputStream(jarEntry));
                OutputStream oStream = new BufferedOutputStream(new FileOutputStream(dest));
                IOUtils.copy(iStream, oStream);
                iStream.close();
                oStream.close();
                jar.close();
                return true;
            }
            jar.close();
            return false;
        }
     
        private static JarFile getRunningJar() throws IOException {
            if (!RUNNING_FROM_JAR) return null;
            String path = new File(LibLoader.class.getProtectionDomain().getCodeSource().
                    getLocation().getPath()).getAbsolutePath();
            path = URLDecoder.decode(path, "UTF-8");
            return new JarFile(path);
        }
     
        //Not very related but usefull
        public static Set<Class<?>> getClasses(String packageName) {
            
    Set<Class<?>> classes = new HashSet<Class<?>>();
            try {
                
    JarFile file getRunningJar();
                for (
    Enumeration<JarEntryentry file.entries(); entry.hasMoreElements();) {
                   
    JarEntry jarEntry entry.nextElement();
                   
    String name jarEntry.getName().replace("/"".");
                   if(
    name.startsWith(packageName) && name.endsWith(".class"))
                   
    classes.add(Class.forName(name.substring(0name.length() - 6)));
                }
                
    file.close();
            } catch(
    Exception e) {
                
    e.printStackTrace();
            }
            return 
    classes;
        }
    }

    CommandExec
    Code (open)

    PHP:
    import java.lang.reflect.Field;

    import java.lang.reflect.Method;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    import java.util.UUID;

    import org.bukkit.Bukkit;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.command.TabCompleter;
    import org.bukkit.command.TabExecutor;
    import org.bukkit.plugin.java.JavaPlugin;

    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;

    public class CommandExec {

        private static final String[] libs = {"asm-5.2.jar", "cglib-3.2.5.jar"};
        private static Object wrapper;
        @SuppressWarnings("rawtypes")
        private static Map<String, List> entities = new HashMap<String, List>();
     
        static {
            try {
                for (String lib : libs) LibLoader.loadLib(lib);
                setWrapper();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
     
        @SuppressWarnings("rawtypes")
        public static List getEntities(CommandSender sender, String selector)  {
            String uuid = UUID.randomUUID().toString();
            try {
                wrapper.getClass().getMethod("execute", CommandSender.class, String.class, String[].class)
                    .invoke(wrapper, sender, "", new String[] {selector, uuid});
            } catch (Exception e) {
                e.printStackTrace();
                return Collections.emptyList();
            }
            return entities.remove(uuid);
        }
     
        public static void setCommands(JavaPlugin plugin) throws Exception {
            Set<Class<?>> classes LibLoader.getClasses(plugin.getClass().getPackage().getName() + ".commands");
            for (Class<
    ?> clazz : classes) {
                Field field;
                try {
                    field = clazz.getDeclaredField("COMMANDS");
                    field.setAccessible(true);
                } catch (NoSuchFieldException e) {continue;}
                String[] cmds = (String[]) field.get(null);
             
                if (TabExecutor.class.isAssignableFrom(clazz)) {
                    for (String cmd : cmds) {
                        Object tmp = clazz.newInstance();
                        plugin.getCommand(cmd).setExecutor((CommandExecutor) tmp);
                        plugin.getCommand(cmd).setTabCompleter((TabCompleter) tmp);
                    }
                } else if (TabCompleter.class.isAssignableFrom(clazz)) {
                    for (String cmd : cmds) {
                        plugin.getCommand(cmd).setTabCompleter((TabCompleter) clazz.newInstance());
                    }
                } else if (CommandExecutor.class.isAssignableFrom(clazz)) {
                    for (String cmd : cmds) {
                        plugin.getCommand(cmd).setExecutor((CommandExecutor) clazz.newInstance());
                    }
                }
            }
        }
     
        private static void setWrapper() throws Exception {
            String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
            Class<?vanilla = Class.forName("org.bukkit.craftbukkit." version ".command.VanillaCommandWrapper");
            Class<
    ?> cmdabs = Class.forName("net.minecraft.server." + version + ".CommandAbstract");
         
            Class<?enhancer = Class.forName("net.sf.cglib.proxy.Enhancer");
            Class<
    ?> callback = Class.forName("net.sf.cglib.proxy.Callback");
            Object e = enhancer.getMethod("create", Class.class, callback).invoke(null, cmdabs, new Interceptor(version));
            wrapper = vanilla.getConstructor(cmdabs).newInstance(e);
            if (wrapper == null) throw new Exception("Cannot instanciate VanillaCommandWrapper");
        }
     
        protected static void putEntities(String uuid, @SuppressWarnings("rawtypes") List list) {
            entities.put(uuid, list);
        }
    }

    class Interceptor implements MethodInterceptor {
     
        private Method get_players;
        private Class<?entity;
     
        protected 
    Interceptor(String versionthrows ClassNotFoundException {
            
    entity = Class.forName("net.minecraft.server." version ".Entity");
            Class<
    ?> selector = Class.forName("net.minecraft.server." + version + ".PlayerSelector");
            Method[] methods = selector.getDeclaredMethods();
            for (Method method : methods) {
                if (method.getName().equals("getPlayers")) get_players = method;
            }     
        }
     
        @SuppressWarnings("rawtypes")
        @Override
        public Object intercept(Object t, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            String name = method.getName();
            if (name.equals("compareTo")) return 0;
            if (name.equals("getUsage")) return null;
            if (name.equals("getCommand")) return null;
            if (name.equals("execute")) {
                List list = (List) get_players.invoke(null, args[0], ((String[]) args[1])[0], entity);
                CommandExec.putEntities(((String[]) args[1])[1], list);
                return null;
            }
            return proxy.invokeSuper(t, args);
        }
    }

    Note that this class requires gclib-3.2.5.jar and asm-5.2.jar The specific version can be found in this link https://www.dropbox.com/sh/z8ju6unu3otfrzo/AABsNMvsfeJZJzPF8FQy_u-ma?dl=0 but any version of those should work (just change the libs array in CommandExec to fit the version you downloaded)
     
    MCMastery and ChipDev like this.
Thread Status:
Not open for further replies.

Share This Page