Explorar o código

Merge pull request #38743 from arrowinaknee/node-config-warnings

Update all get_configuration_warning() to retrieve warnings from the parent
Rémi Verschelde %!s(int64=4) %!d(string=hai) anos
pai
achega
12091b39d2
Modificáronse 40 ficheiros con 284 adicións e 114 borrados
  1. 1 1
      editor/scene_tree_editor.cpp
  2. 7 2
      scene/2d/animated_sprite_2d.cpp
  3. 7 2
      scene/2d/canvas_modulate.cpp
  4. 11 3
      scene/2d/collision_polygon_2d.cpp
  5. 1 1
      scene/2d/cpu_particles_2d.cpp
  6. 1 1
      scene/2d/gpu_particles_2d.cpp
  7. 6 2
      scene/2d/light_2d.cpp
  8. 11 3
      scene/2d/light_occluder_2d.cpp
  9. 7 2
      scene/2d/navigation_agent_2d.cpp
  10. 7 2
      scene/2d/navigation_obstacle_2d.cpp
  11. 11 4
      scene/2d/navigation_region_2d.cpp
  12. 7 2
      scene/2d/parallax_layer.cpp
  13. 7 2
      scene/2d/path_2d.cpp
  14. 1 1
      scene/2d/physics_body_2d.cpp
  15. 7 2
      scene/2d/remote_transform_2d.cpp
  16. 2 2
      scene/2d/skeleton_2d.cpp
  17. 7 2
      scene/2d/visibility_notifier_2d.cpp
  18. 11 3
      scene/3d/collision_polygon_3d.cpp
  19. 15 4
      scene/3d/collision_shape_3d.cpp
  20. 1 1
      scene/3d/cpu_particles_3d.cpp
  21. 7 2
      scene/3d/gi_probe.cpp
  22. 1 1
      scene/3d/gpu_particles_3d.cpp
  23. 3 4
      scene/3d/light_3d.cpp
  24. 7 2
      scene/3d/navigation_agent_3d.cpp
  25. 7 2
      scene/3d/navigation_obstacle_3d.cpp
  26. 12 5
      scene/3d/navigation_region_3d.cpp
  27. 11 3
      scene/3d/path_3d.cpp
  28. 1 1
      scene/3d/physics_body_3d.cpp
  29. 7 2
      scene/3d/remote_transform_3d.cpp
  30. 7 2
      scene/3d/sprite_3d.cpp
  31. 7 2
      scene/3d/vehicle_body_3d.cpp
  32. 12 4
      scene/3d/world_environment.cpp
  33. 36 10
      scene/3d/xr_nodes.cpp
  34. 14 22
      scene/animation/animation_tree.cpp
  35. 1 1
      scene/gui/container.cpp
  36. 1 1
      scene/gui/control.cpp
  37. 1 1
      scene/gui/range.cpp
  38. 7 3
      scene/gui/scroll_container.cpp
  39. 7 2
      scene/main/shader_globals_override.cpp
  40. 7 2
      scene/main/viewport.cpp

+ 1 - 1
editor/scene_tree_editor.cpp

@@ -251,7 +251,7 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
 	if (can_rename) { //should be can edit..
 
 		String warning = p_node->get_configuration_warning();
-		if (warning != String()) {
+		if (!warning.empty()) {
 			item->add_button(0, get_theme_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + p_node->get_configuration_warning());
 		}
 

+ 7 - 2
scene/2d/animated_sprite_2d.cpp

@@ -660,11 +660,16 @@ StringName AnimatedSprite2D::get_animation() const {
 }
 
 String AnimatedSprite2D::get_configuration_warning() const {
+	String warning = Node2D::get_configuration_warning();
+
 	if (frames.is_null()) {
-		return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames.");
+		if (!warning.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.");
 	}
 
-	return String();
+	return warning;
 }
 
 void AnimatedSprite2D::set_specular_color(const Color &p_color) {

+ 7 - 2
scene/2d/canvas_modulate.cpp

@@ -78,14 +78,19 @@ String CanvasModulate::get_configuration_warning() const {
 		return String();
 	}
 
+	String warning = Node2D::get_configuration_warning();
+
 	List<Node *> nodes;
 	get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes);
 
 	if (nodes.size() > 1) {
-		return 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.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		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 String();
+	return warning;
 }
 
 CanvasModulate::CanvasModulate() {

+ 11 - 3
scene/2d/collision_polygon_2d.cpp

@@ -230,15 +230,23 @@ 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();
+
 	if (!Object::cast_to<CollisionObject2D>(get_parent())) {
-		return 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.");
+		if (!warning.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.");
 	}
 
 	if (polygon.empty()) {
-		return TTR("An empty CollisionPolygon2D has no effect on collision.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("An empty CollisionPolygon2D has no effect on collision.");
 	}
 
-	return String();
+	return warning;
 }
 
 void CollisionPolygon2D::set_disabled(bool p_disabled) {

+ 1 - 1
scene/2d/cpu_particles_2d.cpp

@@ -254,7 +254,7 @@ bool CPUParticles2D::get_fractional_delta() const {
 }
 
 String CPUParticles2D::get_configuration_warning() const {
-	String warnings;
+	String warnings = Node2D::get_configuration_warning();
 
 	CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
 

+ 1 - 1
scene/2d/gpu_particles_2d.cpp

@@ -222,7 +222,7 @@ String GPUParticles2D::get_configuration_warning() const {
 		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.");
 	}
 
-	String warnings;
+	String warnings = Node2D::get_configuration_warning();
 
 	if (process_material.is_null()) {
 		if (warnings != String()) {

+ 6 - 2
scene/2d/light_2d.cpp

@@ -310,11 +310,15 @@ void Light2D::_notification(int p_what) {
 }
 
 String Light2D::get_configuration_warning() const {
+	String warning = Node2D::get_configuration_warning();
+
 	if (!texture.is_valid()) {
-		return TTR("A texture with the shape of the light must be supplied to the \"Texture\" property.");
+		if (!warning.empty())
+			warning += "\n\n";
+		warning += TTR("A texture with the shape of the light must be supplied to the \"Texture\" property.");
 	}
 
-	return String();
+	return warning;
 }
 
 void Light2D::set_shadow_smooth(float p_amount) {

+ 11 - 3
scene/2d/light_occluder_2d.cpp

@@ -246,15 +246,23 @@ int LightOccluder2D::get_occluder_light_mask() const {
 }
 
 String LightOccluder2D::get_configuration_warning() const {
+	String warning = Node2D::get_configuration_warning();
+
 	if (!occluder_polygon.is_valid()) {
-		return TTR("An occluder polygon must be set (or drawn) for this occluder to take effect.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += 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) {
-		return TTR("The occluder polygon for this occluder is empty. Please draw a polygon.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The occluder polygon for this occluder is empty. Please draw a polygon.");
 	}
 
-	return String();
+	return warning;
 }
 
 void LightOccluder2D::_bind_methods() {

+ 7 - 2
scene/2d/navigation_agent_2d.cpp

@@ -271,11 +271,16 @@ void NavigationAgent2D::_avoidance_done(Vector3 p_new_velocity) {
 }
 
 String NavigationAgent2D::get_configuration_warning() const {
+	String warning = Node::get_configuration_warning();
+
 	if (!Object::cast_to<Node2D>(get_parent())) {
-		return TTR("The NavigationAgent2D can be used only under a Node2D node");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The NavigationAgent2D can be used only under a Node2D node");
 	}
 
-	return String();
+	return warning;
 }
 
 void NavigationAgent2D::update_navigation() {

+ 7 - 2
scene/2d/navigation_obstacle_2d.cpp

@@ -106,11 +106,16 @@ Node *NavigationObstacle2D::get_navigation_node() const {
 }
 
 String NavigationObstacle2D::get_configuration_warning() const {
+	String warning = Node::get_configuration_warning();
+
 	if (!Object::cast_to<Node2D>(get_parent())) {
-		return TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object.");
 	}
 
-	return String();
+	return warning;
 }
 
 void NavigationObstacle2D::update_agent_shape() {

+ 11 - 4
scene/2d/navigation_region_2d.cpp

@@ -500,19 +500,26 @@ String NavigationRegion2D::get_configuration_warning() const {
 		return String();
 	}
 
+	String warning = Node2D::get_configuration_warning();
+
 	if (!navpoly.is_valid()) {
-		return TTR("A NavigationPolygon resource must be set or created for this node to work. Please set a property or draw a polygon.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("A NavigationPolygon resource must be set or created for this node to work. Please set a property or draw a polygon.");
 	}
 	const Node2D *c = this;
 	while (c) {
 		if (Object::cast_to<Navigation2D>(c)) {
-			return String();
+			return warning;
 		}
 
 		c = Object::cast_to<Node2D>(c->get_parent());
 	}
-
-	return TTR("NavigationRegion2D must be a child or grandchild to a Navigation2D node. It only provides navigation data.");
+	if (!warning.empty()) {
+		warning += "\n\n";
+	}
+	return warning + TTR("NavigationRegion2D must be a child or grandchild to a Navigation2D node. It only provides navigation data.");
 }
 
 void NavigationRegion2D::_bind_methods() {

+ 7 - 2
scene/2d/parallax_layer.cpp

@@ -136,11 +136,16 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, float p_sc
 }
 
 String ParallaxLayer::get_configuration_warning() const {
+	String warning = Node2D::get_configuration_warning();
+
 	if (!Object::cast_to<ParallaxBackground>(get_parent())) {
-		return TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node.");
 	}
 
-	return String();
+	return warning;
 }
 
 void ParallaxLayer::_bind_methods() {

+ 7 - 2
scene/2d/path_2d.cpp

@@ -254,11 +254,16 @@ String PathFollow2D::get_configuration_warning() const {
 		return String();
 	}
 
+	String warning = Node2D::get_configuration_warning();
+
 	if (!Object::cast_to<Path2D>(get_parent())) {
-		return TTR("PathFollow2D only works when set as a child of a Path2D node.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("PathFollow2D only works when set as a child of a Path2D node.");
 	}
 
-	return String();
+	return warning;
 }
 
 void PathFollow2D::_bind_methods() {

+ 1 - 1
scene/2d/physics_body_2d.cpp

@@ -748,7 +748,7 @@ String RigidBody2D::get_configuration_warning() const {
 	String warning = CollisionObject2D::get_configuration_warning();
 
 	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 != String()) {
+		if (!warning.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.");

+ 7 - 2
scene/2d/remote_transform_2d.cpp

@@ -186,11 +186,16 @@ void RemoteTransform2D::force_update_cache() {
 }
 
 String RemoteTransform2D::get_configuration_warning() const {
+	String warning = Node2D::get_configuration_warning();
+
 	if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) {
-		return TTR("Path property must point to a valid Node2D node to work.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("Path property must point to a valid Node2D node to work.");
 	}
 
-	return String();
+	return warning;
 }
 
 void RemoteTransform2D::_bind_methods() {

+ 2 - 2
scene/2d/skeleton_2d.cpp

@@ -136,7 +136,7 @@ int Bone2D::get_index_in_skeleton() const {
 String Bone2D::get_configuration_warning() const {
 	String warning = Node2D::get_configuration_warning();
 	if (!skeleton) {
-		if (warning != String()) {
+		if (!warning.empty()) {
 			warning += "\n\n";
 		}
 		if (parent_bone) {
@@ -147,7 +147,7 @@ String Bone2D::get_configuration_warning() const {
 	}
 
 	if (rest == Transform2D(0, 0, 0, 0, 0, 0)) {
-		if (warning != String()) {
+		if (!warning.empty()) {
 			warning += "\n\n";
 		}
 		warning += TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one.");

+ 7 - 2
scene/2d/visibility_notifier_2d.cpp

@@ -313,12 +313,17 @@ void VisibilityEnabler2D::_node_removed(Node *p_node) {
 }
 
 String VisibilityEnabler2D::get_configuration_warning() const {
+	String warning = VisibilityNotifier2D::get_configuration_warning();
+
 #ifdef TOOLS_ENABLED
 	if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) {
-		return TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent.");
 	}
 #endif
-	return String();
+	return warning;
 }
 
 void VisibilityEnabler2D::_bind_methods() {

+ 11 - 3
scene/3d/collision_polygon_3d.cpp

@@ -156,15 +156,23 @@ bool CollisionPolygon3D::is_disabled() const {
 }
 
 String CollisionPolygon3D::get_configuration_warning() const {
+	String warning = Node3D::get_configuration_warning();
+
 	if (!Object::cast_to<CollisionObject3D>(get_parent())) {
-		return 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 (!warning.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.");
 	}
 
 	if (polygon.empty()) {
-		return TTR("An empty CollisionPolygon3D has no effect on collision.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("An empty CollisionPolygon3D has no effect on collision.");
 	}
 
-	return String();
+	return warning;
 }
 
 bool CollisionPolygon3D::_is_editable_3d_polygon() const {

+ 15 - 4
scene/3d/collision_shape_3d.cpp

@@ -124,23 +124,34 @@ void CollisionShape3D::resource_changed(RES res) {
 }
 
 String CollisionShape3D::get_configuration_warning() const {
+	String warning = Node3D::get_configuration_warning();
+
 	if (!Object::cast_to<CollisionObject3D>(get_parent())) {
-		return 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 (!warning.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.");
 	}
 
 	if (!shape.is_valid()) {
-		return TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it.");
 	}
 
 	if (Object::cast_to<RigidBody3D>(get_parent())) {
 		if (Object::cast_to<ConcavePolygonShape3D>(*shape)) {
 			if (Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) {
-				return TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.");
+				if (!warning.empty()) {
+					warning += "\n\n";
+				}
+				warning += TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.");
 			}
 		}
 	}
 
-	return String();
+	return warning;
 }
 
 void CollisionShape3D::_bind_methods() {

+ 1 - 1
scene/3d/cpu_particles_3d.cpp

@@ -189,7 +189,7 @@ bool CPUParticles3D::get_fractional_delta() const {
 }
 
 String CPUParticles3D::get_configuration_warning() const {
-	String warnings;
+	String warnings = GeometryInstance3D::get_configuration_warning();
 
 	bool mesh_found = false;
 	bool anim_material_found = false;

+ 7 - 2
scene/3d/gi_probe.cpp

@@ -514,10 +514,15 @@ Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
 }
 
 String GIProbe::get_configuration_warning() const {
+	String warning = VisualInstance3D::get_configuration_warning();
+
 	if (RenderingServer::get_singleton()->is_low_end()) {
-		return TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
 	}
-	return String();
+	return warning;
 }
 
 void GIProbe::_bind_methods() {

+ 1 - 1
scene/3d/gpu_particles_3d.cpp

@@ -232,7 +232,7 @@ String GPUParticles3D::get_configuration_warning() const {
 		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.");
 	}
 
-	String warnings;
+	String warnings = GeometryInstance3D::get_configuration_warning();
 
 	bool meshes_found = false;
 	bool anim_material_found = false;

+ 3 - 4
scene/3d/light_3d.cpp

@@ -448,7 +448,7 @@ String OmniLight3D::get_configuration_warning() const {
 	String warning = Light3D::get_configuration_warning();
 
 	if (!has_shadow() && get_projector().is_valid()) {
-		if (warning != String()) {
+		if (!warning.empty()) {
 			warning += "\n\n";
 		}
 		warning += TTR("Projector texture only works with shadows active.");
@@ -482,15 +482,14 @@ String SpotLight3D::get_configuration_warning() const {
 	String warning = Light3D::get_configuration_warning();
 
 	if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) {
-		if (warning != String()) {
+		if (!warning.empty()) {
 			warning += "\n\n";
 		}
-
 		warning += TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows.");
 	}
 
 	if (!has_shadow() && get_projector().is_valid()) {
-		if (warning != String()) {
+		if (!warning.empty()) {
 			warning += "\n\n";
 		}
 		warning += TTR("Projector texture only works with shadows active.");

+ 7 - 2
scene/3d/navigation_agent_3d.cpp

@@ -287,11 +287,16 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {
 }
 
 String NavigationAgent3D::get_configuration_warning() const {
+	String warning = Node::get_configuration_warning();
+
 	if (!Object::cast_to<Node3D>(get_parent())) {
-		return TTR("The NavigationAgent3D can be used only under a spatial node.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The NavigationAgent3D can be used only under a spatial node.");
 	}
 
-	return String();
+	return warning;
 }
 
 void NavigationAgent3D::update_navigation() {

+ 7 - 2
scene/3d/navigation_obstacle_3d.cpp

@@ -113,11 +113,16 @@ Node *NavigationObstacle3D::get_navigation_node() const {
 }
 
 String NavigationObstacle3D::get_configuration_warning() const {
+	String warning = Node::get_configuration_warning();
+
 	if (!Object::cast_to<Node3D>(get_parent())) {
-		return TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object.");
 	}
 
-	return String();
+	return warning;
 }
 
 void NavigationObstacle3D::update_agent_shape() {

+ 12 - 5
scene/3d/navigation_region_3d.cpp

@@ -189,19 +189,26 @@ String NavigationRegion3D::get_configuration_warning() const {
 		return String();
 	}
 
+	String warning = Node3D::get_configuration_warning();
+
 	if (!navmesh.is_valid()) {
-		return TTR("A NavigationMesh resource must be set or created for this node to work.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("A NavigationMesh resource must be set or created for this node to work.");
 	}
 	const Node3D *c = this;
 	while (c) {
-		if (Object::cast_to<Navigation3D>(c)) {
-			return String();
-		}
+		if (Object::cast_to<Navigation3D>(c))
+			return warning;
 
 		c = Object::cast_to<Node3D>(c->get_parent());
 	}
 
-	return TTR("NavigationRegion3D must be a child or grandchild to a Navigation3D node. It only provides navigation data.");
+	if (!warning.empty()) {
+		warning += "\n\n";
+	}
+	return warning + TTR("NavigationRegion3D must be a child or grandchild to a Navigation3D node. It only provides navigation data.");
 }
 
 void NavigationRegion3D::_bind_methods() {

+ 11 - 3
scene/3d/path_3d.cpp

@@ -250,16 +250,24 @@ String PathFollow3D::get_configuration_warning() const {
 		return String();
 	}
 
+	String warning = Node3D::get_configuration_warning();
+
 	if (!Object::cast_to<Path3D>(get_parent())) {
-		return TTR("PathFollow3D only works when set as a child of a Path3D node.");
+		if (!warning.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) {
-			return TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource.");
+			if (!warning.empty()) {
+				warning += "\n\n";
+			}
+			warning += TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource.");
 		}
 	}
 
-	return String();
+	return warning;
 }
 
 void PathFollow3D::_bind_methods() {

+ 1 - 1
scene/3d/physics_body_3d.cpp

@@ -737,7 +737,7 @@ String RigidBody3D::get_configuration_warning() const {
 	String warning = CollisionObject3D::get_configuration_warning();
 
 	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 != String()) {
+		if (!warning.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.");

+ 7 - 2
scene/3d/remote_transform_3d.cpp

@@ -180,11 +180,16 @@ void RemoteTransform3D::force_update_cache() {
 }
 
 String RemoteTransform3D::get_configuration_warning() const {
+	String warning = Node3D::get_configuration_warning();
+
 	if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) {
-		return TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work.");
 	}
 
-	return String();
+	return warning;
 }
 
 void RemoteTransform3D::_bind_methods() {

+ 7 - 2
scene/3d/sprite_3d.cpp

@@ -1074,11 +1074,16 @@ StringName AnimatedSprite3D::get_animation() const {
 }
 
 String AnimatedSprite3D::get_configuration_warning() const {
+	String warning = SpriteBase3D::get_configuration_warning();
+
 	if (frames.is_null()) {
-		return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.");
+		if (!warning.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.");
 	}
 
-	return String();
+	return warning;
 }
 
 void AnimatedSprite3D::_bind_methods() {

+ 7 - 2
scene/3d/vehicle_body_3d.cpp

@@ -103,11 +103,16 @@ void VehicleWheel3D::_notification(int p_what) {
 }
 
 String VehicleWheel3D::get_configuration_warning() const {
+	String warning = Node3D::get_configuration_warning();
+
 	if (!Object::cast_to<VehicleBody3D>(get_parent())) {
-		return TTR("VehicleWheel3D serves to provide a wheel system to a VehicleBody3D. Please use it as a child of a VehicleBody3D.");
+		if (!warning.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.");
 	}
 
-	return String();
+	return warning;
 }
 
 void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) {

+ 12 - 4
scene/3d/world_environment.cpp

@@ -110,22 +110,30 @@ Ref<CameraEffects> WorldEnvironment::get_camera_effects() const {
 }
 
 String WorldEnvironment::get_configuration_warning() const {
+	String warning = Node::get_configuration_warning();
+
 	if (!environment.is_valid()) {
-		return TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.");
 	}
 
 	if (!is_inside_tree()) {
-		return String();
+		return warning;
 	}
 
 	List<Node *> nodes;
 	get_tree()->get_nodes_in_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), &nodes);
 
 	if (nodes.size() > 1) {
-		return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).");
 	}
 
-	return String();
+	return warning;
 }
 
 void WorldEnvironment::_bind_methods() {

+ 36 - 10
scene/3d/xr_nodes.cpp

@@ -60,13 +60,18 @@ String XRCamera3D::get_configuration_warning() const {
 		return String();
 	}
 
+	String warning = Camera3D::get_configuration_warning();
+
 	// must be child node of XROrigin3D!
 	XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
 	if (origin == nullptr) {
-		return TTR("XRCamera3D must have an XROrigin3D node as its parent.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("XRCamera3D must have an XROrigin3D node as its parent.");
 	};
 
-	return String();
+	return warning;
 };
 
 Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const {
@@ -362,17 +367,25 @@ String XRController3D::get_configuration_warning() const {
 		return String();
 	}
 
+	String warning = Node3D::get_configuration_warning();
+
 	// must be child node of XROrigin!
 	XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
 	if (origin == nullptr) {
-		return TTR("XRController3D must have an XROrigin3D node as its parent.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("XRController3D must have an XROrigin3D node as its parent.");
 	};
 
 	if (controller_id == 0) {
-		return TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller.");
 	};
 
-	return String();
+	return warning;
 };
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -479,17 +492,25 @@ String XRAnchor3D::get_configuration_warning() const {
 		return String();
 	}
 
+	String warning = Node3D::get_configuration_warning();
+
 	// must be child node of XROrigin3D!
 	XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
 	if (origin == nullptr) {
-		return TTR("XRAnchor3D must have an XROrigin3D node as its parent.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("XRAnchor3D must have an XROrigin3D node as its parent.");
 	};
 
 	if (anchor_id == 0) {
-		return TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor.");
 	};
 
-	return String();
+	return warning;
 };
 
 Plane XRAnchor3D::get_plane() const {
@@ -512,11 +533,16 @@ String XROrigin3D::get_configuration_warning() const {
 		return String();
 	}
 
+	String warning = Node3D::get_configuration_warning();
+
 	if (tracked_camera == nullptr) {
-		return TTR("XROrigin3D requires an XRCamera3D child node.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("XROrigin3D requires an XRCamera3D child node.");
 	}
 
-	return String();
+	return warning;
 };
 
 void XROrigin3D::_bind_methods() {

+ 14 - 22
scene/animation/animation_tree.cpp

@@ -1288,39 +1288,31 @@ String AnimationTree::get_configuration_warning() const {
 	String warning = Node::get_configuration_warning();
 
 	if (!root.is_valid()) {
-		if (warning != String()) {
+		if (!warning.empty()) {
 			warning += "\n\n";
 		}
 		warning += TTR("No root AnimationNode for the graph is set.");
 	}
 
 	if (!has_node(animation_player)) {
-		if (warning != String()) {
+		if (!warning.empty()) {
 			warning += "\n\n";
 		}
-
 		warning += TTR("Path to an AnimationPlayer node containing animations is not set.");
-		return warning;
-	}
-
-	AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player));
-
-	if (!player) {
-		if (warning != String()) {
-			warning += "\n\n";
-		}
-
-		warning += TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node.");
-		return warning;
-	}
+	} else {
+		AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player));
 
-	if (!player->has_node(player->get_root())) {
-		if (warning != String()) {
-			warning += "\n\n";
+		if (!player) {
+			if (!warning.empty()) {
+				warning += "\n\n";
+			}
+			warning += TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node.");
+		} else if (!player->has_node(player->get_root())) {
+			if (!warning.empty()) {
+				warning += "\n\n";
+			}
+			warning += TTR("The AnimationPlayer root node is not a valid node.");
 		}
-
-		warning += TTR("The AnimationPlayer root node is not a valid node.");
-		return warning;
 	}
 
 	return warning;

+ 1 - 1
scene/gui/container.cpp

@@ -168,7 +168,7 @@ String Container::get_configuration_warning() const {
 	String warning = Control::get_configuration_warning();
 
 	if (get_class() == "Container" && get_script().is_null()) {
-		if (warning != String()) {
+		if (!warning.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.");

+ 1 - 1
scene/gui/control.cpp

@@ -2560,7 +2560,7 @@ String Control::get_configuration_warning() const {
 	String warning = CanvasItem::get_configuration_warning();
 
 	if (data.mouse_filter == MOUSE_FILTER_IGNORE && data.tooltip != "") {
-		if (warning != String()) {
+		if (!warning.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\".");

+ 1 - 1
scene/gui/range.cpp

@@ -34,7 +34,7 @@ String Range::get_configuration_warning() const {
 	String warning = Control::get_configuration_warning();
 
 	if (shared->exp_ratio && shared->min <= 0) {
-		if (warning != String()) {
+		if (!warning.empty()) {
 			warning += "\n\n";
 		}
 		warning += TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0.");

+ 7 - 3
scene/gui/scroll_container.cpp

@@ -520,6 +520,8 @@ void ScrollContainer::set_follow_focus(bool p_follow) {
 }
 
 String ScrollContainer::get_configuration_warning() const {
+	String warning = Container::get_configuration_warning();
+
 	int found = 0;
 
 	for (int i = 0; i < get_child_count(); i++) {
@@ -538,10 +540,12 @@ String ScrollContainer::get_configuration_warning() const {
 	}
 
 	if (found != 1) {
-		return 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.");
-	} else {
-		return "";
+		if (!warning.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.");
 	}
+	return warning;
 }
 
 HScrollBar *ScrollContainer::get_h_scrollbar() {

+ 7 - 2
scene/main/shader_globals_override.cpp

@@ -261,11 +261,16 @@ void ShaderGlobalsOverride::_notification(int p_what) {
 }
 
 String ShaderGlobalsOverride::get_configuration_warning() const {
+	String warning = Node::get_configuration_warning();
+
 	if (!active) {
-		return TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene.");
 	}
 
-	return String();
+	return warning;
 }
 
 void ShaderGlobalsOverride::_bind_methods() {

+ 7 - 2
scene/main/viewport.cpp

@@ -3093,10 +3093,15 @@ String Viewport::get_configuration_warning() const {
 		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();
+
 	if (size.x == 0 || size.y == 0) {
-		return TTR("Viewport size must be greater than 0 to render anything.");
+		if (!warning.empty()) {
+			warning += "\n\n";
+		}
+		warning += TTR("Viewport size must be greater than 0 to render anything.");
 	}
-	return String();
+	return warning;
 }
 
 void Viewport::gui_reset_canvas_sort_index() {