Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (495)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Writing a Java Plugin System  (Read 5283 times)
0 Members and 1 Guest are viewing this topic.
Offline Agro
« Posted 2013-03-23 01:11:16 »

Java has a very useful modules system that allows you to write "plug-ins" for an application using the Reflection API. It can be used for a variety of things and in terms of gaming, it can be used for these:

  • Quests
  • New Gamemodes
  • New Entities

And a lot more stuff, just to give you an idea. Note that this isn't restricted to gaming, and has even more uses in software engineering itself. There are a few reasons why we would want to use this plugin system. First of all, you don't need to write your own scripting language or whatever for something huge. Then, its really quick and fast to set up, and it makes a whole lot of sense.

However, there are some disadvantages as well. Since Java uses the JAR format, it can easily be modified without security like obfuscation and hash checking with the internet. Also, if you are going to open your API to developers, you have to make sure public fields are public, private fields are private, and protected fields are protected. Otherwise they get access to a whole bunch of things that can ruin the game. That's about it for explanations. Now let's get to the real code.

So, first, we have to make an API. Most of it will probably already have been done. I will be presenting a small quests system in this. In my project, I've defined a Quest class as follows:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
public class Quest {

   private int id;
   private int position;

        private QuestRunner qr;

        public void init(QuestRunner qr) {
               this.qr = qr;
        }

        public void setID(int id) {
                this.id = id;
        }
   
   public void nextPosition() {
      position++;
   }
   
   public int getID() {
      return id;
   }
   
   public int getPosition() {
      return position;
   }

        public List<Command> nextEvent() {
                ...
                return commands;
        }
   
}


I included a QuestRunner class(shown later) in the Quest file so the class can add events to the event buffer in the QuestRunner. Events in this term means like things to do like display text, move a character here, start another event, start a battle, etc.

For simplicity's sake, I've also defined a QuestController class, that "controls" the quest, or just organizes them:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
import java.util.ArrayList;
import java.util.List;

public class QuestController {

   private List<Quest> quests;
   
   public QuestController() {
      quests = new ArrayList<Quest>();
   }
   
   public Quest getQuestWithID(int id) {
      for(Quest q : quests)
         if(q.getID() == id)
            return q;
      return null;
   }
   
}


Now, there's also a class called QuestRunner, that runs the events produced by the quest:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
import java.util.ArrayList;
import java.util.List;

public class QuestRunner {

   private List<Command> eventbuffer;
   
   public QuestRunner() {
      eventbuffer = new ArrayList<Command>();
   }
   
   public void runEvents(List<Command> event) {
      for(Command comm: event) {
         eventbuffer.add(comm);
      }
      event.clear();
   }
   
   public class Command {
     
      private int command;
      private String params;
     
      public Command(int c, String p) {
         this.command = c;
         this.params = p;
      }
     
   }
   
}


I've only given enough information in the class so an API can be written with it, not its actual functionality, just to note. Now, I export it as a JAR(not a runnable jar). Unselect all the files, and then I go select only Quest, QuestController, and QuestRunner. This will only make these classes available in the API. So now I export it, and I now have a quest API that can be used in another project.

Note that I the only reason I export as a JAR is for simplicity here. You can export your entire project and the API will have everything available, but usually you'd need to make sure all the visibilities of fields are correct.

So, now, you can make a new project, maybe name it "Quests". In here, make a new class that extends Quest. Do stuff in it, add to the storyline etc. Now you can export it as a JAR including only what classes you need.

Now, back in your main game, you can make use of this JAR file you exported with a URLClassLoader object. Basically it allows you to open a JAR file and get a class:

1  
URLClassLoader classLoader = URLClassLoader .newInstance(new URL[] { new URL("file:./quests/TheStolenJewel.jar") };


The jar is loaded here, so now we can load it into an actual Quest object using the reflection API!:

1  
2  
3  
Class<?> clazz = classLoader.loadClass("com.jgo.games.quests.MainQuest");
Quest quest = (Quest) clazz.newInstance();
quest.init(questrunner);


Notice that the name of the class must be the same for each quest, but you can do some nifty stuff with config files to change that.

So that's it! You have a quest object, now you can do whatever you want with it, just like a real class!

Now you can play with this new thing and do it for anything you want! Cheesy

Thanks for reading! =) Tell me if I've done any errors, I'll fix it right away.

Offline deepthought
« Reply #1 - Posted 2013-03-23 02:27:19 »

The java class loader has the method defineClass(String name,byte[] class, int offset, int len). You could download the class to a byte array and do hash checking or decryption on that.

jocks rule the highschools. GEEKS RULE THE WORLD MWAHAHAHA!!
captain failure test game
Offline Agro
« Reply #2 - Posted 2013-03-23 02:38:22 »

Yeah, that works as well.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline ReBirth
« Reply #3 - Posted 2013-03-23 04:09:02 »

What is the advantage, compared to use the classes as normal library and declare it like usual (not using class loader, just import)?

Offline HeroesGraveDev

JGO Kernel


Medals: 250
Projects: 11
Exp: 2 years


┬─┬ノ(ಠ_ಠノ)(╯°□°)╯︵ ┻━┻


« Reply #4 - Posted 2013-03-23 04:31:18 »

You don't have to mess with the original .jar file to make mods.

If you've made/used Minecraft mods, you'll know what an advantage this is.

Offline ReBirth
« Reply #5 - Posted 2013-03-23 05:07:50 »

I don't play minecraft but I get it. Thanks.

Offline Danny02
« Reply #6 - Posted 2013-03-23 09:49:32 »

take a look at the ServiceLoader from the JRE.
I think it is a way better plugin System then what you presented.

Just add a plugin Jar to the classpath and without any further code the plugin will be found. In your example, you have to load every Jar by your self.

I also think that an API should only consist out of interfaces^^
Online Roquen
« Reply #7 - Posted 2013-03-23 13:27:33 »

The real advantage of systems based on dynamic loading is that you can change behavior at runtime without restart.  To do that you need to use one or more classloaders.  As an example you can do something like this (Fake mixins by inheritance part) to allow for total conversions.  Using a virtual filesystem probably makes a lot of sense as well.

Note: quests are pure data and really shouldn't need behavior extensions.
Offline deepthought
« Reply #8 - Posted 2013-03-23 14:37:09 »

You might need some sort of behavior to tell if the quest has been completed.

jocks rule the highschools. GEEKS RULE THE WORLD MWAHAHAHA!!
captain failure test game
Offline Agro
« Reply #9 - Posted 2013-03-23 16:40:04 »

Well, this was just an example on how to use it. The only reason I showed it was because i use to do Bukkit plugins and I made a working runescape bot before.

Maybe me using quests was a bit broad, but there are many other things that this is capable of. For multiplayer games, it would be a good idea if things were external.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Online Roquen
« Reply #10 - Posted 2013-03-24 07:05:45 »

@deepthought: I'd say that for quests to not be boring, you have to be able to add behavior...but that wasn't my point...my point is where and how.

Take say killing a specific monster/NPC, which might progress a given quest.  How is that different from launching a cut-scene or performing any additional uncommon thing?  It isn't.  You need to be able to script (potentially in a data-driven way) events that occur.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Dwinin (28 views)
2014-09-12 09:08:26

Norakomi (57 views)
2014-09-10 13:57:51

TehJavaDev (72 views)
2014-09-10 06:39:09

Tekkerue (37 views)
2014-09-09 02:24:56

mitcheeb (57 views)
2014-09-08 06:06:29

BurntPizza (43 views)
2014-09-07 01:13:42

Longarmx (27 views)
2014-09-07 01:12:14

Longarmx (34 views)
2014-09-07 01:11:22

Longarmx (34 views)
2014-09-07 01:10:19

mitcheeb (40 views)
2014-09-04 23:08:59
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!