3 Copyright (C) 2012 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
28 #include "util/serialize.h"
29 #include "util/string.h"
31 #include "inventorymanager.h" // deserializing InventoryLocations
33 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
35 class RollbackManager: public IRollbackManager
38 // IRollbackManager interface
40 void reportAction(const RollbackAction &action_)
42 // Ignore if not important
43 if(!action_.isImportant(m_gamedef))
45 RollbackAction action = action_;
46 action.unix_time = time(0);
47 action.actor = m_current_actor;
48 infostream<<"RollbackManager::reportAction():"
49 <<" time="<<action.unix_time
50 <<" actor=\""<<action.actor<<"\""
51 <<" action="<<action.toString()
55 std::string getActor()
57 return m_current_actor;
59 void setActor(const std::string &actor)
61 m_current_actor = actor;
65 infostream<<"RollbackManager::flush()"<<std::endl;
66 std::ofstream of(m_filepath.c_str(), std::ios::app);
68 errorstream<<"RollbackManager::flush(): Could not open file "
69 <<"for appending: \""<<m_filepath<<"\""<<std::endl;
72 for(std::list<RollbackAction>::const_iterator
73 i = m_action_todisk_buffer.begin();
74 i != m_action_todisk_buffer.end(); i++)
76 // Do not save stuff that does not have an actor
81 of<<serializeJsonString(i->actor);
83 std::string action_s = i->toString();
84 of<<action_s<<std::endl;
86 m_action_todisk_buffer.clear();
91 RollbackManager(const std::string &filepath, IGameDef *gamedef):
95 infostream<<"RollbackManager::RollbackManager("<<filepath<<")"
100 infostream<<"RollbackManager::~RollbackManager()"<<std::endl;
104 void addAction(const RollbackAction &action)
106 m_action_todisk_buffer.push_back(action);
107 m_action_latest_buffer.push_back(action);
109 // Flush to disk sometimes
110 if(m_action_todisk_buffer.size() >= 100)
114 bool readFile(std::list<RollbackAction> &dst)
116 // Load whole file to memory
117 std::ifstream f(m_filepath.c_str(), std::ios::in);
119 errorstream<<"RollbackManager::readFile(): Could not open "
120 <<"file for reading: \""<<m_filepath<<"\""<<std::endl;
124 if(f.eof() || !f.good())
127 std::getline(f, line);
131 std::istringstream is(line);
134 std::string action_time_raw;
135 std::getline(is, action_time_raw, ' ');
136 std::string action_actor;
138 action_actor = deSerializeJsonString(is);
139 }catch(SerializationError &e){
140 errorstream<<"RollbackManager: Error deserializing actor: "
141 <<e.what()<<std::endl;
144 RollbackAction action;
145 action.unix_time = stoi(action_time_raw);
146 action.actor = action_actor;
150 throw SerializationError("readFile(): second ' ' not found");
152 action.fromStream(is);
153 /*infostream<<"RollbackManager::readFile(): Action from disk: "
154 <<action.toString()<<std::endl;*/
155 dst.push_back(action);
157 catch(SerializationError &e){
158 errorstream<<"RollbackManager: Error on line: "<<line<<std::endl;
159 errorstream<<"RollbackManager: ^ error: "<<e.what()<<std::endl;
165 std::list<RollbackAction> getEntriesSince(int first_time)
167 infostream<<"RollbackManager::getEntriesSince("<<first_time<<")"<<std::endl;
168 // Collect enough data to this buffer
169 std::list<RollbackAction> action_buffer;
170 // Use the latest buffer if it is long enough
171 if(!m_action_latest_buffer.empty() &&
172 m_action_latest_buffer.begin()->unix_time <= first_time){
173 action_buffer = m_action_latest_buffer;
177 // Save all remaining stuff
179 // Load whole file to memory
180 bool good = readFile(action_buffer);
182 errorstream<<"RollbackManager::getEntriesSince(): Failed to"
183 <<" open file; using data in memory."<<std::endl;
184 action_buffer = m_action_latest_buffer;
187 return action_buffer;
190 std::string getLastNodeActor(v3s16 p, int range, int seconds,
191 v3s16 *act_p, int *act_seconds)
193 infostream<<"RollbackManager::getLastNodeActor("<<PP(p)
194 <<", "<<seconds<<")"<<std::endl;
196 int cur_time = time(0);
197 int first_time = cur_time - seconds;
199 std::list<RollbackAction> action_buffer = getEntriesSince(first_time);
201 std::list<RollbackAction> result;
203 for(std::list<RollbackAction>::const_reverse_iterator
204 i = action_buffer.rbegin();
205 i != action_buffer.rend(); i++)
207 if(i->unix_time < first_time)
210 // Find position of action or continue
213 if(i->type == RollbackAction::TYPE_SET_NODE)
217 else if(i->type == RollbackAction::TYPE_MODIFY_INVENTORY_STACK)
219 InventoryLocation loc;
220 loc.deSerialize(i->inventory_location);
221 if(loc.type != InventoryLocation::NODEMETA)
232 if(abs(action_p.X - p.X) > range ||
233 abs(action_p.Y - p.Y) > range ||
234 abs(action_p.Z - p.Z) > range)
241 *act_seconds = cur_time - i->unix_time;
247 std::list<RollbackAction> getRevertActions(const std::string &actor_filter,
250 infostream<<"RollbackManager::getRevertActions("<<actor_filter
251 <<", "<<seconds<<")"<<std::endl;
253 int cur_time = time(0);
254 int first_time = cur_time - seconds;
256 std::list<RollbackAction> action_buffer = getEntriesSince(first_time);
258 std::list<RollbackAction> result;
260 for(std::list<RollbackAction>::const_reverse_iterator
261 i = action_buffer.rbegin();
262 i != action_buffer.rend(); i++)
264 if(i->unix_time < first_time)
266 if(i->actor != actor_filter)
268 const RollbackAction &action = *i;
269 /*infostream<<"RollbackManager::revertAction(): Should revert"
270 <<" time="<<action.unix_time
271 <<" actor=\""<<action.actor<<"\""
272 <<" action="<<action.toString()
274 result.push_back(action);
281 std::string m_filepath;
283 std::string m_current_actor;
284 std::list<RollbackAction> m_action_todisk_buffer;
285 std::list<RollbackAction> m_action_latest_buffer;
288 IRollbackManager *createRollbackManager(const std::string &filepath, IGameDef *gamedef)
290 return new RollbackManager(filepath, gamedef);