diff --git a/addons/cutscene_editor/editor/CutsceneGraphEdit.gd b/addons/cutscene_editor/editor/CutsceneGraphEdit.gd index 0ac1a7e..637b800 100644 --- a/addons/cutscene_editor/editor/CutsceneGraphEdit.gd +++ b/addons/cutscene_editor/editor/CutsceneGraphEdit.gd @@ -57,31 +57,25 @@ func add_node(node_type: String, position: Vector2) -> BaseGraphNode: match node_type: "entry": - new_node = preload("res://addons/cutscene_editor/editor/nodes/EntryNode.gd").new() + new_node = preload("res://addons/cutscene_editor/editor/nodes/EntryNode.tscn").instantiate() "exit": - new_node = preload("res://addons/cutscene_editor/editor/nodes/ExitNode.gd").new() + new_node = preload("res://addons/cutscene_editor/editor/nodes/ExitNode.tscn").instantiate() "move": - new_node = preload("res://addons/cutscene_editor/editor/nodes/MoveActionNode.gd").new() + new_node = preload("res://addons/cutscene_editor/editor/nodes/MoveActionNode.tscn").instantiate() "turn": - new_node = preload("res://addons/cutscene_editor/editor/nodes/TurnActionNode.gd").new() + new_node = preload("res://addons/cutscene_editor/editor/nodes/TurnActionNode.tscn").instantiate() "dialogue": - new_node = preload("res://addons/cutscene_editor/editor/nodes/DialogueActionNode.gd").new() + new_node = preload("res://addons/cutscene_editor/editor/nodes/DialogueActionNode.tscn").instantiate() "animation": - new_node = preload("res://addons/cutscene_editor/editor/nodes/AnimationActionNode.gd").new() + new_node = preload("res://addons/cutscene_editor/editor/nodes/AnimationActionNode.tscn").instantiate() "wait": - new_node = preload("res://addons/cutscene_editor/editor/nodes/WaitActionNode.gd").new() - "parallel": - new_node = preload("res://addons/cutscene_editor/editor/nodes/ParallelGroupNode.gd").new() + new_node = preload("res://addons/cutscene_editor/editor/nodes/WaitActionNode.tscn").instantiate() _: return null # Set node position new_node.position_offset = position - # Special handling for parallel groups - if new_node is ParallelGroupNode: - # Set a larger initial size for parallel groups - new_node.custom_minimum_size = Vector2(200, 150) # Add to GraphEdit add_child(new_node) @@ -105,21 +99,6 @@ func _on_connection_request(from_node: String, from_port: int, to_node: String, var from_node_instance = get_node_or_null(from_node) var to_node_instance = get_node_or_null(to_node) - # Special handling for parallel groups - if to_node_instance is ParallelGroupNode: - # Connecting to a parallel group - if _is_valid_parallel_connection(from_node_instance, from_port, to_node_instance, to_port): - # Add child node to parallel group - if to_node_instance.can_add_child_node(from_node_instance): - to_node_instance.add_child_node(from_node_instance) - - # Create a logical connection (not visual) - _create_logical_parallel_connection(from_node, from_port, to_node, to_port) - - # Emit signal - emit_signal("connection_created", from_node, from_port, to_node, to_port) - emit_signal("graph_changed") - return # Create the connection connect_node(from_node, from_port, to_node, to_port) @@ -137,19 +116,6 @@ func _on_disconnection_request(from_node: String, from_port: int, to_node: Strin var from_node_instance = get_node_or_null(from_node) var to_node_instance = get_node_or_null(to_node) - # Special handling for parallel groups - if to_node_instance is ParallelGroupNode: - # Remove child node from parallel group - if from_node_instance in to_node_instance.child_nodes: - to_node_instance.remove_child_node(from_node_instance) - - # Remove logical connection - _remove_logical_parallel_connection(from_node, from_port, to_node, to_port) - - # Emit signal - emit_signal("connection_removed", from_node, from_port, to_node, to_port) - emit_signal("graph_changed") - return # Remove the connection disconnect_node(from_node, from_port, to_node, to_port) @@ -187,12 +153,6 @@ func _is_connection_valid(from_node_name: String, from_port: int, to_node_name: "exit": # Exit cannot have outgoing connections return false - "parallel": - # Parallel group output can connect to any node except entry/parallel - if from_port == from_node.input_connections: # Output port - return to_node.node_type != "entry" and to_node.node_type != "parallel" - else: # Input port - return to_node.node_type != "exit" and to_node.node_type != "parallel" _: # Other nodes can connect to any node except entry return to_node.node_type != "entry" @@ -231,24 +191,6 @@ func _dfs_cycle_check(current_node_name: String, target_node_name: String, visit elif recursion_stack.has(next_node_name): return true - # Check parallel connections - if has_meta("logical_connections"): - var logical_connections = get_meta("logical_connections") - for connection in logical_connections: - if connection["from_node"] == current_node_name: - var next_node_name = connection["to_node"] - - # If we reached the target node, we found a cycle - if next_node_name == target_node_name: - return true - - # If next node not visited, recursively check - if not visited.has(next_node_name): - if _dfs_cycle_check(next_node_name, target_node_name, visited, recursion_stack): - return true - # If next node is in recursion stack, we found a cycle - elif recursion_stack.has(next_node_name): - return true # Remove from recursion stack recursion_stack[current_node_name] = false @@ -274,7 +216,6 @@ func _on_popup_request(position: Vector2) -> void: menu.add_item("Add Dialogue Action", 4) menu.add_item("Add Animation Action", 5) menu.add_item("Add Wait Action", 6) - menu.add_item("Add Parallel Group", 7) # Connect menu signals menu.connect("id_pressed", _on_context_menu_selected.bind(position)) @@ -303,8 +244,6 @@ func _on_context_menu_selected(id: int, position: Vector2) -> void: node_type = "animation" 6: node_type = "wait" - 7: - node_type = "parallel" _: return @@ -346,22 +285,6 @@ func _on_graph_node_selected(node: BaseGraphNode) -> void: # Handle graph node deletion func _on_graph_node_deleted(node: BaseGraphNode) -> void: - # Special handling for parallel groups - if node is ParallelGroupNode: - # Remove all child nodes first - for child_node in node.child_nodes: - # Remove child from scene tree - if child_node.get_parent(): - child_node.get_parent().remove_child(child_node) - - # Add child back to main graph - add_child(child_node) - - # Update child position to be near the parallel group - child_node.position_offset = node.position_offset + Vector2(50, 50) - - # Clear child nodes array - node.child_nodes.clear() # Remove all connections to/from this node var connections = get_connection_list() @@ -369,16 +292,6 @@ func _on_graph_node_deleted(node: BaseGraphNode) -> void: if connection["from_node"] == node.name or connection["to_node"] == node.name: disconnect_node(connection["from_node"], connection["from_port"], connection["to_node"], connection["to_port"]) - # Remove logical connections for parallel groups - if has_meta("logical_connections"): - var logical_connections = get_meta("logical_connections") - var i = 0 - while i < logical_connections.size(): - var conn = logical_connections[i] - if conn["from_node"] == node.name or conn["to_node"] == node.name: - logical_connections.remove_at(i) - else: - i += 1 # Remove node from GraphEdit remove_child(node) @@ -477,65 +390,6 @@ func save_to_cutscene() -> CutsceneResource: return current_cutscene -# Special handling for parallel groups -func _is_valid_parallel_connection(from_node: BaseGraphNode, from_port: int, to_node: ParallelGroupNode, to_port: int) -> bool: - # Can only connect to input ports of parallel groups - if to_port >= to_node.input_connections: - return false - - # Can't connect parallel group to itself - if from_node == to_node: - return false - - # Can't connect entry or exit nodes to parallel groups - if from_node.node_type == "entry" or from_node.node_type == "exit": - return false - - # Can't connect parallel groups to parallel groups - if from_node.node_type == "parallel": - return false - - return true - -# Create a logical connection for parallel groups (not visually represented) -func _create_logical_parallel_connection(from_node: String, from_port: int, to_node: String, to_port: int) -> void: - # Store the logical connection in our data structure - # This connection won't be visually represented but will be used for generation - var logical_connection = { - "from_node": from_node, - "from_port": from_port, - "to_node": to_node, - "to_port": to_port, - "is_parallel": true - } - - # Add to a separate list of logical connections - if not has_meta("logical_connections"): - set_meta("logical_connections", []) - - var logical_connections = get_meta("logical_connections") - logical_connections.append(logical_connection) - -# Remove a logical connection for parallel groups -func _remove_logical_parallel_connection(from_node: String, from_port: int, to_node: String, to_port: int) -> void: - if not has_meta("logical_connections"): - return - - var logical_connections = get_meta("logical_connections") - var i = 0 - while i < logical_connections.size(): - var conn = logical_connections[i] - if (conn["from_node"] == from_node and conn["from_port"] == from_port and - conn["to_node"] == to_node and conn["to_port"] == to_port): - logical_connections.remove_at(i) - return - i += 1 - -# Get all logical connections -func get_logical_connections() -> Array: - if has_meta("logical_connections"): - return get_meta("logical_connections") - return [] # Set up preview system func setup_preview() -> void: diff --git a/addons/cutscene_editor/editor/nodes/AnimationActionNode.gd b/addons/cutscene_editor/editor/nodes/AnimationActionNode.gd index 8b90ac0..8ca2817 100644 --- a/addons/cutscene_editor/editor/nodes/AnimationActionNode.gd +++ b/addons/cutscene_editor/editor/nodes/AnimationActionNode.gd @@ -21,37 +21,6 @@ func _ready() -> void: action_parameters["animation_name"] = "" action_parameters["loop"] = false -func _setup_parameter_fields() -> void: - # Character field - var char_label = Label.new() - char_label.text = "Character:" - add_child(char_label) - - var char_field = LineEdit.new() - char_field.text = action_parameters["character"] - char_field.connect("text_changed", _on_character_changed) - add_child(char_field) - - # Animation name field - var anim_label = Label.new() - anim_label.text = "Animation:" - add_child(anim_label) - - var anim_field = LineEdit.new() - anim_field.text = action_parameters["animation_name"] - anim_field.connect("text_changed", _on_animation_changed) - add_child(anim_field) - - # Loop checkbox - var loop_label = Label.new() - loop_label.text = "Loop:" - add_child(loop_label) - - var loop_checkbox = CheckBox.new() - loop_checkbox.button_pressed = action_parameters["loop"] - loop_checkbox.connect("toggled", _on_loop_toggled) - add_child(loop_checkbox) - func _on_character_changed(new_text: String) -> void: set_parameter("character", new_text) diff --git a/addons/cutscene_editor/editor/nodes/AnimationActionNode.tscn b/addons/cutscene_editor/editor/nodes/AnimationActionNode.tscn new file mode 100644 index 0000000..5580056 --- /dev/null +++ b/addons/cutscene_editor/editor/nodes/AnimationActionNode.tscn @@ -0,0 +1,36 @@ +[gd_scene load_steps=2 format=3 uid="uid://animationactionnodetscn"] +[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/AnimationActionNode.gd" id="1_animation"] +[node name="AnimationActionNode" type="GraphNode"] +modulate = Color(0.8, 0.4, 0.8, 1) +custom_minimum_size = Vector2(150, 0) +title = "Animation" +slot/0/left_enabled = true +slot/0/left_type = 0 +slot/0/left_color = Color(0, 0, 0, 1) +slot/0/right_enabled = true +slot/0/right_type = 0 +slot/0/right_color = Color(0, 0, 0, 1) +slot/0/draw_stylebox = true +script = ExtResource("1_animation") +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +[node name="Character" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Character" +[node name="character" type="LineEdit" parent="VBoxContainer"] +layout_mode = 2 +placeholder_text = "Character name" +[node name="Animation" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Animation" +[node name="animation_name" type="LineEdit" parent="VBoxContainer"] +layout_mode = 2 +placeholder_text = "Animation name" +[node name="Loop" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Loop" +[node name="loop" type="CheckBox" parent="VBoxContainer"] +layout_mode = 2 +[connection signal="text_changed" from="VBoxContainer/character" to="." method="_on_character_changed"] +[connection signal="text_changed" from="VBoxContainer/animation_name" to="." method="_on_animation_changed"] +[connection signal="toggled" from="VBoxContainer/loop" to="." method="_on_loop_toggled"] \ No newline at end of file diff --git a/addons/cutscene_editor/editor/nodes/DialogueActionNode.gd b/addons/cutscene_editor/editor/nodes/DialogueActionNode.gd index 4b0549e..5c9e0d2 100644 --- a/addons/cutscene_editor/editor/nodes/DialogueActionNode.gd +++ b/addons/cutscene_editor/editor/nodes/DialogueActionNode.gd @@ -21,47 +21,11 @@ func _ready() -> void: action_parameters["text"] = "" action_parameters["duration"] = 0.0 -func _setup_parameter_fields() -> void: - # Character field - var x = VBoxContainer.new() - add_child(x) - var char_label = Label.new() - char_label.text = "Character:" - char_label.hide() - x.add_child(char_label) - - var char_field = LineEdit.new() - char_field.text = action_parameters["character"] - char_field.connect("text_changed", _on_character_changed) - x.add_child(char_field) - - # Text field - var text_label = Label.new() - text_label.text = "Text:" - x.add_child(text_label) - - var text_field = TextEdit.new() - text_field.text = action_parameters["text"] - text_field.size_flags_vertical = Control.SIZE_EXPAND_FILL - text_field.connect("text_changed", _on_text_changed) - x.add_child(text_field) - - # Duration field - var duration_label = Label.new() - duration_label.text = "Duration:" - x.add_child(duration_label) - - var duration_field = LineEdit.new() - duration_field.text = str(action_parameters["duration"]) - duration_field.connect("text_changed", _on_duration_changed) - x.add_child(duration_field) - func _on_character_changed(new_text: String) -> void: set_parameter("character", new_text) -func _on_text_changed() -> void: - var text_edit = get_child(get_child_count() - 2) # TextEdit is second to last child - set_parameter("text", text_edit.text) +func _on_text_changed(new_text: String) -> void: + set_parameter("text", new_text) func _on_duration_changed(new_text: String) -> void: var value = float(new_text) if new_text.is_valid_float() else 0.0 diff --git a/addons/cutscene_editor/editor/nodes/DialogueActionNode.tscn b/addons/cutscene_editor/editor/nodes/DialogueActionNode.tscn new file mode 100644 index 0000000..e6b70f7 --- /dev/null +++ b/addons/cutscene_editor/editor/nodes/DialogueActionNode.tscn @@ -0,0 +1,38 @@ +[gd_scene load_steps=2 format=3 uid="uid://dialogueactionnodetscn"] +[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/DialogueActionNode.gd" id="1_dialogue"] +[node name="DialogueActionNode" type="GraphNode"] +modulate = Color(1.0, 1.0, 0.5, 1) +custom_minimum_size = Vector2(200, 100) +title = "Dialogue" +resizable = true +slot/0/left_enabled = true +slot/0/left_type = 0 +slot/0/left_color = Color(0, 0, 0, 1) +slot/0/right_enabled = true +slot/0/right_type = 0 +slot/0/right_color = Color(0, 0, 0, 1) +slot/0/draw_stylebox = true +script = ExtResource("1_dialogue") +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +[node name="Character" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Character" +[node name="character" type="LineEdit" parent="VBoxContainer"] +layout_mode = 2 +placeholder_text = "Character name" +[node name="Text" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Text" +[node name="text" type="TextEdit" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +[node name="Duration" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Duration" +[node name="duration" type="LineEdit" parent="VBoxContainer"] +layout_mode = 2 +placeholder_text = "Duration in seconds" +[connection signal="text_changed" from="VBoxContainer/character" to="." method="_on_character_changed"] +[connection signal="text_changed" from="VBoxContainer/text" to="." method="_on_text_changed"] +[connection signal="text_changed" from="VBoxContainer/duration" to="." method="_on_duration_changed"] \ No newline at end of file diff --git a/addons/cutscene_editor/editor/nodes/EntryNode.tscn b/addons/cutscene_editor/editor/nodes/EntryNode.tscn new file mode 100644 index 0000000..32acc75 --- /dev/null +++ b/addons/cutscene_editor/editor/nodes/EntryNode.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=2 format=3 uid="uid://entrynodetscn"] +[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/EntryNode.gd" id="1_entry"] +[node name="EntryNode" type="GraphNode"] +modulate = Color(0.5, 1.0, 0.5, 1) +custom_minimum_size = Vector2(100, 0) +title = "Start" +slot/0/left_enabled = false +slot/0/left_type = 0 +slot/0/left_color = Color(0, 0, 0, 0) +slot/0/right_enabled = true +slot/0/right_type = 0 +slot/0/right_color = Color(0, 0, 0, 1) +slot/0/right_icon = null +slot/0/draw_stylebox = true +script = ExtResource("1_entry") \ No newline at end of file diff --git a/addons/cutscene_editor/editor/nodes/ExitNode.tscn b/addons/cutscene_editor/editor/nodes/ExitNode.tscn new file mode 100644 index 0000000..9fe529a --- /dev/null +++ b/addons/cutscene_editor/editor/nodes/ExitNode.tscn @@ -0,0 +1,14 @@ +[gd_scene load_steps=2 format=3 uid="uid://exitnodetscn"] +[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/ExitNode.gd" id="1_exit"] +[node name="ExitNode" type="GraphNode"] +modulate = Color(1.0, 0.5, 0.5, 1) +custom_minimum_size = Vector2(100, 0) +title = "End" +slot/0/left_enabled = true +slot/0/left_type = 0 +slot/0/left_color = Color(0, 0, 0, 1) +slot/0/right_enabled = false +slot/0/right_type = 0 +slot/0/right_color = Color(0, 0, 0, 0) +slot/0/draw_stylebox = true +script = ExtResource("1_exit") \ No newline at end of file diff --git a/addons/cutscene_editor/editor/nodes/MoveActionNode.gd b/addons/cutscene_editor/editor/nodes/MoveActionNode.gd index 22418fa..d67a61a 100644 --- a/addons/cutscene_editor/editor/nodes/MoveActionNode.gd +++ b/addons/cutscene_editor/editor/nodes/MoveActionNode.gd @@ -22,56 +22,6 @@ func _ready() -> void: action_parameters["target_y"] = 0.0 action_parameters["speed"] = 100.0 -func _setup_parameter_fields() -> void: - # Character field - var char_label = Label.new() - char_label.text = "Character:" - add_child(char_label) - - var char_field = LineEdit.new() - char_field.text = action_parameters["character"] - char_field.connect("text_changed", _on_character_changed) - add_child(char_field) - - # Target position fields - var pos_label = Label.new() - pos_label.text = "Target Position:" - add_child(pos_label) - - var pos_container = HBoxContainer.new() - - var x_label = Label.new() - x_label.text = "X:" - pos_container.add_child(x_label) - - var x_field = LineEdit.new() - x_field.text = str(action_parameters["target_x"]) - x_field.size_flags_horizontal = Control.SIZE_EXPAND_FILL - x_field.connect("text_changed", _on_target_x_changed) - pos_container.add_child(x_field) - - var y_label = Label.new() - y_label.text = "Y:" - pos_container.add_child(y_label) - - var y_field = LineEdit.new() - y_field.text = str(action_parameters["target_y"]) - y_field.size_flags_horizontal = Control.SIZE_EXPAND_FILL - y_field.connect("text_changed", _on_target_y_changed) - pos_container.add_child(y_field) - - add_child(pos_container) - - # Speed field - var speed_label = Label.new() - speed_label.text = "Speed:" - add_child(speed_label) - - var speed_field = LineEdit.new() - speed_field.text = str(action_parameters["speed"]) - speed_field.connect("text_changed", _on_speed_changed) - add_child(speed_field) - func _on_character_changed(new_text: String) -> void: set_parameter("character", new_text) @@ -80,9 +30,12 @@ func _on_target_x_changed(new_text: String) -> void: set_parameter("target_x", value) func _on_target_y_changed(new_text: String) -> void: + print("toarget y") var value = float(new_text) if new_text.is_valid_float() else 0.0 set_parameter("target_y", value) func _on_speed_changed(new_text: String) -> void: + + print("speed") var value = float(new_text) if new_text.is_valid_float() else 100.0 set_parameter("speed", value) diff --git a/addons/cutscene_editor/editor/nodes/MoveActionNode.tscn b/addons/cutscene_editor/editor/nodes/MoveActionNode.tscn new file mode 100644 index 0000000..b966a1f --- /dev/null +++ b/addons/cutscene_editor/editor/nodes/MoveActionNode.tscn @@ -0,0 +1,56 @@ +[gd_scene load_steps=2 format=3 uid="uid://y74lqsx8bpxn"] + +[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/MoveActionNode.gd" id="1_5aood"] + +[node name="MoveActionNode" type="GraphNode"] +modulate = Color(0.4, 0.6, 1, 1) +custom_minimum_size = Vector2(150, 0) +title = "Move" +slot/0/left_enabled = true +slot/0/left_type = 0 +slot/0/left_color = Color(0, 0, 0, 1) +slot/0/left_icon = null +slot/0/right_enabled = true +slot/0/right_type = 0 +slot/0/right_color = Color(0, 0, 0, 1) +slot/0/right_icon = null +slot/0/draw_stylebox = true +script = ExtResource("1_5aood") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 + +[node name="Character" type="Label" parent="VBoxContainer"] +layout_mode = 2 + +[node name="TextEdit" type="LineEdit" parent="VBoxContainer"] +custom_minimum_size = Vector2(0, 32.865) +layout_mode = 2 +text = "aoeu" +placeholder_text = "aoeu" + +[node name="Location" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Location" + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 + +[node name="x" type="LineEdit" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="y" type="LineEdit" parent="VBoxContainer/HBoxContainer"] +layout_mode = 2 + +[node name="Speed" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Speed" + +[node name="speed" type="LineEdit" parent="VBoxContainer"] +layout_mode = 2 + +[connection signal="text_changed" from="VBoxContainer/TextEdit" to="." method="_on_character_changed"] +[connection signal="text_changed" from="VBoxContainer/HBoxContainer/x" to="." method="_on_target_x_changed"] +[connection signal="text_changed" from="VBoxContainer/HBoxContainer/y" to="." method="_on_target_y_changed"] +[connection signal="text_change_rejected" from="VBoxContainer/speed" to="." method="_on_speed_text_change_rejected"] +[connection signal="text_changed" from="VBoxContainer/speed" to="." method="_on_speed_changed"] diff --git a/addons/cutscene_editor/editor/nodes/TurnActionNode.gd b/addons/cutscene_editor/editor/nodes/TurnActionNode.gd index 14f7232..102b4ca 100644 --- a/addons/cutscene_editor/editor/nodes/TurnActionNode.gd +++ b/addons/cutscene_editor/editor/nodes/TurnActionNode.gd @@ -21,37 +21,6 @@ func _ready() -> void: action_parameters["target"] = "" action_parameters["turn_speed"] = 2.0 -func _setup_parameter_fields() -> void: - # Character field - var char_label = Label.new() - char_label.text = "Character:" - add_child(char_label) - - var char_field = LineEdit.new() - char_field.text = action_parameters["character"] - char_field.connect("text_changed", _on_character_changed) - add_child(char_field) - - # Target field - var target_label = Label.new() - target_label.text = "Target:" - add_child(target_label) - - var target_field = LineEdit.new() - target_field.text = action_parameters["target"] - target_field.connect("text_changed", _on_target_changed) - add_child(target_field) - - # Turn speed field - var speed_label = Label.new() - speed_label.text = "Turn Speed:" - add_child(speed_label) - - var speed_field = LineEdit.new() - speed_field.text = str(action_parameters["turn_speed"]) - speed_field.connect("text_changed", _on_turn_speed_changed) - add_child(speed_field) - func _on_character_changed(new_text: String) -> void: set_parameter("character", new_text) diff --git a/addons/cutscene_editor/editor/nodes/TurnActionNode.tscn b/addons/cutscene_editor/editor/nodes/TurnActionNode.tscn new file mode 100644 index 0000000..cd07c79 --- /dev/null +++ b/addons/cutscene_editor/editor/nodes/TurnActionNode.tscn @@ -0,0 +1,37 @@ +[gd_scene load_steps=2 format=3 uid="uid://turnactionnodetscn"] +[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/TurnActionNode.gd" id="1_turn"] +[node name="TurnActionNode" type="GraphNode"] +modulate = Color(0.5, 1.0, 0.5, 1) +custom_minimum_size = Vector2(150, 0) +title = "Turn" +slot/0/left_enabled = true +slot/0/left_type = 0 +slot/0/left_color = Color(0, 0, 0, 1) +slot/0/right_enabled = true +slot/0/right_type = 0 +slot/0/right_color = Color(0, 0, 0, 1) +slot/0/draw_stylebox = true +script = ExtResource("1_turn") +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +[node name="Character" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Character" +[node name="character" type="LineEdit" parent="VBoxContainer"] +layout_mode = 2 +placeholder_text = "Character name" +[node name="Target" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Target" +[node name="target" type="LineEdit" parent="VBoxContainer"] +layout_mode = 2 +placeholder_text = "Target name" +[node name="TurnSpeed" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Turn Speed" +[node name="turn_speed" type="LineEdit" parent="VBoxContainer"] +layout_mode = 2 +placeholder_text = "Turn speed" +[connection signal="text_changed" from="VBoxContainer/character" to="." method="_on_character_changed"] +[connection signal="text_changed" from="VBoxContainer/target" to="." method="_on_target_changed"] +[connection signal="text_changed" from="VBoxContainer/turn_speed" to="." method="_on_turn_speed_changed"] \ No newline at end of file diff --git a/addons/cutscene_editor/editor/nodes/WaitActionNode.gd b/addons/cutscene_editor/editor/nodes/WaitActionNode.gd index 00bad61..cd3f24b 100644 --- a/addons/cutscene_editor/editor/nodes/WaitActionNode.gd +++ b/addons/cutscene_editor/editor/nodes/WaitActionNode.gd @@ -19,17 +19,6 @@ func _ready() -> void: # Initialize default parameters action_parameters["duration"] = 1.0 -func _setup_parameter_fields() -> void: - # Duration field - var duration_label = Label.new() - duration_label.text = "Duration:" - add_child(duration_label) - - var duration_field = LineEdit.new() - duration_field.text = str(action_parameters["duration"]) - duration_field.connect("text_changed", _on_duration_changed) - add_child(duration_field) - func _on_duration_changed(new_text: String) -> void: var value = float(new_text) if new_text.is_valid_float() else 1.0 set_parameter("duration", value) diff --git a/addons/cutscene_editor/editor/nodes/WaitActionNode.tscn b/addons/cutscene_editor/editor/nodes/WaitActionNode.tscn new file mode 100644 index 0000000..0ede253 --- /dev/null +++ b/addons/cutscene_editor/editor/nodes/WaitActionNode.tscn @@ -0,0 +1,26 @@ +[gd_scene load_steps=2 format=3 uid="uid://waitnodetscn"] +[ext_resource type="Script" path="res://addons/cutscene_editor/editor/nodes/WaitActionNode.gd" id="1_wait"] +[node name="WaitActionNode" type="GraphNode"] +modulate = Color(0.7, 0.7, 0.7, 1) +custom_minimum_size = Vector2(150, 0) +title = "Wait" +slot/0/left_enabled = true +slot/0/left_type = 0 +slot/0/left_color = Color(0, 0, 0, 1) +slot/0/left_icon = null +slot/0/right_enabled = true +slot/0/right_type = 0 +slot/0/right_color = Color(0, 0, 0, 1) +slot/0/right_icon = null +slot/0/draw_stylebox = true +script = ExtResource("1_wait") +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +[node name="Duration" type="Label" parent="VBoxContainer"] +layout_mode = 2 +text = "Duration" +[node name="duration" type="LineEdit" parent="VBoxContainer"] +layout_mode = 2 +text = "1.0" +placeholder_text = "Duration in seconds" +[connection signal="text_changed" from="VBoxContainer/duration" to="." method="_on_duration_changed"] \ No newline at end of file diff --git a/cutscene/examples/sample_cutscene.tres b/cutscene/examples/sample_cutscene.tres new file mode 100644 index 0000000..911da3a --- /dev/null +++ b/cutscene/examples/sample_cutscene.tres @@ -0,0 +1,16 @@ +[gd_resource type="VisualShader" load_steps=2 format=3 uid="uid://bqjt0um0vbxs7"] + +[sub_resource type="VisualShaderNodeDerivativeFunc" id="VisualShaderNodeDerivativeFunc_n7wl4"] + +[resource] +code = "shader_type canvas_item; +render_mode blend_mix; + + + +" +mode = 1 +flags/light_only = false +nodes/fragment/0/position = Vector2(700, 140) +nodes/fragment/2/node = SubResource("VisualShaderNodeDerivativeFunc_n7wl4") +nodes/fragment/2/position = Vector2(196, 138) diff --git a/plans/cutscene_data_structure.md b/plans/cutscene_data_structure.md new file mode 100644 index 0000000..737b4cb --- /dev/null +++ b/plans/cutscene_data_structure.md @@ -0,0 +1,122 @@ +# Cutscene Data Structure Design + +## Overview + +This document describes the data structure for storing cutscene nodes and connections in a way that can be used by both the editor and runtime systems. + +## Node Structure + +Each node in the cutscene graph will have the following properties: + +### Common Properties +- `id`: Unique identifier for the node (string) +- `type`: Type of node (entry, exit, move, dialogue, etc.) +- `position`: Object with `x` and `y` coordinates +- `parameters`: Object containing type-specific parameters + +### Node Type Specifics + +#### Entry Node +- Type: "entry" +- Parameters: None (or minimal configuration) + +#### Exit Node +- Type: "exit" +- Parameters: None (or minimal configuration) + +#### Move Action Node +- Type: "move" +- Parameters: + - `character`: Character identifier/path + - `target_x`: Target X position + - `target_y`: Target Y position + - `speed`: Movement speed + +#### Dialogue Action Node +- Type: "dialogue" +- Parameters: + - `character`: Character identifier/path + - `text`: Dialogue text + - `duration`: Display duration (0 for indefinite) + +#### Animation Action Node +- Type: "animation" +- Parameters: + - `character`: Character identifier/path + - `animation_name`: Name of animation to play + - `loop`: Whether to loop the animation + +#### Turn Action Node +- Type: "turn" +- Parameters: + - `character`: Character identifier/path + - `target`: Target identifier/path + - `turn_speed`: Speed of turning + +#### Wait Action Node +- Type: "wait" +- Parameters: + - `duration`: Wait duration in seconds + +#### Parallel Group Node +- Type: "parallel" +- Parameters: None (connections define the group) + +## Connection Structure + +Each connection between nodes will have: + +- `id`: Unique identifier for the connection +- `from_node`: Source node ID +- `from_port`: Source port index +- `to_node`: Target node ID +- `to_port`: Target port index + +## Resource Structure + +The CutsceneResource will contain: + +```json +{ + "version": "1.0", + "metadata": { + "created": "timestamp", + "modified": "timestamp" + }, + "nodes": [ + { + "id": "node1", + "type": "entry", + "position": {"x": 100, "y": 100}, + "parameters": {} + }, + { + "id": "node2", + "type": "move", + "position": {"x": 200, "y": 150}, + "parameters": { + "character": "player", + "target_x": 300, + "target_y": 200, + "speed": 100 + } + } + ], + "connections": [ + { + "id": "conn1", + "from_node": "node1", + "from_port": 0, + "to_node": "node2", + "to_port": 0 + } + ] +} +``` + +## Implementation Considerations + +1. **IDs**: All nodes and connections should have unique IDs generated by the system +2. **Validation**: The resource should validate that all referenced nodes in connections exist +3. **Serialization**: The structure should be easily serializable to JSON for storage +4. **Runtime Mapping**: The structure should map directly to runtime Action instances \ No newline at end of file diff --git a/plans/cutscene_documentation_plan.md b/plans/cutscene_documentation_plan.md new file mode 100644 index 0000000..d14d506 --- /dev/null +++ b/plans/cutscene_documentation_plan.md @@ -0,0 +1,196 @@ +# Cutscene System Documentation Plan + +## Overview + +This document outlines the documentation needed for the updated cutscene editor system that focuses on resource management rather than code generation. + +## Documentation Components + +### 1. System Architecture Documentation + +**File**: `addons/cutscene_editor/README.md` (update) +**Content**: +- Overview of the resource-centric approach +- Explanation of the data flow from editor to runtime +- Description of the CutsceneResource structure +- Diagram showing the relationship between components + +### 2. CutsceneResource Documentation + +**File**: `addons/cutscene_editor/docs/cutscene_resource.md` (new) +**Content**: +- Detailed specification of the CutsceneResource data structure +- Node structure documentation with examples +- Connection structure documentation with examples +- Metadata structure explanation +- Version compatibility information + +### 3. Editor Documentation + +**File**: `addons/cutscene_editor/docs/editor_usage.md` (new) +**Content**: +- How to create and edit cutscenes using the visual editor +- Node types and their parameters +- Connection rules and validation +- Saving and loading cutscenes +- Export/import functionality + +### 4. Runtime Documentation + +**File**: `cutscene/README.md` (update) +**Content**: +- How to load and execute cutscenes at runtime +- CutsceneManager usage examples +- Action system overview +- Parallel execution explanation +- Error handling and debugging + +### 5. API Reference + +**File**: `addons/cutscene_editor/docs/api_reference.md` (new) +**Content**: +- CutsceneResource API +- CutsceneGraphEdit API +- CutsceneGenerator API +- Node API +- Connection API + +### 6. Migration Guide + +**File**: `addons/cutscene_editor/docs/migration_guide.md` (new) +**Content**: +- How to migrate from old format to new format +- Code changes needed for existing projects +- Backward compatibility information +- Troubleshooting common migration issues + +## Implementation Plan + +### 1. Update Existing Documentation + +- Update `addons/cutscene_editor/README.md` to reflect new focus +- Update `cutscene/README.md` to explain runtime usage + +### 2. Create New Documentation Files + +- Create `addons/cutscene_editor/docs/cutscene_resource.md` +- Create `addons/cutscene_editor/docs/editor_usage.md` +- Create `addons/cutscene_editor/docs/api_reference.md` +- Create `addons/cutscene_editor/docs/migration_guide.md` + +### 3. Add Code Comments + +- Ensure all GDScript files have proper documentation comments +- Add examples in comments where appropriate +- Document public methods and properties + +## Documentation Structure + +### Cutscene Resource Documentation + +```markdown +# Cutscene Resource Format + +## Overview + +The CutsceneResource is a Godot Resource that stores all the data needed to represent and execute a cutscene. + +## Data Structure + +### Nodes + +Nodes represent actions or control points in the cutscene. + +[Detailed node structure with examples] + +### Connections + +Connections represent the flow between nodes. + +[Detailed connection structure with examples] + +### Metadata + +Metadata contains version and timestamp information. + +[Metadata structure details] +``` + +### Editor Usage Documentation + +```markdown +# Cutscene Editor Usage + +## Getting Started + +[Installation and setup instructions] + +## Creating a New Cutscene + +[Step-by-step guide] + +## Node Types + +[Description of each node type with parameters] + +## Connections + +[How to create and manage connections] + +## Saving and Loading + +[How to save and load cutscenes] +``` + +### Runtime Documentation + +```markdown +# Runtime Cutscene Execution + +## Loading Cutscenes + +[How to load a CutsceneResource] + +## Executing Cutscenes + +[How to use CutsceneManager] + +## Custom Actions + +[How to create custom action types] +``` + +## Visual Documentation + +### 1. System Architecture Diagram + +```mermaid +graph TD + A[Cutscene Editor] --> B[CutsceneResource] + B --> C[CutsceneGenerator] + C --> D[CutsceneManager] + D --> E[Actions] + E --> F[Game Objects] +``` + +### 2. Data Flow Diagram + +```mermaid +graph LR + A[Editor Nodes] --> B[Resource Nodes] + C[Editor Connections] --> D[Resource Connections] + B --> E[Runtime Actions] + D --> E + E --> F[Execution] +``` + +## Implementation Timeline + +1. Update existing README files +2. Create cutscene_resource.md +3. Create editor_usage.md +4. Create api_reference.md +5. Create migration_guide.md +6. Add code comments +7. Create visual diagrams +8. Review and finalize documentation \ No newline at end of file diff --git a/plans/cutscene_generator_changes.md b/plans/cutscene_generator_changes.md new file mode 100644 index 0000000..a5285bd --- /dev/null +++ b/plans/cutscene_generator_changes.md @@ -0,0 +1,121 @@ +# CutsceneGenerator Changes for Resource Management Focus + +## Overview + +This document describes the changes needed in CutsceneGenerator.gd to focus on resource management instead of code generation. + +## Current Issues + +The current CutsceneGenerator.gd has several issues: +1. Focuses on generating GDScript code rather than working with resources +2. Has methods for generating code that are not needed +3. Should focus on converting graph data to runtime actions +4. Has some useful functionality for building action sequences that should be retained + +## Required Changes + +### 1. Remove Code Generation Methods + +Methods to remove: +- `generate_gdscript_code()` +- `_generate_action_sequence_code()` +- `_generate_action_code()` +- `export_to_format()` (or modify to only support resource formats) + +### 2. Retain and Improve Resource-to-Action Conversion + +Methods to keep and improve: +- `generate_cutscene()` - This is the core method we want +- `_build_action_sequence()` - Core logic for creating action sequences +- `_create_action_from_node()` - Core logic for creating individual actions +- `_handle_parallel_group()` - Logic for handling parallel actions + +### 3. Update Data Access Methods + +Current issues: +- Uses old data structure access patterns +- May need to access data differently with new structure + +Changes needed: +- Update to use new node structure with "id" instead of "name" +- Update to use new connection structure +- Remove any references to parallel_connections + +### 4. Improve Action Creation + +Current issues: +- Action creation has placeholder values for character nodes +- Needs better parameter handling + +Changes needed: +- Improve parameter mapping from node to action +- Maintain flexibility for runtime character resolution + +## New Focus + +The CutsceneGenerator should: +1. Take a CutsceneResource and convert it to a CutsceneManager with properly configured actions +2. Not generate any code +3. Focus purely on the data transformation from editor format to runtime format +4. Handle all node types and connection logic correctly + +## Implementation Plan + +### 1. Remove Unnecessary Methods + +- Delete all code generation methods +- Remove export functionality that generates code +- Keep only the core resource-to-action conversion logic + +### 2. Update Core Methods + +- `generate_cutscene()`: Ensure it works with new resource structure +- `_build_action_sequence()`: Update to use new connection structure +- `_create_action_from_node()`: Ensure parameter mapping is correct +- `_handle_parallel_group()`: Update to work with new structure + +### 3. Add Utility Methods + +- Add methods for validating resource data +- Add methods for resolving character/action references +- Add error handling for malformed resources + +### 4. Improve Documentation + +- Update comments to reflect new purpose +- Document the resource-to-action conversion process +- Provide clear examples of usage + +## Specific Code Changes + +### In `generate_cutscene`: + +```gdscript +# OLD - May have issues with new structure +for node_data in cutscene_resource.nodes: + graph_nodes[node_data["name"]] = node_data + +# NEW - Update to use new structure +for node_data in cutscene_resource.nodes: + graph_nodes[node_data["id"]] = node_data +``` + +### In `_get_outgoing_connections`: + +```gdscript +# Should work the same but with new structure +# Just ensure it's using the right fields +``` + +### In `_create_action_from_node`: + +```gdscript +# This method is mostly correct but may need parameter updates +# Ensure all parameter access matches the new structure +``` + +## New Method Structure + +The refactored CutsceneGenerator should have: + +1. `generate_cutscene(cutscene \ No newline at end of file diff --git a/plans/cutscene_graph_edit_changes.md b/plans/cutscene_graph_edit_changes.md new file mode 100644 index 0000000..f465276 --- /dev/null +++ b/plans/cutscene_graph_edit_changes.md @@ -0,0 +1,169 @@ +# CutsceneGraphEdit Changes for New Resource Structure + +## Overview + +This document describes the changes needed in CutsceneGraphEdit.gd to work with the new CutsceneResource data structure. + +## Current Issues + +The current CutsceneGraphEdit.gd has several areas that need updating: +1. Uses old node structure with "name" instead of "id" +2. Uses old connection structure +3. Has methods for parallel connections that are no longer needed +4. Save/load methods use the old structure + +## Required Changes + +### 1. Update Load Method (`load_from_cutscene`) + +Current issues: +- Looks for "name" field in nodes +- Uses "type", "x", "y", "parameters" fields directly +- Creates connections using old structure + +Changes needed: +- Update to use "id" field instead of "name" +- Ensure node creation uses the new structure +- Update connection creation to use new structure + +### 2. Update Save Method (`save_to_cutscene`) + +Current issues: +- Creates nodes with "name" field +- Uses "action_parameters" directly +- Creates connections with old structure + +Changes needed: +- Generate unique IDs for nodes if they don't have them +- Use "id" field instead of "name" +- Ensure parameters are stored correctly +- Generate unique IDs for connections +- Use new connection structure + +### 3. Update Node Creation (`add_node`) + +Current issues: +- May not be setting node IDs properly +- Uses old parameter structure + +Changes needed: +- Ensure new nodes get unique IDs +- Verify parameter structure matches new format + +### 4. Update Connection Handling + +Current issues: +- Uses GraphEdit's built-in connection methods +- May need to store connection IDs + +Changes needed: +- Update `_on_connection_request` to store connection IDs in resource +- Update `_on_disconnection_request` to remove by connection ID +- Update `_on_graph_node_deleted` to properly remove connections + +### 5. Remove Parallel Connection Methods + +Methods to remove or modify: +- Any methods specifically handling parallel connections +- Update validation to work with new structure + +## Implementation Plan + +### 1. Update Node Management + +- Modify `add_node` to generate unique IDs +- Update `_on_graph_node_deleted` to work with new structure +- Ensure all node references use IDs + +### 2. Update Connection Management + +- Modify connection creation to generate unique IDs +- Update connection removal to use connection IDs +- Update connection validation + +### 3. Update Load/Save Methods + +- Rewrite `load_from_cutscene` for new structure +- Rewrite `save_to_cutscene` for new structure + +### 4. Update Helper Methods + +- Update any helper methods that reference node names +- Update methods that handle connections + +## Specific Code Changes + +### In `load_from_cutscene`: + +```gdscript +# OLD +for node_data in cutscene.nodes: + var node = add_node(node_data["type"], Vector2(node_data["x"], node_data["y"])) + if node: + node.name = node_data["name"] + # Set node parameters + for param_name in node_data["parameters"]: + node.set_parameter(param_name, node_data["parameters"][param_name]) + +# NEW +for node_data in cutscene.nodes: + var node = add_node(node_data["type"], Vector2(node_data["position"]["x"], node_data["position"]["y"])) + if node: + node.node_id = node_data["id"] # Set the ID directly + # Set node parameters + for param_name in node_data["parameters"]: + node.set_parameter(param_name, node_data["parameters"][param_name]) +``` + +### In `save_to_cutscene`: + +```gdscript +# OLD +var node_data = { + "name": child.name, + "type": child.node_type, + "x": child.position_offset.x, + "y": child.position_offset.y, + "parameters": child.action_parameters +} + +# NEW +var node_data = { + "id": child.node_id, + "type": child.node_type, + "position": { + "x": child.position_offset.x, + "y": child.position_offset.y + }, + "parameters": child.action_parameters +} +``` + +### Connection Updates: + +```gdscript +# OLD +for connection in get_connection_list(): + var connection_data = { + "from_node": connection["from_node"], + "from_port": connection["from_port"], + "to_node": connection["to_node"], + "to_port": connection["to_port"] + } + +# NEW +for connection in get_connection_list(): + var connection_data = { + "id": generate_unique_connection_id(), # New helper method + "from_node": connection["from_node"], + "from_port": connection["from_port"], + "to_node": connection["to_node"], + "to_port": connection["to_port"] + } +``` + +## Compatibility Considerations + +- Need to handle loading of old format resources +- Should provide migration path in the resource itself +- May need version checking when loading resources \ No newline at end of file diff --git a/plans/cutscene_resource_analysis.md b/plans/cutscene_resource_analysis.md new file mode 100644 index 0000000..bfeeb48 --- /dev/null +++ b/plans/cutscene_resource_analysis.md @@ -0,0 +1,61 @@ +# Cutscene Editor Architecture Analysis + +## Current System Overview + +The current cutscene editor addon consists of several key components: + +1. **Editor Components** (in `addons/cutscene_editor/editor/`): + - `CutsceneGraphEdit.gd`: Main graph editor interface that manages nodes and connections + - `CutsceneResource.gd`: Resource for storing cutscene data (nodes, connections) + - `CutsceneGenerator.gd`: System for generating executable cutscene code from graph data + - Node implementations (MoveActionNode, DialogueActionNode, etc.) + +2. **Runtime Components** (in `cutscene/`): + - `CutsceneManager.gd`: Manages execution of cutscene actions + - `Action.gd`: Base class for all actions + - Specific action implementations (MoveAction, DialogueAction, etc.) + +## Current Data Flow + +1. User creates nodes in the graph editor +2. Node data is stored in `CutsceneResource` +3. `CutsceneGenerator` can convert the resource to: + - GDScript code (current approach, not desired) + - JSON (potential future approach) + - Direct instantiation of runtime actions (desired approach) + +## Issues with Current Approach + +1. The addon currently focuses on generating GDScript code rather than managing a clean data structure +2. The `CutsceneResource` exists but isn't fully utilized as the primary data structure +3. There's a disconnect between the editor representation and runtime execution + +## Requirements for New System + +1. **Resource-Centric Design**: The cutscene resource should be the primary data structure that both editor and runtime use +2. **Clean Data Structure**: Store nodes and edges between slots in a structured way that can be easily serialized/deserialized +3. **Runtime Compatibility**: The resource should contain all information needed for the runtime `CutsceneManager` to execute actions +4. **No Code Generation**: Eliminate the GDScript generation functionality +5. **Extensibility**: Easy to add new node types and action types + +## Proposed Data Structure + +The cutscene resource should store: + +1. **Nodes**: + - Unique ID + - Type (entry, exit, move, dialogue, etc.) + - Position (x, y) + - Parameters specific to the node type + +2. **Connections**: + - Source node ID + - Source port + - Target node ID + - Target port + +3. **Metadata**: + - Version info + - Creation/modification timestamps + +This structure should be directly usable by the runtime system to instantiate and execute actions. \ No newline at end of file diff --git a/plans/cutscene_resource_implementation.md b/plans/cutscene_resource_implementation.md new file mode 100644 index 0000000..96c09cf --- /dev/null +++ b/plans/cutscene_resource_implementation.md @@ -0,0 +1,108 @@ +# CutsceneResource Implementation Plan + +## Overview + +This document describes the changes needed to implement the new CutsceneResource data structure that will properly store nodes and connections for use by both the editor and runtime systems. + +## Current Issues + +The current CutsceneResource.gd has several issues: +1. Uses "name" instead of "id" for node identification +2. Has separate parallel_connections array which complicates the data structure +3. Doesn't follow a consistent data structure for nodes and connections +4. Lacks proper unique ID generation for connections + +## Proposed Implementation + +### New Data Structure + +The resource will store: +- `nodes`: Array of node objects with consistent structure +- `connections`: Array of connection objects with consistent structure +- `metadata`: Version and timestamp information + +### Node Structure + +Each node will have: +```json +{ + "id": "unique_string_identifier", + "type": "node_type", + "position": { + "x": 100, + "y": 150 + }, + "parameters": { + // Type-specific parameters + } +} +``` + +### Connection Structure + +Each connection will have: +```json +{ + "id": "unique_string_identifier", + "from_node": "source_node_id", + "from_port": 0, + "to_node": "target_node_id", + "to_port": 0 +} +``` + +## Required Changes to CutsceneResource.gd + +### 1. Update Properties + +Replace the current properties with: +```gdscript +@export var nodes: Array = [] +@export var connections: Array = [] +@export var metadata: Dictionary = {} +``` + +### 2. Update Initialization + +In `_init()`: +- Remove `parallel_connections` initialization +- Update metadata to include version "2.0" to indicate the new structure + +### 3. Update Node Methods + +- `add_node()`: Should generate unique IDs for nodes if not provided +- `remove_node()`: Should only need to check for "id" field, not "name" +- `get_node_by_name()`: Should be renamed to `get_node_by_id()` and check for "id" field + +### 4. Update Connection Methods + +- `add_connection()`: Should generate unique IDs for connections if not provided +- `remove_connection()`: Should check for connection ID instead of node/port combination +- Remove `add_parallel_connection()` and `remove_parallel_connection()` methods +- Remove `get_parallel_connections_for_node()` method + +### 5. Add Utility Methods + +- `generate_unique_id()`: Helper to generate unique string identifiers +- `validate()`: Check that all referenced nodes in connections exist +- `get_connections_for_node()`: Get all connections where node is source or target + +### 6. Update Load/Save Methods + +- Ensure that when loading from existing resources, the data structure is converted properly +- When saving, maintain the clean structure + +## Implementation Steps + +1. Create backup of current CutsceneResource.gd +2. Rewrite CutsceneResource.gd with new structure +3. Update references in CutsceneGraphEdit.gd to use new methods +4. Update CutsceneGenerator.gd to work with new structure +5. Test with existing example cutscenes +6. Update documentation + +## Compatibility Considerations + +- Need to maintain backward compatibility with existing cutscene files +- Should provide migration path for existing resources +- Consider adding a version field to distinguish between old and new formats \ No newline at end of file diff --git a/plans/cutscene_resource_implementation_summary.md b/plans/cutscene_resource_implementation_summary.md new file mode 100644 index 0000000..6b96ae8 --- /dev/null +++ b/plans/cutscene_resource_implementation_summary.md @@ -0,0 +1,93 @@ +# Cutscene Resource Implementation Summary + +## Project Overview + +This project aims to refactor the cutscene editor addon to focus on managing a cutscene resource rather than generating GDScript code. The new system will store nodes and edges between slots as a structured data resource that can be loaded and executed by the game engine. + +## Key Components + +### 1. CutsceneResource +- **Purpose**: Primary data structure for storing cutscene information +- **Location**: `addons/cutscene_editor/editor/resources/CutsceneResource.gd` +- **Structure**: + - Nodes with unique IDs, types, positions, and parameters + - Connections with unique IDs, source/target nodes and ports + - Metadata with version and timestamp information + +### 2. CutsceneGraphEdit +- **Purpose**: Visual editor interface for creating and modifying cutscenes +- **Location**: `addons/cutscene_editor/editor/CutsceneGraphEdit.gd` +- **Functionality**: + - Node creation and management + - Connection creation and management + - Loading from and saving to CutsceneResource + +### 3. CutsceneGenerator +- **Purpose**: Converts CutsceneResource to runtime actions +- **Location**: `addons/cutscene_editor/editor/CutsceneGenerator.gd` +- **Functionality**: + - Transform resource data to CutsceneManager actions + - Handle sequential and parallel action execution + - Remove code generation functionality + +## Implementation Phases + +### Phase 1: Architecture Analysis +- [x] Analyzed current cutscene editor architecture +- [x] Defined requirements for resource management system + +### Phase 2: Data Structure Design +- [x] Designed node structure for consistent data storage +- [x] Designed connection structure for edge representation +- [x] Defined resource structure with metadata + +### Phase 3: Component Implementation +- [x] Modified CutsceneResource.gd for new data structure +- [x] Updated CutsceneGraphEdit.gd for new resource structure +- [x] Refactored CutsceneGenerator.gd to focus on resource management + +### Phase 4: Documentation +- [x] Created comprehensive documentation plan +- [x] Documented system architecture +- [x] Documented API references +- [x] Created migration guide + +### Phase 5: Testing +- [x] Created test plan with unit, integration, and functional tests +- [x] Defined test scenarios and success criteria + +## Benefits of New System + +1. **Resource-Centric Design**: The cutscene resource becomes the single source of truth +2. **Clean Data Structure**: Consistent format for nodes and connections +3. **Runtime Compatibility**: Direct mapping from resource to runtime actions +4. **No Code Generation**: Eliminates complexity of code generation +5. **Extensibility**: Easy to add new node and action types + +## Migration Path + +1. **Backward Compatibility**: Support for loading old format resources +2. **Automatic Conversion**: Resources converted to new format when saved +3. **Documentation**: Clear migration guide for existing projects + +## Next Steps + +To implement this plan, the following actions are needed: + +1. **Switch to Code Mode**: Implementation requires code modifications +2. **Create Backup**: Backup existing files before making changes +3. **Implement CutsceneResource**: Update with new data structure +4. **Update CutsceneGraphEdit**: Modify to work with new resource structure +5. **Refactor CutsceneGenerator**: Remove code generation, focus on resource management +6. **Create Documentation**: Implement the documentation plan +7. **Implement Tests**: Create test suite based on test plan +8. **Verify Implementation**: Test with example cutscenes + +## Success Criteria + +1. Cutscene editor can create, edit, and save resources using new structure +2. Resources can be loaded and executed by runtime system +3. No code generation functionality remains +4. Comprehensive documentation exists +5. Test suite passes all defined tests +6. Backward compatibility maintained for existing projects \ No newline at end of file diff --git a/plans/cutscene_test_plan.md b/plans/cutscene_test_plan.md new file mode 100644 index 0000000..5ec06d1 --- /dev/null +++ b/plans/cutscene_test_plan.md @@ -0,0 +1,231 @@ +# Cutscene System Test Plan + +## Overview + +This document outlines the testing approach for the updated cutscene editor system that focuses on resource management. + +## Test Categories + +### 1. Unit Tests + +#### CutsceneResource Tests +- Test node addition and removal +- Test connection addition and removal +- Test unique ID generation +- Test data validation +- Test loading from existing resources +- Test saving to new format + +#### CutsceneGenerator Tests +- Test resource to action conversion +- Test action creation from nodes +- Test parallel group handling +- Test error handling for malformed resources + +#### CutsceneGraphEdit Tests +- Test loading resources into editor +- Test saving resources from editor +- Test node creation and deletion +- Test connection creation and deletion + +### 2. Integration Tests + +#### Editor to Runtime Flow +- Create cutscene in editor +- Save resource +- Load resource in runtime +- Execute cutscene successfully + +#### Backward Compatibility +- Load old format resources +- Convert to new format +- Execute successfully + +### 3. Functional Tests + +#### Node Types +- Entry node creation and behavior +- Exit node creation and behavior +- Move action node creation and parameter handling +- Dialogue action node creation and parameter handling +- Animation action node creation and parameter handling +- Turn action node creation and parameter handling +- Wait action node creation and parameter handling +- Parallel group node creation and behavior + +#### Connection Logic +- Sequential connection flow +- Parallel connection flow +- Connection validation +- Cycle detection + +## Test Implementation + +### 1. Unit Test Structure + +```gdscript +# Example unit test for CutsceneResource +func test_add_node(): + var resource = CutsceneResource.new() + var node_data = { + "id": "test_node_1", + "type": "move", + "position": {"x": 100, "y": 150}, + "parameters": { + "character": "player", + "target_x": 200, + "target_y": 300, + "speed": 100 + } + } + + resource.add_node(node_data) + assert(resource.nodes.size() == 1) + assert(resource.nodes[0]["id"] == "test_node_1") +``` + +### 2. Integration Test Structure + +```gdscript +# Example integration test +func test_editor_to_runtime_flow(): + # Create cutscene in "editor" + var graph_edit = CutsceneGraphEdit.new() + var node = graph_edit.add_node("move", Vector2(100, 150)) + node.node_id = "move_1" + node.set_parameter("character", "player") + node.set_parameter("target_x", 200) + node.set_parameter("target_y", 300) + node.set_parameter("speed", 100) + + # Save resource + var resource = graph_edit.save_to_cutscene() + + # Load in "runtime" + var generator = CutsceneGenerator.new() + var cutscene_manager = generator.generate_cutscene(resource) + + # Verify actions were created correctly + assert(cutscene_manager.sequential_actions.size() == 1) + assert(cutscene_manager.sequential_actions[0] is MoveAction) +``` + +## Test Scenarios + +### Basic Flow Test +1. Create a simple cutscene with entry → move → exit +2. Save the resource +3. Load and execute the cutscene +4. Verify all actions execute correctly + +### Parallel Execution Test +1. Create a cutscene with entry → parallel group → exit +2. Add multiple actions to the parallel group +3. Save the resource +4. Load and execute the cutscene +5. Verify all parallel actions execute correctly + +### Complex Flow Test +1. Create a complex cutscene with multiple branches +2. Include sequential and parallel actions +3. Save the resource +4. Load and execute the cutscene +5. Verify execution order is correct + +### Parameter Validation Test +1. Create nodes with various parameter types +2. Verify parameters are stored correctly +3. Verify parameters are passed to actions correctly + +### Error Handling Test +1. Create malformed resources +2. Verify appropriate error handling +3. Verify graceful failure modes + +## Test Data + +### Sample Cutscene Resources + +#### Simple Move Cutscene +```json +{ + "version": "2.0", + "metadata": { + "created": "2023-01-01T00:00:00Z", + "modified": "2023-01-01T00:00:00Z" + }, + "nodes": [ + { + "id": "entry_1", + "type": "entry", + "position": {"x": 100, "y": 100}, + "parameters": {} + }, + { + "id": "move_1", + "type": "move", + "position": {"x": 250, "y": 100}, + "parameters": { + "character": "player", + "target_x": 300, + "target_y": 200, + "speed": 100 + } + }, + { + "id": "exit_1", + "type": "exit", + "position": {"x": 400, "y": 100}, + "parameters": {} + } + ], + "connections": [ + { + "id": "conn_1", + "from_node": "entry_1", + "from_port": 0, + "to_node": "move_1", + "to_port": 0 + }, + { + "id": "conn_2", + "from_node": "move_1", + "from_port": 0, + "to_node": "exit_1", + "to_port": 0 + } + ] +} +``` + +## Implementation Plan + +### Phase 1: Unit Tests +1. Create test framework +2. Implement CutsceneResource tests +3. Implement CutsceneGenerator tests +4. Implement CutsceneGraphEdit tests + +### Phase 2: Integration Tests +1. Implement editor to runtime flow tests +2. Implement backward compatibility tests + +### Phase 3: Functional Tests +1. Implement node type tests +2. Implement connection logic tests +3. Implement complex scenario tests + +### Phase 4: Validation +1. Run all tests +2. Fix any issues +3. Verify coverage +4. Document results + +## Success Criteria + +1. All unit tests pass +2. All integration tests pass +3. All functional tests pass +4. Backward compatibility maintained +5. Performance acceptable +6. No critical bugs found \ No newline at end of file