Skip to content

Commit a5d5b65

Browse files
authored
Merge pull request #164 from endlessm/T35536-decouple-alternative
T35536 decouple mid-term option
2 parents 55f8b7e + 56c2031 commit a5d5b65

File tree

16 files changed

+580
-393
lines changed

16 files changed

+580
-393
lines changed

addons/block_code/block_definition.gd

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
extends Resource
2+
3+
const Types = preload("res://addons/block_code/types/types.gd")
4+
5+
var name: StringName
6+
var type: Types.BlockType
7+
var description: String
8+
var category: String
9+
10+
var label_template: String
11+
var code_template: String
12+
var defaults: Dictionary = {}
13+
14+
## Only for blocks of type Types.ENTRY. If non-empty, this block defines a
15+
## callback that will be connected to the signal with this name.
16+
var signal_name: String = ""
17+
18+
19+
func _init(p_name: StringName, p_type: Types.BlockType):
20+
name = p_name
21+
type = p_type

addons/block_code/blocks_catalog.gd

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
extends Object
2+
3+
const BlockDefinition = preload("res://addons/block_code/block_definition.gd")
4+
const Types = preload("res://addons/block_code/types/types.gd")
5+
6+
static var _catalog: Dictionary
7+
8+
9+
static func setup():
10+
if _catalog:
11+
return
12+
13+
_catalog = {}
14+
var block_definition: BlockDefinition = BlockDefinition.new(&"ready_block", Types.BlockType.ENTRY)
15+
block_definition.label_template = "On Ready"
16+
block_definition.code_template = "func _ready():"
17+
block_definition.description = 'Attached blocks will be executed once when the node is "ready"'
18+
block_definition.category = "Lifecycle"
19+
_catalog[&"ready_block"] = block_definition
20+
21+
block_definition = BlockDefinition.new(&"print", Types.BlockType.EXECUTE)
22+
block_definition.label_template = "print {text: STRING}"
23+
block_definition.code_template = "print({text})"
24+
block_definition.defaults = {"text": "Hello"}
25+
block_definition.description = "Print the text to output"
26+
block_definition.category = "Log"
27+
_catalog[&"print"] = block_definition
28+
29+
30+
static func get_block(block_name: StringName):
31+
return _catalog.get(block_name)
32+
33+
34+
static func has_block(block_name: StringName):
35+
return block_name in _catalog

addons/block_code/examples/pong_game/pong_game.tscn

Lines changed: 427 additions & 331 deletions
Large diffs are not rendered by default.

addons/block_code/ui/block_canvas/block_canvas.gd

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,16 @@ func clear_canvas():
161161

162162

163163
func load_tree(parent: Node, node: SerializedBlockTreeNode):
164-
var _block_scene_path = _block_scenes_by_class[node.serialized_block.block_class]
165-
var scene: Block = load(_block_scene_path).instantiate()
164+
var scene: Block = Util.instantiate_block(node.name)
165+
166+
# TODO: Remove once the data/UI decouple is done.
167+
if scene == null:
168+
var _block_scene_path = _block_scenes_by_class[node.serialized_block.block_class]
169+
scene = load(_block_scene_path).instantiate()
166170
for prop_pair in node.serialized_block.serialized_props:
167171
scene.set(prop_pair[0], prop_pair[1])
172+
173+
scene.position = node.position
168174
scene.resource = node
169175
parent.add_child(scene)
170176

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
class_name SerializedBlockTreeNode
22
extends Resource
33

4-
@export var serialized_block: SerializedBlock
4+
@export var name: StringName
5+
@export var position: Vector2
56
@export var path_child_pairs: Array
67

8+
# TODO: Remove once the data/UI decouple is done.
9+
@export var serialized_block: SerializedBlock
10+
711

8-
func _init(p_serialized_block: SerializedBlock = null, p_path_child_pairs: Array = []):
12+
func _init(p_name: StringName, p_position: Vector2 = Vector2.ZERO, p_serialized_block: SerializedBlock = null, p_path_child_pairs: Array = []):
13+
name = p_name
14+
position = p_position
915
serialized_block = p_serialized_block
1016
path_child_pairs = p_path_child_pairs

addons/block_code/ui/blocks/block/block.gd

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
class_name Block
33
extends MarginContainer
44

5+
const BlocksCatalog = preload("res://addons/block_code/blocks_catalog.gd")
56
const InstructionTree = preload("res://addons/block_code/instruction_tree/instruction_tree.gd")
67
const Types = preload("res://addons/block_code/types/types.gd")
78

89
signal drag_started(block: Block)
910
signal modified
1011

1112
## Name of the block to be referenced by others in search
12-
@export var block_name: String = ""
13+
@export var block_name: StringName
1314

1415
## Label of block (optionally used to draw block labels)
1516
@export var label: String = ""
@@ -83,18 +84,29 @@ func get_instruction_node() -> InstructionTree.TreeNode:
8384
func update_resources(undo_redo: EditorUndoRedoManager):
8485
if resource == null:
8586
var serialized_block = SerializedBlock.new(get_block_class(), get_serialized_props())
86-
resource = SerializedBlockTreeNode.new(serialized_block)
87+
resource = SerializedBlockTreeNode.new(block_name, position, serialized_block)
8788
return
8889

90+
if resource.position != position:
91+
undo_redo.add_undo_property(resource, "position", resource.position)
92+
undo_redo.add_do_property(resource, "position", position)
93+
8994
var serialized_props = get_serialized_props()
95+
9096
if serialized_props != resource.serialized_block.serialized_props:
9197
undo_redo.add_undo_property(resource.serialized_block, "serialized_props", resource.serialized_block.serialized_props)
9298
undo_redo.add_do_property(resource.serialized_block, "serialized_props", serialized_props)
9399

94100

95101
# Override this method to add more serialized properties
96102
func get_serialized_props() -> Array:
97-
return serialize_props(["block_name", "label", "color", "block_type", "position", "scope"])
103+
if not BlocksCatalog.has_block(block_name):
104+
return serialize_props(["block_name", "label", "color", "block_type", "position", "scope"])
105+
106+
# TODO: Remove remaining serialization:
107+
# - Derive color from category.
108+
# - Handle scope in a different way?
109+
return serialize_props(["color", "scope"])
98110

99111

100112
func _to_string():

addons/block_code/ui/blocks/control_block/control_block.tscn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
size_flags_horizontal = 0
88
mouse_filter = 2
99
script = ExtResource("1_2hbir")
10-
block_name = "control_block"
10+
block_name = &"control_block"
1111
label = "Control Block"
1212
color = Color(0.59979, 0.536348, 0.876215, 1)
1313
bottom_snap_path = NodePath("VBoxContainer/SnapPoint")

addons/block_code/ui/blocks/entry_block/entry_block.gd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ func get_entry_statement() -> String:
3030

3131
func get_serialized_props() -> Array:
3232
var props := super()
33-
props.append_array(serialize_props(["signal_name"]))
33+
if not BlocksCatalog.has_block(block_name):
34+
props.append_array(serialize_props(["signal_name"]))
3435
return props

addons/block_code/ui/blocks/entry_block/entry_block.tscn

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
[node name="EntryBlock" instance=ExtResource("1_byjbb")]
77
script = ExtResource("2_3ik8h")
88
signal_name = ""
9-
defaults = {}
10-
block_name = "entry_block"
9+
block_name = &"entry_block"
1110
label = "EntryBlock"
1211
block_type = 1
1312

addons/block_code/ui/blocks/parameter_block/parameter_block.tscn

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ corner_radius_bottom_left = 16
1818
offset_right = 16.0
1919
offset_bottom = 8.0
2020
size_flags_horizontal = 0
21+
mouse_filter = 2
2122
script = ExtResource("1_0hajy")
22-
defaults = null
23-
block_name = "parameter_block"
23+
block_name = &"parameter_block"
2424
label = "Param"
2525
block_type = 3
2626

addons/block_code/ui/blocks/statement_block/statement_block.gd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ func _on_drag_drop_area_mouse_down():
3636

3737
func get_serialized_props() -> Array:
3838
var props := super()
39-
props.append_array(serialize_props(["block_format", "statement", "defaults"]))
39+
if not BlocksCatalog.has_block(block_name):
40+
props.append_array(serialize_props(["block_format", "statement", "defaults"]))
4041

4142
var _param_input_strings: Dictionary = {}
4243
for pair in param_name_input_pairs:

addons/block_code/ui/blocks/statement_block/statement_block.tscn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
size_flags_horizontal = 0
1010
mouse_filter = 2
1111
script = ExtResource("1_6wvlf")
12-
block_name = "statement_block"
12+
block_name = &"statement_block"
1313
label = "StatementBlock"
1414
bottom_snap_path = NodePath("VBoxContainer/SnapPoint")
1515

addons/block_code/ui/bsd_templates/default_blocktrees.tres

Lines changed: 0 additions & 29 deletions
This file was deleted.
Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
1-
[gd_resource type="Resource" script_class="BlockScriptData" load_steps=3 format=3 uid="uid://dit7fykhl3h48"]
1+
[gd_resource type="Resource" script_class="BlockScriptData" load_steps=8 format=3 uid="uid://dit7fykhl3h48"]
22

3-
[ext_resource type="Script" path="res://addons/block_code/block_script_data/block_script_data.gd" id="1_h8ggn"]
4-
[ext_resource type="Resource" uid="uid://djn5nejdsfu2a" path="res://addons/block_code/ui/bsd_templates/default_blocktrees.tres" id="1_y70fv"]
3+
[ext_resource type="Script" path="res://addons/block_code/ui/block_canvas/serialized_block_tree_node.gd" id="1_barc5"]
4+
[ext_resource type="Script" path="res://addons/block_code/ui/block_canvas/serialized_block.gd" id="2_cgfpx"]
5+
[ext_resource type="Script" path="res://addons/block_code/ui/block_canvas/serialized_block_tree_node_array.gd" id="3_gx4d7"]
6+
[ext_resource type="Script" path="res://addons/block_code/block_script_data/block_script_data.gd" id="4_cqq7x"]
7+
8+
[sub_resource type="Resource" id="Resource_b0aen"]
9+
script = ExtResource("2_cgfpx")
10+
block_class = &"EntryBlock"
11+
serialized_props = [["color", Color(0.92549, 0.231373, 0.34902, 1)], ["scope", ""], ["param_input_strings", {}]]
12+
13+
[sub_resource type="Resource" id="Resource_1h6wi"]
14+
script = ExtResource("1_barc5")
15+
name = &"ready_block"
16+
position = Vector2(54, 47)
17+
path_child_pairs = []
18+
serialized_block = SubResource("Resource_b0aen")
19+
20+
[sub_resource type="Resource" id="Resource_nkub8"]
21+
script = ExtResource("3_gx4d7")
22+
array = Array[ExtResource("1_barc5")]([SubResource("Resource_1h6wi")])
523

624
[resource]
7-
script = ExtResource("1_h8ggn")
25+
script = ExtResource("4_cqq7x")
826
script_inherits = "INHERIT_DEFAULT"
9-
block_trees = ExtResource("1_y70fv")
27+
block_trees = SubResource("Resource_nkub8")
28+
variables = Array[Resource("res://addons/block_code/ui/block_canvas/variable_resource.gd")]([])
1029
generated_script = "extends INHERIT_DEFAULT"
30+
version = 0

addons/block_code/ui/picker/categories/category_factory.gd

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ extends Object
33

44
const BlockCategory = preload("res://addons/block_code/ui/picker/categories/block_category.gd")
55
const Types = preload("res://addons/block_code/types/types.gd")
6+
const Util = preload("res://addons/block_code/ui/util.gd")
67

78
const BLOCKS: Dictionary = {
89
"control_block": preload("res://addons/block_code/ui/blocks/control_block/control_block.tscn"),
@@ -171,12 +172,7 @@ static func get_general_blocks() -> Array[Block]:
171172

172173
#region Lifecycle
173174

174-
b = BLOCKS["entry_block"].instantiate()
175-
b.block_name = "ready_block"
176-
b.block_format = "On Ready"
177-
b.statement = "func _ready():"
178-
b.tooltip_text = 'Attached blocks will be executed once when the node is "ready"'
179-
b.category = "Lifecycle"
175+
b = Util.instantiate_block(&"ready_block")
180176
block_list.append(b)
181177

182178
b = BLOCKS["entry_block"].instantiate()
@@ -259,13 +255,7 @@ static func get_general_blocks() -> Array[Block]:
259255
#endregion
260256
#region Logs
261257

262-
b = BLOCKS["statement_block"].instantiate()
263-
b.block_name = "print"
264-
b.block_format = "print {text: STRING}"
265-
b.statement = "print({text})"
266-
b.defaults = {"text": "Hello"}
267-
b.tooltip_text = "Print the text to output"
268-
b.category = "Log"
258+
b = Util.instantiate_block(&"print")
269259
block_list.append(b)
270260

271261
#endregion

addons/block_code/ui/util.gd

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,34 @@
11
extends Object
22

3+
const BlockDefinition = preload("res://addons/block_code/block_definition.gd")
4+
const BlocksCatalog = preload("res://addons/block_code/blocks_catalog.gd")
5+
const Types = preload("res://addons/block_code/types/types.gd")
6+
7+
const SCENE_PER_TYPE = {
8+
Types.BlockType.ENTRY: preload("res://addons/block_code/ui/blocks/entry_block/entry_block.tscn"),
9+
Types.BlockType.EXECUTE: preload("res://addons/block_code/ui/blocks/statement_block/statement_block.tscn"),
10+
}
11+
12+
13+
static func instantiate_block(block_name: StringName) -> Block:
14+
BlocksCatalog.setup()
15+
var block_definition: BlockDefinition = BlocksCatalog.get_block(block_name)
16+
if block_definition == null:
17+
push_error("The block %s is not in the catalog yet!" % block_name)
18+
return
19+
20+
var scene = SCENE_PER_TYPE[block_definition.type]
21+
var b = scene.instantiate()
22+
b.block_name = block_definition.name
23+
b.block_format = block_definition.label_template
24+
b.statement = block_definition.code_template
25+
b.defaults = block_definition.defaults
26+
b.tooltip_text = block_definition.description
27+
b.category = block_definition.category
28+
if block_definition.type == Types.BlockType.ENTRY and block_definition.signal_name != "":
29+
b.signal_name = block_definition.signal_name
30+
return b
31+
332

433
## Polyfill of Node.is_part_of_edited_scene(), available to GDScript in Godot 4.3+.
534
static func node_is_part_of_edited_scene(node: Node) -> bool:

0 commit comments

Comments
 (0)