[Tutorial] Include API plugins INSIDE your own plugin

Discussion in 'Resources' started by Alex5657, Jul 24, 2013.

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

    Alex5657

    Everybody knows about the classic method of keeping an API in your jar. However, plugin APIs are a completely different story. They must be enabled for their code to function correctly. But installing an API plugin on your server is kind of pointless. So here I will show you how to combine both your plugin and the API it uses. (I will be using RemoteEntities for demonstration purposes).

    If you are using eclipse, just include the plugin in the build path for now.

    First off, we will need an instance of the plugin. Since all plugins must have an empty constructor, we can simply create it.
    Code:java
    1.  
    2. RemoteEntities rePlugin = new RemoteEntities();
    3.  

    Next we will need to initialize it in the server. For this we will need the initialize() method. However, its access modifier is "protected" so we will need to use reflection to get it and give us access to use it.
    Code:java
    1.  
    2. Method initialize = null;
    3. try {
    4. initialize = JavaPlugin.class.getMethod("initialize", PluginLoader.class,Server.class,PluginDescriptionFile.class,File.class,File.class,ClassLoader.class);
    5. } catch (Exception ex) {
    6. ex.printStackTrace();
    7. }
    8. initialize.setAccessible(true);
    9.  

    Alright, so this method takes 6 arguments:
    The plugin loader, the server, description file(plugin.yml), data folder, its file and the class loader

    The plugin loader, server and class loader are the same for every plugin and the file will be the same for both plugins so we can simply get them now.
    Code:java
    1.  
    2. Server server = getServer();
    3. PluginLoader pluginLoader = getPluginLoader();
    4. ClassLoader classLoader = getClassLoader();
    5. File file = getFile();
    6.  

    Now, the unique stuff. Lets start off with the description. We can store the yml in the jar and read it from there, which would be the proper way, but since we know the contents of it we can just do it directly in code. Here is how RemoteEntities plugin.yml looks like:
    Code:
    main: de.kumpelblase2.remoteentities.RemoteEntities
    author: kumpelblase2
    name: RemoteEntities
    version: 1.6
    
    So lets write that down!
    Code:java
    1.  
    2. PluginDescriptionFile description = new PluginDescriptionFile("RemoteEntities","1.6","de.kumpelblase2.remoteentities.RemoteEntities");
    3. description.getAuthors().add("kumpelblase2"); //Not needed, just so the author doesn't get mad at me ^_^
    4.  

    Great! Now we have a description! Lets give it a data folder now.
    Code:java
    1.  
    2. File dataFolder = new File("plugins/RemoteEntities");
    3.  

    As simple as that! We can now invoke "initialize"!
    Code:java
    1.  
    2. initialize.invoke(rePlugin,pluginLoader,server,description,dataFolder,file,classLoader);
    3.  

    The plugin is now initialized in server! All we need to do is enable it now.
    Code:java
    1.  
    2. server.getPluginManager().enablePlugin(rePlugin);
    3.  

    And now the final step: include the class files in your plugins jar.
    Firstly, you will need to export your plugin. Then unpack your plugin with WinRAR or 7zip (Windows)(I really don't know how Macs work) to see the contents. Warning: don't extract it, we will be adding stuff to the jar. Unpack your API plugin as well. Now just drag and drop everything except plugin.yml and META-INF from your API plugin to your plugin.

    And that is it! Your plugin that was depended on an API is now completely independent!

    Full code:
    Code:java
    1.  
    2. RemoteEntities rePlugin = new RemoteEntities();
    3. Method initialize = null;
    4. try {
    5. initialize = JavaPlugin.class.getMethod("initialize", PluginLoader.class,Server.class,PluginDescriptionFile.class,File.class,File.class,ClassLoader.class);
    6. } catch (Exception ex) {
    7. ex.printStackTrace();
    8. }
    9. initialize.setAccessible(true);
    10. Server server = getServer();
    11. PluginLoader pluginLoader = getPluginLoader();
    12. ClassLoader classLoader = getClassLoader();
    13. File file = getFile();
    14. PluginDescriptionFile description = new PluginDescriptionFile("RemoteEntities","1.6","de.kumpelblase2.remoteentities.RemoteEntities");
    15. description.getAuthors().add("kumpelblase2");
    16. File dataFolder = new File("plugins/RemoteEntities");
    17. initialize.invoke(rePlugin,pluginLoader,server,description,dataFolder,file,classLoader);
    18. server.getPluginManager().enablePlugin(rePlugin);
    19.  


    Note: I would highly recommend that your surround that code with an "if" statement checking if the plugin (RemoteEntities in our case) is already enabled. I really don't know what will happen if you try to run two instances of the same plugin, all I know is that it will be bad.
     
  2. Offline

    MylesIsCool

    Just remember not to breach the license of the APIs.
     
  3. Offline

    mbaxter ʇıʞʞnq ɐ sɐɥ ı

    Good to note that pretty much no plugin doing this would get accepted on BukkitDev
     
  4. Offline

    Alex5657

    usuk
     
  5. Offline

    sayaad


    That and the purpose of some of these APIs is for the use of a single synchronized method to be used cross-plugin to prevent damage of some sort. (See TagAPI)
     
  6. Offline

    Alex5657

    If there is only one plugin using the API, it would be more efficient to include it. I put a note at the bottom which you obviously didn't read
     
  7. Offline

    mbaxter ʇıʞʞnq ɐ sɐɥ ı

    In that situation, the author of both plugins is the same and should not have released it separately to begin with :p
     
  8. Offline

    Alex5657

    Lol :p. Wait, if an author of both plugins is the same (one is an API, another is an actual plugin) can he include the API inside his own plugin?
    Another question: if I explicitly declare that any user of my API can include it in their own plugins, will their work be accepted to BukkitDev?
     
  9. Offline

    Wingzzz

    Alex5657
    At that point, strip the API plugin of being a plugin itself and shade the API into the plugin. This removes your need for including a plugin API in a plugin. Simply include an API in your plugin if both are written by you. Otherwise, if you wrote a plugin API, then you intended to have it act as a plugin, anyways in which case you should not be including it inside another plugin if it is intended to be a plugin itself ;)
     
Thread Status:
Not open for further replies.

Share This Page