Translated using Weblate (Chinese (Simplified))
[oweals/minetest.git] / src / database / database-leveldb.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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 "config.h"
21
22 #if USE_LEVELDB
23
24 #include "database-leveldb.h"
25
26 #include "log.h"
27 #include "filesys.h"
28 #include "exceptions.h"
29 #include "remoteplayer.h"
30 #include "server/player_sao.h"
31 #include "util/serialize.h"
32 #include "util/string.h"
33
34 #include "leveldb/db.h"
35
36
37 #define ENSURE_STATUS_OK(s) \
38         if (!(s).ok()) { \
39                 throw DatabaseException(std::string("LevelDB error: ") + \
40                                 (s).ToString()); \
41         }
42
43
44 Database_LevelDB::Database_LevelDB(const std::string &savedir)
45 {
46         leveldb::Options options;
47         options.create_if_missing = true;
48         leveldb::Status status = leveldb::DB::Open(options,
49                 savedir + DIR_DELIM + "map.db", &m_database);
50         ENSURE_STATUS_OK(status);
51 }
52
53 Database_LevelDB::~Database_LevelDB()
54 {
55         delete m_database;
56 }
57
58 bool Database_LevelDB::saveBlock(const v3s16 &pos, const std::string &data)
59 {
60         leveldb::Status status = m_database->Put(leveldb::WriteOptions(),
61                         i64tos(getBlockAsInteger(pos)), data);
62         if (!status.ok()) {
63                 warningstream << "saveBlock: LevelDB error saving block "
64                         << PP(pos) << ": " << status.ToString() << std::endl;
65                 return false;
66         }
67
68         return true;
69 }
70
71 void Database_LevelDB::loadBlock(const v3s16 &pos, std::string *block)
72 {
73         std::string datastr;
74         leveldb::Status status = m_database->Get(leveldb::ReadOptions(),
75                 i64tos(getBlockAsInteger(pos)), &datastr);
76
77         *block = (status.ok()) ? datastr : "";
78 }
79
80 bool Database_LevelDB::deleteBlock(const v3s16 &pos)
81 {
82         leveldb::Status status = m_database->Delete(leveldb::WriteOptions(),
83                         i64tos(getBlockAsInteger(pos)));
84         if (!status.ok()) {
85                 warningstream << "deleteBlock: LevelDB error deleting block "
86                         << PP(pos) << ": " << status.ToString() << std::endl;
87                 return false;
88         }
89
90         return true;
91 }
92
93 void Database_LevelDB::listAllLoadableBlocks(std::vector<v3s16> &dst)
94 {
95         leveldb::Iterator* it = m_database->NewIterator(leveldb::ReadOptions());
96         for (it->SeekToFirst(); it->Valid(); it->Next()) {
97                 dst.push_back(getIntegerAsBlock(stoi64(it->key().ToString())));
98         }
99         ENSURE_STATUS_OK(it->status());  // Check for any errors found during the scan
100         delete it;
101 }
102
103 PlayerDatabaseLevelDB::PlayerDatabaseLevelDB(const std::string &savedir)
104 {
105         leveldb::Options options;
106         options.create_if_missing = true;
107         leveldb::Status status = leveldb::DB::Open(options,
108                 savedir + DIR_DELIM + "players.db", &m_database);
109         ENSURE_STATUS_OK(status);
110 }
111
112 PlayerDatabaseLevelDB::~PlayerDatabaseLevelDB()
113 {
114         delete m_database;
115 }
116
117 void PlayerDatabaseLevelDB::savePlayer(RemotePlayer *player)
118 {
119         /*
120         u8 version = 1
121         u16 hp
122         v3f position
123         f32 pitch
124         f32 yaw
125         u16 breath
126         u32 attribute_count
127         for each attribute {
128                 std::string name
129                 std::string (long) value
130         }
131         std::string (long) serialized_inventory
132         */
133
134         std::ostringstream os;
135         writeU8(os, 1);
136
137         PlayerSAO *sao = player->getPlayerSAO();
138         sanity_check(sao);
139         writeU16(os, sao->getHP());
140         writeV3F32(os, sao->getBasePosition());
141         writeF32(os, sao->getLookPitch());
142         writeF32(os, sao->getRotation().Y);
143         writeU16(os, sao->getBreath());
144
145         StringMap stringvars = sao->getMeta().getStrings();
146         writeU32(os, stringvars.size());
147         for (const auto &it : stringvars) {
148                 os << serializeString(it.first);
149                 os << serializeLongString(it.second);
150         }
151
152         player->inventory.serialize(os);
153
154         leveldb::Status status = m_database->Put(leveldb::WriteOptions(),
155                 player->getName(), os.str());
156         ENSURE_STATUS_OK(status);
157         player->onSuccessfulSave();
158 }
159
160 bool PlayerDatabaseLevelDB::removePlayer(const std::string &name)
161 {
162         leveldb::Status s = m_database->Delete(leveldb::WriteOptions(), name);
163         return s.ok();
164 }
165
166 bool PlayerDatabaseLevelDB::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
167 {
168         std::string raw;
169         leveldb::Status s = m_database->Get(leveldb::ReadOptions(),
170                 player->getName(), &raw);
171         if (!s.ok())
172                 return false;
173         std::istringstream is(raw);
174
175         if (readU8(is) > 1)
176                 return false;
177
178         sao->setHPRaw(readU16(is));
179         sao->setBasePosition(readV3F32(is));
180         sao->setLookPitch(readF32(is));
181         sao->setPlayerYaw(readF32(is));
182         sao->setBreath(readU16(is), false);
183
184         u32 attribute_count = readU32(is);
185         for (u32 i = 0; i < attribute_count; i++) {
186                 std::string name = deSerializeString(is);
187                 std::string value = deSerializeLongString(is);
188                 sao->getMeta().setString(name, value);
189         }
190         sao->getMeta().setModified(false);
191
192         // This should always be last.
193         try {
194                 player->inventory.deSerialize(is);
195         } catch (SerializationError &e) {
196                 errorstream << "Failed to deserialize player inventory. player_name="
197                         << player->getName() << " " << e.what() << std::endl;
198         }
199
200         return true;
201 }
202
203 void PlayerDatabaseLevelDB::listPlayers(std::vector<std::string> &res)
204 {
205         leveldb::Iterator* it = m_database->NewIterator(leveldb::ReadOptions());
206         res.clear();
207         for (it->SeekToFirst(); it->Valid(); it->Next()) {
208                 res.push_back(it->key().ToString());
209         }
210         delete it;
211 }
212
213 AuthDatabaseLevelDB::AuthDatabaseLevelDB(const std::string &savedir)
214 {
215         leveldb::Options options;
216         options.create_if_missing = true;
217         leveldb::Status status = leveldb::DB::Open(options,
218                 savedir + DIR_DELIM + "auth.db", &m_database);
219         ENSURE_STATUS_OK(status);
220 }
221
222 AuthDatabaseLevelDB::~AuthDatabaseLevelDB()
223 {
224         delete m_database;
225 }
226
227 bool AuthDatabaseLevelDB::getAuth(const std::string &name, AuthEntry &res)
228 {
229         std::string raw;
230         leveldb::Status s = m_database->Get(leveldb::ReadOptions(), name, &raw);
231         if (!s.ok())
232                 return false;
233         std::istringstream is(raw);
234
235         /*
236         u8 version = 1
237         std::string password
238         u16 number of privileges
239         for each privilege {
240                 std::string privilege
241         }
242         s64 last_login
243         */
244
245         if (readU8(is) > 1)
246                 return false;
247
248         res.id = 1;
249         res.name = name;
250         res.password = deSerializeString(is);
251
252         u16 privilege_count = readU16(is);
253         res.privileges.clear();
254         res.privileges.reserve(privilege_count);
255         for (u16 i = 0; i < privilege_count; i++) {
256                 res.privileges.push_back(deSerializeString(is));
257         }
258
259         res.last_login = readS64(is);
260         return true;
261 }
262
263 bool AuthDatabaseLevelDB::saveAuth(const AuthEntry &authEntry)
264 {
265         std::ostringstream os;
266         writeU8(os, 1);
267         os << serializeString(authEntry.password);
268
269         size_t privilege_count = authEntry.privileges.size();
270         FATAL_ERROR_IF(privilege_count > U16_MAX,
271                 "Unsupported number of privileges");
272         writeU16(os, privilege_count);
273         for (const std::string &privilege : authEntry.privileges) {
274                 os << serializeString(privilege);
275         }
276
277         writeS64(os, authEntry.last_login);
278         leveldb::Status s = m_database->Put(leveldb::WriteOptions(),
279                 authEntry.name, os.str());
280         return s.ok();
281 }
282
283 bool AuthDatabaseLevelDB::createAuth(AuthEntry &authEntry)
284 {
285         return saveAuth(authEntry);
286 }
287
288 bool AuthDatabaseLevelDB::deleteAuth(const std::string &name)
289 {
290         leveldb::Status s = m_database->Delete(leveldb::WriteOptions(), name);
291         return s.ok();
292 }
293
294 void AuthDatabaseLevelDB::listNames(std::vector<std::string> &res)
295 {
296         leveldb::Iterator* it = m_database->NewIterator(leveldb::ReadOptions());
297         res.clear();
298         for (it->SeekToFirst(); it->Valid(); it->Next()) {
299                 res.emplace_back(it->key().ToString());
300         }
301         delete it;
302 }
303
304 void AuthDatabaseLevelDB::reload()
305 {
306         // No-op for LevelDB.
307 }
308
309 #endif // USE_LEVELDB