2009-10-29 76 views
1

真的不知道怎麼問那麼裸請與我:)保存參考Lua的用戶數據

#1的Lua:

local test = Test(); 

#2 C:

//creating "lua's test" 
luaL_newmetatable(L, "someTable"); 
lua_userdata *userData = (lua_userdata *)lua_newuserdata(L, sizeof(lua_userdata)); 

luaL_getmetatable(L, "someTable"); 
lua_setmetatable(L, -2); 

#3的Lua :

function test.newMethod() 
end 

#4 C:

//this part is not executed from Lua 
//what i have to have here from #2 to call "test.newMethod" and how to call it? 
//if userdata would be on stack i guess i could: 
luaL_getmetafield (L, 1, "newMethod"); 
lua_call(L, 0, 0); 
//but because this part is not executed by Lua call its not on stack. 

編輯:

將試圖解釋在僞代碼更簡單:

的Lua:

local test = Object(); 

C:

int Object(){ 
    ... 
    somePointer = luaL_newmetatable(...); //how to get this "somePointer"? maybe luaL_ref? 
    push ... 
} 

的Lua:讓新的方法

function test.newMethod() 
    ... 
end 

在C一些事件(可以說定時器)觸發C法

void triggeredCMethod(){ 
    //here i need to call test.newMethod 
    //if i would have here 'somePointer' and could push it to Lua stack i could find and call newMethod 
} 

所以問題是:如何用C存儲指針一些Lua的對象(希望我需要的),由得到的Lua對象指針和調用方法,它

+0

讓我看看我是否有這個權利。你有一個在Lua中定義的函數,並且你想傳遞一個你在C中創建的userdata參數。在創建userdata和你需要使用它之間可能會傳遞一些任意的時間,所以你可以只要創建它就立即將它推到Lua堆棧上。準確? – 2009-10-29 22:21:24

+0

和你的問題是? – 2009-10-30 01:27:09

回答

5

我假設你希望能夠調用動態添加功能。這段代碼應該相對簡單地解釋它。注意我不做太多的錯誤檢查並做出一些假設,不要複製粘貼這個解決方案。

typedef struct 
{ 
    int number; 
    int reference; 
    lua_State *L; 
} TestUserdata; 

static int m_newindex(lua_State *L) 
{ 
    /* This is passed three values, first (at -3) is the object, bring this to the front */ 
    lua_getfenv(L, -3); 
    /* Now bring the second arg forward, the key */ 
    lua_pushvalue(L, -3); 
    /* And the third arg, the value */ 
    lua_pushvalue(L, -3); 
    /* And we're done */ 
    lua_rawset(L, -3); 

    return 0; 
} 

static int m_tostring(lua_State *L) 
{ 
    lua_pushstring(L, "TestUserdata"); 
    return 1; 
} 

static int callobject(lua_State *L) 
{ 
    /* Grab the object passed, check it's the right type */ 
    TestUserdata *data = luaL_checkudata(L, 1, "TestUserdata"); 

    /* Grab the function environment we gave it in createobject, and look in there for newmethod */ 
    lua_getfenv(L, -1); 
    lua_pushstring(L, "newmethod"); 
    lua_rawget(L, -2); 

    /* Call the function */ 
    lua_pushinteger(L, data->number); 
    lua_call(L, 1, 0); 

    return 0; 
} 

static const struct luaL_reg userdata_m[] = { 
    { "__newindex", m_newindex }, 
    { "__tostring", m_tostring }, 
    { NULL, NULL } 
}; 

int main (int argc, char *argv[]) 
{ 
    lua_State *L = luaL_newstate(); 
    luaL_openlibs(L); 

    /* Let's create us a userdatum metatable, and fill it up with goodies */ 
    luaL_newmetatable(L, "TestUserdata"); 
    /* Use luaL_register to fill up the metatable for us */ 
    luaL_register(L, NULL, userdata_m); 
    lua_pop(L, 1); /* Clean up the stack, we won't need the metatable left here */ 

    TestUserdata *data = lua_newuserdata(L, sizeof(TestUserdata)); 
    lua_pushvalue(L, -1); /* Copy for luaL_ref */ 
    int ref = luaL_ref(L, LUA_REGISTRYINDEX); 
    data->reference = ref; 
    data->number = 42; 
    data->L = L; 

    /* Load the metatable from before and 'give' it to this userdatum */ 
    luaL_getmetatable(L, "TestUserdata"); 
    lua_setmetatable(L, -2); 

    /* Give this object an empty function environment */ 
    lua_newtable(L); 
    lua_setfenv(L, -2); 

    lua_setglobal(L, "test"); 

    luaL_dostring(L, "function test.newmethod(num) print(num) end"); 

    /* Now provided we have the object, we can call any method defined anywhere */ 
    lua_rawgeti(data->L, LUA_REGISTRYINDEX, data->reference); 
    lua_getfenv(data->L, -1); 
    lua_pushstring(data->L, "newmethod"); 
    lua_rawget(data->L, -2); 
    lua_remove(data->L, -2); 

    if(lua_isfunction(data->L, -1) == 1) 
    { 
     lua_pushinteger(data->L, data->number); 

     lua_pcall(data->L, 1, 0, 0); 
    } 

    lua_close(L); 

    return 0; 
} 

檢查一下,我認爲這就是你要做的。

+0

你的解決方案的問題是你從Lua調用「callobject(test)」。這樣做你可以將所有需要的東西放到Lua堆棧中。 如何從Lua做同樣的調用?基本上我的問題是如何通過不是來自Lua的「測試」對象。 – RolandasR 2009-10-30 10:31:35

+0

這種情況類似。讓我爲你更新... – jsimmons 2009-10-30 11:23:44

+0

是的,非常感謝你。 – RolandasR 2009-10-31 08:50:36

0

如果你想要的是調用的Lua函數'test.newMethod()',那麼我想你想的這個量級上的東西:

lua_getglobal(L, "test"); 
lua_getfield(L, -1, "newMethod"); 
lua_call(L, 0, 0); 

我不t t嗨,你需要弄亂metatable或userdata。

但是你的問題的力是不完全清楚我...