diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index 970f5125cdb..3cd2ab09033 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -18,9 +18,9 @@
- Calls [code]method[/code] on each member of the given group. You can pass arguments to [code]method[/code] by specifying them at the end of the method call. This method is equivalent of calling [method call_group_flags] with [constant GROUP_CALL_DEFAULT] flag.
+ Calls [code]method[/code] on each member of the given group. You can pass arguments to [code]method[/code] by specifying them at the end of the method call.
[b]Note:[/b] Due to design limitations, [method call_group] will fail silently if one of the arguments is [code]null[/code].
- [b]Note:[/b] [method call_group] will always call methods with an one-frame delay, in a way similar to [method Object.call_deferred]. To call methods immediately, use [method call_group_flags] with the [constant GROUP_CALL_REALTIME] flag.
+ [b]Note:[/b] [method call_group] will call methods immediately on all members at once, which can cause stuttering if an expensive method is called on lots of members. To wait for one frame after [method call_group] was called, use [method call_group_flags] with the [constant GROUP_CALL_DEFERRED] flag.
@@ -30,11 +30,12 @@
Calls [code]method[/code] on each member of the given group, respecting the given [enum GroupCallFlags]. You can pass arguments to [code]method[/code] by specifying them at the end of the method call.
- [b]Note:[/b] Due to design limitations, [method call_group_flags] will fail silently if one of the arguments is [code]null[/code].
[codeblock]
- # Call the method immediately and in reverse order.
- get_tree().call_group_flags(SceneTree.GROUP_CALL_REALTIME | SceneTree.GROUP_CALL_REVERSE, "bases", "destroy")
+ # Call the method in a deferred manner and in reverse order.
+ get_tree().call_group_flags(SceneTree.GROUP_CALL_DEFERRED | SceneTree.GROUP_CALL_REVERSE)
[/codeblock]
+ [b]Note:[/b] Due to design limitations, [method call_group_flags] will fail silently if one of the arguments is [code]null[/code].
+ [b]Note:[/b] Group call flags are used to control the method calling behavior. By default, methods will be called immediately in a way similar to [method call_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [code]flags[/code] argument, methods will be called with a one-frame delay in a way similar to [method Object.set_deferred].
@@ -139,6 +140,7 @@
Sends the given notification to all members of the [code]group[/code].
+ [b]Note:[/b] [method notify_group] will immediately notify all members at once, which can cause stuttering if an expensive method is called as a result of sending the notification lots of members. To wait for one frame, use [method notify_group_flags] with the [constant GROUP_CALL_DEFERRED] flag.
@@ -148,6 +150,7 @@
Sends the given notification to all members of the [code]group[/code], respecting the given [enum GroupCallFlags].
+ [b]Note:[/b] Group call flags are used to control the notification sending behavior. By default, notifications will be sent immediately in a way similar to [method notify_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [code]flags[/code] argument, notifications will be sent with a one-frame delay in a way similar to using [code]Object.call_deferred("notification", ...)[/code].
@@ -189,6 +192,7 @@
Sets the given [code]property[/code] to [code]value[/code] on all members of the given group.
+ [b]Note:[/b] [method set_group] will set the property immediately on all members at once, which can cause stuttering if a property with an expensive setter is set on lots of members. To wait for one frame, use [method set_group_flags] with the [constant GROUP_CALL_DEFERRED] flag.
@@ -199,6 +203,7 @@
Sets the given [code]property[/code] to [code]value[/code] on all members of the given group, respecting the given [enum GroupCallFlags].
+ [b]Note:[/b] Group call flags are used to control the property setting behavior. By default, properties will be set immediately in a way similar to [method set_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [code]flags[/code] argument, properties will be set with a one-frame delay in a way similar to [method Object.call_deferred].
@@ -297,8 +302,8 @@
Call a group in reverse scene order.
-
- Call a group immediately (calls are normally made on idle).
+
+ Call a group with a one-frame delay (idle frame, not physics).
Call a group only once even if the call is executed many times.
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index efde8d8a2bc..f61dbc071d0 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -57,7 +57,7 @@ void Camera2D::_update_scroll() {
Size2 screen_size = _get_camera_screen_size();
Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5) : Point2());
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_camera_moved", xform, screen_offset);
+ get_tree()->call_group(group_name, "_camera_moved", xform, screen_offset);
};
}
@@ -421,7 +421,7 @@ bool Camera2D::is_current() const {
void Camera2D::make_current() {
if (is_inside_tree()) {
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_make_current", this);
+ get_tree()->call_group(group_name, "_make_current", this);
} else {
current = true;
}
@@ -430,7 +430,7 @@ void Camera2D::make_current() {
void Camera2D::clear_current() {
if (is_inside_tree()) {
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_make_current", (Object *)nullptr);
+ get_tree()->call_group(group_name, "_make_current", (Object *)nullptr);
} else {
current = false;
}
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index 4f05e803772..4c53776bbaf 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -217,8 +217,6 @@ void Camera3D::make_current() {
}
get_viewport()->_camera_3d_set(this);
-
- //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,camera_group,"_camera_make_current",this);
}
void Camera3D::clear_current(bool p_enable_next) {
diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp
index f6386446281..fe9d9ae4dd1 100644
--- a/scene/3d/world_environment.cpp
+++ b/scene/3d/world_environment.cpp
@@ -71,7 +71,7 @@ void WorldEnvironment::_update_current_environment() {
} else {
get_viewport()->find_world_3d()->set_environment(Ref());
}
- get_tree()->call_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
}
void WorldEnvironment::_update_current_camera_effects() {
@@ -82,7 +82,7 @@ void WorldEnvironment::_update_current_camera_effects() {
get_viewport()->find_world_3d()->set_camera_effects(Ref());
}
- get_tree()->call_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");
}
void WorldEnvironment::set_environment(const Ref &p_environment) {
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index a151d3cb330..9d80b3cc0f8 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -181,7 +181,7 @@ void SceneTree::_flush_ugc() {
argptrs[i] = &E->get()[i];
}
- call_group_flagsp(GROUP_CALL_REALTIME, E->key().group, E->key().call, argptrs, E->get().size());
+ call_group_flagsp(GROUP_CALL_DEFAULT, E->key().group, E->key().call, argptrs, E->get().size());
unique_group_calls.erase(E);
}
@@ -220,7 +220,7 @@ void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_gro
return;
}
- if (p_call_flags & GROUP_CALL_UNIQUE && !(p_call_flags & GROUP_CALL_REALTIME)) {
+ if (p_call_flags & GROUP_CALL_UNIQUE && p_call_flags & GROUP_CALL_DEFERRED) {
ERR_FAIL_COND(ugc_locked);
UGCall ug;
@@ -254,7 +254,7 @@ void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_gro
continue;
}
- if (p_call_flags & GROUP_CALL_REALTIME) {
+ if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
Callable::CallError ce;
nodes[i]->callp(p_function, p_args, p_argcount, ce);
} else {
@@ -268,7 +268,7 @@ void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_gro
continue;
}
- if (p_call_flags & GROUP_CALL_REALTIME) {
+ if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
Callable::CallError ce;
nodes[i]->callp(p_function, p_args, p_argcount, ce);
} else {
@@ -307,7 +307,7 @@ void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_gr
continue;
}
- if (p_call_flags & GROUP_CALL_REALTIME) {
+ if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
nodes[i]->notification(p_notification);
} else {
MessageQueue::get_singleton()->push_notification(nodes[i], p_notification);
@@ -320,7 +320,7 @@ void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_gr
continue;
}
- if (p_call_flags & GROUP_CALL_REALTIME) {
+ if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
nodes[i]->notification(p_notification);
} else {
MessageQueue::get_singleton()->push_notification(nodes[i], p_notification);
@@ -358,7 +358,7 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group
continue;
}
- if (p_call_flags & GROUP_CALL_REALTIME) {
+ if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
nodes[i]->set(p_name, p_value);
} else {
MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value);
@@ -371,7 +371,7 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group
continue;
}
- if (p_call_flags & GROUP_CALL_REALTIME) {
+ if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
nodes[i]->set(p_name, p_value);
} else {
MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value);
@@ -390,7 +390,7 @@ void SceneTree::notify_group(const StringName &p_group, int p_notification) {
}
void SceneTree::set_group(const StringName &p_group, const String &p_name, const Variant &p_value) {
- set_group_flags(0, p_group, p_name, p_value);
+ set_group_flags(GROUP_CALL_DEFAULT, p_group, p_name, p_value);
}
void SceneTree::initialize() {
@@ -413,7 +413,7 @@ bool SceneTree::physics_process(double p_time) {
emit_signal(SNAME("physics_frame"));
_notify_group_pause(SNAME("physics_process_internal"), Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
- call_group_flags(GROUP_CALL_REALTIME, SNAME("_picking_viewports"), SNAME("_process_picking"));
+ call_group(SNAME("_picking_viewports"), SNAME("_process_picking"));
_notify_group_pause(SNAME("physics_process"), Node::NOTIFICATION_PHYSICS_PROCESS);
_flush_ugc();
MessageQueue::get_singleton()->flush(); //small little hack
@@ -944,7 +944,7 @@ void SceneTree::_call_group(const Variant **p_args, int p_argcount, Callable::Ca
StringName group = *p_args[0];
StringName method = *p_args[1];
- call_group_flagsp(0, group, method, p_args + 2, p_argcount - 2);
+ call_group_flagsp(GROUP_CALL_DEFAULT, group, method, p_args + 2, p_argcount - 2);
}
int64_t SceneTree::get_frame() const {
@@ -1277,7 +1277,7 @@ void SceneTree::_bind_methods() {
BIND_ENUM_CONSTANT(GROUP_CALL_DEFAULT);
BIND_ENUM_CONSTANT(GROUP_CALL_REVERSE);
- BIND_ENUM_CONSTANT(GROUP_CALL_REALTIME);
+ BIND_ENUM_CONSTANT(GROUP_CALL_DEFERRED);
BIND_ENUM_CONSTANT(GROUP_CALL_UNIQUE);
}
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 9d7757e0a37..d633fb38d05 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -151,7 +151,6 @@ private:
int collision_debug_contacts;
void _change_scene(Node *p_to);
- //void _call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,const Variant& p_arg1,const Variant& p_arg2);
List[> timers;
List][> tweens;
@@ -225,7 +224,7 @@ public:
enum GroupCallFlags {
GROUP_CALL_DEFAULT = 0,
GROUP_CALL_REVERSE = 1,
- GROUP_CALL_REALTIME = 2,
+ GROUP_CALL_DEFERRED = 2,
GROUP_CALL_UNIQUE = 4,
};
@@ -235,17 +234,20 @@ public:
void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification);
void set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value);
+ // `notify_group()` is immediate by default since Godot 4.0.
void notify_group(const StringName &p_group, int p_notification);
+ // `set_group()` is immediate by default since Godot 4.0.
void set_group(const StringName &p_group, const String &p_name, const Variant &p_value);
template
+ // `call_group()` is immediate by default since Godot 4.0.
void call_group(const StringName &p_group, const StringName &p_function, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
const Variant *argptrs[sizeof...(p_args) + 1];
for (uint32_t i = 0; i < sizeof...(p_args); i++) {
argptrs[i] = &args[i];
}
- call_group_flagsp(0, p_group, p_function, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ call_group_flagsp(GROUP_CALL_DEFAULT, p_group, p_function, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
}
template
diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp
index 7c689bd4365..ed08c45a01f 100644
--- a/scene/main/shader_globals_override.cpp
+++ b/scene/main/shader_globals_override.cpp
@@ -267,7 +267,7 @@ void ShaderGlobalsOverride::_notification(int p_what) {
remove_from_group(SceneStringNames::get_singleton()->shader_overrides_group_active);
remove_from_group(SceneStringNames::get_singleton()->shader_overrides_group);
- get_tree()->call_group(SceneStringNames::get_singleton()->shader_overrides_group, "_activate"); //another may want to activate when this is removed
+ get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringNames::get_singleton()->shader_overrides_group, "_activate"); //another may want to activate when this is removed
active = false;
} break;
}
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index d7e58ed7077..e4037c28430 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2186,7 +2186,7 @@ void Viewport::_gui_control_grab_focus(Control *p_control) {
// No need for change.
return;
}
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "_viewports", "_gui_remove_focus_for_window", (Node *)get_base_window());
+ get_tree()->call_group("_viewports", "_gui_remove_focus_for_window", (Node *)get_base_window());
gui.key_focus = p_control;
emit_signal(SNAME("gui_focus_changed"), p_control);
p_control->notification(Control::NOTIFICATION_FOCUS_ENTER);
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 16fce5e08aa..27e15909402 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -84,7 +84,7 @@ void Material::inspect_native_shader_code() {
SceneTree *st = Object::cast_to(OS::get_singleton()->get_main_loop());
RID shader = get_shader_rid();
if (st && shader.is_valid()) {
- st->call_group("_native_shader_source_visualizer", "_inspect_shader", shader);
+ st->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_native_shader_source_visualizer", "_inspect_shader", shader);
}
}
]