cocos2dx中C++与lua交互

  最近在写热更新的模块,目的是C++调用CRUL multi接口实现多线程下载功能并提供实时的状态查询接口给lua调用,采用的是生产者消费者模型。在使用tolua手动导出lua接口的时候碰到了一些问题,并在此记录。

  lua与C++的交互是使用lua的registry表,C/C++代码可以自由使用,但Lua代码不能访问他.为每一个要注册到lua的数据,在registry创建一个元表.以类型名为key,元表为value.

luaL_newmetatable函数创建一个新表(将用作metatable),将新表放到栈顶并建立表和registry中类型名的联系。这个关联是双向的:使用类型名作为表的key;同时使用表作为类型名的key(这种双向的关联,使得其他的两个函数的实现效率更高).

lua调用过程实际上是lua调用C/C++在lua中注册的代理函数,代理函数调用相关的实际函数返回结果在lua栈中,lua再对返回值进行操作.

tolua API

  TOLUA_API void tolua_open (lua_State* L)

  一些tolua的全局table的创建.

  TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar)

  创建一个module,如果name的module不为nil,不做处理.

  TOLUA_API void tolua_beginmodule (lua_State* L, const char* name)

  将一个模块或者类入栈.

TOLUA_API void tolua_beginmodule (lua_State* L, const char* name)
{
    //在函数执行前 已经有一个module在lua栈上,这个module是_G
    //在bool LuaStack::init(void)函数调用luaL_register(_state, "_G", global_functions)时,
    //压入栈顶的.
    if (name) { // ... module
//---- now module[name] is a table, get it's metatable to store keys
        // get module[name]
        lua_pushstring(L,name); // ... module name
        lua_rawget(L,-2);       // ... module module[name]
        // Is module[name] a class table?
        lua_pushliteral(L, ".isclass");
        lua_rawget(L, -2);                  // stack: ... module module[name] class_flag
        if (lua_isnil(L, -1)) {
            lua_pop(L, 1);                  // stack: ... module module[name]
            return;                         // not a class table, use origin table
        }
        lua_pop(L, 1);                      // stack: ... module class_table
        // get metatable
        if (lua_getmetatable(L, -1)) {  // ... module class_table mt
            lua_remove(L, -2);          // ... module mt
        }
//---- by SunLightJuly, 2014.6.5
    } else {
        lua_pushvalue(L,LUA_GLOBALSINDEX);
    }
}

TOLUA_API void tolua_usertype (lua_State* L, const char* type)

  注册用户类型,在注册表中构建_R[type] 和 _R[const type]的元表.

static void mapsuper (lua_State* L, const char* name, const char* base)

设置name继承于base,将base的所有超类方法映射到name中(包含base的方法).

static void mapsuper (lua_State* L, const char* name, const char* base)
{
    /* push registry.super */
    //在_R[tolua_super]中获取name的元表,如果为nil则创建一个元表.
    lua_pushstring(L,"tolua_super");
    lua_rawget(L,LUA_REGISTRYINDEX);    /* stack: super */
    luaL_getmetatable(L,name);          /* stack: super mt */
    lua_rawget(L,-2);                   /* stack: super table */
    
    if (lua_isnil(L,-1))
    {
        /* create table */
        lua_pop(L,1);
        lua_newtable(L);                    /* stack: super table */
        luaL_getmetatable(L,name);          /* stack: super table mt */
        lua_pushvalue(L,-2);                /* stack: super table mt table */
        lua_rawset(L,-4);                   /* stack: super table */
    }

    /* set base as super class */
    //_R[tolua_super][name_mt]["base"] = true
    lua_pushstring(L,base);
    lua_pushboolean(L,1);
    lua_rawset(L,-3);                    /* stack: super table */

    /* set all super class of base as super class of name */
    //获取_R[base_mt]
    luaL_getmetatable(L,base);          /* stack: super table base_mt */
    lua_rawget(L,-3);                   /* stack: super table base_table */

    //迭代base_mt,映射所有方法到name_mt

    //lua_next()的工作过程是:
    //1 从栈顶弹出一个key
    //2 从栈指定位置的table里取下一对key-value, 先将key入栈再将value入栈
    //3 如果第2步成功则返回非0值,否则返回0.并不像栈中压入任何值
    if (lua_istable(L,-1))
    {
        /* traverse base table */
        lua_pushnil(L);  /* first key */
        while (lua_next(L,-2) != 0)
        {
            /* stack: ... base_table key value */
            lua_pushvalue(L,-2);    /* stack: ... base_table key value key */
            lua_insert(L,-2);       /* stack: ... base_table key key value */
            //这里栈顶的key是为了取下一对key-value使用,同上面的函数lua_pushnil的作用
            lua_rawset(L,-5);       /* stack: ... base_table key */
        }
    }
    lua_pop(L,3);                       /* stack: <empty> */
}

static void mapinheritance (lua_State* L, const char* name, const char* base)

设置name继承base,设置 name_mt[tolua_ubox] = base_mt[tolua_ubox],基类的tolua_ubox不存在 为子类的tolua_ubox创建一张关联value的weak表.

static void mapinheritance (lua_State* L, const char* name, const char* base)
{
    /* set metatable inheritance */
    luaL_getmetatable(L,name);

    if (base && *base)
        luaL_getmetatable(L,base);
    else {

        if (lua_getmetatable(L, -1)) { /* already has a mt, we don't overwrite it */
            lua_pop(L, 2);
            return;
        };
        luaL_getmetatable(L,"tolua_commonclass");
    };

    set_ubox(L);

    lua_setmetatable(L,-2);
    lua_pop(L,1);
}

导入示例:

	tolua_open(tolua_S);
    //此时栈中元素stack: ... module cc (此时module是_G)在
    //LuaStack::init(void)
    //luaL_register(_state, "_G", global_functions) 压入栈顶.
 	tolua_beginmodule(tolua_S,"cc");
		tolua_usertype(tolua_S,"cc.HotUpdate");
        //函数有使用module(_G),所以确保module存在
		tolua_cclass(tolua_S,"HotUpdate","cc.HotUpdate","cc.Ref",nullptr);
		tolua_beginmodule(tolua_S,"HotUpdate");
			tolua_function(tolua_S,"create", lua_cocos2dx_HotUpdate_create);
			tolua_function(tolua_S,"registerScriptHandler", lua_cocos2dx_HotUpdate_registerScriptHandler);
		tolua_endmodule(tolua_S);
		std::string typeName = "cocos2d::HotUpdate";//typeid(so::HotUpdate).name();
		g_luaType[typeName] = "cc.HotUpdate";
		g_typeCast["HotUpdate"] = "cc.HotUpdate";
	tolua_endmodule(tolua_S);

 测试示例:

    local hotUpdate = cc.HotUpdate:create("", "")
    print("type(HotUpdate) = ", type(HotUpdate));
    print("type(cc.HotUpdate) = ", type(cc.HotUpdate));
    print("type(hotUpdate) = ", type(hotUpdate))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值