C# scripting in OpenSim November 21, 2008
Posted by justincc in opensim, opensim-scripting, opensim-tech-basics.trackback
A month ago, I wrote a short article about how to add an OSSL (OpenSimulator Scripting Language) function to OpenSim. This assumed that you were writing a script using the Linden Scripting Language (LSL).
However, in principle LSL is not the only language that you can write scripts in for OpenSim. LSL scripts in OpenSim are actually translated into C# before being compiled and executed. Therefore, it’s possible to bypass LSL and instead write in C# directly (or in Visual Basic, Javascript or any language which has a .net compiler that can be added to OpenSim). Indeed, some OSSL functions (such as osParseJSON()) will not currently work in LSL at all – the data it returns cannot be easily stuffed into any LSL data type. Unfortunately, there is a
major caveat with allowing OpenSim to directly execute C# and other non-LSL scripts. We’ll cover this later on.
But first of all, how does one write and execute a C# script in OpenSim? The first step is to make sure that OpenSim is allowed to compile C#. In your OpenSim.ini file, you will need the entry
AllowedCompilers = lsl, cs
in either the [ScriptEngine.DotNetEngine] or [XEngine] sections depending on which script engine your using (or both, if you want to be sure).
Now that this is done, we can enter a C# script. Here is a very short example.
//c#
// justincc's short test script
string message = "Hello avatar!";
string xml = "<tag>ribbit</tag>";
public void default_event_state_entry()
{
llSay(0, message);
}
public void default_event_touch_start(
LSL_Types.LSLInteger total_number)
{
System.IO.StringReader sr
= new System.IO.StringReader(xml);
System.Xml.XmlTextReader reader
= new System.Xml.XmlTextReader(sr);
llSay(0, reader.ReadElementString("tag"));
}
You can copy and paste this into a normal Second Life script within OpenSim.
As you can see, the structure is quite different from that of an LSL script. The first line
//c#
is always required to tell OpenSim that the script should be compiled as a C# script. WIthout this, the LSL compiler would be used instead (unless you’ve changed the default compiler in OpenSim.ini).
In the subsequent lines you can see that we don’t have the ‘default’ state section that one would find in an LSL script. Instead, the functions that receive events need to have names in the format <state>_event_<event function>. For instance,
state_entry() in the default state an LSL script
becomes public void default_event_state_entry().
touch_start(integer total_number)
becomes default_event_touch_start(LSLType.LSLInteger total_number).
We need to use LSLType.LSLInteger instead of C#’s int since this is the method signature that the script engine expects).
There is a more complex example of a C# script that uses osParseJSON() here.
So what are the advantages of writing scripts directly in C#? The major one is that one gets can use the .NET APIs directly. We can’t use C#’s using directives in the script so they need to be accessed using their full names (e.g. System.IO.StringReader rather than StringReader). Among other things, this allows one to use much richer data types in C# that aren’t available in LSL, such as System.Collections.Generic.Dictionary. One could also do such things as parsing XML using .NET (or mono’s) bundled XML parsers, as shown in the example above.
However, this advantage also forms C# scripting’s current major weakness. At the moment, as well being able to use such helpful classes as System.Collections.Generic.Dictionary, it’s also possible to call methods such as System.File.IO.Delete(”path/to/really/important/system/file”). Mantis 2610 has some more details of why this is. Hopefully, this can be fixed at some stage, but at the moment I would have to recommend that you don’t enable C# scripting on a server unless you really, really, really trust everybody who has access to it.
Alternatively, one may also be able to prevent non-administrators from creating or editing scripts at all. I hope to write about this at a later date, though these OpenSim facilities are still very experimental.
AllowedCompilers = lsl,cs
doesn’t work in OpenSimulator Server 0.6.1.8108
I am getting error: “Primitive: Error compiling script:
The compiler for language “cs” is not in list of allowed compilers. Script will not be executed!”
@Robert – Perhaps you could post (if it’s small) or e-mail me your script and I can give it a quick try?
So where do we go from here? Is there any documentation eg. how to set a LSLType.LSLList variable in C#? Are all events named consistantly (eg default_event_sensor, default_event_link_message)?
Linda
@Linda – this is a problem, afaik there is no wiki documentation on this at the moment.
So how did you learn to use something like LSL_Types.LSLInteger?
Linda
Good question
As far as I remember, this was mainly from looking at some previous code examples such as Rob Smart’s osParseJSON() demonstration code at
http://robsmart.co.uk/2008/09/14/opensim-web-20-contribution/
In addition, I did some direct experimentation with OpenSim. There is a setting in OpenSim.ini which will save out the C# code of any script, which should be useful in working some stuff out. Also, you can use the knowledge that all compiled scripts have LSL_Stub.cs as a base class (and hence effectively just call classes and methods referenced there).
Thanks, I will look into that
Linda
I have been playing with this today.
I started by setting the flag in the DotNetEngine block of the ini file that writes out the C# that LSL is converted to before compiling:
WriteScriptSourceToDebugFile=true
Then each time you compile an LSL script a C# source is stored in your /bin/ScriptEngines folder.
Here is what NewScript looks like in that file:
using OpenSim.Region.ScriptEngine.Shared;
using System.Collections.Generic;
namespace SecondLife
{
public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass
{
public Script()
{
}
public void default_event_state_entry()
{
llSay(new LSL_Types.LSLInteger(0), new LSL_Types.LSLString(”Script running”));
}
}
}
Here is the eqivalent compilable C# New Script
//c#
public void default_event_state_entry()
{
llSay(0, “Script running”);
}
using the LSL types as shown in the generated code may be better – I am not the one to ask about that.
So how do you get c# scripts to work.
I am using Open Simulator 0.6.3.8730 and using JJ sample script I am getting the following error:
Primitive: Error compiling script:
Line (16,11): Error CS0234: The type or namespace name ‘Xml’ does not exist in the namespace ‘System’ (are you missing an assembly reference?)
Line (17,21): Error CS0234: The type or namespace name ‘Xml’ does not exist in the namespace ‘System’ (are you missing an assembly reference?)
Ini settings:-
DefaultScriptEngine = “ScriptEngine.DotNetEngine”
[ScriptEngine.DotNetEngine]
Enabled = true
DefaultCompileLanguage=cs
AllowedCompilers=lsl,cs
Furthermore…When I try the default LSL script i get
Primitive: Error compiling script:
Line (0,0): Error CS1619: Cannot create temporary file ‘c:\Program Files\OpenSim\ScriptEngines\77b62ee3-7997-4c3b-a0b0-db44ef29ce14′ — The directory name is invalid.
I have set the permissions on the OpenSim to full control.
I’m not sure what you mean by the JJ Sample script, Cliff.
Your other error on compiling the default LSL sounds like some kind of bug – you might want to check the wiki and our Mantis bug tracking system for similar issues and solutions.
Thanks for the reply Justin.
I was refering to the blog and code shown at
http://justincc.wordpress.com/2008/11/21/c-scripting-in-opensim/
I copied the c# sharp code from this blog and it produce the error shown in my previous note.
regarding lsl i was referring to the default script that is created when you created a new script.
Both of these scripts (lsl default and your c# script) are as supplied – no changes – so given this, what do the errors mean?
I must admit, I can’t explain the first error. If you’re copying the script verbatim (with
System.Xml.XmlTextReader reader
= new System.Xml.XmlTextReader(sr);
) then it shouldn’t come up with that error.
The second error sounds more like some kind of problem with your system rather than OpenSim itself. You might want to check that you can create the directory listed in the error manually.
Hello justincc,
First of all thank you very much for your helpful posts all around internet;)
I have spent the last few days trying to make this work on my OpenSim server with no success yet, hence I am writing this post.
I keep getting the same error:
Primitive: Error compiling script:
Line (16,11): Error CS0234: The type or namespace name ‘Xml’ does not exist in the namespace ‘System’ (are you missing an assembly reference?)
Line (17,21): Error CS0234: The type or namespace name ‘Xml’ does not exist in the namespace ‘System’ (are you missing an assembly reference?)
It is exactly the same with the second error reported by Cliff few posts earlier.
Tried with both XEngine and Dotnetengine, tweaked every possibly relative option but no luck. All .Net frameworks, SDK etc are installed, MS Visual Studio 2008 and Windows Standard Server 2008. I have some C# programming experience and even tried editing OpenSim source code (Compiler.cs and some other files) but no luck whatsoever.
I have reached a deadend, and I really need C# functionality in opensim scripts, mainly for database access. I know this may not be the perfect place to post this, but you are one of the few that may be aware of a solution to this problem.
Thank you very much in advance,
Desperate developer
Takis
@Takis – how curious. I’ll try to remember to give this a try myself tomorrow on the latest OpenSim code. You might also want to try opening an OpenSim bug report so that other developers are aware of this.
If I haven’t posted in the next few days here again feel free to give me a poke