2

因此,我创建了包含所有静态方法的“接口类”,我想将它们公开给hscript脚本。它看起来像这样:

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);
    }
}

问题是,我需要以terrain某种方式设置对象,但我不希望它暴露给脚本。我公开整个课程

var interp = new Interp();
var module = Type.resolveClass("com.application.interfaces.Terrain");
interp.variables.set("Terrain", module)

这个想法是覆盖方法callhscript.Interp所以它不执行任何名为的方法_init,但我不知道该怎么做。原始call方法如下所示:

function call( o : Dynamic, f : Dynamic, args : Array<Dynamic> ) : Dynamic {
    return Reflect.callMethod(o,f,args);
}
4

2 回答 2

2

您可以使用 Terrain 的类实例而不是使用静态成员吗​​?例如:

interp.variables.set("Terrain", new Terrain(new TerrainCore()));

脚本用户不会知道他们使用的是静态方法还是实例方法,因为它仍然可以通过以下方式访问:

Terrain.test(123);

在脚本中。

另一种选择(基于 clemos)是使用 rtti 来计算允许的内容(而不是维护它的列表),例如:

Terrain._init(new TerrainCore());

_init 现在是一个私有函数,因此您需要@:allow从调用类中获取它(见下文),此外,您需要使用注释,@:rtti以便在运行时获取有关函数的信息,因此 Terrain 现在看起来像:

@: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);
    }
}

最后,脚本 interpfcall现在尊重一个字段是公共的还是私有的,即:

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);
}

值得注意的是,我使用statics而不是fields出于明显的原因。我也不确定这会对循环和 rtti 造成什么开销。

于 2015-10-25T10:33:33.593 回答
2

我相信fcall你应该覆盖它,因为call它只用于顶级调用:

https://github.com/HaxeFoundation/hscript/blob/master/hscript/Interp.hx#L328-L331

f过滤参数应该很容易,例如:

if ( FORBIDDEN_FIELDS.indexOf( f ) > -1 ) throw EInvalidAccess( f );

或者

if ( f.indexOf('_') == 0 ) throw EInvalidAccess( f );
于 2015-10-25T10:33:48.030 回答