From 4e2970e34d20dde274efe3cd0e4aedcdb96d8ea5 Mon Sep 17 00:00:00 2001 From: Desour Date: Fri, 21 Feb 2025 12:19:04 +0100 Subject: [PATCH] mod_vfs stuff from TurkeyMcMac's PR Co-authored-by: Jude Melton-Houghton --- src/client/CMakeLists.txt | 1 + src/client/client.cpp | 53 +++--------------------- src/client/client.h | 13 ++---- src/client/mod_vfs.cpp | 56 ++++++++++++++++++++++++++ src/client/mod_vfs.h | 23 +++++++++++ src/script/cpp_api/s_base.cpp | 19 +++++++-- src/script/cpp_api/s_base.h | 2 + src/script/cpp_api/s_security.cpp | 3 +- src/script/sscsm/sscsm_environment.cpp | 12 ++++-- src/script/sscsm/sscsm_environment.h | 4 +- 10 files changed, 119 insertions(+), 67 deletions(-) create mode 100644 src/client/mod_vfs.cpp create mode 100644 src/client/mod_vfs.h diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index b11e6ee6f..4de58efb5 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -73,6 +73,7 @@ set(client_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/texturesource.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imagesource.cpp ${CMAKE_CURRENT_SOURCE_DIR}/wieldmesh.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/mod_vfs.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shadows/dynamicshadows.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shadows/dynamicshadowsrender.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shadows/shadowsshadercallbacks.cpp diff --git a/src/client/client.cpp b/src/client/client.cpp index f24aeb2c3..04f62efe9 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -10,6 +10,7 @@ #include #include "client.h" #include "client/fontengine.h" +#include "client/mod_vfs.h" #include "network/clientopcodes.h" #include "network/connection.h" #include "network/networkpacket.h" @@ -223,12 +224,14 @@ void Client::loadMods() return; } + m_mod_vfs = std::make_unique(); + m_script = new ClientScripting(this); m_env.setScript(m_script); m_script->setEnv(&m_env); // Load builtin - scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath()); + m_mod_vfs->scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath()); m_script->loadModFromMemory(BUILTIN_MOD_NAME); m_script->checkSetByBuiltin(); @@ -264,7 +267,7 @@ void Client::loadMods() // Load "mod" scripts for (const ModSpec &mod : m_mods) { mod.checkAndLog(); - scanModIntoMemory(mod.name, mod.path); + m_mod_vfs->scanModIntoMemory(mod.name, mod.path); } // Run them @@ -286,35 +289,6 @@ void Client::loadMods() m_script->on_minimap_ready(m_minimap); } -void Client::scanModSubfolder(const std::string &mod_name, const std::string &mod_path, - std::string mod_subpath) -{ - std::string full_path = mod_path + DIR_DELIM + mod_subpath; - std::vector mod = fs::GetDirListing(full_path); - for (const fs::DirListNode &j : mod) { - if (j.name[0] == '.') - continue; - - if (j.dir) { - scanModSubfolder(mod_name, mod_path, mod_subpath + j.name + DIR_DELIM); - continue; - } - 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::string contents; - if (!fs::ReadFile(real_path, contents, true)) { - continue; - } - - m_mod_vfs.emplace(vfs_path, contents); - } -} - const std::string &Client::getBuiltinLuaPath() { static const std::string builtin_dir = porting::path_share + DIR_DELIM + "builtin"; @@ -2083,23 +2057,6 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename, bool cache) return mesh; } -const std::string* Client::getModFile(std::string filename) -{ - // strip dir delimiter from beginning of path - auto pos = filename.find_first_of(':'); - if (pos == std::string::npos) - return nullptr; - pos++; - auto pos2 = filename.find_first_not_of('/', pos); - if (pos2 > pos) - filename.erase(pos, pos2 - pos); - - StringMap::const_iterator it = m_mod_vfs.find(filename); - if (it == m_mod_vfs.end()) - return nullptr; - return &it->second; -} - /* * Mod channels */ diff --git a/src/client/client.h b/src/client/client.h index 2f6b44cdb..248427e28 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -58,6 +58,7 @@ struct PointedThing; struct ItemVisualsManager; class ClientScripting; class SSCSMController; +struct ModVFS; namespace con { class IConnection; @@ -126,14 +127,6 @@ public: ~Client(); DISABLE_CLASS_COPY(Client); - // Load local mods into memory - void scanModSubfolder(const std::string &mod_name, const std::string &mod_path, - std::string mod_subpath); - inline void scanModIntoMemory(const std::string &mod_name, const std::string &mod_path) - { - scanModSubfolder(mod_name, mod_path, ""); - } - /* request all threads managed by client to be stopped */ @@ -382,7 +375,7 @@ public: bool checkLocalPrivilege(const std::string &priv) { return checkPrivilege(priv); } virtual scene::IAnimatedMesh* getMesh(const std::string &filename, bool cache = false); - const std::string* getModFile(std::string filename); + ModVFS *getModVFS() { return m_mod_vfs.get(); } ModStorageDatabase *getModStorageDatabase() override { return m_mod_storage_database; } ItemVisualsManager *getItemVisualsManager() { return m_item_visuals_manager; } @@ -583,7 +576,7 @@ private: ModStorageDatabase *m_mod_storage_database = nullptr; float m_mod_storage_save_timer = 10.0f; std::vector m_mods; - StringMap m_mod_vfs; + std::unique_ptr m_mod_vfs; // SSCSM std::unique_ptr m_sscsm_controller; diff --git a/src/client/mod_vfs.cpp b/src/client/mod_vfs.cpp new file mode 100644 index 000000000..391beb4ea --- /dev/null +++ b/src/client/mod_vfs.cpp @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2025 Luanti authors +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "mod_vfs.h" +#include "filesys.h" +#include "log.h" +#include + +void ModVFS::scanModSubfolder(const std::string &mod_name, const std::string &mod_path, + std::string mod_subpath) +{ + std::string full_path = mod_path + DIR_DELIM + mod_subpath; + std::vector mod = fs::GetDirListing(full_path); + for (const fs::DirListNode &j : mod) { + if (j.name[0] == '.') + continue; + + if (j.dir) { + scanModSubfolder(mod_name, mod_path, mod_subpath + j.name + DIR_DELIM); + continue; + } + 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 << "ModVFS::scanModSubfolder(): Loading \"" << real_path + << "\" as \"" << vfs_path << "\"." << std::endl; + + std::string contents; + if (!fs::ReadFile(real_path, contents)) { + errorstream << "ModVFS::scanModSubfolder(): Can't read file \"" + << real_path << "\"." << std::endl; + continue; + } + + m_vfs.emplace(vfs_path, contents); + } +} + +const std::string *ModVFS::getModFile(std::string filename) +{ + // strip dir delimiter from beginning of path + auto pos = filename.find_first_of(':'); + if (pos == std::string::npos) + return nullptr; + ++pos; + auto pos2 = filename.find_first_not_of('/', pos); + if (pos2 > pos) + filename.erase(pos, pos2 - pos); + + auto it = m_vfs.find(filename); + if (it == m_vfs.end()) + return nullptr; + return &it->second; +} diff --git a/src/client/mod_vfs.h b/src/client/mod_vfs.h new file mode 100644 index 000000000..c192b2289 --- /dev/null +++ b/src/client/mod_vfs.h @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2025 Luanti authors +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#pragma once + +#include +#include + +struct ModVFS +{ + void scanModSubfolder(const std::string &mod_name, const std::string &mod_path, + std::string mod_subpath); + + inline void scanModIntoMemory(const std::string &mod_name, const std::string &mod_path) + { + scanModSubfolder(mod_name, mod_path, ""); + } + + const std::string *getModFile(std::string filename); + + std::unordered_map m_vfs; +}; diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index ba931b22a..66d25f83e 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -16,6 +16,8 @@ #include "server.h" #if CHECK_CLIENT_BUILD() #include "client/client.h" +#include "client/mod_vfs.h" +#include "sscsm/sscsm_environment.h" #endif #if BUILD_WITH_TRACY @@ -269,12 +271,13 @@ void ScriptApiBase::loadModFromMemory(const std::string &mod_name) { ModNameStorer mod_name_storer(getStack(), mod_name); - sanity_check(m_type == ScriptingType::Client); + sanity_check(m_type == ScriptingType::Client + || m_type == ScriptingType::SSCSM); const std::string init_filename = mod_name + ":init.lua"; const std::string chunk_name = "@" + init_filename; - const std::string *contents = getClient()->getModFile(init_filename); + const std::string *contents = getModVFS()->getModFile(init_filename); if (!contents) throw ModError("Mod \"" + mod_name + "\" lacks init.lua"); @@ -521,8 +524,18 @@ Server* ScriptApiBase::getServer() } #if CHECK_CLIENT_BUILD() -Client* ScriptApiBase::getClient() +Client *ScriptApiBase::getClient() { return dynamic_cast(m_gamedef); } + +ModVFS *ScriptApiBase::getModVFS() +{ + if (m_type == ScriptingType::Client) + return getClient()->getModVFS(); + else if (m_type == ScriptingType::SSCSM) + return getSSCSMEnv()->getModVFS(); + else + return nullptr; +} #endif diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h index 4435e140b..0e6e9886b 100644 --- a/src/script/cpp_api/s_base.h +++ b/src/script/cpp_api/s_base.h @@ -62,6 +62,7 @@ class GUIEngine; class SSCSMEnvironment; class ServerActiveObject; struct PlayerHPChangeReason; +struct ModVFS; class ScriptApiBase : protected LuaHelper { public: @@ -95,6 +96,7 @@ public: Server *getServer(); #if CHECK_CLIENT_BUILD() Client *getClient(); + ModVFS *getModVFS(); #endif // IMPORTANT: These cannot be used for any security-related uses, they exist diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index fab1f09e3..962c3d561 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -9,6 +9,7 @@ #include "server.h" #if CHECK_CLIENT_BUILD() #include "client/client.h" +#include "client/mod_vfs.h" #endif #include "settings.h" @@ -878,7 +879,7 @@ int ScriptApiSecurity::sl_g_loadfile(lua_State *L) if (script->getType() == ScriptingType::Client || script->getType() == ScriptingType::SSCSM) { std::string path = readParam(L, 1); - const std::string *contents = script->getClient()->getModFile(path); //TODO + const std::string *contents = script->getModVFS()->getModFile(path); if (!contents) { std::string error_msg = "Couldn't find script called: " + path; lua_pushnil(L); diff --git a/src/script/sscsm/sscsm_environment.cpp b/src/script/sscsm/sscsm_environment.cpp index 6f6d8d2b7..90bebeccb 100644 --- a/src/script/sscsm/sscsm_environment.cpp +++ b/src/script/sscsm/sscsm_environment.cpp @@ -6,15 +6,19 @@ #include "sscsm_requests.h" #include "sscsm_events.h" #include "sscsm_stupid_channel.h" +#include "client/mod_vfs.h" SSCSMEnvironment::SSCSMEnvironment(std::shared_ptr channel) : Thread("SSCSMEnvironment-thread"), m_channel(std::move(channel)), - m_script(std::make_unique(this)) + m_script(std::make_unique(this)), + m_vfs(std::make_unique()) { } +SSCSMEnvironment::~SSCSMEnvironment() = default; + void *SSCSMEnvironment::run() { while (true) { @@ -44,14 +48,14 @@ SerializedSSCSMAnswer SSCSMEnvironment::exchange(SerializedSSCSMRequest req) void SSCSMEnvironment::updateVFSFiles(std::vector> &&files) { for (auto &&p : files) { - m_vfs.emplace(std::move(p.first), std::move(p.second)); + m_vfs->m_vfs.emplace(std::move(p.first), std::move(p.second)); } } std::optional SSCSMEnvironment::readVFSFile(const std::string &path) { - auto it = m_vfs.find(path); - if (it == m_vfs.end()) + auto it = m_vfs->m_vfs.find(path); + if (it == m_vfs->m_vfs.end()) return std::nullopt; else return it->second; diff --git a/src/script/sscsm/sscsm_environment.h b/src/script/sscsm/sscsm_environment.h index f055a88b7..643e49fcd 100644 --- a/src/script/sscsm/sscsm_environment.h +++ b/src/script/sscsm/sscsm_environment.h @@ -25,7 +25,7 @@ class SSCSMEnvironment : public Thread // /client_builtin/subdir/foo.lua // /server_builtin/subdir/foo.lua // /mods/modname/subdir/foo.lua - std::unordered_map m_vfs; + std::unique_ptr m_vfs; void *run() override; @@ -33,9 +33,11 @@ class SSCSMEnvironment : public Thread public: SSCSMEnvironment(std::shared_ptr channel); + ~SSCSMEnvironment(); SSCSMScripting *getScript() { return m_script.get(); } + ModVFS *getModVFS() { return m_vfs.get(); } void updateVFSFiles(std::vector> &&files); std::optional readVFSFile(const std::string &path);