bevyengine / bevyengine/bevy

`DirectNestedLoader::load` sometimes uses asset type's default loader instead of inspecting path

Open
#15,356 0 comments 0 reactions 0 assignees View on GitHub
A-Assets C-Bug C-Usability D-Modest S-Needs-Design
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

## Bevy version

v0.14.2

## \[Optional\] Relevant system information

Should be irrelevant, this is a Bevy bug.

## What you did

I tried to register a "proxy" `AssetLoader` (in my case: it loads a Krita .kra file, extracts the `mergedimage.png`, and then wants to pass that onto the default `ImageLoader`).

The "obvious" way to load the inner image would be to delegate to the `LoadContext`'s `NestedLoader`:

```rust
load_context
.loader()
.direct()
.with_reader(&mut futures_lite::io::Cursor::new(merged_image))
.load::(png_path)
.await
.unwrap()
.take()
```

## What went wrong

`bevy_asset` tries to use my `KritaLoader` to load the `png` resource as well, even though it is only registered (via `AssetLoader::extensions`) to load `kra` files (and I can confirm that _other_ `png` resources load normally just fine).

## Additional information

As a workaround, using an untyped loader works fine, since the loader is decided using the path instead of the asset type:

```rust
load_context
.loader()
.direct()
.with_reader(&mut futures_lite::io::Cursor::new(merged_image))
.untyped()
.load(png_path)
.await
.unwrap()
.take::()
.unwrap())
```

This all seems to come down to that [`load_internal` calls `AssetServer::get_asset_loader_with_asset_type_id` if `reader` and `asset_type_id` are both `Some`](https://github.com/bevyengine/bevy/blob/v0.14.2/crates/bevy_asset/src/loader_builders.rs#L195-L200), which doesn't know about the path at all. The other code paths both pass in the path.

Changing it to use `AssetServer::get_meta_loader_and_reader` instead seems to fix this issue (but makes it crash if the file path doesn't exist). The "correcter" path seems to be calling `asset_server.data.loaders.read().find()` (which also seems like it might even help collapse this part of the three cases?), but doing that from `load_internal` feels like a pretty bad layering violation at first glance.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.