瀏覽代碼

improved loop detection

Jonathan Higgins 3 月之前
父節點
當前提交
15d1f51109
共有 1 個文件被更改,包括 47 次插入5 次删除
  1. 47 5
      scenes/main/scripts/run_thread.gd

+ 47 - 5
scenes/main/scripts/run_thread.gd

@@ -199,7 +199,18 @@ func run_thread_with_branches():
 			graph[from].append(to)
 			reverse_graph[to].append(from)
 			indegree[to] += 1  # Count incoming edges
-
+			
+	# check for loops
+	var has_cycle := detect_cycles(graph, {})  # pass loop_nodes list later
+	if has_cycle:
+		log_console("[color=#9c2828][b]Error: Thread not valid[/b][/color]", true)
+		log_console("Threads cannot contain loops (except loop-iterator nodes).", true)
+		if progress_window.visible:
+			progress_window.hide()
+		if !console_window.visible:
+			console_window.popup_centered()
+		return
+		
 	# Step 3: Topological sort to get execution order
 	var sorted = []  # Sorted list of node names
 	var queue = []   # Queue of nodes with 0 indegree
@@ -217,10 +228,10 @@ func run_thread_with_branches():
 				queue.append(neighbor)
 
 	# If not all nodes were processed, there's a cycle
-	if sorted.size() != graph.size():
-		log_console("[color=#9c2828][b]Error: Thread not valid[/b][/color]", true)
-		log_console("Threads cannot contain loops.", true)
-		return
+	#if sorted.size() != graph.size():
+		#log_console("[color=#9c2828][b]Error: Thread not valid[/b][/color]", true)
+		#log_console("Threads cannot contain loops.", true)
+		#return
 	progress_bar.value = progress_step
 	# Step 4: Start processing audio
 
@@ -1239,3 +1250,34 @@ func monitor_process(pid: int, stdout: FileAccess, stderr: FileAccess) -> String
 			
 	process_running = false
 	return output
+
+# Main cycle detection
+func detect_cycles(graph: Dictionary, loop_nodes: Dictionary) -> bool:
+	var visited := {}
+	var stack := {}
+
+	for node in graph.keys():
+		if _dfs_cycle(node, graph, visited, stack, loop_nodes):
+			return true
+	return false
+	
+func _dfs_cycle(node: String, graph: Dictionary, visited: Dictionary, stack: Dictionary, loop_nodes: Dictionary) -> bool:
+	if not visited.has(node):
+		visited[node] = true
+		stack[node] = true
+
+		for neighbor in graph[node]:
+			# If neighbor hasn't been visited, recurse
+			if not visited.has(neighbor):
+				if _dfs_cycle(neighbor, graph, visited, stack, loop_nodes):
+					# Cycle found down this path
+					if not (loop_nodes.has(node) or loop_nodes.has(neighbor)):
+						return true
+			elif stack.has(neighbor):
+				# Back edge found → cycle
+				if not (loop_nodes.has(node) or loop_nodes.has(neighbor)):
+					return true
+
+	# Done exploring this node
+	stack.erase(node)
+	return false