Skip to content

Commit 29ab20c

Browse files
authoredApr 23, 2017
Player data to Database (#5475)
* Player data to Database Add player data into databases (SQLite3 & PG only) PostgreSQL & SQLite: better POO Design for databases Add --migrate-players argument to server + deprecation warning * Remove players directory if empty
1 parent dda171d commit 29ab20c

31 files changed

+1547
-370
lines changed
 

‎build/android/jni/Android.mk

+1
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ LOCAL_SRC_FILES := \
134134
jni/src/convert_json.cpp \
135135
jni/src/craftdef.cpp \
136136
jni/src/database-dummy.cpp \
137+
jni/src/database-files.cpp \
137138
jni/src/database-sqlite3.cpp \
138139
jni/src/database.cpp \
139140
jni/src/debug.cpp \

‎builtin/game/chatcommands.lua

+25
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,31 @@ core.register_chatcommand("auth_reload", {
279279
end,
280280
})
281281

282+
core.register_chatcommand("remove_player", {
283+
params = "<name>",
284+
description = "Remove player data",
285+
privs = {server=true},
286+
func = function(name, param)
287+
local toname = param
288+
if toname == "" then
289+
return false, "Name field required"
290+
end
291+
292+
local rc = core.remove_player(toname)
293+
294+
if rc == 0 then
295+
core.log("action", name .. " removed player data of " .. toname .. ".")
296+
return true, "Player \"" .. toname .. "\" removed."
297+
elseif rc == 1 then
298+
return true, "No such player \"" .. toname .. "\" to remove."
299+
elseif rc == 2 then
300+
return true, "Player \"" .. toname .. "\" is connected, cannot remove."
301+
end
302+
303+
return false, "Unhandled remove_player return code " .. rc .. ""
304+
end,
305+
})
306+
282307
core.register_chatcommand("teleport", {
283308
params = "<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>",
284309
description = "Teleport to player or position",

‎doc/lua_api.txt

+2
Original file line numberDiff line numberDiff line change
@@ -2599,6 +2599,8 @@ These functions return the leftover itemstack.
25992599
* `minetest.cancel_shutdown_requests()`: cancel current delayed shutdown
26002600
* `minetest.get_server_status()`: returns server status string
26012601
* `minetest.get_server_uptime()`: returns the server uptime in seconds
2602+
* `minetest.remove_player(name)`: remove player from database (if he is not connected).
2603+
* Returns a code (0: successful, 1: no such player, 2: player is connected)
26022604

26032605
### Bans
26042606
* `minetest.get_ban_list()`: returns the ban list (same as `minetest.get_ban_description("")`)

‎src/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ set(common_SRCS
377377
convert_json.cpp
378378
craftdef.cpp
379379
database-dummy.cpp
380+
database-files.cpp
380381
database-leveldb.cpp
381382
database-postgresql.cpp
382383
database-redis.cpp

‎src/client.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ void Client::initLocalMapSaving(const Address &address,
770770

771771
fs::CreateAllDirs(world_path);
772772

773-
m_localdb = new Database_SQLite3(world_path);
773+
m_localdb = new MapDatabaseSQLite3(world_path);
774774
m_localdb->beginSave();
775775
actionstream << "Local map saving started, map will be saved at '" << world_path << "'" << std::endl;
776776
}

‎src/client.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class ClientMediaDownloader;
4949
struct MapDrawControl;
5050
class MtEventManager;
5151
struct PointedThing;
52-
class Database;
52+
class MapDatabase;
5353
class Minimap;
5454
struct MinimapMapblock;
5555
class Camera;
@@ -645,7 +645,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
645645
LocalClientState m_state;
646646

647647
// Used for saving server map to disk client-side
648-
Database *m_localdb;
648+
MapDatabase *m_localdb;
649649
IntervalLimiter m_localdb_save_interval;
650650
u16 m_cache_save_interval;
651651

‎src/content_sao.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -764,9 +764,10 @@ bool LuaEntitySAO::collideWithObjects() const
764764

765765
// No prototype, PlayerSAO does not need to be deserialized
766766

767-
PlayerSAO::PlayerSAO(ServerEnvironment *env_, u16 peer_id_, bool is_singleplayer):
767+
PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, u16 peer_id_,
768+
bool is_singleplayer):
768769
UnitSAO(env_, v3f(0,0,0)),
769-
m_player(NULL),
770+
m_player(player_),
770771
m_peer_id(peer_id_),
771772
m_inventory(NULL),
772773
m_damage(0),
@@ -819,7 +820,7 @@ PlayerSAO::~PlayerSAO()
819820
delete m_inventory;
820821
}
821822

822-
void PlayerSAO::initialize(RemotePlayer *player, const std::set<std::string> &privs)
823+
void PlayerSAO::finalize(RemotePlayer *player, const std::set<std::string> &privs)
823824
{
824825
assert(player);
825826
m_player = player;

‎src/content_sao.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ class RemotePlayer;
194194
class PlayerSAO : public UnitSAO
195195
{
196196
public:
197-
PlayerSAO(ServerEnvironment *env_, u16 peer_id_, bool is_singleplayer);
197+
PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, u16 peer_id_, bool is_singleplayer);
198198
~PlayerSAO();
199199
ActiveObjectType getType() const
200200
{ return ACTIVEOBJECT_TYPE_PLAYER; }
@@ -349,7 +349,7 @@ class PlayerSAO : public UnitSAO
349349
bool getCollisionBox(aabb3f *toset) const;
350350
bool collideWithObjects() const { return true; }
351351

352-
void initialize(RemotePlayer *player, const std::set<std::string> &privs);
352+
void finalize(RemotePlayer *player, const std::set<std::string> &privs);
353353

354354
v3f getEyePosition() const { return m_base_position + getEyeOffset(); }
355355
v3f getEyeOffset() const;

‎src/database-dummy.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2525
#include "database.h"
2626
#include "irrlichttypes.h"
2727

28-
class Database_Dummy : public Database
28+
class Database_Dummy : public MapDatabase, public PlayerDatabase
2929
{
3030
public:
3131
bool saveBlock(const v3s16 &pos, const std::string &data);
3232
void loadBlock(const v3s16 &pos, std::string *block);
3333
bool deleteBlock(const v3s16 &pos);
3434
void listAllLoadableBlocks(std::vector<v3s16> &dst);
3535

36+
void savePlayer(RemotePlayer *player) {}
37+
bool loadPlayer(RemotePlayer *player, PlayerSAO *sao) { return true; }
38+
bool removePlayer(const std::string &name) { return true; }
39+
void listPlayers(std::vector<std::string> &) {}
40+
41+
void beginSave() {}
42+
void endSave() {}
3643
private:
3744
std::map<s64, std::string> m_database;
3845
};

‎src/database-files.cpp

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*
2+
Minetest
3+
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
4+
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of the GNU Lesser General Public License as published by
7+
the Free Software Foundation; either version 2.1 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public License along
16+
with this program; if not, write to the Free Software Foundation, Inc.,
17+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*/
19+
20+
#include <cassert>
21+
#include <json/json.h>
22+
#include "database-files.h"
23+
#include "content_sao.h"
24+
#include "remoteplayer.h"
25+
#include "settings.h"
26+
#include "porting.h"
27+
#include "filesys.h"
28+
29+
// !!! WARNING !!!
30+
// This backend is intended to be used on Minetest 0.4.16 only for the transition backend for
31+
// player files
32+
33+
void PlayerDatabaseFiles::serialize(std::ostringstream &os, RemotePlayer *player)
34+
{
35+
// Utilize a Settings object for storing values
36+
Settings args;
37+
args.setS32("version", 1);
38+
args.set("name", player->getName());
39+
40+
sanity_check(player->getPlayerSAO());
41+
args.setS32("hp", player->getPlayerSAO()->getHP());
42+
args.setV3F("position", player->getPlayerSAO()->getBasePosition());
43+
args.setFloat("pitch", player->getPlayerSAO()->getPitch());
44+
args.setFloat("yaw", player->getPlayerSAO()->getYaw());
45+
args.setS32("breath", player->getPlayerSAO()->getBreath());
46+
47+
std::string extended_attrs = "";
48+
player->serializeExtraAttributes(extended_attrs);
49+
args.set("extended_attributes", extended_attrs);
50+
51+
args.writeLines(os);
52+
53+
os << "PlayerArgsEnd\n";
54+
55+
player->inventory.serialize(os);
56+
}
57+
58+
void PlayerDatabaseFiles::savePlayer(RemotePlayer *player)
59+
{
60+
std::string savedir = m_savedir + DIR_DELIM;
61+
std::string path = savedir + player->getName();
62+
bool path_found = false;
63+
RemotePlayer testplayer("", NULL);
64+
65+
for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES && !path_found; i++) {
66+
if (!fs::PathExists(path)) {
67+
path_found = true;
68+
continue;
69+
}
70+
71+
// Open and deserialize file to check player name
72+
std::ifstream is(path.c_str(), std::ios_base::binary);
73+
if (!is.good()) {
74+
errorstream << "Failed to open " << path << std::endl;
75+
return;
76+
}
77+
78+
testplayer.deSerialize(is, path, NULL);
79+
is.close();
80+
if (strcmp(testplayer.getName(), player->getName()) == 0) {
81+
path_found = true;
82+
continue;
83+
}
84+
85+
path = savedir + player->getName() + itos(i);
86+
}
87+
88+
if (!path_found) {
89+
errorstream << "Didn't find free file for player " << player->getName()
90+
<< std::endl;
91+
return;
92+
}
93+
94+
// Open and serialize file
95+
std::ostringstream ss(std::ios_base::binary);
96+
serialize(ss, player);
97+
if (!fs::safeWriteToFile(path, ss.str())) {
98+
infostream << "Failed to write " << path << std::endl;
99+
}
100+
player->setModified(false);
101+
}
102+
103+
bool PlayerDatabaseFiles::removePlayer(const std::string &name)
104+
{
105+
std::string players_path = m_savedir + DIR_DELIM;
106+
std::string path = players_path + name;
107+
108+
RemotePlayer temp_player("", NULL);
109+
for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
110+
// Open file and deserialize
111+
std::ifstream is(path.c_str(), std::ios_base::binary);
112+
if (!is.good())
113+
continue;
114+
115+
temp_player.deSerialize(is, path, NULL);
116+
is.close();
117+
118+
if (temp_player.getName() == name) {
119+
fs::DeleteSingleFileOrEmptyDirectory(path);
120+
return true;
121+
}
122+
123+
path = players_path + name + itos(i);
124+
}
125+
126+
return false;
127+
}
128+
129+
bool PlayerDatabaseFiles::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
130+
{
131+
std::string players_path = m_savedir + DIR_DELIM;
132+
std::string path = players_path + player->getName();
133+
134+
const std::string player_to_load = player->getName();
135+
for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
136+
// Open file and deserialize
137+
std::ifstream is(path.c_str(), std::ios_base::binary);
138+
if (!is.good())
139+
continue;
140+
141+
player->deSerialize(is, path, sao);
142+
is.close();
143+
144+
if (player->getName() == player_to_load)
145+
return true;
146+
147+
path = players_path + player_to_load + itos(i);
148+
}
149+
150+
infostream << "Player file for player " << player_to_load << " not found" << std::endl;
151+
return false;
152+
}
153+
154+
void PlayerDatabaseFiles::listPlayers(std::vector<std::string> &res)
155+
{
156+
std::vector<fs::DirListNode> files = fs::GetDirListing(m_savedir);
157+
// list files into players directory
158+
for (std::vector<fs::DirListNode>::const_iterator it = files.begin(); it !=
159+
files.end(); ++it) {
160+
// Ignore directories
161+
if (it->dir)
162+
continue;
163+
164+
const std::string &filename = it->name;
165+
std::string full_path = m_savedir + DIR_DELIM + filename;
166+
std::ifstream is(full_path.c_str(), std::ios_base::binary);
167+
if (!is.good())
168+
continue;
169+
170+
RemotePlayer player(filename.c_str(), NULL);
171+
// Null env & dummy peer_id
172+
PlayerSAO playerSAO(NULL, &player, 15789, false);
173+
174+
player.deSerialize(is, "", &playerSAO);
175+
is.close();
176+
177+
res.push_back(player.getName());
178+
}
179+
}

‎src/database-files.h

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
Minetest
3+
Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
4+
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of the GNU Lesser General Public License as published by
7+
the Free Software Foundation; either version 2.1 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public License along
16+
with this program; if not, write to the Free Software Foundation, Inc.,
17+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*/
19+
20+
#ifndef DATABASE_FILES_HEADER
21+
#define DATABASE_FILES_HEADER
22+
23+
// !!! WARNING !!!
24+
// This backend is intended to be used on Minetest 0.4.16 only for the transition backend for
25+
// player files
26+
27+
#include "database.h"
28+
29+
class PlayerDatabaseFiles : public PlayerDatabase
30+
{
31+
public:
32+
PlayerDatabaseFiles(const std::string &savedir) : m_savedir(savedir) {}
33+
virtual ~PlayerDatabaseFiles() {}
34+
35+
void savePlayer(RemotePlayer *player);
36+
bool loadPlayer(RemotePlayer *player, PlayerSAO *sao);
37+
bool removePlayer(const std::string &name);
38+
void listPlayers(std::vector<std::string> &res);
39+
40+
private:
41+
void serialize(std::ostringstream &os, RemotePlayer *player);
42+
43+
std::string m_savedir;
44+
};
45+
46+
#endif

‎src/database-leveldb.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2828
#include "database.h"
2929
#include "leveldb/db.h"
3030

31-
class Database_LevelDB : public Database
31+
class Database_LevelDB : public MapDatabase
3232
{
3333
public:
3434
Database_LevelDB(const std::string &savedir);
@@ -39,6 +39,8 @@ class Database_LevelDB : public Database
3939
bool deleteBlock(const v3s16 &pos);
4040
void listAllLoadableBlocks(std::vector<v3s16> &dst);
4141

42+
void beginSave() {}
43+
void endSave() {}
4244
private:
4345
leveldb::DB *m_database;
4446
};

0 commit comments

Comments
 (0)
Please sign in to comment.