LocalPlayer::accelerateHorizontal: cleanups
[oweals/minetest.git] / src / database-files.cpp
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
31 // for 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 }