Skip to content

Commit b6b4944

Browse files
committed
blocks: Add groups option block extension
Several blocks work with node groups. Rather than having the user enter the group, offer the current groups as options. This is trickier than expected since Godot offers no API to get the current groups. Finding them involves 2 parts: * Get scene local groups by calling get_groups() on each node in the scene. * Get project global groups (starting in 4.3) by getting the `global_group` values in the project settings. Monitoring for changes to the global groups is possible by listening for project settings changes. Monitoring for local group changes is not possible since the only events that occur are internal to Godot and not available in GDScript. https://phabricator.endlessm.com/T35647
1 parent 40acf7b commit b6b4944

8 files changed

+169
-28
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://bpvefei72nh3a"]
1+
[gd_resource type="Resource" load_steps=5 format=3 uid="uid://bpvefei72nh3a"]
22

33
[ext_resource type="Script" path="res://addons/block_code/code_generation/block_definition.gd" id="1_5qal7"]
4+
[ext_resource type="Script" path="res://addons/block_code/code_generation/option_data.gd" id="1_auf06"]
5+
[ext_resource type="Script" path="res://addons/block_code/blocks/communication/groups.gd" id="1_p83c7"]
6+
7+
[sub_resource type="Resource" id="Resource_sus0f"]
8+
script = ExtResource("1_auf06")
9+
selected = 0
10+
items = []
411

512
[resource]
613
script = ExtResource("1_5qal7")
@@ -10,8 +17,11 @@ description = "Add the node into the group"
1017
category = "Communication | Groups"
1118
type = 2
1219
variant_type = 0
13-
display_template = "add {node: OBJECT} to group {group: STRING}"
14-
code_template = "{node}.add_to_group({group})"
15-
defaults = {}
20+
display_template = "add {node: OBJECT} to group {group: NIL}"
21+
code_template = "{node}.add_to_group(\\\"{group}\\\")"
22+
defaults = {
23+
"group": SubResource("Resource_sus0f")
24+
}
1625
signal_name = ""
1726
scope = ""
27+
extension_script = ExtResource("1_p83c7")
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://bvrmau8atjx1x"]
1+
[gd_resource type="Resource" load_steps=5 format=3 uid="uid://bvrmau8atjx1x"]
22

3+
[ext_resource type="Script" path="res://addons/block_code/code_generation/option_data.gd" id="1_aom4j"]
34
[ext_resource type="Script" path="res://addons/block_code/code_generation/block_definition.gd" id="1_bcm71"]
5+
[ext_resource type="Script" path="res://addons/block_code/blocks/communication/groups.gd" id="2_42ixf"]
6+
7+
[sub_resource type="Resource" id="Resource_fk0wa"]
8+
script = ExtResource("1_aom4j")
9+
selected = 0
10+
items = []
411

512
[resource]
613
script = ExtResource("1_bcm71")
@@ -10,8 +17,11 @@ description = "Add this node into the group"
1017
category = "Communication | Groups"
1118
type = 2
1219
variant_type = 0
13-
display_template = "add to group {group: STRING}"
14-
code_template = "add_to_group({group})"
15-
defaults = {}
20+
display_template = "add to group {group: NIL}"
21+
code_template = "add_to_group(\\\"{group}\\\")"
22+
defaults = {
23+
"group": SubResource("Resource_fk0wa")
24+
}
1625
signal_name = ""
1726
scope = ""
27+
extension_script = ExtResource("2_42ixf")
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://c15vtdfihdxb8"]
1+
[gd_resource type="Resource" load_steps=5 format=3 uid="uid://c15vtdfihdxb8"]
22

3+
[ext_resource type="Script" path="res://addons/block_code/code_generation/option_data.gd" id="1_3nuts"]
34
[ext_resource type="Script" path="res://addons/block_code/code_generation/block_definition.gd" id="1_mlm68"]
5+
[ext_resource type="Script" path="res://addons/block_code/blocks/communication/groups.gd" id="1_of577"]
6+
7+
[sub_resource type="Resource" id="Resource_f4ctg"]
8+
script = ExtResource("1_3nuts")
9+
selected = 0
10+
items = []
411

512
[resource]
613
script = ExtResource("1_mlm68")
@@ -10,8 +17,11 @@ description = "Calls the method/function on each member of the given group"
1017
category = "Communication | Methods"
1118
type = 2
1219
variant_type = 0
13-
display_template = "call method {method_name: STRING} in group {group: STRING}"
14-
code_template = "get_tree().call_group({group}, {method_name})"
15-
defaults = {}
20+
display_template = "call method {method_name: STRING} in group {group: NIL}"
21+
code_template = "get_tree().call_group(\\\"{group\\\"}, {method_name})"
22+
defaults = {
23+
"group": SubResource("Resource_f4ctg")
24+
}
1625
signal_name = ""
1726
scope = ""
27+
extension_script = ExtResource("1_of577")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
@tool
2+
## Common BlockExtension for scene group options.
3+
extends BlockExtension
4+
5+
const OptionData = preload("res://addons/block_code/code_generation/option_data.gd")
6+
const Util = preload("res://addons/block_code/ui/util.gd")
7+
8+
9+
# Global groups are just project settings in the global_group group.
10+
# ProjectSettings doesn't offer an API to get the project groups or to get all
11+
# settings. Fortunately, settings are simply implemented as properties on the
12+
# ProjectSettings object.
13+
static func _add_global_groups(groups: Dictionary):
14+
for prop in ProjectSettings.get_property_list():
15+
var name: String = prop["name"]
16+
var parts := name.split("/", false, 1)
17+
if parts[0] == "global_group":
18+
groups[parts[1]] = null
19+
20+
21+
# Add all the groups in a node and its children, ignoring internal _ prefixed
22+
# groups.
23+
static func _add_node_groups(groups: Dictionary, node: Node):
24+
for group in node.get_groups():
25+
if not group.begins_with("_"):
26+
groups[String(group)] = null
27+
28+
for child in node.get_children():
29+
_add_node_groups(groups, child)
30+
31+
32+
func _get_edited_scene_groups() -> Array[String]:
33+
var groups: Dictionary
34+
_add_global_groups(groups)
35+
36+
var root := context_node.get_tree().edited_scene_root
37+
_add_node_groups(groups, root)
38+
39+
var sorted_groups: Array[String]
40+
sorted_groups.assign(groups.keys())
41+
sorted_groups.sort()
42+
return sorted_groups
43+
44+
45+
func _init():
46+
# FIXME: Only global group changes are monitored. Scene local groups should
47+
# also be monitored, but godot does not have any reasonable API to do that.
48+
ProjectSettings.settings_changed.connect(_on_project_settings_changed)
49+
50+
51+
func _context_node_changed():
52+
# If the context node changed, the scene local groups need to be updated.
53+
changed.emit()
54+
55+
56+
func get_defaults() -> Dictionary:
57+
if not context_node:
58+
return {}
59+
60+
# The default groups are only needed in the editor.
61+
if not Util.node_is_part_of_edited_scene(context_node):
62+
return {}
63+
64+
var groups: Array[String] = _get_edited_scene_groups()
65+
return {"group": OptionData.new(groups)}
66+
67+
68+
func _on_project_settings_changed():
69+
# FIXME: The global groups should be cached and compared so that the
70+
# defaults are only changed when the global groups actually change.
71+
changed.emit()
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://q4cnstftvsiu"]
1+
[gd_resource type="Resource" load_steps=5 format=3 uid="uid://q4cnstftvsiu"]
22

3+
[ext_resource type="Script" path="res://addons/block_code/code_generation/option_data.gd" id="1_cla3i"]
34
[ext_resource type="Script" path="res://addons/block_code/code_generation/block_definition.gd" id="1_tjyq5"]
5+
[ext_resource type="Script" path="res://addons/block_code/blocks/communication/groups.gd" id="2_o165d"]
6+
7+
[sub_resource type="Resource" id="Resource_d0v0d"]
8+
script = ExtResource("1_cla3i")
9+
selected = 0
10+
items = []
411

512
[resource]
613
script = ExtResource("1_tjyq5")
@@ -10,8 +17,11 @@ description = "Is this node in the group"
1017
category = "Communication | Groups"
1118
type = 3
1219
variant_type = 1
13-
display_template = "is in group {group: STRING}"
14-
code_template = "is_in_group({group})"
15-
defaults = {}
20+
display_template = "is in group {group: NIL}"
21+
code_template = "is_in_group(\\\"{group}\\\")"
22+
defaults = {
23+
"group": SubResource("Resource_d0v0d")
24+
}
1625
signal_name = ""
1726
scope = ""
27+
extension_script = ExtResource("2_o165d")
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://bbtdxeey74x67"]
1+
[gd_resource type="Resource" load_steps=5 format=3 uid="uid://bbtdxeey74x67"]
22

33
[ext_resource type="Script" path="res://addons/block_code/code_generation/block_definition.gd" id="1_5krrs"]
4+
[ext_resource type="Script" path="res://addons/block_code/blocks/communication/groups.gd" id="1_r4prw"]
5+
[ext_resource type="Script" path="res://addons/block_code/code_generation/option_data.gd" id="1_y4j0k"]
6+
7+
[sub_resource type="Resource" id="Resource_o38ym"]
8+
script = ExtResource("1_y4j0k")
9+
selected = 0
10+
items = []
411

512
[resource]
613
script = ExtResource("1_5krrs")
@@ -10,8 +17,11 @@ description = "Is the node in the group"
1017
category = "Communication | Groups"
1118
type = 3
1219
variant_type = 1
13-
display_template = "{node: OBJECT} is in group {group: STRING}"
14-
code_template = "{node}.is_in_group({group})"
15-
defaults = {}
20+
display_template = "{node: OBJECT} is in group {group: NIL}"
21+
code_template = "{node}.is_in_group(\\\"{group}\\\")"
22+
defaults = {
23+
"group": SubResource("Resource_o38ym")
24+
}
1625
signal_name = ""
1726
scope = ""
27+
extension_script = ExtResource("1_r4prw")
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://dgenw5wyqorvq"]
1+
[gd_resource type="Resource" load_steps=5 format=3 uid="uid://dgenw5wyqorvq"]
22

33
[ext_resource type="Script" path="res://addons/block_code/code_generation/block_definition.gd" id="1_cdwef"]
4+
[ext_resource type="Script" path="res://addons/block_code/blocks/communication/groups.gd" id="1_i50fw"]
5+
[ext_resource type="Script" path="res://addons/block_code/code_generation/option_data.gd" id="1_mnxp7"]
6+
7+
[sub_resource type="Resource" id="Resource_45b71"]
8+
script = ExtResource("1_mnxp7")
9+
selected = 0
10+
items = []
411

512
[resource]
613
script = ExtResource("1_cdwef")
@@ -10,8 +17,11 @@ description = "Remove this node from the group"
1017
category = "Communication | Groups"
1118
type = 2
1219
variant_type = 0
13-
display_template = "remove from group {group: STRING}"
14-
code_template = "remove_from_group({group})"
15-
defaults = {}
20+
display_template = "remove from group {group: NIL}"
21+
code_template = "remove_from_group(\\\"{group}\\\")"
22+
defaults = {
23+
"group": SubResource("Resource_45b71")
24+
}
1625
signal_name = ""
1726
scope = ""
27+
extension_script = ExtResource("1_i50fw")
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://b2dwk77hnri8y"]
1+
[gd_resource type="Resource" load_steps=5 format=3 uid="uid://b2dwk77hnri8y"]
22

3+
[ext_resource type="Script" path="res://addons/block_code/code_generation/option_data.gd" id="1_clwhe"]
4+
[ext_resource type="Script" path="res://addons/block_code/blocks/communication/groups.gd" id="1_h3lhb"]
35
[ext_resource type="Script" path="res://addons/block_code/code_generation/block_definition.gd" id="1_pec24"]
46

7+
[sub_resource type="Resource" id="Resource_03rge"]
8+
script = ExtResource("1_clwhe")
9+
selected = 0
10+
items = []
11+
512
[resource]
613
script = ExtResource("1_pec24")
714
name = &"remove_node_from_group"
@@ -10,8 +17,11 @@ description = "Remove the node from the group"
1017
category = "Communication | Groups"
1118
type = 2
1219
variant_type = 0
13-
display_template = "remove {node: OBJECT} from group {group: STRING}"
14-
code_template = "{node}.remove_from_group({group})"
15-
defaults = {}
20+
display_template = "remove {node: OBJECT} from group {group: NIL}"
21+
code_template = "{node}.remove_from_group(\\\"{group}\\\")"
22+
defaults = {
23+
"group": SubResource("Resource_03rge")
24+
}
1625
signal_name = ""
1726
scope = ""
27+
extension_script = ExtResource("1_h3lhb")

0 commit comments

Comments
 (0)