Skip to content

Add BSN asset catalog: load, save, and labeled sub-asset registration#23648

Draft
jbuehler23 wants to merge 2 commits intobevyengine:mainfrom
jbuehler23:bsn-asset-catalog-v2
Draft

Add BSN asset catalog: load, save, and labeled sub-asset registration#23648
jbuehler23 wants to merge 2 commits intobevyengine:mainfrom
jbuehler23:bsn-asset-catalog-v2

Conversation

@jbuehler23
Copy link
Copy Markdown
Contributor

Objective

Addresses item 3 in #23637: BSN asset catalog loading and serialization.

Depends on #23576 (@pcwalton's dynamic BSN) - so a lot of the changes are duplicated here, and looks larger than it actually is!

Solution

Adds a BSN asset catalog module to bevy_scene2 for managing named assets in .bsn format.

What this adds!

1. Runtime loading (load_bsn_assets)

Parses BSN text containing named asset definitions and inserts them into Assets<T> stores via reflection. Nothing triggers automatically, you call this when you need to load a catalog at runtime (ie, editor startup, level load).

use bevy_scene2::bsn_asset_catalog::load_bsn_assets;

let entries = load_bsn_assets(world, bsn_text)?;
for entry in &entries {
    println!("{}: {:?}", entry.name, entry.handle);
}

2. Serialization (`serialize_assets_to_bsn`)

Serializes named assets from the world back to BSN text. Uses default diffing so only non-default fields are written. `Handle` fields are resolved to asset path strings. Nothing saves automatically - you call this when you want to persist your asset catalog (ie, on "save" in the editor).

use bevy_scene2::bsn_asset_catalog::{serialize_assets_to_bsn, CatalogAssetRef};

let refs = vec![CatalogAssetRef {
    name: "BrickWall".into(),
    type_id: TypeId::of::<StandardMaterial>(),
    asset_id: handle.id().untyped(),
}];
let bsn_text = serialize_assets_to_bsn(world, &refs);
std::fs::write("assets.bsn", bsn_text)?;

3. Automatic labeled sub-asset registration (in `DynamicBsnLoader`)

When a .bsn file is loaded through the asset server, named entries that are asset types (types with `ReflectAsset` + `ReflectDefault` type data) are automatically registered as labeled sub-assets:

let material: Handle<StandardMaterial> = asset_server.load("scenes/material_catalog.bsn#PolishedMetal");

The asset server loads the parent .bsn file, the `DynamicBsnLoader` scans the AST for named asset entries, creates them via reflection, and registers them as labeled sub-assets. **This** happens automatically.

4. `bevy_asset` additions

- `ReflectAsset::into_loaded_asset()` - convert a reflected asset value into an `ErasedLoadedAsset` for sub-asset registration
- `LoadContext::add_loaded_labeled_asset_erased()` - type-erased version of add_loaded_labeled_asset for reflection-based asset creation

## Example
Example catalog file (assets/scenes/material_catalog.bsn)
```rust
cargo run --example bsn_asset_catalog
bevy_ecs::hierarchy::Children [
    #PolishedMetal
    bevy_pbr::pbr_material::StandardMaterial {
        perceptual_roughness: 0.05,
        metallic: 1.0,
        reflectance: 1.0,
    }
    ,
    #RoughStone
    bevy_pbr::pbr_material::StandardMaterial {
        perceptual_roughness: 0.9,
        reflectance: 0.3,
    }
]

Only non-default fields are written! (metallic: 0.0 is omitted for RoughStone since it's the default).

Example loads four named materials from the catalog, and displays them on spheres with different PBR properties. You will see that it "loaded" the assets on startup, and then on save you will see the BSN asset catalog get written.

This is a port of Jackdaw's shared asset catalogue in JSN, for BSN!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants