Valhalla Legends Forums Archive | Java Programming | Adding plugin support

AuthorMessageTime
Tuberload
This is just a quick example to start off with demonstrating how to dynamically load and use Java class files.

PluginLoader.java:
[code]package tuberload.phuzionbot;

public class PluginLoader
{
   public static void main (String[] args)
   {
      PluginLoader pl = new PluginLoader();
      
      pl.run();
   }
   
   public void run()
   {
      try
      {
         Class c = Class.forName ("tuberload.phuzionbot.TestPlugin");
         TestPlugin pt = (TestPlugin)c.newInstance();
         
         pt.test();
      } catch (Exception exc) { System.out.println (exc); }
   }
}[/code]

TestPlugin.java:
[code]package tuberload.phuzionbot;

public class TestPlugin
{
   public void test()
   {
      System.out.println ("Executing test plugin.");
   }
}[/code]

This is a very simple example but could be made into something much bigger. Once I finish developing my plugin system I will post it here.
June 15, 2004, 10:18 PM
iago
That's the same thing I do:

[code] public static boolean runCommand(String username, String message, BNetWrapper out, boolean remote) throws java.io.IOException
{
if(message == null || message.length() < 2)
return NOTHANDLED;

char triggerChar = remote ? out.getSetting("trigger").charAt(0) : '/';

if(message.charAt(0) != triggerChar)
return NOTHANDLED;

String commandName = message;
String parameters = null;

int space = message.indexOf(' ');

if(space != -1)
{
commandName = message.substring(0, space);
parameters = message.substring(space + 1);
}

commandName = Character.toUpperCase(commandName.charAt(1)) + (commandName.length() > 1 ? commandName.substring(2).toLowerCase()
: "");

try
{
if(remote == CommandInterface.REMOTE)
{
// Verify the user has the appropriate flags to access this command
RemoteCommandInterface command = (RemoteCommandInterface)Class.forName("javaop.bnet.commands.remotehandlers." + command
Name).newInstance();

if(command.getRequiredFlags().length() == 0 || out.hasAny(username, command.getRequiredFlags()))
return command.execute(username, parameters, out);
else
throw new AccessException(username, commandName);
}
else
return ((CommandInterface)Class.forName("javaop.bnet.commands.handlers." + commandName).newInstance()).execute(co
mmandName, parameters, out);
}
catch(AccessException e)
{
out.log("User attempted to access illegal command: " + e, 0);
return HANDLED;
}
catch(UsageException e)
{
out.sendWhisper(username, e.toString());
return HANDLED;
}
catch(Exception e)
{
e.printStackTrace();
return NOTHANDLED;
}
}
[/code]
June 15, 2004, 10:43 PM
Tuberload
Ah very nice. I am making it so the plugin manager registers the plugins to receive events from the event generator. That way they get direct access to whatever they want. Basically they will inherit an interface depending on what Battle.net packets they want to receive events for.

I am also working on making my own simple script engine for fun, but I figured why not use the power of Java as far as the core plugins are concerned.
June 15, 2004, 11:10 PM
Myndfyr
[quote author=Tuberload link=board=34;threadid=7269;start=0#msg65392 date=1087337924]
This is just a quick example to start off with demonstrating how to dynamically load and use Java class files.

PluginLoader.java:
[code]package tuberload.phuzionbot;

public class PluginLoader
{
   public static void main (String[] args)
   {
      PluginLoader pl = new PluginLoader();
      
      pl.run();
   }
   
   public void run()
   {
      try
      {
         Class c = Class.forName ("tuberload.phuzionbot.TestPlugin");
         TestPlugin pt = (TestPlugin)c.newInstance();
         
         pt.test();
      } catch (Exception exc) { System.out.println (exc); }
   }
}[/code]

TestPlugin.java:
[code]package tuberload.phuzionbot;

public class TestPlugin
{
   public void test()
   {
      System.out.println ("Executing test plugin.");
   }
}[/code]

This is a very simple example but could be made into something much bigger. Once I finish developing my plugin system I will post it here.
[/quote]

I'm ignoring iago's system cuz I'm too lazy to read it....

Anyway, I was just going to suggest you make the plugins either implement an interface or inherit from a class. That way they all override base plugin functionality and you know what methods you can call on the descendent plugin. You don't need to reflect over the methods or anything, and you can create and cast an instance of the object in your compiled class without knowing what the name of the descendent plugin class will be named. :)

Just a thought, don't know if you were considering it.

For me, all plugin classes must inherit from PluginBase. (They also must have a class-level attribute, but that's a C# thing). The PluginBase class is defined as something like this:

[code]

public abstract class PluginBase
{
public abstract void Initialize(IEventHost eventHost,
StringDictionary persistedSettings);
public abstract void Close(IEventHost eventHost);

public abstract void PersistSettings(StringDictionary persistedSettings);
}

[/code]

The Initialize method registers all event handlers the plugin will handle, and also loads the settings from a StringDictionary marshaled by the bot. (A StringDictionary is a special type of collection that is essentially a typed Hashtable, that lets me use string indexers rather than generic Object or numeric indexers, to retrieve strings). Close tells the plugin to unregister its event handlers, and PersistSettings tells the plugin to save its settings for the next round.

Anyway, just some suggestions.
June 16, 2004, 12:44 AM
iago
Myndfyre -- mine implements an interface like you suggested. The RemoteCommand interface is pretty sexy:

[code]public interface RemoteCommandInterface extends CommandInterface
{
public String getName();
public String getUsage();
public String getRequiredFlags();
public String getDescription();
}[/code]

The flags are automatically checked, so I don't have to worry as long as I specify which flags people need. And when somebody does .help [command], it calls .getDescription. I also wrote a program that steps through the directory and summarizes the commands, producing output like:
www.valhallalegends.com/iago/commands.txt
www.valhallalegends.com/iago/flags.txt
(I know those are inaccessable right now, but they will be ok later)
June 16, 2004, 1:26 AM
Tuberload
[quote author=Myndfyre link=board=34;threadid=7269;start=0#msg65411 date=1087346669]I'm ignoring iago's system cuz I'm too lazy to read it....

Anyway, I was just going to suggest you make the plugins either implement an interface or inherit from a class. That way they all override base plugin functionality and you know what methods you can call on the descendent plugin. You don't need to reflect over the methods or anything, and you can create and cast an instance of the object in your compiled class without knowing what the name of the descendent plugin class will be named. :)

Just a thought, don't know if you were considering it.

For me, all plugin classes must inherit from PluginBase. (They also must have a class-level attribute, but that's a C# thing). The PluginBase class is defined as something like this:[/quote]

Did you ignore my second post as well: :P

[quote author=Tuberload link=board=34;threadid=7269;start=0#msg65399 date=1087341023]
Ah very nice. I am making it so the plugin manager registers the plugins to receive events from the event generator. That way they get direct access to whatever they want. Basically they will inherit an interface depending on what Battle.net packets they want to receive events for.

I am also working on making my own simple script engine for fun, but I figured why not use the power of Java as far as the core plugins are concerned.
[/quote]

Like the original post says, this is just a quick example of how to dynamically load a Java class and use it.

I have created multiple interfaces for plugin developers to inherit based upon their desired access to the bot. Your suggestions are welcome though; perhaps we can discuss this more when I release my working solution.
June 16, 2004, 1:42 AM
Myndfyr
[quote author=Tuberload link=board=34;threadid=7269;start=0#msg65418 date=1087350160]
Did you ignore my second post as well: :P

[quote author=Tuberload link=board=34;threadid=7269;start=0#msg65399 date=1087341023]
Ah very nice. I am making it so the plugin manager registers the plugins to receive events from the event generator. That way they get direct access to whatever they want. Basically they will inherit an interface depending on what Battle.net packets they want to receive events for.

I am also working on making my own simple script engine for fun, but I figured why not use the power of Java as far as the core plugins are concerned.
[/quote]

Like the original post says, this is just a quick example of how to dynamically load a Java class and use it.

I have created multiple interfaces for plugin developers to inherit based upon their desired access to the bot. Your suggestions are welcome though; perhaps we can discuss this more when I release my working solution.
[/quote]

No, Tuberload, I didn't ignore your second post. However, neither post mentioned interfaces or parent classes. Your code from the first post:

TestPlugin.java:
[code]package tuberload.phuzionbot;

public class TestPlugin
{
public void test()
{
System.out.println ("Executing test plugin.");
}
}[/code]

TestPlugin doesn't extend or implement anything. And your loader:

[code]
Class c = Class.forName ("tuberload.phuzionbot.TestPlugin");
TestPlugin pt = (TestPlugin)c.newInstance();
[/code]

It doesn't truly "dynamically" load your plugin -- you provide the type name, which *could* dynamically load a plugin, if you made the parameter to .forName() a string variable rather than a literal. HOWEVER, the example that you gave makes such loading irrelevant, because you then use code that knows the type -- TestPlugin -- that you're dynamically loading.

To make it work for any type, you'd need to either inherit a base class or implement interfaces (which I saw you said you did). But then, what you'd want to do is, rather than making the plugin class name part of the code, make the base class/interface what you declare in code:
[code]
IPlugin plugin = (IPlugin)c.newInstance();
[/code]

Anyway, I don't know if you made that clear (I don't think you did), and that's what my post was trying to get to. Your example wasn't a quick example of how to dynamically load a Java class, because the next statement would have loaded it anyway, without the loading being dynamic.

My 2 cents. (For those on this forum that think I'm Mr. C#, I have 1+ yr of Java experience. I just choose not to talk about it too much :P )
June 16, 2004, 5:16 PM
Tuberload
[quote author=Tuberload link=board=34;threadid=7269;start=0#msg65392 date=1087337924]
This is just a quick example to start off with demonstrating how to dynamically load and use Java class files.

This is a very simple example but could be made into something much bigger. Once I finish developing my plugin system I will post it here.
[/quote]

Ah yes, that must not have been very clear that this was just an example of how to use Java Class objects… Why would anyone give a quick example of something, in an attempt to spark some thinking, when they could just wait until they were finished and give it all away? Beats me...

[quote author=Tuberload link=board=34;threadid=7269;start=0#msg65399 date=1087341023]
Ah very nice. I am making it so the plugin manager registers the plugins to receive events from the event generator. That way they get direct access to whatever they want. Basically they will inherit an interface depending on what Battle.net packets they want to receive events for.

I am also working on making my own simple script engine for fun, but I figured why not use the power of Java as far as the core plugins are concerned.
[/quote]

Hrmmm, that looks like I talked about inheriting an interface to me...

To me it seems you just glanced at my source code, and hurried up to make a post on the *right* way to do things. (For those of you on the forum I have 2+ years of Java experience, so I do have somewhat of a clue about what is going on.)
June 16, 2004, 7:27 PM

Search