Using properties from C# classes

Mar 22, 2011 at 3:21 PM

I have a set of C# classes with their properties and respective setters and getters, that I would like to use in Javascript. From the examples provided in the documentation I managed to declare the classes and implement the methods but I am having trouble with the properties declaration and the mapping with my C# get and set functions. Can anyone send me an example on how it is done?

Coordinator
Mar 23, 2011 at 7:44 AM

I've sent you an e-mail.

Apr 3, 2011 at 4:04 AM

Hi Paul,

I have a similar issue.

I'm trying to embed Jurasic into Unity3d (www.unity3d.com) as a "play time" game script engine.

(more http://forum.unity3d.com/threads/83456-Javascript-engine-inside-a-Unity-game-%28aka-user-programmable-games%29)

I managed to run scripts from inside a unity game, but I'm having trouble integrating C# and Javascript contexts. The main

problem is my classes need to inherit from a specific superclass.

Sorry to ask but, is there a easier way to access (read/write) a class from JS to C# and vice-versa?

 

Here is the approach I'm trying:

 

using Jurassic;
using Jurassic.Library;

public class BlockProxy : ObjectInstance
{
	int textureId = 0;
	int x = 0;
	int y = 0;
	int z = 0;
	
    public BlockProxy(ObjectInstance prototype) : base(prototype)
    {
		this.PopulateFunctions();
		
        //this.DefineProperty("textureId", new PropertyDescriptor(0, PropertyAttributes.Sealed), true);
        //this.DefineProperty("x", new PropertyDescriptor(0, PropertyAttributes.Sealed), true);
        //this.DefineProperty("y", new PropertyDescriptor(0, PropertyAttributes.Sealed), true);
        //this.DefineProperty("z", new PropertyDescriptor(0, PropertyAttributes.Sealed), true);
    }
	
	[JSFunction(Name = "setTextureId")]
	public void SetTextureId(int newValue)
	{
		textureId = newValue;
	}
	
	[JSFunction(Name = "getTextureId")]
	public int GetTextureId()
	{
		return textureId;
	}	

	[JSFunction(Name = "getX")]
	public int GetX()
	{
		return x;
	}
	
	[JSFunction(Name = "getY")]
	public int GetY()
	{
		return y;
	}
	
	[JSFunction(Name = "getZ")]
	public int GetZ()
	{
		return z;
	}
}



using Jurassic;
using Jurassic.Library;

public class BlockProxyConstructor : ClrFunction
{
    public BlockProxyConstructor(ScriptEngine engine)
        : base(engine.Function.InstancePrototype, "BlockProxy", new BlockProxy(engine.Object.InstancePrototype))
    {
    }
}

 

 

 

using UnityEngine;

public class CodeEngine : MonoBehaviour 
{
	public GameObject block;
	public Texture[] textures;
	
	static int count;
	static float t1;
	
	private BlockProxy blockProxy;
	
	private Jurassic.ScriptEngine engine;
	
	void Awake() 
	{
		engine = new Jurassic.ScriptEngine();
		BlockProxyConstructor bpConstructor = new BlockProxyConstructor(engine);
		blockProxy = (BlockProxy) bpConstructor.InstancePrototype;
		engine.SetGlobalValue("BlockProxy", bpConstructor);
	}
	
	void Start()
	{
		Execute("var bp = new BlockProxy(); bp.setTextureId(7);");
	}
	
	void OnGUI()
	{
		GUI.Label(new Rect(10, 20, 100, 50), "count="+count);
		GUI.Label(new Rect(10, 50, 100, 50), "t1="+t1);
	}
	
    public void Execute(string code)
    {
    	count++;
		float st = Time.realtimeSinceStartup;
				
		engine.Execute(code);
		
		block.renderer.material.mainTexture = textures[blockProxy.GetTextureId()];
		block.transform.position = new Vector3(blockProxy.GetX(), blockProxy.GetY(), blockProxy.GetZ());				

		t1 = Time.realtimeSinceStartup-st;
    }
}

 

I'd like to write something like  "blockProxy.setTextureId(7);" (JS) and that to change a specific blockProxy from C# context's.

Is that possible?

 

Apr 3, 2011 at 4:09 AM

Forgot to mention, the above code is throwing the following error:

 

MethodAccessException: Method `Jurassic.Library.ClrFunction:<.ctor>b__1 ()' is inaccessible from method `(wrapper dynamic-method) object:binder_for_Jurassic.Library.ClrFunction.<.ctor>b__1 (Jurassic.ScriptEngine,object,object[])'

System.Delegate.CreateDelegate (System.Type,object,System.Reflection.MethodInfo,bool) <IL 0x002c2, 0x00b2e>
System.Delegate.CreateDelegate (System.Type,System.Reflection.MethodInfo,bool) <IL 0x00004, 0x00032>
System.Delegate.CreateDelegate (System.Type,System.Reflection.MethodInfo) <IL 0x00003, 0x0002d>
System.Reflection.Emit.DynamicMethod.CreateDelegate (System.Type) <IL 0x0002c, 0x000ce>
Jurassic.Compiler.Binder.CreateDelegateCore (int) <IL 0x000d8, 0x002fe>
Jurassic.Compiler.Binder.CreateDelegate (int) <IL 0x0002f, 0x000fb>
Jurassic.Compiler.Binder.Call (Jurassic.ScriptEngine,object,object[]) <IL 0x00004, 0x00031>
Jurassic.Library.ClrFunction.ConstructLateBound (object[]) <IL 0x0002c, 0x000ec>
(wrapper dynamic-method) object.global_ (Jurassic.ScriptEngine,Jurassic.Compiler.Scope,object) <IL 0x000a4, 0x00364>
Jurassic.Compiler.GlobalMethodGenerator.Execute () <IL 0x00035, 0x000e8>
Jurassic.ScriptEngine.Execute (Jurassic.ScriptSource) <IL 0x00085, 0x001f3>
Jurassic.ScriptEngine.Execute (string) <IL 0x00007, 0x00057>
CodeEngine.Execute (string) (at Assets/Scripts/All Scenes/CodeEngine.cs:39)
CodeEngine.Start () (at Assets/Scripts/All Scenes/CodeEngine.cs:25)

Coordinator
Apr 3, 2011 at 10:46 AM

The interop features in the latest released version (v2.1) are not very good at the moment, as you've found out.  However, I have implemented something I call "seamless .NET interop" in the latest nightly release. This is designed to allow you to use regular .NET classes and call them from JavaScript (the current interop system is not designed for this at all).

For example:

private class TestInstance
{
  public int Value
  {
    get { return this.value; }
    set { this.value = value; }
  }

}

var
engine = new ScriptEngine();
engine.SetGlobalValue(
"TestClass", typeof(TestClass));
engine.Execute("var instance = new TestClass()");
engine.Execute("instance.Property = 6");
Console.WriteLine(engine.Evaluate("instance.Property")); // Prints "6".

As far as I can tell, this fits your needs pretty well. I haven't had time to test this very well, so I wonder if you could grab the latest source from CodePlex and try it? That would help me a lot :-)

Apr 3, 2011 at 7:46 PM
Edited Apr 4, 2011 at 11:18 PM

Thanks Paul, I will download it as soon as possible and give you feedback...

Apr 6, 2011 at 4:06 PM

Hi Paul,

I built a new dll from the latest code. But here is the issue: unity
has a security
sandbox similar to the flash player for its web player builds. One of
those restrictions
is no reflection operations in dlls, but you can do it in your own
code. I tested the
new dll and it doesn't work using the new approach above. I suppose there is
reflection involved to set/get the class properties etc, right?
A workaround would be to include jurassic's code as if it was a normal game
code (no dlls). But unity uses .net (mono) 3.5.
since I'm basically a Java guy and .net is new to me, is it hard for
me to adapt the
code to be .net 3.5 compatible? Is there any other alternative paths?

TIA,

Rod

Coordinator
Apr 7, 2011 at 9:36 AM

Jurassic works with .NET 3.5 but I have not tested with Mono so I don't know if it works there.  Jurassic also works inside a sandbox - but I have only tested in the silverlight sandbox - if unity has a more restrictive sandbox then it may not work.  Sorry!

Apr 7, 2011 at 4:29 PM

Hi,

The previous version I used (stable one) was working, since I compiled it to a .net 3.5 dll.

Jurassic´s source code uses .net 4 syntax, right? If so, how difficult would it be to a Java

guy to learn the differences between .net 3.5 and .net 4 and adapt it to .net 3.5 syntax?

This way I can use Jurassic´s source directly in a project, so reflection can be used.

 

TIA,

R.

Coordinator
Apr 7, 2011 at 11:49 PM

The main Jurassic DLL uses some .NET 4 syntax (from memory just optional parameters), but it compiles into a form that is compatible with .NET 3.5.  Removing all the optional parameters would be pretty tough - quite a few of the built-in library methods rely on them.  In some cases you could replace the optional parameters with overloads but this may not work in all cases.