Lua function issues

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Lua function issues

      I'm having some issues with my lua. I finally got it working, and I got it to make me some buttons on the screen, but I'm having issues getting the buttons to call a lua function when pressed.

      At the moment when the button is pressed I get an access violation error...
      First-chance exception at 0x10022d86 in FPS Game.exe: 0xC0000005: Access violation reading location 0x0000000c.
      Unhandled exception at 0x10022d86 in FPS Game.exe: 0xC0000005: Access violation reading location 0x0000000c.

      ...which triggers a breakpoint on this line in luafunction.h:

      Source Code

      1. LUAFUNCTION_POSTCALL(0);


      Here's the lua I wrote for this:

      Source Code

      1. function testfunction()
      2. EventManager:QueueEvent("DetachSceneEvent")
      3. end
      4. Scene =
      5. {
      6. { font = "Default", type = 0, text = "Button", tooltip = "I am a button!", x = 10, y = 10, width = 90, height = 40, callback = testfunction, centered = false },
      7. { type = 1, text = "I am some text!", x = 300, y = 10, centered = true, font = "Default" }
      8. }
      9. EventManager:QueueEvent("AttachSceneEvent", Scene)
      Display All

      The scene table just initializes the various scene elements. All I have implemented right now is a button and some text.

      The code seems to be able to load this fine. I get the buttons and text on the screen, so that doesn't seem to be an issue. However, the function won't work.

      Source Code

      1. callback = obj["callback"];

      obj is the particular element of the table I'm looking at currently, in this case the button.

      Source Code

      1. new LuaFunction<void>(callback)

      And here's where I make the actual function. It's passed into a class that holds onto it and the button's ID so that when the button is pressed the correct function is called, which seems to work just awesome.

      Source Code

      1. (*it->second->callback)();

      And here's where I actually call the function. it is the iterator for the map that holds all of the buttons in the current scene.

      Any help would be greatly appreciated.
    • The syntax of the callback is incorrect. What you want is this:

      Source Code

      1. // grab the function as a LuaObject
      2. LuaObject callback(obj["callback"]);
      3. // Always check to make sure it's actually a function or bad things can happen. Error checking here will
      4. // save you hair pulling later.
      5. if (callback.IsFunction())
      6. {
      7. // Instantiate a LuaFunction object. No need for new; we can statically allocate this (much faster).
      8. LuaFunction<void> func(callback);
      9. // Call the function. Note that we're calling the LuaFunction object, not the LuaObject instance.
      10. func();
      11. }
      12. else
      13. {
      14. // Silent failures make me sad, so kick out an error if something went wrong.
      15. assert(0 && "callback is not a valid function, or some other meaningful error");
      16. }
      Display All


      I'm not sure if the code below is just incomplete, but it appears that you call new to instantiate a LuaFunction object but you never assign it to anything. Then you attempt to use the function call operator on the LuaObject, which I would have assumed would generate a compiler error. Either way, it looks like it's dying trying to call the function.

      -Rez
    • Yes, the code is incomplete.

      Source Code

      1. new LuaFunction<void>(callback)


      This is sent into a function with the button itself, where it is stored in a class.

      Source Code

      1. AddGUIButton(button, new LuaFunction<void>(callback));


      Source Code

      1. IGUIElement* IGUIScene::AddGUIButton(IGUIButton* button, LuaFunction<void> *callback)
      2. {
      3. button->setID(curGUIID);
      4. GUIElements[curGUIID] = button;
      5. buttons[curGUIID++] = new ButtonData(button, callback);
      6. return button;
      7. }


      GUIElements is just a vector to hold any GUI elements, so they can be automatically destroyed when the scene is detached.
      buttons is a vector that holds all of my buttons, so that when they are clicked I can automatically send the callback to the right function.

      Oh, and the ".isfunction()" checks are in there, I just didn't put them in here.
    • Why not try something like this:

      Source Code

      1. // new prototype which takes a LuaObject reference instead of a LuaFunction pointer
      2. void AddGUIButton(IGUIButton* button, LuaObject& callback);
      3. // and here's the new call
      4. AddGUIButton(button, callback);
      5. // Nothing changes here, except that your ButtonData class will need to take a LuaObject.
      6. // It should probably take an instance instead of a reference in case the LuaObject you pass
      7. // in falls out of scope.
      8. IGUIElement* IGUIScene::AddGUIButton(IGUIButton* button, LuaObject& callback)
      9. {
      10. button->setID(curGUIID);
      11. GUIElements[curGUIID] = button;
      12. buttons[curGUIID++] = new ButtonData(button, callback);
      13. return button;
      14. }
      15. // Here's how you'd call it
      16. void ButtonData::InvokeCallback()
      17. {
      18. LuaFunction<void> func(m_callback);
      19. func();
      20. }
      Display All


      Speaking of which, the lua function testfunction() isn't going out of scope, is it? I'm assuming it's a global function? That would certainly cause bad things to happen. Incidentally, as long as you have a LuaObject instance pointing to it, it won't be garbage collected. Luaobject's maintain a strong reference to the object.

      -Rez
    • If a LuaObject goes out of scope after creating a LuaFunction, does the LuaFunction go bad?

      Also, is it OK to just copy a LuaObject? I tried making my ButtonData class simply hold the object itself, instead of pointers. It didn't work, but I just want to make sure that I'm not screwing with the managed memory.

      The original does go out of scope, so references/pointers to it wouldn't work out. That's why I originally went with a dynamically created LuaFunction.

      [Edit] Realized after posting that LuaObjects have a .clone, which I'm assuming I should use instead of just copying it. Didn't fix the issue, but probably a better idea.

      The post was edited 2 times, last by Nethara ().

    • Originally posted by Nethara
      If a LuaObject goes out of scope after creating a LuaFunction, does the LuaFunction go bad?

      I honestly don't know. The way I showed you above is how I've always done it. You could write up a quick test to see.


      Also, is it OK to just copy a LuaObject? I tried making my ButtonData class simply hold the object itself, instead of pointers. It didn't work, but I just want to make sure that I'm not screwing with the managed memory.

      Yes, passing-by-value and storing the value are perfectly valid operations. I do it all the time. Every time you have a LuaObject instance (not pointer or reference to an instance), it holds a strong reference to the actual Lua data. As long as that LuaObject instance exists, the lua garbage collector will never collect it.


      The original does go out of scope, so references/pointers to it wouldn't work out. That's why I originally went with a dynamically created LuaFunction.

      You mean the function on the Lua side? If it goes out of scope, you will definitely need to hold on to a LuaObject instance.


      [Edit] Realized after posting that LuaObjects have a .clone, which I'm assuming I should use instead of just copying it. Didn't fix the issue, but probably a better idea.

      Clone() is just for performing a deep clone of tables. It won't help you here.

      I've done exactly what you're proposing to do. My entity definitions are just tables in Lua that get sent into the engine side. I have a component attached to some entities called a ScriptComponent. One of the optional elements that table can have is a constructor function, which is passed to C++. When the C++ object is created, it calls the Lua construction function, passing in the Lua instance of the ScriptComponent.

      Can you post the full code? Maybe something will jump out at me.

      -Rez
    • I meant the original LuaObject instance, when I first got the scene data. The function itself is global.

      Source Code

      1. // Get the callback function and create the button.
      2. callback = obj["callback"];
      3. AddGUIButton(button, callback);
      4. IGUIElement* IGUIScene::AddGUIButton(IGUIButton* button, LuaObject &callback)
      5. {
      6. if(callback.IsFunction())
      7. {
      8. button->setID(curGUIID);
      9. GUIElements[curGUIID] = button;
      10. buttons[curGUIID++] = new ButtonData(button, callback);
      11. return button;
      12. }
      13. else
      14. {
      15. assert(0 && "Couldn't create button : callback isn't a function!");
      16. return NULL; // Just to impress the god forsaken compiler
      17. }
      18. }
      19. struct ButtonData
      20. {
      21. LuaObject callback;
      22. IGUIButton* button;
      23. ButtonData(IGUIButton* button, LuaObject &callback) : callback(callback), button(button) {}
      24. void InvokeCallback()
      25. {
      26. LuaFunction<void> func(callback);
      27. func();
      28. }
      29. };
      30. // The HumanView listens for the buttondown event and calls this in the scene.
      31. void IGUIScene::VOnButtonDown(int id)
      32. {
      33. ButtonMap::iterator it = buttons.find(id);
      34. if(it == buttons.end())
      35. return;
      36. it->second->InvokeCallback();
      37. }
      Display All


      And here's the lua part, just so you don't have to scroll up :)

      Source Code

      1. function testfunction ( )
      2. EventManager:QueueEvent("DetachSceneEvent")
      3. end
      4. Scene =
      5. {
      6. { font = "Default", type = 0, text = "Button", tooltip = "I am a button!", x = 10, y = 10, width = 90, height = 40, callback = testfunction, centered = false },
      7. { type = 1, text = "I am some text!", x = 300, y = 10, centered = true, font = "Default" }
      8. }
      9. EventManager:QueueEvent("AttachSceneEvent", Scene)
      Display All

      The post was edited 2 times, last by Nethara ().

    • Hmm, nothing jumps out at me here. In the InvokeCallback() function, print out the result of callback.TypeName(). It should be "function" or something like that. Also, instead of calling your function through LuaFunction, call it with DoString(). This should help narrow down the problem. If TypeName() returns "nil" or something else invalid, you know the issue is somewhere between your call to IsFunction() and the actual invocation. If DoString() works, you know the problem is with the LuaObject or LuaFunction and not your Lua code. If it doesn't, the problem is probably on the Lua side.

      -Rez
    • TypeName() gives me "function", and I can execute the functions by either putting the function call into the scripts or by using executestring.

      If it helps at all, it seems to crash on this line:

      Source Code

      1. if (lua_pcall(L, numArgs, 1, 0))

      It was in a #defined macro so I didn't really think about it before.

      The post was edited 1 time, last by Nethara ().

    • RE: Lua function issues

      Okay, so I fixed it but I have no clue how. [Edit] No I didn't...

      I got the src/ folder from luaplus.org and changed all of my includes to that. It then started giving me all of those linker errors that I was having when I started that thread a few weeks ago (if you were wondering, that got fixed by getting the library and includes from the book resources).

      So I swapped back to the book's src folder, got a linker error that I didn't have before (but was easy to fix and seemed unrelated), and it worked. I have no clue what's up, but it's fixed now.

      So, thanks for your help and patience.

      [Edit] Scratch what I said, it's not working anymore. I changed one line in a completely unrelated file and it stopped working. So I have no clue what the heck is up...

      The post was edited 2 times, last by Nethara ().

    • :-/

      If you're changing things in unrelated files, I wonder if there's some stale data in there somewhere. Have you done a clean build recently? If not, go to Build -> Clean Solution then compile. It'll recompile everything from scratch.

      At this point, I'm out of ideas. You don't seem to be doing anything unreasonable. If you want, zip up the whole solution (including GCC code and 3rd party stuff) and post it somewhere. I'll poke at it from here.

      -Rez
    • RE: Lua function issues

      A clean rebuild didn't help.

      I tried this:

      Source Code

      1. LuaFunction<void> funct(lua->GetLuaObject("Scene").GetByIndex(1).GetByName("callback"));
      2. funct();


      I stuck that right after I loaded the lua files, and that had the same issue. Maybe my luaplus files are bad?
    • Try something even simpler. Write a hello world function in lua:

      Source Code

      1. function HelloWorld()
      2. print("Hello World");
      3. end


      Then, right after that lua file is load, try running it with LuaState::DoString(). If that works, you should be able to run it with this:

      Source Code

      1. // assuming g_pLuaState holds the lua state object
      2. ScriptVar functionObj = g_pLuaState->GetGlobals().GetByName("HelloWorld");
      3. assert(functionObj.IsFunction());
      4. LuaFunction<void> func(functionObj);
      5. func(); // this should call your function


      If that works, the error is in your code somewhere. If it crashes in the same spot, the error is probably in LuaPlus. Assuming that's the case, try rebuilding LuaPlus from the source.

      By the way, what version of VS are you running?

      -Rez

      The post was edited 1 time, last by rezination ().

    • So the DoString() call worked but the LuaFunction stuff didn't?

      Then the only thing I can think of is that something in 2010 broke backwards compatibility with LuaPlus, which I believe was compiled in VS 2005. Your best bet is to try and rebuild the LuaPlus libs in 2010.

      -Rez
    • Yeah, I remember LuaPlus being a pain to build. Unfortunately, there's not much I can do to help unless you want to zip up all the code and send it to me. At this point, it looks like vs2010 is not happy with LuaPlus.

      -Rez
    • Well, do you have any suggestions as to alternatives to luaplus? I really like luaplus for it's simplicity, but at this point it just seems too big of a pain. So a shove in the direction of an alternative (doesn't necessarily need to be lua) would be greatly appreciated!

      Oh, and thanks for the help so far.
    • Well, LuaPlus has a lot in common with LuaBind. LuaBind requires boost (so does GCC) and it's suppose to better in a lot of different way. I'd check that out.

      -Rez
    • RE: Lua function issues

      So kind of straying off topic of the original post, but I tried implementing luabind into my project. After about 30 minutes to an hour worth of commenting out luaplus specific lines (just to get it working), I got to the point where the only issues are my unresolved externals!

      Source Code

      1. 1>Engine.lib(LuaStateManager.obj) : error LNK2001: unresolved external symbol "int __cdecl luabind::detail::implicit_cast(class luabind::detail::class_rep const *,class type_info const * const &,int &)" (?implicit_cast@detail@luabind@@YAHPBVclass_rep@12@ABQBVtype_info@@AAH@Z)
      2. 1>Engine.lib(LuaStateManager.obj) : error LNK2001: unresolved external symbol "class luabind::adl::object __cdecl luabind::detail::make_function_aux(struct lua_State *,int,class boost::function1<int,struct lua_State *> const &,class boost::function1<int,struct lua_State *> const &,class boost::function2<int,struct lua_State *,char const *> const &)" (?make_function_aux@detail@luabind@@YA?AVobject@adl@2@PAUlua_State@@HABV?$function1@HPAUlua_State@@@boost@@1ABV?$function2@HPAUlua_State@@PBD@7@@Z)
      3. 1>Engine.lib(LuaStateManager.obj) : error LNK2001: unresolved external symbol "public: void * __thiscall luabind::detail::class_rep::convert_to(class type_info const *,class luabind::detail::object_rep const *,struct luabind::detail::conversion_storage &)const " (?convert_to@class_rep@detail@luabind@@QBEPAXPBVtype_info@@PBVobject_rep@23@AAUconversion_storage@23@@Z)
      4. 1>Engine.lib(LuaStateManager.obj) : error LNK2001: unresolved external symbol "public: void __thiscall luabind::detail::class_base::init(class type_info const *,class type_info const *,class type_info const *,void * (__cdecl*)(void *),void const * (__cdecl*)(void *),void (__cdecl*)(void *,void *),void (__cdecl*)(void *,void *),void (__cdecl*)(void *,void *),void (__cdecl*)(void *),void (__cdecl*)(void *),void (__cdecl*)(void *),void (__cdecl*)(void *),void (__cdecl*)(void *),int,int)" (?init@class_base@detail@luabind@@QAEXPBVtype_info@@00P6APAXPAX@ZP6APBX1@ZP6AX11@Z44P6AX1@Z5555HH@Z)
      5. 1>Engine.lib(LuaStateManager.obj) : error LNK2001: unresolved external symbol "int __cdecl luabind::detail::ref(struct lua_State *)" (?ref@detail@luabind@@YAHPAUlua_State@@@Z)
      6. 1>Engine.lib(LuaStateManager.obj) : error LNK2001: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl luabind::detail::get_class_name(struct lua_State *,class type_info const *)" (?get_class_name@detail@luabind@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PAUlua_State@@PBVtype_info@@@Z)
      7. 1>Engine.lib(LuaStateManager.obj) : error LNK2001: unresolved external symbol "void __cdecl luabind::detail::unref(struct lua_State *,int)" (?unref@detail@luabind@@YAXPAUlua_State@@H@Z)

      I don't have a clue where these things would be defined. I'm linking in both lua51.lib and luabind.lib.