1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-08-11 17:51:04 +00:00

Use a database for mod storage (#11763)

This commit is contained in:
Jude Melton-Houghton 2022-01-07 13:28:49 -05:00 committed by GitHub
parent b81948a14c
commit bf22569019
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 798 additions and 127 deletions

View file

@ -66,6 +66,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server/player_sao.h"
#include "server/serverinventorymgr.h"
#include "translation.h"
#include "database/database-sqlite3.h"
#include "database/database-files.h"
#include "database/database-dummy.h"
#include "gameparams.h"
class ClientNotFoundException : public BaseException
{
@ -344,10 +348,15 @@ Server::~Server()
delete m_thread;
}
// Write any changes before deletion.
if (m_mod_storage_database)
m_mod_storage_database->endSave();
// Delete things in the reverse order of creation
delete m_emerge;
delete m_env;
delete m_rollback;
delete m_mod_storage_database;
delete m_banmanager;
delete m_itemdef;
delete m_nodedef;
@ -393,6 +402,10 @@ void Server::init()
std::string ban_path = m_path_world + DIR_DELIM "ipban.txt";
m_banmanager = new BanManager(ban_path);
// Create mod storage database and begin a save for later
m_mod_storage_database = openModStorageDatabase(m_path_world);
m_mod_storage_database->beginSave();
m_modmgr = std::unique_ptr<ServerModManager>(new ServerModManager(m_path_world));
std::vector<ModSpec> unsatisfied_mods = m_modmgr->getUnsatisfiedMods();
// complain about mods with unsatisfied dependencies
@ -733,20 +746,12 @@ void Server::AsyncRunStep(bool initial_step)
}
m_clients.unlock();
// Save mod storages if modified
// Write changes to the mod storage
m_mod_storage_save_timer -= dtime;
if (m_mod_storage_save_timer <= 0.0f) {
m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval");
int n = 0;
for (std::unordered_map<std::string, ModMetadata *>::const_iterator
it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) {
if (it->second->isModified()) {
it->second->save(getModStoragePath());
n++;
}
}
if (n > 0)
infostream << "Saved " << n << " modified mod storages." << std::endl;
m_mod_storage_database->endSave();
m_mod_storage_database->beginSave();
}
}
@ -3689,11 +3694,6 @@ std::string Server::getBuiltinLuaPath()
return porting::path_share + DIR_DELIM + "builtin";
}
std::string Server::getModStoragePath() const
{
return m_path_world + DIR_DELIM + "mod_storage";
}
v3f Server::findSpawnPos()
{
ServerMap &map = m_env->getServerMap();
@ -3857,11 +3857,8 @@ bool Server::registerModStorage(ModMetadata *storage)
void Server::unregisterModStorage(const std::string &name)
{
std::unordered_map<std::string, ModMetadata *>::const_iterator it = m_mod_storages.find(name);
if (it != m_mod_storages.end()) {
// Save unconditionaly on unregistration
it->second->save(getModStoragePath());
if (it != m_mod_storages.end())
m_mod_storages.erase(name);
}
}
void dedicated_server_loop(Server &server, bool &kill)
@ -3999,3 +3996,106 @@ Translations *Server::getTranslationLanguage(const std::string &lang_code)
return translations;
}
ModMetadataDatabase *Server::openModStorageDatabase(const std::string &world_path)
{
std::string world_mt_path = world_path + DIR_DELIM + "world.mt";
Settings world_mt;
if (!world_mt.readConfigFile(world_mt_path.c_str()))
throw BaseException("Cannot read world.mt!");
std::string backend = world_mt.exists("mod_storage_backend") ?
world_mt.get("mod_storage_backend") : "files";
if (backend == "files")
warningstream << "/!\\ You are using the old mod storage files backend. "
<< "This backend is deprecated and may be removed in a future release /!\\"
<< std::endl << "Switching to SQLite3 is advised, "
<< "please read http://wiki.minetest.net/Database_backends." << std::endl;
return openModStorageDatabase(backend, world_path, world_mt);
}
ModMetadataDatabase *Server::openModStorageDatabase(const std::string &backend,
const std::string &world_path, const Settings &world_mt)
{
if (backend == "sqlite3")
return new ModMetadataDatabaseSQLite3(world_path);
if (backend == "files")
return new ModMetadataDatabaseFiles(world_path);
if (backend == "dummy")
return new Database_Dummy();
throw BaseException("Mod storage database backend " + backend + " not supported");
}
bool Server::migrateModStorageDatabase(const GameParams &game_params, const Settings &cmd_args)
{
std::string migrate_to = cmd_args.get("migrate-mod-storage");
Settings world_mt;
std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt";
if (!world_mt.readConfigFile(world_mt_path.c_str())) {
errorstream << "Cannot read world.mt!" << std::endl;
return false;
}
std::string backend = world_mt.exists("mod_storage_backend") ?
world_mt.get("mod_storage_backend") : "files";
if (backend == migrate_to) {
errorstream << "Cannot migrate: new backend is same"
<< " as the old one" << std::endl;
return false;
}
ModMetadataDatabase *srcdb = nullptr;
ModMetadataDatabase *dstdb = nullptr;
bool succeeded = false;
try {
srcdb = Server::openModStorageDatabase(backend, game_params.world_path, world_mt);
dstdb = Server::openModStorageDatabase(migrate_to, game_params.world_path, world_mt);
dstdb->beginSave();
std::vector<std::string> mod_list;
srcdb->listMods(&mod_list);
for (const std::string &modname : mod_list) {
StringMap meta;
srcdb->getModEntries(modname, &meta);
for (const auto &pair : meta) {
dstdb->setModEntry(modname, pair.first, pair.second);
}
}
dstdb->endSave();
succeeded = true;
actionstream << "Successfully migrated the metadata of "
<< mod_list.size() << " mods" << std::endl;
world_mt.set("mod_storage_backend", migrate_to);
if (!world_mt.updateConfigFile(world_mt_path.c_str()))
errorstream << "Failed to update world.mt!" << std::endl;
else
actionstream << "world.mt updated" << std::endl;
} catch (BaseException &e) {
errorstream << "An error occurred during migration: " << e.what() << std::endl;
}
delete srcdb;
delete dstdb;
if (succeeded && backend == "files") {
// Back up files
const std::string storage_path = game_params.world_path + DIR_DELIM + "mod_storage";
const std::string backup_path = game_params.world_path + DIR_DELIM + "mod_storage.bak";
if (!fs::Rename(storage_path, backup_path))
warningstream << "After migration, " << storage_path
<< " could not be renamed to " << backup_path << std::endl;
}
return succeeded;
}