|
Issue with calling Lua function from C/C++ |
Kevin Adrian
Member #7,087
April 2006
|
Hi, for my current Allegro project I want to use Lua as scripting language. But for the moment I have an issue with calling Lua functions in C/C++. It seems that the metatable of an object is overwritten or deprecated when a second object with a different metatable is used in the same script. I want to implement a Lua function 'update(m,h)' which is called from C/C++ in my project. This function will expect two light userdata objects of different types (this means two different metatables): Scenario 1) function update(m) print("[Lua] map-id: "..m:get_id()) -- this works end Scenario 2) function update(h) print("[Lua] hero name: "..h:name()) -- this works end Scenario 3) function update(m,h) print("[Lua] hero name: "..h:name()) -- this works print("[Lua] map-id: "..m:get_id()) -- this does not work anymore! m is available, but get_id() cannot be called. end On C/C++ side, this Lua function is called the following way: 1void __lua_update(lua_State* L,_HERO* h,MAP* m) {
2
3 lua_getglobal(L,"update");
4
5 // push map object
6 lua_pushlightuserdata(L,(void*) m);
7 luaL_getmetatable(L,"L_map");
8 lua_setmetatable(L,-2);
9
10 // push hero object
11 lua_pushlightuserdata(L,(void*) h);
12 luaL_getmetatable(L,"L_hero");
13 lua_setmetatable(L,-2);
14
15 lua_pcall(L,2,0,0);
16}
NOTE: Both metatables 'L_map' and 'L_hero' have been created in an earlier init phase. Does anybody have some advices how to solve this issue, so that both map and hero object can be accessed within the Lua script? Best regards My mouth will speak words of wisdom; the utterance from my heart will give understanding. (Psalm 49:3) |
Edgar Reynaldo
Major Reynaldo
May 2007
|
According to the docs, a table (like the one for update) can only have one metatable. So you're overwriting the metatable for your update function when you call setmetatable(L , -2) twice. Somehow you need to bind the metatable for each object to a separate object. Programming in LUA : 13 said: Each table in Lua may have its own metatable. (As we will see later, userdata also can have metatables.)
My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
bamccaig
Member #7,536
July 2006
|
I'm confused by what this __lua_update function is supposed to do. It doesn't seem to make sense to associate a metatable with a table during an "update" function. I've barely learned the basics of Lua and that was probably 8 years ago, but this C function appears to:
It sounds vaguely like it should work, assuming that you don't care about destroying any other "metatable" associated with these objects whenever you call this function... Presumably, if it's the same one there's no harm done if Edgar is right about overwriting (as opposed to chaining) them. It also sounds like a very strange pattern. If anything, if you were to do this kind of "hack", I'd expect you to restore the original metatables before returning... So tell me, how far off am I compared to your understanding? -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Polybios
Member #12,293
October 2010
|
Without looking at the code: Kevin Adrian said: This function will expect two light userdata objects of different types (this means two different metatables) IIRC, light userdata cannot even have individual metatables. Lua manual said: Userdata represent C values in Lua. A light userdata represents a pointer, a void*. It is a value (like a number): you do not create it, it has no individual metatable, and it is not collected (as it was never created). A light userdata is equal to "any" light userdata with the same C address. Maybe it would be better to use a full userdata object for storing your pointers. Your code looks fine to me, although I am a bit confused by your update variants. Generally, it could be a good idea to keep important Lua values in the registry using luaL_ref and luaL_unref. Pushing them again is quite fast, so you don't have to recreate the metatables on every update. Interfacing Lua can be a pain... A hack that I used once was to use light userdata values as index to a table with weak values. So the C++ pointers were the keys and full userdata with proper metatables set that referenced the same objects were the values. So I could push those by pointer. Not elegant, not very fast, but it worked... |
Kevin Adrian
Member #7,087
April 2006
|
Thanks a lot for your advices. I have not that much experience in Lua and binding to C/C++. I will check my code and rework it. My mouth will speak words of wisdom; the utterance from my heart will give understanding. (Psalm 49:3) |
|