0

私はiOS5.xでゲームのLua(5.2)スクリプトを許可するライブラリに取り組んでいます。クラスを作成し、Luaから作成してアクセスできるように、バインディングを追加しました。Luaから呼び出されたC初期化メソッドを以下に示します。

static int newGeminiObject(lua_State *L){
    GeminiObject *go = [[GeminiObject alloc] initWithLuaState:L];

    GeminiObject **lgo = (GeminiObject **)lua_newuserdata(L, sizeof(GeminiObject *));
    *lgo = go;

    luaL_getmetatable(L, GEMINI_OBJECT_LUA_KEY);
    lua_setmetatable(L, -2);

    lua_newtable(L);
    lua_setuservalue(L, -2);

    NSLog(@"New GeminiObject created");

    // add this new object to the globall list of objects
    [[Gemini shared].geminiObjects addObject:go];

    return 1;

}

これにより、さまざまなメソッドへのアクセスを提供するために他の場所に設定されたメタテーブルが割り当てられます。さらに、スクリプトコードがオブジェクトに属性を割り当てることができるように、ユーザー値としてテーブルをアタッチします。

これらのオブジェクトはLuaスクリプトで問題なく作成できます。

require "gemini"
x = gemini.new()
x:addEventListener("touch", objectTouched)

ここで、objectTouchedは、タッチイベントを処理する他の場所で定義されたLuaメソッドです。ここでaddEventListenerそれをイベントにバインドしtouchます。

これらのオブジェクトは問題なく機能します。しかし、Cから作成しようとすると、問題が発生します。オブジェクトを作成することはできますが、それをグローバルに割り当ててからスクリプトで呼び出そうとすると失敗します。

次のCコードが実行されます

-(void) addRuntimeObject {
    GeminiObject *rt = [[GeminiObject alloc] initWithLuaState:L];
    GeminiObject **lruntime = (GeminiObject **)lua_newuserdata(L, sizeof(GeminiObject *));
    *lruntime = rt;

    // set the metatable - effectively declaring the type for this object
    luaL_getmetatable(L, GEMINI_OBJECT_LUA_KEY);
    lua_setmetatable(L, -2);

    // add a table to hold anything the user wants to add
    lua_newtable(L);
    lua_setuservalue(L, -2);

    // create an entry in the global table
    lua_setglobal(L, "Runtime");

    // empty the stack
    lua_pop(L, lua_gettop(L));
}

これにより、「Runtime」という名前のグローバルが定義されます。このようなスクリプトからこの変数にアクセスしようとしています

Runtime:addEventListener("enterFrame", enterFrame)

次のエラーが発生します。

attempt to index global 'Runtime' (a userdata value)

これはuserdata値ですが、Luaで直接作成する場合は問題にならないようです。メタテーブルバインディングは、メソッドとメタメソッドへのアクセスを提供します。繰り返しますが、これは、オブジェクトがCで作成されたときではなく、Luaから作成された場合に正常に機能します。

私がここで間違っていること、またはユーザーデータからグローバルを作成する正しい方法についてのアイデアはありますか?

編集

GEMINI_OBJECT_LUA_KEYに関する混乱に関する以下のコメントに基づいて、バインディングで実際に使用されているコードをリストすると思いました。

static const struct luaL_Reg geminiObjectLib_f [] = {
    {"new", newGeminiObject},
    {NULL, NULL}
};

static const struct luaL_Reg geminiObjectLib_m [] = {
    {"addEventListener", addEventListener},
    {"__gc", geminiObjectGC},
    {"__index", l_irc_index},
    {"__newindex", l_irc_newindex},
    {NULL, NULL}
};

int luaopen_geminiObjectLib (lua_State *L){
    // create the metatable and put it into the registry
    luaL_newmetatable(L, GEMINI_OBJECT_LUA_KEY);

    lua_pushvalue(L, -1); // duplicates the metatable


    luaL_setfuncs(L, geminiObjectLib_m, 0);

    // create a table/library to hold the functions
    luaL_newlib(L, geminiObjectLib_f);

    NSLog(@"gemini lib opened");

    return 1;
}

このコードは、のメソッドとメタメソッドを提供する関数のライブラリ(ここには表示されていません)を登録しますGeminiObjects。toを呼び出すとluaL_newmetatable、新しいメタテーブルが作成され、レジストリ内でキーに関連付けられますGEMINI_OBJECT_LUA_KEYGEMINI_OBJECT_LUA_KEYヘッダーで定義された一意の文字列です。 luaL_setfuncs実際に関数ポインタをメタテーブルに追加し、オブジェクトのメソッドとして使用できるようにします。

4

1 に答える 1

2

それでも興味がある人のために、Luaメーリングリストの親切な人たちから私の質問に対する答えを得ました。ここでの問題は、ライブラリバインディング関数luaopen_geminiObjectLibがへの呼び出しの前に呼び出されないことaddRuntimeObjectです。

iOSはダイナミックライブラリをサポートしていないため、Luaソースのpreloadedlibs配列にポインタを追加することでライブラリを静的に追加しました。linit.c残念ながら、この方法で追加されたライブラリrequire('libname')は、Luaスクリプトで実行されるまでロードされません。Luaスクリプトを実行する前にメソッドを呼び出していaddRuntimeObjectたため、ライブラリはまだロードされていませんでした。

解決策は、同じファイル内の配列luaopen_geminiObjectLibへのポインタを追加することです。これにより、Luaが起動したときに、スクリプトを必要とせずにライブラリがロードされます。loadedlibslinit.crequire

于 2012-04-10T23:34:43.577 に答える