Add LevelDB player database (#9982)

This commit is contained in:
luk3yx 2020-06-13 04:54:20 +12:00 committed by GitHub
parent 3f0cbbc372
commit 982a030f33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 138 additions and 4 deletions

@ -105,12 +105,12 @@ Migrate from current map backend to another. Possible values are sqlite3,
leveldb, redis, postgresql, and dummy. leveldb, redis, postgresql, and dummy.
.TP .TP
.B \-\-migrate-auth <value> .B \-\-migrate-auth <value>
Migrate from current auth backend to another. Possible values are sqlite3 and Migrate from current auth backend to another. Possible values are sqlite3,
files. leveldb, and files.
.TP .TP
.B \-\-migrate-players <value> .B \-\-migrate-players <value>
Migrate from current players backend to another. Possible values are sqlite3, Migrate from current players backend to another. Possible values are sqlite3,
postgresql, dummy, and files. leveldb, postgresql, dummy, and files.
.TP .TP
.B \-\-terminal .B \-\-terminal
Display an interactive terminal over ncurses during execution. Display an interactive terminal over ncurses during execution.

@ -26,6 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h" #include "log.h"
#include "filesys.h" #include "filesys.h"
#include "exceptions.h" #include "exceptions.h"
#include "remoteplayer.h"
#include "server/player_sao.h"
#include "util/serialize.h" #include "util/serialize.h"
#include "util/string.h" #include "util/string.h"
@ -98,6 +100,116 @@ void Database_LevelDB::listAllLoadableBlocks(std::vector<v3s16> &dst)
delete it; delete it;
} }
PlayerDatabaseLevelDB::PlayerDatabaseLevelDB(const std::string &savedir)
{
leveldb::Options options;
options.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(options,
savedir + DIR_DELIM + "players.db", &m_database);
ENSURE_STATUS_OK(status);
}
PlayerDatabaseLevelDB::~PlayerDatabaseLevelDB()
{
delete m_database;
}
void PlayerDatabaseLevelDB::savePlayer(RemotePlayer *player)
{
/*
u8 version = 1
u16 hp
v3f position
f32 pitch
f32 yaw
u16 breath
u32 attribute_count
for each attribute {
std::string name
std::string (long) value
}
std::string (long) serialized_inventory
*/
std::ostringstream os;
writeU8(os, 1);
PlayerSAO *sao = player->getPlayerSAO();
sanity_check(sao);
writeU16(os, sao->getHP());
writeV3F32(os, sao->getBasePosition());
writeF32(os, sao->getLookPitch());
writeF32(os, sao->getRotation().Y);
writeU16(os, sao->getBreath());
StringMap stringvars = sao->getMeta().getStrings();
writeU32(os, stringvars.size());
for (const auto &it : stringvars) {
os << serializeString(it.first);
os << serializeLongString(it.second);
}
player->inventory.serialize(os);
leveldb::Status status = m_database->Put(leveldb::WriteOptions(),
player->getName(), os.str());
ENSURE_STATUS_OK(status);
player->onSuccessfulSave();
}
bool PlayerDatabaseLevelDB::removePlayer(const std::string &name)
{
leveldb::Status s = m_database->Delete(leveldb::WriteOptions(), name);
return s.ok();
}
bool PlayerDatabaseLevelDB::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
{
std::string raw;
leveldb::Status s = m_database->Get(leveldb::ReadOptions(),
player->getName(), &raw);
if (!s.ok())
return false;
std::istringstream is(raw);
if (readU8(is) > 1)
return false;
sao->setHPRaw(readU16(is));
sao->setBasePosition(readV3F32(is));
sao->setLookPitch(readF32(is));
sao->setPlayerYaw(readF32(is));
sao->setBreath(readU16(is), false);
u32 attribute_count = readU32(is);
for (u32 i = 0; i < attribute_count; i++) {
std::string name = deSerializeString(is);
std::string value = deSerializeLongString(is);
sao->getMeta().setString(name, value);
}
sao->getMeta().setModified(false);
// This should always be last.
try {
player->inventory.deSerialize(is);
} catch (SerializationError &e) {
errorstream << "Failed to deserialize player inventory. player_name="
<< player->getName() << " " << e.what() << std::endl;
}
return true;
}
void PlayerDatabaseLevelDB::listPlayers(std::vector<std::string> &res)
{
leveldb::Iterator* it = m_database->NewIterator(leveldb::ReadOptions());
res.clear();
for (it->SeekToFirst(); it->Valid(); it->Next()) {
res.push_back(it->key().ToString());
}
delete it;
}
AuthDatabaseLevelDB::AuthDatabaseLevelDB(const std::string &savedir) AuthDatabaseLevelDB::AuthDatabaseLevelDB(const std::string &savedir)
{ {
leveldb::Options options; leveldb::Options options;

@ -45,6 +45,21 @@ private:
leveldb::DB *m_database; leveldb::DB *m_database;
}; };
class PlayerDatabaseLevelDB : public PlayerDatabase
{
public:
PlayerDatabaseLevelDB(const std::string &savedir);
~PlayerDatabaseLevelDB();
void savePlayer(RemotePlayer *player);
bool loadPlayer(RemotePlayer *player, PlayerSAO *sao);
bool removePlayer(const std::string &name);
void listPlayers(std::vector<std::string> &res);
private:
leveldb::DB *m_database;
};
class AuthDatabaseLevelDB : public AuthDatabase class AuthDatabaseLevelDB : public AuthDatabase
{ {
public: public:

@ -2089,6 +2089,7 @@ PlayerDatabase *ServerEnvironment::openPlayerDatabase(const std::string &name,
if (name == "dummy") if (name == "dummy")
return new Database_Dummy(); return new Database_Dummy();
#if USE_POSTGRESQL #if USE_POSTGRESQL
if (name == "postgresql") { if (name == "postgresql") {
std::string connect_string; std::string connect_string;
@ -2096,6 +2097,12 @@ PlayerDatabase *ServerEnvironment::openPlayerDatabase(const std::string &name,
return new PlayerDatabasePostgreSQL(connect_string); return new PlayerDatabasePostgreSQL(connect_string);
} }
#endif #endif
#if USE_LEVELDB
if (name == "leveldb")
return new PlayerDatabaseLevelDB(savedir);
#endif
if (name == "files") if (name == "files")
return new PlayerDatabaseFiles(savedir + DIR_DELIM + "players"); return new PlayerDatabaseFiles(savedir + DIR_DELIM + "players");
@ -2116,7 +2123,7 @@ bool ServerEnvironment::migratePlayersDatabase(const GameParams &game_params,
if (!world_mt.exists("player_backend")) { if (!world_mt.exists("player_backend")) {
errorstream << "Please specify your current backend in world.mt:" errorstream << "Please specify your current backend in world.mt:"
<< std::endl << std::endl
<< " player_backend = {files|sqlite3|postgresql}" << " player_backend = {files|sqlite3|leveldb|postgresql}"
<< std::endl; << std::endl;
return false; return false;
} }