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:
parent
b3cd495936
commit
4e2970e34d
10 changed files with 119 additions and 67 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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
56
src/client/mod_vfs.cpp
Normal 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
23
src/client/mod_vfs.h
Normal 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;
|
||||||
|
};
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue