Skip to content
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

Don't abort loading when ext_resource is missing #85159

Merged
merged 1 commit into from
Dec 11, 2023

Conversation

KoBeWi
Copy link
Member

@KoBeWi KoBeWi commented Nov 20, 2023

Fixes #85152
Bugsquad edit: Fixes #86154
Resource loaders have inconsistent error values in case of missing files. If a loader returns error that indicates missing file, it's safe to ignore it; the resource will be replaced by null when you Open Anyway.

There are more errors related to files, not sure if ignore them all (the premise is technically the same).

@KoBeWi KoBeWi added this to the 4.3 milestone Nov 20, 2023
@KoBeWi KoBeWi requested a review from a team as a code owner November 20, 2023 23:39
@RandomShaper
Copy link
Member

I think that Open anyway should set (and later unset) ResourceLoader::set_abort_on_missing_resources(). To me, that's already existing functionality to be able to load despite external resources missing. However, the branch when that's disabled, which calls ResourceLoader::notify_dependency_error() should maybe set err (the one that will be returned) to OK.

@KoBeWi
Copy link
Member Author

KoBeWi commented Nov 21, 2023

Changed to use set_abort_on_missing_resources(). The name feels backwards, unless I'm misunderstanding it.

@RandomShaper
Copy link
Member

RandomShaper commented Nov 21, 2023

Quoting current usages:

if (ResourceLoader::get_abort_on_missing_resources()) {
error = ERR_FILE_MISSING_DEPENDENCIES;
error_text = "[ext_resource] referenced non-existent resource at: " + path;
_printerr();
err = error;
} else {
ResourceLoader::notify_dependency_error(local_path, path, type);
}

if (ResourceLoader::get_abort_on_missing_resources()) {
error = ERR_FILE_CORRUPT;
error_text = "[ext_resource] referenced non-existent resource at: " + path;
_printerr();
return error;
} else {
ResourceLoader::notify_dependency_error(local_path, path, type);
}

if (!ResourceLoader::get_abort_on_missing_resources()) {
ResourceLoader::notify_dependency_error(local_path, external_resources[erindex].path, external_resources[erindex].type);
} else {
error = ERR_FILE_MISSING_DEPENDENCIES;
ERR_FAIL_V_MSG(error, "Can't load dependency: " + external_resources[erindex].path + ".");
}

if (!ResourceLoader::get_abort_on_missing_resources()) {
ResourceLoader::notify_dependency_error(local_path, path, external_resources[i].type);
} else {
error = ERR_FILE_MISSING_DEPENDENCIES;
ERR_FAIL_V_MSG(error, "Can't load dependency: " + path + ".");
}

So, abort on missing resources, if true, means reporting an error to the caller. If false, it means send the broken dep error and otherwise ignore.


Now, EditorNode::load_resource and EditorNode::load_scene already provide the ignore-broken-deps functionality (bool p_ignore_broken_deps). I'd say that it's the responsibility of those two functions to use ResourceLoader::set_abort_on_missing_resources() depending on the value of that parameter:

if (p_ignore_broken_deps) {
    ResourceLoader::set_abort_on_missing_resources(false);
}

// Load, etc.

if (!p_ignore_broken_deps && dependency_errors.has(p_resource)) {
    // Show dependency dialog. There will be dep errors, but we won't enter this branch.
}

if (p_ignore_broken_deps) {
    ResourceLoader::set_abort_on_missing_resources(true); // Restore.
}

What do you think?

@KoBeWi
Copy link
Member Author

KoBeWi commented Nov 21, 2023

Makes sense, changed.

@KoBeWi
Copy link
Member Author

KoBeWi commented Nov 22, 2023

Reverted to my original fix. The only call for set_abort_on_missing_resources() (not counting some web code) is this:

ResourceLoader::set_abort_on_missing_resources(false);

The the abort is already disabled in the editor, and according to your comments it is working as intended, so the problem is text format code not handling it properly. Also the new fix was breaking binary format, so it was bad anyway.

@RandomShaper
Copy link
Member

ResourceLoaderBinary will error with ERR_FILE_MISSING_DEPENDENCIES in case an external resource can't be loaded, regardless the reason. It may make sense that loading of text resources was more permissive because of certain specific needs in the editor. However, for consistency I'd still model that with some kind of global setting that both can obey. If abort-on-missing-resources is too limiting by being a boolean, could it maybe be a three-item enum, with a new value that would behave like the current false, only that it won't either abort nor report broken deps in cases like a missing file?

In any case, I'm willing to attempt to add such a refactor myself in another PR. If this PR is already enough to fix a known issue, I won't oppose to merging it and we can keep the discussion over actual code showing what I'm trying to tell.

PS: I've realized why abort-on-missing-resources looks reversed. It depends on what is aborted. The editor sets to false so the resource loader doesn't abort, but the editor itself will by showing the broken deps dialog instead of the scene.

@akien-mga akien-mga changed the title Don't abort loading when ext_resource is missing Don't abort loading when ext_resource is missing Dec 11, 2023
@akien-mga akien-mga merged commit ea15b4a into godotengine:master Dec 11, 2023
15 checks passed
@akien-mga
Copy link
Member

Thanks!

@KoBeWi KoBeWi deleted the 404_strikes_back branch December 12, 2023 02:22
@tlobig
Copy link
Contributor

tlobig commented Dec 22, 2023

fixes #86154

@neruthes
Copy link

neruthes commented Jan 20, 2024

I had a similar problem where no preload is involved. My guess is that strong-type variables are causing cyclic GDScript parsing. Consider some code like this:

# hive.gd
extends Node2D
class_name MyHive
var bee : MyBee = null
# bee.gd
extends Node2D
class_name MyBee
var hive : MyHive = null

After removing a type notation in the attached GDScript, my scene is working again.

I wish that this PR also fixes any problem that may arise in this hypothetical situation. I will report back if the problem persists in 4.3.

@KoBeWi
Copy link
Member Author

KoBeWi commented Jan 20, 2024

GDScript does support cyclic dependencies since 4.0. Also it shouldn't be affecting scenes...

@neruthes
Copy link

GDScript does support cyclic dependencies since 4.0. Also it shouldn't be affecting scenes...

That is a surprise to me. I will try making a minimal working example.

@KoBeWi
Copy link
Member Author

KoBeWi commented Jan 20, 2024

Though by cyclic dependencies I mean scripts only. Preloading other resources, especially scenes, in a cyclic way won't work and will make the scenes non-openable until you remove the preloads.

@neruthes
Copy link

neruthes commented Jan 20, 2024

Though by cyclic dependencies I mean scripts only. Preloading other resources, especially scenes, in a cyclic way won't work and will make the scenes non-openable until you remove the preloads.

Thanks for the clarification. I had another look into my scripts and figured out that a script contained a preload which I failed to notice.

I found the correct way to reproduce the problem and you may have a look.

In summary:

  • Hive.gd (class_name Hive) contains preload Bee.tscn (var bee2: Bee = preload("res://main/Bee.tscn").instantiate()).
  • Bee.tscn uses Bee.gd (class_name Bee).
  • Bee.gd has a varaible typed Hive (var master : Hive = null).
  • Boom! Cannot open Bee.tscn in editor, but running game with F5 is ok.

image

@KoBeWi
Copy link
Member Author

KoBeWi commented Jan 20, 2024

Thanks, there's already an existing issue about this bug, I attached your project there: #79545 (comment)

@neruthes
Copy link

Thanks, there's already an existing issue about this bug, I attached your project there: #79545 (comment)

Thank you. You have done great help in this PR.

@akien-mga akien-mga added the cherrypick:4.2 Considered for cherry-picking into a future 4.2.x release label Apr 6, 2024
@akien-mga
Copy link
Member

Cherry-picked for 4.2.2.

@akien-mga akien-mga removed the cherrypick:4.2 Considered for cherry-picking into a future 4.2.x release label Apr 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants