Valhalla Legends Forums Archive | Visual Basic Programming | Plugins

AuthorMessageTime
Networks
I understand the basic principles of creating a plugin using ActiveX dll however I don't understand how to put them into an array or at least to find others in a directory and load them. Any help?
December 7, 2004, 11:15 PM
iago
I wrote a whole bunch of Java code for that today, which can load them locally or from a remote server.  I can share if you'd like, maybe you can learn something from it.
December 7, 2004, 11:43 PM
HdxBmx27
I would love to see the info you have on it iago, Java or otherwise.
~-~(HDX)~-~
December 8, 2004, 12:08 AM
iago
damnit, I was hoping nobody would want to.  I'm not terribly proud of the code I have, it still needs work, but I just got it working today:

This is the interface that I force my plugins to implement:
[code]package pluginmanagers;

import bot.PublicBot;

/*
* Created on Dec 1, 2004
* By iago
*/

/** Every plugin has to have a class called "PluginMain" in the default folder that implements this interface.  If it doesn't, then
* the plugin will fail to load.
* @author iago
*
*/
public interface PluginInterface
{
    /** Called when the plugin is loaded (whenever it's detected) the first time.  You aren't allowed to make hooks at this point.  This
    * can be done when the plugin is Activated.
    * TODO: Make global hooks occur here. */
    public void load();

    /** Called when the plugin is enabled, or, if it's on by default, when the bot starts.  This is called once
    * for each running instance of the bot that's using it. */
    public void activate(PublicBot bot);
    /** Called when the plugin is disabled.  This includes when the instance is unloaded. */
    public void deactivate(PublicBot bot);
   
    /** Gets the friendly name for the plugin */
    public String getName();
}[/code]

This class is rather long, so I cut out the boring stuff.  Basically, it wraps around and calls all the plugins that could possibly be called.  I know there's gotta be a better way to do this, but I still can't think of one:
[code]/*
* Created on Dec 2, 2004
* By iago
*/

/** This class will be available to all plugins.  Each bot will have exactly one instance, and when the bot loads a plugin it passes
* in its instance of this class, allowing the newly loaded plugin to register itself for these callbacks.
*
* Plugins register themselves in this, and when an event occurs that belongs to a plugin, this takes care of sending the event
* to the registered plugins.
*
* @author iago
*
*/
public class PluginCallbacks
{
    private Vector botPlugins = new Vector();
    private Vector commandPlugins = new Vector();
    private Vector connectionPlugins = new Vector();
    private Vector errorPlugins = new Vector();
    private Vector eventPlugins = new Vector();
    private Vector incomingPacketPlugins = new Vector();
    private Vector outgoingPacketPlugins = new Vector();
    private Vector systemMessagePlugins = new Vector();
    private Vector userDatabasePlugins = new Vector();
    private Vector userErrorPlugins = new Vector();
   
    /** Register the command to receive commands.  This is when a user type .command in the channel.
    * @param callback The class that will be receiving this command.
    * @param name The name of the command is the command the user types, like "ban" or "kick", and may contain wildcards
    * like "ban.*" or "kick..".  It will, however, only be matched against the first word in user's command.
    * @param args The number of single-word arguments to match before taking the rest of the string.  For example, if you
    * wanted to write a .ban command, you could specify args = 1, then ".ban joe you suck" would match
    * .ban to the command name, joe to the first paramter, and the rest of the string to the other parameters.
    * If you want to write a .say command, specify "0", and you will only ever get a single long string.
    * If the user fails to use enough strings, a shorter array of args will be passed in, and should be handled
    * appropriately by the plugin.
    */
   
    public void registerBotPlugin(BotCallback callback, Object data)
    {
        botPlugins.add(new BotPlugin(callback, data));
    }
   
    public void registerCommandPlugin(CommandCallback callback, String name, int args, boolean requiresOps, String help, Object data)
    {
        commandPlugins.add(new CommandPlugin(callback, name, args, requiresOps, help, data));
    }
   
    public void registerConnectionPlugin(ConnectionCallback callback, Object data)
    {
        connectionPlugins.add(new ConnectionPlugin(callback, data));
    }
   
    public void registerErrorPlugin(ErrorCallback callback, Object data)
    {
        errorPlugins.add(new ErrorPlugin(callback, data));
    }
 
    public void registerEventPlugin(EventCallback callback, byte event, Object data)
    {
        eventPlugins.add(new EventPlugin(callback, event, data));
    }
   
    public void registerIncomingPacketPlugin(PacketCallback callback, byte packet, Object data)
    {
        incomingPacketPlugins.add(new PacketPlugin(callback, packet, data));
    }
   
    public void registerOutgoingPacketPlugin(PacketCallback callback, byte packet, Object data)
    {
        outgoingPacketPlugins.add(new PacketPlugin(callback, packet, data));
    }
   
    public void registerSystemMessagePlugin(SystemMessageCallback callback, int minLevel, int maxLevel, Object data)
    {
        //System.out.println("  ----> REGISTERING SYSTEM MESSAGE CALLBACK");
        systemMessagePlugins.add(new SystemMessagePlugin(callback, minLevel, maxLevel, data));
    }
   
    public void registerUserDatabasePlugin(UserDatabaseCallback callback, Object data)
    {
        userDatabasePlugins.add(new UserDatabasePlugin(callback, data));
    }
   
    public void registerUserErrorPlugin(UserErrorCallback callback, Object data)
    {
        userErrorPlugins.add(new UserErrorPlugin(callback, data));
    }
   
   
   
// Bot callbacks
    /** This is called as soon as the instance of the bot is started.*/
    public void botInstanceStarting(PublicBot out)
    {
        Enumeration e = botPlugins.elements();
        while(e.hasMoreElements())
        {
            BotPlugin plugin = (BotPlugin)e.nextElement();
            ((BotCallback)plugin.getCallback()).botInstanceStarting(out, plugin.getData());
        }
    }
    /** This is called when the instance of the bot is ending */
    public void botInstanceStopping(PublicBot out)
    {
        Enumeration e = botPlugins.elements();
        while(e.hasMoreElements())
        {
            BotPlugin plugin = (BotPlugin)e.nextElement();
            ((BotCallback)plugin.getCallback()).botInstanceStopping(out, plugin.getData());
        }
    }

...........[lots more functions that look like those 2]
[/code]


And finally, this is the code I wrote today.  It loads the plugins from the given paths (it recursively searches directories for .jar files, and it also can load them from a proper url (http://..).  It can then activate/deactivate the plugin for any instance of the bot.
[code]/*
* Created on Dec 1, 2004
* By iago
*/

/** There will be once instance of this class for each bot instance running.  The initializePlugins() function should be called
*  exactly once when the bot starts, and it should be passed the paths to search for plugins.  An instance of this should be
*  passed to each of the bots (or it should be created by a bot for itself, perhaps), where loadPlugin and unloadPlugin can be called.
*
* @author iago
*
*/
public class PluginManager
{
    private static Hashtable allPlugins;
    private static Hashtable activePlugins;
   
   
    /** searchPaths is a Vector of File's */
    public static void initializePlugins(Vector searchPaths)
    {
        allPlugins = new Hashtable();
        activePlugins = new Hashtable();
       
        for(int i = 0; i < searchPaths.size(); i++)
        {
            if(searchPaths.get(i) instanceof File)
                loadFile((File) searchPaths.get(i));
            else
                loadFile(searchPaths.get(i).toString());
           
        }
    }
   
    private static void loadFile(File f)
    {
        if(f.isDirectory())
        {
            File []files = f.listFiles();
            for(int i = 0; i < files.length; i++)
                loadFile(files[i]);
        }
        else if(f.getName().matches(".*\\.jar"))
        {
            loadFile("file://" + f.getAbsolutePath());
        }
    }
   
    private static void loadFile(String url)
    {
        try
        {
            //System.out.println("Trying to load file: " + url);
            loadFile(new URL(url));
        }
        catch(MalformedURLException e)
        {
            try
            {
                //System.out.println("--> Failed, trying to load file: file://" + url);
                loadFile(new URL("file://" + url));
            }
            catch(MalformedURLException e2)
            {
                System.err.println("--> Unable to load plugin: " + url);
                System.out.println(e);
                System.out.println(e2);
            }
        }
    }
   
    private static void loadFile(URL url)
    {
        try
        {
            System.out.println("Loading plugin: " + url);
           
        URL[] urls = { url };
        URLClassLoader ucl = new URLClassLoader(urls);
        Class cl = ucl.loadClass("PluginMain");
        PluginInterface plugin = (PluginInterface) cl.newInstance();
       
       
        if(plugin.getName() == null)
        {
            System.err.println("Error loading class: the plugin's name is set to null.  Aborting its load.");
        }
        else if(allPlugins.get(plugin.getName()) != null)
        {
            System.err.println("Plugin conflict: Plugin \"" + plugin.getName() + "\" already exists.  If this is because it's included in your list " +
                    "twice, then disregard this message.  Otherwise, one of the plugins needs a different name.  Aborting load.");
        }
        else
        {
            plugin.load();
            allPlugins.put(plugin.getName(), plugin);
        }
       
        }
        catch(ClassNotFoundException e)
        {
            System.out.println("  --> Load failed.");
        }
        catch(Exception e)
        {
            System.out.println("Unable to load plugin file: " + url);
            System.out.println(e);
        }
    }
   
    public static Vector getPluginList()
    {
        Vector v = new Vector();
        Enumeration e = allPlugins.keys();
        while(e.hasMoreElements())
            v.add(e.nextElement());
        return v;
    }
   
    /** This loads a plugin into memory for the current instance, calling the plugin's activate() function
    * TODO: Throw an exception if the plugin isn't found */
    public static boolean activatePlugin(String name, PublicBot bot)
    {
        PluginInterface plugin = (PluginInterface) allPlugins.get(name);
        if(plugin == null)
            return false;
       
        plugin.activate(bot);
        activePlugins.put(name, bot);
       
        return true;
    }
   
    /** This unloads a plugin from memory for the current instance, calling the plugin's deactivate() function
    * TODO: Throw an exception if the plugin isn't found.
    * TODO: Make it possible to unregister plugins */
    public static boolean deactivatePlugin(String name, PublicBot bot)
    {
        PluginInterface plugin = (PluginInterface) activePlugins.get(name);
        if(plugin == null)
            return false;
       
        plugin.deactivate(bot);
        activePlugins.remove(bot);
       
        return true;
    }

}
[/code]

Hope this helps out a little or at least gives you SOME idea. 
December 8, 2004, 4:14 AM

Search