It's hard to tell, but I think you have a pattern where each of your lua scripts defines a global function called "main", and you invoke that in each of them?
So, the issue right now is that (a) all your Lua code runs infinite busy loops, and (b) you have no way of signalling to your threads that they should stop processing, whether because you are shutting down the application or just restarting your scripts.
What you probably want to do is change paradigms. For each file that successfully loads as a Lua script, you want to create and register a Lua Module object to communicate with that script. The module is responsible for the lifetime of the Lua State. Lua code can register event listeners and callbacks and such with the Module which they live inside.
When your application generates an event (including the "run this code 30 times per second" event, or whatever), you iterate through all modules and raise the relevant event on them. The module wrapper translates the C++ event into a Lua function call, and calls the handler code inside their Lua module. You'll want to take care of threading concerns, and handle runaway Lua code, at this point.
This way, when you want to "reload" scripts, all you have to do is tell each Lua Module wrapper to scrap their current state and re-load it from file.
class LuaModule {
private:
std::string m_path;
lua_State *L;
void load();
void unload();
public:
LuaModule(std::string path);
LuaModule(LuaModule &&other);
~LuaModule();
void reload();
/* ok(); returns true if module is ready to use */
bool ok() const;
/* callGlobal(name); really simple example invoke, returns true if the method exists and completed without error */
bool callGlobal(const char *name);
};
void
LuaModule::load()
{
if( ok() ) {
// We are already loaded; we have to be unloaded first.
return;
}
if( m_path == "" ) {
// We can't be loaded, on purpose. See the move-constructor.
return;
}
// Compile the Lua source file in question.
lua_State* L = luaL_newstate();
int status = luaL_loadfile(L, m_path.c_str());
if( status == 0 ) {
// Link the libraries (which were not necessary to just parse the file).
luaL_openlibs(L);
getGlobalNamespace(L)
.beginClass<CPed>("cped")
.endClass() // закрыть регистрацию класса.
.beginClass<CVehicle>("CVehicle") // имя класса авто в lua.
.endClass() // закрыть регистрацию класса.
.addCFunction("findplayer", findplayer) // возвращает указатель игрока.
.addCFunction("sethealth", sethealth) // название функции в lua и c++. уст здоровье.
.addCFunction("setarmour", setarmour) // название функции в lua и c++. уст броню.
;
// Call the top-level block function, to initialize this module.
lua_pcall(L, 0, 0, 0);
} else {
// Error during loadfile; close the state.
lua_close(L);
L = nullptr;
}
}
void
LuaModule::unload()
{
if( ! ok() ) return;
lua_close(L);
L = nullptr;
}
LuaModule::LuaModule(std::string path)
: m_path(path), L(nullptr)
{
load();
}
LuaModule::LuaModule(LuaModule &&other)
: m_path(other.m_path), L(other.L)
{
// Detach the other from its LuaState, and empty its filename to make sure it can't be re-used.
other.L = nullptr;
other.m_path = "";
}
LuaModule::~LuaModule()
{
unload();
}
void
LuaModule::reload()
{
unload();
load();
}
bool
LuaModule::ok()
{
return L != nullptr;
}
bool
LuaModule::callGlobal(const char *name)
{
if( ! ok() ) {
// This LuaModule was not ready to be called.
return false;
}
lua_getglobal(L, name);
if( LUA_TFUNCTION != lua_type(L, -1) ) {
// Value was not a function; pop whatever it was and return false.
lua_pop(L, 1);
return false;
}
if( 0 != lua_pcall(L, 0, 0, 0) ) {
// Call failed with an error (now on-stack)
lua_pop(L, 1);
return false;
}
// State OK, method existed, and method exited without error.
return true;
}
// In your game's main loop somewhere...
switch(event.type) {
case PLAYER_DAMAGED:
broadcast("onPlayerDamaged");
break;
//...
}
//...
std::vector<LuaModule> allModules;
//...
void loadFile(std::string filename) {
LuaModule tmp(filename);
if( tmp.ok() ) {
allModules.push_back(std::move(tmp));
}
}
//...
void broadcast(const char* event) {
for(auto& module: allModules) {
module.callGlobal(event);
}
}
//...
///////////////////////////////////////////////////////////////////////
// player-invulnerable.lua
-- Find the player during script init
player = findplayer()
function onPlayerDamaged()
-- Make the player near-invulnerable by
-- resetting their health whenever harmed.
sethealth(player, 200)
setarmour(player, 250)
end
RIP GameDev.net: launched 2 unusably-broken forum engines in as many years, and now has ceased operating as a forum at all, happy to remain naught but an advertising platform with an attached social media presense, headed by a staff who by their own admission have no idea what their userbase wants or expects.Here's to the good times; shame they exist in the past.