Beispiel #1
0
void CircuitElement::swap(const MapNode& n_old, const ContentFeatures& n_old_features,
                          const MapNode& n_new, const ContentFeatures& n_new_features) {
	CircuitElementContainer tmp_faces[6];
	for(int i = 0; i < 6; ++i) {
		u8 shift = FACE_TO_SHIFT(rotateFace(n_old, n_old_features, SHIFT_TO_FACE(i)));
		tmp_faces[shift] = m_faces[i];
	}
	for(int i = 0; i < 6; ++i) {
		u8 shift = FACE_TO_SHIFT(revRotateFace(n_new, n_new_features, SHIFT_TO_FACE(i)));
		m_faces[shift] = tmp_faces[i];
		if(m_faces[shift].is_connected) {
			m_faces[shift].list_iterator->shift = shift;
		}
	}
	setDelay(n_new_features.circuit_element_delay);
}
Beispiel #2
0
void CircuitElement::update() {
	if(m_current_output_state) {
		for(int i = 0; i < 6; ++i) {
			if(m_faces[i].is_connected) {
				m_faces[i].list_pointer->addState(static_cast<bool>(m_current_output_state & SHIFT_TO_FACE(i)));
			}
		}
	}
}
Beispiel #3
0
void CircuitElement::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]) {
	static v3POS directions[6] = {v3POS(0, 1, 0),
	                              v3POS(0, -1, 0),
	                              v3POS(1, 0, 0),
	                              v3POS(-1, 0, 0),
	                              v3POS(0, 0, 1),
	                              v3POS(0, 0, -1),
	                             };
	// First - wire pos, second - acceptable faces
	std::queue <std::pair <v3POS, u8> > q;
	v3POS current_pos, next_pos;
	MapNode next_node, current_node;
	// used[pos] = or of all faces, that are already processed
	std::map <v3POS, u8> used;
	u8 face_id = FACE_TO_SHIFT(face);
	connected_faces[face_id] = true;
	used[pos] = face;
	current_node = map->getNodeNoEx(pos);
	const ContentFeatures& first_node_features = ndef->get(current_node);
	face = rotateFace(current_node, first_node_features, face);
	face_id = FACE_TO_SHIFT(face);

	current_pos = pos + directions[face_id];
	current_node = map->getNodeNoEx(current_pos);
	const ContentFeatures& current_node_features = ndef->get(current_node);
	u8 real_face = revRotateFace(current_node, current_node_features, face);
	u8 real_face_id = FACE_TO_SHIFT(real_face);

	if(current_node_features.is_wire || current_node_features.is_wire_connector) {
		q.push(std::make_pair(current_pos, current_node_features.wire_connections[real_face_id]));

		while(!q.empty()) {
			current_pos = q.front().first;
			u8 acceptable_faces = q.front().second;
			q.pop();
			current_node = map->getNodeNoEx(current_pos);
			const ContentFeatures& current_node_features = ndef->get(current_node);

			for(int i = 0; i < 6; ++i) {
				u8 real_face = revRotateFace(current_node, current_node_features, SHIFT_TO_FACE(i));
				if(acceptable_faces & real_face) {
					used[current_pos] |= real_face;
					next_pos = current_pos + directions[i];
					next_node = map->getNodeNoEx(next_pos);
					const ContentFeatures& node_features = ndef->get(next_node);
					u8 next_real_face = revRotateFace(next_node, node_features, OPPOSITE_FACE(SHIFT_TO_FACE(i)));
					u8 next_real_shift = FACE_TO_SHIFT(next_real_face);

					// If start element, mark some of it's faces
					if(next_pos == pos) {
						connected_faces[next_real_shift] = true;
					}

					auto next_used_iterator = used.find(next_pos);
					bool is_part_of_circuit = node_features.is_wire_connector || node_features.is_circuit_element ||
						(node_features.is_wire && (next_node.getContent() == current_node.getContent()));
					bool not_used = (next_used_iterator == used.end()) ||
						!(next_used_iterator->second & next_real_face);

					if(is_part_of_circuit && not_used) {
						if(node_features.is_circuit_element) {
							connected.push_back(std::make_pair(pos_to_iterator[next_pos], next_real_shift));
						} else {
							q.push(std::make_pair(next_pos, node_features.wire_connections[next_real_shift]));
						}

						if(next_used_iterator != used.end()) {
							next_used_iterator->second |= next_real_face;
						} else {
							used[next_pos] = next_real_face;
						}
					}
				}
			}
		}
	} else if(current_node_features.is_circuit_element) {
		connected.push_back(std::make_pair(pos_to_iterator[current_pos], OPPOSITE_SHIFT(real_face_id)));
	}
}
Beispiel #4
0
void Circuit::addElement(Map& map, INodeDefManager* ndef, v3s16 pos, const unsigned char* func) {
	JMutexAutoLock lock(m_elements_mutex);

	bool already_existed[6];
	bool connected_faces[6] = {0};

	std::vector <std::pair <std::list <CircuitElement>::iterator, int > > connected;
	MapNode node = map.getNode(pos);

	std::pair <const unsigned char*, unsigned long> node_func;
	if(ndef->get(node).param_type_2 == CPT2_FACEDIR) {
		// If block is rotatable, then rotate it's function.
		node_func = m_circuit_elements_states.addState(func, node.param2);
	} else {
		node_func = m_circuit_elements_states.addState(func);
	}
	saveCircuitElementsStates();
	std::list <CircuitElement>::iterator current_element_iterator =
	    m_elements.insert(m_elements.begin(), CircuitElement(pos, node_func.first, node_func.second,
	                      m_max_id++, ndef->get(node).circuit_element_delay));
	m_pos_to_iterator[pos] = current_element_iterator;

	// For each face add all other connected faces.
	for(int i = 0; i < 6; ++i) {
		if(!connected_faces[i]) {
			connected.clear();
			CircuitElement::findConnectedWithFace(connected, map, ndef, pos, SHIFT_TO_FACE(i), m_pos_to_iterator, connected_faces);
			if(connected.size() > 0) {
				std::list <CircuitElementVirtual>::iterator virtual_element_it;
				bool found = false;
				for(std::vector <std::pair <std::list <CircuitElement>::iterator, int> >::iterator j = connected.begin();
				        j != connected.end(); ++j) {
					if(j->first->getFace(j->second).is_connected) {
						virtual_element_it = j->first->getFace(j->second).list_pointer;
						found = true;
						break;
					}
				}

				// If virtual element already exist
				if(found) {
					already_existed[i] = true;
				} else {
					already_existed[i] = false;
					virtual_element_it = m_virtual_elements.insert(m_virtual_elements.begin(),
					                     CircuitElementVirtual(m_max_virtual_id++));
				}

				std::list <CircuitElementVirtualContainer>::iterator it;
				for(std::vector <std::pair <std::list <CircuitElement>::iterator, int> >::iterator j = connected.begin();
				        j != connected.end(); ++j) {
					if(!j->first->getFace(j->second).is_connected) {
						it = virtual_element_it->insert(virtual_element_it->begin(), CircuitElementVirtualContainer());
						it->shift = j->second;
						it->element_pointer = j->first;
						j->first->connectFace(j->second, it, virtual_element_it);
					}
				}
				it = virtual_element_it->insert(virtual_element_it->begin(), CircuitElementVirtualContainer());
				it->shift = i;
				it->element_pointer = current_element_iterator;
				current_element_iterator->connectFace(i, it, virtual_element_it);
			}

		}
	}

	for(int i = 0; i < 6; ++i) {
		if(current_element_iterator->getFace(i).is_connected && !already_existed[i]) {
			saveVirtualElement(current_element_iterator->getFace(i).list_pointer, true);
		}
	}
	saveElement(current_element_iterator, true);
}
Beispiel #5
0
void Circuit::processElementsQueue(Map& map, INodeDefManager* ndef) {
	if(m_elements_queue.size() > 0) {
		JMutexAutoLock lock(m_elements_mutex);

		std::vector <std::pair <std::list <CircuitElement>::iterator, int> > connected;
		std::vector <std::list <CircuitElementVirtual>::iterator> created_virtual_elements;
		MapNode node;
		bool connected_faces[6];

		// Filling with empty elements
		for(unsigned int i = 0; i < m_elements_queue.size(); ++i) {
			node = map.getNode(m_elements_queue[i]);
			std::pair <const unsigned char*, unsigned long> node_func;
			if(ndef->get(node).param_type_2 == CPT2_FACEDIR) {
				node_func = m_circuit_elements_states.addState(ndef->get(node).circuit_element_states, node.param2);
			} else {
				node_func = m_circuit_elements_states.addState(ndef->get(node).circuit_element_states);
			}
			m_pos_to_iterator[m_elements_queue[i]] = m_elements.insert(m_elements.begin(),
			        CircuitElement(m_elements_queue[i],
			                       node_func.first, node_func.second,
			                       m_max_id++, ndef->get(node).circuit_element_delay));
		}

		for(unsigned int i = 0; i < m_elements_queue.size(); ++i) {
			v3s16 pos = m_elements_queue[i];
			std::list <CircuitElement>::iterator current_element_it = m_pos_to_iterator[pos];
			for(int j = 0; j < 6; ++j) {
				connected_faces[j] = false;
			}
			for(int j = 0; j < 6; ++j) {
				if(!current_element_it->getFace(j).is_connected && !connected_faces[j]) {
					connected.clear();
					CircuitElement::findConnectedWithFace(connected, map, ndef, pos, SHIFT_TO_FACE(j),
					                                      m_pos_to_iterator, connected_faces);

					if(!connected.empty()) {
						std::list <CircuitElementVirtual>::iterator virtual_element_it;
						bool found = false;
						for(std::vector <std::pair <std::list <CircuitElement>::iterator, int> >::iterator k = connected.begin();
						        k != connected.end(); ++k) {
							if(k->first->getFace(k->second).is_connected) {
								virtual_element_it = k->first->getFace(k->second).list_pointer;
								found = true;
								break;
							}
						}

						if(!found) {
							virtual_element_it = m_virtual_elements.insert(m_virtual_elements.begin(),
							                     CircuitElementVirtual(m_max_virtual_id++));
						}

						std::list <CircuitElementVirtualContainer>::iterator it;
						for(std::vector <std::pair <std::list <CircuitElement>::iterator, int> >::iterator k = connected.begin();
						        k != connected.end(); ++k) {
							if(!k->first->getFace(k->second).is_connected) {
								it = virtual_element_it->insert(virtual_element_it->begin(), CircuitElementVirtualContainer());
								it->shift = k->second;
								it->element_pointer = k->first;
								k->first->connectFace(k->second, it, virtual_element_it);
							}
						}
						it = virtual_element_it->insert(virtual_element_it->begin(), CircuitElementVirtualContainer());
						it->shift = j;
						it->element_pointer = current_element_it;
						current_element_it->connectFace(j, it, virtual_element_it);
					}
				}
			}
		}

		for(unsigned int i = 0; i < created_virtual_elements.size(); ++i) {
			saveVirtualElement(created_virtual_elements[i], true);
		}

		for(unsigned int i = 0; i < m_elements_queue.size(); ++i) {
			saveElement(m_pos_to_iterator[m_elements_queue[i]], false);
		}

		m_elements_queue.clear();

		saveCircuitElementsStates();

	}
}
Beispiel #6
0
void Circuit::removeWire(Map& map, INodeDefManager* ndef, v3s16 pos, MapNode& node) {
	JMutexAutoLock lock(m_elements_mutex);

	std::vector <std::pair <std::list <CircuitElement>::iterator, int> > current_face_connected;

	bool connected_faces[6];
	for(int i = 0; i < 6; ++i) {
		connected_faces[i] = false;
	}

	// Find and remove virtual elements
	bool found_virtual_elements = false;
	for(int i = 0; i < 6; ++i) {
		if(!connected_faces[i]) {
			current_face_connected.clear();
			CircuitElement::findConnectedWithFace(current_face_connected, map, ndef, pos,
			                                      SHIFT_TO_FACE(i), m_pos_to_iterator, connected_faces);
			for(unsigned int j = 0; j < current_face_connected.size(); ++j) {
				CircuitElementContainer current_edge = current_face_connected[j].first->getFace(current_face_connected[j].second);
				if(current_edge.is_connected) {
					found_virtual_elements = true;
					m_virtual_database->del(itos(current_edge.list_pointer->getId()));

					m_virtual_elements.erase(current_edge.list_pointer);
					break;
				}
			}

			for(unsigned int j = 0; j < current_face_connected.size(); ++j) {
				saveElement(current_face_connected[j].first, false);
			}

		}
	}

	for(int i = 0; i < 6; ++i) {
		connected_faces[i] = false;
	}

	if(found_virtual_elements) {
		// Restore some previously deleted connections.
		for(int i = 0; i < 6; ++i) {
			if(!connected_faces[i]) {
				current_face_connected.clear();
				CircuitElement::findConnectedWithFace(current_face_connected, map, ndef, pos, SHIFT_TO_FACE(i),
				                                      m_pos_to_iterator, connected_faces);

				if(current_face_connected.size() > 1) {
					std::list <CircuitElementVirtual>::iterator new_virtual_element = m_virtual_elements.insert(
					            m_virtual_elements.begin(), CircuitElementVirtual(m_max_virtual_id++));

					for(unsigned int j = 0; j < current_face_connected.size(); ++j) {
						std::list <CircuitElementVirtualContainer>::iterator new_container = new_virtual_element->insert(
						            new_virtual_element->begin(), CircuitElementVirtualContainer());
						new_container->element_pointer = current_face_connected[j].first;
						new_container->shift = current_face_connected[j].second;
						current_face_connected[j].first->connectFace(current_face_connected[j].second,
						        new_container, new_virtual_element);

						saveElement(current_face_connected[j].first, false);
					}

					saveVirtualElement(new_virtual_element, false);
				}
			}
		}
	}
}
Beispiel #7
0
void Circuit::addWire(Map& map, INodeDefManager* ndef, v3s16 pos) {
	JMutexAutoLock lock(m_elements_mutex);

	// This is used for converting elements of current_face_connected to their ids in all_connected.
	std::vector <std::pair <std::list <CircuitElement>::iterator, int> > all_connected;
	std::vector <std::list <CircuitElementVirtual>::iterator> created_virtual_elements;

	bool used[6][6];
	bool connected_faces[6];
	for(int i = 0; i < 6; ++i) {
		for(int j = 0; j < 6; ++j) {
			used[i][j] = false;
		}
	}

	MapNode node = map.getNode(pos);

	// For each face connect faces, that are not yet connected.
	for(int i = 0; i < 6; ++i) {
		all_connected.clear();
		for(unsigned int j = 0; j < 6; ++j) {
			if((ndef->get(node).wire_connections[i] & (SHIFT_TO_FACE(j))) && !used[i][j]) {
				CircuitElement::findConnectedWithFace(all_connected, map, ndef, pos, SHIFT_TO_FACE(j),
				                                      m_pos_to_iterator, connected_faces);
				used[i][j] = true;
				used[j][i] = true;
			}
		}

		if(all_connected.size() > 1) {
			CircuitElementContainer element_with_virtual;
			bool found_virtual = false;
			for(std::vector <std::pair <std::list <CircuitElement>::iterator, int> >::iterator i = all_connected.begin();
			        i != all_connected.end(); ++i) {
				if(i->first->getFace(i->second).is_connected) {
					element_with_virtual = i->first->getFace(i->second);
					found_virtual = true;
					break;
				}
			}

			if(found_virtual) {
				// Clear old connections (remove some virtual elements)
				for(std::vector <std::pair <std::list <CircuitElement>::iterator, int> >::iterator i = all_connected.begin();
				        i != all_connected.end(); ++i) {
					if(i->first->getFace(i->second).is_connected
					        && (i->first->getFace(i->second).list_pointer != element_with_virtual.list_pointer)) {
						m_virtual_database->del(itos(i->first->getFace(i->second).list_pointer->getId()));
						i->first->disconnectFace(i->second);
						m_virtual_elements.erase(i->first->getFace(i->second).list_pointer);
					}
				}
			} else {
				element_with_virtual.list_pointer = m_virtual_elements.insert(m_virtual_elements.begin(),
				                                    CircuitElementVirtual(m_max_virtual_id++));
			}
			created_virtual_elements.push_back(element_with_virtual.list_pointer);

			// Create new connections
			for(std::vector <std::pair <std::list <CircuitElement>::iterator, int> >::iterator i = all_connected.begin();
			        i != all_connected.end(); ++i) {
				if(!(i->first->getFace(i->second).is_connected)) {
					std::list <CircuitElementVirtualContainer>::iterator it = element_with_virtual.list_pointer->insert(
					            element_with_virtual.list_pointer->begin(), CircuitElementVirtualContainer());
					it->element_pointer = i->first;
					it->shift = i->second;
					i->first->connectFace(i->second, it, element_with_virtual.list_pointer);
				}
			}
		}
	}

	for(unsigned int i = 0; i < created_virtual_elements.size(); ++i) {
		saveVirtualElement(created_virtual_elements[i], true);
	}
}
void CircuitElement::findConnectedWithFace(std::vector <std::pair <std::list<CircuitElement>::iterator, int > >& connected,
        Map& map, INodeDefManager* ndef, v3s16 pos, FaceId face,
        std::map<v3s16, std::list<CircuitElement>::iterator>& pos_to_iterator,
        bool connected_faces[6]) {
	static v3s16 directions[6] = {v3s16(0, -1, 0),
	                              v3s16(0, 0, 1),
	                              v3s16(-1, 0, 0),
	                              v3s16(0, 1, 0),
	                              v3s16(0, 0, -1),
	                              v3s16(1, 0, 0),
	                             };
	std::map <v3s16, unsigned char> used;
	used[pos] = face;
	std::queue <std::pair <v3s16, unsigned char> > q;
	v3s16 current_pos;
	v3s16 next_pos;
	std::map <v3s16, unsigned char>::iterator current_used_iterator;
	std::map <v3s16, unsigned char>::iterator tmp_used_iterator;
	ContentFeatures node_features, current_node_features;
	MapNode next_node, current_node;

	int face_id = FACE_TO_SHIFT(face);
	connected_faces[face_id] = true;
	current_pos.X = pos.X + directions[face_id].X;
	current_pos.Y = pos.Y + directions[face_id].Y;
	current_pos.Z = pos.Z + directions[face_id].Z;
	next_node = map.getNodeNoEx(current_pos);
	node_features = ndef->get(next_node);
	q.push(std::make_pair(current_pos, node_features.wire_connections[FACE_TO_SHIFT(OPPOSITE_FACE(face))]));

	if(ndef->get(map.getNodeNoEx(current_pos)).is_wire || ndef->get(map.getNodeNoEx(current_pos)).is_connector) {
		while(!q.empty()) {
			unsigned char acceptable_faces;
			current_pos = q.front().first;
			acceptable_faces = q.front().second;
			q.pop();

			for(int i = 0; i < 6; ++i) {
				if(acceptable_faces & (SHIFT_TO_FACE(i))) {
					next_pos.X = current_pos.X + directions[i].X;
					next_pos.Y = current_pos.Y + directions[i].Y;
					next_pos.Z = current_pos.Z + directions[i].Z;
					used[current_pos] |= SHIFT_TO_FACE(i);
					next_node = map.getNodeNoEx(next_pos);
					node_features = ndef->get(next_node);
					current_node = map.getNodeNoEx(current_pos);
					current_node_features = ndef->get(current_node);
					current_used_iterator = used.find(next_pos);

					// If start element, mark some of it's faces
					if(next_pos == pos) {
						connected_faces[OPPOSITE_SHIFT(i)] = true;
					}

					if((current_used_iterator == used.end()) ||
					        !(current_used_iterator->second & SHIFT_TO_FACE(OPPOSITE_SHIFT(i)))) {
						if(current_node_features.is_connector || node_features.is_connector
						        || (node_features.is_wire && (next_node.getContent() == current_node.getContent()))) {
							if(node_features.param_type_2 == CPT2_FACEDIR) {
								q.push(std::make_pair(next_pos, CircuitElementStates::rotateState(
								                          node_features.wire_connections[OPPOSITE_SHIFT(i)],
								                          FACEDIR_TO_FACE(next_node.param2))));
							} else {
								q.push(std::make_pair(next_pos, node_features.wire_connections[OPPOSITE_SHIFT(i)]));
							}
							tmp_used_iterator = used.find(next_pos);
							if(tmp_used_iterator != used.end()) {
								tmp_used_iterator->second |= SHIFT_TO_FACE(OPPOSITE_SHIFT(i));
							} else {
								used[next_pos] = SHIFT_TO_FACE(OPPOSITE_SHIFT(i));
							}
						}

						if(node_features.is_circuit_element) {
							tmp_used_iterator = used.find(next_pos);
							if(tmp_used_iterator != used.end()) {
								tmp_used_iterator->second |= SHIFT_TO_FACE(OPPOSITE_SHIFT(i));
							} else {
								used[next_pos] = SHIFT_TO_FACE(OPPOSITE_SHIFT(i));
							}
							connected.push_back(std::make_pair(pos_to_iterator[next_pos],
							                                   OPPOSITE_SHIFT(i)));
						}
					}
				}
			}
		}
	} else if(ndef->get(map.getNodeNoEx(current_pos)).is_circuit_element) {
		connected.push_back(std::make_pair(pos_to_iterator[current_pos],
		                                   FACE_TO_SHIFT(OPPOSITE_FACE(face))));
	}
}