Remove labeled_assets
from LoadedAsset
and ErasedLoadedAsset
(#15481)
# Objective Fixes #15417. ## Solution - Remove the `labeled_assets` fields from `LoadedAsset` and `ErasedLoadedAsset`. - Created new structs `CompleteLoadedAsset` and `CompleteErasedLoadedAsset` to hold the `labeled_subassets`. - When a subasset is `LoadContext::finish`ed, it produces a `CompleteLoadedAsset`. - When a `CompleteLoadedAsset` is added to a `LoadContext` (as a subasset), their `labeled_assets` are merged, reporting any overlaps. One important detail to note: nested subassets with overlapping names could in theory have been used in the past for the purposes of asset preprocessing. Even though there was no way to access these "shadowed" nested subassets, asset preprocessing does get access to these nested subassets. This does not seem like a case we should support though. It is confusing at best. ## Testing - This is just a refactor. --- ## Migration Guide - Most uses of `LoadedAsset` and `ErasedLoadedAsset` should be replaced with `CompleteLoadedAsset` and `CompleteErasedLoadedAsset` respectively.
This commit is contained in:
parent
232824c009
commit
f17644879d
@ -22,6 +22,7 @@ trace = []
|
||||
bevy_app = { path = "../bevy_app", version = "0.16.0-dev" }
|
||||
bevy_asset_macros = { path = "macros", version = "0.16.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
|
||||
bevy_log = { path = "../bevy_log", version = "0.16.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.16.0-dev", features = [
|
||||
"uuid",
|
||||
] }
|
||||
@ -69,9 +70,6 @@ uuid = { version = "1.13.1", default-features = false, features = ["js"] }
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
notify-debouncer-full = { version = "0.5.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
bevy_log = { path = "../bevy_log", version = "0.16.0-dev" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
@ -725,7 +725,7 @@ mod tests {
|
||||
.map_err(|_| Self::Error::CannotLoadDependency {
|
||||
dependency: dep.into(),
|
||||
})?;
|
||||
let cool = loaded.get();
|
||||
let cool = loaded.get_asset().get();
|
||||
embedded.push_str(&cool.text);
|
||||
}
|
||||
Ok(CoolText {
|
||||
|
@ -13,6 +13,7 @@ use alloc::{
|
||||
};
|
||||
use atomicow::CowArc;
|
||||
use bevy_ecs::world::World;
|
||||
use bevy_log::warn;
|
||||
use bevy_platform_support::collections::{HashMap, HashSet};
|
||||
use bevy_tasks::{BoxedFuture, ConditionalSendFuture};
|
||||
use core::any::{Any, TypeId};
|
||||
@ -60,7 +61,7 @@ pub trait ErasedAssetLoader: Send + Sync + 'static {
|
||||
load_context: LoadContext<'a>,
|
||||
) -> BoxedFuture<
|
||||
'a,
|
||||
Result<ErasedLoadedAsset, Box<dyn core::error::Error + Send + Sync + 'static>>,
|
||||
Result<CompleteErasedLoadedAsset, Box<dyn core::error::Error + Send + Sync + 'static>>,
|
||||
>;
|
||||
|
||||
/// Returns a list of extensions supported by this asset loader, without the preceding dot.
|
||||
@ -91,7 +92,7 @@ where
|
||||
mut load_context: LoadContext<'a>,
|
||||
) -> BoxedFuture<
|
||||
'a,
|
||||
Result<ErasedLoadedAsset, Box<dyn core::error::Error + Send + Sync + 'static>>,
|
||||
Result<CompleteErasedLoadedAsset, Box<dyn core::error::Error + Send + Sync + 'static>>,
|
||||
> {
|
||||
Box::pin(async move {
|
||||
let settings = meta
|
||||
@ -152,7 +153,6 @@ pub struct LoadedAsset<A: Asset> {
|
||||
pub(crate) value: A,
|
||||
pub(crate) dependencies: HashSet<UntypedAssetId>,
|
||||
pub(crate) loader_dependencies: HashMap<AssetPath<'static>, AssetHash>,
|
||||
pub(crate) labeled_assets: HashMap<CowArc<'static, str>, LabeledAsset>,
|
||||
}
|
||||
|
||||
impl<A: Asset> LoadedAsset<A> {
|
||||
@ -166,7 +166,6 @@ impl<A: Asset> LoadedAsset<A> {
|
||||
value,
|
||||
dependencies,
|
||||
loader_dependencies: HashMap::default(),
|
||||
labeled_assets: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,19 +178,6 @@ impl<A: Asset> LoadedAsset<A> {
|
||||
pub fn get(&self) -> &A {
|
||||
&self.value
|
||||
}
|
||||
|
||||
/// Returns the [`ErasedLoadedAsset`] for the given label, if it exists.
|
||||
pub fn get_labeled(
|
||||
&self,
|
||||
label: impl Into<CowArc<'static, str>>,
|
||||
) -> Option<&ErasedLoadedAsset> {
|
||||
self.labeled_assets.get(&label.into()).map(|a| &a.asset)
|
||||
}
|
||||
|
||||
/// Iterate over all labels for "labeled assets" in the loaded asset
|
||||
pub fn iter_labels(&self) -> impl Iterator<Item = &str> {
|
||||
self.labeled_assets.keys().map(|s| &**s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Asset> From<A> for LoadedAsset<A> {
|
||||
@ -205,7 +191,6 @@ pub struct ErasedLoadedAsset {
|
||||
pub(crate) value: Box<dyn AssetContainer>,
|
||||
pub(crate) dependencies: HashSet<UntypedAssetId>,
|
||||
pub(crate) loader_dependencies: HashMap<AssetPath<'static>, AssetHash>,
|
||||
pub(crate) labeled_assets: HashMap<CowArc<'static, str>, LabeledAsset>,
|
||||
}
|
||||
|
||||
impl<A: Asset> From<LoadedAsset<A>> for ErasedLoadedAsset {
|
||||
@ -214,7 +199,6 @@ impl<A: Asset> From<LoadedAsset<A>> for ErasedLoadedAsset {
|
||||
value: Box::new(asset.value),
|
||||
dependencies: asset.dependencies,
|
||||
loader_dependencies: asset.loader_dependencies,
|
||||
labeled_assets: asset.labeled_assets,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -241,19 +225,6 @@ impl ErasedLoadedAsset {
|
||||
self.value.asset_type_name()
|
||||
}
|
||||
|
||||
/// Returns the [`ErasedLoadedAsset`] for the given label, if it exists.
|
||||
pub fn get_labeled(
|
||||
&self,
|
||||
label: impl Into<CowArc<'static, str>>,
|
||||
) -> Option<&ErasedLoadedAsset> {
|
||||
self.labeled_assets.get(&label.into()).map(|a| &a.asset)
|
||||
}
|
||||
|
||||
/// Iterate over all labels for "labeled assets" in the loaded asset
|
||||
pub fn iter_labels(&self) -> impl Iterator<Item = &str> {
|
||||
self.labeled_assets.keys().map(|s| &**s)
|
||||
}
|
||||
|
||||
/// Cast this loaded asset as the given type. If the type does not match,
|
||||
/// the original type-erased asset is returned.
|
||||
pub fn downcast<A: Asset>(mut self) -> Result<LoadedAsset<A>, ErasedLoadedAsset> {
|
||||
@ -262,7 +233,6 @@ impl ErasedLoadedAsset {
|
||||
value: *value,
|
||||
dependencies: self.dependencies,
|
||||
loader_dependencies: self.loader_dependencies,
|
||||
labeled_assets: self.labeled_assets,
|
||||
}),
|
||||
Err(value) => {
|
||||
self.value = value;
|
||||
@ -290,6 +260,100 @@ impl<A: Asset> AssetContainer for A {
|
||||
}
|
||||
}
|
||||
|
||||
/// A loaded asset and all its loaded subassets.
|
||||
pub struct CompleteLoadedAsset<A: Asset> {
|
||||
/// The loaded asset.
|
||||
pub(crate) asset: LoadedAsset<A>,
|
||||
/// The subassets by their label.
|
||||
pub(crate) labeled_assets: HashMap<CowArc<'static, str>, LabeledAsset>,
|
||||
}
|
||||
|
||||
impl<A: Asset> CompleteLoadedAsset<A> {
|
||||
/// Take ownership of the stored [`Asset`] value.
|
||||
pub fn take(self) -> A {
|
||||
self.asset.value
|
||||
}
|
||||
|
||||
/// Returns the stored asset.
|
||||
pub fn get_asset(&self) -> &LoadedAsset<A> {
|
||||
&self.asset
|
||||
}
|
||||
|
||||
/// Returns the [`ErasedLoadedAsset`] for the given label, if it exists.
|
||||
pub fn get_labeled(
|
||||
&self,
|
||||
label: impl Into<CowArc<'static, str>>,
|
||||
) -> Option<&ErasedLoadedAsset> {
|
||||
self.labeled_assets.get(&label.into()).map(|a| &a.asset)
|
||||
}
|
||||
|
||||
/// Iterate over all labels for "labeled assets" in the loaded asset
|
||||
pub fn iter_labels(&self) -> impl Iterator<Item = &str> {
|
||||
self.labeled_assets.keys().map(|s| &**s)
|
||||
}
|
||||
}
|
||||
|
||||
/// A "type erased / boxed" counterpart to [`CompleteLoadedAsset`]. This is used in places where the
|
||||
/// loaded type is not statically known.
|
||||
pub struct CompleteErasedLoadedAsset {
|
||||
/// The loaded asset.
|
||||
pub(crate) asset: ErasedLoadedAsset,
|
||||
/// The subassets by their label.
|
||||
pub(crate) labeled_assets: HashMap<CowArc<'static, str>, LabeledAsset>,
|
||||
}
|
||||
|
||||
impl CompleteErasedLoadedAsset {
|
||||
/// Cast (and take ownership) of the [`Asset`] value of the given type. This will return
|
||||
/// [`Some`] if the stored type matches `A` and [`None`] if it does not.
|
||||
pub fn take<A: Asset>(self) -> Option<A> {
|
||||
self.asset.take()
|
||||
}
|
||||
|
||||
/// Returns the stored asset.
|
||||
pub fn get_asset(&self) -> &ErasedLoadedAsset {
|
||||
&self.asset
|
||||
}
|
||||
|
||||
/// Returns the [`ErasedLoadedAsset`] for the given label, if it exists.
|
||||
pub fn get_labeled(
|
||||
&self,
|
||||
label: impl Into<CowArc<'static, str>>,
|
||||
) -> Option<&ErasedLoadedAsset> {
|
||||
self.labeled_assets.get(&label.into()).map(|a| &a.asset)
|
||||
}
|
||||
|
||||
/// Iterate over all labels for "labeled assets" in the loaded asset
|
||||
pub fn iter_labels(&self) -> impl Iterator<Item = &str> {
|
||||
self.labeled_assets.keys().map(|s| &**s)
|
||||
}
|
||||
|
||||
/// Cast this loaded asset as the given type. If the type does not match,
|
||||
/// the original type-erased asset is returned.
|
||||
pub fn downcast<A: Asset>(
|
||||
mut self,
|
||||
) -> Result<CompleteLoadedAsset<A>, CompleteErasedLoadedAsset> {
|
||||
match self.asset.downcast::<A>() {
|
||||
Ok(asset) => Ok(CompleteLoadedAsset {
|
||||
asset,
|
||||
labeled_assets: self.labeled_assets,
|
||||
}),
|
||||
Err(asset) => {
|
||||
self.asset = asset;
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Asset> From<CompleteLoadedAsset<A>> for CompleteErasedLoadedAsset {
|
||||
fn from(value: CompleteLoadedAsset<A>) -> Self {
|
||||
Self {
|
||||
asset: value.asset.into(),
|
||||
labeled_assets: value.labeled_assets,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that occurs when attempting to call [`NestedLoader::load`] which
|
||||
/// is configured to work [immediately].
|
||||
///
|
||||
@ -397,8 +461,8 @@ impl<'a> LoadContext<'a> {
|
||||
) -> Handle<A> {
|
||||
let mut context = self.begin_labeled_asset();
|
||||
let asset = load(&mut context);
|
||||
let loaded_asset = context.finish(asset);
|
||||
self.add_loaded_labeled_asset(label, loaded_asset)
|
||||
let complete_asset = context.finish(asset);
|
||||
self.add_loaded_labeled_asset(label, complete_asset)
|
||||
}
|
||||
|
||||
/// This will add the given `asset` as a "labeled [`Asset`]" with the `label` label.
|
||||
@ -423,10 +487,14 @@ impl<'a> LoadContext<'a> {
|
||||
pub fn add_loaded_labeled_asset<A: Asset>(
|
||||
&mut self,
|
||||
label: impl Into<CowArc<'static, str>>,
|
||||
loaded_asset: LoadedAsset<A>,
|
||||
loaded_asset: CompleteLoadedAsset<A>,
|
||||
) -> Handle<A> {
|
||||
let label = label.into();
|
||||
let loaded_asset: ErasedLoadedAsset = loaded_asset.into();
|
||||
let CompleteLoadedAsset {
|
||||
asset,
|
||||
labeled_assets,
|
||||
} = loaded_asset;
|
||||
let loaded_asset: ErasedLoadedAsset = asset.into();
|
||||
let labeled_path = self.asset_path.clone().with_label(label.clone());
|
||||
let handle = self
|
||||
.asset_server
|
||||
@ -438,6 +506,11 @@ impl<'a> LoadContext<'a> {
|
||||
handle: handle.clone().untyped(),
|
||||
},
|
||||
);
|
||||
for (label, asset) in labeled_assets {
|
||||
if self.labeled_assets.insert(label.clone(), asset).is_some() {
|
||||
warn!("A labeled asset with the label \"{label}\" already exists. Replacing with the new asset.");
|
||||
}
|
||||
}
|
||||
handle
|
||||
}
|
||||
|
||||
@ -450,11 +523,13 @@ impl<'a> LoadContext<'a> {
|
||||
}
|
||||
|
||||
/// "Finishes" this context by populating the final [`Asset`] value.
|
||||
pub fn finish<A: Asset>(self, value: A) -> LoadedAsset<A> {
|
||||
LoadedAsset {
|
||||
value,
|
||||
dependencies: self.dependencies,
|
||||
loader_dependencies: self.loader_dependencies,
|
||||
pub fn finish<A: Asset>(self, value: A) -> CompleteLoadedAsset<A> {
|
||||
CompleteLoadedAsset {
|
||||
asset: LoadedAsset {
|
||||
value,
|
||||
dependencies: self.dependencies,
|
||||
loader_dependencies: self.loader_dependencies,
|
||||
},
|
||||
labeled_assets: self.labeled_assets,
|
||||
}
|
||||
}
|
||||
@ -525,8 +600,8 @@ impl<'a> LoadContext<'a> {
|
||||
meta: &dyn AssetMetaDyn,
|
||||
loader: &dyn ErasedAssetLoader,
|
||||
reader: &mut dyn Reader,
|
||||
) -> Result<ErasedLoadedAsset, LoadDirectError> {
|
||||
let loaded_asset = self
|
||||
) -> Result<CompleteErasedLoadedAsset, LoadDirectError> {
|
||||
let complete_asset = self
|
||||
.asset_server
|
||||
.load_with_meta_loader_and_reader(
|
||||
&path,
|
||||
@ -544,7 +619,7 @@ impl<'a> LoadContext<'a> {
|
||||
let info = meta.processed_info().as_ref();
|
||||
let hash = info.map(|i| i.full_hash).unwrap_or_default();
|
||||
self.loader_dependencies.insert(path, hash);
|
||||
Ok(loaded_asset)
|
||||
Ok(complete_asset)
|
||||
}
|
||||
|
||||
/// Create a builder for loading nested assets in this context.
|
||||
|
@ -4,8 +4,8 @@
|
||||
use crate::{
|
||||
io::Reader,
|
||||
meta::{meta_transform_settings, AssetMetaDyn, MetaTransform, Settings},
|
||||
Asset, AssetLoadError, AssetPath, ErasedAssetLoader, ErasedLoadedAsset, Handle, LoadContext,
|
||||
LoadDirectError, LoadedAsset, LoadedUntypedAsset, UntypedHandle,
|
||||
Asset, AssetLoadError, AssetPath, CompleteErasedLoadedAsset, CompleteLoadedAsset,
|
||||
ErasedAssetLoader, Handle, LoadContext, LoadDirectError, LoadedUntypedAsset, UntypedHandle,
|
||||
};
|
||||
use alloc::{borrow::ToOwned, boxed::Box, sync::Arc};
|
||||
use core::any::TypeId;
|
||||
@ -57,11 +57,11 @@ impl ReaderRef<'_> {
|
||||
/// If you know the type ID of the asset at runtime, but not at compile time,
|
||||
/// use [`with_dynamic_type`] followed by [`load`] to start loading an asset
|
||||
/// of that type. This lets you get an [`UntypedHandle`] (via [`Deferred`]),
|
||||
/// or a [`ErasedLoadedAsset`] (via [`Immediate`]).
|
||||
/// or a [`CompleteErasedLoadedAsset`] (via [`Immediate`]).
|
||||
///
|
||||
/// - in [`UnknownTyped`]: loading either a type-erased version of the asset
|
||||
/// ([`ErasedLoadedAsset`]), or a handle *to a handle* of the actual asset
|
||||
/// ([`LoadedUntypedAsset`]).
|
||||
/// ([`CompleteErasedLoadedAsset`]), or a handle *to a handle* of the actual
|
||||
/// asset ([`LoadedUntypedAsset`]).
|
||||
///
|
||||
/// If you have no idea what type of asset you will be loading (not even at
|
||||
/// runtime with a [`TypeId`]), use this.
|
||||
@ -386,7 +386,7 @@ impl<'builder, 'reader, T> NestedLoader<'_, '_, T, Immediate<'builder, 'reader>>
|
||||
self,
|
||||
path: &AssetPath<'static>,
|
||||
asset_type_id: Option<TypeId>,
|
||||
) -> Result<(Arc<dyn ErasedAssetLoader>, ErasedLoadedAsset), LoadDirectError> {
|
||||
) -> Result<(Arc<dyn ErasedAssetLoader>, CompleteErasedLoadedAsset), LoadDirectError> {
|
||||
let (mut meta, loader, mut reader) = if let Some(reader) = self.mode.reader {
|
||||
let loader = if let Some(asset_type_id) = asset_type_id {
|
||||
self.load_context
|
||||
@ -448,7 +448,7 @@ impl NestedLoader<'_, '_, StaticTyped, Immediate<'_, '_>> {
|
||||
pub async fn load<'p, A: Asset>(
|
||||
self,
|
||||
path: impl Into<AssetPath<'p>>,
|
||||
) -> Result<LoadedAsset<A>, LoadDirectError> {
|
||||
) -> Result<CompleteLoadedAsset<A>, LoadDirectError> {
|
||||
let path = path.into().into_owned();
|
||||
self.load_internal(&path, Some(TypeId::of::<A>()))
|
||||
.await
|
||||
@ -476,7 +476,7 @@ impl NestedLoader<'_, '_, DynamicTyped, Immediate<'_, '_>> {
|
||||
pub async fn load<'p>(
|
||||
self,
|
||||
path: impl Into<AssetPath<'p>>,
|
||||
) -> Result<ErasedLoadedAsset, LoadDirectError> {
|
||||
) -> Result<CompleteErasedLoadedAsset, LoadDirectError> {
|
||||
let path = path.into().into_owned();
|
||||
let asset_type_id = Some(self.typing.asset_type_id);
|
||||
self.load_internal(&path, asset_type_id)
|
||||
@ -492,7 +492,7 @@ impl NestedLoader<'_, '_, UnknownTyped, Immediate<'_, '_>> {
|
||||
pub async fn load<'p>(
|
||||
self,
|
||||
path: impl Into<AssetPath<'p>>,
|
||||
) -> Result<ErasedLoadedAsset, LoadDirectError> {
|
||||
) -> Result<CompleteErasedLoadedAsset, LoadDirectError> {
|
||||
let path = path.into().into_owned();
|
||||
self.load_internal(&path, None)
|
||||
.await
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
processor::AssetProcessor,
|
||||
saver::{AssetSaver, SavedAsset},
|
||||
transformer::{AssetTransformer, IdentityAssetTransformer, TransformedAsset},
|
||||
AssetLoadError, AssetLoader, AssetPath, DeserializeMetaError, ErasedLoadedAsset,
|
||||
AssetLoadError, AssetLoader, AssetPath, CompleteErasedLoadedAsset, DeserializeMetaError,
|
||||
MissingAssetLoaderForExtensionError, MissingAssetLoaderForTypeNameError,
|
||||
};
|
||||
use alloc::{
|
||||
@ -305,15 +305,15 @@ impl<'a> ProcessContext<'a> {
|
||||
pub async fn load_source_asset<L: AssetLoader>(
|
||||
&mut self,
|
||||
meta: AssetMeta<L, ()>,
|
||||
) -> Result<ErasedLoadedAsset, AssetLoadError> {
|
||||
) -> Result<CompleteErasedLoadedAsset, AssetLoadError> {
|
||||
let server = &self.processor.server;
|
||||
let loader_name = core::any::type_name::<L>();
|
||||
let loader = server.get_asset_loader_with_type_name(loader_name).await?;
|
||||
let mut reader = SliceReader::new(self.asset_bytes);
|
||||
let loaded_asset = server
|
||||
let complete_asset = server
|
||||
.load_with_meta_loader_and_reader(self.path, &meta, &*loader, &mut reader, false, true)
|
||||
.await?;
|
||||
for (path, full_hash) in &loaded_asset.loader_dependencies {
|
||||
for (path, full_hash) in &complete_asset.asset.loader_dependencies {
|
||||
self.new_processed_info
|
||||
.process_dependencies
|
||||
.push(ProcessDependencyInfo {
|
||||
@ -321,7 +321,7 @@ impl<'a> ProcessContext<'a> {
|
||||
path: path.to_owned(),
|
||||
});
|
||||
}
|
||||
Ok(loaded_asset)
|
||||
Ok(complete_asset)
|
||||
}
|
||||
|
||||
/// The path of the asset being processed.
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
io::Writer, meta::Settings, transformer::TransformedAsset, Asset, AssetLoader,
|
||||
ErasedLoadedAsset, Handle, LabeledAsset, UntypedHandle,
|
||||
CompleteErasedLoadedAsset, ErasedLoadedAsset, Handle, LabeledAsset, UntypedHandle,
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
use atomicow::CowArc;
|
||||
@ -44,7 +44,7 @@ pub trait ErasedAssetSaver: Send + Sync + 'static {
|
||||
fn save<'a>(
|
||||
&'a self,
|
||||
writer: &'a mut Writer,
|
||||
asset: &'a ErasedLoadedAsset,
|
||||
complete_asset: &'a CompleteErasedLoadedAsset,
|
||||
settings: &'a dyn Settings,
|
||||
) -> BoxedFuture<'a, Result<(), Box<dyn core::error::Error + Send + Sync + 'static>>>;
|
||||
|
||||
@ -56,14 +56,14 @@ impl<S: AssetSaver> ErasedAssetSaver for S {
|
||||
fn save<'a>(
|
||||
&'a self,
|
||||
writer: &'a mut Writer,
|
||||
asset: &'a ErasedLoadedAsset,
|
||||
complete_asset: &'a CompleteErasedLoadedAsset,
|
||||
settings: &'a dyn Settings,
|
||||
) -> BoxedFuture<'a, Result<(), Box<dyn core::error::Error + Send + Sync + 'static>>> {
|
||||
Box::pin(async move {
|
||||
let settings = settings
|
||||
.downcast_ref::<S::Settings>()
|
||||
.expect("AssetLoader settings should match the loader type");
|
||||
let saved_asset = SavedAsset::<S::Asset>::from_loaded(asset).unwrap();
|
||||
let saved_asset = SavedAsset::<S::Asset>::from_loaded(complete_asset).unwrap();
|
||||
if let Err(err) = self.save(writer, saved_asset, settings).await {
|
||||
return Err(err.into());
|
||||
}
|
||||
@ -91,11 +91,11 @@ impl<'a, A: Asset> Deref for SavedAsset<'a, A> {
|
||||
|
||||
impl<'a, A: Asset> SavedAsset<'a, A> {
|
||||
/// Creates a new [`SavedAsset`] from `asset` if its internal value matches `A`.
|
||||
pub fn from_loaded(asset: &'a ErasedLoadedAsset) -> Option<Self> {
|
||||
let value = asset.value.downcast_ref::<A>()?;
|
||||
pub fn from_loaded(complete_asset: &'a CompleteErasedLoadedAsset) -> Option<Self> {
|
||||
let value = complete_asset.asset.value.downcast_ref::<A>()?;
|
||||
Some(SavedAsset {
|
||||
value,
|
||||
labeled_assets: &asset.labeled_assets,
|
||||
labeled_assets: &complete_asset.labeled_assets,
|
||||
})
|
||||
}
|
||||
|
||||
@ -114,17 +114,13 @@ impl<'a, A: Asset> SavedAsset<'a, A> {
|
||||
}
|
||||
|
||||
/// Returns the labeled asset, if it exists and matches this type.
|
||||
pub fn get_labeled<B: Asset, Q>(&self, label: &Q) -> Option<SavedAsset<B>>
|
||||
pub fn get_labeled<B: Asset, Q>(&self, label: &Q) -> Option<&B>
|
||||
where
|
||||
CowArc<'static, str>: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
let labeled = self.labeled_assets.get(label)?;
|
||||
let value = labeled.asset.value.downcast_ref::<B>()?;
|
||||
Some(SavedAsset {
|
||||
value,
|
||||
labeled_assets: &labeled.asset.labeled_assets,
|
||||
})
|
||||
labeled.asset.value.downcast_ref::<B>()
|
||||
}
|
||||
|
||||
/// Returns the type-erased labeled asset, if it exists and matches this type.
|
||||
|
@ -14,8 +14,8 @@ use crate::{
|
||||
},
|
||||
path::AssetPath,
|
||||
Asset, AssetEvent, AssetHandleProvider, AssetId, AssetLoadFailedEvent, AssetMetaCheck, Assets,
|
||||
DeserializeMetaError, ErasedLoadedAsset, Handle, LoadedUntypedAsset, UntypedAssetId,
|
||||
UntypedAssetLoadFailedEvent, UntypedHandle,
|
||||
CompleteErasedLoadedAsset, DeserializeMetaError, ErasedLoadedAsset, Handle, LoadedUntypedAsset,
|
||||
UntypedAssetId, UntypedAssetLoadFailedEvent, UntypedHandle,
|
||||
};
|
||||
use alloc::{borrow::ToOwned, boxed::Box, vec, vec::Vec};
|
||||
use alloc::{
|
||||
@ -697,12 +697,18 @@ impl AssetServer {
|
||||
|
||||
/// Sends a load event for the given `loaded_asset` and does the same recursively for all
|
||||
/// labeled assets.
|
||||
fn send_loaded_asset(&self, id: UntypedAssetId, mut loaded_asset: ErasedLoadedAsset) {
|
||||
for (_, labeled_asset) in loaded_asset.labeled_assets.drain() {
|
||||
self.send_loaded_asset(labeled_asset.handle.id(), labeled_asset.asset);
|
||||
fn send_loaded_asset(&self, id: UntypedAssetId, mut complete_asset: CompleteErasedLoadedAsset) {
|
||||
for (_, labeled_asset) in complete_asset.labeled_assets.drain() {
|
||||
self.send_asset_event(InternalAssetEvent::Loaded {
|
||||
id: labeled_asset.handle.id(),
|
||||
loaded_asset: labeled_asset.asset,
|
||||
});
|
||||
}
|
||||
|
||||
self.send_asset_event(InternalAssetEvent::Loaded { id, loaded_asset });
|
||||
self.send_asset_event(InternalAssetEvent::Loaded {
|
||||
id,
|
||||
loaded_asset: complete_asset.asset,
|
||||
});
|
||||
}
|
||||
|
||||
/// Kicks off a reload of the asset stored at the given path. This will only reload the asset if it currently loaded.
|
||||
@ -1326,7 +1332,7 @@ impl AssetServer {
|
||||
reader: &mut dyn Reader,
|
||||
load_dependencies: bool,
|
||||
populate_hashes: bool,
|
||||
) -> Result<ErasedLoadedAsset, AssetLoadError> {
|
||||
) -> Result<CompleteErasedLoadedAsset, AssetLoadError> {
|
||||
// TODO: experiment with this
|
||||
let asset_path = asset_path.clone_owned();
|
||||
let load_context =
|
||||
|
@ -1,4 +1,7 @@
|
||||
use crate::{meta::Settings, Asset, ErasedLoadedAsset, Handle, LabeledAsset, UntypedHandle};
|
||||
use crate::{
|
||||
meta::Settings, Asset, CompleteErasedLoadedAsset, ErasedLoadedAsset, Handle, LabeledAsset,
|
||||
UntypedHandle,
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
use atomicow::CowArc;
|
||||
use bevy_platform_support::collections::HashMap;
|
||||
@ -56,11 +59,11 @@ impl<A: Asset> DerefMut for TransformedAsset<A> {
|
||||
|
||||
impl<A: Asset> TransformedAsset<A> {
|
||||
/// Creates a new [`TransformedAsset`] from `asset` if its internal value matches `A`.
|
||||
pub fn from_loaded(asset: ErasedLoadedAsset) -> Option<Self> {
|
||||
if let Ok(value) = asset.value.downcast::<A>() {
|
||||
pub fn from_loaded(complete_asset: CompleteErasedLoadedAsset) -> Option<Self> {
|
||||
if let Ok(value) = complete_asset.asset.value.downcast::<A>() {
|
||||
return Some(TransformedAsset {
|
||||
value: *value,
|
||||
labeled_assets: asset.labeled_assets,
|
||||
labeled_assets: complete_asset.labeled_assets,
|
||||
});
|
||||
}
|
||||
None
|
||||
@ -87,117 +90,13 @@ impl<A: Asset> TransformedAsset<A> {
|
||||
&mut self.value
|
||||
}
|
||||
/// Returns the labeled asset, if it exists and matches this type.
|
||||
pub fn get_labeled<B: Asset, Q>(&mut self, label: &Q) -> Option<TransformedSubAsset<B>>
|
||||
pub fn get_labeled<B: Asset, Q>(&mut self, label: &'_ Q) -> Option<&mut B>
|
||||
where
|
||||
CowArc<'static, str>: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
let labeled = self.labeled_assets.get_mut(label)?;
|
||||
let value = labeled.asset.value.downcast_mut::<B>()?;
|
||||
Some(TransformedSubAsset {
|
||||
value,
|
||||
labeled_assets: &mut labeled.asset.labeled_assets,
|
||||
})
|
||||
}
|
||||
/// Returns the type-erased labeled asset, if it exists and matches this type.
|
||||
pub fn get_erased_labeled<Q>(&self, label: &Q) -> Option<&ErasedLoadedAsset>
|
||||
where
|
||||
CowArc<'static, str>: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
let labeled = self.labeled_assets.get(label)?;
|
||||
Some(&labeled.asset)
|
||||
}
|
||||
/// Returns the [`UntypedHandle`] of the labeled asset with the provided 'label', if it exists.
|
||||
pub fn get_untyped_handle<Q>(&self, label: &Q) -> Option<UntypedHandle>
|
||||
where
|
||||
CowArc<'static, str>: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
let labeled = self.labeled_assets.get(label)?;
|
||||
Some(labeled.handle.clone())
|
||||
}
|
||||
/// Returns the [`Handle`] of the labeled asset with the provided 'label', if it exists and is an asset of type `B`
|
||||
pub fn get_handle<Q, B: Asset>(&self, label: &Q) -> Option<Handle<B>>
|
||||
where
|
||||
CowArc<'static, str>: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
let labeled = self.labeled_assets.get(label)?;
|
||||
if let Ok(handle) = labeled.handle.clone().try_typed::<B>() {
|
||||
return Some(handle);
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Adds `asset` as a labeled sub asset using `label` and `handle`
|
||||
pub fn insert_labeled(
|
||||
&mut self,
|
||||
label: impl Into<CowArc<'static, str>>,
|
||||
handle: impl Into<UntypedHandle>,
|
||||
asset: impl Into<ErasedLoadedAsset>,
|
||||
) {
|
||||
let labeled = LabeledAsset {
|
||||
asset: asset.into(),
|
||||
handle: handle.into(),
|
||||
};
|
||||
self.labeled_assets.insert(label.into(), labeled);
|
||||
}
|
||||
/// Iterate over all labels for "labeled assets" in the loaded asset
|
||||
pub fn iter_labels(&self) -> impl Iterator<Item = &str> {
|
||||
self.labeled_assets.keys().map(|s| &**s)
|
||||
}
|
||||
}
|
||||
|
||||
/// A labeled sub-asset of [`TransformedAsset`]
|
||||
pub struct TransformedSubAsset<'a, A: Asset> {
|
||||
value: &'a mut A,
|
||||
labeled_assets: &'a mut HashMap<CowArc<'static, str>, LabeledAsset>,
|
||||
}
|
||||
|
||||
impl<'a, A: Asset> Deref for TransformedSubAsset<'a, A> {
|
||||
type Target = A;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Asset> DerefMut for TransformedSubAsset<'a, A> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: Asset> TransformedSubAsset<'a, A> {
|
||||
/// Creates a new [`TransformedSubAsset`] from `asset` if its internal value matches `A`.
|
||||
pub fn from_loaded(asset: &'a mut ErasedLoadedAsset) -> Option<Self> {
|
||||
let value = asset.value.downcast_mut::<A>()?;
|
||||
Some(TransformedSubAsset {
|
||||
value,
|
||||
labeled_assets: &mut asset.labeled_assets,
|
||||
})
|
||||
}
|
||||
/// Retrieves the value of this asset.
|
||||
#[inline]
|
||||
pub fn get(&self) -> &A {
|
||||
self.value
|
||||
}
|
||||
/// Mutably retrieves the value of this asset.
|
||||
#[inline]
|
||||
pub fn get_mut(&mut self) -> &mut A {
|
||||
self.value
|
||||
}
|
||||
/// Returns the labeled asset, if it exists and matches this type.
|
||||
pub fn get_labeled<B: Asset, Q>(&mut self, label: &Q) -> Option<TransformedSubAsset<B>>
|
||||
where
|
||||
CowArc<'static, str>: Borrow<Q>,
|
||||
Q: ?Sized + Hash + Eq,
|
||||
{
|
||||
let labeled = self.labeled_assets.get_mut(label)?;
|
||||
let value = labeled.asset.value.downcast_mut::<B>()?;
|
||||
Some(TransformedSubAsset {
|
||||
value,
|
||||
labeled_assets: &mut labeled.asset.labeled_assets,
|
||||
})
|
||||
labeled.asset.value.downcast_mut::<B>()
|
||||
}
|
||||
/// Returns the type-erased labeled asset, if it exists and matches this type.
|
||||
pub fn get_erased_labeled<Q>(&self, label: &Q) -> Option<&ErasedLoadedAsset>
|
||||
|
@ -3,7 +3,7 @@
|
||||
use bevy::{
|
||||
asset::{
|
||||
io::{Reader, VecReader},
|
||||
AssetLoader, ErasedLoadedAsset, LoadContext, LoadDirectError,
|
||||
AssetLoader, CompleteErasedLoadedAsset, LoadContext, LoadDirectError,
|
||||
},
|
||||
prelude::*,
|
||||
reflect::TypePath,
|
||||
@ -14,7 +14,7 @@ use thiserror::Error;
|
||||
|
||||
#[derive(Asset, TypePath)]
|
||||
struct GzAsset {
|
||||
uncompressed: ErasedLoadedAsset,
|
||||
uncompressed: CompleteErasedLoadedAsset,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -149,15 +149,15 @@ impl AssetLoader for CoolTextLoader {
|
||||
let ron: CoolTextRon = ron::de::from_bytes(&bytes)?;
|
||||
let mut base_text = ron.text;
|
||||
for embedded in ron.embedded_dependencies {
|
||||
let loaded = load_context
|
||||
let complete_loaded = load_context
|
||||
.loader()
|
||||
.immediate()
|
||||
.load::<Text>(&embedded)
|
||||
.await?;
|
||||
base_text.push_str(&loaded.get().0);
|
||||
base_text.push_str(&complete_loaded.get_asset().get().0);
|
||||
}
|
||||
for (path, settings_override) in ron.dependencies_with_settings {
|
||||
let loaded = load_context
|
||||
let complete_loaded = load_context
|
||||
.loader()
|
||||
.with_settings(move |settings| {
|
||||
*settings = settings_override.clone();
|
||||
@ -165,7 +165,7 @@ impl AssetLoader for CoolTextLoader {
|
||||
.immediate()
|
||||
.load::<Text>(&path)
|
||||
.await?;
|
||||
base_text.push_str(&loaded.get().0);
|
||||
base_text.push_str(&complete_loaded.get_asset().get().0);
|
||||
}
|
||||
Ok(CoolText {
|
||||
text: base_text,
|
||||
|
Loading…
Reference in New Issue
Block a user