openfl / lime

A foundational Haxe framework for cross-platform development
https://lime.openfl.org/
MIT License
754 stars 370 forks source link

Error when getting an asset from an AssetLibrary loaded at runtime in HTML5 #1718

Closed mrcdk closed 11 months ago

mrcdk commented 11 months ago

Hi, I'm working on an project which has multiple projects. Each project has a different <library /> to contain its specific assets. I load a library with OpenFL Assets.loadLibrary() at runtime to be able to load and unload them whenever I need it. After updating to OpenFL 9.3.1 and Lime 8.1.0 I'm getting the following error when compiling a HTML5 build "[lime.utils.Assets] ERROR: <asset_type> asset "<library>:<asset_id>" exists, but only asynchronously" (where <asset_type> is the type of the asset <library> is the name the library and <asset_id> the id of the asset) when I try to use one of the assets of that library.

I located the issue but I'm not sure which way would be the best to fix it so I'll explain what's happening.

https://github.com/openfl/openfl/blob/b93ed01c6efa927b4aecea3142de91fe469b52fa/src/openfl/utils/Assets.hx#L584-L610

OpenFL Assets.loadLibrary() calls Lime Assets.loadLibrary() that will load the library, preload the assets and register it in the Lime side.

Once it's loaded in the Lime side it does this:

    _library = new AssetLibrary();
    _library.__proxy = library;
    LimeAssets.registerLibrary(name, _library);

LimeAssets.registerLibrary() will now register a new OpenFL AssetLibrary which has the Lime AssetLibrary as its __proxy

But when it tries to register it here it will find that there's a loaded library with the same name, compare the loaded library with the library to register and fail as the loaded library is a different object (Lime's AssetLibrary) than the library to register (OpenFL's AssetLibrary):

https://github.com/openfl/lime/blob/6d36d6f8740a8215fd1e535016a076c28b893b37/src/lime/utils/Assets.hx#L500-L510

This will force the loaded library to be unloaded.

Now that AssetLibrary.unload() is implemented here the preloaded assets get erased when the library gets unloaded and when trying to get an asset from that library it will throw the error I'm getting.

The issue isn't happening on native builds (Only tested Windows and Linux)

joshtynjala commented 11 months ago

I feel like the fix may be as simple as calling libraries.remove(name) before registering the OpenFL library that is wrapping the Lime one. Can you try making this change locally to give it a quick test for me?

libraries.remove(name);
_library = new AssetLibrary();
_library.__proxy = library;
LimeAssets.registerLibrary(name, _library);
mrcdk commented 11 months ago

Yeah, that did work but I had to do it like this:

@:privateAccess LimeAssets.libraries.remove(name);
_library = new AssetLibrary();
_library.__proxy = library;
LimeAssets.registerLibrary(name, _library);

as this part of the code is in OpenFL and not in Lime and Lime Assets.libraries is private.

joshtynjala commented 11 months ago

Thanks! I was thinking that we were in a subclass, but I realize now it is AssetLibrary that's the subclass, and not Assets.

Regardless, this will probably still be the best solution for OpenFL for the time being. I think it may make sense to add a method to Lime's Assets that removes a library without unloading it, and OpenFL can use that without @:privateAccess in the future.

mrcdk commented 11 months ago

Thanks for the fix!