bevy_asset_loader icon indicating copy to clipboard operation
bevy_asset_loader copied to clipboard

gltf scenes randomly get swapped

Open GitGhillie opened this issue 1 year ago • 10 comments

Since the 0.12 update it seems to be possible to spawn gltf scenes without the #Scene0 at the end of the path, using bevy_asset_loader. However, doing this I ran into a strange issue where sometimes when I open the app the scenes get swapped. Here A and B are two different files:

AB And on another run: BA

Reproducer can be found here: https://github.com/GitGhillie/asset_loading_mre

GitGhillie avatar Jan 23 '24 19:01 GitGhillie

Does it still happen when you use the label #Scene0?

Have you tried to reproduce this without bevy_asset_loader?

NiklasEi avatar Jan 23 '24 19:01 NiklasEi

It does not, but it's quite the footgun imo

GitGhillie avatar Jan 23 '24 19:01 GitGhillie

It does not, but it's quite the footgun imo

Yeah, definitely a bug. Just trying to understand where the issue might be.

NiklasEi avatar Jan 23 '24 19:01 NiklasEi

Have you tried to reproduce this without bevy_asset_loader?

Haven't tried to reproduce without yet (I did try some things but I've never looked into assets before so it will take me while to come up with something that's equivalent I guess). I did try with bevy_asset_loader on bevy main (2951ddf), same issue

GitGhillie avatar Jan 23 '24 19:01 GitGhillie

For example, if I try scene_handles.handle_a = asset_server.load("A.glb"); and then try to spawn it:

#[derive(Resource, Default)]
struct SceneHandles {
    handle_a: Handle<Scene>,
    handle_b: Handle<Scene>,
}

...
commands.spawn((
        Name::from("Scene A"),
        SceneBundle {
            scene: scene_handles.handle_a.clone(),
            transform: Transform::from_xyz(-1.0, 0.0, 0.0),
            ..default()
        },
    ));

I get:

ERROR bevy_asset::server: Requested handle of type TypeId { t: 20984825428628115851185960703696596255 } for asset 'B.glb' does not match actual asset type 'bevy_gltf::Gltf', which used loader 'bevy_gltf::loader::GltfLoader'

So I'm guessing bevy_asset_loader is doing something more complicated under the hood than I expect

GitGhillie avatar Jan 23 '24 20:01 GitGhillie

I can reproduce the issue with your repository. This is the generated AssetCollection impl:

impl AssetCollection for SceneAssets {
    fn create(world: &mut ::bevy::ecs::world::World) -> Self {
        let from_world_fields = ();
        world
            .resource_scope(|
                world,
                asset_keys: ::bevy::prelude::Mut<
                    ::bevy_asset_loader::dynamic_asset::DynamicAssets,
                >|
                {
                    SceneAssets {
                        scene_a: {
                            let asset_server = world
                                .get_resource::<::bevy::asset::AssetServer>()
                                .expect("Cannot get AssetServer");
                            asset_server.load("A.glb")
                        },
                        scene_b: {
                            let asset_server = world
                                .get_resource::<::bevy::asset::AssetServer>()
                                .expect("Cannot get AssetServer");
                            asset_server.load("B.glb")
                        },
                    }
                })
    }

    fn load(
        world: &mut ::bevy::ecs::world::World,
    ) -> Vec<::bevy::prelude::UntypedHandle> {
        let cell = world.cell();
        let asset_server = cell
            .get_resource::<::bevy::prelude::AssetServer>()
            .expect("Cannot get AssetServer");
        let asset_keys = cell
            .get_resource::<bevy_asset_loader::prelude::DynamicAssets>()
            .expect("Cannot get bevy_asset_loader::prelude::DynamicAssets");
        let mut handles = ::alloc::vec::Vec::new();
        handles.push(asset_server.load_untyped("A.glb").untyped());
        handles.push(asset_server.load_untyped("B.glb").untyped());
        handles
    }
}

The only difference to what you tried to do in Bevy directly seems to be the use of load_untyped. Maybe there is some issue with handle reusage :thinking:

NiklasEi avatar Jan 23 '24 21:01 NiklasEi

Interesting (TIL about cargo expand). So you are loading it twice (once untyped in load and once normally in create)? I would've expected it to get the handle in create from the LoadingAssetHandles or something like that.

GitGhillie avatar Jan 24 '24 15:01 GitGhillie

I was able to repro without bevy_asset_loader: https://github.com/bevyengine/bevy/issues/11509 In the meantime I think we should be able to come up with a workaround

GitGhillie avatar Jan 24 '24 16:01 GitGhillie

So you are loading it twice (once untyped in load and once normally in create)? I would've expected it to get the handle in create from the LoadingAssetHandles or something like that.

The actual loading should only happen once since Bevy keeps assets in memory as long as we keep a Handle. LoadingAssetHandles contains only untyped handles and no easy mapping from paths, while load will directly use the right handle type based on the collection resource.

In the meantime I think we should be able to come up with a workaround

The "workaround" would be to use the #Scene0 label in my opinion. Is there a reason you do not use it?

NiklasEi avatar Jan 24 '24 17:01 NiklasEi

Thanks, that makes sense.

The "workaround" would be to use the #Scene0 label in my opinion. Is there a reason you do not use it?

I used to but since the 0.12 update it seems not possible anymore to use #Scene0 with bevy_gltf_components (for context https://github.com/kaosat-dev/Blender_bevy_components_workflow/issues/102#issuecomment-1902772089).

GitGhillie avatar Jan 24 '24 18:01 GitGhillie

Closing as it's not a bevy_asset_loader issue

GitGhillie avatar Feb 19 '24 16:02 GitGhillie