Create a Stendhal server extension

From Arianne
Revision as of 15:59, 20 August 2006 by imported>Zenix2
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

How to create a server extension? This will teach you how to! Todays project: add the commands "/date" and "/time" for the users, so that they can check what time it is, or what date it is.

Requirements

Whats required?

  • An OS
  • Text editor
  • Java
  • A ready stendhal server
  • Java knowledge is recommened

Getting started with a example

If you download the source code, there is a extension already there for you! It's the Spouse extension. This allows marriage in-game! Here's how to add it to your server. First, open up marauroa.ini in your server directory (or wherever else everything is). Add this:

# load StendhalServerExtension(s)
groovy=games.stendhal.server.scripting.StendhalGroovyRunner
http=games.stendhal.server.StendhalHttpServer
spouse=games.stendhal.server.extension.SpouseExtension
server_extension=groovy,spouse

Here is the run down: groovy=games.stendhal.server.scripting.StendhalGroovyRunner spouse=games.stendhal.server.extension.SpouseExtension These are just variables that hold the pointer to a specfic class that is the actual extension itself server_extension=groovy,spouse This is the line marauroa reads. After the equal, the list of variables are pointers to the extension class.

Recompile and restart your server and have a blast! If you can run /jail, then you're a priest! Read the comments in the source code of SpouseExtension.java to learn of the command's syntax. (/marry and /spouse are the two commands added)


Getting your own setup

Ok, let's be cliched here. The "hello, world!" of stendhal server extensions!

The file

Create a file in <downloaded stendhal source>/src/games/stendhal/server/extension/ called "HelloWorldExtension.java" and add this to it (just for now):

package games.stendhal.server.extension;

import games.stendhal.server.StendhalRPAction;
import games.stendhal.server.StendhalRPRuleProcessor;
import games.stendhal.server.StendhalRPWorld;
import games.stendhal.server.StendhalRPZone;
import games.stendhal.server.StendhalServerExtension;
import games.stendhal.server.entity.Player;
import marauroa.common.Log4J;
import marauroa.common.game.RPAction;
import marauroa.server.game.RPWorld;

import org.apache.log4j.Logger;

public class HelloWorldExtension extends StendhalServerExtension {

    private final String HELLOWORLD = "helloworld";
    private static final Logger logger = Log4J.getLogger(HelloWorldExtension.class);
    
    /**
     * @param rules - the reference to the rules processor
     * @param world - the reference to the game objects
     */
    public HelloWorldExtension(StendhalRPRuleProcessor rules, StendhalRPWorld world) {
        super(rules, world);
        logger.info("HelloWorldExtension starting...");
        StendhalRPRuleProcessor.register("hello", this);
    }

    /* 
     * @see games.stendhal.server.StendhalServerExtension#init()
     */
    @Override
    public void init() {
        // this extension has no spespecific init code, everything is
        // implemented as /commands that are handled onAction
    }
    
    @Override
    public void onAction(RPWorld world, StendhalRPRuleProcessor rules,
            Player player, RPAction action) {
       String type = action.get("type");
        
        if (type.equals("hello")) {
            onHello(world, rules, player, action);
        }
     
    }
    
    private void onHello(RPWorld world, StendhalRPRuleProcessor rules, Player player, RPAction action) {
    	player.sendPrivateText("Hello, world!");
    }
}

Time for an explanation: First, we import a whole lot of stuff. This is just so we can interact with EVERY aspect of the server & game world. Next, we define our class and initilazation function. In that, we request for some variables, and startup the logger. This line:

private static final Logger logger = Log4J.getLogger(HelloWorldExtension.class);

MUST point to the right class, or it won't work, and you'll go nowhere when trying to send information to the logs! Now, this line is new (well, isn't all of this? :P)

StendhalRPRuleProcessor.register("hello", this);

This code tells the server "register the command '/hello' to the class 'this'" ('this' is a dynamic variable that points the class). Nice, huh? Now the user can type '/hello' into their textboxes without getting a not found error! Wheeee! Now, lets continue onto the onAction functio. In it, we check to see if the command is hello, and run the onHello function. (Why do we check it? Dunno, that's just how I learned it, and I haven't found a way to do it otherwise) In the onHello world function, we then send the player who ran the command a private message: Hello, world! Pretty boring, huh? Now, onto the main project!

Date and Time

Now, I'm not going to re-post the entire script, as it gets to be just under 100 lines of code, and I don't want a INCREDIBLY long page! First, we import a new class: java.util.Calendar With that, we can get the current date and time! Then, add these lines to your class method:

StendhalRPRuleProcessor.register("date", this);
StendhalRPRuleProcessor.register("time", this);

These register the date and time commands. Now, we add the if to onAction:

        if (type.equals("date")) {
            onDate(world, rules, player, action);
        } else if (type.equals("time")) {
            onTime(world, rules, player, action);
        }

And add the two functions onDate and onTime:

    private void onDate(RPWorld world, StendhalRPRuleProcessor rules,
			Player player, RPAction action) {
		Calendar calendar = Calendar.getInstance();
		String[] months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "July", "Aug", "Sep", "Oct", "Nov", "Dec"};
		player.sendPrivateText("The current date is: " + months[calendar.get(calendar.MONTH)] + ", " + calendar.get(calendar.DATE) + ", " + calendar.get(calendar.YEAR));
	}
	
    private void onTime(RPWorld world, StendhalRPRuleProcessor rules,
			Player player, RPAction action) {
		Calendar calendar = Calendar.getInstance();
		player.sendPrivateText("The current time is: " + calendar.getTime().toString());
	}

That's it! Now, just recompile your server, and boom! Your 75% there! Now, one last thing; configuring the server to motice your new extension.

Configuration of marauroa

Now, again open up marauroa.ini, and add these lines:

date_time=games.stendhal.server.extension.DateAndTimeExtension
server_extension=date_time

Now, if you've been following the tut, don't just copy/paste the second line - add 'date_time' to the end of the list, with a comma before it. Also, if you've saved the file somewhere else other than where the Spouse extension is (which I don't recommend doing, it's in a folder called "extension") you're going to have to change the class path to point to that.

Done

Done! Now you've completely added 2 extensions, one of which is pointless other than, "I did it! I did it!" Have your users be notified of the change; they may or may not like it!