Make `{call,set,notify}_group()` immediate by default

This results in less surprising behavior out of the box.

Internal usages were modified to keep the existing behavior
identical there.
This commit is contained in:
Hugo Locurcio 2021-08-12 23:40:13 +02:00
parent 174c14762f
commit aabbb40009
No known key found for this signature in database
GPG Key ID: 39E8F8BE30B0A49C
9 changed files with 37 additions and 32 deletions

View File

@ -18,9 +18,9 @@
<argument index="0" name="group" type="StringName" />
<argument index="1" name="method" type="StringName" />
<description>
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.
</description>
</method>
<method name="call_group_flags" qualifiers="vararg">
@ -30,11 +30,12 @@
<argument index="2" name="method" type="StringName" />
<description>
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].
</description>
</method>
<method name="change_scene">
@ -139,6 +140,7 @@
<argument index="1" name="notification" type="int" />
<description>
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.
</description>
</method>
<method name="notify_group_flags">
@ -148,6 +150,7 @@
<argument index="2" name="notification" type="int" />
<description>
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].
</description>
</method>
<method name="queue_delete">
@ -189,6 +192,7 @@
<argument index="2" name="value" type="Variant" />
<description>
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.
</description>
</method>
<method name="set_group_flags">
@ -199,6 +203,7 @@
<argument index="3" name="value" type="Variant" />
<description>
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].
</description>
</method>
<method name="set_multiplayer">
@ -297,8 +302,8 @@
<constant name="GROUP_CALL_REVERSE" value="1" enum="GroupCallFlags">
Call a group in reverse scene order.
</constant>
<constant name="GROUP_CALL_REALTIME" value="2" enum="GroupCallFlags">
Call a group immediately (calls are normally made on idle).
<constant name="GROUP_CALL_DEFERRED" value="2" enum="GroupCallFlags">
Call a group with a one-frame delay (idle frame, not physics).
</constant>
<constant name="GROUP_CALL_UNIQUE" value="4" enum="GroupCallFlags">
Call a group only once even if the call is executed many times.

View File

@ -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;
}

View File

@ -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) {

View File

@ -71,7 +71,7 @@ void WorldEnvironment::_update_current_environment() {
} else {
get_viewport()->find_world_3d()->set_environment(Ref<Environment>());
}
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<CameraEffects>());
}
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<Environment> &p_environment) {

View File

@ -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);
}

View File

@ -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<Ref<SceneTreeTimer>> timers;
List<Ref<Tween>> 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 <typename... VarArgs>
// `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 <typename... VarArgs>

View File

@ -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;
}

View File

@ -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);

View File

@ -84,7 +84,7 @@ void Material::inspect_native_shader_code() {
SceneTree *st = Object::cast_to<SceneTree>(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);
}
}