So, I've created "interface class" with all static methods, which I want to expose to hscript
scripts. It looks like this:
package com.application.interfaces.Terrain;
import com.application.TerrainCore
class Terrain {
private static var terrain:TerrainCore;
public static function _init(inTerrain:TerrainCore):Void {
terrain = inTerrain;
}
public static function test(s:Int):Void {
terrain.test(s);
}
}
The problem is, that I need to set terrain
object somehow, but I don't want it to be exposed to scripts. I expose whole classes with
var interp = new Interp();
var module = Type.resolveClass("com.application.interfaces.Terrain");
interp.variables.set("Terrain", module)
The idea was to override method call
in hscript.Interp
so it doesn't execute any method named _init
, but I don't know how to do that. Original call
method looks like this:
function call( o : Dynamic, f : Dynamic, args : Array<Dynamic> ) : Dynamic {
return Reflect.callMethod(o,f,args);
}
Can you use a class instance of Terrain instead of using static members? Eg:
interp.variables.set("Terrain", new Terrain(new TerrainCore()));
Script users wont know if they are using static or instance methods as it will still be access via:
Terrain.test(123);
in script.
Another option (based on clemos), is to use rtti to work out what is allowed (instead of maintaining a list of it), eg:
Terrain._init(new TerrainCore());
_init is a private function now, so you need to @:allow
it from your calling class (see below), also, you need to annotate with @:rtti
so you can grab info about the functions at runtime, so Terrain now looks like:
@:rtti
class Terrain {
private static var terrain:TerrainCore;
@:allow(test.hscript.demo.Main)
private static function _init(inTerrain:TerrainCore):Void {
terrain = inTerrain;
}
public static function test(s:Int):Void {
terrain.test(s);
}
}
Finally, the script interp fcall
now honours whether a field is public or private, ie:
public override function fcall(o:Dynamic, f:String, args:Array<Dynamic>):Dynamic
var rtti = haxe.rtti.Rtti.getRtti(o);
for (field in rtti.statics) {
if (field.name == f && field.isPublic == false) {
error(EInvalidAccess(f));
}
}
return super.fcall(o, f, args);
}
Its worth noting that I used statics
rather than fields
for obvious reasons. Im also not sure what overhead this would cause with the loop and the rtti.