3 Copyright (C) 2017 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
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.
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.
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.
21 #include <json/json.h>
22 #include "database-files.h"
23 #include "remoteplayer.h"
27 #include "server/player_sao.h"
28 #include "util/string.h"
31 // This backend is intended to be used on Minetest 0.4.16 only for the transition backend
34 PlayerDatabaseFiles::PlayerDatabaseFiles(const std::string &savedir) : m_savedir(savedir)
36 fs::CreateDir(m_savedir);
39 void PlayerDatabaseFiles::serialize(std::ostringstream &os, RemotePlayer *player)
41 // Utilize a Settings object for storing values
43 args.setS32("version", 1);
44 args.set("name", player->getName());
46 sanity_check(player->getPlayerSAO());
47 args.setU16("hp", player->getPlayerSAO()->getHP());
48 args.setV3F("position", player->getPlayerSAO()->getBasePosition());
49 args.setFloat("pitch", player->getPlayerSAO()->getLookPitch());
50 args.setFloat("yaw", player->getPlayerSAO()->getRotation().Y);
51 args.setU16("breath", player->getPlayerSAO()->getBreath());
53 std::string extended_attrs;
54 player->serializeExtraAttributes(extended_attrs);
55 args.set("extended_attributes", extended_attrs);
59 os << "PlayerArgsEnd\n";
61 player->inventory.serialize(os);
64 void PlayerDatabaseFiles::savePlayer(RemotePlayer *player)
66 fs::CreateDir(m_savedir);
68 std::string savedir = m_savedir + DIR_DELIM;
69 std::string path = savedir + player->getName();
70 bool path_found = false;
71 RemotePlayer testplayer("", NULL);
73 for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES && !path_found; i++) {
74 if (!fs::PathExists(path)) {
79 // Open and deserialize file to check player name
80 std::ifstream is(path.c_str(), std::ios_base::binary);
82 errorstream << "Failed to open " << path << std::endl;
86 testplayer.deSerialize(is, path, NULL);
88 if (strcmp(testplayer.getName(), player->getName()) == 0) {
93 path = savedir + player->getName() + itos(i);
97 errorstream << "Didn't find free file for player " << player->getName()
102 // Open and serialize file
103 std::ostringstream ss(std::ios_base::binary);
104 serialize(ss, player);
105 if (!fs::safeWriteToFile(path, ss.str())) {
106 infostream << "Failed to write " << path << std::endl;
109 player->onSuccessfulSave();
112 bool PlayerDatabaseFiles::removePlayer(const std::string &name)
114 std::string players_path = m_savedir + DIR_DELIM;
115 std::string path = players_path + name;
117 RemotePlayer temp_player("", NULL);
118 for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
119 // Open file and deserialize
120 std::ifstream is(path.c_str(), std::ios_base::binary);
124 temp_player.deSerialize(is, path, NULL);
127 if (temp_player.getName() == name) {
128 fs::DeleteSingleFileOrEmptyDirectory(path);
132 path = players_path + name + itos(i);
138 bool PlayerDatabaseFiles::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
140 std::string players_path = m_savedir + DIR_DELIM;
141 std::string path = players_path + player->getName();
143 const std::string player_to_load = player->getName();
144 for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) {
145 // Open file and deserialize
146 std::ifstream is(path.c_str(), std::ios_base::binary);
150 player->deSerialize(is, path, sao);
153 if (player->getName() == player_to_load)
156 path = players_path + player_to_load + itos(i);
159 infostream << "Player file for player " << player_to_load << " not found" << std::endl;
163 void PlayerDatabaseFiles::listPlayers(std::vector<std::string> &res)
165 std::vector<fs::DirListNode> files = fs::GetDirListing(m_savedir);
166 // list files into players directory
167 for (std::vector<fs::DirListNode>::const_iterator it = files.begin(); it !=
169 // Ignore directories
173 const std::string &filename = it->name;
174 std::string full_path = m_savedir + DIR_DELIM + filename;
175 std::ifstream is(full_path.c_str(), std::ios_base::binary);
179 RemotePlayer player(filename.c_str(), NULL);
180 // Null env & dummy peer_id
181 PlayerSAO playerSAO(NULL, &player, 15789, false);
183 player.deSerialize(is, "", &playerSAO);
186 res.emplace_back(player.getName());
190 AuthDatabaseFiles::AuthDatabaseFiles(const std::string &savedir) : m_savedir(savedir)
195 bool AuthDatabaseFiles::getAuth(const std::string &name, AuthEntry &res)
197 const auto res_i = m_auth_list.find(name);
198 if (res_i == m_auth_list.end()) {
205 bool AuthDatabaseFiles::saveAuth(const AuthEntry &authEntry)
207 m_auth_list[authEntry.name] = authEntry;
210 return writeAuthFile();
213 bool AuthDatabaseFiles::createAuth(AuthEntry &authEntry)
215 m_auth_list[authEntry.name] = authEntry;
218 return writeAuthFile();
221 bool AuthDatabaseFiles::deleteAuth(const std::string &name)
223 if (!m_auth_list.erase(name)) {
224 // did not delete anything -> hadn't existed
227 return writeAuthFile();
230 void AuthDatabaseFiles::listNames(std::vector<std::string> &res)
233 res.reserve(m_auth_list.size());
234 for (const auto &res_pair : m_auth_list) {
235 res.push_back(res_pair.first);
239 void AuthDatabaseFiles::reload()
244 bool AuthDatabaseFiles::readAuthFile()
246 std::string path = m_savedir + DIR_DELIM + "auth.txt";
247 std::ifstream file(path, std::ios::binary);
252 while (file.good()) {
254 std::getline(file, line);
255 std::vector<std::string> parts = str_split(line, ':');
256 if (parts.size() < 3) // also: empty line at end
258 const std::string &name = parts[0];
259 const std::string &password = parts[1];
260 std::vector<std::string> privileges = str_split(parts[2], ',');
261 s64 last_login = parts.size() > 3 ? atol(parts[3].c_str()) : 0;
263 m_auth_list[name] = {
274 bool AuthDatabaseFiles::writeAuthFile()
276 std::string path = m_savedir + DIR_DELIM + "auth.txt";
277 std::ostringstream output(std::ios_base::binary);
278 for (const auto &auth_i : m_auth_list) {
279 const AuthEntry &authEntry = auth_i.second;
280 output << authEntry.name << ":" << authEntry.password << ":";
281 output << str_join(authEntry.privileges, ",");
282 output << ":" << authEntry.last_login;
285 if (!fs::safeWriteToFile(path, output.str())) {
286 infostream << "Failed to write " << path << std::endl;