//! Implements loader for a custom asset type. use bevy::utils::thiserror; use bevy::{ asset::{io::Reader, AssetLoader, LoadContext}, prelude::*, reflect::TypePath, utils::BoxedFuture, }; use futures_lite::AsyncReadExt; use serde::Deserialize; use thiserror::Error; #[derive(Asset, TypePath, Debug, Deserialize)] pub struct CustomAsset { pub value: i32, } #[derive(Default)] pub struct CustomAssetLoader; /// Possible errors that can be produced by [`CustomAssetLoader`] #[non_exhaustive] #[derive(Debug, Error)] pub enum CustomAssetLoaderError { /// An [IO](std::io) Error #[error("Could load shader: {0}")] Io(#[from] std::io::Error), /// A [RON](ron) Error #[error("Could not parse RON: {0}")] RonSpannedError(#[from] ron::error::SpannedError), } impl AssetLoader for CustomAssetLoader { type Asset = CustomAsset; type Settings = (); type Error = CustomAssetLoaderError; fn load<'a>( &'a self, reader: &'a mut Reader, _settings: &'a (), _load_context: &'a mut LoadContext, ) -> BoxedFuture<'a, Result> { Box::pin(async move { let mut bytes = Vec::new(); reader.read_to_end(&mut bytes).await?; let custom_asset = ron::de::from_bytes::(&bytes)?; Ok(custom_asset) }) } fn extensions(&self) -> &[&str] { &["custom"] } } fn main() { App::new() .add_plugins(DefaultPlugins) .init_resource::() .init_asset::() .init_asset_loader::() .add_systems(Startup, setup) .add_systems(Update, print_on_load) .run(); } #[derive(Resource, Default)] struct State { handle: Handle, printed: bool, } fn setup(mut state: ResMut, asset_server: Res) { state.handle = asset_server.load("data/asset.custom"); } fn print_on_load(mut state: ResMut, custom_assets: ResMut>) { let custom_asset = custom_assets.get(&state.handle); if state.printed || custom_asset.is_none() { return; } info!("Custom asset loaded: {:?}", custom_asset.unwrap()); state.printed = true; }