OpenSim.Region.ScriptEngine.Common
From OpenSimulator
m |
|||
Line 82: | Line 82: | ||
===IScript interface=== | ===IScript interface=== | ||
So you have implemented the two classes described above. Now how does this connect to your JavaScript or Perl or YourCustomSuperLanguage script engine or VM?<br /> | So you have implemented the two classes described above. Now how does this connect to your JavaScript or Perl or YourCustomSuperLanguage script engine or VM?<br /> | ||
+ | <br /> | ||
You have to create a class. This class must inherit "OpenSim.Region.ScriptEngine.Common.IScript". Inside IScript your class will have two major things: <br /> | You have to create a class. This class must inherit "OpenSim.Region.ScriptEngine.Common.IScript". Inside IScript your class will have two major things: <br /> | ||
+ | <br /> | ||
1. During script start (in ScriptManager), you call yourscript.Start() and give it a LSL command module. So insite your script class where you override this Start() function you need to remember this LSL command module.<br /> | 1. During script start (in ScriptManager), you call yourscript.Start() and give it a LSL command module. So insite your script class where you override this Start() function you need to remember this LSL command module.<br /> | ||
How you bind this LSL command module to your custom engine is totally up to you. The LSL command module contains all LSL functions, and any function you use there will affect the correct object/region/whatever. You don't need to do more than ''myLSLCommandModule.llSay(0, "Hello world!");'' to make it work.<br /> | How you bind this LSL command module to your custom engine is totally up to you. The LSL command module contains all LSL functions, and any function you use there will affect the correct object/region/whatever. You don't need to do more than ''myLSLCommandModule.llSay(0, "Hello world!");'' to make it work.<br /> | ||
+ | <br /> | ||
2. Any time a LSL event is generated either by an in-world event or by for example a timer, a function in your script class needs to be executed. For this you have the "Exec" override. I suggest you have a look at "OpenSim.Region.ScriptEngine.Common.Executor" to see how this work. Basically you receive a string containing function name and the parameters for that event.<br /> | 2. Any time a LSL event is generated either by an in-world event or by for example a timer, a function in your script class needs to be executed. For this you have the "Exec" override. I suggest you have a look at "OpenSim.Region.ScriptEngine.Common.Executor" to see how this work. Basically you receive a string containing function name and the parameters for that event.<br /> | ||
If you use the default Executor you need to initialize it by giving it a reference to yourself (the IScript script class). Then you need to have functions in your class matching LSL functions when it comes to both name and parameters. Example:<br /> | If you use the default Executor you need to initialize it by giving it a reference to yourself (the IScript script class). Then you need to have functions in your class matching LSL functions when it comes to both name and parameters. Example:<br /> | ||
− | public touch_start | + | public touch_start(int number_of_touches) { |
+ | // whatever code for this event... probably calling your own VM's function with the same name? ;) | ||
+ | } |
Revision as of 11:09, 20 January 2008
Contents |
OpenSim.Region.ScriptEngine.Common
How to implement your own script engine
Creating a new script engine for OpenSim is simple (haha).
What I mean by simple is that if you already have a VM (Virtual Machine) or script engine of some sort then integrating it as a OpenSim ScriptEngine plugin is simple.
How do I get started?
1. Create a new project named "OpenSim.Region.MySuperScriptEngine" (replace "MySuperScriptEngine" with the name of your scriptengine).
2. Create a new class (file) named "ScriptEngine". It must be named exactly ScriptEngine for OpenSim to use it. ScriptEngine must inherit from "OpenSim.Region.ScriptEngine.Common.ScriptEngineBase.ScriptEngine".
3. You need to override a couple of functions. Most probably you don't want to do any special work here, so look below for a sample default file.
4. Create a new class (file) named "ScriptManager" that inherits from "OpenSim.Region.ScriptEngine.Common.ScriptEngineBase.ScriptManager".
5. Your ScriptManager class needs to override two functions. One to start a script and one to stop a script.
ScriptEngine class
The main purpose of ScriptEngine class is to be able to intercept scene, for example starting with a "fake" scene instead of OpenSim's scene. You probably don't want this, so just go for the standard initialization.
A standard class would look like this:
using System; using Nini.Config; using OpenSim.Framework.Console; using OpenSim.Region.Environment.Scenes; namespace OpenSim.Region.ScriptEngine.MySuperScriptEngine { [Serializable] public class ScriptEngine : OpenSim.Region.ScriptEngine.Common.ScriptEngineBase.ScriptEngine { public override void Initialise(Scene scene, IConfigSource config) { InitializeEngine(scene, MainLog.Instance, true, GetScriptManager()); } public override OpenSim.Region.ScriptEngine.Common.ScriptEngineBase.ScriptManager _GetScriptManager() { return new ScriptManager(this); } } }
ScriptManager class
A script is refecenced by object id "localID" (the object/prim it is inside) and script id "itemID" (the particular (unique) instance of that script). These parameters along with a string "Script" containing the script text (source code) are passed to your (overriden) start script function in your ScriptManager class.
Keeping track of active scripts is done automatically, so your job is simply to create a new script and hand it over. After that your work is done until the script is asked to stop, then you have to do a few simple tasks to remove it again.
Here is a sample on a minimal script startup:
public override void _StartScript(uint localID, LLUUID itemID, string Script) { SceneObjectPart m_host = World.GetSceneObjectPart(localID); try { IScript CompiledScript = MySpecialCompiler.DoCompile(Script); // Compile and return an IScript object that is the actual script CompiledScript.Source = ScriptSource; // Store source for recompile on script reset events SetScript(localID, itemID, CompiledScript); // All is ok. Add script to OpenSim's script manager. From here on its on autopilot. // Create a private instance of LSL commands (note that m_scriptEngine, m_host are from baseclass, so you don't need to change them) LSL_BuiltIn_Commands LSLB = new LSL_BuiltIn_Commands(m_scriptEngine, m_host, localID, itemID); CompiledScript.Start(LSLB); // Start the script - giving it LSL commands // Fire the first start-event, this is the event run on LSL scripts when they first start m_scriptEngine.m_EventQueueManager.AddToScriptQueue(localID, itemID, "state_entry", EventQueueManager.llDetectNull, new object[] { }); } catch (Exception e) { // To see how you can send the compile error in-world, have a look at OpenSim.Region.ScriptEngine.DotNetEngine.ScriptManager } }
And your minimal script shutdown would be:
public override void _StopScript(uint localID, LLUUID itemID) { m_scriptEngine.m_LSLLongCmdHandler.RemoveScript(localID, itemID); // Stop long command on script like timers, http requests, etc. IScript LSLBC = GetScript(localID, itemID); // Get the script we are stopping if (LSLBC == null) // Nothing to do? Exit. return; try { LSLBC.Exec.StopScript(); // Tell script to stop RemoveScript(localID, itemID); // Remove script from internal memory structure } catch (Exception e) { // You probably want to log this to console or something } }
IScript interface
So you have implemented the two classes described above. Now how does this connect to your JavaScript or Perl or YourCustomSuperLanguage script engine or VM?
You have to create a class. This class must inherit "OpenSim.Region.ScriptEngine.Common.IScript". Inside IScript your class will have two major things:
1. During script start (in ScriptManager), you call yourscript.Start() and give it a LSL command module. So insite your script class where you override this Start() function you need to remember this LSL command module.
How you bind this LSL command module to your custom engine is totally up to you. The LSL command module contains all LSL functions, and any function you use there will affect the correct object/region/whatever. You don't need to do more than myLSLCommandModule.llSay(0, "Hello world!"); to make it work.
2. Any time a LSL event is generated either by an in-world event or by for example a timer, a function in your script class needs to be executed. For this you have the "Exec" override. I suggest you have a look at "OpenSim.Region.ScriptEngine.Common.Executor" to see how this work. Basically you receive a string containing function name and the parameters for that event.
If you use the default Executor you need to initialize it by giving it a reference to yourself (the IScript script class). Then you need to have functions in your class matching LSL functions when it comes to both name and parameters. Example:
public touch_start(int number_of_touches) { // whatever code for this event... probably calling your own VM's function with the same name? ;) }