浏览代码

Merge pull request #51591 from Calinou/call-group-default-immediate

Make `{call,set,notify}_group()` immediate by default
Rémi Verschelde 3 年之前
父节点
当前提交
b6983eeccf

+ 12 - 7
doc/classes/SceneTree.xml

@@ -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.

+ 3 - 3
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;
 	}

+ 0 - 2
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) {

+ 2 - 2
scene/3d/world_environment.cpp

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

+ 12 - 12
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);
 }
 

+ 5 - 3
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<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>

+ 1 - 1
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;
 	}

+ 1 - 1
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);

+ 1 - 1
scene/resources/material.cpp

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