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); }
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))); } } } }
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))); } }
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); }
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(); } }
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); } } } } }
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)))); } }