Skip to content

Commit

Permalink
Flag new Lua states to reload if created during cache reload
Browse files Browse the repository at this point in the history
Also some restructure/cleanup of the ElunaLoader class and functions
  • Loading branch information
Foereaper committed Jul 18, 2024
1 parent 8c6c47c commit 5b63bf5
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 41 deletions.
45 changes: 28 additions & 17 deletions ElunaLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,8 @@ void ElunaUpdateListener::handleFileAction(efsw::WatchID /*watchid*/, std::strin
}
#endif

ElunaLoader::ElunaLoader()
ElunaLoader::ElunaLoader() : _cacheState(SCRIPT_CACHE_NONE)
{
_cacheState = SCRIPT_CACHE_NONE;
#ifdef TRINITY
lua_scriptWatcher = -1;
#endif
Expand Down Expand Up @@ -113,27 +112,28 @@ void ElunaLoader::LoadScripts()
// set the cache state to loading
_cacheState = SCRIPT_CACHE_LOADING;

lua_folderpath = sElunaConfig->GetConfig(CONFIG_ELUNA_SCRIPT_PATH);
uint32 oldMSTime = ElunaUtil::GetCurrTime();

std::string lua_folderpath = sElunaConfig->GetConfig(CONFIG_ELUNA_SCRIPT_PATH);
const std::string& lua_path_extra = sElunaConfig->GetConfig(CONFIG_ELUNA_REQUIRE_PATH_EXTRA);
const std::string& lua_cpath_extra = sElunaConfig->GetConfig(CONFIG_ELUNA_REQUIRE_CPATH_EXTRA);

uint32 oldMSTime = ElunaUtil::GetCurrTime();
lua_scripts.clear();
lua_extensions.clear();
combined_scripts.clear();

#ifndef ELUNA_WINDOWS
if (lua_folderpath[0] == '~')
if (const char* home = getenv("HOME"))
lua_folderpath.replace(0, 1, home);
#endif

ELUNA_LOG_INFO("[Eluna]: Searching for scripts in `%s`", lua_folderpath.c_str());
lua_requirepath.clear();
lua_requirecpath.clear();

// open a new temporary Lua state to compile bytecode in
lua_State* L = luaL_newstate();
luaL_openlibs(L);

// clear all cache variables
lua_requirepath.clear();
lua_requirecpath.clear();

// read and compile all scripts
ReadFiles(L, lua_folderpath);

Expand All @@ -157,7 +157,6 @@ void ElunaLoader::LoadScripts()
if (!lua_requirecpath.empty())
lua_requirecpath.erase(lua_requirecpath.end() - 1);

ELUNA_LOG_INFO("[Eluna]: Loaded and precompiled %u scripts in %u ms", uint32(combined_scripts.size()), ElunaUtil::GetTimeDiff(oldMSTime));
requiredMaps.clear();
std::istringstream maps(sElunaConfig->GetConfig(CONFIG_ELUNA_ONLY_ON_MAPS));
while (maps.good())
Expand All @@ -175,6 +174,8 @@ void ElunaLoader::LoadScripts()
}
}

ELUNA_LOG_INFO("[Eluna]: Loaded and precompiled %u scripts in %u ms", uint32(lua_scripts.size()), ElunaUtil::GetTimeDiff(oldMSTime));

// set the cache state to ready
_cacheState = SCRIPT_CACHE_READY;
}
Expand All @@ -190,6 +191,8 @@ int ElunaLoader::LoadBytecodeChunk(lua_State* /*L*/, uint8* bytes, size_t len, B
// Finds lua script files from given path (including subdirectories) and pushes them to scripts
void ElunaLoader::ReadFiles(lua_State* L, std::string path)
{
std::string lua_folderpath = sElunaConfig->GetConfig(CONFIG_ELUNA_SCRIPT_PATH);

ELUNA_LOG_DEBUG("[Eluna]: ReadFiles from path `%s`", path.c_str());

fs::path someDir(path);
Expand Down Expand Up @@ -321,15 +324,18 @@ void ElunaLoader::ProcessScript(lua_State* L, std::string filename, const std::s
return;

if (extension)
lua_extensions.push_back(script);
_extensions.push_back(script);
else
lua_scripts.push_back(script);
_scripts.push_back(script);

ELUNA_LOG_DEBUG("[Eluna]: ProcessScript processed `%s` successfully", fullpath.c_str());
}

#ifdef TRINITY
void ElunaLoader::InitializeFileWatcher()
{
std::string lua_folderpath = sElunaConfig->GetConfig(CONFIG_ELUNA_SCRIPT_PATH);

lua_scriptWatcher = lua_fileWatcher.addWatch(lua_folderpath, &elunaUpdateListener, true);
if (lua_scriptWatcher >= 0)
{
Expand All @@ -353,10 +359,15 @@ static bool ScriptPathComparator(const LuaScript& first, const LuaScript& second

void ElunaLoader::CombineLists()
{
lua_extensions.sort(ScriptPathComparator);
lua_scripts.sort(ScriptPathComparator);
combined_scripts.insert(combined_scripts.end(), lua_extensions.begin(), lua_extensions.end());
combined_scripts.insert(combined_scripts.end(), lua_scripts.begin(), lua_scripts.end());
_extensions.sort(ScriptPathComparator);
_scripts.sort(ScriptPathComparator);

lua_scripts.clear();
lua_scripts.insert(lua_scripts.end(), _extensions.begin(), _extensions.end());
lua_scripts.insert(lua_scripts.end(), _scripts.begin(), _scripts.end());

_extensions.clear();
_scripts.clear();
}

bool ElunaLoader::ShouldMapLoadEluna(uint32 id)
Expand Down
36 changes: 20 additions & 16 deletions ElunaLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,37 +49,41 @@ class ElunaLoader
ElunaLoader& operator= (ElunaLoader const&) = delete;
ElunaLoader& operator= (ElunaLoader&&) = delete;
static ElunaLoader* instance();

void LoadScripts();
void ReloadScriptCache();
void ReadFiles(lua_State* L, std::string path);
void CombineLists();
void ProcessScript(lua_State* L, std::string filename, const std::string& fullpath, int32 mapId);
bool ShouldMapLoadEluna(uint32 mapId);
bool CompileScript(lua_State* L, LuaScript& script);
static int LoadBytecodeChunk(lua_State* L, uint8* bytes, size_t len, BytecodeBuffer* buffer);
void ReloadElunaForMap(int mapId);
uint8 GetCacheState() { return _cacheState; }

// Lua script folder path
std::string lua_folderpath;
// lua path variable for require() function
std::string lua_requirepath;
std::string lua_requirecpath;
const uint8 GetCacheState() const { return _cacheState; }
const std::vector<LuaScript>& GetLuaScripts() const { return lua_scripts; }
const std::string GetRequirePath() const { return lua_requirepath; }
const std::string GetRequireCPath() const { return lua_requirecpath; }

typedef std::list<LuaScript> ScriptList;
ScriptList lua_scripts;
ScriptList lua_extensions;
std::vector<LuaScript> combined_scripts;
std::list<uint32> requiredMaps;

#ifdef TRINITY
// efsw file watcher
void InitializeFileWatcher();
efsw::FileWatcher lua_fileWatcher;
efsw::WatchID lua_scriptWatcher;
#endif

private:
void ReloadScriptCache();
void ReadFiles(lua_State* L, std::string path);
void CombineLists();
void ProcessScript(lua_State* L, std::string filename, const std::string& fullpath, int32 mapId);
bool CompileScript(lua_State* L, LuaScript& script);
static int LoadBytecodeChunk(lua_State* L, uint8* bytes, size_t len, BytecodeBuffer* buffer);

protected:
std::atomic<uint8> _cacheState;
std::vector<LuaScript> lua_scripts;
std::string lua_requirepath;
std::string lua_requirecpath;
ScriptList _scripts;
ScriptList _extensions;
std::list<uint32> requiredMaps;
std::thread _reloadThread;
};

Expand Down
28 changes: 20 additions & 8 deletions LuaEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,12 @@ CreatureUniqueBindings(NULL)
{
OpenLua();
eventMgr = new EventMgr(this);
RunScripts();

// if the script cache is ready, run scripts, otherwise flag state for reload
if (sElunaLoader->GetCacheState() == SCRIPT_CACHE_READY)
RunScripts();
else
reload = true;
}

Eluna::~Eluna()
Expand Down Expand Up @@ -109,8 +114,11 @@ static int PrecompiledLoader(lua_State* L)
const char* modname = lua_tostring(L, 1);
if (modname == NULL)
return 0;
auto it = std::find_if(sElunaLoader->combined_scripts.begin(), sElunaLoader->combined_scripts.end(), [modname](const LuaScript& script) { return script.filename == modname; });
if (it == sElunaLoader->combined_scripts.end()) {

const std::vector<LuaScript>& scripts = sElunaLoader->GetLuaScripts();

auto it = std::find_if(scripts.begin(), scripts.end(), [modname](const LuaScript& script) { return script.filename == modname; });
if (it == scripts.end()) {
lua_pushfstring(L, "\n\tno precompiled script '%s' found", modname);
return 1;
}
Expand All @@ -137,16 +145,18 @@ void Eluna::OpenLua()
// open base lua libraries
luaL_openlibs(L);

// open additional lua libraries

// Register methods and functions
RegisterFunctions(this);

// get require paths
const std::string& requirepath = sElunaLoader->GetRequirePath();
const std::string& requirecpath = sElunaLoader->GetRequireCPath();

// Set lua require folder paths (scripts folder structure)
lua_getglobal(L, "package");
lua_pushstring(L, sElunaLoader->lua_requirepath.c_str());
lua_pushstring(L, requirepath.c_str());
lua_setfield(L, -2, "path");
lua_pushstring(L, sElunaLoader->lua_requirecpath.c_str());
lua_pushstring(L, requirecpath.c_str());
lua_setfield(L, -2, "cpath");
// Set package.loaders loader for precompiled scripts
lua_getfield(L, -1, "loaders");
Expand Down Expand Up @@ -255,7 +265,9 @@ void Eluna::RunScripts()
lua_getglobal(L, "require");
// Stack: require

for (auto it = sElunaLoader->combined_scripts.begin(); it != sElunaLoader->combined_scripts.end(); ++it)
const std::vector<LuaScript>& scripts = sElunaLoader->GetLuaScripts();

for (auto it = scripts.begin(); it != scripts.end(); ++it)
{
// if the Eluna state is in compatibility mode, it should load all scripts, including those tagged with a specific map ID
if (!GetCompatibilityMode())
Expand Down

0 comments on commit 5b63bf5

Please sign in to comment.