ScriptEngines

From OpenSimulator

(Difference between revisions)
Jump to: navigation, search
(New page: == Script Engines == OpenSim supports scripting via script engines. Script engines are special region modules, which cannot be shared modules. A script engine defines a way to load and ...)
 
(Script Engines)
Line 11: Line 11:
 
This calls out of the appdomain to the API implementation.
 
This calls out of the appdomain to the API implementation.
  
Currently, a compiler exists for lsl, c#, j# and vb.
+
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.
+
A runtime exists for the LSL API and for the OSSL API.
  
 
The runtime and compiler are not dependent on each other, and also not dependent on the script engine.
 
The runtime and compiler are not dependent on each other, and also not dependent on the script engine.
  
A proposed structure coudl be like this:
+
The following describes the directory structure:
  
 
  ScriptEngines/DotNetEngine/                      The engine itself. Methods to manage threads, AppDomains, etc
 
  ScriptEngines/DotNetEngine/                      The engine itself. Methods to manage threads, AppDomains, etc
  ScriptEngines/Compilers/DotNet/                  The currrent compiler
+
  ScriptEngines/XEngine/                           The engine itself. Methods to manage threads, AppDomains, etc
  ScriptEngines/API/LSL/                           The current LSL API
+
ScriptEngines/Interfaces/                        Common interfaces used to create script engines and components
  ScriptEngines/API/LSL/Runtime                   The stub runtime
+
ScriptEngines/Shared/CodeTools/                  The currrent compiler
  ScriptEngines/API/LSL/Implementation            The acutual LSL API implementation
+
  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
  
The script engine would load the compiler, telling to to compile the given text from the source languages into a .NET assembly. referencing a certain API. The resulting assembly would be Script_compiled_<GUID>.dll. It would reference the API requested during compile, e.g. OpenSim.ScriptEngines.API.LSL.Runtime.dll. The scripot engine would load this assembly into an appdomain. The script engine loads OpenSim.ScriptEngines.API.LSL.Implementation.dll to execute the function calls from the script.
+
An API is defined as an implementation, and interface and a runtime. The reason for this seemingly conplicated approach has to do with scripts running in AppDomains apart from the normal OpenSim code.
  
Alternative script engines, like the XEngine, would be in
+
Creating an IP 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.
  
ScriptEngines/XEngine/
+
First, create your API implementation.
  
They would share the compiler collection, API runtimes and API implementations.
+
namespace OpenSim.Region.ScriptEngine.Shared.Api
 +
{
 +
    public class XXX_Api: MasrshalByRefObject, 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.

Revision as of 10:50, 22 June 2008

Script Engines

OpenSim supports scripting via script engines.

Script engines are special region modules, which cannot be shared modules.

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.

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 conplicated approach has to do with scripts running in AppDomains apart from the normal OpenSim code.

Creating an IP 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: MasrshalByRefObject, 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.

Personal tools
General
About This Wiki