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

Fix StrongHandle TypeId mismatch when using labels #10465

Conversation

Selene-Amanita
Copy link
Member

@Selene-Amanita Selene-Amanita commented Nov 9, 2023

Objective

Fix #10436

Note

  • I didn't test this PR thoroughly, but it does seem to fix the bug at least.
  • There might be a better way to fix the bug, but I don't see it, don't hesitate to make another PR or adopt this one if there is too much to change
  • I don't know what the type of a "MorphTarget" is supposed to be
  • I'm not sure what to do with the CI error about the error type being too big

Solution

  • Force the implementation of label_type_name and label_type_id methods on the AssetLoader trait
  • (previously, changed by 52bd527) Modify the asset path string parser to get a "label_type", which is the last word after the last # and / characters and before digits, for example for cup.glb#Mesh0/Primitive0 it would be Primitive, that's what will be passed to the methods above
  • use all of this to assign the correct TypeId to the underlying StrongHandle when using load or load_untyped

See the conversation here for more information: https://discord.com/channels/691052431525675048/1062754025218510918/1171562681736642622

Migration Guide

If you have a type that implements AssetLoader, and that AssetLoader should support label, you should implement two methods, label_type_name and label_type_id. They take a label string that you can parse to return the corresponding TypeId/TypeName, or None if it's an invalid label.

@Selene-Amanita Selene-Amanita added C-Bug An unexpected or incorrect behavior A-Assets Load files from disk to use for things like images, models, and sounds P-Crash A sudden unexpected crash labels Nov 9, 2023
@Selene-Amanita Selene-Amanita added this to the 0.12.1 milestone Nov 9, 2023
Copy link
Member

@NiklasEi NiklasEi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thank you for doing this 🙂
I would prefer a more general API instead of focusing on the last word in the label and expecting it to have a number. Can we have the new methods take the asset path or the complete label? Then the loader can decide how to parse it.

@@ -39,6 +39,10 @@ pub trait AssetLoader: Send + Sync + 'static {

/// Returns a list of extensions supported by this asset loader, without the preceding dot.
fn extensions(&self) -> &[&str];
/// Returns the type name of the sub-asset type with the given `label`.
fn label_type_name(&self, label_type: &str) -> Option<&'static str>;
Copy link
Member

@NiklasEi NiklasEi Nov 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the new methods should have default implementations returning name/id of Self::Asset

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should make this change non breaking.

Copy link
Member Author

@Selene-Amanita Selene-Amanita Nov 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was on the fence yeah. I kinda wanted to make the implementation of AssetLoader for the user as easy as possible, and parsing a label is kinda annoying, but yeah in doing that I kinda set in stone what a label should look like and we might not want that, also the code of AssetPath becomes kinda messy yeah.

I would like to hear another opinion on this.

fn asset_type_id(&self) -> TypeId {
TypeId::of::<L::Asset>()
}

fn asset_type_name(&self) -> &'static str {
std::any::type_name::<L::Asset>()
fn label_type_name(&self, label_type: Option<&str>) -> Option<&'static str> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion this logic should be part of the loader. We could directly call the methods on the loader here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That puts the responsibility of thinking about "if there is no label it's the root Asset type" on the person who implement AssetLoader. I think the only reason we might want that is if we want to allow an AssetLoader to only take paths with labels, but even if we do that it would still load an asset with a handle with a path without a label so it doesn't really make sense I think?

Copy link
Member

@NiklasEi NiklasEi Nov 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In most cases an asset loader should not care about the new functions at all. If the default implementations of the functions return the type name/id of the main asset, only the ones requiring their own implementations need to handle "no label" => "main asset type" and is is fine imo. So far I am only aware of the Gltf loader that would need implementations of the new functions.

/// This is given as a convenience only when parsing an asset path string,
/// but it is not set when a `label` is set directly.
/// Should not be used for comparison.
pub(crate) label_type: Option<CowArc<'a, str>>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove this and leave the path parsing to the loader.

@NiklasEi
Copy link
Member

NiklasEi commented Nov 9, 2023

The error about the error type is because the new asset loader error is quite big and included in the Gltf loader error. The new error could just contain the path, which might make it small enough.

@Selene-Amanita
Copy link
Member Author

I don't really understand how the error is big, I basically copied MissingLabel into WrongLabel, it's a bunch of String?

@Selene-Amanita
Copy link
Member Author

Based on @NiklasEi 's feedback, commit 52bd527 stops preemptively parsing the label and leaves that to the AssetLoader implementation. You can check before and after the commit to see which one you prefer.

@NiklasEi
Copy link
Member

NiklasEi commented Nov 9, 2023

Maybe we should have the new functions return the type names and IDs without Option. If an asset loader will be used to load a certain path, there should always be a handle type for that path. Then we can also remove the new error variant.

@cart
Copy link
Member

cart commented Nov 9, 2023

Hmm I'll need to think on this a bit as something seems off with this approach. AssetLoader::label_type_name(label: &str) feels wrong. I think we shouldn't support "storing type names in label names" as a first class citizen in the asset system, especially given that it won't work in all cases. "Works by convention / if people remember to implement it correctly" isn't safe enough, and assigners of labels should feel free to use whatever convention makes sense for the asset. Assets (in general) are asynchronously resolved. AssetLoaders can run without knowing the type of a label ahead of time. load_untyped should also have no need to know the type name before the AssetLoader has run.

@cart cart removed this from the 0.12.1 milestone Nov 11, 2023
github-merge-queue bot pushed a commit that referenced this pull request Nov 14, 2023
# Objective

Fixes #10436
Alternative to #10465 

## Solution

`load_untyped_async` / `load_internal` currently has a bug. In
`load_untyped_async`, we pass None into `load_internal` for the
`UntypedHandle` of the labeled asset path. This results in a call to
`get_or_create_path_handle_untyped` with `loader.asset_type_id()`
This is a new code path that wasn't hit prior to the newly added
`load_untyped` because `load_untyped_async` was a private method only
used in the context of the `load_folder` impl (which doesn't have
labels)

The fix required some refactoring to catch that case and defer handle
retrieval. I have also made `load_untyped_async` public as it is now
"ready for public use" and unlocks new scenarios.
@Selene-Amanita
Copy link
Member Author

Fixed by #10514, closing this.

cart added a commit that referenced this pull request Nov 30, 2023
# Objective

Fixes #10436
Alternative to #10465 

## Solution

`load_untyped_async` / `load_internal` currently has a bug. In
`load_untyped_async`, we pass None into `load_internal` for the
`UntypedHandle` of the labeled asset path. This results in a call to
`get_or_create_path_handle_untyped` with `loader.asset_type_id()`
This is a new code path that wasn't hit prior to the newly added
`load_untyped` because `load_untyped_async` was a private method only
used in the context of the `load_folder` impl (which doesn't have
labels)

The fix required some refactoring to catch that case and defer handle
retrieval. I have also made `load_untyped_async` public as it is now
"ready for public use" and unlocks new scenarios.
rdrpenguin04 pushed a commit to rdrpenguin04/bevy that referenced this pull request Jan 9, 2024
# Objective

Fixes bevyengine#10436
Alternative to bevyengine#10465 

## Solution

`load_untyped_async` / `load_internal` currently has a bug. In
`load_untyped_async`, we pass None into `load_internal` for the
`UntypedHandle` of the labeled asset path. This results in a call to
`get_or_create_path_handle_untyped` with `loader.asset_type_id()`
This is a new code path that wasn't hit prior to the newly added
`load_untyped` because `load_untyped_async` was a private method only
used in the context of the `load_folder` impl (which doesn't have
labels)

The fix required some refactoring to catch that case and defer handle
retrieval. I have also made `load_untyped_async` public as it is now
"ready for public use" and unlocks new scenarios.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Assets Load files from disk to use for things like images, models, and sounds C-Bug An unexpected or incorrect behavior P-Crash A sudden unexpected crash
Projects
None yet
Development

Successfully merging this pull request may close these issues.

load_untyped has issues loading scenes from gltf files
3 participants