From 82a2e02323615473fc3039508b4c4529591e27d9 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 8 Nov 2019 20:01:47 +0100 Subject: [PATCH] Load client mods into memory before execution. Preperation for server-sent CSM which will eventually need this. --- src/client/client.cpp | 35 +++++++++++++++++++++---------- src/client/client.h | 4 ++-- src/script/cpp_api/s_base.cpp | 16 ++++++++------ src/script/cpp_api/s_security.cpp | 15 ++++++++----- 4 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/client/client.cpp b/src/client/client.cpp index caa3cc78c..3190641cf 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -200,14 +200,30 @@ void Client::scanModSubfolder(const std::string &mod_name, const std::string &mo std::string full_path = mod_path + DIR_DELIM + mod_subpath; std::vector mod = fs::GetDirListing(full_path); for (const fs::DirListNode &j : mod) { - std::string filename = j.name; if (j.dir) { - scanModSubfolder(mod_name, mod_path, mod_subpath - + filename + DIR_DELIM); + scanModSubfolder(mod_name, mod_path, mod_subpath + j.name + DIR_DELIM); continue; } - std::replace( mod_subpath.begin(), mod_subpath.end(), DIR_DELIM_CHAR, '/'); - m_mod_files[mod_name + ":" + mod_subpath + filename] = full_path + filename; + std::replace(mod_subpath.begin(), mod_subpath.end(), DIR_DELIM_CHAR, '/'); + + std::string real_path = full_path + j.name; + std::string vfs_path = mod_name + ":" + mod_subpath + j.name; + infostream << "Client::scanModSubfolder(): Loading \"" << real_path + << "\" as \"" << vfs_path << "\"." << std::endl; + + std::ifstream is(real_path, std::ios::binary | std::ios::ate); + if(!is.good()) { + errorstream << "Client::scanModSubfolder(): Can't read file \"" + << real_path << "\"." << std::endl; + continue; + } + auto size = is.tellg(); + std::string contents(size, '\0'); + is.seekg(0); + is.read(&contents[0], size); + + infostream << " size: " << size << " bytes" << std::endl; + m_mod_vfs.emplace(vfs_path, contents); } } @@ -1866,12 +1882,9 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename, bool cache) const std::string* Client::getModFile(const std::string &filename) { - StringMap::const_iterator it = m_mod_files.find(filename); - if (it == m_mod_files.end()) { - errorstream << "Client::getModFile(): File not found: \"" << filename - << "\"" << std::endl; - return NULL; - } + StringMap::const_iterator it = m_mod_vfs.find(filename); + if (it == m_mod_vfs.end()) + return nullptr; return &it->second; } diff --git a/src/client/client.h b/src/client/client.h index e3c931837..40ad4c064 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -576,8 +576,6 @@ private: // Storage for mesh data for creating multiple instances of the same mesh StringMap m_mesh_data; - StringMap m_mod_files; - // own state LocalClientState m_state; @@ -588,11 +586,13 @@ private: IntervalLimiter m_localdb_save_interval; u16 m_cache_save_interval; + // Client modding ClientScripting *m_script = nullptr; bool m_modding_enabled; std::unordered_map m_mod_storages; float m_mod_storage_save_timer = 10.0f; std::vector m_mods; + StringMap m_mod_vfs; bool m_shutdown = false; diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index caa335d76..1f40bb06a 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -197,18 +197,22 @@ void ScriptApiBase::loadModFromMemory(const std::string &mod_name) { ModNameStorer mod_name_storer(getStack(), mod_name); - const std::string *init_filename = getClient()->getModFile(mod_name + ":init.lua"); - const std::string display_filename = mod_name + ":init.lua"; - if(init_filename == NULL) - throw ModError("Mod:\"" + mod_name + "\" lacks init.lua"); + sanity_check(m_type == ScriptingType::Client); - verbosestream << "Loading and running script " << display_filename << std::endl; + const std::string init_filename = mod_name + ":init.lua"; + const std::string chunk_name = "@" + init_filename; + + const std::string *contents = getClient()->getModFile(init_filename); + if (!contents) + throw ModError("Mod \"" + mod_name + "\" lacks init.lua"); + + verbosestream << "Loading and running script " << chunk_name << std::endl; lua_State *L = getStack(); int error_handler = PUSH_ERROR_HANDLER(L); - bool ok = ScriptApiSecurity::safeLoadFile(L, init_filename->c_str(), display_filename.c_str()); + bool ok = ScriptApiSecurity::safeLoadString(L, *contents, chunk_name.c_str()); if (ok) ok = !lua_pcall(L, 0, 0, error_handler); if (!ok) { diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index fd68a2cb0..b5abcfb5d 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -627,16 +627,19 @@ int ScriptApiSecurity::sl_g_loadfile(lua_State *L) ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1); lua_pop(L, 1); + // Client implementation if (script->getType() == ScriptingType::Client) { - std::string display_path = readParam(L, 1); - const std::string *path = script->getClient()->getModFile(display_path); - if (!path) { - std::string error_msg = "Coudln't find script called:" + display_path; + std::string path = readParam(L, 1); + const std::string *contents = script->getClient()->getModFile(path); + if (!contents) { + std::string error_msg = "Coudln't find script called: " + path; lua_pushnil(L); lua_pushstring(L, error_msg.c_str()); return 2; } - if (!safeLoadFile(L, path->c_str(), display_path.c_str())) { + + std::string chunk_name = "@" + path; + if (!safeLoadString(L, *contents, chunk_name.c_str())) { lua_pushnil(L); lua_insert(L, -2); return 2; @@ -644,6 +647,8 @@ int ScriptApiSecurity::sl_g_loadfile(lua_State *L) return 1; } #endif + + // Server implementation const char *path = NULL; if (lua_isstring(L, 1)) { path = lua_tostring(L, 1);