summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortefusion <makotoprogr4mming@gmail.com>2022-08-02 21:11:19 +0200
committertefusion <makotoprogr4mming@gmail.com>2022-08-04 17:13:56 +0200
commitf1c19e058c67a0452a1743449821806b14d3cae6 (patch)
tree8bde18e9e25e6b45bd639f69778b52f1d99343f4
parent9f408aef4541888d61fe78c36e752d84f1769efc (diff)
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.
-rw-r--r--scene/gui/graph_edit.cpp15
1 files changed, 14 insertions, 1 deletions
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 42f434f0ac..09efee71a3 100644
--- a/scene/gui/graph_edit.cpp
+++ b/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());
}