tolua++分析

9353 ワード

_RはLUA_を表すREGISTRYINDEX
C++に1つのモジュールを出力ステップ、例えばcc.Node
static void extendNode(lua_State* tolua_S)
{
    lua_pushstring(tolua_S,"cc.Node");
    lua_rawget(tolua_S,LUA_REGISTRYINDEX);
    if (lua_istable(tolua_S,-1))
    {
        lua_pushstring(tolua_S,"registerScriptHandler");
        lua_pushcfunction(tolua_S,tolua_cocos2d_Node_registerScriptHandler);
        lua_rawset(tolua_S,-3);
        lua_pushstring(tolua_S,"unregisterScriptHandler");
        lua_pushcfunction(tolua_S,tolua_cocos2d_Node_unregisterScriptHandler);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S,"scheduleUpdateWithPriorityLua");
        lua_pushcfunction(tolua_S,tolua_Cocos2d_Node_scheduleUpdateWithPriorityLua);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S,"unscheduleUpdate");
        lua_pushcfunction(tolua_S,tolua_cocos2d_Node_unscheduleUpdate);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S,"getPosition");
        lua_pushcfunction(tolua_S,tolua_cocos2d_Node_getPosition);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S, "setContentSize");
        lua_pushcfunction(tolua_S, tolua_cocos2d_Node_setContentSize);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S, "setAnchorPoint");
        lua_pushcfunction(tolua_S, tolua_cocos2d_Node_setAnchorPoint);
        lua_rawset(tolua_S, -3);
        lua_pushstring(tolua_S, "enumerateChildren");
        lua_pushcfunction(tolua_S, lua_cocos2dx_Node_enumerateChildren);
        lua_rawset(tolua_S, -3);
    }
    lua_pop(tolua_S, 1);
}

方向Rに関数を入れる
int lua_register_cocos2dx_Node(lua_State* tolua_S)
{ 
    tolua_usertype(tolua_S,"cc.Node");
    tolua_cclass(tolua_S,"Node","cc.Node","cc.Ref",nullptr);

    tolua_beginmodule(tolua_S,"Node");
        tolua_function(tolua_S,"addChild",lua_cocos2dx_Node_addChild);
        tolua_function(tolua_S,"removeComponent",lua_cocos2dx_Node_removeComponent);
        tolua_function(tolua_S,"setPhysicsBody",lua_cocos2dx_Node_setPhysicsBody);
        tolua_function(tolua_S,"getDescription",lua_cocos2dx_Node_getDescription);
        tolua_function(tolua_S,"setRotationSkewY",lua_cocos2dx_Node_setRotationSkewY);
        tolua_function(tolua_S,"setOpacityModifyRGB",lua_cocos2dx_Node_setOpacityModifyRGB);
        tolua_function(tolua_S,"setCascadeOpacityEnabled",lua_cocos2dx_Node_setCascadeOpacityEnabled);
        tolua_function(tolua_S,"getChildren",lua_cocos2dx_Node_getChildren);
        //....  
        tolua_function(tolua_S,"stopAction",lua_cocos2dx_Node_stopAction);
        tolua_function(tolua_S,"getActionManager",lua_cocos2dx_Node_getActionManager);
        tolua_function(tolua_S,"create", lua_cocos2dx_Node_create);
    tolua_endmodule(tolua_S);
    std::string typeName = typeid(cocos2d::Node).name();
    g_luaType[typeName] = "cc.Node";
    g_typeCast["Node"] = "cc.Node";
    return 1;
}

例:cc.Layer派生とcc.Node,cc.Node派生とcc.Ref
int lua_register_cocos2dx_Layer(lua_State* tolua_S)
{
    tolua_usertype(tolua_S,"cc.Layer");
    tolua_cclass(tolua_S,"Layer","cc.Layer","cc.Node",nullptr);

    tolua_beginmodule(tolua_S,"Layer");
        tolua_function(tolua_S,"create", lua_cocos2dx_Layer_create);
    tolua_endmodule(tolua_S);
    std::string typeName = typeid(cocos2d::Layer).name();
    g_luaType[typeName] = "cc.Layer";
    g_typeCast["Layer"] = "cc.Layer";
    return 1;
}
int lua_register_cocos2dx_Node(lua_State* tolua_S)
{ 
    tolua_usertype(tolua_S,"cc.Node");
    tolua_cclass(tolua_S,"Node","cc.Node","cc.Ref",nullptr);

    tolua_beginmodule(tolua_S,"Node");
        tolua_function(tolua_S,"addChild",lua_cocos2dx_Node_addChild);
        tolua_function(tolua_S,"removeComponent",lua_cocos2dx_Node_removeComponent);
        tolua_function(tolua_S,"setPhysicsBody",lua_cocos2dx_Node_setPhysicsBody);
        tolua_function(tolua_S,"getDescription",lua_cocos2dx_Node_getDescription);
        tolua_function(tolua_S,"setRotationSkewY",lua_cocos2dx_Node_setRotationSkewY);
        tolua_function(tolua_S,"setOpacityModifyRGB",lua_cocos2dx_Node_setOpacityModifyRGB);
        tolua_function(tolua_S,"setCascadeOpacityEnabled",lua_cocos2dx_Node_setCascadeOpacityEnabled);
        tolua_function(tolua_S,"getChildren",lua_cocos2dx_Node_getChildren);
        //....  
        tolua_function(tolua_S,"stopAction",lua_cocos2dx_Node_stopAction);
        tolua_function(tolua_S,"getActionManager",lua_cocos2dx_Node_getActionManager);
        tolua_function(tolua_S,"create", lua_cocos2dx_Node_create);
    tolua_endmodule(tolua_S);
    std::string typeName = typeid(cocos2d::Node).name();
    g_luaType[typeName] = "cc.Node";
    g_typeCast["Node"] = "cc.Node";
    return 1;
}

上のコードは主に以下の操作を行います.
cc.Layerのメタテーブルはccに設定.Node
cc.ノードのメタテーブルはccに設定.Ref
cc.Refのメタテーブルはtolua_に設定されていますcommonclass
ccを呼び出すとオブジェクトlayer:abc()などのLayer関数(layerはcc.Layerオブジェクト).Layerのメタテーブルはccになる.Layer
luaは先にccにいます.Layerでabc関数を検索し、cc.Node、最後はcc.Ref.
local A={
	__index = A,
	abc=function()
		print('abc')
	end
}
A.__index = A
local B={
	bbb=function()
		print('bbb')
	end
}
B.__index = B
local C=
{
	ccc=function()
		print('ccc')
	end
}
C.__index = C
local obj = {}

setmetatable(B,A)
setmetatable(C,B)
setmetatable(obj,C)
obj:ccc()
obj:bbb()
obj:abc()

tolua++の継承関係は上のコードと同じです.
最終的にtolua++は、次の問題を解決します.
1.既知のメタテーブルmtから取得したメタテーブル名_R[mt]
2.既に知られている呼称の元の表luaL_getmetatable(L,name)
3.既知メタテーブルの継承関係
_R["tolua_super"][mt] = { 
super1 = true,
super2 = true,
...,
}
4.一つのluaオブジェクトを知る、C++オブジェクトを取る.
luaオブジェクトがuserdataの場合、userdataを返し、テーブルの場合、テーブルのc_を返します.instance
tolua_を使用できますisusertypeは、tolua_などのオブジェクトが指定されたタイプであるかどうかを確認します.isusertype(tolua_S,1,"cc.Ref",0,&tolua_err)スタック1がccであるかどうかをチェックする.Refオブジェクト
cobj=(cococos 2 d::Ref*)tolua_tousertype(tolua_S,1,0);オブジェクトが取り出されます.
5.tolua.getpeer(target)が取るtargetの環境.に等しい場合R、nilに戻ります
tolua.setpeer(target,t)targetの環境を設定し、targetはuserdataである必要があります.
例:
function HomeWork.extend(target)     local t = tolua.getpeer(target)     if not t then         t = {}         tolua.setpeer(target, t)     end     setmetatable(t, HomeWork)     return target end
local layer = HomeWork.extend(cc.Layer:create())
1つの関数の呼び出し順序は、tテーブル(layerの環境テーブル)の中から、tのメタテーブルHomeWorkの中に、実はccである.Layer
6.luaオブジェクトのバインド
たとえば、シーンオブジェクトをluaオブジェクトとしてバインドする
 object_to_luaval<:scene>(tolua_S, "cc.Scene",(cocos2d::Scene*)scene);
template 
void object_to_luaval(lua_State* L,const char* type, T* ret)
{
    if(nullptr != ret)
    {
      
        cocos2d::Ref* dynObject = dynamic_cast(ret);

        if (nullptr != dynObject)
        {
            int ID = (int)(dynObject->_ID) ;
            int* luaID = &(dynObject->_luaID);
            toluafix_pushusertype_ccobject(L,ID, luaID, (void*)ret,type);
        }
        else
        {
            tolua_pushusertype(L,(void*)ret,getLuaTypeName(ret, type));
        }
    }
    else
    {
        lua_pushnil(L);
    }
}

7.オブジェクトの解放
オブジェクトはすべてRefから派生し、参照カウント管理を使用します.
~Refの実現は以下の通りである.
Ref::~Ref()
{
#if CC_ENABLE_SCRIPT_BINDING
    // if the object is referenced by Lua engine, remove it
    if (_luaID)
    {
        ScriptEngineManager::getInstance()->getScriptEngine()->removeScriptObjectByObject(this);
    }
    else
    {
        ScriptEngineProtocol* pEngine = ScriptEngineManager::getInstance()->getScriptEngine();
        if (pEngine != nullptr && pEngine->getScriptType() == kScriptTypeJavascript)
        {
            pEngine->removeScriptObjectByObject(this);
        }
    }
#endif


#if CC_USE_MEM_LEAK_DETECTION
    if (_referenceCount != 0)
        untrackRef(this);
#endif
}

最後にtoluafix_を呼び出すremove_ccobject_by_refid(_state, pObj->_luaID);およびvoid ScriptHandlerMgr::removeObjectAllHandlers(void*object)
8.tolua_ubox
9.オブジェクトの作成
使用法:分類子テーブルの作成
_R[mt] = class_name
int tolua_isusertype (lua_State* L, int lo, const char* type, int def, tolua_Error* err)
int lua_isusertype (lua_State* L, int lo, const char* type)
loはuserdataまたはtableでなければならない.(mtはloの元のテーブル)であり、loにはメタテーブルが必要である
もし_R[mt]==typeは、typeタイプのデータであることを示す.
または_R["tolua_super"][mt]は表STである、ST[type]がnilまたはfalseでない場合、loがtypeのサブクラスであることを示す例である.
static  int lua_isusertable (lua_State* L, int lo, const char* type)
もし_R[lo]==type、trueを返します
int tolua_fast_isa(lua_State *L, int mt_indexa, int mt_indexb, int super_index)
void tolua_pushusertype_internal (lua_State* L, void* value, const char* type, int addToRoot)
typeという名前の元のテーブルmtがある場合.
C = mt["tolua_ubox"] or _R["tolua_ubox"]
C[value]