Example of a Basic Server Plugin

From Multiverse

Jump to: navigation, search
Contributed by: Multiverse Last Tested: 08 Mar 08 Tested By: PaulO Tested With: 1.1

Contents

Overview

This example of a basic server plugin gets a list of all users currently logged in to the server, and displays it in the Client. This plugin is called "Admin plugin."

Here are the basic steps:

  1. Write the Java class for the plug-in, AdminPlugin.java.
  2. Create a simple Python file, admin.py, to register the plug-in. Save this file in the world script directory (for example, mv-home/config/sampleworld for sampleworld).
  3. Edit the server startup script, multiverse.sh, to the scripts read and executed by the mob server plugin. Thus, the admin plug-in will run in the same JVM as the mob server. This is just a convenience. If you like, you could run it in a separate JVM.
  4. Add code to mv-home/config/common/proxy.py to subscribe to messages generated by the plugin, and process them.

Write the plug-in class

This example class is in the multiverse.server.plugins package, but you can put your plug-ins in any appropriate package, for example, mycompany.plugins. Add the package to the JAR file mars.jar, which the server startup scripts then append to the classpath.

Every plug-in class must extend multiverse.server.engine.EnginePlugin. In general, a plug-in should override the getName() and onActivate() methods. The server engine calls onActivate() when it loads the plug-in, so that is normally where you put code that you want the plug-in to execute. In this example, the plug-in instantiates an inner class, InnerThread, and creates a new thread on which to execute it.

The run() method

The plug-in does its real work in the run() method of the InnerThread inner class. This method is an implementation of the run() method of the Runnable interface.

First, the run() method creates a new message (a multiverse.msgsys.Message object) of type "GET_ALL_USERS". Then, it sends a message to the subscribers with a matching filter, and retrieves an Object response to the message, with the line

List<String> strings = (List<String>)Engine.getAgent().sendRPCReturnObject(msg);

It then displays this list in the server log.

Finally, it waits (sleeps) for ten seconds, and repeats the process.


package multiverse.server.plugins;

import java.util.List;

import multiverse.msgsys.*;
import multiverse.server.engine.Engine;
import multiverse.server.engine.EnginePlugin;
import multiverse.server.util.Log;

/**
* sample new message type "GET_ALL_USERS"
* sample response message
* sample hook
*/
public class AdminPlugin extends EnginePlugin {
    public String getName() {
        return "AdminPlugin";
    }
    
    public void onActivate() {
        InputThread inputThread = new InputThread();
        new Thread(inputThread).start();
    }
    
    public class InputThread implements Runnable {
        public void run() {
            while (true) {
                // sleep for 10 seconds
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    throw new RuntimeException("interrupt exception");
                }
                // send a GET_ALL_USERS message
                Message msg = new Message();
                msg.setMsgType(GET_ALL_USERS);
                List<String> userList = (List<String>)Engine.getAgent().sendRPCReturnObject(msg);
                
                // print out the list
                for (String userName : userList) {
                    Log.debug("InputThread: User= " + userName);
                }
                Log.debug("InputThread: LIST DONE-----------------------");
            }
        }
    }

    public static final MessageType GET_ALL_USERS = MessageType.intern("GET_ALL_USERS");
}

Register the plug-in

Create a new file, admin.py in mv-home/config/sampleworld directory. Add the following Python code to the file:

from multiverse.server.engine import *
from multiverse.server.plugins import *

Engine.registerPlugin("multiverse.server.plugins.AdminPlugin")

Add plug-in "advertisement"

The AdminPlugin, as part of the mobserver process, must "advertise" that it sends the GET_ALL_USERS message. Make it do that by adding the following line to the file mv-home/config/common/mobserver-ads.txt:

GET_ALL_USERS

And by adding the following line to file mv-home/config/yourworld/worldmessages.py:

MessageCatalog.addMsgTypeTranslation(worldMessageCatalog, AdminPlugin.GET_ALL_USERS)

Modify startup script

To execute the plug-in in the same JVM as the mob server, modify the server startup script. If you are using multiverse.sh, add the line in bold below:

       java \
           ${JAVA_FLAGS} \
           -Dmultiverse.loggername=mobserver \
           multiverse.server.marshalling.Trampoline \
           multiverse.server.engine.Engine \
           -i "${MV_BIN}"/mobserver_local.py \
           -i "${MV_COMMON}"/mvmessages.py \
           -i "${MV_WORLD}"/worldmessages.py \
           -m "${MV_COMMON}"/mvmarshallers.txt \
           -m "${MV_WORLD}"/worldmarshallers.txt \
           "${MV_COMMON}"/global_props.py \
           "${MV_WORLD}"/global_props.py \
           "${MV_COMMON}"/mobserver_init.py \
           "${MV_WORLD}"/mobserver_init.py \
           "${MV_COMMON}"/questplugin.py \
           "${MV_COMMON}"/mobserver.py \
           "${MV_WORLD}"/mobserver.py \
           "${MV_COMMON}"/extensions_mobserver.py \
           "${MV_WORLD}"/admin.py \
           &

If you are using start-multiverse.bat, add the line in bold below:

echo Starting mob server
START /B java ^
       %JAVA_FLAGS% ^
       -Dmultiverse.loggername=mobserver ^
       multiverse.server.marshalling.Trampoline ^
       multiverse.server.engine.Engine ^
       -i mobserver_local.py ^
       -i %MV_COMMON%\mvmessages.py ^
       -i %MV_WORLD%\worldmessages.py ^
       -m %MV_COMMON%\mvmarshallers.txt ^
       -m %MV_WORLD%\worldmarshallers.txt ^
       %MV_COMMON%\global_props.py ^
       %MV_WORLD%\global_props.py ^
       %MV_COMMON%\mobserver_init.py ^
       %MV_WORLD%\mobserver_init.py ^
       %MV_COMMON%\questplugin.py ^
       %MV_COMMON%\mobserver.py ^
       %MV_WORLD%\mobserver.py ^
       %MV_COMMON%\extensions_mobserver.py ^
       %MV_WORLD%\admin.py

Add method to subscribe to and process messages

Add the following code to multiverse/config/sampleworld/extensions_proxy.py:

proxyPlugin = Engine.getPlugin("Proxy1")

class WhoHook (Hook):
   def processMessage(self, msg, flags):
      Log.debug("WhoHook: got a who request, msg type is " + msg.getMsgType().getMsgTypeString())
      userList = LinkedList()
      
      # get a list of oids
      userList = proxyPlugin.getPlayerNames()
      Log.debug("WhoHook: returning user list size=" + str(userList.size()))
            
      # send the response message
      Engine.getAgent().sendObjectResponse(msg, userList)
      return Boolean(True)

Engine.getAgent().createSubscription(MessageTypeFilter(AdminPlugin.GET_ALL_USERS), proxyPlugin, MessageAgent.RESPONDER)
proxyPlugin.getHookManager().addHook(AdminPlugin.GET_ALL_USERS, WhoHook())

This Python code does the following:

  • Defines a class, WhoHook, with one method, processMessage() that processes messages from the admin plug-in.
  • Subscribes the proxy server to the "GET_ALL_USERS" message with the line
Engine.getAgent().createSubscription(MessageTypeFilter(AdminPlugin.GET_ALL_USERS), proxyPlugin, MessageAgent.RESPONDER)
  • Adds the WhoHook class as a hook for the message. You can associate more than one hook with a given message type which will be returned in order by getHooks().

The method ProxyPlugin.getPlayerNames() returns a list of the names of all players logged into the server.

Finally the HookManager matches incoming subscription messages with a hook that handles each message.

Same Admin Plug In Written in Python instead of Java

The following is the same basic admin plug-in written in Python instead of Java.

from java.lang import *
from java.util import *
from multiverse.server.engine import *
from multiverse.server.util import *
from multiverse.msgsys import *

#Create the engine plug in instance
adminplugin = EnginePlugin("adminplugin")
Engine.registerPlugin(adminplugin)

#Create the message
msgType_GetAllUser_Msg = MessageType.intern("mvcommons.GET_ALL_USERS") 
Engine.getAgent().addAdvertisement(msgType_GetAllUser_Msg)
msg = Message();
msg.setMsgType(msgType_GetAllUser_Msg)

#Send the message
while 1:
    Thread.sleep(20000)
    userlist = LinkedList()
    userlist = Engine.getAgent().sendRPCReturnObject(msg)
    Log.debug("AdminPlugin: returning user list size=" + str(userlist.size()))
Personal tools