I’m having an issue loading assets that I believe may be a bug with the scene loading API. Here’s the simple test case.
const assetsA = app.assets.findByTag('Scene A')
const assetListLoaderA = new pc.AssetListLoader(assetsA, app.assets )
assetListLoaderA.load(err => console.log('Scene A assets loaded')
const assetsB = app.assets.findByTag('Scene B')
const assetListLoaderB = new pc.AssetListLoader(assetsB, app.assets )
assetListLoaderB.load(err => console.log('Scene B assets loaded')
The idea is that we have two scenes; Scene A an Scene B. Each asset is tagged with the name of the scene they’re used in. This allows us to preload SceneA and B independently of each other.
When assets are shared between scenes ie. they are tagged with both ‘Scene A’ and ‘Scene B’, then ‘Scene A assets loaded’ is logged but ‘Scene B assets loaded’ is not. I assume this is because they have begun loading or have finished ‘loading’ already, and therefore
assetListLoaderB.load becomes a no-op.
What I expected to happen
Even if the
assetListLoaderB.load does not initiate a load, it should still trigger the callback when the assets do successfully load, even if that initiated elsewhere in the app. I would expect the callback to act as an event handler as/when the assets in the list loaded. Note that I’ve also tried using the
ready method per asset which also does not work as essentially the load method of the AssetRegistry bails out early
I got caught out by this yesterday where trying to load an already loaded asset doesn’t fire ‘ready’.
In this case, it looks like if it’s already loading, it doesn’t add it to the list: https://github.com/playcanvas/engine/blob/master/src/asset/asset-list-loader.js#L86
I guess this would mean that is possible that Scene B assets callback can be fired before all the assets that are tagged by Scene B are loaded because they were triggered by the Scene A load.
It’s a bit of a tricky one to handle as it break existing behaviour
I know this is a simple example but do you need to have two asset loaders for your current use case? Would it be possible to use https://developer.playcanvas.com/en/api/pc.AssetRegistry.html#findByTag
With the following:
var assets = app.assets.findByTag("Scene A", "Scene B");
Yeah, also the Asset Registry catches the same thing. I guess there’s an argument that it makes sense if the asset is already loaded, but if it’s still loading then you have to wait for it to fail/succeed before creating another loader list
What I would like is if it’s loaded, the ready and loaded callbacks are immediately fired in the asset registry.
If loading, it should still listen for the loaded event rather than ignore it.
Yeah for sure, I think that’s what I would expect to happen. If a http request has initiated, then don’t start a new one, but still register the events regardless
Yeah I guess I could manually track any assets that appear in Scene B that have already been loaded and exclude them. For my use case it’s relatively simple, but a more complex app seems like it would be quite brittle.
I think what I did was get all Scene B assets and created a new array without the ones that were already loaded.
Yep, although I have to also do it it is currently
loading too, but no way to know if it actually succeeds withouth going further up. It just requires a little re-architecture on my part and I’m lazy
Also @yaustar @will I think there’s a race condition on the AssetListLoader. I haven’t verified for sure but when the assets are coming from cache, each asset loads immediately and returns syncrhnously meaning the loadingComplete method is fired and the count and total are the same. This then happens for the other assets. The total should probably be accumulated before any loading starts.
You can test this byt loading a large number of assets and logging the total and count in the onLoad handler. You can see the count increasing in each cal, but also the total increases too.
Yeah, I can’t remember if callbacks/events are fired if an asset is already loaded
I think this is if it comes from the browser cache where it loads and fires the load event before the loop has finished
I’ve got it on my list to investigate unless you beat me to it first