1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

mod_vfs stuff from TurkeyMcMac's PR

Co-authored-by: Jude Melton-Houghton <jwmhjwmh@gmail.com>
This commit is contained in:
Desour 2025-02-21 12:19:04 +01:00
parent b3cd495936
commit 4e2970e34d
10 changed files with 119 additions and 67 deletions

View file

@ -73,6 +73,7 @@ set(client_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/texturesource.cpp ${CMAKE_CURRENT_SOURCE_DIR}/texturesource.cpp
${CMAKE_CURRENT_SOURCE_DIR}/imagesource.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imagesource.cpp
${CMAKE_CURRENT_SOURCE_DIR}/wieldmesh.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/dynamicshadows.cpp
${CMAKE_CURRENT_SOURCE_DIR}/shadows/dynamicshadowsrender.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shadows/dynamicshadowsrender.cpp
${CMAKE_CURRENT_SOURCE_DIR}/shadows/shadowsshadercallbacks.cpp ${CMAKE_CURRENT_SOURCE_DIR}/shadows/shadowsshadercallbacks.cpp

View file

@ -10,6 +10,7 @@
#include <json/json.h> #include <json/json.h>
#include "client.h" #include "client.h"
#include "client/fontengine.h" #include "client/fontengine.h"
#include "client/mod_vfs.h"
#include "network/clientopcodes.h" #include "network/clientopcodes.h"
#include "network/connection.h" #include "network/connection.h"
#include "network/networkpacket.h" #include "network/networkpacket.h"
@ -223,12 +224,14 @@ void Client::loadMods()
return; return;
} }
m_mod_vfs = std::make_unique<ModVFS>();
m_script = new ClientScripting(this); m_script = new ClientScripting(this);
m_env.setScript(m_script); m_env.setScript(m_script);
m_script->setEnv(&m_env); m_script->setEnv(&m_env);
// Load builtin // Load builtin
scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath()); m_mod_vfs->scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());
m_script->loadModFromMemory(BUILTIN_MOD_NAME); m_script->loadModFromMemory(BUILTIN_MOD_NAME);
m_script->checkSetByBuiltin(); m_script->checkSetByBuiltin();
@ -264,7 +267,7 @@ void Client::loadMods()
// Load "mod" scripts // Load "mod" scripts
for (const ModSpec &mod : m_mods) { for (const ModSpec &mod : m_mods) {
mod.checkAndLog(); mod.checkAndLog();
scanModIntoMemory(mod.name, mod.path); m_mod_vfs->scanModIntoMemory(mod.name, mod.path);
} }
// Run them // Run them
@ -286,35 +289,6 @@ void Client::loadMods()
m_script->on_minimap_ready(m_minimap); 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<fs::DirListNode> 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() const std::string &Client::getBuiltinLuaPath()
{ {
static const std::string builtin_dir = porting::path_share + DIR_DELIM + "builtin"; 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; 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 * Mod channels
*/ */

View file

@ -58,6 +58,7 @@ struct PointedThing;
struct ItemVisualsManager; struct ItemVisualsManager;
class ClientScripting; class ClientScripting;
class SSCSMController; class SSCSMController;
struct ModVFS;
namespace con { namespace con {
class IConnection; class IConnection;
@ -126,14 +127,6 @@ public:
~Client(); ~Client();
DISABLE_CLASS_COPY(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 request all threads managed by client to be stopped
*/ */
@ -382,7 +375,7 @@ public:
bool checkLocalPrivilege(const std::string &priv) bool checkLocalPrivilege(const std::string &priv)
{ return checkPrivilege(priv); } { return checkPrivilege(priv); }
virtual scene::IAnimatedMesh* getMesh(const std::string &filename, bool cache = false); 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; } ModStorageDatabase *getModStorageDatabase() override { return m_mod_storage_database; }
ItemVisualsManager *getItemVisualsManager() { return m_item_visuals_manager; } ItemVisualsManager *getItemVisualsManager() { return m_item_visuals_manager; }
@ -583,7 +576,7 @@ private:
ModStorageDatabase *m_mod_storage_database = nullptr; ModStorageDatabase *m_mod_storage_database = nullptr;
float m_mod_storage_save_timer = 10.0f; float m_mod_storage_save_timer = 10.0f;
std::vector<ModSpec> m_mods; std::vector<ModSpec> m_mods;
StringMap m_mod_vfs; std::unique_ptr<ModVFS> m_mod_vfs;
// SSCSM // SSCSM
std::unique_ptr<SSCSMController> m_sscsm_controller; std::unique_ptr<SSCSMController> m_sscsm_controller;

56
src/client/mod_vfs.cpp Normal file
View file

@ -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 <algorithm>
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<fs::DirListNode> 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;
}

23
src/client/mod_vfs.h Normal file
View file

@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2025 Luanti authors
//
// SPDX-License-Identifier: LGPL-2.1-or-later
#pragma once
#include <string>
#include <unordered_map>
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<std::string, std::string> m_vfs;
};

View file

@ -16,6 +16,8 @@
#include "server.h" #include "server.h"
#if CHECK_CLIENT_BUILD() #if CHECK_CLIENT_BUILD()
#include "client/client.h" #include "client/client.h"
#include "client/mod_vfs.h"
#include "sscsm/sscsm_environment.h"
#endif #endif
#if BUILD_WITH_TRACY #if BUILD_WITH_TRACY
@ -269,12 +271,13 @@ void ScriptApiBase::loadModFromMemory(const std::string &mod_name)
{ {
ModNameStorer mod_name_storer(getStack(), 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 init_filename = mod_name + ":init.lua";
const std::string chunk_name = "@" + init_filename; 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) if (!contents)
throw ModError("Mod \"" + mod_name + "\" lacks init.lua"); throw ModError("Mod \"" + mod_name + "\" lacks init.lua");
@ -521,8 +524,18 @@ Server* ScriptApiBase::getServer()
} }
#if CHECK_CLIENT_BUILD() #if CHECK_CLIENT_BUILD()
Client* ScriptApiBase::getClient() Client *ScriptApiBase::getClient()
{ {
return dynamic_cast<Client *>(m_gamedef); return dynamic_cast<Client *>(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 #endif

View file

@ -62,6 +62,7 @@ class GUIEngine;
class SSCSMEnvironment; class SSCSMEnvironment;
class ServerActiveObject; class ServerActiveObject;
struct PlayerHPChangeReason; struct PlayerHPChangeReason;
struct ModVFS;
class ScriptApiBase : protected LuaHelper { class ScriptApiBase : protected LuaHelper {
public: public:
@ -95,6 +96,7 @@ public:
Server *getServer(); Server *getServer();
#if CHECK_CLIENT_BUILD() #if CHECK_CLIENT_BUILD()
Client *getClient(); Client *getClient();
ModVFS *getModVFS();
#endif #endif
// IMPORTANT: These cannot be used for any security-related uses, they exist // IMPORTANT: These cannot be used for any security-related uses, they exist

View file

@ -9,6 +9,7 @@
#include "server.h" #include "server.h"
#if CHECK_CLIENT_BUILD() #if CHECK_CLIENT_BUILD()
#include "client/client.h" #include "client/client.h"
#include "client/mod_vfs.h"
#endif #endif
#include "settings.h" #include "settings.h"
@ -878,7 +879,7 @@ int ScriptApiSecurity::sl_g_loadfile(lua_State *L)
if (script->getType() == ScriptingType::Client if (script->getType() == ScriptingType::Client
|| script->getType() == ScriptingType::SSCSM) { || script->getType() == ScriptingType::SSCSM) {
std::string path = readParam<std::string>(L, 1); std::string path = readParam<std::string>(L, 1);
const std::string *contents = script->getClient()->getModFile(path); //TODO const std::string *contents = script->getModVFS()->getModFile(path);
if (!contents) { if (!contents) {
std::string error_msg = "Couldn't find script called: " + path; std::string error_msg = "Couldn't find script called: " + path;
lua_pushnil(L); lua_pushnil(L);

View file

@ -6,15 +6,19 @@
#include "sscsm_requests.h" #include "sscsm_requests.h"
#include "sscsm_events.h" #include "sscsm_events.h"
#include "sscsm_stupid_channel.h" #include "sscsm_stupid_channel.h"
#include "client/mod_vfs.h"
SSCSMEnvironment::SSCSMEnvironment(std::shared_ptr<StupidChannel> channel) : SSCSMEnvironment::SSCSMEnvironment(std::shared_ptr<StupidChannel> channel) :
Thread("SSCSMEnvironment-thread"), Thread("SSCSMEnvironment-thread"),
m_channel(std::move(channel)), m_channel(std::move(channel)),
m_script(std::make_unique<SSCSMScripting>(this)) m_script(std::make_unique<SSCSMScripting>(this)),
m_vfs(std::make_unique<ModVFS>())
{ {
} }
SSCSMEnvironment::~SSCSMEnvironment() = default;
void *SSCSMEnvironment::run() void *SSCSMEnvironment::run()
{ {
while (true) { while (true) {
@ -44,14 +48,14 @@ SerializedSSCSMAnswer SSCSMEnvironment::exchange(SerializedSSCSMRequest req)
void SSCSMEnvironment::updateVFSFiles(std::vector<std::pair<std::string, std::string>> &&files) void SSCSMEnvironment::updateVFSFiles(std::vector<std::pair<std::string, std::string>> &&files)
{ {
for (auto &&p : 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<std::string_view> SSCSMEnvironment::readVFSFile(const std::string &path) std::optional<std::string_view> SSCSMEnvironment::readVFSFile(const std::string &path)
{ {
auto it = m_vfs.find(path); auto it = m_vfs->m_vfs.find(path);
if (it == m_vfs.end()) if (it == m_vfs->m_vfs.end())
return std::nullopt; return std::nullopt;
else else
return it->second; return it->second;

View file

@ -25,7 +25,7 @@ class SSCSMEnvironment : public Thread
// /client_builtin/subdir/foo.lua // /client_builtin/subdir/foo.lua
// /server_builtin/subdir/foo.lua // /server_builtin/subdir/foo.lua
// /mods/modname/subdir/foo.lua // /mods/modname/subdir/foo.lua
std::unordered_map<std::string, std::string> m_vfs; std::unique_ptr<ModVFS> m_vfs;
void *run() override; void *run() override;
@ -33,9 +33,11 @@ class SSCSMEnvironment : public Thread
public: public:
SSCSMEnvironment(std::shared_ptr<StupidChannel> channel); SSCSMEnvironment(std::shared_ptr<StupidChannel> channel);
~SSCSMEnvironment();
SSCSMScripting *getScript() { return m_script.get(); } SSCSMScripting *getScript() { return m_script.get(); }
ModVFS *getModVFS() { return m_vfs.get(); }
void updateVFSFiles(std::vector<std::pair<std::string, std::string>> &&files); void updateVFSFiles(std::vector<std::pair<std::string, std::string>> &&files);
std::optional<std::string_view> readVFSFile(const std::string &path); std::optional<std::string_view> readVFSFile(const std::string &path);