소스 검색

Fix GraphEdit::arange_nodes causing a freeze

When a Graph contains cycles, e.g. 1->2->3->1 _layering would end
up in an infinite loop since IS_SUBSET would never be true.
By keeping check of the size of z, which contains the already layered
nodes, one can detect a freeze (since it should change after
current_layer increases. If it doesn't "u" didn't change and q and u
will  never be equal resulting  in a freeze/infinite while loop).
If a freeze happens warn the user and put all the nodes part of the
cycle (leftover in p) to the  first layer which will end up in them
being listed top to bottom.
tefusion 3 년 전
부모
커밋
f1c19e058c
1개의 변경된 파일14개의 추가작업 그리고 1개의 파일을 삭제
  1. 14 1
      scene/gui/graph_edit.cpp

+ 14 - 1
scene/gui/graph_edit.cpp

@@ -1823,7 +1823,20 @@ HashMap<int, Vector<StringName>> GraphEdit::_layering(const HashSet<StringName>
 		}
 		if (!selected) {
 			current_layer++;
+			uint32_t previous_size_z = z.size();
 			_set_operations(GraphEdit::UNION, z, u);
+			if (z.size() == previous_size_z) {
+				WARN_PRINT("Graph contains cycle(s). The cycle(s) will not be rearranged accurately.");
+				Vector<StringName> t;
+				if (l.has(0)) {
+					t.append_array(l[0]);
+				}
+				for (const StringName &E : p) {
+					t.push_back(E);
+				}
+				l.insert(0, t);
+				break;
+			}
 		}
 		selected = false;
 	}
@@ -2138,7 +2151,7 @@ void GraphEdit::arrange_nodes() {
 			HashSet<StringName> s;
 			for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
 				GraphNode *p_from = Object::cast_to<GraphNode>(node_names[E->get().from]);
-				if (E->get().to == gn->get_name() && p_from->is_selected()) {
+				if (E->get().to == gn->get_name() && p_from->is_selected() && E->get().to != E->get().from) {
 					if (!s.has(p_from->get_name())) {
 						s.insert(p_from->get_name());
 					}