Bläddra i källkod

reworked saving and loading to make it more robust

Jonathan Higgins 7 månader sedan
förälder
incheckning
c082aa01d5
4 ändrade filer med 219 tillägg och 33 borttagningar
  1. 11 0
      scenes/Nodes/node_logic.gd
  2. 0 0
      scenes/Nodes/node_logic.gd.uid
  3. 1 1
      scenes/Nodes/nodes.tscn
  4. 207 32
      scenes/main/control.gd

+ 11 - 0
scenes/Nodes/min_max_sliders.gd → scenes/Nodes/node_logic.gd

@@ -1,12 +1,20 @@
 extends GraphNode
 
 @export var min_gap: float = 0.5  # editable value in inspector for the minimum gap between min and max
+signal open_help
 
 func _ready() -> void:
 	var sliders := _get_all_hsliders(self) #finds all sliders
 	#links sliders to this script
 	for slider in sliders:
 		slider.value_changed.connect(_on_slider_value_changed.bind(slider))
+		
+	#add button to title bar
+	var titlebar = self.get_titlebar_hbox()
+	var btn = Button.new()
+	btn.text = "?"
+	btn.connect("pressed", Callable(self, "_open_help")) #pass key (process name) when button is pressed
+	titlebar.add_child(btn)
 
 func _get_all_hsliders(node: Node) -> Array:
 	#moves through all children recusively to find nested sliders
@@ -42,3 +50,6 @@ func _on_slider_value_changed(value: float, changed_slider: HSlider) -> void:
 			var min_value: float = other_slider.value
 			if changed_slider.value < min_value + min_gap:
 				changed_slider.value = min_value + min_gap
+
+func _open_help():
+	open_help.emit(self.get_meta("command"))

+ 0 - 0
scenes/Nodes/min_max_sliders.gd.uid → scenes/Nodes/node_logic.gd.uid


+ 1 - 1
scenes/Nodes/nodes.tscn

@@ -2,7 +2,7 @@
 
 [ext_resource type="PackedScene" uid="uid://csapiqka522fh" path="res://scenes/Nodes/audioplayer.tscn" id="2_b6nw4"]
 [ext_resource type="PackedScene" uid="uid://dya5kxx132fgp" path="res://scenes/Nodes/valueslider.tscn" id="3_b6nw4"]
-[ext_resource type="Script" uid="uid://cdbx1dt3ohqte" path="res://scenes/Nodes/min_max_sliders.gd" id="3_uv17x"]
+[ext_resource type="Script" uid="uid://cdbx1dt3ohqte" path="res://scenes/Nodes/node_logic.gd" id="3_uv17x"]
 
 [node name="Control" type="Control"]
 layout_mode = 3

+ 207 - 32
scenes/main/control.gd

@@ -99,14 +99,18 @@ func new_patch():
 		if node is GraphNode:
 			node.queue_free()
 	
+	await get_tree().process_frame  # Wait for nodes to actually be removed
+	
 	graph_edit.scroll_offset = Vector2(0, 0)
 	
 		#Generate input and output nodes
 	var effect: GraphNode = Nodes.get_node(NodePath("inputfile")).duplicate()
+	effect.name = "inputfile"
 	get_node("GraphEdit").add_child(effect, true)
 	effect.position_offset = Vector2(20,80)
 	
 	effect = Nodes.get_node(NodePath("outputfile")).duplicate()
+	effect.name = "outputfile"
 	get_node("GraphEdit").add_child(effect, true)
 	effect.position_offset = Vector2((DisplayServer.screen_get_size().x - 480) / uiscale, 80)
 	_register_node_movement() #link nodes for tracking position changes for changes tracking
@@ -327,6 +331,7 @@ func _make_node_from_search_menu(command: String):
 	#Find node with matching name to button and create a version of it in the graph edit
 	#and position it close to the origin right click to open the menu
 	var effect: GraphNode = Nodes.get_node(NodePath(command)).duplicate()
+	effect.name = command
 	get_node("GraphEdit").add_child(effect, true)
 	effect.set_position_offset((effect_position + graph_edit.scroll_offset) / graph_edit.zoom) #set node to current mouse position in graph edit
 	_register_inputs_in_node(effect) #link sliders for changes tracking
@@ -350,6 +355,7 @@ func _on_button_pressed(button: Button):
 	#Find node with matching name to button and create a version of it in the graph edit
 	#and position it close to the origin right click to open the menu
 	var effect: GraphNode = Nodes.get_node(NodePath(button.name)).duplicate()
+	effect.name = button.name
 	get_node("GraphEdit").add_child(effect, true)
 	effect.set_position_offset((effect_position + graph_edit.scroll_offset) / graph_edit.zoom) #set node to current mouse position in graph edit
 	_register_inputs_in_node(effect) #link sliders for changes tracking
@@ -1450,7 +1456,6 @@ func _on_file_button_index_pressed(index: int) -> void:
 			else:
 				$LoadDialog.popup_centered()
 
-
 func save_graph_edit(path: String):
 	var file = FileAccess.open(path, FileAccess.WRITE)
 	if file == null:
@@ -1459,45 +1464,59 @@ func save_graph_edit(path: String):
 
 	var node_data_list = []
 	var connection_data_list = []
+	var node_id_map = {}  # Map node name to numeric ID
 
+	var node_id = 1
+	# Assign each node a unique numeric ID and gather node data
 	for node in graph_edit.get_children():
 		if node is GraphNode:
+			node_id_map[node.name] = node_id
+
 			var offset = node.position_offset
 			var node_data = {
+				"id": node_id,
 				"name": node.name,
 				"command": node.get_meta("command"),
 				"offset": { "x": offset.x, "y": offset.y },
 				"slider_values": {},
-				"notes":{}
+				"notes": {}
 			}
 
+			# Save slider values and metadata
 			for child in node.find_children("*", "Slider", true, false):
 				var relative_path = node.get_path_to(child)
 				var path_str = str(relative_path)
 
-				# Save slider value
 				node_data["slider_values"][path_str] = {
 					"value": child.value,
 					"editable": child.editable,
 					"meta": {}
 				}
-
-				# Save all metadata
 				for key in child.get_meta_list():
 					node_data["slider_values"][path_str]["meta"][str(key)] = child.get_meta(key)
 				
+			# Save notes from CodeEdit children
 			for child in node.find_children("*", "CodeEdit", true, false):
 				node_data["notes"][child.name] = child.text
 
 			node_data_list.append(node_data)
+			node_id += 1
 
+	# Save connections using node IDs instead of names
 	for conn in graph_edit.get_connection_list():
-		connection_data_list.append({
-			"from_node": conn["from_node"],
-			"from_port": conn["from_port"],
-			"to_node": conn["to_node"],
-			"to_port": conn["to_port"]
-		})
+		# Map from_node and to_node names to IDs
+		var from_id = node_id_map.get(conn["from_node"], null)
+		var to_id = node_id_map.get(conn["to_node"], null)
+
+		if from_id != null and to_id != null:
+			connection_data_list.append({
+				"from_node_id": from_id,
+				"from_port": conn["from_port"],
+				"to_node_id": to_id,
+				"to_port": conn["to_port"]
+			})
+		else:
+			print("Warning: Connection references unknown node(s). Skipping connection.")
 
 	var graph_data = {
 		"nodes": node_data_list,
@@ -1530,12 +1549,16 @@ func load_graph_edit(path: String):
 	var graph_data = json.get_data()
 	graph_edit.clear_connections()
 
+	# Remove all existing GraphNodes from graph_edit
 	for node in graph_edit.get_children():
 		if node is GraphNode:
 			node.queue_free()
 
-	await get_tree().process_frame  # Ensure nodes are cleared
+	await get_tree().process_frame  # Ensure nodes are freed before adding new ones
+
+	var id_to_node = {}  # Map node IDs to new node instances
 
+	# Recreate nodes and store them by ID
 	for node_data in graph_data["nodes"]:
 		var command_name = node_data.get("command", "")
 		var template = Nodes.get_node_or_null(command_name)
@@ -1548,62 +1571,214 @@ func load_graph_edit(path: String):
 		new_node.position_offset = Vector2(node_data["offset"]["x"], node_data["offset"]["y"])
 		new_node.set_meta("command", command_name)
 		graph_edit.add_child(new_node)
-		_register_node_movement() #link nodes for tracking position changes for changes tracking
+		_register_node_movement()  # Track node movement changes
+
+		id_to_node[node_data["id"]] = new_node
 
 		# Restore sliders
 		for slider_path_str in node_data["slider_values"]:
 			var slider = new_node.get_node_or_null(slider_path_str)
 			if slider and (slider is HSlider or slider is VSlider):
 				var slider_info = node_data["slider_values"][slider_path_str]
-				
 				if typeof(slider_info) == TYPE_DICTIONARY:
 					slider.value = slider_info.get("value", slider.value)
-					
-					# Restore enabled/disabled
 					if slider_info.has("editable"):
 						slider.editable = slider_info["editable"]
-					
-					# Restore metadata
 					if slider_info.has("meta"):
 						for key in slider_info["meta"]:
 							var value = slider_info["meta"][key]
-
-							# Convert arrays of stringified Vector2s back to real Vector2s
 							if key == "brk_data" and typeof(value) == TYPE_ARRAY:
 								var new_array: Array = []
 								for item in value:
 									if typeof(item) == TYPE_STRING:
-										# Extract values from "(x, y)"
 										var numbers: PackedStringArray = item.strip_edges().trim_prefix("(").trim_suffix(")").split(",")
 										if numbers.size() == 2:
 											var x = float(numbers[0])
 											var y = float(numbers[1])
 											new_array.append(Vector2(x, y))
 								value = new_array
-
 							slider.set_meta(key, value)
 				else:
-					# Legacy support: just value
 					slider.value = slider_info
-			
-	
-				
+
 		# Restore notes
 		for codeedit_name in node_data["notes"]:
 			var codeedit = new_node.find_child(codeedit_name, true, false)
 			if codeedit and (codeedit is CodeEdit):
 				codeedit.text = node_data["notes"][codeedit_name]
-		_register_inputs_in_node(new_node) #link sliders for changes tracking
-	# Restore connections
+
+		_register_inputs_in_node(new_node)  # Track slider changes
+
+	# Recreate connections by looking up nodes by ID
 	for conn in graph_data["connections"]:
-		graph_edit.connect_node(
-			conn["from_node"], conn["from_port"],
-			conn["to_node"], conn["to_port"]
-		)
+		var from_node = id_to_node.get(conn["from_node_id"], null)
+		var to_node = id_to_node.get(conn["to_node_id"], null)
+
+		if from_node != null and to_node != null:
+			graph_edit.connect_node(
+				from_node.name, conn["from_port"],
+				to_node.name, conn["to_port"]
+			)
+		else:
+			print("Warning: Connection references unknown node ID(s). Skipping connection.")
+
 	link_output()
 	print("Graph loaded.")
 	get_window().title = "SoundThread - " + path.get_file().trim_suffix(".thd")
 
+#func save_graph_edit(path: String):
+	#var file = FileAccess.open(path, FileAccess.WRITE)
+	#if file == null:
+		#print("Failed to open file for saving")
+		#return
+#
+	#var node_data_list = []
+	#var connection_data_list = []
+#
+	#for node in graph_edit.get_children():
+		#if node is GraphNode:
+			#var offset = node.position_offset
+			#var node_data = {
+				#"name": node.name,
+				#"command": node.get_meta("command"),
+				#"offset": { "x": offset.x, "y": offset.y },
+				#"slider_values": {},
+				#"notes":{}
+			#}
+#
+			#for child in node.find_children("*", "Slider", true, false):
+				#var relative_path = node.get_path_to(child)
+				#var path_str = str(relative_path)
+#
+				## Save slider value
+				#node_data["slider_values"][path_str] = {
+					#"value": child.value,
+					#"editable": child.editable,
+					#"meta": {}
+				#}
+#
+				## Save all metadata
+				#for key in child.get_meta_list():
+					#node_data["slider_values"][path_str]["meta"][str(key)] = child.get_meta(key)
+				#
+			#for child in node.find_children("*", "CodeEdit", true, false):
+				#node_data["notes"][child.name] = child.text
+#
+			#node_data_list.append(node_data)
+#
+	#for conn in graph_edit.get_connection_list():
+		#connection_data_list.append({
+			#"from_node": conn["from_node"],
+			#"from_port": conn["from_port"],
+			#"to_node": conn["to_node"],
+			#"to_port": conn["to_port"]
+		#})
+#
+	#var graph_data = {
+		#"nodes": node_data_list,
+		#"connections": connection_data_list
+	#}
+#
+	#var json = JSON.new()
+	#var json_string = json.stringify(graph_data, "\t")
+	#file.store_string(json_string)
+	#file.close()
+	#print("Graph saved.")
+	#changesmade = false
+	#get_window().title = "SoundThread - " + path.get_file().trim_suffix(".thd")
+#
+#
+#func load_graph_edit(path: String):
+	#var file = FileAccess.open(path, FileAccess.READ)
+	#if file == null:
+		#print("Failed to open file for loading")
+		#return
+#
+	#var json_text = file.get_as_text()
+	#file.close()
+#
+	#var json = JSON.new()
+	#if json.parse(json_text) != OK:
+		#print("Error parsing JSON")
+		#return
+#
+	#var graph_data = json.get_data()
+	#graph_edit.clear_connections()
+#
+	#for node in graph_edit.get_children():
+		#if node is GraphNode:
+			#node.queue_free()
+#
+	#await get_tree().process_frame  # Ensure nodes are cleared
+#
+	#for node_data in graph_data["nodes"]:
+		#var command_name = node_data.get("command", "")
+		#var template = Nodes.get_node_or_null(command_name)
+		#if not template:
+			#print("Template not found for command:", command_name)
+			#continue
+#
+		#var new_node: GraphNode = template.duplicate()
+		#new_node.name = node_data["name"]
+		#new_node.position_offset = Vector2(node_data["offset"]["x"], node_data["offset"]["y"])
+		#new_node.set_meta("command", command_name)
+		#graph_edit.add_child(new_node)
+		#_register_node_movement() #link nodes for tracking position changes for changes tracking
+#
+		## Restore sliders
+		#for slider_path_str in node_data["slider_values"]:
+			#var slider = new_node.get_node_or_null(slider_path_str)
+			#if slider and (slider is HSlider or slider is VSlider):
+				#var slider_info = node_data["slider_values"][slider_path_str]
+				#
+				#if typeof(slider_info) == TYPE_DICTIONARY:
+					#slider.value = slider_info.get("value", slider.value)
+					#
+					## Restore enabled/disabled
+					#if slider_info.has("editable"):
+						#slider.editable = slider_info["editable"]
+					#
+					## Restore metadata
+					#if slider_info.has("meta"):
+						#for key in slider_info["meta"]:
+							#var value = slider_info["meta"][key]
+#
+							## Convert arrays of stringified Vector2s back to real Vector2s
+							#if key == "brk_data" and typeof(value) == TYPE_ARRAY:
+								#var new_array: Array = []
+								#for item in value:
+									#if typeof(item) == TYPE_STRING:
+										## Extract values from "(x, y)"
+										#var numbers: PackedStringArray = item.strip_edges().trim_prefix("(").trim_suffix(")").split(",")
+										#if numbers.size() == 2:
+											#var x = float(numbers[0])
+											#var y = float(numbers[1])
+											#new_array.append(Vector2(x, y))
+								#value = new_array
+#
+							#slider.set_meta(key, value)
+				#else:
+					## Legacy support: just value
+					#slider.value = slider_info
+			#
+	#
+				#
+		## Restore notes
+		#for codeedit_name in node_data["notes"]:
+			#var codeedit = new_node.find_child(codeedit_name, true, false)
+			#if codeedit and (codeedit is CodeEdit):
+				#codeedit.text = node_data["notes"][codeedit_name]
+		#_register_inputs_in_node(new_node) #link sliders for changes tracking
+	## Restore connections
+	#for conn in graph_data["connections"]:
+		#graph_edit.connect_node(
+			#conn["from_node"], conn["from_port"],
+			#conn["to_node"], conn["to_port"]
+		#)
+	#link_output()
+	#print("Graph loaded.")
+	#get_window().title = "SoundThread - " + path.get_file().trim_suffix(".thd")
+
 
 func _on_save_dialog_file_selected(path: String) -> void:
 	save_graph_edit(path) #save file