Load client mods into memory before execution.
authorsfan5 <sfan5@live.de>
Fri, 8 Nov 2019 19:01:47 +0000 (20:01 +0100)
committersfan5 <sfan5@live.de>
Sat, 9 Nov 2019 15:08:38 +0000 (16:08 +0100)
Preperation for server-sent CSM which will eventually need this.

src/client/client.cpp
src/client/client.h
src/script/cpp_api/s_base.cpp
src/script/cpp_api/s_security.cpp

index caa3cc78cfbd5abdc9bd254df3b498e0a532e334..3190641cfa464e5d3fe57dbb75708309d84f18e9 100644 (file)
@@ -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<fs::DirListNode> 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;
 }
 
index e3c931837754eb0fba0b9b4a5824807321074d23..40ad4c064ae4bb7bb19b2183cde72f8b771bf5e2 100644 (file)
@@ -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<std::string, ModMetadata *> m_mod_storages;
        float m_mod_storage_save_timer = 10.0f;
        std::vector<ModSpec> m_mods;
+       StringMap m_mod_vfs;
 
        bool m_shutdown = false;
 
index caa335d769a67fce6743ddf4013af43918e5f4ec..1f40bb06ae9b711083620f64e7116cdcb8eb8fa2 100644 (file)
@@ -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) {
index fd68a2cb0b0b18217417d7554de95de467b809ab..b5abcfb5da8f5fa05a0056b70113f9e42b02faf0 100644 (file)
@@ -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<std::string>(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<std::string>(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);