add ability to provide custom a AssetIo implementation (#1037)
				
					
				
			make it easier to override the default asset IO instance
This commit is contained in:
		
							parent
							
								
									841755aaf2
								
							
						
					
					
						commit
						596bed8ce2
					
				@ -177,6 +177,10 @@ path = "examples/asset/asset_loading.rs"
 | 
			
		||||
name = "custom_asset"
 | 
			
		||||
path = "examples/asset/custom_asset.rs"
 | 
			
		||||
 | 
			
		||||
[[example]]
 | 
			
		||||
name = "custom_asset_io"
 | 
			
		||||
path = "examples/asset/custom_asset_io.rs"
 | 
			
		||||
 | 
			
		||||
[[example]]
 | 
			
		||||
name = "audio"
 | 
			
		||||
path = "examples/audio/audio.rs"
 | 
			
		||||
 | 
			
		||||
@ -60,6 +60,10 @@ impl Clone for AssetServer {
 | 
			
		||||
 | 
			
		||||
impl AssetServer {
 | 
			
		||||
    pub fn new<T: AssetIo>(source_io: T, task_pool: TaskPool) -> Self {
 | 
			
		||||
        Self::with_boxed_io(Box::new(source_io), task_pool)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn with_boxed_io(asset_io: Box<dyn AssetIo>, task_pool: TaskPool) -> Self {
 | 
			
		||||
        AssetServer {
 | 
			
		||||
            server: Arc::new(AssetServerInternal {
 | 
			
		||||
                loaders: Default::default(),
 | 
			
		||||
@ -69,7 +73,7 @@ impl AssetServer {
 | 
			
		||||
                handle_to_path: Default::default(),
 | 
			
		||||
                asset_lifecycles: Default::default(),
 | 
			
		||||
                task_pool,
 | 
			
		||||
                asset_io: Box::new(source_io),
 | 
			
		||||
                asset_io,
 | 
			
		||||
            }),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -51,28 +51,41 @@ impl Default for AssetServerSettings {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create an instance of the platform default `AssetIo`
 | 
			
		||||
///
 | 
			
		||||
/// This is useful when providing a custom `AssetIo` instance that needs to
 | 
			
		||||
/// delegate to the default `AssetIo` for the platform.
 | 
			
		||||
pub fn create_platform_default_asset_io(app: &mut AppBuilder) -> Box<dyn AssetIo> {
 | 
			
		||||
    let settings = app
 | 
			
		||||
        .resources_mut()
 | 
			
		||||
        .get_or_insert_with(AssetServerSettings::default);
 | 
			
		||||
 | 
			
		||||
    #[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))]
 | 
			
		||||
    let source = FileAssetIo::new(&settings.asset_folder);
 | 
			
		||||
    #[cfg(target_arch = "wasm32")]
 | 
			
		||||
    let source = WasmAssetIo::new(&settings.asset_folder);
 | 
			
		||||
    #[cfg(target_os = "android")]
 | 
			
		||||
    let source = AndroidAssetIo::new(&settings.asset_folder);
 | 
			
		||||
 | 
			
		||||
    Box::new(source)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Plugin for AssetPlugin {
 | 
			
		||||
    fn build(&self, app: &mut AppBuilder) {
 | 
			
		||||
        let task_pool = app
 | 
			
		||||
            .resources()
 | 
			
		||||
            .get::<IoTaskPool>()
 | 
			
		||||
            .expect("`IoTaskPool` resource not found.")
 | 
			
		||||
            .0
 | 
			
		||||
            .clone();
 | 
			
		||||
        if app.resources().get::<AssetServer>().is_none() {
 | 
			
		||||
            let task_pool = app
 | 
			
		||||
                .resources()
 | 
			
		||||
                .get::<IoTaskPool>()
 | 
			
		||||
                .expect("`IoTaskPool` resource not found.")
 | 
			
		||||
                .0
 | 
			
		||||
                .clone();
 | 
			
		||||
 | 
			
		||||
        let asset_server = {
 | 
			
		||||
            let settings = app
 | 
			
		||||
                .resources_mut()
 | 
			
		||||
                .get_or_insert_with(AssetServerSettings::default);
 | 
			
		||||
            let source = create_platform_default_asset_io(app);
 | 
			
		||||
 | 
			
		||||
            #[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))]
 | 
			
		||||
            let source = FileAssetIo::new(&settings.asset_folder);
 | 
			
		||||
            #[cfg(target_arch = "wasm32")]
 | 
			
		||||
            let source = WasmAssetIo::new(&settings.asset_folder);
 | 
			
		||||
            #[cfg(target_os = "android")]
 | 
			
		||||
            let source = AndroidAssetIo::new(&settings.asset_folder);
 | 
			
		||||
            AssetServer::new(source, task_pool)
 | 
			
		||||
        };
 | 
			
		||||
            let asset_server = AssetServer::with_boxed_io(source, task_pool);
 | 
			
		||||
 | 
			
		||||
            app.add_resource(asset_server);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        app.add_stage_before(
 | 
			
		||||
            bevy_app::stage::PRE_UPDATE,
 | 
			
		||||
@ -84,7 +97,6 @@ impl Plugin for AssetPlugin {
 | 
			
		||||
            stage::ASSET_EVENTS,
 | 
			
		||||
            SystemStage::parallel(),
 | 
			
		||||
        )
 | 
			
		||||
        .add_resource(asset_server)
 | 
			
		||||
        .register_type::<HandleId>()
 | 
			
		||||
        .add_system_to_stage(
 | 
			
		||||
            bevy_app::stage::PRE_UPDATE,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										104
									
								
								examples/asset/custom_asset_io.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								examples/asset/custom_asset_io.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,104 @@
 | 
			
		||||
use bevy::{
 | 
			
		||||
    asset::{AssetIo, AssetIoError},
 | 
			
		||||
    prelude::*,
 | 
			
		||||
    utils::BoxedFuture,
 | 
			
		||||
};
 | 
			
		||||
use std::path::{Path, PathBuf};
 | 
			
		||||
 | 
			
		||||
/// A custom asset io implementation that simply defers to the platform default
 | 
			
		||||
/// implementation.
 | 
			
		||||
///
 | 
			
		||||
/// This can be used as a starting point for developing a useful implementation
 | 
			
		||||
/// that can defer to the default when needed.
 | 
			
		||||
struct CustomAssetIo(Box<dyn AssetIo>);
 | 
			
		||||
 | 
			
		||||
impl AssetIo for CustomAssetIo {
 | 
			
		||||
    fn load_path<'a>(&'a self, path: &'a Path) -> BoxedFuture<'a, Result<Vec<u8>, AssetIoError>> {
 | 
			
		||||
        println!("load_path({:?})", path);
 | 
			
		||||
        self.0.load_path(path)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn read_directory(
 | 
			
		||||
        &self,
 | 
			
		||||
        path: &Path,
 | 
			
		||||
    ) -> Result<Box<dyn Iterator<Item = PathBuf>>, AssetIoError> {
 | 
			
		||||
        println!("read_directory({:?})", path);
 | 
			
		||||
        self.0.read_directory(path)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn is_directory(&self, path: &Path) -> bool {
 | 
			
		||||
        println!("is_directory({:?})", path);
 | 
			
		||||
        self.0.is_directory(path)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn watch_path_for_changes(&self, path: &Path) -> Result<(), AssetIoError> {
 | 
			
		||||
        println!("watch_path_for_changes({:?})", path);
 | 
			
		||||
        self.0.watch_path_for_changes(path)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn watch_for_changes(&self) -> Result<(), AssetIoError> {
 | 
			
		||||
        println!("watch_for_changes()");
 | 
			
		||||
        self.0.watch_for_changes()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A plugin used to execute the override of the asset io
 | 
			
		||||
struct CustomAssetIoPlugin;
 | 
			
		||||
 | 
			
		||||
impl Plugin for CustomAssetIoPlugin {
 | 
			
		||||
    fn build(&self, app: &mut AppBuilder) {
 | 
			
		||||
        // must get a hold of the task pool in order to create the asset server
 | 
			
		||||
 | 
			
		||||
        let task_pool = app
 | 
			
		||||
            .resources()
 | 
			
		||||
            .get::<bevy::tasks::IoTaskPool>()
 | 
			
		||||
            .expect("`IoTaskPool` resource not found.")
 | 
			
		||||
            .0
 | 
			
		||||
            .clone();
 | 
			
		||||
 | 
			
		||||
        let asset_io = {
 | 
			
		||||
            // the platform default asset io requires a reference to the app
 | 
			
		||||
            // builder to find its configuration
 | 
			
		||||
 | 
			
		||||
            let default_io = bevy::asset::create_platform_default_asset_io(app);
 | 
			
		||||
 | 
			
		||||
            // create the custom asset io instance
 | 
			
		||||
 | 
			
		||||
            CustomAssetIo(default_io)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // the asset server is constructed and added the resource manager
 | 
			
		||||
 | 
			
		||||
        app.add_resource(AssetServer::new(asset_io, task_pool));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    App::build()
 | 
			
		||||
        .add_plugins_with(DefaultPlugins, |group| {
 | 
			
		||||
            // the custom asset io plugin must be inserted in-between the
 | 
			
		||||
            // `CorePlugin' and `AssetPlugin`. It needs to be after the
 | 
			
		||||
            // CorePlugin, so that the IO task pool has already been constructed.
 | 
			
		||||
            // And it must be before the `AssetPlugin` so that the asset plugin
 | 
			
		||||
            // doesn't create another instance of an assert server. In general,
 | 
			
		||||
            // the AssetPlugin should still run so that other aspects of the
 | 
			
		||||
            // asset system are initialized correctly.
 | 
			
		||||
            group.add_before::<bevy::asset::AssetPlugin, _>(CustomAssetIoPlugin)
 | 
			
		||||
        })
 | 
			
		||||
        .add_startup_system(setup)
 | 
			
		||||
        .run();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn setup(
 | 
			
		||||
    commands: &mut Commands,
 | 
			
		||||
    asset_server: Res<AssetServer>,
 | 
			
		||||
    mut materials: ResMut<Assets<ColorMaterial>>,
 | 
			
		||||
) {
 | 
			
		||||
    let texture_handle = asset_server.load("branding/icon.png");
 | 
			
		||||
    commands
 | 
			
		||||
        .spawn(Camera2dBundle::default())
 | 
			
		||||
        .spawn(SpriteBundle {
 | 
			
		||||
            material: materials.add(texture_handle.into()),
 | 
			
		||||
            ..Default::default()
 | 
			
		||||
        });
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user