Author | Message | Time |
---|---|---|
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 |