jump to navigation

C# scripting in OpenSim November 21, 2008

Posted by justincc in opensim, opensim-scripting, opensim-tech-basics.
trackback

c-script-small2A 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.

Comments»

1. Robert - February 7, 2009

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!”

2. justincc - February 8, 2009

@Robert – Perhaps you could post (if it’s small) or e-mail me your script and I can give it a quick try?

3. Linda - March 15, 2009

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

4. justincc - March 15, 2009

@Linda – this is a problem, afaik there is no wiki documentation on this at the moment.

5. Linda - March 15, 2009

So how did you learn to use something like LSL_Types.LSLInteger? 🙂

Linda

6. justincc - March 16, 2009

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).

7. Linda - March 16, 2009

Thanks, I will look into that 🙂

Linda

8. Starky Rubble - March 27, 2009

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.

9. Cliff - April 8, 2009

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

10. Cliff - April 8, 2009

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.

11. justincc - April 9, 2009

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.

12. Cliff - April 13, 2009

Thanks for the reply Justin.

I was refering to the blog and code shown at

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?

13. justincc - April 16, 2009

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.

Takis - May 27, 2009

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

14. justincc - June 1, 2009

@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 🙂

15. PipVolta - September 9, 2009

hi, with regard to the Xml problem described above it seems to be a problem in the Mono compiler. If you put the code into monoDev and try to compile it you also get the Xml does not exist error message, even though you can put ‘using System.Xml;’ at the top, and the references block admits to the existence of System.Xml.
It seems that some libraries just arent available on Mono I guess.
Hope this helps
Pip

16. su - September 10, 2009

Hi justincc,
Do you know of any good C# scripting tutorial that we can use to code in Opensim?

17. justincc - September 10, 2009

@PipVolta : that’s very strange – my original testing of the scripts was done on Mono so everything should work fine there. It looks like I might need to go back and take a look.

@su: Unfortunately I don’t know of any good OpenSim C# scripting tutorial out there.

18. PipVolta - September 10, 2009

Hi justincc
I was testing with MonoDev 2.0 by the way. I am continuing to write scripts in C#, but have met another imponderable. Do you happen to know how to switch states – the statement ‘state newstate’ doesn’t have any very obvious equivalent in C# – presumably there is a function call of some sort? or do we have to do the complete C# event handler setup process?
Regards
Pip

19. su - September 11, 2009

I’m also getting the same error as Cliff and Takis. Strange that it recognizes System.IO, but cannot recognize System.XML. So anyone found the reason for this?
@justincc- is there any place where we can add additional assemblies to OpenSim .NET environment?

Rgds,
Su

20. su - September 11, 2009

Hi justincc,
I installed Opensim in my machine in standalone mode and set
AllowedCompilers = lsl,cs

I am also getting the same error that Robert got: “Primitive: Error compiling script:
The compiler for language “cs” is not in list of allowed compilers. Script will not be executed!”

I am using OpenSimulator Server 0.6.6.
Were you being able to figure out the reason for this?

Rgds,
Su

21. su - September 11, 2009

I was able to resolve the second error. problem there was with the Script Engine. In my case, when the script engine was “XEngine”, it did not work. Then I changed it to “ScriptEngine.DotNetEngine” and now the compiler detects C#. but the error with the compiler not being able to detect System.Xml is still there

22. su - September 16, 2009

i reported a bug to mantis (http://opensimulator.org/mantis/view.php?id=4137) and according to the response I got from Melanie, the allowed references are hardcoded into the compiler. But since it is working for you, does it mean that you can change the compiler settings to include the references needed?

23. justincc - September 16, 2009

@su – Hmm, thanks for the data, I’ll go back and give this a test when I can. It sounds a little strange to me.

24. justincc - September 22, 2009

@su – I just tried the script I have in the blogpost on the most uptodate OpenSim (97c18caa766e2dd72b152b78827ef554f2054f8c, 22nd Sept 2009) and it works fine (and this under XEngine). Are you using the full names of types (e.g. System.Xml.XmlTextReader rather than just XmlTextReader)? Unfortunately, C#’s normal using statements will not work with OpenSim’s C# ‘scripts’.

25. su - September 26, 2009

@justincc- yes i was using the full names. Sine my own code was not working, I just copy-pasted your example code. Is there anything else we have to add to your code?

26. justincc - September 28, 2009

@su – Not to my knowledge. But I’d be happy to take a look at your code if you e-mail me your OpenSim.ini and the exact text of what you’re trying to run.

27. Dimple - November 12, 2009

Justin/Su,

I am getting same System.XML error (Error CS0234: The type or namespace name ‘Xml’ does not exist in the namespace ‘System’ (are you missing an assembly reference?)
, it recognizes System.IO, but cannot recognize System.XML.

I am working on 0.6.7 opensim. Any ideas? Please Help!!!

Regards,
Dimple

28. justincc - November 13, 2009

@Dimple. I just spent a bit of time investigating this and found out that it works fine under Mono (on Linux) and only fails under .NET on Windows. I’m thinking of a more radical fix in the trunk line (possibly by allowing a full class to be used including using statements).

Unfortunately, in 0.6.7 things are a little more difficult since I don’t really want to start putting in arbitrary hardcoded references. If you’re desparate, in Compiler.cs in the OpenSim.Region.ScriptEngine.Shared.CodeTools project, you could try adding an extra reference in the CompileFromDotNetText() method. That is, where you see

parameters.ReferencedAssemblies.Add(Path.Combine(rootPath,
“OpenSim.Region.ScriptEngine.Shared.dll”));
parameters.ReferencedAssemblies.Add(Path.Combine(rootPath,
“OpenSim.Region.ScriptEngine.Shared.Api.Runtime.dll”));

you could try adding something like

parameters.ReferencedAssemblies.Add(“System.Xml.dll”);

though I couldn’t guarantee this will work. If you try it, I’d be interested in the feedback.

29. Dimple - November 14, 2009

Hey Justin,

It works!!! You add the reference and wallah ….

Thanks alot for your timely help!!!

Regards,
Dimple

30. Martin - June 28, 2010

Hi,

Is it really C# or a simulation of C#?
I mean: can I write any valid C# statement?

for example, can I call methods that are defined in a dll file?
can I write codes that are using inheritance? etc.

31. Martin - June 28, 2010

I wrote the following simple code and am keep receiving the “The given key was not present in the dictionary” error.

//c#

class myclass {
public int i;
}

public void default_event_state_entry()
{
llSay(0, “Hello avatar!”);
}

public void default_event_touch_start(
LSL_Types.LSLInteger total_number)
{
myclass m;
m.i = 3;
}

if I just comment the last line (where it says m.i = 3;), the code compiles successfully!

any idea?

32. Martin - June 28, 2010

well, the previous code had a real error. i had to instantiate the object “m”.
I inserted the following line and that problem resolved:
m = new myclass();

but still I think it is not really C#

I changed the definition of myclass to this:
class myclass {
public int i;
public void mymethod()
{
llSay(0, “hi”);
}
}

and I am getting error from the llSay line. it will be compiled if i just comment out the llSay line.
strange!

33. justincc - June 29, 2010

@Martin – You can’t write any valid C# statement because the entire script is being wrapped inside a C# class underneath the covers. That wrapping class contains methods for all the functions such as llSay().

This is why your second example won’t work – your inner class doesn’t have a direct reference to the llSay() method.

This is why C# scripting can only be used in contexts where scripting is restricted to very trusted parties, since you do have access to various system libraries.

34. Martin - June 29, 2010

Thanks for your response.
what about this:
can I write my classes and methods in a dll file and then use those classes in a script in opensim?

35. justincc - June 30, 2010

@Martin – You would need to be able to reference your dll from the script. I must admit, I’m not quite sure how this stuff is set up right now. I thought ReferencedAssemblies used to be added in the Compiler class of OpenSim.Region.ScriptEngine.Shared.CodeTools but this isn’t obviously the case. I haven’t tried to reference an external system dll before.

36. justincc - June 30, 2010

Ah, I see I actually gave that answer to @Dimple above, so adding ReferencedAssemblies would work, though I’m rather puzzled as to how System.Xml stuff is invokable. I thought that assemblies might also be coming from OpenSim.Region.ScriptEngine.Shared.CodeTools project entries but System.Xml isn’t there… Perhaps things have changed as we moved up versions of Mono (and .NET).

37. Martin - July 4, 2010

Do you know what I should do to be able to see a reasonable error text?
currently the only text that I see, no matter what the actual error is, is: “The given key was not present in the dictionary”

Do you know any active forum where non-lsl scripting issues can be discussed?

which scripting engine (ScriptEngine.DotNetEngine or XEngine) works better for C#?

Thanks for your patience and responses.

38. NeilC - July 7, 2010

@Martin – I have the same issue, are you using .NET (windows)as I am?

Previous posters seem to be getting error messages so I’m wondering if they were using mono. I’m not seeing any error in the console either despite DEBUG level logging. Justin – do you have any idea about this? Is it ‘mantis worthy’?

39. Martin - July 8, 2010

@NeilC – it is not related to mono.
I tested it under Linux using mono and also under windows.
in both cases, the only error message (for all errors) that I see is “The given key was not present in the dictionary”

it does not even say anything about the error line,

40. justincc - July 14, 2010

@Martin – If you want to put a small test script in a comment I can give it a go and see if I can see what’s happening. Unfortunately, there isn’t a dedicated forum for discussing this kind of scripting. You could try the opensim-users mailing list but as with all open-source mailing lists, there isn’t a guarantee of a response.

As for script engine, DotNetEngine is effectively deprecated now – I wouldn’t bother with it if I were you.

@NeilC – Again, it might be worth me having a look at the very simplest script that triggers this error first – it might be something simple.

Also, OpenSim has changed quite a bit since I originally wrote this blog post so it’s possible that something has got lost in terms of generating useful error data.

41. saL - July 18, 2010

@martin – have you had any success in accessing variables of inner classes?

general – if a script is wrapped into a class something like the below example *should* work, right? (but it doesn’t);

//c#
class myclass {
OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass clazz;

public myclass (OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass c) {clazz = c;}

public void mymethod(){
clazz.llSay(0, “hi”);
}
}

myclass m = new myclass(this);

public void default_event_state_entry(){
m.mymethod;
}

42. international moving companies - May 21, 2013

I am regular visitor, how are you everybody? This article posted at this website is genuinely pleasant.

43. YEngine and C# coding in OpenSim | Starflower Bracken's Blog - November 20, 2019

[…] to Justin Clark-Casey in November 2008 (no longer an OpenSim developer), it is dangerous to allow C# and VB.NET because some .NET classes […]


Leave a reply to justincc Cancel reply