Use Array for node configuration warnings

Previously, the warnings were passed as a string and delimitation of which were hard coded at each implementation.
This commit is contained in:
Nathan Franke 2020-10-29 05:01:28 -05:00
parent 4a1f2dcb74
commit 2a8c59c171
No known key found for this signature in database
GPG key ID: 92164DCCF3B1F723
96 changed files with 426 additions and 674 deletions

View file

@ -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]. 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> </description>
</method> </method>
<method name="_get_configuration_warning" qualifiers="virtual"> <method name="_get_configuration_warnings" qualifiers="virtual">
<return type="String"> <return type="Array">
</return> </return>
<description> <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. 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 string produces no warning. Returning an empty array produces no warnings.
Call [method update_configuration_warning] when the warning needs to be updated for this node. Call [method update_configuration_warnings] when the warnings need to be updated for this node.
</description> </description>
</method> </method>
<method name="_input" qualifiers="virtual"> <method name="_input" qualifiers="virtual">
@ -856,12 +856,12 @@
Sets whether this is an instance load placeholder. See [InstancePlaceholder]. Sets whether this is an instance load placeholder. See [InstancePlaceholder].
</description> </description>
</method> </method>
<method name="update_configuration_warning"> <method name="update_configuration_warnings">
<return type="void"> <return type="void">
</return> </return>
<description> <description>
Updates the warning displayed for this node in the Scene Dock. 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> </description>
</method> </method>
</methods> </methods>

View file

@ -120,7 +120,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
} }
undo_redo->commit_action(); undo_redo->commit_action();
} else if (p_id == BUTTON_WARNING) { } 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()) { if (config_err == String()) {
return; 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.. 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()) { 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(); int num_connections = p_node->get_persistent_signal_connection_count();

View file

@ -272,7 +272,7 @@ void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
notify_property_list_changed(); notify_property_list_changed();
_reset_timeout(); _reset_timeout();
update(); update();
update_configuration_warning(); update_configuration_warnings();
} }
Ref<SpriteFrames> AnimatedSprite2D::get_sprite_frames() const { Ref<SpriteFrames> AnimatedSprite2D::get_sprite_frames() const {
@ -440,17 +440,14 @@ StringName AnimatedSprite2D::get_animation() const {
return animation; return animation;
} }
String AnimatedSprite2D::get_configuration_warning() const { TypedArray<String> AnimatedSprite2D::get_configuration_warnings() const {
String warning = Node2D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (frames.is_null()) { if (frames.is_null()) {
if (!warning.is_empty()) { warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite to display frames."));
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 warning; return warnings;
} }
void AnimatedSprite2D::_bind_methods() { void AnimatedSprite2D::_bind_methods() {

View file

@ -109,7 +109,7 @@ public:
void set_flip_v(bool p_flip); void set_flip_v(bool p_flip);
bool is_flipped_v() const; bool is_flipped_v() const;
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
AnimatedSprite2D(); AnimatedSprite2D();
}; };

View file

@ -51,7 +51,7 @@ void CanvasModulate::_notification(int p_what) {
remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id())); 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; return color;
} }
String CanvasModulate::get_configuration_warning() const { TypedArray<String> CanvasModulate::get_configuration_warnings() const {
if (!is_visible_in_tree() || !is_inside_tree()) { TypedArray<String> warnings = Node::get_configuration_warnings();
return String();
}
String warning = Node2D::get_configuration_warning(); 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);
List<Node *> nodes; if (nodes.size() > 1) {
get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes); 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."));
if (nodes.size() > 1) {
if (!warning.is_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 warning; return warnings;
} }
CanvasModulate::CanvasModulate() { CanvasModulate::CanvasModulate() {

View file

@ -46,7 +46,7 @@ public:
void set_color(const Color &p_color); void set_color(const Color &p_color);
Color get_color() const; Color get_color() const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
CanvasModulate(); CanvasModulate();
~CanvasModulate(); ~CanvasModulate();

View file

@ -363,17 +363,14 @@ void CollisionObject2D::_update_pickable() {
} }
} }
String CollisionObject2D::get_configuration_warning() const { TypedArray<String> CollisionObject2D::get_configuration_warnings() const {
String warning = Node2D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (shapes.is_empty()) { if (shapes.is_empty()) {
if (!warning.is_empty()) { 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."));
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.");
} }
return warning; return warnings;
} }
void CollisionObject2D::_bind_methods() { void CollisionObject2D::_bind_methods() {

View file

@ -107,7 +107,7 @@ public:
void set_pickable(bool p_enabled); void set_pickable(bool p_enabled);
bool is_pickable() const; 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; } _FORCE_INLINE_ RID get_rid() const { return rid; }

View file

@ -204,7 +204,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) {
_update_in_shape_owner(); _update_in_shape_owner();
} }
update(); update();
update_configuration_warning(); update_configuration_warnings();
} }
Vector<Point2> CollisionPolygon2D::get_polygon() const { Vector<Point2> CollisionPolygon2D::get_polygon() const {
@ -219,7 +219,7 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) {
_update_in_shape_owner(); _update_in_shape_owner();
} }
update(); update();
update_configuration_warning(); update_configuration_warnings();
} }
CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const { CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const {
@ -240,40 +240,28 @@ bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, doubl
} }
#endif #endif
String CollisionPolygon2D::get_configuration_warning() const { TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const {
String warning = Node2D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject2D>(get_parent())) { if (!Object::cast_to<CollisionObject2D>(get_parent())) {
if (!warning.is_empty()) { 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."));
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.");
} }
int polygon_count = polygon.size(); int polygon_count = polygon.size();
if (polygon_count == 0) { if (polygon_count == 0) {
if (!warning.is_empty()) { warnings.push_back(TTR("An empty CollisionPolygon2D has no effect on collision."));
warning += "\n\n";
}
warning += TTR("An empty CollisionPolygon2D has no effect on collision.");
} else { } else {
bool solids = build_mode == BUILD_SOLIDS; bool solids = build_mode == BUILD_SOLIDS;
if (solids) { if (solids) {
if (polygon_count < 3) { if (polygon_count < 3) {
if (!warning.is_empty()) { warnings.push_back(TTR("Invalid polygon. At least 3 points are needed in 'Solids' build mode."));
warning += "\n\n";
}
warning += TTR("Invalid polygon. At least 3 points are needed in 'Solids' build mode.");
} }
} else if (polygon_count < 2) { } else if (polygon_count < 2) {
if (!warning.is_empty()) { warnings.push_back(TTR("Invalid polygon. At least 2 points are needed in 'Segments' build mode."));
warning += "\n\n";
}
warning += TTR("Invalid polygon. At least 2 points are needed in 'Segments' build mode.");
} }
} }
return warning; return warnings;
} }
void CollisionPolygon2D::set_disabled(bool p_disabled) { void CollisionPolygon2D::set_disabled(bool p_disabled) {

View file

@ -78,7 +78,7 @@ public:
void set_polygon(const Vector<Point2> &p_polygon); void set_polygon(const Vector<Point2> &p_polygon);
Vector<Point2> get_polygon() const; 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); void set_disabled(bool p_disabled);
bool is_disabled() const; bool is_disabled() const;

View file

@ -162,7 +162,7 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) {
shape->connect("changed", callable_mp(this, &CollisionShape2D::_shape_changed)); shape->connect("changed", callable_mp(this, &CollisionShape2D::_shape_changed));
} }
update_configuration_warning(); update_configuration_warnings();
} }
Ref<Shape2D> CollisionShape2D::get_shape() const { 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); 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())) { 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()) { 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<ConvexPolygonShape2D> convex = shape;
Ref<ConcavePolygonShape2D> concave = shape; Ref<ConcavePolygonShape2D> concave = shape;
if (convex.is_valid() || concave.is_valid()) { 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) { void CollisionShape2D::set_disabled(bool p_disabled) {

View file

@ -72,7 +72,7 @@ public:
void set_one_way_collision_margin(real_t p_margin); void set_one_way_collision_margin(real_t p_margin);
real_t get_one_way_collision_margin() const; real_t get_one_way_collision_margin() const;
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
CollisionShape2D(); CollisionShape2D();
}; };

View file

@ -244,18 +244,15 @@ bool CPUParticles2D::get_fractional_delta() const {
return fractional_delta; return fractional_delta;
} }
String CPUParticles2D::get_configuration_warning() const { TypedArray<String> CPUParticles2D::get_configuration_warnings() const {
String warnings = Node2D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr()); CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
if (get_material().is_null() || (mat && !mat->get_particles_animation())) { 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 || 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()) { get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid()) {
if (warnings != String()) { warnings.push_back(TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));
warnings += "\n";
}
warnings += "- " + TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
} }
} }

View file

@ -275,7 +275,7 @@ public:
void set_gravity(const Vector2 &p_gravity); void set_gravity(const Vector2 &p_gravity);
Vector2 get_gravity() const; Vector2 get_gravity() const;
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
void restart(); void restart();

View file

@ -137,7 +137,7 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
} }
RS::get_singleton()->particles_set_process_material(particles, material_rid); RS::get_singleton()->particles_set_process_material(particles, material_rid);
update_configuration_warning(); update_configuration_warnings();
} }
void GPUParticles2D::set_speed_scale(float p_scale) { void GPUParticles2D::set_speed_scale(float p_scale) {
@ -216,18 +216,15 @@ bool GPUParticles2D::get_fractional_delta() const {
return fractional_delta; 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()) { 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 (process_material.is_null()) {
if (warnings != String()) { warnings.push_back(TTR("A material to process the particles is not assigned, so no behavior is imprinted."));
warnings += "\n";
}
warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
} else { } else {
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr()); CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
@ -236,10 +233,7 @@ String GPUParticles2D::get_configuration_warning() const {
if (process && if (process &&
(process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 || (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())) { process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
if (warnings != String()) { warnings.push_back(TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));
warnings += "\n";
}
warnings += "- " + TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled.");
} }
} }
} }

View file

@ -110,7 +110,7 @@ public:
void set_texture(const Ref<Texture2D> &p_texture); void set_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture() const; Ref<Texture2D> get_texture() const;
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
void restart(); void restart();
Rect2 capture_rect() const; Rect2 capture_rect() const;

View file

@ -66,6 +66,7 @@ void Joint2D::_update_joint(bool p_only_free) {
if (p_only_free || !is_inside_tree()) { if (p_only_free || !is_inside_tree()) {
PhysicsServer2D::get_singleton()->joint_clear(joint); PhysicsServer2D::get_singleton()->joint_clear(joint);
warning = String(); warning = String();
update_configuration_warnings();
return; return;
} }
@ -76,42 +77,25 @@ void Joint2D::_update_joint(bool p_only_free) {
PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b);
if (node_a && !body_a && node_b && !body_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"); warning = TTR("Node A and Node B must be PhysicsBody2Ds");
update_configuration_warning(); } else if (node_a && !body_a) {
return;
}
if (node_a && !body_a) {
PhysicsServer2D::get_singleton()->joint_clear(joint);
warning = TTR("Node A must be a PhysicsBody2D"); warning = TTR("Node A must be a PhysicsBody2D");
update_configuration_warning(); } else if (node_b && !body_b) {
return;
}
if (node_b && !body_b) {
PhysicsServer2D::get_singleton()->joint_clear(joint);
warning = TTR("Node B must be a PhysicsBody2D"); warning = TTR("Node B must be a PhysicsBody2D");
update_configuration_warning(); } else if (!body_a || !body_b) {
return;
}
if (!body_a || !body_b) {
PhysicsServer2D::get_singleton()->joint_clear(joint);
warning = TTR("Joint is not connected to two PhysicsBody2Ds"); warning = TTR("Joint is not connected to two PhysicsBody2Ds");
update_configuration_warning(); } else if (body_a == body_b) {
return;
}
if (body_a == body_b) {
PhysicsServer2D::get_singleton()->joint_clear(joint);
warning = TTR("Node A and Node B must be different PhysicsBody2Ds"); warning = TTR("Node A and Node B must be different PhysicsBody2Ds");
update_configuration_warning(); } else {
return; warning = String();
} }
warning = String(); update_configuration_warnings();
update_configuration_warning();
if (!warning.is_empty()) {
PhysicsServer2D::get_singleton()->joint_clear(joint);
return;
}
if (body_a) { if (body_a) {
body_a->force_update_transform(); body_a->force_update_transform();
@ -211,17 +195,14 @@ bool Joint2D::get_exclude_nodes_from_collision() const {
return exclude_from_collision; return exclude_from_collision;
} }
String Joint2D::get_configuration_warning() const { TypedArray<String> Joint2D::get_configuration_warnings() const {
String node_warning = Node2D::get_configuration_warning(); TypedArray<String> warnings = Node2D::get_configuration_warnings();
if (!warning.is_empty()) { if (!warning.is_empty()) {
if (!node_warning.is_empty()) { warnings.push_back(warning);
node_warning += "\n\n";
}
node_warning += warning;
} }
return node_warning; return warnings;
} }
void Joint2D::_bind_methods() { void Joint2D::_bind_methods() {

View file

@ -62,7 +62,7 @@ protected:
_FORCE_INLINE_ bool is_configured() const { return configured; } _FORCE_INLINE_ bool is_configured() const { return configured; }
public: 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); void set_node_a(const NodePath &p_node_a);
NodePath get_node_a() const; NodePath get_node_a() const;

View file

@ -373,7 +373,7 @@ void PointLight2D::set_texture(const Ref<Texture2D> &p_texture) {
RS::get_singleton()->canvas_light_set_texture(_get_light(), RID()); RS::get_singleton()->canvas_light_set_texture(_get_light(), RID());
} }
update_configuration_warning(); update_configuration_warnings();
} }
Ref<Texture2D> PointLight2D::get_texture() const { Ref<Texture2D> PointLight2D::get_texture() const {
@ -390,17 +390,14 @@ Vector2 PointLight2D::get_texture_offset() const {
return texture_offset; return texture_offset;
} }
String PointLight2D::get_configuration_warning() const { TypedArray<String> PointLight2D::get_configuration_warnings() const {
String warning = Node2D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!texture.is_valid()) { if (!texture.is_valid()) {
if (!warning.is_empty()) { warnings.push_back(TTR("A texture with the shape of the light must be supplied to the \"Texture\" property."));
warning += "\n\n";
}
warning += 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) { void PointLight2D::set_texture_scale(real_t p_scale) {

View file

@ -169,7 +169,7 @@ public:
void set_texture_scale(real_t p_scale); void set_texture_scale(real_t p_scale);
real_t get_texture_scale() const; real_t get_texture_scale() const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
PointLight2D(); PointLight2D();
}; };

View file

@ -242,24 +242,18 @@ int LightOccluder2D::get_occluder_light_mask() const {
return mask; return mask;
} }
String LightOccluder2D::get_configuration_warning() const { TypedArray<String> LightOccluder2D::get_configuration_warnings() const {
String warning = Node2D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!occluder_polygon.is_valid()) { if (!occluder_polygon.is_valid()) {
if (!warning.is_empty()) { warnings.push_back(TTR("An occluder polygon must be set (or drawn) for this occluder to take effect."));
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) { if (occluder_polygon.is_valid() && occluder_polygon->get_polygon().size() == 0) {
if (!warning.is_empty()) { warnings.push_back(TTR("The occluder polygon for this occluder is empty. Please draw a polygon."));
warning += "\n\n";
}
warning += 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) { void LightOccluder2D::set_as_sdf_collision(bool p_enable) {

View file

@ -106,7 +106,7 @@ public:
void set_as_sdf_collision(bool p_enable); void set_as_sdf_collision(bool p_enable);
bool is_set_as_sdf_collision() const; bool is_set_as_sdf_collision() const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
LightOccluder2D(); LightOccluder2D();
~LightOccluder2D(); ~LightOccluder2D();

View file

@ -239,17 +239,14 @@ void NavigationAgent2D::_avoidance_done(Vector3 p_new_velocity) {
emit_signal("velocity_computed", velocity); emit_signal("velocity_computed", velocity);
} }
String NavigationAgent2D::get_configuration_warning() const { TypedArray<String> NavigationAgent2D::get_configuration_warnings() const {
String warning = Node::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node2D>(get_parent())) { if (!Object::cast_to<Node2D>(get_parent())) {
if (!warning.is_empty()) { warnings.push_back(TTR("The NavigationAgent2D can be used only under a Node2D node"));
warning += "\n\n";
}
warning += TTR("The NavigationAgent2D can be used only under a Node2D node");
} }
return warning; return warnings;
} }
void NavigationAgent2D::update_navigation() { void NavigationAgent2D::update_navigation() {

View file

@ -136,7 +136,7 @@ public:
void set_velocity(Vector2 p_velocity); void set_velocity(Vector2 p_velocity);
void _avoidance_done(Vector3 p_new_velocity); void _avoidance_done(Vector3 p_new_velocity);
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
private: private:
void update_navigation(); void update_navigation();

View file

@ -69,17 +69,14 @@ NavigationObstacle2D::~NavigationObstacle2D() {
agent = RID(); // Pointless agent = RID(); // Pointless
} }
String NavigationObstacle2D::get_configuration_warning() const { TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const {
String warning = Node::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node2D>(get_parent())) { if (!Object::cast_to<Node2D>(get_parent())) {
if (!warning.is_empty()) { warnings.push_back(TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object."));
warning += "\n\n";
}
warning += TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object.");
} }
return warning; return warnings;
} }
void NavigationObstacle2D::update_agent_shape() { void NavigationObstacle2D::update_agent_shape() {

View file

@ -52,7 +52,7 @@ public:
return agent; return agent;
} }
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
private: private:
void update_agent_shape(); void update_agent_shape();

View file

@ -491,7 +491,7 @@ void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_
} }
_navpoly_changed(); _navpoly_changed();
update_configuration_warning(); update_configuration_warnings();
} }
Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const { Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const {
@ -509,21 +509,16 @@ void NavigationRegion2D::_map_changed(RID p_map) {
} }
} }
String NavigationRegion2D::get_configuration_warning() const { TypedArray<String> NavigationRegion2D::get_configuration_warnings() const {
if (!is_visible_in_tree() || !is_inside_tree()) { TypedArray<String> warnings = Node2D::get_configuration_warnings();
return String();
}
String warning = Node2D::get_configuration_warning(); if (is_visible_in_tree() && is_inside_tree()) {
if (!navpoly.is_valid()) {
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."));
if (!warning.is_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.");
} }
return warning; return warnings;
} }
void NavigationRegion2D::_bind_methods() { void NavigationRegion2D::_bind_methods() {

View file

@ -120,7 +120,7 @@ public:
void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly); void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly);
Ref<NavigationPolygon> get_navigation_polygon() const; Ref<NavigationPolygon> get_navigation_polygon() const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
NavigationRegion2D(); NavigationRegion2D();
~NavigationRegion2D(); ~NavigationRegion2D();

View file

@ -135,17 +135,14 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_s
_update_mirroring(); _update_mirroring();
} }
String ParallaxLayer::get_configuration_warning() const { TypedArray<String> ParallaxLayer::get_configuration_warnings() const {
String warning = Node2D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<ParallaxBackground>(get_parent())) { if (!Object::cast_to<ParallaxBackground>(get_parent())) {
if (!warning.is_empty()) { warnings.push_back(TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node."));
warning += "\n\n";
}
warning += TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node.");
} }
return warning; return warnings;
} }
void ParallaxLayer::_bind_methods() { void ParallaxLayer::_bind_methods() {

View file

@ -61,7 +61,7 @@ public:
void set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset); 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(); ParallaxLayer();
}; };

View file

@ -249,21 +249,16 @@ void PathFollow2D::_validate_property(PropertyInfo &property) const {
} }
} }
String PathFollow2D::get_configuration_warning() const { TypedArray<String> PathFollow2D::get_configuration_warnings() const {
if (!is_visible_in_tree() || !is_inside_tree()) { TypedArray<String> warnings = Node::get_configuration_warnings();
return String();
}
String warning = Node2D::get_configuration_warning(); if (is_visible_in_tree() && is_inside_tree()) {
if (!Object::cast_to<Path2D>(get_parent())) {
if (!Object::cast_to<Path2D>(get_parent())) { warnings.push_back(TTR("PathFollow2D only works when set as a child of a Path2D node."));
if (!warning.is_empty()) {
warning += "\n\n";
} }
warning += TTR("PathFollow2D only works when set as a child of a Path2D node.");
} }
return warning; return warnings;
} }
void PathFollow2D::_bind_methods() { void PathFollow2D::_bind_methods() {

View file

@ -105,7 +105,7 @@ public:
void set_cubic_interpolation(bool p_enable); void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const; bool get_cubic_interpolation() const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
PathFollow2D() {} PathFollow2D() {}
}; };

View file

@ -708,26 +708,23 @@ void RigidBody2D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
update_configuration_warning(); update_configuration_warnings();
} }
} }
#endif #endif
} }
String RigidBody2D::get_configuration_warning() const { TypedArray<String> RigidBody2D::get_configuration_warnings() const {
Transform2D t = get_transform(); 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 ((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()) { 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."));
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.");
} }
return warning; return warnings;
} }
void RigidBody2D::_bind_methods() { void RigidBody2D::_bind_methods() {

View file

@ -246,7 +246,7 @@ public:
TypedArray<Node2D> get_colliding_bodies() const; //function for script 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();
~RigidBody2D(); ~RigidBody2D();

View file

@ -138,7 +138,7 @@ void RemoteTransform2D::set_remote_node(const NodePath &p_remote_node) {
_update_remote(); _update_remote();
} }
update_configuration_warning(); update_configuration_warnings();
} }
NodePath RemoteTransform2D::get_remote_node() const { NodePath RemoteTransform2D::get_remote_node() const {
@ -185,17 +185,14 @@ void RemoteTransform2D::force_update_cache() {
_update_cache(); _update_cache();
} }
String RemoteTransform2D::get_configuration_warning() const { TypedArray<String> RemoteTransform2D::get_configuration_warnings() const {
String warning = Node2D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) { if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) {
if (!warning.is_empty()) { warnings.push_back(TTR("Path property must point to a valid Node2D node to work."));
warning += "\n\n";
}
warning += TTR("Path property must point to a valid Node2D node to work.");
} }
return warning; return warnings;
} }
void RemoteTransform2D::_bind_methods() { void RemoteTransform2D::_bind_methods() {

View file

@ -70,7 +70,7 @@ public:
void force_update_cache(); void force_update_cache();
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
RemoteTransform2D(); RemoteTransform2D();
}; };

View file

@ -100,7 +100,7 @@ void Bone2D::set_rest(const Transform2D &p_rest) {
skeleton->_make_bone_setup_dirty(); skeleton->_make_bone_setup_dirty();
} }
update_configuration_warning(); update_configuration_warnings();
} }
Transform2D Bone2D::get_rest() const { Transform2D Bone2D::get_rest() const {
@ -133,27 +133,21 @@ int Bone2D::get_index_in_skeleton() const {
return skeleton_index; return skeleton_index;
} }
String Bone2D::get_configuration_warning() const { TypedArray<String> Bone2D::get_configuration_warnings() const {
String warning = Node2D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!skeleton) { if (!skeleton) {
if (!warning.is_empty()) {
warning += "\n\n";
}
if (parent_bone) { 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 { } 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 (rest == Transform2D(0, 0, 0, 0, 0, 0)) {
if (!warning.is_empty()) { warnings.push_back(TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."));
warning += "\n\n";
}
warning += TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one.");
} }
return warning; return warnings;
} }
Bone2D::Bone2D() { Bone2D::Bone2D() {

View file

@ -60,7 +60,7 @@ public:
void apply_rest(); void apply_rest();
Transform2D get_skeleton_rest() const; 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); void set_default_length(real_t p_length);
real_t get_default_length() const; real_t get_default_length() const;

View file

@ -59,7 +59,7 @@ void TileMap::_notification(int p_what) {
RID space = get_world_2d()->get_space(); RID space = get_world_2d()->get_space();
_update_quadrant_transform(); _update_quadrant_transform();
_update_quadrant_space(space); _update_quadrant_space(space);
update_configuration_warning(); update_configuration_warnings();
} break; } break;
@ -1301,7 +1301,7 @@ void TileMap::set_collision_use_parent(bool p_use_parent) {
_recreate_quadrants(); _recreate_quadrants();
notify_property_list_changed(); notify_property_list_changed();
update_configuration_warning(); update_configuration_warnings();
} }
void TileMap::set_collision_friction(float p_friction) { 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 { TypedArray<String> TileMap::get_configuration_warnings() const {
String warning = Node2D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (use_parent && !collision_parent) { if (use_parent && !collision_parent) {
if (!warning.is_empty()) { 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."));
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.");
} }
return warning; return warnings;
} }
void TileMap::_bind_methods() { void TileMap::_bind_methods() {

View file

@ -340,7 +340,7 @@ public:
void set_clip_uv(bool p_enable); void set_clip_uv(bool p_enable);
bool get_clip_uv() const; 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; virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override;

View file

@ -310,18 +310,15 @@ void VisibilityEnabler2D::_node_removed(Node *p_node) {
nodes.erase(p_node); nodes.erase(p_node);
} }
String VisibilityEnabler2D::get_configuration_warning() const { TypedArray<String> VisibilityEnabler2D::get_configuration_warnings() const {
String warning = VisibilityNotifier2D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) { if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) {
if (!warning.is_empty()) { warnings.push_back(TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent."));
warning += "\n\n";
}
warning += TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent.");
} }
#endif #endif
return warning; return warnings;
} }
void VisibilityEnabler2D::_bind_methods() { void VisibilityEnabler2D::_bind_methods() {

View file

@ -102,7 +102,7 @@ public:
void set_enabler(Enabler p_enabler, bool p_enable); void set_enabler(Enabler p_enabler, bool p_enable);
bool is_enabler_enabled(Enabler p_enabler) const; bool is_enabler_enabled(Enabler p_enabler) const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
VisibilityEnabler2D(); VisibilityEnabler2D();
}; };

View file

@ -395,17 +395,14 @@ bool CollisionObject3D::get_capture_input_on_drag() const {
return capture_input_on_drag; return capture_input_on_drag;
} }
String CollisionObject3D::get_configuration_warning() const { TypedArray<String> CollisionObject3D::get_configuration_warnings() const {
String warning = Node3D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (shapes.is_empty()) { if (shapes.is_empty()) {
if (!warning.is_empty()) { 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."));
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.");
} }
return warning; return warnings;
} }
CollisionObject3D::CollisionObject3D() { CollisionObject3D::CollisionObject3D() {

View file

@ -110,7 +110,7 @@ public:
_FORCE_INLINE_ RID get_rid() const { return rid; } _FORCE_INLINE_ RID get_rid() const { return rid; }
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
CollisionObject3D(); CollisionObject3D();
~CollisionObject3D(); ~CollisionObject3D();

View file

@ -121,7 +121,7 @@ void CollisionPolygon3D::set_polygon(const Vector<Point2> &p_polygon) {
if (parent) { if (parent) {
_build_polygon(); _build_polygon();
} }
update_configuration_warning(); update_configuration_warnings();
update_gizmo(); update_gizmo();
} }
@ -167,24 +167,18 @@ void CollisionPolygon3D::set_margin(real_t p_margin) {
} }
} }
String CollisionPolygon3D::get_configuration_warning() const { TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const {
String warning = Node3D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) { if (!Object::cast_to<CollisionObject3D>(get_parent())) {
if (!warning.is_empty()) { 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."));
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.is_empty()) { if (polygon.is_empty()) {
if (!warning.is_empty()) { warnings.push_back(TTR("An empty CollisionPolygon3D has no effect on collision."));
warning += "\n\n";
}
warning += TTR("An empty CollisionPolygon3D has no effect on collision.");
} }
return warning; return warnings;
} }
bool CollisionPolygon3D::_is_editable_3d_polygon() const { bool CollisionPolygon3D::_is_editable_3d_polygon() const {

View file

@ -74,7 +74,7 @@ public:
real_t get_margin() const; real_t get_margin() const;
void set_margin(real_t p_margin); void set_margin(real_t p_margin);
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
CollisionPolygon3D(); CollisionPolygon3D();
}; };

View file

@ -120,34 +120,25 @@ void CollisionShape3D::resource_changed(RES res) {
update_gizmo(); update_gizmo();
} }
String CollisionShape3D::get_configuration_warning() const { TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
String warning = Node3D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) { if (!Object::cast_to<CollisionObject3D>(get_parent())) {
if (!warning.is_empty()) { 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."));
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()) { if (!shape.is_valid()) {
if (!warning.is_empty()) { warnings.push_back(TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it."));
warning += "\n\n";
}
warning += TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it.");
} }
if (shape.is_valid() && if (shape.is_valid() &&
Object::cast_to<RigidBody3D>(get_parent()) && Object::cast_to<RigidBody3D>(get_parent()) &&
Object::cast_to<ConcavePolygonShape3D>(*shape) && Object::cast_to<ConcavePolygonShape3D>(*shape) &&
Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) { Object::cast_to<RigidBody3D>(get_parent())->get_mode() != RigidBody3D::MODE_STATIC) {
if (!warning.is_empty()) { warnings.push_back(TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."));
warning += "\n\n";
}
warning += TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static.");
} }
return warning; return warnings;
} }
void CollisionShape3D::_bind_methods() { void CollisionShape3D::_bind_methods() {
@ -188,7 +179,7 @@ void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {
if (is_inside_tree()) { if (is_inside_tree()) {
_shape_changed(); _shape_changed();
} }
update_configuration_warning(); update_configuration_warnings();
} }
Ref<Shape3D> CollisionShape3D::get_shape() const { Ref<Shape3D> CollisionShape3D::get_shape() const {

View file

@ -64,7 +64,7 @@ public:
void set_disabled(bool p_disabled); void set_disabled(bool p_disabled);
bool is_disabled() const; bool is_disabled() const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
CollisionShape3D(); CollisionShape3D();
~CollisionShape3D(); ~CollisionShape3D();

View file

@ -189,8 +189,8 @@ bool CPUParticles3D::get_fractional_delta() const {
return fractional_delta; return fractional_delta;
} }
String CPUParticles3D::get_configuration_warning() const { TypedArray<String> CPUParticles3D::get_configuration_warnings() const {
String warnings = GeometryInstance3D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
bool mesh_found = false; bool mesh_found = false;
bool anim_material_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); anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
if (!mesh_found) { if (!mesh_found) {
if (warnings != String()) { warnings.push_back(TTR("Nothing is visible because no mesh has been assigned."));
warnings += "\n";
}
warnings += "- " + 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 || 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())) { get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) {
if (warnings != String()) { warnings.push_back(TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
warnings += "\n";
}
warnings += "- " + TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".");
} }
return warnings; return warnings;

View file

@ -280,7 +280,7 @@ public:
void set_gravity(const Vector3 &p_gravity); void set_gravity(const Vector3 &p_gravity);
Vector3 get_gravity() const; Vector3 get_gravity() const;
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
void restart(); void restart();

View file

@ -503,19 +503,15 @@ Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
return Vector<Face3>(); return Vector<Face3>();
} }
String GIProbe::get_configuration_warning() const { TypedArray<String> GIProbe::get_configuration_warnings() const {
String warning = VisualInstance3D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (RenderingServer::get_singleton()->is_low_end()) { if (RenderingServer::get_singleton()->is_low_end()) {
if (!warning.is_empty()) { warnings.push_back(TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."));
warning += "\n\n";
}
warning += TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.");
} else if (probe_data.is_null()) { } 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 warnings;
return warning;
} }
void GIProbe::_bind_methods() { void GIProbe::_bind_methods() {

View file

@ -165,7 +165,7 @@ public:
virtual AABB get_aabb() const override; virtual AABB get_aabb() const override;
virtual Vector<Face3> get_faces(uint32_t p_usage_flags) 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();
~GIProbe(); ~GIProbe();

View file

@ -115,7 +115,7 @@ void GPUParticles3D::set_process_material(const Ref<Material> &p_material) {
} }
RS::get_singleton()->particles_set_process_material(particles, material_rid); RS::get_singleton()->particles_set_process_material(particles, material_rid);
update_configuration_warning(); update_configuration_warnings();
} }
void GPUParticles3D::set_speed_scale(float p_scale) { 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); 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 { Ref<Mesh> GPUParticles3D::get_draw_pass_mesh(int p_pass) const {
@ -235,12 +235,12 @@ bool GPUParticles3D::get_fractional_delta() const {
return fractional_delta; return fractional_delta;
} }
String GPUParticles3D::get_configuration_warning() const { TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
if (RenderingServer::get_singleton()->is_low_end()) { TypedArray<String> warnings = Node::get_configuration_warnings();
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 = GeometryInstance3D::get_configuration_warning(); if (RenderingServer::get_singleton()->is_low_end()) {
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."));
}
bool meshes_found = false; bool meshes_found = false;
bool anim_material_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); anim_material_found = anim_material_found || (spat && spat->get_billboard_mode() == StandardMaterial3D::BILLBOARD_PARTICLES);
if (!meshes_found) { if (!meshes_found) {
if (warnings != String()) { warnings.push_back(TTR("Nothing is visible because meshes have not been assigned to draw passes."));
warnings += "\n";
}
warnings += "- " + TTR("Nothing is visible because meshes have not been assigned to draw passes.");
} }
if (process_material.is_null()) { if (process_material.is_null()) {
if (warnings != String()) { warnings.push_back(TTR("A material to process the particles is not assigned, so no behavior is imprinted."));
warnings += "\n";
}
warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
} else { } else {
const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr()); const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
if (!anim_material_found && process && 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(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())) { process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
if (warnings != String()) { warnings.push_back(TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
warnings += "\n";
}
warnings += "- " + TTR("Particles animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\".");
} }
} }

View file

@ -125,7 +125,7 @@ public:
void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh); void set_draw_pass_mesh(int p_pass, const Ref<Mesh> &p_mesh);
Ref<Mesh> get_draw_pass_mesh(int p_pass) const; 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); void set_sub_emitter(const NodePath &p_path);
NodePath get_sub_emitter() const; NodePath get_sub_emitter() const;

View file

@ -48,7 +48,7 @@ void Light3D::set_param(Param p_param, float p_value) {
update_gizmo(); update_gizmo();
if (p_param == PARAM_SPOT_ANGLE) { 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); RS::get_singleton()->light_set_shadow(light, p_enable);
if (type == RenderingServer::LIGHT_SPOT || type == RenderingServer::LIGHT_OMNI) { if (type == RenderingServer::LIGHT_SPOT || type == RenderingServer::LIGHT_OMNI) {
update_configuration_warning(); update_configuration_warnings();
} }
notify_property_list_changed(); notify_property_list_changed();
@ -153,7 +153,7 @@ void Light3D::set_projector(const Ref<Texture2D> &p_texture) {
projector = p_texture; projector = p_texture;
RID tex_id = projector.is_valid() ? projector->get_rid() : RID(); RID tex_id = projector.is_valid() ? projector->get_rid() : RID();
RS::get_singleton()->light_set_projector(light, tex_id); RS::get_singleton()->light_set_projector(light, tex_id);
update_configuration_warning(); update_configuration_warnings();
} }
Ref<Texture2D> Light3D::get_projector() const { Ref<Texture2D> Light3D::get_projector() const {
@ -457,17 +457,14 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const {
return shadow_mode; return shadow_mode;
} }
String OmniLight3D::get_configuration_warning() const { TypedArray<String> OmniLight3D::get_configuration_warnings() const {
String warning = Light3D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!has_shadow() && get_projector().is_valid()) { if (!has_shadow() && get_projector().is_valid()) {
if (!warning.is_empty()) { warnings.push_back(TTR("Projector texture only works with shadows active."));
warning += "\n\n";
}
warning += TTR("Projector texture only works with shadows active.");
} }
return warning; return warnings;
} }
void OmniLight3D::_bind_methods() { void OmniLight3D::_bind_methods() {
@ -491,24 +488,18 @@ OmniLight3D::OmniLight3D() :
set_param(PARAM_SHADOW_NORMAL_BIAS, 2.0); set_param(PARAM_SHADOW_NORMAL_BIAS, 2.0);
} }
String SpotLight3D::get_configuration_warning() const { TypedArray<String> SpotLight3D::get_configuration_warnings() const {
String warning = Light3D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) { if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) {
if (!warning.is_empty()) { warnings.push_back(TTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows."));
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 (!has_shadow() && get_projector().is_valid()) {
if (!warning.is_empty()) { warnings.push_back(TTR("Projector texture only works with shadows active."));
warning += "\n\n";
}
warning += TTR("Projector texture only works with shadows active.");
} }
return warning; return warnings;
} }
void SpotLight3D::_bind_methods() { void SpotLight3D::_bind_methods() {

View file

@ -202,7 +202,7 @@ public:
void set_shadow_mode(ShadowMode p_mode); void set_shadow_mode(ShadowMode p_mode);
ShadowMode get_shadow_mode() const; ShadowMode get_shadow_mode() const;
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
OmniLight3D(); OmniLight3D();
}; };
@ -216,7 +216,7 @@ protected:
static void _bind_methods(); static void _bind_methods();
public: public:
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
SpotLight3D() : SpotLight3D() :
Light3D(RenderingServer::LIGHT_SPOT) {} Light3D(RenderingServer::LIGHT_SPOT) {}

View file

@ -245,17 +245,14 @@ void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {
emit_signal("velocity_computed", p_new_velocity); emit_signal("velocity_computed", p_new_velocity);
} }
String NavigationAgent3D::get_configuration_warning() const { TypedArray<String> NavigationAgent3D::get_configuration_warnings() const {
String warning = Node::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node3D>(get_parent())) { if (!Object::cast_to<Node3D>(get_parent())) {
if (!warning.is_empty()) { warnings.push_back(TTR("The NavigationAgent3D can be used only under a spatial node."));
warning += "\n\n";
}
warning += TTR("The NavigationAgent3D can be used only under a spatial node.");
} }
return warning; return warnings;
} }
void NavigationAgent3D::update_navigation() { void NavigationAgent3D::update_navigation() {

View file

@ -143,7 +143,7 @@ public:
void set_velocity(Vector3 p_velocity); void set_velocity(Vector3 p_velocity);
void _avoidance_done(Vector3 p_new_velocity); void _avoidance_done(Vector3 p_new_velocity);
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
private: private:
void update_navigation(); void update_navigation();

View file

@ -76,17 +76,14 @@ NavigationObstacle3D::~NavigationObstacle3D() {
agent = RID(); // Pointless agent = RID(); // Pointless
} }
String NavigationObstacle3D::get_configuration_warning() const { TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const {
String warning = Node::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!parent_node3d) { if (!Object::cast_to<Node3D>(get_parent())) {
if (!warning.is_empty()) { warnings.push_back(TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object."));
warning += "\n\n";
}
warning += TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object.");
} }
return warning; return warnings;
} }
void NavigationObstacle3D::update_agent_shape() { void NavigationObstacle3D::update_agent_shape() {

View file

@ -52,7 +52,7 @@ public:
return agent; return agent;
} }
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
private: private:
void update_agent_shape(); void update_agent_shape();

View file

@ -135,7 +135,7 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes
emit_signal("navigation_mesh_changed"); emit_signal("navigation_mesh_changed");
update_gizmo(); update_gizmo();
update_configuration_warning(); update_configuration_warnings();
} }
Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const { Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const {
@ -177,21 +177,16 @@ void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) {
emit_signal("bake_finished"); emit_signal("bake_finished");
} }
String NavigationRegion3D::get_configuration_warning() const { TypedArray<String> NavigationRegion3D::get_configuration_warnings() const {
if (!is_visible_in_tree() || !is_inside_tree()) { TypedArray<String> warnings = Node::get_configuration_warnings();
return String();
}
String warning = Node3D::get_configuration_warning(); if (is_visible_in_tree() && is_inside_tree()) {
if (!navmesh.is_valid()) {
if (!navmesh.is_valid()) { warnings.push_back(TTR("A NavigationMesh resource must be set or created for this node to work."));
if (!warning.is_empty()) {
warning += "\n\n";
} }
warning += TTR("A NavigationMesh resource must be set or created for this node to work.");
} }
return warning; return warnings;
} }
void NavigationRegion3D::_bind_methods() { void NavigationRegion3D::_bind_methods() {
@ -217,7 +212,7 @@ void NavigationRegion3D::_bind_methods() {
void NavigationRegion3D::_navigation_changed() { void NavigationRegion3D::_navigation_changed() {
update_gizmo(); update_gizmo();
update_configuration_warning(); update_configuration_warnings();
} }
NavigationRegion3D::NavigationRegion3D() { NavigationRegion3D::NavigationRegion3D() {

View file

@ -66,7 +66,7 @@ public:
void bake_navigation_mesh(); void bake_navigation_mesh();
void _bake_finished(Ref<NavigationMesh> p_nav_mesh); void _bake_finished(Ref<NavigationMesh> p_nav_mesh);
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
NavigationRegion3D(); NavigationRegion3D();
~NavigationRegion3D(); ~NavigationRegion3D();

View file

@ -50,7 +50,7 @@ void Path3D::_curve_changed() {
for (int i = 0; i < get_child_count(); i++) { for (int i = 0; i < get_child_count(); i++) {
PathFollow3D *child = Object::cast_to<PathFollow3D>(get_child(i)); PathFollow3D *child = Object::cast_to<PathFollow3D>(get_child(i));
if (child) { 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 { TypedArray<String> PathFollow3D::get_configuration_warnings() const {
if (!is_visible_in_tree() || !is_inside_tree()) { TypedArray<String> warnings = Node::get_configuration_warnings();
return String();
}
String warning = Node3D::get_configuration_warning(); if (is_visible_in_tree() && is_inside_tree()) {
if (!Object::cast_to<Path3D>(get_parent())) {
if (!Object::cast_to<Path3D>(get_parent())) { warnings.push_back(TTR("PathFollow3D only works when set as a child of a Path3D node."));
if (!warning.is_empty()) { } else {
warning += "\n\n"; 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) {
warning += TTR("PathFollow3D only works when set as a child of a Path3D node."); warnings.push_back(TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource."));
} 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";
} }
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() { void PathFollow3D::_bind_methods() {
@ -368,7 +360,7 @@ float PathFollow3D::get_unit_offset() const {
void PathFollow3D::set_rotation_mode(RotationMode p_rotation_mode) { void PathFollow3D::set_rotation_mode(RotationMode p_rotation_mode) {
rotation_mode = p_rotation_mode; rotation_mode = p_rotation_mode;
update_configuration_warning(); update_configuration_warnings();
_update_transform(); _update_transform();
} }

View file

@ -104,7 +104,7 @@ public:
void set_cubic_interpolation(bool p_enable); void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const; bool get_cubic_interpolation() const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
PathFollow3D() {} PathFollow3D() {}
}; };

View file

@ -444,7 +444,7 @@ void RigidBody3D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) { 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); PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC);
} break; } break;
} }
update_configuration_warning(); update_configuration_warnings();
} }
RigidBody3D::Mode RigidBody3D::get_mode() const { RigidBody3D::Mode RigidBody3D::get_mode() const {
@ -709,19 +709,16 @@ Array RigidBody3D::get_colliding_bodies() const {
return ret; return ret;
} }
String RigidBody3D::get_configuration_warning() const { TypedArray<String> RigidBody3D::get_configuration_warnings() const {
Transform t = get_transform(); 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 ((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()) { 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."));
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.");
} }
return warning; return warnings;
} }
void RigidBody3D::_bind_methods() { void RigidBody3D::_bind_methods() {

View file

@ -238,7 +238,7 @@ public:
void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()); void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3());
void apply_torque_impulse(const Vector3 &p_impulse); void apply_torque_impulse(const Vector3 &p_impulse);
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
RigidBody3D(); RigidBody3D();
~RigidBody3D(); ~RigidBody3D();

View file

@ -65,6 +65,7 @@ void Joint3D::_update_joint(bool p_only_free) {
if (p_only_free || !is_inside_tree()) { if (p_only_free || !is_inside_tree()) {
PhysicsServer3D::get_singleton()->joint_clear(joint); PhysicsServer3D::get_singleton()->joint_clear(joint);
warning = String(); warning = String();
update_configuration_warnings();
return; return;
} }
@ -75,42 +76,25 @@ void Joint3D::_update_joint(bool p_only_free) {
PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b); PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b);
if (node_a && !body_a && node_b && !body_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"); warning = TTR("Node A and Node B must be PhysicsBody3Ds");
update_configuration_warning(); } else if (node_a && !body_a) {
return;
}
if (node_a && !body_a) {
PhysicsServer3D::get_singleton()->joint_clear(joint);
warning = TTR("Node A must be a PhysicsBody3D"); warning = TTR("Node A must be a PhysicsBody3D");
update_configuration_warning(); } else if (node_b && !body_b) {
return;
}
if (node_b && !body_b) {
PhysicsServer3D::get_singleton()->joint_clear(joint);
warning = TTR("Node B must be a PhysicsBody3D"); warning = TTR("Node B must be a PhysicsBody3D");
update_configuration_warning(); } else if (!body_a && !body_b) {
return;
}
if (!body_a && !body_b) {
PhysicsServer3D::get_singleton()->joint_clear(joint);
warning = TTR("Joint is not connected to any PhysicsBody3Ds"); warning = TTR("Joint is not connected to any PhysicsBody3Ds");
update_configuration_warning(); } else if (body_a == body_b) {
return;
}
if (body_a == body_b) {
PhysicsServer3D::get_singleton()->joint_clear(joint);
warning = TTR("Node A and Node B must be different PhysicsBody3Ds"); warning = TTR("Node A and Node B must be different PhysicsBody3Ds");
update_configuration_warning(); } else {
return; warning = String();
} }
warning = String(); update_configuration_warnings();
update_configuration_warning();
if (!warning.is_empty()) {
PhysicsServer3D::get_singleton()->joint_clear(joint);
return;
}
configured = true; configured = true;
@ -206,17 +190,14 @@ bool Joint3D::get_exclude_nodes_from_collision() const {
return exclude_from_collision; return exclude_from_collision;
} }
String Joint3D::get_configuration_warning() const { TypedArray<String> Joint3D::get_configuration_warnings() const {
String node_warning = Node3D::get_configuration_warning(); TypedArray<String> warnings = Node3D::get_configuration_warnings();
if (!warning.is_empty()) { if (!warning.is_empty()) {
if (!node_warning.is_empty()) { warnings.push_back(warning);
node_warning += "\n\n";
}
node_warning += warning;
} }
return node_warning; return warnings;
} }
void Joint3D::_bind_methods() { void Joint3D::_bind_methods() {

View file

@ -63,7 +63,7 @@ protected:
_FORCE_INLINE_ bool is_configured() const { return configured; } _FORCE_INLINE_ bool is_configured() const { return configured; }
public: 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); void set_node_a(const NodePath &p_node_a);
NodePath get_node_a() const; NodePath get_node_a() const;

View file

@ -133,7 +133,7 @@ void RemoteTransform3D::set_remote_node(const NodePath &p_remote_node) {
_update_remote(); _update_remote();
} }
update_configuration_warning(); update_configuration_warnings();
} }
NodePath RemoteTransform3D::get_remote_node() const { NodePath RemoteTransform3D::get_remote_node() const {
@ -179,17 +179,14 @@ void RemoteTransform3D::force_update_cache() {
_update_cache(); _update_cache();
} }
String RemoteTransform3D::get_configuration_warning() const { TypedArray<String> RemoteTransform3D::get_configuration_warnings() const {
String warning = Node3D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) { if (!has_node(remote_node) || !Object::cast_to<Node3D>(get_node(remote_node))) {
if (!warning.is_empty()) { warnings.push_back(TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."));
warning += "\n\n";
}
warning += 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() { void RemoteTransform3D::_bind_methods() {

View file

@ -70,7 +70,7 @@ public:
void force_update_cache(); void force_update_cache();
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
RemoteTransform3D(); RemoteTransform3D();
}; };

View file

@ -249,7 +249,7 @@ void SoftBody3D::_softbody_changed() {
prepare_physics_server(); prepare_physics_server();
_reset_points_offsets(); _reset_points_offsets();
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
update_configuration_warning(); update_configuration_warnings();
#endif #endif
} }
@ -301,7 +301,7 @@ void SoftBody3D::_notification(int p_what) {
if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
if (Engine::get_singleton()->is_editor_hint()) { 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"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable");
} }
String SoftBody3D::get_configuration_warning() const { TypedArray<String> SoftBody3D::get_configuration_warnings() const {
String warning = MeshInstance3D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (get_mesh().is_null()) { if (get_mesh().is_null()) {
if (!warning.is_empty()) { warnings.push_back(TTR("This body will be ignored until you set a mesh."));
warning += "\n\n";
}
warning += TTR("This body will be ignored until you set a mesh.");
} }
Transform t = get_transform(); 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 ((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()) { 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."));
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.");
} }
return warning; return warnings;
} }
void SoftBody3D::_update_physics_server() { void SoftBody3D::_update_physics_server() {

View file

@ -113,7 +113,7 @@ protected:
void _notification(int p_what); void _notification(int p_what);
static void _bind_methods(); static void _bind_methods();
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
protected: protected:
void _update_physics_server(); void _update_physics_server();

View file

@ -928,7 +928,7 @@ void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
notify_property_list_changed(); notify_property_list_changed();
_reset_timeout(); _reset_timeout();
_queue_update(); _queue_update();
update_configuration_warning(); update_configuration_warnings();
} }
Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const { Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const {
@ -1058,17 +1058,14 @@ StringName AnimatedSprite3D::get_animation() const {
return animation; return animation;
} }
String AnimatedSprite3D::get_configuration_warning() const { TypedArray<String> AnimatedSprite3D::get_configuration_warnings() const {
String warning = SpriteBase3D::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (frames.is_null()) { if (frames.is_null()) {
if (!warning.is_empty()) { warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."));
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 warning; return warnings;
} }
void AnimatedSprite3D::_bind_methods() { void AnimatedSprite3D::_bind_methods() {

View file

@ -236,7 +236,7 @@ public:
virtual Rect2 get_item_rect() const override; virtual Rect2 get_item_rect() const override;
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
AnimatedSprite3D(); AnimatedSprite3D();
}; };

View file

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

View file

@ -145,7 +145,7 @@ public:
void set_steering(real_t p_steering); void set_steering(real_t p_steering);
real_t get_steering() const; real_t get_steering() const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
VehicleWheel3D(); VehicleWheel3D();
}; };

View file

@ -65,7 +65,7 @@ void WorldEnvironment::_update_current_environment() {
} else { } else {
get_viewport()->find_world_3d()->set_environment(Ref<Environment>()); 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() { 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_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) { 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()) { if (is_inside_tree()) {
_update_current_environment(); _update_current_environment();
} else { } 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()) { if (is_inside_tree()) {
_update_current_camera_effects(); _update_current_camera_effects();
} else { } else {
update_configuration_warning(); update_configuration_warnings();
} }
} }
@ -129,35 +129,26 @@ Ref<CameraEffects> WorldEnvironment::get_camera_effects() const {
return camera_effects; return camera_effects;
} }
String WorldEnvironment::get_configuration_warning() const { TypedArray<String> WorldEnvironment::get_configuration_warnings() const {
String warning = Node::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!environment.is_valid()) { if (!environment.is_valid()) {
if (!warning.is_empty()) { warnings.push_back(TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect."));
warning += "\n\n";
}
warning += TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect.");
} }
if (!is_inside_tree()) { if (!is_inside_tree()) {
return warning; return warnings;
} }
if (environment.is_valid() && get_viewport()->find_world_3d()->get_environment() != environment) { if (environment.is_valid() && get_viewport()->find_world_3d()->get_environment() != environment) {
if (!warning.is_empty()) { warnings.push_back(("Only the first Environment has an effect in a scene (or set of instantiated scenes)."));
warning += "\n\n";
}
warning += TTR("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 (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) {
if (!warning.is_empty()) { warnings.push_back(TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."));
warning += "\n\n";
}
warning += TTR("Only the first CameraEffects has an effect in a scene (or set of instantiated scenes).");
} }
return warning; return warnings;
} }
void WorldEnvironment::_bind_methods() { void WorldEnvironment::_bind_methods() {

View file

@ -55,7 +55,7 @@ public:
void set_camera_effects(const Ref<CameraEffects> &p_camera_effects); void set_camera_effects(const Ref<CameraEffects> &p_camera_effects);
Ref<CameraEffects> get_camera_effects() const; Ref<CameraEffects> get_camera_effects() const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
WorldEnvironment(); WorldEnvironment();
}; };

View file

@ -55,23 +55,18 @@ void XRCamera3D::_notification(int p_what) {
}; };
}; };
String XRCamera3D::get_configuration_warning() const { TypedArray<String> XRCamera3D::get_configuration_warnings() const {
if (!is_visible() || !is_inside_tree()) { TypedArray<String> warnings = Node::get_configuration_warnings();
return String();
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(); return 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";
}
warning += TTR("XRCamera3D must have an XROrigin3D node as its parent.");
};
return warning;
}; };
Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const { 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. // 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. // Note that setting this to 0 means this node is not bound to a controller yet.
controller_id = p_controller_id; controller_id = p_controller_id;
update_configuration_warning(); update_configuration_warnings();
}; };
int XRController3D::get_controller_id() const { int XRController3D::get_controller_id() const {
@ -362,30 +357,22 @@ XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const {
return tracker->get_tracker_hand(); return tracker->get_tracker_hand();
}; };
String XRController3D::get_configuration_warning() const { TypedArray<String> XRController3D::get_configuration_warnings() const {
if (!is_visible() || !is_inside_tree()) { TypedArray<String> warnings = Node::get_configuration_warnings();
return String();
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."));
}
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."));
}
} }
String warning = Node3D::get_configuration_warning(); return 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";
}
warning += TTR("XRController3D must have an XROrigin3D node as its parent.");
};
if (controller_id == 0) {
if (!warning.is_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 warning;
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -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. // 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. // Note that setting this to 0 means this node is not bound to an anchor yet.
anchor_id = p_anchor_id; anchor_id = p_anchor_id;
update_configuration_warning(); update_configuration_warnings();
}; };
int XRAnchor3D::get_anchor_id() const { int XRAnchor3D::get_anchor_id() const {
@ -487,30 +474,22 @@ bool XRAnchor3D::get_is_active() const {
return is_active; return is_active;
}; };
String XRAnchor3D::get_configuration_warning() const { TypedArray<String> XRAnchor3D::get_configuration_warnings() const {
if (!is_visible() || !is_inside_tree()) { TypedArray<String> warnings = Node::get_configuration_warnings();
return String();
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."));
}
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."));
}
} }
String warning = Node3D::get_configuration_warning(); return 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";
}
warning += TTR("XRAnchor3D must have an XROrigin3D node as its parent.");
};
if (anchor_id == 0) {
if (!warning.is_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 warning;
}; };
Plane XRAnchor3D::get_plane() const { Plane XRAnchor3D::get_plane() const {
@ -528,21 +507,16 @@ Ref<Mesh> XRAnchor3D::get_mesh() const {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
String XROrigin3D::get_configuration_warning() const { TypedArray<String> XROrigin3D::get_configuration_warnings() const {
if (!is_visible() || !is_inside_tree()) { TypedArray<String> warnings = Node::get_configuration_warnings();
return String();
}
String warning = Node3D::get_configuration_warning(); if (is_visible() && is_inside_tree()) {
if (tracked_camera == nullptr) {
if (tracked_camera == nullptr) { warnings.push_back(TTR("XROrigin3D requires an XRCamera3D child node."));
if (!warning.is_empty()) {
warning += "\n\n";
} }
warning += TTR("XROrigin3D requires an XRCamera3D child node.");
} }
return warning; return warnings;
}; };
void XROrigin3D::_bind_methods() { void XROrigin3D::_bind_methods() {

View file

@ -50,7 +50,7 @@ protected:
void _notification(int p_what); void _notification(int p_what);
public: 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 Vector3 project_local_ray_normal(const Point2 &p_pos) const override;
virtual Point2 unproject_position(const Vector3 &p_pos) const override; virtual Point2 unproject_position(const Vector3 &p_pos) const override;
@ -97,7 +97,7 @@ public:
Ref<Mesh> get_mesh() const; Ref<Mesh> get_mesh() const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
XRController3D() {} XRController3D() {}
~XRController3D() {} ~XRController3D() {}
@ -133,7 +133,7 @@ public:
Ref<Mesh> get_mesh() const; Ref<Mesh> get_mesh() const;
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
XRAnchor3D() {} XRAnchor3D() {}
~XRAnchor3D() {} ~XRAnchor3D() {}
@ -158,7 +158,7 @@ protected:
static void _bind_methods(); static void _bind_methods();
public: public:
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
void set_tracked_camera(XRCamera3D *p_tracked_camera); void set_tracked_camera(XRCamera3D *p_tracked_camera);
void clear_tracked_camera_if(XRCamera3D *p_tracked_camera); void clear_tracked_camera_if(XRCamera3D *p_tracked_camera);

View file

@ -458,7 +458,7 @@ void AnimationTree::set_tree_root(const Ref<AnimationNode> &p_root) {
properties_dirty = true; properties_dirty = true;
update_configuration_warning(); update_configuration_warnings();
} }
Ref<AnimationNode> AnimationTree::get_tree_root() const { 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) { void AnimationTree::set_animation_player(const NodePath &p_player) {
animation_player = p_player; animation_player = p_player;
update_configuration_warning(); update_configuration_warnings();
} }
NodePath AnimationTree::get_animation_player() const { NodePath AnimationTree::get_animation_player() const {
@ -1281,38 +1281,26 @@ uint64_t AnimationTree::get_last_process_pass() const {
return process_pass; return process_pass;
} }
String AnimationTree::get_configuration_warning() const { TypedArray<String> AnimationTree::get_configuration_warnings() const {
String warning = Node::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!root.is_valid()) { if (!root.is_valid()) {
if (!warning.is_empty()) { warnings.push_back(TTR("No root AnimationNode for the graph is set."));
warning += "\n\n";
}
warning += TTR("No root AnimationNode for the graph is set.");
} }
if (!has_node(animation_player)) { if (!has_node(animation_player)) {
if (!warning.is_empty()) { warnings.push_back(TTR("Path to an AnimationPlayer node containing animations is not set."));
warning += "\n\n";
}
warning += TTR("Path to an AnimationPlayer node containing animations is not set.");
} else { } else {
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player)); AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player));
if (!player) { if (!player) {
if (!warning.is_empty()) { warnings.push_back(TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node."));
warning += "\n\n";
}
warning += TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node.");
} else if (!player->has_node(player->get_root())) { } else if (!player->has_node(player->get_root())) {
if (!warning.is_empty()) { warnings.push_back(TTR("The AnimationPlayer root node is not a valid node."));
warning += "\n\n";
}
warning += TTR("The AnimationPlayer root node is not a valid node.");
} }
} }
return warning; return warnings;
} }
void AnimationTree::set_root_motion_track(const NodePath &p_track) { void AnimationTree::set_root_motion_track(const NodePath &p_track) {

View file

@ -300,7 +300,7 @@ public:
void set_animation_player(const NodePath &p_player); void set_animation_player(const NodePath &p_player);
NodePath get_animation_player() const; NodePath get_animation_player() const;
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
bool is_state_invalid() const; bool is_state_invalid() const;
String get_invalid_state_reason() const; String get_invalid_state_reason() const;

View file

@ -159,16 +159,14 @@ void Container::_notification(int p_what) {
} }
} }
String Container::get_configuration_warning() const { TypedArray<String> Container::get_configuration_warnings() const {
String warning = Control::get_configuration_warning(); TypedArray<String> warnings = Control::get_configuration_warnings();
if (get_class() == "Container" && get_script().is_null()) { if (get_class() == "Container" && get_script().is_null()) {
if (!warning.is_empty()) { 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."));
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.");
} }
return warning;
return warnings;
} }
void Container::_bind_methods() { void Container::_bind_methods() {

View file

@ -56,7 +56,7 @@ public:
void fit_child_in_rect(Control *p_child, const Rect2 &p_rect); 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(); Container();
}; };

View file

@ -2183,7 +2183,7 @@ Ref<Theme> Control::get_theme() const {
void Control::set_tooltip(const String &p_tooltip) { void Control::set_tooltip(const String &p_tooltip) {
data.tooltip = p_tooltip; data.tooltip = p_tooltip;
update_configuration_warning(); update_configuration_warnings();
} }
String Control::get_tooltip(const Point2 &p_pos) const { 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) { void Control::set_mouse_filter(MouseFilter p_filter) {
ERR_FAIL_INDEX(p_filter, 3); ERR_FAIL_INDEX(p_filter, 3);
data.mouse_filter = p_filter; data.mouse_filter = p_filter;
update_configuration_warning(); update_configuration_warnings();
} }
Control::MouseFilter Control::get_mouse_filter() const { 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 { TypedArray<String> Control::get_configuration_warnings() const {
String warning = CanvasItem::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (data.mouse_filter == MOUSE_FILTER_IGNORE && data.tooltip != "") { if (data.mouse_filter == MOUSE_FILTER_IGNORE && data.tooltip != "") {
if (!warning.is_empty()) { 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\"."));
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\".");
} }
return warning; return warnings;
} }
void Control::set_clip_contents(bool p_clip) { void Control::set_clip_contents(bool p_clip) {

View file

@ -524,7 +524,7 @@ public:
bool is_visibility_clip_disabled() const; 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 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() {} Control() {}
}; };

View file

@ -30,17 +30,14 @@
#include "range.h" #include "range.h"
String Range::get_configuration_warning() const { TypedArray<String> Range::get_configuration_warnings() const {
String warning = Control::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (shared->exp_ratio && shared->min <= 0) { if (shared->exp_ratio && shared->min <= 0) {
if (!warning.is_empty()) { warnings.push_back(TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."));
warning += "\n\n";
}
warning += TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0.");
} }
return warning; return warnings;
} }
void Range::_value_changed_notify() { void Range::_value_changed_notify() {
@ -106,7 +103,7 @@ void Range::set_min(double p_min) {
shared->emit_changed("min"); shared->emit_changed("min");
update_configuration_warning(); update_configuration_warnings();
} }
void Range::set_max(double p_max) { 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); double v = Math::log(value) / Math::log((double)2);
return CLAMP((v - exp_min) / (exp_max - exp_min), 0, 1); return CLAMP((v - exp_min) / (exp_max - exp_min), 0, 1);
} else { } else {
float value = CLAMP(get_value(), shared->min, shared->max); float value = CLAMP(get_value(), shared->min, shared->max);
return CLAMP((value - get_min()) / (get_max() - get_min()), 0, 1); 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) { void Range::set_exp_ratio(bool p_enable) {
shared->exp_ratio = p_enable; shared->exp_ratio = p_enable;
update_configuration_warning(); update_configuration_warnings();
} }
bool Range::is_ratio_exp() const { bool Range::is_ratio_exp() const {

View file

@ -97,7 +97,7 @@ public:
void share(Range *p_range); void share(Range *p_range);
void unshare(); void unshare();
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
Range(); Range();
~Range(); ~Range();

View file

@ -544,8 +544,8 @@ void ScrollContainer::set_follow_focus(bool p_follow) {
follow_focus = p_follow; follow_focus = p_follow;
} }
String ScrollContainer::get_configuration_warning() const { TypedArray<String> ScrollContainer::get_configuration_warnings() const {
String warning = Container::get_configuration_warning(); TypedArray<String> warnings = Container::get_configuration_warnings();
int found = 0; int found = 0;
@ -565,12 +565,10 @@ String ScrollContainer::get_configuration_warning() const {
} }
if (found != 1) { if (found != 1) {
if (!warning.is_empty()) { 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."));
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;
return warnings;
} }
HScrollBar *ScrollContainer::get_h_scrollbar() { HScrollBar *ScrollContainer::get_h_scrollbar() {

View file

@ -103,7 +103,7 @@ public:
virtual bool clips_input() const override; virtual bool clips_input() const override;
virtual String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
ScrollContainer(); ScrollContainer();
}; };

View file

@ -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() && 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")) { get_script_instance()->get_script()->is_tool() && get_script_instance()->has_method("_get_configuration_warnings")) {
return get_script_instance()->call("_get_configuration_warning"); 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 #ifdef TOOLS_ENABLED
if (!is_inside_tree()) { if (!is_inside_tree()) {
return; 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", "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("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_ENTER_TREE);
BIND_CONSTANT(NOTIFICATION_EXIT_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("_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_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("_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() { String Node::_get_name_num_separator() {

View file

@ -412,9 +412,10 @@ public:
_FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; } _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); void set_display_folded(bool p_folded);
bool is_displayed_folded() const; bool is_displayed_folded() const;

View file

@ -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 { TypedArray<String> ShaderGlobalsOverride::get_configuration_warnings() const {
String warning = Node::get_configuration_warning(); TypedArray<String> warnings = Node::get_configuration_warnings();
if (!active) { if (!active) {
if (!warning.is_empty()) { warnings.push_back(TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene."));
warning += "\n\n";
}
warning += TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene.");
} }
return warning; return warnings;
} }
void ShaderGlobalsOverride::_bind_methods() { void ShaderGlobalsOverride::_bind_methods() {

View file

@ -58,7 +58,7 @@ protected:
static void _bind_methods(); static void _bind_methods();
public: public:
String get_configuration_warning() const override; TypedArray<String> get_configuration_warnings() const override;
ShaderGlobalsOverride(); ShaderGlobalsOverride();
}; };

View file

@ -3175,20 +3175,17 @@ Variant Viewport::gui_get_drag_data() const {
return gui.drag_data; 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) { /*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."); 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 (size.x == 0 || size.y == 0) {
if (!warning.is_empty()) { warnings.push_back(TTR("Viewport size must be greater than 0 to render anything."));
warning += "\n\n";
}
warning += TTR("Viewport size must be greater than 0 to render anything.");
} }
return warning; return warnings;
} }
void Viewport::gui_reset_canvas_sort_index() { void Viewport::gui_reset_canvas_sort_index() {

View file

@ -580,7 +580,7 @@ public:
void gui_reset_canvas_sort_index(); void gui_reset_canvas_sort_index();
int gui_get_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); void set_debug_draw(DebugDraw p_debug_draw);
DebugDraw get_debug_draw() const; DebugDraw get_debug_draw() const;