ScriptEngines

From OpenSimulator

(Difference between revisions)
Jump to: navigation, search
m (Removed 'Template:' prefix from template includings and/or changed external-link into internal-link)
m
Line 7: Line 7:
 
This page deals with common parts of scripting and with [[XEngine]]. For [[DotNetEngine]], also see [[OpenSim.Region.ScriptEngine]]
 
This page deals with common parts of scripting and with [[XEngine]]. For [[DotNetEngine]], also see [[OpenSim.Region.ScriptEngine]]
  
Note: This page represents an implementation goal. Much of this already works, but some parts are not
+
:Note: This page represents an implementation goal. Much of this already works, but some parts are not implemented yet.
      implemented yet.
+
  
 
OpenSim supports scripting via script engines.
 
OpenSim supports scripting via script engines.
Line 15: Line 14:
  
 
== Changes (If you were running XEngine and it went back to DotNetEngine after r6420, read here) ==
 
== Changes (If you were running XEngine and it went back to DotNetEngine after r6420, read here) ==
Multiple script engines can now be active at once. The script_engine directive in OpenSim.ini is no longer used!
+
Multiple script engines can now be active at once. The script_engine directive in OpenSim.ini is no longer used!  
Instead, in the [Startup] section, you will now find
+
Instead, in the [Startup] section, you will now find
 +
<source lang="ini">
 +
DefaultScriptEngine = "ScriptEngine.DotNetEngine"
 +
</source>
 +
DotNetEngine is the default, to change it to XEngine, change the comments to activate the line
 +
<source lang="ini">
 +
DefaultScriptEngine = "XEngine"
 +
</source>
 +
Each engine can also be disabled by inserting
 +
<source lang="ini">
 +
Enabled = false
 +
</source>
 +
into its config section. These default to true for both engines.
 
   
 
   
DefaultScriptEngine = "ScriptEngine.DotNetEngine"
+
From this version on, OpenSim is able to run multiple script engines simultaneously. The default is the DotNetEngine.
 
   
 
   
DotNetEngine is the default, to change it to XEngine, change the comments to activate the line
+
If these new options are absent, DotNetEngine will operate.
+
DefaultScriptEngine = "XEngine"
+
+
Each engine can also be disabled by inserting
+
+
Enabled = false
+
+
into its config section. These default to true for both engines.
+
+
From this version on, OpenSim is able to run multiple script engines simultaneously.
+
The default is the DotNetEngine.
+
+
If these new options are absent, DotNetEngine will operate.
+
  
 
==Multiple script engine usage==
 
==Multiple script engine usage==
  
To run a script on a specific engine, begin the script with:
+
To run a script on a specific engine, begin the script with:
+
<source lang="lsl">
//XEngine: or //ScriptEngine.DotNetEngine:
+
//XEngine: or //ScriptEngine.DotNetEngine:
+
</source>
Optionally, this can be followed by a language code:
+
Optionally, this can be followed by a language code:
+
<source lang="lsl">
//XEngine:lsl
+
//XEngine:lsl
//ScriptEngine.DotNetEngine:c#
+
//ScriptEngine.DotNetEngine:c#
+
</source>
Beware: there is a little side effect. If you start your script with anything like
+
Beware: there is a little side effect. If you start your script with anything like
//any text you want:
+
<source lang="lsl">
(starting with "//" and ending with ":") you'll get an error
+
//any text you want:
  "Selected engine unavailable. Running script on XEngine"
+
</source>
 +
(starting with "//" and ending with ":") you'll get an error
 +
 
 +
''"Selected engine unavailable. Running script on XEngine"''
  
 
A script engine defines a way to load and run a script. It uses compilers and runtimes to accomplish this.
 
A script engine defines a way to load and run a script. It uses compilers and runtimes to accomplish this.
Line 65: Line 66:
 
The following describes the directory structure:
 
The following describes the directory structure:
  
ScriptEngines/DotNetEngine/                     The engine itself. Methods to manage threads, AppDomains, etc
+
{|style="margin-left:20px;"
ScriptEngines/XEngine/                           The engine itself. Methods to manage threads, AppDomains, etc
+
|ScriptEngines/DotNetEngine/||The engine itself. Methods to manage threads, AppDomains, etc
ScriptEngines/Interfaces/                       Common interfaces used to create script engines and components
+
|-
ScriptEngines/Shared/CodeTools/                 The currrent compiler
+
|ScriptEngines/XEngine/||The engine itself. Methods to manage threads, AppDomains, etc
ScriptEngines/Shared/Api/Interface/             The Api interfaces (see below)
+
|-
ScriptEngines/Shared/Api/Implementation/         The Api implementations (see below)
+
|ScriptEngines/Interfaces/||Common interfaces used to create script engines and components
ScriptEngines/Shared/Api/Runtime/               The Api runtimes (see below)
+
|-
ScriptEngines/Shared/Api/Runtime/YieldProlog/   The Yield Prolog runtime
+
|ScriptEngines/Shared/CodeTools/||The currrent compiler
 +
|-
 +
|ScriptEngines/Shared/Api/Interface/||The Api interfaces (see below)
 +
|-
 +
|ScriptEngines/Shared/Api/Implementation/||The Api implementations (see below)
 +
|-
 +
|ScriptEngines/Shared/Api/Runtime/||The Api runtimes (see below)
 +
|-
 +
|ScriptEngines/Shared/Api/Runtime/YieldProlog/||The Yield Prolog runtime
 +
|}
 +
 
  
 
An API is defined as an implementation, and interface and a runtime. The reason for this seemingly complicated approach has to do with scripts running in AppDomains apart from the normal OpenSim code.
 
An API is defined as an implementation, and interface and a runtime. The reason for this seemingly complicated approach has to do with scripts running in AppDomains apart from the normal OpenSim code.
Line 80: Line 91:
 
First, create your API implementation.
 
First, create your API implementation.
  
 +
<source lang="csharp">
 
  namespace OpenSim.Region.ScriptEngine.Shared.Api
 
  namespace OpenSim.Region.ScriptEngine.Shared.Api
 
  {
 
  {
Line 102: Line 114:
 
     }
 
     }
 
  }
 
  }
 +
</source>
  
 
Here, the class name (XXX_Api) is used by reflection, it must end in "_Api" to be recognized as an Api.
 
Here, the class name (XXX_Api) is used by reflection, it must end in "_Api" to be recognized as an Api.
Line 112: Line 125:
 
Next, create an interface to link the Api to the runtime:
 
Next, create an interface to link the Api to the runtime:
  
 +
<source lang="csharp">
 
  namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
 
  namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
 
  {
 
  {
Line 119: Line 133:
 
     }
 
     }
 
  }
 
  }
 +
</source>
  
 
Place this file in OpenSim/Region/ScriptEngines/Api/Interface, named IXXX_Api.
 
Place this file in OpenSim/Region/ScriptEngines/Api/Interface, named IXXX_Api.
Line 125: Line 140:
 
Now, the stub file is needed to connect the script to the Api. This stub file will be loaded into the script AppDomain, and should not contain any processing. It merely forwards the calls to the Api outside of the AppDomain.
 
Now, the stub file is needed to connect the script to the Api. This stub file will be loaded into the script AppDomain, and should not contain any processing. It merely forwards the calls to the Api outside of the AppDomain.
  
 +
<source lang="csharp">
 
  namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
 
  namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
 
  {
 
  {
Line 145: Line 161:
 
     }
 
     }
 
  }
 
  }
 +
</source>
  
 
Save this in OpenSim/Region/ScriptEngines/Shared/Api/Runtime, name it XXX_Stub.cs
 
Save this in OpenSim/Region/ScriptEngines/Shared/Api/Runtime, name it XXX_Stub.cs

Revision as of 03:53, 26 June 2011


Script Engines

This page deals with common parts of scripting and with XEngine. For DotNetEngine, also see OpenSim.Region.ScriptEngine

Note: This page represents an implementation goal. Much of this already works, but some parts are not implemented yet.

OpenSim supports scripting via script engines.

Script engines are normal region modules, but creating one as a shared module has not yet been tried.

Changes (If you were running XEngine and it went back to DotNetEngine after r6420, read here)

Multiple script engines can now be active at once. The script_engine directive in OpenSim.ini is no longer used! Instead, in the [Startup] section, you will now find

DefaultScriptEngine = "ScriptEngine.DotNetEngine"

DotNetEngine is the default, to change it to XEngine, change the comments to activate the line

DefaultScriptEngine = "XEngine"

Each engine can also be disabled by inserting

Enabled = false

into its config section. These default to true for both engines.

From this version on, OpenSim is able to run multiple script engines simultaneously. The default is the DotNetEngine.

If these new options are absent, DotNetEngine will operate.

Multiple script engine usage

To run a script on a specific engine, begin the script with:

//XEngine: or //ScriptEngine.DotNetEngine:

Optionally, this can be followed by a language code:

//XEngine:lsl
//ScriptEngine.DotNetEngine:c#

Beware: there is a little side effect. If you start your script with anything like

//any text you want:

(starting with "//" and ending with ":") you'll get an error

"Selected engine unavailable. Running script on XEngine"

A script engine defines a way to load and run a script. It uses compilers and runtimes to accomplish this.

Compilers take script text and convert it to a .NET assembly. Such an assembly needs to reference a runtime, which provides API stubs.

This calls out of the appdomain to the API implementation.

Currently, a compiler exists for lsl, c#, j# and vb. YieldProlog (yp) can be added to c# scripts.

A runtime exists for the LSL API and for the OSSL API. LSL_Status/Functions

The runtime and compiler are not dependent on each other, and also not dependent on the script engine.

The following describes the directory structure:

ScriptEngines/DotNetEngine/ The engine itself. Methods to manage threads, AppDomains, etc
ScriptEngines/XEngine/ The engine itself. Methods to manage threads, AppDomains, etc
ScriptEngines/Interfaces/ Common interfaces used to create script engines and components
ScriptEngines/Shared/CodeTools/ The currrent compiler
ScriptEngines/Shared/Api/Interface/ The Api interfaces (see below)
ScriptEngines/Shared/Api/Implementation/ The Api implementations (see below)
ScriptEngines/Shared/Api/Runtime/ The Api runtimes (see below)
ScriptEngines/Shared/Api/Runtime/YieldProlog/ The Yield Prolog runtime


An API is defined as an implementation, and interface and a runtime. The reason for this seemingly complicated approach has to do with scripts running in AppDomains apart from the normal OpenSim code.

Creating an API is pretty straightforward, but a few naming conventions must be observed for the Api to function correctly. The script runtime uses reflection to match Api runtimes to implementations, and it uses names to find these matches.

First, create your API implementation.

namespace OpenSim.Region.ScriptEngine.Shared.Api
 {
     public class XXX_Api: MarshalByRefObject, IXXX_Api, IScriptApi
     {
        internal IScriptEngine m_ScriptEngine;
        internal SceneObjectPart m_host;
        internal uint m_localID;
        internal LLUUID m_itemID;
 
        public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, LLUUID itemID)
        {
            m_ScriptEngine = ScriptEngine;
            m_host = host;
            m_localID = localID;
            m_itemID = itemID;
        }
 
        public void myApiFunction()
        {
        }
     }
 }

Here, the class name (XXX_Api) is used by reflection, it must end in "_Api" to be recognized as an Api.

Place the file in OpenSim/Region/ScriptEngines/Shared/Api/Implementaton/

By convention, it should be named XXX_Api.cs


Next, create an interface to link the Api to the runtime:

namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
 {
     public interface IXXX_Api
     {
         void myApiFunction();
     }
 }

Place this file in OpenSim/Region/ScriptEngines/Api/Interface, named IXXX_Api.


Now, the stub file is needed to connect the script to the Api. This stub file will be loaded into the script AppDomain, and should not contain any processing. It merely forwards the calls to the Api outside of the AppDomain.

namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
 {
     public partial class ScriptBaseClass : MarshalByRefObject
     {
         public IXXX_Api m_XXX_Functions;
 
         public void ApiTypeXXX(IScriptApi api)
         {
             if(!(api is IXXX_Api))
                 return;
 
             m_XXX_Functions = (IXXX_Api)api;
         }
 
         public void myApiFunction()
         {
             m_XXX_Functions.myApiFunction();
         }
     }
 }

Save this in OpenSim/Region/ScriptEngines/Shared/Api/Runtime, name it XXX_Stub.cs

Here, the ApiTypeXXX naming is the mandatory name, by which the script engine recognizes this Api and matches it up to the API implementation.

Please note that your Api here becomes a part of a partial class, which, in turn, becomes the base class of the script.

On script load, the Api runtime (stub) is called with a reference to the IScriptApi interface of the implementation. That, cast to the custom interface, is used to access the function implementations.

The reason we cannot directly reference the implementation is that that would cause the entire implementation to be loaded into the script's AppDomain. We need to avoid this to keep the memory footprint small.


The directory OpenSim/Region/ScriptEngines/Shared/CodeTools contains all compilers, converters and other code manipulation tools. It is shared between all script engines. Because of the shared compiler, the script engines can also share compiled assemblies, eliminating the need to recompile each script for each script engine.

Personal tools
General
About This Wiki