diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index bf1bd0de93ad..43ebbddc606e 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -1091,6 +1091,14 @@ void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinf OBJTYPE_WLOCK type->property_list.push_back(p_pinfo); + if (p_pinfo.type == Variant::OBJECT) { + type->resource_properties.push_back(p_pinfo.name); + } else if (p_pinfo.type == Variant::ARRAY) { + type->array_properties.push_back(p_pinfo.name); + } else if (p_pinfo.type == Variant::DICTIONARY) { + type->dict_properties.push_back(p_pinfo.name); + } + type->property_map[p_pinfo.name] = p_pinfo; #ifdef DEBUG_METHODS_ENABLED if (mb_get) { @@ -1852,4 +1860,45 @@ void ClassDB::cleanup() { native_structs.clear(); } -// +void ClassDB::tag_collect_pass(Object *p_object, uint32_t p_pass, bool p_containers) { + ClassInfo *check = classes.getptr(p_object->get_class_name()); + while (check) { + for (uint32_t i = 0; i < check->resource_properties.size(); i++) { + Ref res = p_object->get(check->resource_properties[i]); + if (res.is_valid()) { + res->tag_collect_pass(p_pass, p_containers); + } + } + if (p_containers) { + for (uint32_t i = 0; i < check->dict_properties.size(); i++) { + Dictionary dict = p_object->get(check->dict_properties[i]); + dict.tag_collect_pass(p_pass, p_containers); + } + + for (uint32_t i = 0; i < check->array_properties.size(); i++) { + Array arr = p_object->get(check->array_properties[i]); + arr.tag_collect_pass(p_pass, p_containers); + } + } + check = check->inherits_ptr; + } +} + +void ClassDB::unlink_resources(Object *p_object, bool p_containers) { + ClassInfo *check = classes.getptr(p_object->get_class_name()); + while (check) { + for (uint32_t i = 0; i < check->resource_properties.size(); i++) { + p_object->set(check->resource_properties[i], Ref()); + } + if (p_containers) { + for (uint32_t i = 0; i < check->dict_properties.size(); i++) { + p_object->set(check->dict_properties[i], Dictionary()); + } + + for (uint32_t i = 0; i < check->array_properties.size(); i++) { + p_object->set(check->array_properties[i], Array()); + } + } + check = check->inherits_ptr; + } +} diff --git a/core/object/class_db.h b/core/object/class_db.h index 7a4ee1afa451..15ca37e035c5 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -116,6 +116,12 @@ class ClassDB { HashMap signal_map; List property_list; HashMap property_map; + + // For tagging + LocalVector resource_properties; + LocalVector array_properties; + LocalVector dict_properties; + #ifdef DEBUG_METHODS_ENABLED List constant_order; List method_order; @@ -450,6 +456,9 @@ class ClassDB { static void get_native_struct_list(List *r_names); static String get_native_struct_code(const StringName &p_name); static uint64_t get_native_struct_size(const StringName &p_name); // Used for asserting + + static void tag_collect_pass(Object *object, uint32_t p_pass, bool p_containers); + static void unlink_resources(Object *p_object, bool p_containers); }; #define BIND_ENUM_CONSTANT(m_constant) \ diff --git a/core/object/object.cpp b/core/object/object.cpp index 05a6ac6cee89..a83e7c42310f 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -857,20 +857,25 @@ void Object::notification(int p_notification, bool p_reversed) { } String Object::to_string() { + String id = itos(get_instance_id()); if (script_instance) { bool valid; String ret = script_instance->to_string(&valid); if (valid) { return ret; } + if (script_instance->get_script().is_valid()) { + id = script_instance->get_script()->get_script_name(); + } } + if (_extension && _extension->to_string) { String ret; GDExtensionBool is_valid; _extension->to_string(_extension_instance, &is_valid, &ret); return ret; } - return "<" + get_class() + "#" + itos(get_instance_id()) + ">"; + return "<" + get_class() + "#" + id + ">"; } void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) { @@ -2068,6 +2073,34 @@ void ObjectDB::debug_objects(DebugFunc p_func) { spin_lock.unlock(); } +void Object::tag_collect_pass(uint32_t p_pass, bool p_collect_containers) { + if (collect_pass == p_pass) { + return; // Already collected. + } + + collect_pass = p_pass; // Mark beforehand due to recursion. + + if (script_instance) { + script_instance->tag_collect_pass(p_pass, p_collect_containers); + Ref