1 /*
2   This file is part of Freeminer.
3 
4   Freeminer is free software: you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation, either version 3 of the License, or
7   (at your option) any later version.
8 
9   Freeminer  is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13 
14   You should have received a copy of the GNU General Public License
15   along with Freeminer.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "circuit.h"
19 #include "circuit_element.h"
20 #include "debug.h"
21 #include "nodedef.h"
22 #include "mapblock.h"
23 #include "mapnode.h"
24 #include "scripting_game.h"
25 #include "map.h"
26 #include "serialization.h"
27 #include "settings.h"
28 #include "log.h"
29 #include "key_value_storage.h"
30 #include "filesys.h"
31 
32 #include <map>
33 #include <iomanip>
34 #include <cassert>
35 #include <string>
36 #include <sstream>
37 #include <fstream>
38 
39 #define PP(x) ((x).X)<<" "<<((x).Y)<<" "<<((x).Z)<<" "
40 
41 const u32 Circuit::circuit_simulator_version = 1;
42 const char Circuit::elements_states_file[] = "circuit_elements_states";
43 
Circuit(GameScripting * script,Map * map,INodeDefManager * ndef,std::string savedir)44 Circuit::Circuit(GameScripting* script, Map* map, INodeDefManager* ndef, std::string savedir) :
45 	m_script(script),
46 	m_map(map),
47 	m_ndef(ndef),
48 	m_min_update_delay(0.2f),
49 	m_since_last_update(0.0f),
50 	m_max_id(0),
51 	m_max_virtual_id(1),
52 	m_savedir(savedir)
53  {
54 		load();
55 }
56 
~Circuit()57 Circuit::~Circuit() {
58 	save();
59 	m_elements.clear();
60 	delete m_database;
61 	delete m_virtual_database;
62 	m_script = nullptr;
63 	m_map = nullptr;
64 	m_ndef = nullptr;
65 	m_database = nullptr;
66 	m_virtual_database = nullptr;
67 }
68 
open()69 void Circuit::open() {
70 	m_database->open();
71 	m_virtual_database->open();
72 }
73 
close()74 void Circuit::close() {
75 	m_database->close();
76 	m_virtual_database->close();
77 }
78 
addBlock(MapBlock * block)79 void Circuit::addBlock(MapBlock* block) {
80 	// v3POS pos;
81 	// for(pos.X = 0; pos.X < 16; ++pos.X)
82 	// {
83 	// 	for(pos.Y = 0; pos.Y < 16; ++pos.Y)
84 	// 	{
85 	// 		for(pos.Z = 0; pos.Z < 16; ++pos.Z)
86 	// 		{
87 	// 			MapNode tmp_node = block->getNode(pos);
88 	// 			if(ndef->get(tmp_node).is_circuit_element)
89 	// 			{
90 	// 				pos.X = m_pos.X * MAP_BLOCKSIZE + x;
91 	// 				pos.Y = m_pos.Y * MAP_BLOCKSIZE + y;
92 	// 				pos.Z = m_pos.Z * MAP_BLOCKSIZE + z;
93 	// 			}
94 	// 		}
95 	// 	}
96 	// }
97 }
98 
addNode(v3POS pos)99 void Circuit::addNode(v3POS pos) {
100 	MapNode n = m_map->getNodeNoEx(pos);
101 	const ContentFeatures& node_f = m_ndef->get(n);
102 	if(node_f.is_wire || node_f.is_wire_connector) {
103 		addWire(pos);
104 	}
105 	// Call circuit update
106 	if(node_f.is_circuit_element) {
107 		addElement(pos);
108 	}
109 }
110 
removeNode(v3POS pos,const MapNode & n_old)111 void Circuit::removeNode(v3POS pos, const MapNode& n_old) {
112 	if(m_ndef->get(n_old).is_wire || m_ndef->get(n_old).is_wire_connector) {
113 		removeWire(pos);
114 	}
115 	if(m_ndef->get(n_old).is_circuit_element) {
116 		removeElement(pos);
117 	}
118 }
119 
swapNode(v3POS pos,const MapNode & n_old,const MapNode & n_new)120 void Circuit::swapNode(v3POS pos, const MapNode& n_old, const MapNode& n_new) {
121 	const ContentFeatures& n_old_f = m_ndef->get(n_old);
122 	const ContentFeatures& n_new_f = m_ndef->get(n_new);
123 	if(n_new_f.is_circuit_element) {
124 		if(n_old_f.is_circuit_element) {
125 			swapElement(n_old, n_new, pos);
126 		} else {
127 			if(n_old_f.is_wire || n_old_f.is_wire_connector) {
128 				removeWire(pos);
129 			}
130 			addElement(pos);
131 		}
132 	} else {
133 		if(n_old_f.is_circuit_element) {
134 			removeElement(pos);
135 		} else if(n_old_f.is_wire || n_old_f.is_wire_connector) {
136 			removeWire(pos);
137 		}
138 		if(n_new_f.is_wire) {
139 			addWire(pos);
140 		}
141 	}
142 }
143 
addElement(v3POS pos)144 void Circuit::addElement(v3POS pos) {
145 	auto lock = m_elements_mutex.lock_unique_rec();
146 
147 	bool already_existed[6];
148 	bool connected_faces[6] = {0};
149 
150 	std::vector <std::pair <std::list <CircuitElement>::iterator, u8> > connected;
151 	MapNode node = m_map->getNodeNoEx(pos);
152 
153 	auto current_element_iterator = m_elements.insert(m_elements.begin(),
154 	     CircuitElement(pos, m_max_id++, m_ndef->get(node).circuit_element_delay));
155 	m_pos_to_iterator[pos] = current_element_iterator;
156 
157 	// For each face add all other connected faces.
158 	for(int i = 0; i < 6; ++i) {
159 		if(!connected_faces[i]) {
160 			connected.clear();
161 			CircuitElement::findConnectedWithFace(connected, m_map, m_ndef, pos, SHIFT_TO_FACE(i), m_pos_to_iterator, connected_faces);
162 			if(connected.size() > 0) {
163 				std::list <CircuitElementVirtual>::iterator virtual_element_it;
164 				bool found = false;
165 				for(auto j = connected.begin(); j != connected.end(); ++j) {
166 					if(j->first->getFace(j->second).is_connected) {
167 						virtual_element_it = j->first->getFace(j->second).list_pointer;
168 						found = true;
169 						break;
170 					}
171 				}
172 
173 				// If virtual element already exist
174 				if(found) {
175 					already_existed[i] = true;
176 				} else {
177 					already_existed[i] = false;
178 					virtual_element_it = m_virtual_elements.insert(m_virtual_elements.begin(),
179 					                     CircuitElementVirtual(m_max_virtual_id++));
180 				}
181 
182 				std::list <CircuitElementVirtualContainer>::iterator it;
183 				for(auto j = connected.begin(); j != connected.end(); ++j) {
184 					if(!j->first->getFace(j->second).is_connected) {
185 						it = virtual_element_it->insert(virtual_element_it->begin(), CircuitElementVirtualContainer());
186 						it->shift = j->second;
187 						it->element_pointer = j->first;
188 						j->first->connectFace(j->second, it, virtual_element_it);
189 					}
190 				}
191 				it = virtual_element_it->insert(virtual_element_it->begin(), CircuitElementVirtualContainer());
192 				it->shift = i;
193 				it->element_pointer = current_element_iterator;
194 				current_element_iterator->connectFace(i, it, virtual_element_it);
195 			}
196 
197 		}
198 	}
199 
200 	for(int i = 0; i < 6; ++i) {
201 		if(current_element_iterator->getFace(i).is_connected && !already_existed[i]) {
202 			saveVirtualElement(current_element_iterator->getFace(i).list_pointer, true);
203 		}
204 	}
205 	saveElement(current_element_iterator, true);
206 
207 }
208 
removeElement(v3POS pos)209 void Circuit::removeElement(v3POS pos) {
210 	auto lock = m_elements_mutex.lock_unique_rec();
211 
212 	std::vector <std::list <CircuitElementVirtual>::iterator> virtual_elements_for_update;
213 	std::list <CircuitElement>::iterator current_element = m_pos_to_iterator[pos];
214 	m_database->del(itos(current_element->getId()));
215 
216 	current_element->getNeighbors(virtual_elements_for_update);
217 
218 	m_elements.erase(current_element);
219 
220 	for(auto i = virtual_elements_for_update.begin(); i != virtual_elements_for_update.end(); ++i) {
221 		if((*i)->size() > 1) {
222 			std::ostringstream out(std::ios_base::binary);
223 			(*i)->serialize(out);
224 			m_virtual_database->put(itos((*i)->getId()), out.str());
225 		} else {
226 			m_virtual_database->del(itos((*i)->getId()));
227 			std::list <CircuitElement>::iterator element_to_save;
228 			for(auto j = (*i)->begin(); j != (*i)->end(); ++j) {
229 				element_to_save = j->element_pointer;
230 			}
231 			m_virtual_elements.erase(*i);
232 			saveElement(element_to_save, false);
233 		}
234 	}
235 
236 	m_pos_to_iterator.erase(pos);
237 }
238 
addWire(v3POS pos)239 void Circuit::addWire(v3POS pos) {
240 	auto lock = m_elements_mutex.lock_unique_rec();
241 
242 	// This is used for converting elements of current_face_connected to their ids in all_connected.
243 	std::vector <std::pair <std::list <CircuitElement>::iterator, u8> > all_connected;
244 	std::vector <std::list <CircuitElementVirtual>::iterator> created_virtual_elements;
245 
246 	bool used[6][6];
247 	bool connected_faces[6];
248 
249 	MapNode node = m_map->getNode(pos);
250 	std::vector <std::pair <std::list <CircuitElement>::iterator, u8> > connected_to_face[6];
251 	for(int i = 0; i < 6; ++i) {
252 		CircuitElement::findConnectedWithFace(connected_to_face[i], m_map, m_ndef, pos, SHIFT_TO_FACE(i),
253 		                                      m_pos_to_iterator, connected_faces);
254 	}
255 
256 	for(int i = 0; i < 6; ++i) {
257 		for(int j = 0; j < 6; ++j) {
258 			used[i][j] = false;
259 		}
260 	}
261 
262 	// For each face connect faces, that are not yet connected.
263 	for(int i = 0; i < 6; ++i) {
264 		all_connected.clear();
265 		u8 acceptable_faces = m_ndef->get(node).wire_connections[i];
266 		for(int j = 0; j < 6; ++j) {
267 			if((acceptable_faces & (SHIFT_TO_FACE(j))) && !used[i][j]) {
268 				all_connected.insert(all_connected.end(), connected_to_face[j].begin(), connected_to_face[j].end());
269 				used[i][j] = true;
270 				used[j][i] = true;
271 			}
272 		}
273 
274 		if(all_connected.size() > 1) {
275 			CircuitElementContainer element_with_virtual;
276 			bool found_virtual = false;
277 			for(auto i = all_connected.begin(); i != all_connected.end(); ++i) {
278 				if(i->first->getFace(i->second).is_connected) {
279 					element_with_virtual = i->first->getFace(i->second);
280 					found_virtual = true;
281 					break;
282 				}
283 			}
284 
285 			if(found_virtual) {
286 				// Clear old connections (remove some virtual elements)
287 				for(auto i = all_connected.begin(); i != all_connected.end(); ++i) {
288 					if(i->first->getFace(i->second).is_connected
289 					        && (i->first->getFace(i->second).list_pointer != element_with_virtual.list_pointer)) {
290 						m_virtual_database->del(itos(i->first->getFace(i->second).list_pointer->getId()));
291 						i->first->disconnectFace(i->second);
292 						m_virtual_elements.erase(i->first->getFace(i->second).list_pointer);
293 					}
294 				}
295 			} else {
296 				element_with_virtual.list_pointer = m_virtual_elements.insert(m_virtual_elements.begin(),
297 				                                    CircuitElementVirtual(m_max_virtual_id++));
298 			}
299 			created_virtual_elements.push_back(element_with_virtual.list_pointer);
300 
301 			// Create new connections
302 			for(auto i = all_connected.begin(); i != all_connected.end(); ++i) {
303 				if(!(i->first->getFace(i->second).is_connected)) {
304 					auto it = element_with_virtual.list_pointer->insert(
305 						element_with_virtual.list_pointer->begin(), CircuitElementVirtualContainer());
306 					it->element_pointer = i->first;
307 					it->shift = i->second;
308 					i->first->connectFace(i->second, it, element_with_virtual.list_pointer);
309 				}
310 			}
311 		}
312 	}
313 
314 	for(u32 i = 0; i < created_virtual_elements.size(); ++i) {
315 		saveVirtualElement(created_virtual_elements[i], true);
316 	}
317 }
318 
removeWire(v3POS pos)319 void Circuit::removeWire(v3POS pos) {
320 	auto lock = m_elements_mutex.lock_unique_rec();
321 
322 	std::vector <std::pair <std::list <CircuitElement>::iterator, u8> > current_face_connected;
323 
324 	bool connected_faces[6];
325 	for(int i = 0; i < 6; ++i) {
326 		connected_faces[i] = false;
327 	}
328 
329 	// Find and remove virtual elements
330 	bool found_virtual_elements = false;
331 	for(int i = 0; i < 6; ++i) {
332 		if(!connected_faces[i]) {
333 			current_face_connected.clear();
334 			CircuitElement::findConnectedWithFace(current_face_connected, m_map, m_ndef, pos,
335 			                                      SHIFT_TO_FACE(i), m_pos_to_iterator, connected_faces);
336 			for(auto j = current_face_connected.begin(); j != current_face_connected.end(); ++j) {
337 				CircuitElementContainer current_edge = j->first->getFace(j->second);
338 				if(current_edge.is_connected) {
339 					found_virtual_elements = true;
340 					m_virtual_database->del(itos(current_edge.list_pointer->getId()));
341 					m_virtual_elements.erase(current_edge.list_pointer);
342 					break;
343 				}
344 			}
345 
346 			for(auto j = current_face_connected.begin(); j != current_face_connected.end(); ++j) {
347 				saveElement(j->first, false);
348 			}
349 		}
350 	}
351 
352 	for(int i = 0; i < 6; ++i) {
353 		connected_faces[i] = false;
354 	}
355 
356 	if(found_virtual_elements) {
357 		// Restore some previously deleted connections.
358 		for(int i = 0; i < 6; ++i) {
359 			if(!connected_faces[i]) {
360 				current_face_connected.clear();
361 				CircuitElement::findConnectedWithFace(current_face_connected, m_map, m_ndef, pos, SHIFT_TO_FACE(i),
362 				                                      m_pos_to_iterator, connected_faces);
363 
364 				if(current_face_connected.size() > 1) {
365 					auto new_virtual_element = m_virtual_elements.insert(
366 						m_virtual_elements.begin(), CircuitElementVirtual(m_max_virtual_id++));
367 
368 					for(u32 j = 0; j < current_face_connected.size(); ++j) {
369 						auto new_container = new_virtual_element->insert(
370 						            new_virtual_element->begin(), CircuitElementVirtualContainer());
371 						new_container->element_pointer = current_face_connected[j].first;
372 						new_container->shift = current_face_connected[j].second;
373 						current_face_connected[j].first->connectFace(current_face_connected[j].second,
374 						        new_container, new_virtual_element);
375 
376 						saveElement(current_face_connected[j].first, false);
377 					}
378 
379 					saveVirtualElement(new_virtual_element, false);
380 				}
381 			}
382 		}
383 	}
384 }
385 
update(float dtime)386 void Circuit::update(float dtime) {
387 	if(m_since_last_update > m_min_update_delay) {
388 		auto lock = m_elements_mutex.lock_unique_rec();
389 		m_since_last_update -= m_min_update_delay;
390 		// Each element send signal to other connected virtual elements.
391 		bool is_map_loaded = true;
392 		for(auto i = m_elements.begin(); i != m_elements.end(); ++i) {
393 			i->update();
394 		}
395 
396 		// Each virtual element send signal to other connected elements.
397 		for(auto i = m_virtual_elements.begin(); i != m_virtual_elements.end(); ++i) {
398 			i->update();
399 		}
400 
401 		// Update state of each element.
402 		for(auto i = m_elements.begin(); i != m_elements.end(); ++i) {
403 			if(!i->updateState(m_script, m_map, m_ndef)) {
404 				is_map_loaded = false;
405 				break;
406 			}
407 		}
408 		if(!is_map_loaded) {
409 			for(auto i = m_elements.begin(); i != m_elements.end(); ++i) {
410 				i->resetState();
411 			}
412 		}
413 	} else {
414 		m_since_last_update += dtime;
415 	}
416 }
417 
418 
swapElement(const MapNode & n_old,const MapNode & n_new,v3POS pos)419 void Circuit::swapElement(const MapNode& n_old, const MapNode& n_new, v3POS pos) {
420 	auto lock = m_elements_mutex.lock_unique_rec();
421 
422 	const ContentFeatures& n_old_features = m_ndef->get(n_old);
423 	const ContentFeatures& n_new_features = m_ndef->get(n_new);
424 	std::list <CircuitElement>::iterator current_element = m_pos_to_iterator[pos];
425 	current_element->swap(n_old, n_old_features, n_new, n_new_features);
426 	saveElement(current_element, false);
427 
428 }
429 
load()430 void Circuit::load() {
431 	u32 element_id;
432 	u32 version = 0;
433 	std::istringstream in(std::ios_base::binary);
434 
435 	m_database = new KeyValueStorage(m_savedir, "circuit");
436 	m_virtual_database = new KeyValueStorage(m_savedir, "circuit_virtual");
437 
438 	std::ifstream input_elements_states((m_savedir + DIR_DELIM + elements_states_file).c_str());
439 
440 	if(input_elements_states.good()) {
441 		input_elements_states.read(reinterpret_cast<char*>(&version), sizeof(version));
442 	}
443 #if USE_LEVELDB
444 	// Filling list with empty virtual elements
445 	auto virtual_it = m_virtual_database->new_iterator();
446 	std::map <u32, std::list <CircuitElementVirtual>::iterator> id_to_virtual_element;
447 	for(virtual_it->SeekToFirst(); virtual_it->Valid(); virtual_it->Next()) {
448 		element_id = stoi(virtual_it->key().ToString());
449 		id_to_virtual_element[element_id] =
450 		    m_virtual_elements.insert(m_virtual_elements.begin(), CircuitElementVirtual(element_id));
451 		if(element_id + 1 > m_max_virtual_id) {
452 			m_max_virtual_id = element_id + 1;
453 		}
454 	}
455 
456 	// Filling list with empty elements
457 	auto it = m_database->new_iterator();
458 	std::map <u32, std::list <CircuitElement>::iterator> id_to_element;
459 	for(it->SeekToFirst(); it->Valid(); it->Next()) {
460 		element_id = stoi(it->key().ToString());
461 		id_to_element[element_id] =
462 		    m_elements.insert(m_elements.begin(), CircuitElement(element_id));
463 		if(element_id + 1 > m_max_id) {
464 			m_max_id = element_id + 1;
465 		}
466 	}
467 
468 	// Loading states of elements
469 	if(input_elements_states.good()) {
470 		for(u32 i = 0; i < m_elements.size(); ++i) {
471 			input_elements_states.read(reinterpret_cast<char*>(&element_id), sizeof(element_id));
472 			if(id_to_element.find(element_id) != id_to_element.end()) {
473 				id_to_element[element_id]->deSerializeState(input_elements_states);
474 			} else {
475 				throw SerializationError(static_cast<std::string>("File \"")
476 				                         + elements_states_file + "\" seems to be corrupted.");
477 			}
478 		}
479 	}
480 
481 	// Loading elements data
482 	for(it->SeekToFirst(); it->Valid(); it->Next()) {
483 		in.str(it->value().ToString());
484 		element_id = stoi(it->key().ToString());
485 		auto current_element = id_to_element[element_id];
486 		current_element->deSerialize(in, id_to_virtual_element);
487 		m_pos_to_iterator[current_element->getPos()] = current_element;
488 	}
489 	delete it;
490 
491 	// Loading virtual elements data
492 	for(virtual_it->SeekToFirst(); virtual_it->Valid(); virtual_it->Next()) {
493 		in.str(virtual_it->value().ToString());
494 		element_id = stoi(virtual_it->key().ToString());
495 		auto current_element = id_to_virtual_element[element_id];
496 		current_element->deSerialize(in, current_element, id_to_element);
497 	}
498 
499 	delete virtual_it;
500 #endif
501 }
502 
save()503 void Circuit::save() {
504 	auto lock = m_elements_mutex.lock_shared_rec();
505 	std::ostringstream ostr(std::ios_base::binary);
506 	std::ofstream out((m_savedir + DIR_DELIM + elements_states_file).c_str(), std::ios_base::binary);
507 	out.write(reinterpret_cast<const char*>(&circuit_simulator_version), sizeof(circuit_simulator_version));
508 	for(std::list<CircuitElement>::iterator i = m_elements.begin(); i != m_elements.end(); ++i) {
509 		i->serializeState(ostr);
510 	}
511 	out << ostr.str();
512 }
513 
saveElement(std::list<CircuitElement>::iterator element,bool save_edges)514 inline void Circuit::saveElement(std::list<CircuitElement>::iterator element, bool save_edges) {
515 	std::ostringstream out(std::ios_base::binary);
516 	element->serialize(out);
517 	m_database->put(itos(element->getId()), out.str());
518 	if(save_edges) {
519 		for(int i = 0; i < 6; ++i) {
520 			CircuitElementContainer tmp_container = element->getFace(i);
521 			if(tmp_container.is_connected) {
522 				std::ostringstream out(std::ios_base::binary);
523 				tmp_container.list_pointer->serialize(out);
524 				m_virtual_database->put(itos(tmp_container.list_pointer->getId()), out.str());
525 			}
526 		}
527 	}
528 }
529 
saveVirtualElement(std::list<CircuitElementVirtual>::iterator element,bool save_edges)530 inline void Circuit::saveVirtualElement(std::list <CircuitElementVirtual>::iterator element, bool save_edges) {
531 	std::ostringstream out(std::ios_base::binary);
532 	element->serialize(out);
533 	m_virtual_database->put(itos(element->getId()), out.str());
534 	if(save_edges) {
535 		for(std::list <CircuitElementVirtualContainer>::iterator i = element->begin(); i != element->end(); ++i) {
536 			std::ostringstream out(std::ios_base::binary);
537 			i->element_pointer->serialize(out);
538 			m_database->put(itos(i->element_pointer->getId()), out.str());
539 		}
540 	}
541 }
542