Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions autoloads/constants.gd
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const NODE_SCENES = {
"Choice": preload("res://nodes/choice_node/choice_node.tscn"),
"Comment": preload("res://nodes/comment_node/comment_node.tscn"),
"Condition": preload("res://nodes/condition_node/condition_node.tscn"),
"Custom": preload("res://nodes/custom_node/custom_node.tscn"),
"DefineCustom": preload("res://nodes/define_custom_node/define_custom_node.tscn"),
"Random": preload("res://nodes/random_node/random_node.tscn"),
"EndPath": preload("res://nodes/end_path_node/end_path_node.tscn"),
"Event": preload("res://nodes/event_node/event_node.tscn"),
Expand Down
37 changes: 36 additions & 1 deletion common/layouts/graph_edit/monologue_graph_edit.gd
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
class_name MonologueGraphEdit extends GraphEdit


signal connection_made
signal connection_broken

var close_button_scene = preload("res://common/ui/buttons/close_button.tscn")
var base_options = {}
var data: Dictionary
Expand Down Expand Up @@ -125,6 +128,7 @@ func disconnect_outbound_from_node(from_node: StringName, from_port: int) -> voi
var to_node = connection.get("to_node")
var to_port = connection.get("to_port")
disconnect_node(from_node, from_port, to_node, to_port)
connection_broken.emit()


## Deletes the given graphnode and return its dictionary data.
Expand All @@ -134,6 +138,7 @@ func free_graphnode(node: MonologueGraphNode) -> Dictionary:
for c in inbound_connections + outbound_connections:
disconnect_node(c.get("from_node"), c.get("from_port"),
c.get("to_node"), c.get("to_port"))
connection_broken.emit()

var node_data = node._to_dict()
if "options" in node:
Expand Down Expand Up @@ -259,9 +264,10 @@ func post_node_offset(nodes: Array[MonologueGraphNode]) -> void:
func propagate_connection(from_node, from_port, to_node, to_port, next = true) -> void:
if next:
connect_node(from_node, from_port, to_node, to_port)

connection_made.emit()
else:
disconnect_node(from_node, from_port, to_node, to_port)
connection_broken.emit()

var graph_node = get_node_or_null(NodePath(from_node))
if graph_node and graph_node.has_method("update_next_id"):
Expand Down Expand Up @@ -358,6 +364,8 @@ func _on_connection_request(from_node, from_port, to_node, to_port) -> void:
undo_redo.add_do_method(propagate_connection.bindv(arguments))
undo_redo.add_undo_method(propagate_connection.bindv(arguments + [false]))
undo_redo.commit_action()

connection_made.emit()


func _on_disconnection_request(from_node, from_port, to_node, to_port) -> void:
Expand Down Expand Up @@ -408,3 +416,30 @@ func _on_mouse_entered() -> void:
func _on_mouse_exited() -> void:
DisplayServer.cursor_set_custom_image(null)
mouse_hovering = false


func get_all_custom_nodes() -> Array[MonologueGraphNode]:
var nodes: Array[MonologueGraphNode] = get_nodes()
return nodes.filter(func(n): return n is DefineCustomNode)


# Recursive function
func get_end_of_chain_nodes(node: MonologueGraphNode, n: int = 0) -> Array:
var port_count: int = node.get_output_port_count()
var end_of_chain: Array = []

if n >= 255:
return end_of_chain

var all_connections: Array = []
for port_idx in range(port_count):
all_connections.append_array(get_all_connections_from_slot(node.name, port_idx))

for connected in all_connections:
if connected == null: continue
end_of_chain.append_array(get_end_of_chain_nodes(connected, n+1))

if port_count > all_connections.size():
end_of_chain.append(node)

return end_of_chain
4 changes: 4 additions & 0 deletions common/ui/fields/collapsible_field/collapsible_field.gd
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,7 @@ func _on_add_button_pressed() -> void:

func _is_not_being_deleted(node: Node) -> bool:
return not node.is_queued_for_deletion()


func _update() -> void:
add_button.visible = show_add_button
8 changes: 8 additions & 0 deletions common/windows/graph_node_picker/graph_node_picker.gd
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ func _on_enable_picker_mode(node: String = "", port: int = -1, mouse_pos = null,
var mouse_position = Vector2i(get_parent().get_global_mouse_position())
position = get_tree().get_root().position + mouse_position
current_screen = get_tree().get_root().current_screen

%Tree._load()
show()


Expand All @@ -61,3 +63,9 @@ func _on_create_button_pressed() -> void: close()
func _on_visibility_changed() -> void:
var root_screen: int = get_tree().get_root().current_screen
current_screen = root_screen


func _on_tree_button_clicked(_item: TreeItem, _column: int, id: int, _mouse_button_index: int) -> void:
if id == 1:
GlobalSignal.emit("add_graph_node", ["DefineCustom", self])
close()
2 changes: 2 additions & 0 deletions common/windows/graph_node_picker/graph_node_picker.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ layout_mode = 2
placeholder_text = "Search"

[node name="Tree" type="Tree" parent="PanelContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
hide_root = true
Expand All @@ -59,6 +60,7 @@ text = "Cancel"
[connection signal="close_requested" from="." to="." method="_on_close_requested"]
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]
[connection signal="text_changed" from="PanelContainer/VBoxContainer/SearchBar" to="PanelContainer/VBoxContainer/Tree" method="_on_search_bar_text_changed"]
[connection signal="button_clicked" from="PanelContainer/VBoxContainer/Tree" to="." method="_on_tree_button_clicked"]
[connection signal="item_selected" from="PanelContainer/VBoxContainer/Tree" to="PanelContainer/VBoxContainer/Tree" method="_on_item_selected"]
[connection signal="pressed" from="PanelContainer/VBoxContainer/HBoxContainer/CreateButton" to="." method="_on_create_button_pressed"]
[connection signal="pressed" from="PanelContainer/VBoxContainer/HBoxContainer/CreateButton" to="PanelContainer/VBoxContainer/Tree" method="_create"]
Expand Down
34 changes: 27 additions & 7 deletions common/windows/graph_node_picker/graph_node_tree.gd
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ extends Tree

## The data to build the tree
## An oject can contain keys with name "text", "value", icon" and "children".
var _data = [
func _get_data() -> Array:
return [
{"text": "Narration", "children": [
{"text": "Sentence", "icon": "text.svg"},
{"text": "Choice", "icon": "choice.svg"},
Expand All @@ -30,35 +31,54 @@ var _data = [
{"text": "Helpers", "children": [
{"text": "Comment", "icon": "comment.svg"},
{"text": "Reroute", "icon": "path.svg"},
]}
]},
{"text": "Custom nodes", "button_icon": "plus.svg", "button_id": 1,"children": _get_custom_nodes()}
]

var _first_item_found: bool = false


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
func _load() -> void:
clear()
var root = create_item()
_recusive_load_data(_data, root)
_recusive_load_data(_get_data(), root)
deselect_all()


func _get_custom_nodes() -> Array:
var all_custom_nodes: Array = window.switcher.current.get_all_custom_nodes()
var data: Array = []

for custom_node: MonologueGraphNode in all_custom_nodes:
data.append({
"text": custom_node.custom_node_name.value
})

return data


func _recusive_load_data(items: Array, tree_parent: TreeItem) -> void:
for obj: Dictionary in items:
var tree_item = create_item(tree_parent)
var tree_item: TreeItem = create_item(tree_parent)
tree_item.collapsed = true

if obj.has("text"):
tree_item.set_text(0, obj.get("text"))
if obj.has("icon"):
var icon_texture = load("res://ui/assets/icons/" + obj.get("icon"))
tree_item.set_icon(0, icon_texture)
if obj.has("button_icon"):
var icon_texture = load("res://ui/assets/icons/" + obj.get("button_icon"))
tree_item.add_button(0, icon_texture, obj.get("button_id", 1))
if obj.has("children"):
_recusive_load_data(obj.get("children"), tree_item)


func _create() -> void:
var node_type = get_selected().get_text(0)
if get_selected().get_parent().get_text(0) == "Custom nodes":
GlobalSignal.emit("add_custom_graph_node", [node_type, window])
return
GlobalSignal.emit("add_graph_node", [node_type, window])


Expand Down
95 changes: 95 additions & 0 deletions nodes/custom_node/custom_node.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
class_name CustomNode extends MonologueGraphNode


var define_node_id: String = ""


func _ready():
node_type = "NodeCustom"

get_graph_edit().connection_made.connect(_update)
get_graph_edit().connection_broken.connect(_update)

super._ready()
_update()


func _get_define_node() -> MonologueGraphNode:
return get_graph_edit().get_node_by_id(define_node_id)


func _update(_old_value: Variant = null, _new_value: Variant = null) -> void:
await get_tree().process_frame # Ensure all nodes are loaded
var define_node: MonologueGraphNode = _get_define_node()
if define_node:
if not define_node.custom_node_name.is_connected("preview", _update_title):
define_node.custom_node_name.connect("preview", _update_title)
_update_title()

var slot_count: int = max(1, define_node.get_end_of_chain_slot_count())
var diff_slot_count: int = get_child_count() - slot_count

if sign(diff_slot_count) >= 0:
var child_idx: int = get_child_count() - 1
for child in get_children().slice(get_child_count() - abs(diff_slot_count), get_child_count()):
var connections: Array = get_graph_edit().get_all_connections_from_slot(name, child_idx)
for connected in connections:
get_graph_edit().disconnect_node(name, child_idx, connected.name, 0)

child.queue_free()
else:
for i in range(abs(diff_slot_count)):
var new_child: HBoxContainer = HBoxContainer.new()
new_child.custom_minimum_size.y = 32.0
add_child(new_child)
set_slot(get_child_count()-1, false, 0, Color.WHITE, true, 0, Color.WHITE)
_update_slot_icons()
await get_tree().process_frame
size.x = 0
super._update()



func _update_title(_value: Variant = null) -> void:
var define_node: MonologueGraphNode = _get_define_node()
if define_node:
await get_tree().process_frame
title = define_node.custom_node_name.value


func _from_dict(dict):
define_node_id = dict.get("DefineNodeID")

super._from_dict(dict)


func _to_fields(dict: Dictionary) -> void:
super._to_fields(dict)
dict["DefineNodeID"] = define_node_id
dict["Outputs"] = []

for port in range(get_output_port_count()):
var next_node: MonologueGraphNode = get_graph_edit().get_all_connections_from_slot(name, port)[0]
dict["Outputs"].append(next_node.id.value)


func _load_connections(data: Dictionary, _key: String = "NextID") -> void:
var outputs: Array = data.get("Outputs", [])

for i in range(outputs.size()-1):
var new_child: HBoxContainer = HBoxContainer.new()
new_child.custom_minimum_size.y = 32.0
add_child(new_child)
set_slot(i+1, false, 0, Color.WHITE, true, 0, Color.WHITE)

var port_idx: int = 0
for output_id in outputs:
if output_id is String:
var next_node = get_parent().get_node_by_id(output_id)
if next_node:
get_parent().connect_node(name, port_idx, next_node.name, 0)
port_idx += 1


func _to_next(_dict: Dictionary, _key: String = "NextID") -> void:
pass
1 change: 1 addition & 0 deletions nodes/custom_node/custom_node.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://dfqx6iucx3e2m
29 changes: 29 additions & 0 deletions nodes/custom_node/custom_node.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[gd_scene load_steps=3 format=3 uid="uid://cl785aih6klk8"]

[ext_resource type="Script" uid="uid://dfqx6iucx3e2m" path="res://nodes/custom_node/custom_node.gd" id="3_w5pkq"]

[sub_resource type="Theme" id="Theme_llmqa"]

[node name="CustomNode" type="GraphNode"]
offset_right = 191.0
offset_bottom = 63.0
size_flags_horizontal = 0
size_flags_vertical = 0
theme = SubResource("Theme_llmqa")
theme_override_constants/separation = 0
title = "<node_name>"
slot/0/left_enabled = true
slot/0/left_type = 0
slot/0/left_color = Color(1, 1, 1, 1)
slot/0/left_icon = null
slot/0/right_enabled = true
slot/0/right_type = 0
slot/0/right_color = Color(1, 1, 1, 1)
slot/0/right_icon = null
slot/0/draw_stylebox = false
script = ExtResource("3_w5pkq")
titlebar_color = Color(0.0196078, 0.513726, 0.341176, 1)

[node name="HBox" type="HBoxContainer" parent="."]
custom_minimum_size = Vector2(0, 32)
layout_mode = 2
36 changes: 36 additions & 0 deletions nodes/define_custom_node/define_custom_node.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class_name DefineCustomNode extends MonologueGraphNode


var custom_node_name: Property = Property.new(LINE, {}, "MyCustomNode")


func _ready():
node_type = "NodeDefineCustom"

custom_node_name.connect("preview", _update)

super._ready()
_update()


func _update(_value: Variant = null) -> void:
title = "Define %s" % custom_node_name.value


func get_end_of_chain_slot_count() -> int:
var end_of_chain_nodes: Array = get_graph_edit().get_end_of_chain_nodes(self)
var end_of_chain_slot_count: int = 0

for node: MonologueGraphNode in end_of_chain_nodes:
var port_count: int = node.get_output_port_count()
var all_connections: Array = []
for port_idx in range(port_count):
all_connections.append_array(get_graph_edit().get_all_connections_from_slot(node.name, port_idx))

end_of_chain_slot_count += port_count - all_connections.size()

return end_of_chain_slot_count


func _from_dict(dict: Dictionary):
super._from_dict(dict)
1 change: 1 addition & 0 deletions nodes/define_custom_node/define_custom_node.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://bki5xr0imaspb
Loading