jump to navigation

Passing data between a script and a region module with modSendCommand() July 16, 2010

Posted by justincc in opensim, opensim-dev, opensim-modules, opensim-scripting, secondlife, virtual-environments, virtual-worlds.
trackback

Hi folks.  As many of you may know, one of the most interesting things about OpenSimulator is the ability to extend it using region modules.  Region modules plug in to the server and allow you to do pretty much anything with the world, such as sending text chat between different grids, controlling objects, moving avatars, implementing cellular automata and in the case of Realxtend, even adding meshes (for use with the Realxtend client).  In fact, a large percentage of ‘core’ OpenSim functionality is implemented using region modules.

However, up until fairly recently it hasn’t been easy to communicate with these modules from in-world LSL/OSSL scripts.  Implementing new script functions to call module methods – osDoSomethingCool(), for example – is very awkward because it requires direct patches to OpenSim code.  OpenSim’s current script compilation mechanism doesn’t allow these to be set up from within a region module.

In principle, one could also call region module functions from in-world C# scripts.  But these also require direct patching of OpenSim, this time to include the right DLL references from C# script assemblies.

In OpenSim 0.6.9, however, a new script function called modSendCommand() was introduced.  This allows an LSL/OSSL script to post some arbitrary data to a ‘script command’ event.  A region module can listen for this event and in turn send a reply.  The script receives this reply via the in-world link_message event.  Let’s go through an example.

modSendCommand() example

Enabling the command

The first thing is to enable modSendCommand() in OpenSim.ini.  Make sure the line

AllowMODFunctions = true

is set to true and uncommented.

The Region Module

Secondly, we need a region module to listen for the data sent by modSendCommand() and send a reply.

using System;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;

namespace ModSendCommandExample
{
  public class MyRegionModule : IRegionModule
  {
    Scene m_scene;
    IScriptModuleComms m_commsMod;

    public string Name { get { return "MyRegionModule"; } }
    public bool IsSharedModule { get { return false; } }
    public void Close() {}

    public void Initialise(Scene scene, IConfigSource source)
    {
       m_scene = scene;
    }

    public void PostInitialise()
    {
      m_commsMod
        = m_scene.RequestModuleInterface<IScriptModuleComms>();
      m_commsMod.OnScriptCommand += ProcessScriptCommand;
    }

    void ProcessScriptCommand(
      UUID scriptId,
      string reqId, string module, string input, string k)
    {
      if ("MYMOD" != module)
        return;

      string[] tokens
          = input.Split(
              new char[] { '|' }, StringSplitOptions.None);

      string command = tokens[0];
      switch (command)
      {
        case "Greet":
          string name = tokens[1];
          m_commsMod.DispatchReply(scriptId, 1, "Hello " + name, "");
          break;
      }
    }
  }
}

The module subscribes to the OnScriptCommand IScriptModuleComms event in PostInitialise().  When a script command event occurs, it checks that the module identifier is correct (MYMOD) and then splits the command into components delimited by a bar (|).  This isn’t essential – it’s just one way of invoking arbitrary commands.

In this case, the command name is the first component.  If it’s “Greet”, then a reply is sent back using the supplied name argument which is the second component.

The In-world Script

Here’s the in-world script that makes the call and receives the reply.

default
{
  touch_start(integer total_number)
  {
    modSendCommand("MYMOD", "Greet|World", "");
  }

  link_message(integer sender_num, integer num, string message, key id)
  {
    if (sender_num == -1)
    {
      llSay(0, message);
    }
  }
}

As you can see, a touch triggers the command to the module.  The script receives back the link_message event and says the data in-world.

You can download compilable region module source and script code for this example from here.

Conclusion

modSendCommand() isn’t a perfect mechanism by any means – I still think it would be much nicer to have explictly named script commands.  Packing all the data into a single string seems pretty crazy considering that both script and region module are running in the same process.  Nonetheless, I would say that being able to implement script command processing purely within the region module is a major plus.  This way, the module can simply be dropped in a vanilla OpenSim’s bin directory with no extra patches required.

Advertisements

Comments»

1. Tweets that mention Passing data between a script and a region module with modSendCommand() | justincc.org -- Topsy.com - July 17, 2010

[…] This post was mentioned on Twitter by devi, Justin Clark-Casey. Justin Clark-Casey said: Passing data between a script and a region module with modSendCommand() – http://bit.ly/cTsPzA – Finally found time to write! #opensim […]

2. rjs - July 18, 2010

Very nice tut. Seems as though the possibilities are endless.

Thanks for posting on this Justin.

3. Skidz Tweak - August 23, 2010

Question… I am thinking of making a texture organizer.. I have done this in scripts, and find it slow in opensim. Would this be significantly faster? Could I use this to access prim inventory data, and manipulate prims in the link set? If so, whats the name of those objects I would use? I know I could just send linked messages to scripts, but would like to keep scripts to a min.

Also, if I ran two, in world organizer, would they share the same instance? I could think of some really fun uses for something like this 🙂

4. justincc - August 24, 2010

@Skidz – If you’re running this on a custom grid, have you tried dropping the ScriptDelayFactor? This will reduce all the standard delays on scripting functions.

In principle, you could do anything via a region module at the backend. The main problem is that the internals of OpenSim are currently extremely messy and poorly documented – it would take a lot of patience to find out how to do certain things. The best way to find out is generally by looking at existing region module code, or by looking at the automated test code in OpenSim.

5. Skidz Tweak - August 25, 2010

@justincc – Thanks for the tips – will check them out


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: