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

Plugin fails to load textures because they get imported too late #17483

Closed
Zylann opened this issue Mar 13, 2018 · 8 comments
Closed

Plugin fails to load textures because they get imported too late #17483

Zylann opened this issue Mar 13, 2018 · 8 comments

Comments

@Zylann
Copy link
Contributor

Zylann commented Mar 13, 2018

Godot 3.0.2

I made a plugin which has SVG icons and some textures, but I noticed if I clone the repo and then open it in an empty project, it opens but all plugin's textures fail to load because Godot has not imported them yet.
This happens when you open a project with an enabled plugin inside, but before the first import happened (typically cloning a repo or maybe even installing the plugin).

@vnen
Copy link
Member

vnen commented Mar 15, 2018

I've seen this too. I'm not sure how to solve though. Should the editor only enable the plugins after everything was imported?

@FeralBytes
Copy link
Contributor

@vnen what has been tried?
A very harsh fix would be to trigger an editor restart after a add-on is imported. It's harsh but would fix the problem.

@Zylann
Copy link
Contributor Author

Zylann commented Jan 1, 2019

@FeralBytes when an addon is installed from asset lib, resource import can be triggered before enabling the plugin, so no need to restart Godot.
But, in the case where you literally copy the addon inside the project (because it's the first start, or because you switched Git branch), Godot may turn the plugin on before its resources got imported.
One problem is that plugins can register resource importers, which means if the plugin needs to load resources on startup which it would have imported, we end up in a chicken-and-egg problem, but I wonder if this ever happened in practice.

@ghost
Copy link

ghost commented Jan 15, 2020

A work around that seems to work for me is during the plugin startup yield for 3 frames and then use load() on the SVGs during the plugin startup. Have to take care though if it exits somehow during one of these frames.

@follower
Copy link
Contributor

Context

I encountered this issue while attempting to help someone get an Android plugin working: https://old.reddit.com/r/godot/comments/f4uhpk/i_get_stuck_with_android_plugin/

It took a lot of time to track down what was causing the issue. (And it was unrelated to the Android-specific issue that also existed.)

Workarounds

After further research I think the simplest workaround is to change all image-related uses of load()/preload() to ResourceLoader.load() (with full paths).

At least in the case of add_custom_type(), using ResourceLoader.load() (which returns a null object on failure to load) results in the plugin still loading/initializing/running (when no .import directory exists) even though the custom resource icon is missing (and a default icon is displayed instead).

There are still a number of red engine error messages output in the console but there's no error dialog popup and the functionality still works.

Here's a patch to a plugin that implements this change: funabab/godot-camera-plugin-demo@313f626

(In addition, in the above patch I'm removing a more complex workaround which used Image.load() & ImageTexture.create_from_image() which results in icons always loading correctly but also generates a yellow warning about accessing an image as a resource. I think the warning might be possible to be avoided by putting the image in a directory excluded with .gdignore but by that stage I'd shaved so many yaks that I stopped before testing that.)

Underlying causes & impact

My impression is that the implications of the background resource import functionality may not have been fully considered when the editor plugin functionality was added. Which is understandable given that the issue primarily seems to appear once at start-up when a plugin is copied/"installed" directly from a source repository such as GitHub.

Unfortunately this edge case occurs immediately for people using someone else's plugin which isn't yet in the asset store & creates a poor first impression of the plugin & is non-trivial to debug--and discover the underlying issue is with the engine.

So, while the issue can be worked around to some degree (and the ResourceLoader.load() approach could be documented e.g. here, I think it is an issue that needs to be solved at the engine level--particularly for the icon use case.)

Potential fix approaches

Jumping back for a second, I wonder if background resource importing shouldn't be the default when no .import folder exists (which is the official Godot .gitignore policy) and/or when, say, preload() is called.

As mentioned in the preload() docs:

You can also preload resources. Unlike load, this function will read the file from disk and load it at compile-time.

So, I think it could be considered reasonable for preload() and/or editor plugin loading to be forced to wait for any background resource importing to complete.

[To be continued: I have further thoughts/research around this issue but will make this do for now.]

@ghost
Copy link

ghost commented Jun 15, 2020

Maybe was related: #39313

@follower
Copy link
Contributor

I went down this rabbit hole again in #36417 (comment) but seeing as it relates to this issue I'll repeat the TLDR here...


TL;DR: Editor plugins shouldn't attempt to use the resource system during initialization despite documentation stating otherwise.

Suggested workarounds:

  • Delay resource loading in an editor plugin until it's known that "first reimport" has occurred. (It's currently unclear when exactly that is--but it's some point after a project scene has been opened.)

  • Avoid using the resource system at all and rely on direct loading of assets via e.g. ImageLoader from a plugin subdirectory protected by .gdignore. (Only works for purely editor-only plugins and maybe add_custom_type() icons.) [To be confirmed.]


There's a bunch more investigation/context in #36417 (comment) but thought I probably shouldn't copy the whole thing here. :)

@KoBeWi
Copy link
Member

KoBeWi commented Apr 25, 2024

Tested with this code in Godot 4.3:

@tool
extends EditorPlugin

func _enter_tree() -> void:
	print(preload("res://addons/ploogin/icon.svg"))

It spits errors, but the texture is then printed correctly. The plugins will retry loading after initial import if they fail on first load, so this is effectively resolved. The errors are not important if they don't break anything.

@KoBeWi KoBeWi closed this as completed Apr 25, 2024
@KoBeWi KoBeWi added this to the 4.2 milestone Apr 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants