diff options
96 files changed, 415 insertions, 663 deletions
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 7750d45226..b5335e47cd 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -37,13 +37,13 @@  				Corresponds to the [constant NOTIFICATION_EXIT_TREE] notification in [method Object._notification] and signal [signal tree_exiting]. To get notified when the node has already left the active tree, connect to the [signal tree_exited].  			</description>  		</method> -		<method name="_get_configuration_warning" qualifiers="virtual"> -			<return type="String"> +		<method name="_get_configuration_warnings" qualifiers="virtual"> +			<return type="Array">  			</return>  			<description> -				The string returned from this method is displayed as a warning in the Scene Dock if the script that overrides it is a [code]tool[/code] script. -				Returning an empty string produces no warning. -				Call [method update_configuration_warning] when the warning needs to be updated for this node. +				The elements in the array returned from this method are displayed as warnings in the Scene Dock if the script that overrides it is a [code]tool[/code] script. +				Returning an empty array produces no warnings. +				Call [method update_configuration_warnings] when the warnings need to be updated for this node.  			</description>  		</method>  		<method name="_input" qualifiers="virtual"> @@ -856,12 +856,12 @@  				Sets whether this is an instance load placeholder. See [InstancePlaceholder].  			</description>  		</method> -		<method name="update_configuration_warning"> +		<method name="update_configuration_warnings">  			<return type="void">  			</return>  			<description>  				Updates the warning displayed for this node in the Scene Dock. -				Use [method _get_configuration_warning] to setup the warning message to display. +				Use [method _get_configuration_warnings] to setup the warning message to display.  			</description>  		</method>  	</methods> diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index b5e9aec854..ec37fa53b3 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -120,7 +120,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i  		}  		undo_redo->commit_action();  	} else if (p_id == BUTTON_WARNING) { -		String config_err = n->get_configuration_warning(); +		String config_err = n->get_configuration_warnings_as_string();  		if (config_err == String()) {  			return;  		} @@ -252,9 +252,9 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll  	if (can_rename) { //should be can edit.. -		String warning = p_node->get_configuration_warning(); +		String warning = p_node->get_configuration_warnings_as_string();  		if (!warning.is_empty()) { -			item->add_button(0, get_theme_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + p_node->get_configuration_warning()); +			item->add_button(0, get_theme_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + warning);  		}  		int num_connections = p_node->get_persistent_signal_connection_count(); diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index 4aa079b013..9ee37670d1 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -272,7 +272,7 @@ void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {  	notify_property_list_changed();  	_reset_timeout();  	update(); -	update_configuration_warning(); +	update_configuration_warnings();  }  Ref<SpriteFrames> AnimatedSprite2D::get_sprite_frames() const { @@ -440,17 +440,14 @@ StringName AnimatedSprite2D::get_animation() const {  	return animation;  } -String AnimatedSprite2D::get_configuration_warning() const { -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> AnimatedSprite2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (frames.is_null()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames."); +		warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames."));  	} -	return warning; +	return warnings;  }  void AnimatedSprite2D::_bind_methods() { diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h index 14ecb18866..ef0027edf1 100644 --- a/scene/2d/animated_sprite_2d.h +++ b/scene/2d/animated_sprite_2d.h @@ -109,7 +109,7 @@ public:  	void set_flip_v(bool p_flip);  	bool is_flipped_v() const; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	AnimatedSprite2D();  }; diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index 5d5aaae505..52eabefbcb 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -51,7 +51,7 @@ void CanvasModulate::_notification(int p_what) {  			remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id()));  		} -		update_configuration_warning(); +		update_configuration_warnings();  	}  } @@ -73,24 +73,19 @@ Color CanvasModulate::get_color() const {  	return color;  } -String CanvasModulate::get_configuration_warning() const { -	if (!is_visible_in_tree() || !is_inside_tree()) { -		return String(); -	} - -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> CanvasModulate::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); -	List<Node *> nodes; -	get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes); +	if (is_visible_in_tree() && is_inside_tree()) { +		List<Node *> nodes; +		get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes); -	if (nodes.size() > 1) { -		if (!warning.is_empty()) { -			warning += "\n\n"; +		if (nodes.size() > 1) { +			warnings.push_back(TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored."));  		} -		warning += TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored.");  	} -	return warning; +	return warnings;  }  CanvasModulate::CanvasModulate() { diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h index 4d55a5d9cb..3d85a92a11 100644 --- a/scene/2d/canvas_modulate.h +++ b/scene/2d/canvas_modulate.h @@ -46,7 +46,7 @@ public:  	void set_color(const Color &p_color);  	Color get_color() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	CanvasModulate();  	~CanvasModulate(); diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index c83ed36917..30728a2755 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -363,17 +363,14 @@ void CollisionObject2D::_update_pickable() {  	}  } -String CollisionObject2D::get_configuration_warning() const { -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> CollisionObject2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (shapes.is_empty()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape."); +		warnings.push_back(TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape."));  	} -	return warning; +	return warnings;  }  void CollisionObject2D::_bind_methods() { diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index e82b61d441..7a1fd23e72 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -107,7 +107,7 @@ public:  	void set_pickable(bool p_enabled);  	bool is_pickable() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	_FORCE_INLINE_ RID get_rid() const { return rid; } diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 38198c496e..a69ef73a54 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -204,7 +204,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) {  		_update_in_shape_owner();  	}  	update(); -	update_configuration_warning(); +	update_configuration_warnings();  }  Vector<Point2> CollisionPolygon2D::get_polygon() const { @@ -219,7 +219,7 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) {  		_update_in_shape_owner();  	}  	update(); -	update_configuration_warning(); +	update_configuration_warnings();  }  CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const { @@ -240,40 +240,28 @@ bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, doubl  }  #endif -String CollisionPolygon2D::get_configuration_warning() const { -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!Object::cast_to<CollisionObject2D>(get_parent())) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); +		warnings.push_back(TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));  	}  	int polygon_count = polygon.size();  	if (polygon_count == 0) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("An empty CollisionPolygon2D has no effect on collision."); +		warnings.push_back(TTR("An empty CollisionPolygon2D has no effect on collision."));  	} else {  		bool solids = build_mode == BUILD_SOLIDS;  		if (solids) {  			if (polygon_count < 3) { -				if (!warning.is_empty()) { -					warning += "\n\n"; -				} -				warning += TTR("Invalid polygon. At least 3 points are needed in 'Solids' build mode."); +				warnings.push_back(TTR("Invalid polygon. At least 3 points are needed in 'Solids' build mode."));  			}  		} else if (polygon_count < 2) { -			if (!warning.is_empty()) { -				warning += "\n\n"; -			} -			warning += TTR("Invalid polygon. At least 2 points are needed in 'Segments' build mode."); +			warnings.push_back(TTR("Invalid polygon. At least 2 points are needed in 'Segments' build mode."));  		}  	} -	return warning; +	return warnings;  }  void CollisionPolygon2D::set_disabled(bool p_disabled) { diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index 9df9802629..95dd8c9e21 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -78,7 +78,7 @@ public:  	void set_polygon(const Vector<Point2> &p_polygon);  	Vector<Point2> get_polygon() const; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	void set_disabled(bool p_disabled);  	bool is_disabled() const; diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index 93949f741b..d9009ef85c 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -162,7 +162,7 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) {  		shape->connect("changed", callable_mp(this, &CollisionShape2D::_shape_changed));  	} -	update_configuration_warning(); +	update_configuration_warnings();  }  Ref<Shape2D> CollisionShape2D::get_shape() const { @@ -177,19 +177,23 @@ bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double  	return shape->_edit_is_selected_on_click(p_point, p_tolerance);  } -String CollisionShape2D::get_configuration_warning() const { +TypedArray<String> CollisionShape2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); +  	if (!Object::cast_to<CollisionObject2D>(get_parent())) { -		return TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); +		warnings.push_back(TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));  	}  	if (!shape.is_valid()) { -		return TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"); +		warnings.push_back(TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"));  	} +  	Ref<ConvexPolygonShape2D> convex = shape;  	Ref<ConcavePolygonShape2D> concave = shape;  	if (convex.is_valid() || concave.is_valid()) { -		return TTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead."); +		warnings.push_back(TTR("Polygon-based shapes are not meant be used nor edited directly through the CollisionShape2D node. Please use the CollisionPolygon2D node instead."));  	} -	return String(); + +	return warnings;  }  void CollisionShape2D::set_disabled(bool p_disabled) { diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h index 695d0c6657..eaf72627c8 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/collision_shape_2d.h @@ -72,7 +72,7 @@ public:  	void set_one_way_collision_margin(real_t p_margin);  	real_t get_one_way_collision_margin() const; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	CollisionShape2D();  }; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 6a69a4c618..5f2efeb8ca 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -244,18 +244,15 @@ bool CPUParticles2D::get_fractional_delta() const {  	return fractional_delta;  } -String CPUParticles2D::get_configuration_warning() const { -	String warnings = Node2D::get_configuration_warning(); +TypedArray<String> CPUParticles2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());  	if (get_material().is_null() || (mat && !mat->get_particles_animation())) {  		if (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 ||  				get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid()) { -			if (warnings != String()) { -				warnings += "\n"; -			} -			warnings += "- " + TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."); +			warnings.push_back(TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));  		}  	} diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index ab04ee4a57..ba34a0f45d 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -275,7 +275,7 @@ public:  	void set_gravity(const Vector2 &p_gravity);  	Vector2 get_gravity() const; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	void restart(); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index af70c47f7c..8a0631a614 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -137,7 +137,7 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {  	}  	RS::get_singleton()->particles_set_process_material(particles, material_rid); -	update_configuration_warning(); +	update_configuration_warnings();  }  void GPUParticles2D::set_speed_scale(float p_scale) { @@ -216,18 +216,15 @@ bool GPUParticles2D::get_fractional_delta() const {  	return fractional_delta;  } -String GPUParticles2D::get_configuration_warning() const { +TypedArray<String> GPUParticles2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); +  	if (RenderingServer::get_singleton()->is_low_end()) { -		return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose."); +		warnings.push_back(TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles2D node instead. You can use the \"Convert to CPUParticles2D\" option for this purpose."));  	} -	String warnings = Node2D::get_configuration_warning(); -  	if (process_material.is_null()) { -		if (warnings != String()) { -			warnings += "\n"; -		} -		warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted."); +		warnings.push_back(TTR("A material to process the particles is not assigned, so no behavior is imprinted."));  	} else {  		CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr()); @@ -236,10 +233,7 @@ String GPUParticles2D::get_configuration_warning() const {  			if (process &&  					(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||  							process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) { -				if (warnings != String()) { -					warnings += "\n"; -				} -				warnings += "- " + TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."); +				warnings.push_back(TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));  			}  		}  	} diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index 774cef9cc9..20f9f768ed 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -110,7 +110,7 @@ public:  	void set_texture(const Ref<Texture2D> &p_texture);  	Ref<Texture2D> get_texture() const; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	void restart();  	Rect2 capture_rect() const; diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index 7d9cdd52ac..8a4ccc2f96 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -66,6 +66,7 @@ void Joint2D::_update_joint(bool p_only_free) {  	if (p_only_free || !is_inside_tree()) {  		PhysicsServer2D::get_singleton()->joint_clear(joint);  		warning = String(); +		update_configuration_warnings();  		return;  	} @@ -76,43 +77,26 @@ void Joint2D::_update_joint(bool p_only_free) {  	PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b);  	if (node_a && !body_a && node_b && !body_b) { -		PhysicsServer2D::get_singleton()->joint_clear(joint);  		warning = TTR("Node A and Node B must be PhysicsBody2Ds"); -		update_configuration_warning(); -		return; -	} - -	if (node_a && !body_a) { -		PhysicsServer2D::get_singleton()->joint_clear(joint); +	} else if (node_a && !body_a) {  		warning = TTR("Node A must be a PhysicsBody2D"); -		update_configuration_warning(); -		return; -	} - -	if (node_b && !body_b) { -		PhysicsServer2D::get_singleton()->joint_clear(joint); +	} else if (node_b && !body_b) {  		warning = TTR("Node B must be a PhysicsBody2D"); -		update_configuration_warning(); -		return; -	} - -	if (!body_a || !body_b) { -		PhysicsServer2D::get_singleton()->joint_clear(joint); +	} else if (!body_a || !body_b) {  		warning = TTR("Joint is not connected to two PhysicsBody2Ds"); -		update_configuration_warning(); -		return; +	} else if (body_a == body_b) { +		warning = TTR("Node A and Node B must be different PhysicsBody2Ds"); +	} else { +		warning = String();  	} -	if (body_a == body_b) { +	update_configuration_warnings(); + +	if (!warning.is_empty()) {  		PhysicsServer2D::get_singleton()->joint_clear(joint); -		warning = TTR("Node A and Node B must be different PhysicsBody2Ds"); -		update_configuration_warning();  		return;  	} -	warning = String(); -	update_configuration_warning(); -  	if (body_a) {  		body_a->force_update_transform();  	} @@ -211,17 +195,14 @@ bool Joint2D::get_exclude_nodes_from_collision() const {  	return exclude_from_collision;  } -String Joint2D::get_configuration_warning() const { -	String node_warning = Node2D::get_configuration_warning(); +TypedArray<String> Joint2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node2D::get_configuration_warnings();  	if (!warning.is_empty()) { -		if (!node_warning.is_empty()) { -			node_warning += "\n\n"; -		} -		node_warning += warning; +		warnings.push_back(warning);  	} -	return node_warning; +	return warnings;  }  void Joint2D::_bind_methods() { diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h index 08e02ee29d..dc5a08f815 100644 --- a/scene/2d/joints_2d.h +++ b/scene/2d/joints_2d.h @@ -62,7 +62,7 @@ protected:  	_FORCE_INLINE_ bool is_configured() const { return configured; }  public: -	virtual String get_configuration_warning() const override; +	virtual TypedArray<String> get_configuration_warnings() const override;  	void set_node_a(const NodePath &p_node_a);  	NodePath get_node_a() const; diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 99e35cad1d..8fb765f16b 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -373,7 +373,7 @@ void PointLight2D::set_texture(const Ref<Texture2D> &p_texture) {  		RS::get_singleton()->canvas_light_set_texture(_get_light(), RID());  	} -	update_configuration_warning(); +	update_configuration_warnings();  }  Ref<Texture2D> PointLight2D::get_texture() const { @@ -390,17 +390,14 @@ Vector2 PointLight2D::get_texture_offset() const {  	return texture_offset;  } -String PointLight2D::get_configuration_warning() const { -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> PointLight2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!texture.is_valid()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("A texture with the shape of the light must be supplied to the \"Texture\" property."); +		warnings.push_back(TTR("A texture with the shape of the light must be supplied to the \"Texture\" property."));  	} -	return warning; +	return warnings;  }  void PointLight2D::set_texture_scale(real_t p_scale) { diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index ae6cf6d0a0..d9ecd81f1c 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -169,7 +169,7 @@ public:  	void set_texture_scale(real_t p_scale);  	real_t get_texture_scale() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	PointLight2D();  }; diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 9589702e2e..fdc28f81c2 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -242,24 +242,18 @@ int LightOccluder2D::get_occluder_light_mask() const {  	return mask;  } -String LightOccluder2D::get_configuration_warning() const { -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> LightOccluder2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!occluder_polygon.is_valid()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("An occluder polygon must be set (or drawn) for this occluder to take effect."); +		warnings.push_back(TTR("An occluder polygon must be set (or drawn) for this occluder to take effect."));  	}  	if (occluder_polygon.is_valid() && occluder_polygon->get_polygon().size() == 0) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("The occluder polygon for this occluder is empty. Please draw a polygon."); +		warnings.push_back(TTR("The occluder polygon for this occluder is empty. Please draw a polygon."));  	} -	return warning; +	return warnings;  }  void LightOccluder2D::set_as_sdf_collision(bool p_enable) { diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h index f567c6d965..b4a48d1062 100644 --- a/scene/2d/light_occluder_2d.h +++ b/scene/2d/light_occluder_2d.h @@ -106,7 +106,7 @@ public:  	void set_as_sdf_collision(bool p_enable);  	bool is_set_as_sdf_collision() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	LightOccluder2D();  	~LightOccluder2D(); diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index 064fcc91a4..a18687afed 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -239,17 +239,14 @@ void NavigationAgent2D::_avoidance_done(Vector3 p_new_velocity) {  	emit_signal("velocity_computed", velocity);  } -String NavigationAgent2D::get_configuration_warning() const { -	String warning = Node::get_configuration_warning(); +TypedArray<String> NavigationAgent2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!Object::cast_to<Node2D>(get_parent())) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("The NavigationAgent2D can be used only under a Node2D node"); +		warnings.push_back(TTR("The NavigationAgent2D can be used only under a Node2D node"));  	} -	return warning; +	return warnings;  }  void NavigationAgent2D::update_navigation() { diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 153ede8cec..138ba3bc64 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -136,7 +136,7 @@ public:  	void set_velocity(Vector2 p_velocity);  	void _avoidance_done(Vector3 p_new_velocity); -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  private:  	void update_navigation(); diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index 965e2b6dc1..a06f7a9fd0 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -69,17 +69,14 @@ NavigationObstacle2D::~NavigationObstacle2D() {  	agent = RID(); // Pointless  } -String NavigationObstacle2D::get_configuration_warning() const { -	String warning = Node::get_configuration_warning(); +TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!Object::cast_to<Node2D>(get_parent())) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object."); +		warnings.push_back(TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object."));  	} -	return warning; +	return warnings;  }  void NavigationObstacle2D::update_agent_shape() { diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h index 135ca4651e..9cffc2c0c3 100644 --- a/scene/2d/navigation_obstacle_2d.h +++ b/scene/2d/navigation_obstacle_2d.h @@ -52,7 +52,7 @@ public:  		return agent;  	} -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  private:  	void update_agent_shape(); diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 8be8c8db4a..d2caf5bea8 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -491,7 +491,7 @@ void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_  	}  	_navpoly_changed(); -	update_configuration_warning(); +	update_configuration_warnings();  }  Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const { @@ -509,21 +509,16 @@ void NavigationRegion2D::_map_changed(RID p_map) {  	}  } -String NavigationRegion2D::get_configuration_warning() const { -	if (!is_visible_in_tree() || !is_inside_tree()) { -		return String(); -	} - -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> NavigationRegion2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node2D::get_configuration_warnings(); -	if (!navpoly.is_valid()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; +	if (is_visible_in_tree() && is_inside_tree()) { +		if (!navpoly.is_valid()) { +			warnings.push_back(TTR("A NavigationMesh resource must be set or created for this node to work. Please set a property or draw a polygon."));  		} -		warning += TTR("A NavigationPolygon resource must be set or created for this node to work. Please set a property or draw a polygon.");  	} -	return warning; +	return warnings;  }  void NavigationRegion2D::_bind_methods() { diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 58f04599be..2db8d70791 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -120,7 +120,7 @@ public:  	void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);  	Ref<NavigationPolygon> get_navigation_polygon() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	NavigationRegion2D();  	~NavigationRegion2D(); diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index 725e858a43..228020d383 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -135,17 +135,14 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_s  	_update_mirroring();  } -String ParallaxLayer::get_configuration_warning() const { -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> ParallaxLayer::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!Object::cast_to<ParallaxBackground>(get_parent())) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node."); +		warnings.push_back(TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node."));  	} -	return warning; +	return warnings;  }  void ParallaxLayer::_bind_methods() { diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h index e826e6da9c..cc2d2e096e 100644 --- a/scene/2d/parallax_layer.h +++ b/scene/2d/parallax_layer.h @@ -61,7 +61,7 @@ public:  	void set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset); -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	ParallaxLayer();  }; diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index be160ee1dd..9912612c4f 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -249,21 +249,16 @@ void PathFollow2D::_validate_property(PropertyInfo &property) const {  	}  } -String PathFollow2D::get_configuration_warning() const { -	if (!is_visible_in_tree() || !is_inside_tree()) { -		return String(); -	} - -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> PathFollow2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); -	if (!Object::cast_to<Path2D>(get_parent())) { -		if (!warning.is_empty()) { -			warning += "\n\n"; +	if (is_visible_in_tree() && is_inside_tree()) { +		if (!Object::cast_to<Path2D>(get_parent())) { +			warnings.push_back(TTR("PathFollow2D only works when set as a child of a Path2D node."));  		} -		warning += TTR("PathFollow2D only works when set as a child of a Path2D node.");  	} -	return warning; +	return warnings;  }  void PathFollow2D::_bind_methods() { diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index 671ab493c3..3b12f025fc 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -105,7 +105,7 @@ public:  	void set_cubic_interpolation(bool p_enable);  	bool get_cubic_interpolation() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	PathFollow2D() {}  }; diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index a615d96687..830834c964 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -708,26 +708,23 @@ void RigidBody2D::_notification(int p_what) {  	if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {  		if (Engine::get_singleton()->is_editor_hint()) { -			update_configuration_warning(); +			update_configuration_warnings();  		}  	}  #endif  } -String RigidBody2D::get_configuration_warning() const { +TypedArray<String> RigidBody2D::get_configuration_warnings() const {  	Transform2D t = get_transform(); -	String warning = CollisionObject2D::get_configuration_warning(); +	TypedArray<String> warnings = CollisionObject2D::get_configuration_warnings();  	if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.elements[0].length() - 1.0) > 0.05 || ABS(t.elements[1].length() - 1.0) > 0.05)) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("Size changes to RigidBody2D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."); +		warnings.push_back(TTR("Size changes to RigidBody2D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));  	} -	return warning; +	return warnings;  }  void RigidBody2D::_bind_methods() { diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 2dc853b23b..aeec662e5c 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -246,7 +246,7 @@ public:  	TypedArray<Node2D> get_colliding_bodies() const; //function for script -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	RigidBody2D();  	~RigidBody2D(); diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp index f10714e28a..a7613dc009 100644 --- a/scene/2d/remote_transform_2d.cpp +++ b/scene/2d/remote_transform_2d.cpp @@ -138,7 +138,7 @@ void RemoteTransform2D::set_remote_node(const NodePath &p_remote_node) {  		_update_remote();  	} -	update_configuration_warning(); +	update_configuration_warnings();  }  NodePath RemoteTransform2D::get_remote_node() const { @@ -185,17 +185,14 @@ void RemoteTransform2D::force_update_cache() {  	_update_cache();  } -String RemoteTransform2D::get_configuration_warning() const { -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> RemoteTransform2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("Path property must point to a valid Node2D node to work."); +		warnings.push_back(TTR("Path property must point to a valid Node2D node to work."));  	} -	return warning; +	return warnings;  }  void RemoteTransform2D::_bind_methods() { diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h index 4a26d7b339..36fddb58c7 100644 --- a/scene/2d/remote_transform_2d.h +++ b/scene/2d/remote_transform_2d.h @@ -70,7 +70,7 @@ public:  	void force_update_cache(); -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	RemoteTransform2D();  }; diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 2d19d254b1..22180797f0 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -100,7 +100,7 @@ void Bone2D::set_rest(const Transform2D &p_rest) {  		skeleton->_make_bone_setup_dirty();  	} -	update_configuration_warning(); +	update_configuration_warnings();  }  Transform2D Bone2D::get_rest() const { @@ -133,27 +133,21 @@ int Bone2D::get_index_in_skeleton() const {  	return skeleton_index;  } -String Bone2D::get_configuration_warning() const { -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> Bone2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!skeleton) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		}  		if (parent_bone) { -			warning += TTR("This Bone2D chain should end at a Skeleton2D node."); +			warnings.push_back(TTR("This Bone2D chain should end at a Skeleton2D node."));  		} else { -			warning += TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node."); +			warnings.push_back(TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node."));  		}  	}  	if (rest == Transform2D(0, 0, 0, 0, 0, 0)) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."); +		warnings.push_back(TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."));  	} -	return warning; +	return warnings;  }  Bone2D::Bone2D() { diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index 1f43ea742b..fd62b87bde 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -60,7 +60,7 @@ public:  	void apply_rest();  	Transform2D get_skeleton_rest() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	void set_default_length(real_t p_length);  	real_t get_default_length() const; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 81a5b0b28c..776d3bca5f 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -59,7 +59,7 @@ void TileMap::_notification(int p_what) {  			RID space = get_world_2d()->get_space();  			_update_quadrant_transform();  			_update_quadrant_space(space); -			update_configuration_warning(); +			update_configuration_warnings();  		} break; @@ -1301,7 +1301,7 @@ void TileMap::set_collision_use_parent(bool p_use_parent) {  	_recreate_quadrants();  	notify_property_list_changed(); -	update_configuration_warning(); +	update_configuration_warnings();  }  void TileMap::set_collision_friction(float p_friction) { @@ -1693,17 +1693,14 @@ void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) {  	}  } -String TileMap::get_configuration_warning() const { -	String warning = Node2D::get_configuration_warning(); +TypedArray<String> TileMap::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (use_parent && !collision_parent) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		return TTR("TileMap with Use Parent on needs a parent CollisionObject2D to give shapes to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); +		warnings.push_back(TTR("TileMap with Use Parent on needs a parent CollisionObject2D to give shapes to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."));  	} -	return warning; +	return warnings;  }  void TileMap::_bind_methods() { diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 26c84a0bb9..9d27053fee 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -340,7 +340,7 @@ public:  	void set_clip_uv(bool p_enable);  	bool get_clip_uv() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override; diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index 916038a1f3..8feb47f1cc 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -310,18 +310,15 @@ void VisibilityEnabler2D::_node_removed(Node *p_node) {  	nodes.erase(p_node);  } -String VisibilityEnabler2D::get_configuration_warning() const { -	String warning = VisibilityNotifier2D::get_configuration_warning(); +TypedArray<String> VisibilityEnabler2D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  #ifdef TOOLS_ENABLED  	if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent."); +		warnings.push_back(TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent."));  	}  #endif -	return warning; +	return warnings;  }  void VisibilityEnabler2D::_bind_methods() { diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h index 3d1701a1e5..7f4a5bc193 100644 --- a/scene/2d/visibility_notifier_2d.h +++ b/scene/2d/visibility_notifier_2d.h @@ -102,7 +102,7 @@ public:  	void set_enabler(Enabler p_enabler, bool p_enable);  	bool is_enabler_enabled(Enabler p_enabler) const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	VisibilityEnabler2D();  }; diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index 39880db29c..352a793987 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -395,17 +395,14 @@ bool CollisionObject3D::get_capture_input_on_drag() const {  	return capture_input_on_drag;  } -String CollisionObject3D::get_configuration_warning() const { -	String warning = Node3D::get_configuration_warning(); +TypedArray<String> CollisionObject3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (shapes.is_empty()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape."); +		warnings.push_back(TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape."));  	} -	return warning; +	return warnings;  }  CollisionObject3D::CollisionObject3D() { diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index fe20176984..a2a0cbf988 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -110,7 +110,7 @@ public:  	_FORCE_INLINE_ RID get_rid() const { return rid; } -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	CollisionObject3D();  	~CollisionObject3D(); diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp index e3e2eb4669..ac715b22b2 100644 --- a/scene/3d/collision_polygon_3d.cpp +++ b/scene/3d/collision_polygon_3d.cpp @@ -121,7 +121,7 @@ void CollisionPolygon3D::set_polygon(const Vector<Point2> &p_polygon) {  	if (parent) {  		_build_polygon();  	} -	update_configuration_warning(); +	update_configuration_warnings();  	update_gizmo();  } @@ -167,24 +167,18 @@ void CollisionPolygon3D::set_margin(real_t p_margin) {  	}  } -String CollisionPolygon3D::get_configuration_warning() const { -	String warning = Node3D::get_configuration_warning(); +TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!Object::cast_to<CollisionObject3D>(get_parent())) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."); +		warnings.push_back(TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."));  	}  	if (polygon.is_empty()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("An empty CollisionPolygon3D has no effect on collision."); +		warnings.push_back(TTR("An empty CollisionPolygon3D has no effect on collision."));  	} -	return warning; +	return warnings;  }  bool CollisionPolygon3D::_is_editable_3d_polygon() const { diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/collision_polygon_3d.h index 750751b509..73b8a8e0e3 100644 --- a/scene/3d/collision_polygon_3d.h +++ b/scene/3d/collision_polygon_3d.h @@ -74,7 +74,7 @@ public:  	real_t get_margin() const;  	void set_margin(real_t p_margin); -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	CollisionPolygon3D();  }; diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index 242d82ab4c..bec87914c0 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -120,34 +120,25 @@ void CollisionShape3D::resource_changed(RES res) {  	update_gizmo();  } -String CollisionShape3D::get_configuration_warning() const { -	String warning = Node3D::get_configuration_warning(); +TypedArray<String> CollisionShape3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!Object::cast_to<CollisionObject3D>(get_parent())) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."); +		warnings.push_back(TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape."));  	}  	if (!shape.is_valid()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it."); +		warnings.push_back(TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it."));  	}  	if (shape.is_valid() &&  			Object::cast_to<RigidBody3D>(get_parent()) &&  			Object::cast_to<ConcavePolygonShape3D>(*shape) &&  			Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."); +		warnings.push_back(TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."));  	} -	return warning; +	return warnings;  }  void CollisionShape3D::_bind_methods() { @@ -188,7 +179,7 @@ void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {  	if (is_inside_tree()) {  		_shape_changed();  	} -	update_configuration_warning(); +	update_configuration_warnings();  }  Ref<Shape3D> CollisionShape3D::get_shape() const { diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h index 5512417f75..56a4ae3039 100644 --- a/scene/3d/collision_shape_3d.h +++ b/scene/3d/collision_shape_3d.h @@ -64,7 +64,7 @@ public:  	void set_disabled(bool p_disabled);  	bool is_disabled() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	CollisionShape3D();  	~CollisionShape3D(); diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index d22d7ff3ab..780773bb57 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -189,8 +189,8 @@ bool CPUParticles3D::get_fractional_delta() const {  	return fractional_delta;  } -String CPUParticles3D::get_configuration_warning() const { -	String warnings = GeometryInstance3D::get_configuration_warning(); +TypedArray<String> CPUParticles3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	bool mesh_found = false;  	bool anim_material_found = false; @@ -209,18 +209,12 @@ String CPUParticles3D::get_configuration_warning() const {  	anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);  	if (!mesh_found) { -		if (warnings != String()) { -			warnings += "\n"; -		} -		warnings += "- " + TTR("Nothing is visible because no mesh has been assigned."); +		warnings.push_back(TTR("Nothing is visible because no mesh has been assigned."));  	}  	if (!anim_material_found && (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 ||  										get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) { -		if (warnings != String()) { -			warnings += "\n"; -		} -		warnings += "- " + TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."); +		warnings.push_back(TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));  	}  	return warnings; diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index 10ac32622d..c073c93c47 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -280,7 +280,7 @@ public:  	void set_gravity(const Vector3 &p_gravity);  	Vector3 get_gravity() const; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	void restart(); diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 43f820e5d4..0da53d0101 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -503,19 +503,15 @@ Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {  	return Vector<Face3>();  } -String GIProbe::get_configuration_warning() const { -	String warning = VisualInstance3D::get_configuration_warning(); +TypedArray<String> GIProbe::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (RenderingServer::get_singleton()->is_low_end()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."); +		warnings.push_back(TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."));  	} else if (probe_data.is_null()) { -		warning += TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI."); +		warnings.push_back(TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI."));  	} - -	return warning; +	return warnings;  }  void GIProbe::_bind_methods() { diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index 534b425557..dac7dd3e17 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -165,7 +165,7 @@ public:  	virtual AABB get_aabb() const override;  	virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	GIProbe();  	~GIProbe(); diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index e2cfc2ed87..a075dcf990 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -115,7 +115,7 @@ void GPUParticles3D::set_process_material(const Ref<Material> &p_material) {  	}  	RS::get_singleton()->particles_set_process_material(particles, material_rid); -	update_configuration_warning(); +	update_configuration_warnings();  }  void GPUParticles3D::set_speed_scale(float p_scale) { @@ -208,7 +208,7 @@ void GPUParticles3D::set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh) {  	RS::get_singleton()->particles_set_draw_pass_mesh(particles, p_pass, mesh_rid); -	update_configuration_warning(); +	update_configuration_warnings();  }  Ref<Mesh> GPUParticles3D::get_draw_pass_mesh(int p_pass) const { @@ -235,13 +235,13 @@ bool GPUParticles3D::get_fractional_delta() const {  	return fractional_delta;  } -String GPUParticles3D::get_configuration_warning() const { +TypedArray<String> GPUParticles3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); +  	if (RenderingServer::get_singleton()->is_low_end()) { -		return TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose."); +		warnings.push_back(TTR("GPU-based particles are not supported by the GLES2 video driver.\nUse the CPUParticles3D node instead. You can use the \"Convert to CPUParticles3D\" option for this purpose."));  	} -	String warnings = GeometryInstance3D::get_configuration_warning(); -  	bool meshes_found = false;  	bool anim_material_found = false; @@ -264,26 +264,17 @@ String GPUParticles3D::get_configuration_warning() const {  	anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);  	if (!meshes_found) { -		if (warnings != String()) { -			warnings += "\n"; -		} -		warnings += "- " + TTR("Nothing is visible because meshes have not been assigned to draw passes."); +		warnings.push_back(TTR("Nothing is visible because meshes have not been assigned to draw passes."));  	}  	if (process_material.is_null()) { -		if (warnings != String()) { -			warnings += "\n"; -		} -		warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted."); +		warnings.push_back(TTR("A material to process the particles is not assigned, so no behavior is imprinted."));  	} else {  		const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());  		if (!anim_material_found && process &&  				(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||  						process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) { -			if (warnings != String()) { -				warnings += "\n"; -			} -			warnings += "- " + TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."); +			warnings.push_back(TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));  		}  	} diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index 0c1a1a510c..b9e2b5ccef 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -125,7 +125,7 @@ public:  	void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh);  	Ref<Mesh> get_draw_pass_mesh(int p_pass) const; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	void set_sub_emitter(const NodePath &p_path);  	NodePath get_sub_emitter() const; diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index f109640aef..d45749d36b 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -48,7 +48,7 @@ void Light3D::set_param(Param p_param, float p_value) {  		update_gizmo();  		if (p_param == PARAM_SPOT_ANGLE) { -			update_configuration_warning(); +			update_configuration_warnings();  		}  	}  } @@ -63,7 +63,7 @@ void Light3D::set_shadow(bool p_enable) {  	RS::get_singleton()->light_set_shadow(light, p_enable);  	if (type == RenderingServer::LIGHT_SPOT || type == RenderingServer::LIGHT_OMNI) { -		update_configuration_warning(); +		update_configuration_warnings();  	}  	notify_property_list_changed(); @@ -153,7 +153,7 @@ void Light3D::set_projector(const Ref<Texture2D> &p_texture) {  	projector = p_texture;  	RID tex_id = projector.is_valid() ? projector->get_rid() : RID();  	RS::get_singleton()->light_set_projector(light, tex_id); -	update_configuration_warning(); +	update_configuration_warnings();  }  Ref<Texture2D> Light3D::get_projector() const { @@ -457,17 +457,14 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const {  	return shadow_mode;  } -String OmniLight3D::get_configuration_warning() const { -	String warning = Light3D::get_configuration_warning(); +TypedArray<String> OmniLight3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!has_shadow() && get_projector().is_valid()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("Projector texture only works with shadows active."); +		warnings.push_back(TTR("Projector texture only works with shadows active."));  	} -	return warning; +	return warnings;  }  void OmniLight3D::_bind_methods() { @@ -491,24 +488,18 @@ OmniLight3D::OmniLight3D() :  	set_param(PARAM_SHADOW_NORMAL_BIAS, 2.0);  } -String SpotLight3D::get_configuration_warning() const { -	String warning = Light3D::get_configuration_warning(); +TypedArray<String> SpotLight3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows."); +		warnings.push_back(TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows."));  	}  	if (!has_shadow() && get_projector().is_valid()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("Projector texture only works with shadows active."); +		warnings.push_back(TTR("Projector texture only works with shadows active."));  	} -	return warning; +	return warnings;  }  void SpotLight3D::_bind_methods() { diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index 311db54bce..e145b08b74 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -202,7 +202,7 @@ public:  	void set_shadow_mode(ShadowMode p_mode);  	ShadowMode get_shadow_mode() const; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	OmniLight3D();  }; @@ -216,7 +216,7 @@ protected:  	static void _bind_methods();  public: -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	SpotLight3D() :  			Light3D(RenderingServer::LIGHT_SPOT) {} diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index 21ca3d70dd..7346f243ba 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -245,17 +245,14 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {  	emit_signal("velocity_computed", p_new_velocity);  } -String NavigationAgent3D::get_configuration_warning() const { -	String warning = Node::get_configuration_warning(); +TypedArray<String> NavigationAgent3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!Object::cast_to<Node3D>(get_parent())) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("The NavigationAgent3D can be used only under a spatial node."); +		warnings.push_back(TTR("The NavigationAgent3D can be used only under a spatial node."));  	} -	return warning; +	return warnings;  }  void NavigationAgent3D::update_navigation() { diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h index 22db889618..814c0714e8 100644 --- a/scene/3d/navigation_agent_3d.h +++ b/scene/3d/navigation_agent_3d.h @@ -143,7 +143,7 @@ public:  	void set_velocity(Vector3 p_velocity);  	void _avoidance_done(Vector3 p_new_velocity); -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  private:  	void update_navigation(); diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index df03bca4fd..20ffc3b00e 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -76,17 +76,14 @@ NavigationObstacle3D::~NavigationObstacle3D() {  	agent = RID(); // Pointless  } -String NavigationObstacle3D::get_configuration_warning() const { -	String warning = Node::get_configuration_warning(); +TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); -	if (!parent_node3d) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object."); +	if (!Object::cast_to<Node3D>(get_parent())) { +		warnings.push_back(TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object."));  	} -	return warning; +	return warnings;  }  void NavigationObstacle3D::update_agent_shape() { diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h index b1bb53724a..2f78f624a4 100644 --- a/scene/3d/navigation_obstacle_3d.h +++ b/scene/3d/navigation_obstacle_3d.h @@ -52,7 +52,7 @@ public:  		return agent;  	} -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  private:  	void update_agent_shape(); diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 3ca704e4b8..0afad62404 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -135,7 +135,7 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes  	emit_signal("navigation_mesh_changed");  	update_gizmo(); -	update_configuration_warning(); +	update_configuration_warnings();  }  Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const { @@ -177,21 +177,16 @@ void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {  	emit_signal("bake_finished");  } -String NavigationRegion3D::get_configuration_warning() const { -	if (!is_visible_in_tree() || !is_inside_tree()) { -		return String(); -	} - -	String warning = Node3D::get_configuration_warning(); +TypedArray<String> NavigationRegion3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); -	if (!navmesh.is_valid()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; +	if (is_visible_in_tree() && is_inside_tree()) { +		if (!navmesh.is_valid()) { +			warnings.push_back(TTR("A NavigationMesh resource must be set or created for this node to work."));  		} -		warning += TTR("A NavigationMesh resource must be set or created for this node to work.");  	} -	return warning; +	return warnings;  }  void NavigationRegion3D::_bind_methods() { @@ -217,7 +212,7 @@ void NavigationRegion3D::_bind_methods() {  void NavigationRegion3D::_navigation_changed() {  	update_gizmo(); -	update_configuration_warning(); +	update_configuration_warnings();  }  NavigationRegion3D::NavigationRegion3D() { diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index 52fa2d6159..c2045215b1 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -66,7 +66,7 @@ public:  	void bake_navigation_mesh();  	void _bake_finished(Ref<NavigationMesh> p_nav_mesh); -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	NavigationRegion3D();  	~NavigationRegion3D(); diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 7e2601902b..4ec4ee6207 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -50,7 +50,7 @@ void Path3D::_curve_changed() {  		for (int i = 0; i < get_child_count(); i++) {  			PathFollow3D *child = Object::cast_to<PathFollow3D>(get_child(i));  			if (child) { -				child->update_configuration_warning(); +				child->update_configuration_warnings();  			}  		}  	} @@ -241,29 +241,21 @@ void PathFollow3D::_validate_property(PropertyInfo &property) const {  	}  } -String PathFollow3D::get_configuration_warning() const { -	if (!is_visible_in_tree() || !is_inside_tree()) { -		return String(); -	} - -	String warning = Node3D::get_configuration_warning(); +TypedArray<String> PathFollow3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); -	if (!Object::cast_to<Path3D>(get_parent())) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("PathFollow3D only works when set as a child of a Path3D node."); -	} else { -		Path3D *path = Object::cast_to<Path3D>(get_parent()); -		if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) { -			if (!warning.is_empty()) { -				warning += "\n\n"; +	if (is_visible_in_tree() && is_inside_tree()) { +		if (!Object::cast_to<Path3D>(get_parent())) { +			warnings.push_back(TTR("PathFollow3D only works when set as a child of a Path3D node.")); +		} else { +			Path3D *path = Object::cast_to<Path3D>(get_parent()); +			if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled() && rotation_mode == ROTATION_ORIENTED) { +				warnings.push_back(TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource."));  			} -			warning += TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource.");  		}  	} -	return warning; +	return warnings;  }  void PathFollow3D::_bind_methods() { @@ -368,7 +360,7 @@ float PathFollow3D::get_unit_offset() const {  void PathFollow3D::set_rotation_mode(RotationMode p_rotation_mode) {  	rotation_mode = p_rotation_mode; -	update_configuration_warning(); +	update_configuration_warnings();  	_update_transform();  } diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h index 17ee47593e..8545370a4a 100644 --- a/scene/3d/path_3d.h +++ b/scene/3d/path_3d.h @@ -104,7 +104,7 @@ public:  	void set_cubic_interpolation(bool p_enable);  	bool get_cubic_interpolation() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	PathFollow3D() {}  }; diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index e225c1f22d..2afbebdacc 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -444,7 +444,7 @@ void RigidBody3D::_notification(int p_what) {  	if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {  		if (Engine::get_singleton()->is_editor_hint()) { -			update_configuration_warning(); +			update_configuration_warnings();  		}  	} @@ -469,7 +469,7 @@ void RigidBody3D::set_mode(Mode p_mode) {  			PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC);  		} break;  	} -	update_configuration_warning(); +	update_configuration_warnings();  }  RigidBody3D::Mode RigidBody3D::get_mode() const { @@ -709,19 +709,16 @@ Array RigidBody3D::get_colliding_bodies() const {  	return ret;  } -String RigidBody3D::get_configuration_warning() const { +TypedArray<String> RigidBody3D::get_configuration_warnings() const {  	Transform t = get_transform(); -	String warning = CollisionObject3D::get_configuration_warning(); +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."); +		warnings.push_back(TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));  	} -	return warning; +	return warnings;  }  void RigidBody3D::_bind_methods() { diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 1450fce6a6..9515b044ab 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -238,7 +238,7 @@ public:  	void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3());  	void apply_torque_impulse(const Vector3 &p_impulse); -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	RigidBody3D();  	~RigidBody3D(); diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp index de9c75621b..3d58d1c10e 100644 --- a/scene/3d/physics_joint_3d.cpp +++ b/scene/3d/physics_joint_3d.cpp @@ -65,6 +65,7 @@ void Joint3D::_update_joint(bool p_only_free) {  	if (p_only_free || !is_inside_tree()) {  		PhysicsServer3D::get_singleton()->joint_clear(joint);  		warning = String(); +		update_configuration_warnings();  		return;  	} @@ -75,43 +76,26 @@ void Joint3D::_update_joint(bool p_only_free) {  	PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b);  	if (node_a && !body_a && node_b && !body_b) { -		PhysicsServer3D::get_singleton()->joint_clear(joint);  		warning = TTR("Node A and Node B must be PhysicsBody3Ds"); -		update_configuration_warning(); -		return; -	} - -	if (node_a && !body_a) { -		PhysicsServer3D::get_singleton()->joint_clear(joint); +	} else if (node_a && !body_a) {  		warning = TTR("Node A must be a PhysicsBody3D"); -		update_configuration_warning(); -		return; -	} - -	if (node_b && !body_b) { -		PhysicsServer3D::get_singleton()->joint_clear(joint); +	} else if (node_b && !body_b) {  		warning = TTR("Node B must be a PhysicsBody3D"); -		update_configuration_warning(); -		return; -	} - -	if (!body_a && !body_b) { -		PhysicsServer3D::get_singleton()->joint_clear(joint); +	} else if (!body_a && !body_b) {  		warning = TTR("Joint is not connected to any PhysicsBody3Ds"); -		update_configuration_warning(); -		return; +	} else if (body_a == body_b) { +		warning = TTR("Node A and Node B must be different PhysicsBody3Ds"); +	} else { +		warning = String();  	} -	if (body_a == body_b) { +	update_configuration_warnings(); + +	if (!warning.is_empty()) {  		PhysicsServer3D::get_singleton()->joint_clear(joint); -		warning = TTR("Node A and Node B must be different PhysicsBody3Ds"); -		update_configuration_warning();  		return;  	} -	warning = String(); -	update_configuration_warning(); -  	configured = true;  	if (body_a) { @@ -206,17 +190,14 @@ bool Joint3D::get_exclude_nodes_from_collision() const {  	return exclude_from_collision;  } -String Joint3D::get_configuration_warning() const { -	String node_warning = Node3D::get_configuration_warning(); +TypedArray<String> Joint3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node3D::get_configuration_warnings();  	if (!warning.is_empty()) { -		if (!node_warning.is_empty()) { -			node_warning += "\n\n"; -		} -		node_warning += warning; +		warnings.push_back(warning);  	} -	return node_warning; +	return warnings;  }  void Joint3D::_bind_methods() { diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/physics_joint_3d.h index f624ba602b..3e0ea38a5c 100644 --- a/scene/3d/physics_joint_3d.h +++ b/scene/3d/physics_joint_3d.h @@ -63,7 +63,7 @@ protected:  	_FORCE_INLINE_ bool is_configured() const { return configured; }  public: -	virtual String get_configuration_warning() const override; +	virtual TypedArray<String> get_configuration_warnings() const override;  	void set_node_a(const NodePath &p_node_a);  	NodePath get_node_a() const; diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp index 83ac813c53..29a407905b 100644 --- a/scene/3d/remote_transform_3d.cpp +++ b/scene/3d/remote_transform_3d.cpp @@ -133,7 +133,7 @@ void RemoteTransform3D::set_remote_node(const NodePath &p_remote_node) {  		_update_remote();  	} -	update_configuration_warning(); +	update_configuration_warnings();  }  NodePath RemoteTransform3D::get_remote_node() const { @@ -179,17 +179,14 @@ void RemoteTransform3D::force_update_cache() {  	_update_cache();  } -String RemoteTransform3D::get_configuration_warning() const { -	String warning = Node3D::get_configuration_warning(); +TypedArray<String> RemoteTransform3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."); +		warnings.push_back(TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."));  	} -	return warning; +	return warnings;  }  void RemoteTransform3D::_bind_methods() { diff --git a/scene/3d/remote_transform_3d.h b/scene/3d/remote_transform_3d.h index 21005d92d1..321bd3b51e 100644 --- a/scene/3d/remote_transform_3d.h +++ b/scene/3d/remote_transform_3d.h @@ -70,7 +70,7 @@ public:  	void force_update_cache(); -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	RemoteTransform3D();  }; diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index 3fde4d6ef3..08e25b589e 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -249,7 +249,7 @@ void SoftBody3D::_softbody_changed() {  	prepare_physics_server();  	_reset_points_offsets();  #ifdef TOOLS_ENABLED -	update_configuration_warning(); +	update_configuration_warnings();  #endif  } @@ -301,7 +301,7 @@ void SoftBody3D::_notification(int p_what) {  	if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {  		if (Engine::get_singleton()->is_editor_hint()) { -			update_configuration_warning(); +			update_configuration_warnings();  		}  	} @@ -366,27 +366,19 @@ void SoftBody3D::_bind_methods() {  	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable");  } -String SoftBody3D::get_configuration_warning() const { -	String warning = MeshInstance3D::get_configuration_warning(); +TypedArray<String> SoftBody3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (get_mesh().is_null()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} - -		warning += TTR("This body will be ignored until you set a mesh."); +		warnings.push_back(TTR("This body will be ignored until you set a mesh."));  	}  	Transform t = get_transform();  	if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} - -		warning += TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."); +		warnings.push_back(TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));  	} -	return warning; +	return warnings;  }  void SoftBody3D::_update_physics_server() { diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h index f98df39209..0d0d39d48f 100644 --- a/scene/3d/soft_body_3d.h +++ b/scene/3d/soft_body_3d.h @@ -113,7 +113,7 @@ protected:  	void _notification(int p_what);  	static void _bind_methods(); -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  protected:  	void _update_physics_server(); diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 0be54e7243..33b8b488c6 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -928,7 +928,7 @@ void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {  	notify_property_list_changed();  	_reset_timeout();  	_queue_update(); -	update_configuration_warning(); +	update_configuration_warnings();  }  Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const { @@ -1058,17 +1058,14 @@ StringName AnimatedSprite3D::get_animation() const {  	return animation;  } -String AnimatedSprite3D::get_configuration_warning() const { -	String warning = SpriteBase3D::get_configuration_warning(); +TypedArray<String> AnimatedSprite3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (frames.is_null()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."); +		warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."));  	} -	return warning; +	return warnings;  }  void AnimatedSprite3D::_bind_methods() { diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index d1bc8dc737..5e47e66bcb 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -236,7 +236,7 @@ public:  	virtual Rect2 get_item_rect() const override; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	AnimatedSprite3D();  }; diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp index 5b0b3b89d3..edd58347f0 100644 --- a/scene/3d/vehicle_body_3d.cpp +++ b/scene/3d/vehicle_body_3d.cpp @@ -102,17 +102,14 @@ void VehicleWheel3D::_notification(int p_what) {  	}  } -String VehicleWheel3D::get_configuration_warning() const { -	String warning = Node3D::get_configuration_warning(); +TypedArray<String> VehicleWheel3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!Object::cast_to<VehicleBody3D>(get_parent())) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D."); +		warnings.push_back(TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D."));  	} -	return warning; +	return warnings;  }  void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) { diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h index 860fa7e3b7..646071a363 100644 --- a/scene/3d/vehicle_body_3d.h +++ b/scene/3d/vehicle_body_3d.h @@ -145,7 +145,7 @@ public:  	void set_steering(real_t p_steering);  	real_t get_steering() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	VehicleWheel3D();  }; diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp index 214ffd6bd5..829ecc5ec2 100644 --- a/scene/3d/world_environment.cpp +++ b/scene/3d/world_environment.cpp @@ -65,7 +65,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_warning"); +	get_tree()->call_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings");  }  void WorldEnvironment::_update_current_camera_effects() { @@ -76,7 +76,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_warning"); +	get_tree()->call_group("_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) { @@ -96,7 +96,7 @@ void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) {  	if (is_inside_tree()) {  		_update_current_environment();  	} else { -		update_configuration_warning(); +		update_configuration_warnings();  	}  } @@ -121,7 +121,7 @@ void WorldEnvironment::set_camera_effects(const Ref<CameraEffects> &p_camera_eff  	if (is_inside_tree()) {  		_update_current_camera_effects();  	} else { -		update_configuration_warning(); +		update_configuration_warnings();  	}  } @@ -129,35 +129,26 @@ Ref<CameraEffects> WorldEnvironment::get_camera_effects() const {  	return camera_effects;  } -String WorldEnvironment::get_configuration_warning() const { -	String warning = Node::get_configuration_warning(); +TypedArray<String> WorldEnvironment::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!environment.is_valid()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect."); +		warnings.push_back(TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect."));  	}  	if (!is_inside_tree()) { -		return warning; +		return warnings;  	}  	if (environment.is_valid() && get_viewport()->find_world_3d()->get_environment() != environment) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("Only the first Environment has an effect in a scene (or set of instantiated scenes)."); +		warnings.push_back(("Only the first Environment has an effect in a scene (or set of instantiated scenes)."));  	}  	if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("Only the first CameraEffects has an effect in a scene (or set of instantiated scenes)."); +		warnings.push_back(TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."));  	} -	return warning; +	return warnings;  }  void WorldEnvironment::_bind_methods() { diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h index e3f28d6d6b..9e85982381 100644 --- a/scene/3d/world_environment.h +++ b/scene/3d/world_environment.h @@ -55,7 +55,7 @@ public:  	void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);  	Ref<CameraEffects> get_camera_effects() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	WorldEnvironment();  }; diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index 63be4352d5..b5037f9be7 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -55,23 +55,18 @@ void XRCamera3D::_notification(int p_what) {  	};  }; -String XRCamera3D::get_configuration_warning() const { -	if (!is_visible() || !is_inside_tree()) { -		return String(); +TypedArray<String> XRCamera3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); + +	if (is_visible() && is_inside_tree()) { +		// must be child node of XROrigin3D! +		XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); +		if (origin == nullptr) { +			warnings.push_back(TTR("XRCamera3D must have an XROrigin3D node as its parent.")); +		};  	} -	String warning = Camera3D::get_configuration_warning(); - -	// must be child node of XROrigin3D! -	XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); -	if (origin == nullptr) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("XRCamera3D must have an XROrigin3D node as its parent."); -	}; - -	return warning; +	return warnings;  };  Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const { @@ -265,7 +260,7 @@ void XRController3D::set_controller_id(int p_controller_id) {  	// We don't check any bounds here, this controller may not yet be active and just be a place holder until it is.  	// Note that setting this to 0 means this node is not bound to a controller yet.  	controller_id = p_controller_id; -	update_configuration_warning(); +	update_configuration_warnings();  };  int XRController3D::get_controller_id() const { @@ -362,30 +357,22 @@ XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const {  	return tracker->get_tracker_hand();  }; -String XRController3D::get_configuration_warning() const { -	if (!is_visible() || !is_inside_tree()) { -		return String(); -	} - -	String warning = Node3D::get_configuration_warning(); +TypedArray<String> XRController3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); -	// must be child node of XROrigin! -	XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); -	if (origin == nullptr) { -		if (!warning.is_empty()) { -			warning += "\n\n"; +	if (is_visible() && is_inside_tree()) { +		// must be child node of XROrigin! +		XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); +		if (origin == nullptr) { +			warnings.push_back(TTR("XRController3D must have an XROrigin3D node as its parent."));  		} -		warning += TTR("XRController3D must have an XROrigin3D node as its parent."); -	}; -	if (controller_id == 0) { -		if (!warning.is_empty()) { -			warning += "\n\n"; +		if (controller_id == 0) { +			warnings.push_back(TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."));  		} -		warning += TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."); -	}; +	} -	return warning; +	return warnings;  };  //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -459,7 +446,7 @@ void XRAnchor3D::set_anchor_id(int p_anchor_id) {  	// We don't check any bounds here, this anchor may not yet be active and just be a place holder until it is.  	// Note that setting this to 0 means this node is not bound to an anchor yet.  	anchor_id = p_anchor_id; -	update_configuration_warning(); +	update_configuration_warnings();  };  int XRAnchor3D::get_anchor_id() const { @@ -487,30 +474,22 @@ bool XRAnchor3D::get_is_active() const {  	return is_active;  }; -String XRAnchor3D::get_configuration_warning() const { -	if (!is_visible() || !is_inside_tree()) { -		return String(); -	} - -	String warning = Node3D::get_configuration_warning(); +TypedArray<String> XRAnchor3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); -	// must be child node of XROrigin3D! -	XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); -	if (origin == nullptr) { -		if (!warning.is_empty()) { -			warning += "\n\n"; +	if (is_visible() && is_inside_tree()) { +		// must be child node of XROrigin3D! +		XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); +		if (origin == nullptr) { +			warnings.push_back(TTR("XRAnchor3D must have an XROrigin3D node as its parent."));  		} -		warning += TTR("XRAnchor3D must have an XROrigin3D node as its parent."); -	}; -	if (anchor_id == 0) { -		if (!warning.is_empty()) { -			warning += "\n\n"; +		if (anchor_id == 0) { +			warnings.push_back(TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."));  		} -		warning += TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."); -	}; +	} -	return warning; +	return warnings;  };  Plane XRAnchor3D::get_plane() const { @@ -528,21 +507,16 @@ Ref<Mesh> XRAnchor3D::get_mesh() const {  //////////////////////////////////////////////////////////////////////////////////////////////////// -String XROrigin3D::get_configuration_warning() const { -	if (!is_visible() || !is_inside_tree()) { -		return String(); -	} - -	String warning = Node3D::get_configuration_warning(); +TypedArray<String> XROrigin3D::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings(); -	if (tracked_camera == nullptr) { -		if (!warning.is_empty()) { -			warning += "\n\n"; +	if (is_visible() && is_inside_tree()) { +		if (tracked_camera == nullptr) { +			warnings.push_back(TTR("XROrigin3D requires an XRCamera3D child node."));  		} -		warning += TTR("XROrigin3D requires an XRCamera3D child node.");  	} -	return warning; +	return warnings;  };  void XROrigin3D::_bind_methods() { diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index 7cd6e2ac57..90079f5fe9 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -50,7 +50,7 @@ protected:  	void _notification(int p_what);  public: -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const override;  	virtual Point2 unproject_position(const Vector3 &p_pos) const override; @@ -97,7 +97,7 @@ public:  	Ref<Mesh> get_mesh() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	XRController3D() {}  	~XRController3D() {} @@ -133,7 +133,7 @@ public:  	Ref<Mesh> get_mesh() const; -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	XRAnchor3D() {}  	~XRAnchor3D() {} @@ -158,7 +158,7 @@ protected:  	static void _bind_methods();  public: -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	void set_tracked_camera(XRCamera3D *p_tracked_camera);  	void clear_tracked_camera_if(XRCamera3D *p_tracked_camera); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 4b4d3943c9..44f2d38a84 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -458,7 +458,7 @@ void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) {  	properties_dirty = true; -	update_configuration_warning(); +	update_configuration_warnings();  }  Ref<AnimationNode> AnimationTree::get_tree_root() const { @@ -1262,7 +1262,7 @@ void AnimationTree::_notification(int p_what) {  void AnimationTree::set_animation_player(const NodePath &p_player) {  	animation_player = p_player; -	update_configuration_warning(); +	update_configuration_warnings();  }  NodePath AnimationTree::get_animation_player() const { @@ -1281,38 +1281,26 @@ uint64_t AnimationTree::get_last_process_pass() const {  	return process_pass;  } -String AnimationTree::get_configuration_warning() const { -	String warning = Node::get_configuration_warning(); +TypedArray<String> AnimationTree::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!root.is_valid()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("No root AnimationNode for the graph is set."); +		warnings.push_back(TTR("No root AnimationNode for the graph is set."));  	}  	if (!has_node(animation_player)) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("Path to an AnimationPlayer node containing animations is not set."); +		warnings.push_back(TTR("Path to an AnimationPlayer node containing animations is not set."));  	} else {  		AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player));  		if (!player) { -			if (!warning.is_empty()) { -				warning += "\n\n"; -			} -			warning += TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node."); +			warnings.push_back(TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node."));  		} else if (!player->has_node(player->get_root())) { -			if (!warning.is_empty()) { -				warning += "\n\n"; -			} -			warning += TTR("The AnimationPlayer root node is not a valid node."); +			warnings.push_back(TTR("The AnimationPlayer root node is not a valid node."));  		}  	} -	return warning; +	return warnings;  }  void AnimationTree::set_root_motion_track(const NodePath &p_track) { diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 1c5aec26ab..700ff1cb5b 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -300,7 +300,7 @@ public:  	void set_animation_player(const NodePath &p_player);  	NodePath get_animation_player() const; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	bool is_state_invalid() const;  	String get_invalid_state_reason() const; diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index 2e6b798eea..dea69aae6b 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -159,16 +159,14 @@ void Container::_notification(int p_what) {  	}  } -String Container::get_configuration_warning() const { -	String warning = Control::get_configuration_warning(); +TypedArray<String> Container::get_configuration_warnings() const { +	TypedArray<String> warnings = Control::get_configuration_warnings();  	if (get_class() == "Container" && get_script().is_null()) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead."); +		warnings.push_back(TTR("Container by itself serves no purpose unless a script configures its children placement behavior.\nIf you don't intend to add a script, use a plain Control node instead."));  	} -	return warning; + +	return warnings;  }  void Container::_bind_methods() { diff --git a/scene/gui/container.h b/scene/gui/container.h index a4f392a3ae..bce3085f0c 100644 --- a/scene/gui/container.h +++ b/scene/gui/container.h @@ -56,7 +56,7 @@ public:  	void fit_child_in_rect(Control *p_child, const Rect2 &p_rect); -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	Container();  }; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 300201c0db..f569fbc420 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2183,7 +2183,7 @@ Ref<Theme> Control::get_theme() const {  void Control::set_tooltip(const String &p_tooltip) {  	data.tooltip = p_tooltip; -	update_configuration_warning(); +	update_configuration_warnings();  }  String Control::get_tooltip(const Point2 &p_pos) const { @@ -2468,7 +2468,7 @@ int Control::get_v_size_flags() const {  void Control::set_mouse_filter(MouseFilter p_filter) {  	ERR_FAIL_INDEX(p_filter, 3);  	data.mouse_filter = p_filter; -	update_configuration_warning(); +	update_configuration_warnings();  }  Control::MouseFilter Control::get_mouse_filter() const { @@ -2707,17 +2707,14 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List  	}  } -String Control::get_configuration_warning() const { -	String warning = CanvasItem::get_configuration_warning(); +TypedArray<String> Control::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (data.mouse_filter == MOUSE_FILTER_IGNORE && data.tooltip != "") { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."); +		warnings.push_back(TTR("The Hint Tooltip won't be displayed as the control's Mouse Filter is set to \"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."));  	} -	return warning; +	return warnings;  }  void Control::set_clip_contents(bool p_clip) { diff --git a/scene/gui/control.h b/scene/gui/control.h index 184b2df6d3..1f397df589 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -524,7 +524,7 @@ public:  	bool is_visibility_clip_disabled() const;  	virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	Control() {}  }; diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index 86b775e795..adc1ed67ca 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -30,17 +30,14 @@  #include "range.h" -String Range::get_configuration_warning() const { -	String warning = Control::get_configuration_warning(); +TypedArray<String> Range::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (shared->exp_ratio && shared->min <= 0) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."); +		warnings.push_back(TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."));  	} -	return warning; +	return warnings;  }  void Range::_value_changed_notify() { @@ -106,7 +103,7 @@ void Range::set_min(double p_min) {  	shared->emit_changed("min"); -	update_configuration_warning(); +	update_configuration_warnings();  }  void Range::set_max(double p_max) { @@ -181,7 +178,6 @@ double Range::get_as_ratio() const {  		double v = Math::log(value) / Math::log((double)2);  		return CLAMP((v - exp_min) / (exp_max - exp_min), 0, 1); -  	} else {  		float value = CLAMP(get_value(), shared->min, shared->max);  		return CLAMP((value - get_min()) / (get_max() - get_min()), 0, 1); @@ -287,7 +283,7 @@ bool Range::is_using_rounded_values() const {  void Range::set_exp_ratio(bool p_enable) {  	shared->exp_ratio = p_enable; -	update_configuration_warning(); +	update_configuration_warnings();  }  bool Range::is_ratio_exp() const { diff --git a/scene/gui/range.h b/scene/gui/range.h index 1072a109c6..7a129e88d6 100644 --- a/scene/gui/range.h +++ b/scene/gui/range.h @@ -97,7 +97,7 @@ public:  	void share(Range *p_range);  	void unshare(); -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	Range();  	~Range(); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 757a0841ea..73c6371658 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -544,8 +544,8 @@ void ScrollContainer::set_follow_focus(bool p_follow) {  	follow_focus = p_follow;  } -String ScrollContainer::get_configuration_warning() const { -	String warning = Container::get_configuration_warning(); +TypedArray<String> ScrollContainer::get_configuration_warnings() const { +	TypedArray<String> warnings = Container::get_configuration_warnings();  	int found = 0; @@ -565,12 +565,10 @@ String ScrollContainer::get_configuration_warning() const {  	}  	if (found != 1) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually."); +		warnings.push_back(TTR("ScrollContainer is intended to work with a single child control.\nUse a container as child (VBox, HBox, etc.), or a Control and set the custom minimum size manually."));  	} -	return warning; + +	return warnings;  }  HScrollBar *ScrollContainer::get_h_scrollbar() { diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index 9d3ce39345..e7d73bab0a 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -103,7 +103,7 @@ public:  	virtual bool clips_input() const override; -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	ScrollContainer();  }; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 27712242d1..b7313749d6 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2634,15 +2634,27 @@ void Node::clear_internal_tree_resource_paths() {  	}  } -String Node::get_configuration_warning() const { +TypedArray<String> Node::get_configuration_warnings() const {  	if (get_script_instance() && get_script_instance()->get_script().is_valid() && -			get_script_instance()->get_script()->is_tool() && get_script_instance()->has_method("_get_configuration_warning")) { -		return get_script_instance()->call("_get_configuration_warning"); +			get_script_instance()->get_script()->is_tool() && get_script_instance()->has_method("_get_configuration_warnings")) { +		return get_script_instance()->call("_get_configuration_warnings");  	} -	return String(); +	return Array();  } -void Node::update_configuration_warning() { +String Node::get_configuration_warnings_as_string() const { +	TypedArray<String> warnings = get_configuration_warnings(); +	String all_warnings = String(); +	for (int i = 0; i < warnings.size(); i++) { +		if (i > 0) { +			all_warnings += "\n\n"; +		} +		all_warnings += String(warnings[i]); +	} +	return all_warnings; +} + +void Node::update_configuration_warnings() {  #ifdef TOOLS_ENABLED  	if (!is_inside_tree()) {  		return; @@ -2798,7 +2810,7 @@ void Node::_bind_methods() {  	ClassDB::bind_method(D_METHOD("rset_unreliable", "property", "value"), &Node::rset_unreliable);  	ClassDB::bind_method(D_METHOD("rset_unreliable_id", "peer_id", "property", "value"), &Node::rset_unreliable_id); -	ClassDB::bind_method(D_METHOD("update_configuration_warning"), &Node::update_configuration_warning); +	ClassDB::bind_method(D_METHOD("update_configuration_warnings"), &Node::update_configuration_warnings);  	BIND_CONSTANT(NOTIFICATION_ENTER_TREE);  	BIND_CONSTANT(NOTIFICATION_EXIT_TREE); @@ -2874,7 +2886,7 @@ void Node::_bind_methods() {  	BIND_VMETHOD(MethodInfo("_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));  	BIND_VMETHOD(MethodInfo("_unhandled_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));  	BIND_VMETHOD(MethodInfo("_unhandled_key_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEventKey"))); -	BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_configuration_warning")); +	BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, "String"), "_get_configuration_warnings"));  }  String Node::_get_name_num_separator() { diff --git a/scene/main/node.h b/scene/main/node.h index b1e51d2aee..6ca2317d9e 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -412,9 +412,10 @@ public:  	_FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; } -	virtual String get_configuration_warning() const; +	virtual TypedArray<String> get_configuration_warnings() const; +	String get_configuration_warnings_as_string() const; -	void update_configuration_warning(); +	void update_configuration_warnings();  	void set_display_folded(bool p_folded);  	bool is_displayed_folded() const; diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp index b6b2982155..cb3b2cb392 100644 --- a/scene/main/shader_globals_override.cpp +++ b/scene/main/shader_globals_override.cpp @@ -232,7 +232,7 @@ void ShaderGlobalsOverride::_activate() {  			}  		} -		update_configuration_warning(); //may have activated +		update_configuration_warnings(); //may have activated  	}  } @@ -260,17 +260,14 @@ void ShaderGlobalsOverride::_notification(int p_what) {  	}  } -String ShaderGlobalsOverride::get_configuration_warning() const { -	String warning = Node::get_configuration_warning(); +TypedArray<String> ShaderGlobalsOverride::get_configuration_warnings() const { +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (!active) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene."); +		warnings.push_back(TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene."));  	} -	return warning; +	return warnings;  }  void ShaderGlobalsOverride::_bind_methods() { diff --git a/scene/main/shader_globals_override.h b/scene/main/shader_globals_override.h index 8d8794d465..2d9c3c76bd 100644 --- a/scene/main/shader_globals_override.h +++ b/scene/main/shader_globals_override.h @@ -58,7 +58,7 @@ protected:  	static void _bind_methods();  public: -	String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	ShaderGlobalsOverride();  }; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index a3effef99a..4c9ebe016e 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3175,20 +3175,17 @@ Variant Viewport::gui_get_drag_data() const {  	return gui.drag_data;  } -String Viewport::get_configuration_warning() const { +TypedArray<String> Viewport::get_configuration_warnings() const {  	/*if (get_parent() && !Object::cast_to<Control>(get_parent()) && !render_target) {  		return TTR("This viewport is not set as render target. If you intend for it to display its contents directly to the screen, make it a child of a Control so it can obtain a size. Otherwise, make it a RenderTarget and assign its internal texture to some node for display.");  	}*/ -	String warning = Node::get_configuration_warning(); +	TypedArray<String> warnings = Node::get_configuration_warnings();  	if (size.x == 0 || size.y == 0) { -		if (!warning.is_empty()) { -			warning += "\n\n"; -		} -		warning += TTR("Viewport size must be greater than 0 to render anything."); +		warnings.push_back(TTR("Viewport size must be greater than 0 to render anything."));  	} -	return warning; +	return warnings;  }  void Viewport::gui_reset_canvas_sort_index() { diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 8e79b50385..e8a88debf1 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -580,7 +580,7 @@ public:  	void gui_reset_canvas_sort_index();  	int gui_get_canvas_sort_index(); -	virtual String get_configuration_warning() const override; +	TypedArray<String> get_configuration_warnings() const override;  	void set_debug_draw(DebugDraw p_debug_draw);  	DebugDraw get_debug_draw() const;  |