2009-10-29 3 views
1

Не знаю, как спросить, так голые со мной пожалуйста :)Сохранить ссылку на UserData 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, и вы хотели бы передать ей аргумент userdata, который вы создали в C. Некоторое произвольное количество времени может проходить между вами при создании этих пользовательских данных и когда вам нужно их использовать. просто вставьте его в стек Lua, как только он будет создан. Точная? –

+0

и ваш вопрос? –

ответ

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

проблема с вашим решением заключается в том, что вы вызываете «callobject (test)» из Lua. Делая так, вы получаете все, что вам нужно, в стек Lua. Как сделать тот же звонок не от Lua? В основном, мой вопрос состоял в том, как передать этот «тестовый» объект не из Lua. – RolandasR

+0

Этот случай похож. Позвольте мне уточнить для вас ... – jsimmons

+0

Да, большое вам спасибо. – RolandasR

0

Если все, что вы хотите, чтобы вызвать функцию Lua `test.newMethod()« то я думаю, что вы хотите что-то порядка этого:

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

Я DON» t t hink вам нужно возиться с metatable или userdata.

Однако сила вашего вопроса не совсем ясно мне ...