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_element.h"
19 #include "nodedef.h"
20 #include "mapnode.h"
21 #include "map.h"
22 #include "scripting_game.h"
23 
24 #include <set>
25 #include <queue>
26 #include <iomanip>
27 #include <cassert>
28 #include <map>
29 
30 #define PP(x) ((x).X)<<" "<<((x).Y)<<" "<<((x).Z)<<" "
31 
32 u8 CircuitElement::face_to_shift[] = {
33 	0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
34 	4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5
35 };
36 
37 u8 CircuitElement::opposite_shift[] = {
38 	1, 0, 3, 2, 5, 4
39 };
40 
41 u8 CircuitElement::opposite_face[] = {
42 	0, 2, 1, 0, 8, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
43 	32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16
44 };
45 
46 u8 CircuitElement::rotate_face[] = {
47 	1, 1, 1, 1, 16, 16, 16, 16, 32, 32, 32, 32, 4, 4, 4, 4, 8, 8, 8, 8, 2, 2, 2, 2,
48 	2, 2, 2, 2, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8, 8, 4, 4, 4, 4, 1, 1, 1, 1,
49 	4, 32, 8, 16, 4, 1, 8, 2, 4, 2, 8, 1, 2, 32, 1, 16, 1, 32, 2, 16, 8, 32, 4, 16,
50 	8, 16, 4, 32, 8, 2, 4, 1, 8, 1, 4, 2, 1, 16, 2, 32, 2, 16, 1, 32, 4, 16, 8, 32,
51 	16, 4, 32, 8, 2, 4, 1, 8, 1, 4, 2, 8, 16, 2, 32, 1, 16, 1, 32, 2, 16, 8, 32, 4,
52 	32, 8, 16, 4, 1, 8, 2, 4, 2, 8, 1, 4, 32, 1, 16, 2, 32, 2, 16, 1, 32, 4, 16, 8,
53 };
54 
55 u8 CircuitElement::reverse_rotate_face[] = {
56 	1, 1, 1, 1, 32, 4, 16, 8, 16, 8, 32, 4, 8, 32, 4, 16, 4, 16, 8, 32, 2, 2, 2, 2,
57 	2, 2, 2, 2, 16, 8, 32, 4, 32, 4, 16, 8, 4, 16, 8, 32, 8, 32, 4, 16, 1, 1, 1, 1,
58 	4, 16, 8, 32, 4, 16, 8, 32, 4, 16, 8, 32, 1, 1, 1, 1, 2, 2, 2, 2, 8, 32, 4, 16,
59 	8, 32, 4, 16, 8, 32, 4, 16, 8, 32, 4, 16, 2, 2, 2, 2, 1, 1, 1, 1, 4, 16, 8, 32,
60 	16, 8, 32, 4, 1, 1, 1, 1, 2, 2, 2, 2, 16, 8, 32, 4, 16, 8, 32, 4, 16, 8, 32, 4,
61 	32, 4, 16, 8, 2, 2, 2, 2, 1, 1, 1, 1, 32, 4, 16, 8, 32, 4, 16, 8, 32, 4, 16, 8,
62 };
63 
CircuitElement(v3POS pos,u32 element_id,u8 delay)64 CircuitElement::CircuitElement(v3POS pos, u32 element_id, u8 delay) :
65 	m_pos(pos), m_prev_input_state(0), m_current_input_state(0),
66 	m_next_input_state(0), m_current_output_state(0){
67 	m_element_id = element_id;
68 	for(int i = 0; i < 6; ++i) {
69 		m_faces[i].is_connected = false;
70 	}
71 	setDelay(delay);
72 #ifdef CIRCUIT_DEBUG
73 	dstream << (OPPOSITE_FACE(FACE_TOP) == FACE_BOTTOM);
74 	dstream << (OPPOSITE_FACE(FACE_BACK) == FACE_FRONT);
75 	dstream << (OPPOSITE_FACE(FACE_LEFT) == FACE_RIGHT);
76 	dstream << (OPPOSITE_FACE(FACE_BOTTOM) == FACE_TOP);
77 	dstream << (OPPOSITE_FACE(FACE_FRONT) == FACE_BACK);
78 	dstream << (OPPOSITE_FACE(FACE_RIGHT) == FACE_LEFT);
79 	dstream << std::endl;
80 #endif
81 }
82 
CircuitElement(const CircuitElement & element)83 CircuitElement::CircuitElement(const CircuitElement& element) {
84 	m_pos = element.m_pos;
85 	m_element_id = element.m_element_id;
86 	m_prev_input_state = element.m_prev_input_state;
87 	m_current_input_state = element.m_current_input_state;
88 	m_next_input_state = element.m_next_input_state;
89 	m_current_output_state = element.m_current_output_state;
90 	for(int i = 0; i < 6; ++i) {
91 		m_faces[i].list_iterator = element.m_faces[i].list_iterator;
92 		m_faces[i].list_pointer  = element.m_faces[i].list_pointer;
93 		m_faces[i].is_connected  = element.m_faces[i].is_connected;
94 	}
95 	setDelay(element.m_states_queue.size());
96 }
97 
CircuitElement(u32 element_id)98 CircuitElement::CircuitElement(u32 element_id) :
99 	m_pos(v3POS(0, 0, 0)), m_prev_input_state(0), m_current_input_state(0),
100 	m_next_input_state(0), m_current_output_state(0) {
101 	m_element_id = element_id;
102 	for(int i = 0; i < 6; ++i) {
103 		m_faces[i].is_connected = false;
104 	}
105 }
106 
~CircuitElement()107 CircuitElement::~CircuitElement() {
108 	for(int i = 0; i < 6; ++i) {
109 		if(m_faces[i].is_connected) {
110 			m_faces[i].list_pointer->erase(m_faces[i].list_iterator);
111 		}
112 	}
113 }
114 
update()115 void CircuitElement::update() {
116 	if(m_current_output_state) {
117 		for(int i = 0; i < 6; ++i) {
118 			if(m_faces[i].is_connected) {
119 				m_faces[i].list_pointer->addState(static_cast<bool>(m_current_output_state & SHIFT_TO_FACE(i)));
120 			}
121 		}
122 	}
123 }
124 
updateState(GameScripting * m_script,Map * map,INodeDefManager * ndef)125 bool CircuitElement::updateState(GameScripting* m_script, Map* map, INodeDefManager* ndef) {
126 	MapNode node = map->getNodeNoEx(m_pos);
127 	// Map not yet loaded
128 	if(!node) {
129 		dstream << "Circuit simulator: Waiting for map blocks loading..." << std::endl;
130 		return false;
131 	}
132 	const ContentFeatures& node_features = ndef->get(node);
133 	// Update delay (may be not synchronized)
134 	u32 delay = node_features.circuit_element_delay;
135 	if(delay != m_states_queue.size()) {
136 		setDelay(delay);
137 	}
138 	m_states_queue.push_back(m_next_input_state);
139 	m_next_input_state = m_states_queue.front();
140 	m_states_queue.pop_front();
141 	m_current_output_state = node_features.circuit_element_func[m_next_input_state];
142 	if(m_next_input_state && !m_current_input_state && node_features.has_on_activate) {
143 		m_script->node_on_activate(m_pos, node);
144 	}
145 	if(!m_next_input_state && m_current_input_state && node_features.has_on_deactivate) {
146 		m_script->node_on_deactivate(m_pos, node);
147 	}
148 	m_prev_input_state = m_current_input_state;
149 	m_current_input_state = m_next_input_state;
150 	m_next_input_state = 0;
151 	return true;
152 }
153 
resetState()154 void CircuitElement::resetState() {
155 	m_next_input_state = 0;
156 	m_current_input_state = m_prev_input_state;
157 }
158 
serialize(std::ostream & out) const159 void CircuitElement::serialize(std::ostream& out) const {
160 	out.write(reinterpret_cast<const char*>(&m_pos), sizeof(m_pos));
161 	for(int i = 0; i < 6; ++i) {
162 		u32 tmp = 0;
163 		if(m_faces[i].is_connected) {
164 			tmp = m_faces[i].list_pointer->getId();
165 		}
166 		out.write(reinterpret_cast<const char*>(&tmp), sizeof(tmp));
167 	}
168 }
169 
serializeState(std::ostream & out) const170 void CircuitElement::serializeState(std::ostream& out) const {
171 	out.write(reinterpret_cast<const char*>(&m_element_id), sizeof(m_element_id));
172 	out.write(reinterpret_cast<const char*>(&m_current_input_state), sizeof(m_current_input_state));
173 	out.write(reinterpret_cast<const char*>(&m_current_output_state), sizeof(m_current_output_state));
174 	u32 queue_size = m_states_queue.size();
175 	out.write(reinterpret_cast<const char*>(&queue_size), sizeof(queue_size));
176 	for(auto i = m_states_queue.begin(); i != m_states_queue.end(); ++i) {
177 		out.write(reinterpret_cast<const char*>(&(*i)), sizeof(*i));
178 	}
179 }
180 
deSerialize(std::istream & in,std::map<u32,std::list<CircuitElementVirtual>::iterator> & id_to_virtual_pointer)181 void CircuitElement::deSerialize(std::istream& in,
182                                  std::map <u32, std::list <CircuitElementVirtual>::iterator>& id_to_virtual_pointer) {
183 	u32 current_element_id;
184 	in.read(reinterpret_cast<char*>(&m_pos), sizeof(m_pos));
185 	for(int i = 0; i < 6; ++i) {
186 		in.read(reinterpret_cast<char*>(&current_element_id), sizeof(current_element_id));
187 		if(current_element_id > 0) {
188 			m_faces[i].list_pointer = id_to_virtual_pointer[current_element_id];
189 			m_faces[i].is_connected = true;
190 		} else {
191 			m_faces[i].is_connected = false;
192 		}
193 	}
194 }
195 
deSerializeState(std::istream & in)196 void CircuitElement::deSerializeState(std::istream& in) {
197 	u32 queue_size;
198 	u8 input_state;
199 	in.read(reinterpret_cast<char*>(&m_current_input_state), sizeof(m_current_input_state));
200 	in.read(reinterpret_cast<char*>(&m_current_output_state), sizeof(m_current_output_state));
201 	in.read(reinterpret_cast<char*>(&queue_size), sizeof(queue_size));
202 	for(u32 i = 0; i < queue_size; ++i) {
203 		in.read(reinterpret_cast<char*>(&input_state), sizeof(input_state));
204 		m_states_queue.push_back(input_state);
205 	}
206 }
207 
getNeighbors(std::vector<std::list<CircuitElementVirtual>::iterator> & neighbors) const208 void CircuitElement::getNeighbors(std::vector <std::list <CircuitElementVirtual>::iterator>& neighbors) const {
209 	for(int i = 0; i < 6; ++i) {
210 		if(m_faces[i].is_connected) {
211 			bool found = false;
212 			for(auto j = neighbors.begin(); j != neighbors.end(); ++j) {
213 				if(*j == m_faces[i].list_pointer) {
214 					found = true;
215 					break;
216 				}
217 			}
218 			if(!found) {
219 				neighbors.push_back(m_faces[i].list_pointer);
220 			}
221 		}
222 	}
223 }
224 
findConnectedWithFace(std::vector<std::pair<std::list<CircuitElement>::iterator,u8>> & connected,Map * map,INodeDefManager * ndef,v3POS pos,u8 face,std::map<v3POS,std::list<CircuitElement>::iterator> & pos_to_iterator,bool connected_faces[6])225 void CircuitElement::findConnectedWithFace(std::vector <std::pair <std::list<CircuitElement>::iterator, u8> >& connected,
226         Map* map, INodeDefManager* ndef, v3POS pos, u8 face,
227         std::map<v3POS, std::list<CircuitElement>::iterator>& pos_to_iterator,
228         bool connected_faces[6]) {
229 	static v3POS directions[6] = {v3POS(0, 1, 0),
230 	                              v3POS(0, -1, 0),
231 	                              v3POS(1, 0, 0),
232 	                              v3POS(-1, 0, 0),
233 	                              v3POS(0, 0, 1),
234 	                              v3POS(0, 0, -1),
235 	                             };
236 	// First - wire pos, second - acceptable faces
237 	std::queue <std::pair <v3POS, u8> > q;
238 	v3POS current_pos, next_pos;
239 	MapNode next_node, current_node;
240 	// used[pos] = or of all faces, that are already processed
241 	std::map <v3POS, u8> used;
242 	u8 face_id = FACE_TO_SHIFT(face);
243 	connected_faces[face_id] = true;
244 	used[pos] = face;
245 	current_node = map->getNodeNoEx(pos);
246 	const ContentFeatures& first_node_features = ndef->get(current_node);
247 	face = rotateFace(current_node, first_node_features, face);
248 	face_id = FACE_TO_SHIFT(face);
249 
250 	current_pos = pos + directions[face_id];
251 	current_node = map->getNodeNoEx(current_pos);
252 	const ContentFeatures& current_node_features = ndef->get(current_node);
253 	u8 real_face = revRotateFace(current_node, current_node_features, face);
254 	u8 real_face_id = FACE_TO_SHIFT(real_face);
255 
256 	if(current_node_features.is_wire || current_node_features.is_wire_connector) {
257 		q.push(std::make_pair(current_pos, current_node_features.wire_connections[real_face_id]));
258 
259 		while(!q.empty()) {
260 			current_pos = q.front().first;
261 			u8 acceptable_faces = q.front().second;
262 			q.pop();
263 			current_node = map->getNodeNoEx(current_pos);
264 			const ContentFeatures& current_node_features = ndef->get(current_node);
265 
266 			for(int i = 0; i < 6; ++i) {
267 				u8 real_face = revRotateFace(current_node, current_node_features, SHIFT_TO_FACE(i));
268 				if(acceptable_faces & real_face) {
269 					used[current_pos] |= real_face;
270 					next_pos = current_pos + directions[i];
271 					next_node = map->getNodeNoEx(next_pos);
272 					const ContentFeatures& node_features = ndef->get(next_node);
273 					u8 next_real_face = revRotateFace(next_node, node_features, OPPOSITE_FACE(SHIFT_TO_FACE(i)));
274 					u8 next_real_shift = FACE_TO_SHIFT(next_real_face);
275 
276 					// If start element, mark some of it's faces
277 					if(next_pos == pos) {
278 						connected_faces[next_real_shift] = true;
279 					}
280 
281 					auto next_used_iterator = used.find(next_pos);
282 					bool is_part_of_circuit = node_features.is_wire_connector || node_features.is_circuit_element ||
283 						(node_features.is_wire && (next_node.getContent() == current_node.getContent()));
284 					bool not_used = (next_used_iterator == used.end()) ||
285 						!(next_used_iterator->second & next_real_face);
286 
287 					if(is_part_of_circuit && not_used) {
288 						if(node_features.is_circuit_element) {
289 							connected.push_back(std::make_pair(pos_to_iterator[next_pos], next_real_shift));
290 						} else {
291 							q.push(std::make_pair(next_pos, node_features.wire_connections[next_real_shift]));
292 						}
293 
294 						if(next_used_iterator != used.end()) {
295 							next_used_iterator->second |= next_real_face;
296 						} else {
297 							used[next_pos] = next_real_face;
298 						}
299 					}
300 				}
301 			}
302 		}
303 	} else if(current_node_features.is_circuit_element) {
304 		connected.push_back(std::make_pair(pos_to_iterator[current_pos], OPPOSITE_SHIFT(real_face_id)));
305 	}
306 }
307 
getFace(int id) const308 CircuitElementContainer CircuitElement::getFace(int id) const
309 {
310 	return m_faces[id];
311 }
312 
getPos() const313 v3POS CircuitElement::getPos() const {
314 	return m_pos;
315 }
316 
getId() const317 u32 CircuitElement::getId() const {
318 	return m_element_id;
319 }
320 
connectFace(int id,std::list<CircuitElementVirtualContainer>::iterator it,std::list<CircuitElementVirtual>::iterator pt)321 void CircuitElement::connectFace(int id, std::list <CircuitElementVirtualContainer>::iterator it,
322                                  std::list <CircuitElementVirtual>::iterator pt) {
323 	m_faces[id].list_iterator = it;
324 	m_faces[id].list_pointer  = pt;
325 	m_faces[id].is_connected  = true;
326 }
327 
disconnectFace(int id)328 void CircuitElement::disconnectFace(int id) {
329 	m_faces[id].is_connected = false;
330 }
331 
setId(u32 id)332 void CircuitElement::setId(u32 id) {
333 	m_element_id = id;
334 }
335 
setInputState(u8 state)336 void CircuitElement::setInputState(u8 state) {
337 	m_current_input_state = state;
338 }
339 
setDelay(u8 delay)340 void CircuitElement::setDelay(u8 delay) {
341 	if(m_states_queue.size() >= delay) {
342 		while(m_states_queue.size() > delay) {
343 			m_states_queue.pop_front();
344 		}
345 	} else {
346 		while(m_states_queue.size() < delay) {
347 			m_states_queue.push_back(0);
348 		}
349 	}
350 }
351 
swap(const MapNode & n_old,const ContentFeatures & n_old_features,const MapNode & n_new,const ContentFeatures & n_new_features)352 void CircuitElement::swap(const MapNode& n_old, const ContentFeatures& n_old_features,
353                           const MapNode& n_new, const ContentFeatures& n_new_features) {
354 	CircuitElementContainer tmp_faces[6];
355 	for(int i = 0; i < 6; ++i) {
356 		u8 shift = FACE_TO_SHIFT(rotateFace(n_old, n_old_features, SHIFT_TO_FACE(i)));
357 		tmp_faces[shift] = m_faces[i];
358 	}
359 	for(int i = 0; i < 6; ++i) {
360 		u8 shift = FACE_TO_SHIFT(revRotateFace(n_new, n_new_features, SHIFT_TO_FACE(i)));
361 		m_faces[shift] = tmp_faces[i];
362 		if(m_faces[shift].is_connected) {
363 			m_faces[shift].list_iterator->shift = shift;
364 		}
365 	}
366 	setDelay(n_new_features.circuit_element_delay);
367 }
368