mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 12:43:34 +00:00
Allow loading assets with custom async behavior (#13700)
# Objective Currently, bevy supports custom asset loading via `AssetServer:;add`, which allows you to add arbitrary assets to the asset system and returns a handle to it. However this only works for assets that have already been fully loaded. If your loading logic involves any async, you need to wait until the asset is done loading before adding it to the server. This is problematic, as the `Handle` does not get allocated until the very end, which makes it very difficult to use and defeats the value of having handles for asynchronously-loaded assets. ## Solution Add the method `AssetServer::add_async`. This has the same behavior as `AssetServer::add`, only it accepts a future instead of a fully loaded asset. ## Testing I added an identical method to my company's fork of bevy, which works in our app. I'm not quite sure how to go about adding an actual unit test for asset loading behvior, but I will note that `AssetServer::add` also does not appear to have any tests. --- ## Changelog + Added `AssetServer::add_async`, which allows adding assets with custom asynchronous loading behavior to the `AssetServer`
This commit is contained in:
parent
95edd2ea71
commit
9389de5c71
1 changed files with 45 additions and 0 deletions
|
@ -26,6 +26,7 @@ use futures_lite::StreamExt;
|
|||
use info::*;
|
||||
use loaders::*;
|
||||
use parking_lot::RwLock;
|
||||
use std::future::Future;
|
||||
use std::{any::Any, path::PathBuf};
|
||||
use std::{any::TypeId, path::Path, sync::Arc};
|
||||
use thiserror::Error;
|
||||
|
@ -712,6 +713,50 @@ impl AssetServer {
|
|||
handle
|
||||
}
|
||||
|
||||
/// Queues a new asset to be tracked by the [`AssetServer`] and returns a [`Handle`] to it. This can be used to track
|
||||
/// dependencies of assets created at runtime.
|
||||
///
|
||||
/// After the asset has been fully loaded, it will show up in the relevant [`Assets`] storage.
|
||||
#[must_use = "not using the returned strong handle may result in the unexpected release of the asset"]
|
||||
pub fn add_async<A: Asset>(
|
||||
&self,
|
||||
future: impl Future<Output = Result<A, AssetLoadError>> + Send + 'static,
|
||||
) -> Handle<A> {
|
||||
let handle = self
|
||||
.data
|
||||
.infos
|
||||
.write()
|
||||
.create_loading_handle_untyped(std::any::TypeId::of::<A>(), std::any::type_name::<A>());
|
||||
let id = handle.id();
|
||||
|
||||
let event_sender = self.data.asset_event_sender.clone();
|
||||
|
||||
IoTaskPool::get()
|
||||
.spawn(async move {
|
||||
match future.await {
|
||||
Ok(asset) => {
|
||||
let loaded_asset = LoadedAsset::new_with_dependencies(asset, None).into();
|
||||
event_sender
|
||||
.send(InternalAssetEvent::Loaded { id, loaded_asset })
|
||||
.unwrap();
|
||||
}
|
||||
Err(error) => {
|
||||
error!("{error}");
|
||||
event_sender
|
||||
.send(InternalAssetEvent::Failed {
|
||||
id,
|
||||
path: Default::default(),
|
||||
error,
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
handle.typed_debug_checked()
|
||||
}
|
||||
|
||||
/// Loads all assets from the specified folder recursively. The [`LoadedFolder`] asset (when it loads) will
|
||||
/// contain handles to all assets in the folder. You can wait for all assets to load by checking the [`LoadedFolder`]'s
|
||||
/// [`RecursiveDependencyLoadState`].
|
||||
|
|
Loading…
Reference in a new issue