|
@@ -915,14 +915,43 @@ GDScript::GDScript() :
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
+void GDScript::_save_orphaned_subclasses() {
|
|
|
+ struct ClassRefWithName {
|
|
|
+ ObjectID id;
|
|
|
+ String fully_qualified_name;
|
|
|
+ };
|
|
|
+ Vector<ClassRefWithName> weak_subclasses;
|
|
|
+ // collect subclasses ObjectID and name
|
|
|
+ for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
|
|
|
+ E->get()->_owner = NULL; //bye, you are no longer owned cause I died
|
|
|
+ ClassRefWithName subclass;
|
|
|
+ subclass.id = E->get()->get_instance_id();
|
|
|
+ subclass.fully_qualified_name = E->get()->fully_qualified_name;
|
|
|
+ weak_subclasses.push_back(subclass);
|
|
|
+ }
|
|
|
+
|
|
|
+ // clear subclasses to allow unused subclasses to be deleted
|
|
|
+ subclasses.clear();
|
|
|
+ // subclasses are also held by constants, clear those as well
|
|
|
+ constants.clear();
|
|
|
+
|
|
|
+ // keep orphan subclass only for subclasses that are still in use
|
|
|
+ for (int i = 0; i < weak_subclasses.size(); i++) {
|
|
|
+ ClassRefWithName subclass = weak_subclasses[i];
|
|
|
+ Object *obj = ObjectDB::get_instance(subclass.id);
|
|
|
+ if (!obj)
|
|
|
+ continue;
|
|
|
+ // subclass is not released
|
|
|
+ GDScriptLanguage::get_singleton()->add_orphan_subclass(subclass.fully_qualified_name, subclass.id);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
GDScript::~GDScript() {
|
|
|
for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
|
|
|
memdelete(E->get());
|
|
|
}
|
|
|
|
|
|
- for (Map<StringName, Ref<GDScript> >::Element *E = subclasses.front(); E; E = E->next()) {
|
|
|
- E->get()->_owner = NULL; //bye, you are no longer owned cause I died
|
|
|
- }
|
|
|
+ _save_orphaned_subclasses();
|
|
|
|
|
|
#ifdef DEBUG_ENABLED
|
|
|
if (GDScriptLanguage::get_singleton()->lock) {
|
|
@@ -2176,6 +2205,22 @@ GDScriptLanguage::~GDScriptLanguage() {
|
|
|
singleton = NULL;
|
|
|
}
|
|
|
|
|
|
+void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass) {
|
|
|
+ orphan_subclasses[p_qualified_name] = p_subclass;
|
|
|
+}
|
|
|
+
|
|
|
+Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) {
|
|
|
+ Map<String, ObjectID>::Element *orphan_subclass_element = orphan_subclasses.find(p_qualified_name);
|
|
|
+ if (!orphan_subclass_element)
|
|
|
+ return Ref<GDScript>();
|
|
|
+ ObjectID orphan_subclass = orphan_subclass_element->get();
|
|
|
+ Object *obj = ObjectDB::get_instance(orphan_subclass);
|
|
|
+ orphan_subclasses.erase(orphan_subclass_element);
|
|
|
+ if (!obj)
|
|
|
+ return Ref<GDScript>();
|
|
|
+ return Ref<GDScript>(Object::cast_to<GDScript>(obj));
|
|
|
+}
|
|
|
+
|
|
|
/*************** RESOURCE ***************/
|
|
|
|
|
|
RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
|