Haxe / hscript - 防止将某些方法暴露给脚本

Haxe / hscript - Prevent exposing certain methods to scripts

所以,我创建了 "interface class" 和所有静态方法,我想将其公开给 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)

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

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

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

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

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

Terrain.test(123);

在脚本中。

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

Terrain._init(new TerrainCore());

_init 现在是一个私有函数,所以你需要从你的调用 class(见下文)中 @: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);
    }
}

最后,脚本 interp fcall 现在支持字段是 public 还是私有,即:

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 造成什么开销。

我认为您应该覆盖 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 );