Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 48 additions & 3 deletions modules/gdscript/gdscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
7 changes: 7 additions & 0 deletions modules/gdscript/gdscript.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ class GDScript : public Script {

bool _update_exports();

void _save_orphaned_subclasses();

protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
bool _set(const StringName &p_name, const Variant &p_value);
Expand Down Expand Up @@ -355,6 +357,8 @@ class GDScriptLanguage : public ScriptLanguage {
bool profiling;
uint64_t script_frame_time;

Map<String, ObjectID> orphan_subclasses;

public:
int calls;

Expand Down Expand Up @@ -506,6 +510,9 @@ class GDScriptLanguage : public ScriptLanguage {
virtual bool handles_global_class_type(const String &p_type) const;
virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL, String *r_icon_path = NULL) const;

void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass);
Ref<GDScript> get_orphan_subclass(const String &p_qualified_name);

GDScriptLanguage();
~GDScriptLanguage();
};
Expand Down
10 changes: 8 additions & 2 deletions modules/gdscript/gdscript_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2123,15 +2123,21 @@ void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::C
StringName name = p_class->subclasses[i]->name;

Ref<GDScript> subclass;
String fully_qualified_name = p_script->fully_qualified_name + "::" + name;

if (old_subclasses.has(name)) {
subclass = old_subclasses[name];
} else {
subclass.instance();
Ref<GDScript> orphan_subclass = GDScriptLanguage::get_singleton()->get_orphan_subclass(fully_qualified_name);
if (orphan_subclass.is_valid()) {
subclass = orphan_subclass;
} else {
subclass.instance();
}
}

subclass->_owner = p_script;
subclass->fully_qualified_name = p_script->fully_qualified_name + "::" + name;
subclass->fully_qualified_name = fully_qualified_name;
p_script->subclasses.insert(name, subclass);

_make_scripts(subclass.ptr(), p_class->subclasses[i], false);
Expand Down