Skip to content

Support generic asset settings when loading an asset #243

@mgi388

Description

@mgi388

Some asset formats like image have special treatment in this crate for configuring the asset on a per-asset-collection basis:

#[derive(AssetCollection, Resource)]
struct ImageAssets {
    #[asset(path = "images/pixel_tree.png")]
    #[asset(image(sampler = linear))]
    tree_linear: Handle<Image>,
}

But for many assets, you want to provide different settings for the same asset, depending on the asset collection. You can't rely on the asset meta file because you need different settings per asset collection.

For example, in an RTS game, during a level, you might want to load an asset for the Army. The Army asset itself has some settings that control whether additional assets are loaded. Those assets are not needed during the level, but are used in other scenes in the game. It would be good if bevy_asset_loader had a way to configure the assets settings near the #[asset] macro.

Even the GltfLoader inside Bevy has some settings, and you can imagine scenarios where you want to be able to configure these on a per-asset-collection basis:

pub struct GltfLoaderSettings {
    /// If true, the loader will spawn cameras for gltf camera nodes.
    pub load_cameras: bool,
    /// If true, the loader will spawn lights for gltf light nodes.
    pub load_lights: bool,
    /// If true, the loader will include the root of the gltf root node.
    pub include_source: bool,
}

I don't know what a solution looks like. It doesn't have to sit next to the #[asset] macro, but that seems like the most obvious ergonomic choice.

BTW, for DynamicAssets, there seems to be a way to achieve this already. Something like this:

When registering your asset:

dynamic_assets.register_asset(
    "foo",
    Box::new(WrappedFoo {
        path: "my/bar.foo",
        settings: FooLoaderSettings {
            load_a: true,
            load_b: false,
        },
    }),
);

And:

#[derive(Debug, Reflect)]
#[reflect(Debug)]
pub struct WrappedFoo {
    pub path: String,
    pub settings: FooLoaderSettings,
}

impl DynamicAsset for WrappedFoo {
    fn load(&self, asset_server: &AssetServer) -> Vec<UntypedHandle> {
        let settings = self.settings.clone();

        let foo_handle: Handle<OriginalFoo> =
            asset_server.load_with_settings(&self.path, move |s: &mut FooLoaderSettings| {
                *s = settings.clone();
            });

        vec![foo_handle.untyped()]
    }

    fn build(&self, world: &mut World) -> Result<DynamicAssetType, anyhow::Error> {
        let asset_server = world
            .get_resource::<AssetServer>()
            .expect("AssetServer resource should exist");
        Ok(DynamicAssetType::Single(
            asset_server.get_handle_untyped(&self.path).unwrap(),
        ))
    }
}

This seems to work AFAICT.

Originally raised in Discord.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions