bevy/crates/bevy_asset/src/loader.rs

86 lines
2.7 KiB
Rust
Raw Normal View History

2020-06-15 19:47:35 +00:00
use crate::{AssetServer, AssetVersion, Assets, Handle, LoadState};
use anyhow::Result;
2020-07-10 08:37:06 +00:00
use bevy_ecs::{Res, ResMut, Resource};
use crossbeam_channel::{Receiver, Sender, TryRecvError};
use fs::File;
use io::Read;
2020-05-17 03:18:30 +00:00
use std::{
fs, io,
path::{Path, PathBuf},
};
use thiserror::Error;
/// Errors that occur while loading assets
#[derive(Error, Debug)]
pub enum AssetLoadError {
#[error("Encountered an io error while loading asset.")]
Io(#[from] io::Error),
#[error("This asset's loader encountered an error while loading.")]
LoaderError(#[from] anyhow::Error),
}
/// A loader for a given asset of type `T`
pub trait AssetLoader<T>: Send + Sync + 'static {
2020-05-17 03:18:30 +00:00
fn from_bytes(&self, asset_path: &Path, bytes: Vec<u8>) -> Result<T, anyhow::Error>;
fn extensions(&self) -> &[&str];
2020-05-17 03:18:30 +00:00
fn load_from_file(&self, asset_path: &Path) -> Result<T, AssetLoadError> {
let mut file = File::open(asset_path)?;
let mut bytes = Vec::new();
file.read_to_end(&mut bytes)?;
let asset = self.from_bytes(asset_path, bytes)?;
Ok(asset)
}
}
/// The result of loading an asset of type `T`
#[derive(Debug)]
pub struct AssetResult<T: 'static> {
pub result: Result<T, AssetLoadError>,
pub handle: Handle<T>,
2020-05-17 03:18:30 +00:00
pub path: PathBuf,
pub version: AssetVersion,
}
/// A channel to send and receive [AssetResult]s
#[derive(Debug)]
pub struct AssetChannel<T: 'static> {
pub sender: Sender<AssetResult<T>>,
pub receiver: Receiver<AssetResult<T>>,
}
impl<T> AssetChannel<T> {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
let (sender, receiver) = crossbeam_channel::unbounded();
AssetChannel { sender, receiver }
}
}
2020-08-16 03:27:41 +00:00
/// Reads [AssetResult]s from an [AssetChannel] and updates the [Assets] collection and [LoadState] accordingly
2020-07-10 04:18:35 +00:00
pub fn update_asset_storage_system<T: Resource>(
asset_channel: Res<AssetChannel<T>>,
asset_server: Res<AssetServer>,
mut assets: ResMut<Assets<T>>,
) {
loop {
match asset_channel.receiver.try_recv() {
2020-06-15 19:47:35 +00:00
Ok(result) => match result.result {
Ok(asset) => {
assets.set(result.handle, asset);
asset_server
.set_load_state(result.handle.id, LoadState::Loaded(result.version));
}
2020-06-15 19:47:35 +00:00
Err(err) => {
asset_server
.set_load_state(result.handle.id, LoadState::Failed(result.version));
log::error!("Failed to load asset: {:?}", err);
}
},
Err(TryRecvError::Empty) => {
break;
}
Err(TryRecvError::Disconnected) => panic!("AssetChannel disconnected"),
}
}
}