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?
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.
I would love to see the info you have on it iago, Java or otherwise.
~-~(HDX)~-~
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:
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();
}
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:
/*
* 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]
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.
/*
* 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;
}
}
Hope this helps out a little or at least gives you SOME idea.