-
-
Notifications
You must be signed in to change notification settings - Fork 21.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix cyclic reference base being loaded but not valid (which is ok) #69259
Fix cyclic reference base being loaded but not valid (which is ok) #69259
Conversation
@rune-scape I'm informally asking you to review my PR. |
if (base_root.is_valid()) { | ||
if (!base_root.is_null()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This changes nothing, before/after are equivalent.
godot/core/object/ref_counted.h
Lines 212 to 213 in 860884b
inline bool is_valid() const { return reference != nullptr; } | |
inline bool is_null() const { return reference == nullptr; } |
And I think
is_valid()
is preferred in here, that's kinda why this method exists (to avoid having negated is_null()
checks).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right for Ref<T>
instances, except for GDScript
.
godot/modules/gdscript/gdscript.h
Line 185 in 860884b
virtual bool is_valid() const override { return valid; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but thats defned in Script
, not Ref
godot/core/object/script_language.h
Line 144 in 860884b
virtual bool is_valid() const = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. My bad.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
base_root
is Ref<GDScript>
so:
base_root.is_valid()
callsRef::is_valid
,base_root->is_valid()
callsGDScript::is_valid
(or its override as it's virtual).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
base_root
isRef<GDScript>
so:* `base_root.is_valid()` calls `Ref::is_valid`, * `base_root->is_valid()` calls `GDScript::is_valid` (or its override as it's virtual).
I got mixed up. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't blame you its very confusing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow this is an API asking for bugs...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems to me like 2 of the changes wouldn't have any effect, im confused
base = Ref<GDScript>(base_root->find_class(base->fully_qualified_name)); | ||
} | ||
if (base.is_null()) { | ||
_set_error(vformat(R"(Could not find class "%s" in "%s".)", base->fully_qualified_name, base->path), nullptr); | ||
return ERR_COMPILATION_FAILED; | ||
} | ||
ERR_FAIL_COND_V(!base->is_valid(), ERR_BUG); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this shouldn't be removed, if the base isn't valid here, theres something wrong elsewhere,
either get_full_script()
should have given an error, or the inner class is not valid for some reason
the code i replaced didn't allow this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the case of the MRP of #69213, base
is reloading. While reloading, the script valid
value is set to false, as shown:
godot/modules/gdscript/gdscript.cpp
Lines 850 to 860 in 860884b
MutexLock lock(GDScriptCache::singleton->mutex); | |
GDScriptCache::singleton->shallow_gdscript_cache[source_path] = Ref<GDScript>(this); | |
} | |
} | |
valid = false; | |
GDScriptParser parser; | |
Error err = parser.parse(source, path, false); | |
if (err) { | |
if (EngineDebugger::is_active()) { | |
GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message); |
So, as replied to @kleonc, in gdscript.h
, GDScript::is_valid()
returns a different value than being the inverse of GDScript::is_null()
. An invalid script just means that it's reloading. We could change the behaviour, but checking if the script is valid, at this stage, just creates bug, it doesn't prevent ones.
godot/modules/gdscript/gdscript.h
Line 185 in 860884b
virtual bool is_valid() const override { return valid; } |
Maybe we could add a check to is_valid()
that it must be GDScript::reloading == true
too. Otherwise, it's a bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put back the error with the added && !base->reloading
condition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that sounds good to me 👍
a6c152e
to
4e60689
Compare
Thanks! |
I compiled from source to test this and i am receiving new errors. Please let me know if i should create a new issue for this, or if i should wait and test the release of Beta 7? When i try to run my project it complains that it cannot find a property in my inherited class that resides in a base class and shows the error below.
If i comment that out it will then crash when trying to run showing this:
|
|
@adamscott The bug they're reporting is still valid and related to GDScript. #69295 just clarifies that the stacktrace is useless, it doesn't invalidate the fact that it's crashing :) |
Fyi, i am still getting this issue ##69259 (comment) When starting the game it will show
Removing the property will cause the game to crash (not load). Beta 5 does not cause any errors and the project runs as expected. |
Oh, sorry, I completely forgot that issue. Fell out of the radar. |
No problem. Thanks! |
Unfortunately i have the same issue when compiling from your repository and the current master branch.
If i leave the offending property commented then try reload Godot, my project will not even load the editor. So i need to either reload in Beta 5 and uncomment the property, or modify the text file for it to load up in the current builds. If there is any way i can actually try and help debug this i am all ears, i dont feel i am being much help atm. Although unfortunately i am back on 12 hour night shifts for the next few days so i will be pretty busy. I have tried to reproduce the issue in a fresh project but have not managed to so far. |
@adamscott I should probably also note i had a circular dependency issue on the base class in Beta 5. I tried to re-add the type for this in Beta 6 and it still caused issues. When i removed the type, nothing changed as if it had been cached but did not clear, so it still assumed it was of that type, which was still causing issues. I have no idea if that's related or another issue altogether but before that it didnt complain about the property in the other class, but about the class itself. Only after i changed the type of a property in the base class to cause a circular dependency bug it complained about the other property. Hopefully i am making sense. Edit* Ok, if i change the type of this it will throw a different error every time. If i clear the errors by removing/commenting the problems, the game will crash on load like before. It also shows this error in the console
Edit2* Ok, playing around with this, i tried to remove the offending property on the base class. But now my project wont load again in Beta 7 no matter what i do and when loading in Beta 5 half my scripts are empty, even though they are showing ok in an external editor. So it seems i have managed to completely break it and have no idea how to get it load correctly now or even show my scripts. Ok last edit - i hope* I have managed to get it loading in Beta 5 again all ok. The only way i can get the project to even load in Beta 7 is by deleting everything in the imported folder. Then i am back to where i first started where it shows the following error
If i follow this back through the chain to the supposedly problem class and there are no errors. If i close the project and try re-open it in Beta 7 again then it will not open unless i delete the imported folder again. |
@produno If you could create a minimal reproduction project, it would be ideal. I don't know how to reproduce, unfortunately. |
In some cases, a script from
GDScriptCache::get_full_script()
can be not null, but invalid. In the context of cyclic references and while populating class members (GDScriptCompiler::_populate_class_members()
), the test was too strict and was issuing an error even if the script itself is usable.This was breaking seemingly valid code that was working in previous betas.
Making the tests more lax seems to be the right thing to do.
Fixes #69213