mirror of
https://github.com/bevyengine/bevy.git
synced 2026-05-06 06:06:42 -04:00
cd977df8eb
# Objective #22104 added `AsyncSeek` support, but it has some downsides: - It is very "loose": it relies on `AssetLoader` to "attest" that it needs the seek feature. However, AssetLoaders both have access to the `AsyncSeek` API no matter what (it is a supertrait of Reader), and AssetReaders provide `AsyncSeek` behavior even if it isn't requested. In practice this is likely to create situations where AssetLoaders don't request `AsyncSeek` and just rely on it being provided by default, causing unexpected incompatibilities when AssetLoader consumers try to use other AssetReaders that don't support AsyncSeek. - It encourages building "fallback" behavior into the AssetReader in cases where AsyncSeek cannot be supported directly (ex: read the while contents into a Vec). From the perspective of loaders, this _silently_ changes the performance characteristics, and _forces_ a specific kind of fallback behavior. It would be better if the fallback behavior was in the hands of the AssetLoader. ## Solution - Remove `ReaderRequiredFeatures` and associated functionality - Add a new `SeekableReader` trait, where `SeekableReader: Reader + AsyncSeek`. - Add a new `Reader::seekable(&mut self) -> Result<&mut dyn SeekableReader, ReaderNotSeekableError>`, which can either fail or cast to `SeekableReader`, if that is supported. ```rust let seekable_reader = reader.seekable()?; seekable_reader.seek(SeekFrom::Start(10)).await?; ``` This gives `AssetLoader` implementers more clarity when it comes to `Reader` feature support, gives them more autonomy over fallback behavior, makes our APIs more static, and cuts down on the complexity of the system as a whole. --------- Co-authored-by: andriyDev <andriydzikh@gmail.com> Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
66 lines
2.1 KiB
Rust
66 lines
2.1 KiB
Rust
//! Implements a custom asset io loader.
|
|
//! An [`AssetReader`] is what the asset server uses to read the raw bytes of assets.
|
|
//! It does not know anything about the asset formats, only how to talk to the underlying storage.
|
|
|
|
use bevy::{
|
|
asset::io::{
|
|
AssetReader, AssetReaderError, AssetSource, AssetSourceBuilder, AssetSourceId,
|
|
ErasedAssetReader, PathStream, Reader,
|
|
},
|
|
prelude::*,
|
|
};
|
|
use std::path::Path;
|
|
|
|
/// A custom asset reader implementation that wraps a given asset reader implementation
|
|
struct CustomAssetReader(Box<dyn ErasedAssetReader>);
|
|
|
|
impl AssetReader for CustomAssetReader {
|
|
async fn read<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
|
info!("Reading {}", path.display());
|
|
self.0.read(path).await
|
|
}
|
|
async fn read_meta<'a>(&'a self, path: &'a Path) -> Result<impl Reader + 'a, AssetReaderError> {
|
|
self.0.read_meta(path).await
|
|
}
|
|
|
|
async fn read_directory<'a>(
|
|
&'a self,
|
|
path: &'a Path,
|
|
) -> Result<Box<PathStream>, AssetReaderError> {
|
|
self.0.read_directory(path).await
|
|
}
|
|
|
|
async fn is_directory<'a>(&'a self, path: &'a Path) -> Result<bool, AssetReaderError> {
|
|
self.0.is_directory(path).await
|
|
}
|
|
}
|
|
|
|
/// A plugins that registers our new asset reader
|
|
struct CustomAssetReaderPlugin;
|
|
|
|
impl Plugin for CustomAssetReaderPlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.register_asset_source(
|
|
AssetSourceId::Default,
|
|
AssetSourceBuilder::new(|| {
|
|
Box::new(CustomAssetReader(
|
|
// This is the default reader for the current platform
|
|
AssetSource::get_default_reader("assets".to_string())(),
|
|
))
|
|
}),
|
|
);
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins((CustomAssetReaderPlugin, DefaultPlugins))
|
|
.add_systems(Startup, setup)
|
|
.run();
|
|
}
|
|
|
|
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
commands.spawn(Camera2d);
|
|
commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
|
|
}
|