cocos 2 dxにおけるC++とluaのインタラクション

6338 ワード

最近、書き込み熱更新モジュールでは、C++呼び出しCRUL multiインタフェースがマルチスレッドダウンロード機能を実現し、lua呼び出しにリアルタイムのステータスクエリーインタフェースを提供することを目的としており、生産者消費者モデルを採用している.TOluaを使用してluaインタフェースを手動でエクスポートするときにいくつかの問題が発生し、ここに記録されます.
  luaとC++のインタラクションはluaのregistryテーブルを使用し、C/C++コードは自由に使用できるが、Luaコードは彼にアクセスできない.luaに登録するデータごとにregistryにメタテーブルを作成する.タイプ名はkey、メタテーブルはvalueである.
luaL_新metatable関数は、新しいテーブル(metatableとして使用される)を作成し、新しいテーブルをスタックの上部に配置し、テーブルとregistryのタイプ名の関連付けを確立します.この関連付けは双方向です.タイプ名をテーブルのkeyとして使用します.同時にテーブルをタイプ名として用いるkey(このような双方向の関連は、他の2つの関数の実現効率を向上させる).
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がnilでない場合は処理しないmoduleを作成します.
  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:  */
}

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