Jump to content

Running a Lua file


Laurens
 Share

Recommended Posts

Hi,

 

I have decided to embrace Lua for the sake of getting a game done and stop fussing about proper architecture. To this end, I would like to have an executable similar to the engine-provided executable that just runs start.lua. With a twist. I would like to use CEGUI and I need to bootstrap it to Leadwerks in C++. No problems there, but how do I get Leadwerks to run start.lua similar to what the provided executable does? It seems the Lua API provides a dofile() method but this does not seem to be exposed to the engine.

 

Thanks!

Link to comment
Share on other sites

Basically you don't even need to call any Lua scripts. I noticed in my LEBuilder GameLib FPS template that all Lua entity scripts just run fine. So you can do you main loop with C++ and the entity scripts in Lua, that's the best way to do it.

Ryzen 9 RX 6800M ■ 16GB XF8 Windows 11 ■
Ultra ■ LE 2.53DWS 5.6  Reaper ■ C/C++ C# ■ Fortran 2008 ■ Story ■
■ Homepage: https://canardia.com ■

Link to comment
Share on other sites

I honestly wouldn't. I was/am big on "thingoids" because they are cool and easy for other people to plug and play, but coming up with the design and interactions between all these to make a complete game is more of the same of fussing about proper design and given his comment

I have decided to embrace Lua for the sake of getting a game done and stop fussing about proper architecture.
using the main Lua file is the best way to go. You can sub in entity scripts for certain things but if finishing a game is your main priority over coming up with a cool design, then don't fully rely on entity scripts as you'll get lost in design. I speak from my experience in this area. I was against the main Lua file and all for entity scripts because it was fun making those interactions, but to do it for every aspect of a game will eat up a ton of time and make you "hack" around things to get a game done. It's just easier to code in your main Lua file and supplement with the entity scripts.

 

I use my entity scripts like classes. Then I code most of my game in a C fashion in Lua and found I was able to produce something much faster and easier. Just my experience I speak of though.

Link to comment
Share on other sites

Thanks for the fast replies, that should work perfectly!

 

I use my entity scripts like classes. Then I code most of my game in a C fashion in Lua and found I was able to produce something much faster and easier. Just my experience I speak of though.

 

This is the route I intend to take as well, using the main Lua file. I just needed to setup CEGUI in C++. Otherwise CEGUI supports Lua as well so I hope I don't need to get back to C++ again.

Link to comment
Share on other sites

I found this method works great, but a warning from my experience. Test change you make in Lua often. The debugging in Lua is horrible. The errors you'll get sometimes will have nothing to do with what is actually wrong. I know this can happen in other languages but I've found it is worse in Lua (with LE at least). On average every function I add I'll test right away if possible because a missed end or messed up variable and you'll be hosed. I can't even imagine adding a big framework of code and then run it. In C++ I don't have an issue with doing that as I can fix the few errors I've made and recompile. In Lua doing such a thing could have your scratching your head for hours.

Link to comment
Share on other sites

  • 2 weeks later...

Note the last time I linked Lua with LE there were some naming conflicts because Josh used/exposed the same name of functions that Lua has. I remember this being a pain.

 

If what you are trying to do is use CEGUI from Lua, you can create a DLL that has all the CEGUI stuff and expose functions to be called from Lua, and even call functions from your DLL back to Lua. This is what I'm doing with RakNet and it's working well (now that I know he's using LuaJIT and not straight Lua). This might be really nice with a GUI as you could register the name of a Lua function to act as an event callback.

 

This is an example of the DLL I'm using.

 

#define LUA_API_EXP __declspec(dllexport)

#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include "BitStream.h"
#include "RakNetTypes.h"  // MessageID
#include <string>
#include <map>

#include <iostream>
#include <fstream>

using namespace std;

extern "C" 
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

// prevents the function name from being mangled
LUA_API_EXP int luaopen_raknet(lua_State *L);
}

RakNet::RakPeerInterface *peer = RakNet::RakPeerInterface::GetInstance();
RakNet::Packet *packet;
RakNet::SystemAddress serverAddress;

map<RakNet::MessageID, string> luaHandlers;

static int NetBindMessageEvent(lua_State* L)
{
int msgID = luaL_checknumber(L, 1);
const char* luaFunctionName = luaL_checkstring(L, 2);
string functionName = luaFunctionName;

// link the lua function name to this msg id
luaHandlers[msgID] = functionName;

return 0;
}

static const luaL_reg netLib[] =
{
{"Connect", NetConnect},
{"Update", NetUpdate},
{"BindMessageEvent", NetBindMessageEvent},
{"CreateBitStream", NetCreateBitStream},
{"Send", NetSend},
{"WriteBitStream", NetWriteBitStream},
{"ReadBitStream", NetReadBitStream},
{"Disconnect", NetDisconnect},
{NULL, NULL}
};

// lua calls this to open the library
LUA_API_EXP int luaopen_raknet (lua_State *L)
{
if(!log1)
{
	myfile.open ("RakNetLuaLog.txt", ios::out | ios::app);
	log1 = true;
}

WriteLog("Inside luaopen_raknet");

luaL_openlib(L, "raknet", netLib, 0);

return 1;
}

 

Then in Lua you do:

 

ID_CONNECTION_REQUEST_ACCEPTED = 16

-- Load RakNet package
package.loadlib("C:\\Leadwerks Engine SDK\\RakNetLua.dll", "luaopen_raknet")()

function ConnectionSuccess()
end

raknet.BindMessageEvent(ID_CONNECTION_REQUEST_ACCEPTED, "ConnectionSuccess")

 

 

I also expose an Update() function in the DLL and call that every frame from Lua. The Update method for me is looking for network packets and when it finds a packet that matches a message id I've registered calls the Lua function I associated with it. This should work with a GUI also. Can't remember what is all used with CEGUI to make it draw and collect input so not sure if this way would work or not.

Link to comment
Share on other sites

That's pretty sweet (and quite mind bending having never look like anything like it before) Rick.

 

If what you are trying to do is use CEGUI from Lua, you can create a DLL that has all the CEGUI stuff and expose functions to be called from Lua, and even call functions from your DLL back to Lua.

 

CEGUI has a built-in Lua interpreter so I can already do that, my main concern was calling a Lua script from C++ that is not an entity script. I want to do as little as possible in C++ unless it is absolutely required. The main loop would look like this:

 

while (!AppTerminate()) {
   UpdateFramework();

   // Run game.lua (facade for all game logic, written as Lua scripts as well. You can compare this with a game logic class' Update() method)

   RenderFramework();

   glPixelStoref(0x806E, 0); 
   glPixelStoref(GL_PACK_ROW_LENGTH, 0); 
   glPixelStoref(GL_UNPACK_ROW_LENGTH, 0); 
   CEGUI::System::getSingleton().renderGUI();

   Flip();
}

 

This way I can stricly contain game logic in Lua and keep everything else contained in the C++ binary which is a clean seperation that I like.

Link to comment
Share on other sites

So I have been trying to get this working for the past few hours. I have gotten to the point where I can build the application without compilation errors but I am getting one upon linking:

 

build/Debug/MinGW-Windows/_ext/1186093/Script.o:/src/Script.cpp:6: undefined reference to `luaL_loadfile(lua_State*, char const*)'

 

I am obviously missing some DLL. Did you have to compile LuaJIT and reference the resulting "lua51.dll" in your project?

Link to comment
Share on other sites

I compiled the source of LuaJIT into my project. LuaJIT I don't think has anything to do with normal lua so don't need the DLL. A linker error shouldn't have anything to do with a missing DLL though. If anything it would be missing lib, but if you compile LuaJIT source right into your project then there is no .lib file to reference.

 

I would assume LuaJIT has that function but not sure as I'm not using that function and not at home. Can you search the LuaJIT source to see if that function is in there?

Link to comment
Share on other sites

Hi Rick,

 

I'm flustered, no matter how I compile or reference LuaJIT in my project, it is not compiling any .lib. All I end up with is "lua51.dll" and "luajit.exe". There is nothing to link to. I have to assume that when you build your project, there has to be some kind of .lib to link to, even though VS copies it to the appropriate directories for you. Is there anything in your project's directory that slightly resembles the lib?

 

The function is in fact present in the source distribution, in "lauxlib.h" to be precise so that shouldn't be the problem.

Link to comment
Share on other sites

I actually included all the header and source files into my VS project. There was a thing where I had to copy and paste some dasm files in another folder to the rest of the header and source files to get that to compile. There also is an int main() in the Lua source that I had to find and commented out to make it compile. I didn't go the route of compiling LuaJIT into a lib and then using that lib in my project. It's small enough where I just compiled the source along with my project.

 

And yeah this stuff can get very frustrated. You don't know how angry I was that my RakNet Lua DLL was working with the lua.exe program but not LE before Josh mentioned that it's not normal Lua that LE uses it's LuaJIT. LuaJIT is just close enough to actual Lua where some stuff was working, some stuff had small differences, and some stuff didn't work at all.

Link to comment
Share on other sites

Well, don't I feel silly. After getting some help on the LuaHub forums I managed to get MinGW to compile the import library but it turns out the compiler is fine with linking against a DLL so I didn't need it. The root cause of the problem was incorrectly including the header:

 

#include "lauxlib.h"

 

should be

 

extern "C" {
#include "lauxlib.h"   
}

 

I was unaware of the fact you needed to include C code like that. Anyway, it is compiling and running now, sort of. At the point where I run the file, I get a

 

PANIC: unprotected error in call to Lua API (attempt to call a string value)

 

though, but at least I got it running using Leadwerks' Lua state.

Link to comment
Share on other sites

So I finally figured this thing out. I used the code I found here: http://cc.byexamples.com/2008/11/19/lua-stack-dump-for-c/ to debug the Lua stack at various points in the application. This is my final main loop:

 

   Script* s = new Script(reinterpret_cast<lua_State*> (GetLuaState()),
           "Scripts/Game/game.lua");
   while (!AppTerminate()) {
       UpdateFramework();
       s->Run(); // calls luaL_dofile
       RenderFramework();
       glPixelStoref(0x806E, 0);
       glPixelStoref(GL_PACK_ROW_LENGTH, 0);
       glPixelStoref(GL_UNPACK_ROW_LENGTH, 0);
       CEGUI::System::getSingleton().renderGUI();
       Flip();
   }
   delete s;

 

It turns out only the first call to to s->Run() failed, and all others were fine. Appearantly simply calling CreateFramework() does not complete the initialization. Upon calling RenderFramework() the engine loads more resources and all subsequent calls to s->Run() work fine. Perhaps the Lua state is not initialized up until the first call to RenderFramework()? Anyhow, it is working perfectly fine now.

 

Thanks for the help!

Link to comment
Share on other sites

Did you get CEGUI calling Lua functions? I know you mentioned CEGUI has that built in, which I was thinking about today. I assume that means CEGUI has Lua compiled into it. Be sure it's LuaJIT and not normal Lua or else the method calls would probably fail as the lua state variable between the 2 are slightly different.

Link to comment
Share on other sites

Hi Rick,

 

CEGUI can indeed call Lua functions but it does so in its own state. It has Lua 5.0.1 compiled into it and passing Leadwerks' Lua state as a parameter to the construction of the scripting module fails. Communication between CEGUI and Leadwerks is therefore not possible (so you can't call engine methods from the CEGUI state and vice versa) so next order of business is trying to recompile CEGUI and roll in LuaJIT as a replacement to "vanilla" Lua.

Link to comment
Share on other sites

I have spend the last two evenings trying to get CEGUI to compile, even without replacing the Lua implementations but slew of dependencies is hellish and I think I am going to give up on this one. I vaguely remember you having similar problems when you were trying to create a single DLL that contained all the dependencies for Leadwerks. In the spirit of moving forward I think am I going to hardcode the event handlers, which allows me to still define layouts in XML, just not the interactions.

Link to comment
Share on other sites

  • 1 month later...

So I finally figured this thing out. I used the code I found here: http://cc.byexamples.com/2008/11/19/lua-stack-dump-for-c/ to debug the Lua stack at various points in the application. This is my final main loop:

 

   Script* s = new Script(reinterpret_cast<lua_State*> (GetLuaState()),
           "Scripts/Game/game.lua");
   while (!AppTerminate()) {
       UpdateFramework();
       s->Run(); // calls luaL_dofile
       RenderFramework();
       glPixelStoref(0x806E, 0);
       glPixelStoref(GL_PACK_ROW_LENGTH, 0);
       glPixelStoref(GL_UNPACK_ROW_LENGTH, 0);
       CEGUI::System::getSingleton().renderGUI();
       Flip();
   }
   delete s;

 

It turns out only the first call to to s->Run() failed, and all others were fine. Appearantly simply calling CreateFramework() does not complete the initialization. Upon calling RenderFramework() the engine loads more resources and all subsequent calls to s->Run() work fine. Perhaps the Lua state is not initialized up until the first call to RenderFramework()? Anyhow, it is working perfectly fine now.

 

Thanks for the help!

 

 

Hi

 

now : Run is not a methode of Script why is removed in my version 2.5 ?

 

Thank

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...