Object: Add usage hint to instantiate Object properties in editor
Fixes #36372 as Path2D/Path3D's `curve` property no longer uses a Curve instance as default value, but instead it gets a (unique) default Curve instance when created through the editor (CreateDialog). ClassDB gets a sanity check to ensure that we don't do the same mistake for other properties in the future, but instead use the dedicated property usage hint. Fixes #36372. Fixes #36650. Supersedes #36644 and #36656. Co-authored-by: Thakee Nathees <thakeenathees@gmail.com> Co-authored-by: simpuid <utkarsh.email@yahoo.com>
This commit is contained in:
parent
84abf5a979
commit
b3bc5aafc5
7 changed files with 54 additions and 30 deletions
|
@ -1386,7 +1386,23 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
|
|||
if (r_valid != nullptr) {
|
||||
*r_valid = true;
|
||||
}
|
||||
return default_values[p_class][p_property];
|
||||
|
||||
Variant var = default_values[p_class][p_property];
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
// Some properties may have an instantiated Object as default value,
|
||||
// (like Path2D's `curve` used to have), but that's not a good practice.
|
||||
// Instead, those properties should use PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT
|
||||
// to be auto-instantiated when created in the editor.
|
||||
if (var.get_type() == Variant::OBJECT) {
|
||||
Object *obj = var.get_validated_object();
|
||||
if (obj) {
|
||||
WARN_PRINT(vformat("Instantiated %s used as default value for %s's \"%s\" property.", obj->get_class(), p_class, p_property));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
RWLock *ClassDB::lock = nullptr;
|
||||
|
|
|
@ -124,6 +124,7 @@ enum PropertyUsageFlags {
|
|||
PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT = 1 << 24,
|
||||
PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 25, // Used in inspector to increment property when keyed in animation player
|
||||
PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 26, // when loading, the resource for this property can be set at the end of loading
|
||||
PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 27, // For Object properties, instantiate them when creating in editor.
|
||||
|
||||
PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK,
|
||||
PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED,
|
||||
|
|
|
@ -513,30 +513,45 @@ String CreateDialog::get_selected_type() {
|
|||
Object *CreateDialog::instance_selected() {
|
||||
TreeItem *selected = search_options->get_selected();
|
||||
|
||||
if (selected) {
|
||||
Variant md = selected->get_metadata(0);
|
||||
if (!selected) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
String custom;
|
||||
if (md.get_type() != Variant::NIL) {
|
||||
custom = md;
|
||||
}
|
||||
Variant md = selected->get_metadata(0);
|
||||
String custom;
|
||||
if (md.get_type() != Variant::NIL) {
|
||||
custom = md;
|
||||
}
|
||||
|
||||
if (custom != String()) {
|
||||
if (ScriptServer::is_global_class(custom)) {
|
||||
Object *obj = EditorNode::get_editor_data().script_class_instance(custom);
|
||||
Node *n = Object::cast_to<Node>(obj);
|
||||
if (n) {
|
||||
n->set_name(custom);
|
||||
}
|
||||
return obj;
|
||||
Object *obj = nullptr;
|
||||
|
||||
if (!custom.empty()) {
|
||||
if (ScriptServer::is_global_class(custom)) {
|
||||
obj = EditorNode::get_editor_data().script_class_instance(custom);
|
||||
Node *n = Object::cast_to<Node>(obj);
|
||||
if (n) {
|
||||
n->set_name(custom);
|
||||
}
|
||||
return EditorNode::get_editor_data().instance_custom_type(selected->get_text(0), custom);
|
||||
obj = n;
|
||||
} else {
|
||||
return ClassDB::instance(selected->get_text(0));
|
||||
obj = EditorNode::get_editor_data().instance_custom_type(selected->get_text(0), custom);
|
||||
}
|
||||
} else {
|
||||
obj = ClassDB::instance(selected->get_text(0));
|
||||
}
|
||||
|
||||
// Check if any Object-type property should be instantiated.
|
||||
List<PropertyInfo> pinfo;
|
||||
obj->get_property_list(&pinfo);
|
||||
|
||||
for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
|
||||
if (E->get().type == Variant::OBJECT && E->get().usage & PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT) {
|
||||
Object *prop = ClassDB::instance(E->get().class_name);
|
||||
obj->set(E->get().name, prop);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return obj;
|
||||
}
|
||||
|
||||
void CreateDialog::_item_selected() {
|
||||
|
|
|
@ -149,11 +149,7 @@ void Path2D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_curve", "curve"), &Path2D::set_curve);
|
||||
ClassDB::bind_method(D_METHOD("get_curve"), &Path2D::get_curve);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve2D"), "set_curve", "get_curve");
|
||||
}
|
||||
|
||||
Path2D::Path2D() {
|
||||
set_curve(Ref<Curve2D>(memnew(Curve2D))); //create one by default
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_curve", "get_curve");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
void set_curve(const Ref<Curve2D> &p_curve);
|
||||
Ref<Curve2D> get_curve() const;
|
||||
|
||||
Path2D();
|
||||
Path2D() {}
|
||||
};
|
||||
|
||||
class PathFollow2D : public Node2D {
|
||||
|
|
|
@ -77,15 +77,11 @@ void Path3D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_curve", "curve"), &Path3D::set_curve);
|
||||
ClassDB::bind_method(D_METHOD("get_curve"), &Path3D::get_curve);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), "set_curve", "get_curve");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT), "set_curve", "get_curve");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("curve_changed"));
|
||||
}
|
||||
|
||||
Path3D::Path3D() {
|
||||
set_curve(Ref<Curve3D>(memnew(Curve3D))); //create one by default
|
||||
}
|
||||
|
||||
//////////////
|
||||
|
||||
void PathFollow3D::_update_transform() {
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
void set_curve(const Ref<Curve3D> &p_curve);
|
||||
Ref<Curve3D> get_curve() const;
|
||||
|
||||
Path3D();
|
||||
Path3D() {}
|
||||
};
|
||||
|
||||
class PathFollow3D : public Node3D {
|
||||
|
|
Loading…
Reference in a new issue