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*>(¤t_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