@@ -13,6 +13,7 @@ use alloc::{
13
13
} ;
14
14
use atomicow:: CowArc ;
15
15
use bevy_ecs:: world:: World ;
16
+ use bevy_log:: warn;
16
17
use bevy_platform_support:: collections:: { HashMap , HashSet } ;
17
18
use bevy_tasks:: { BoxedFuture , ConditionalSendFuture } ;
18
19
use core:: any:: { Any , TypeId } ;
@@ -60,7 +61,7 @@ pub trait ErasedAssetLoader: Send + Sync + 'static {
60
61
load_context : LoadContext < ' a > ,
61
62
) -> BoxedFuture <
62
63
' a ,
63
- Result < ErasedLoadedAsset , Box < dyn core:: error:: Error + Send + Sync + ' static > > ,
64
+ Result < CompleteErasedLoadedAsset , Box < dyn core:: error:: Error + Send + Sync + ' static > > ,
64
65
> ;
65
66
66
67
/// Returns a list of extensions supported by this asset loader, without the preceding dot.
91
92
mut load_context : LoadContext < ' a > ,
92
93
) -> BoxedFuture <
93
94
' a ,
94
- Result < ErasedLoadedAsset , Box < dyn core:: error:: Error + Send + Sync + ' static > > ,
95
+ Result < CompleteErasedLoadedAsset , Box < dyn core:: error:: Error + Send + Sync + ' static > > ,
95
96
> {
96
97
Box :: pin ( async move {
97
98
let settings = meta
@@ -152,7 +153,6 @@ pub struct LoadedAsset<A: Asset> {
152
153
pub ( crate ) value : A ,
153
154
pub ( crate ) dependencies : HashSet < UntypedAssetId > ,
154
155
pub ( crate ) loader_dependencies : HashMap < AssetPath < ' static > , AssetHash > ,
155
- pub ( crate ) labeled_assets : HashMap < CowArc < ' static , str > , LabeledAsset > ,
156
156
}
157
157
158
158
impl < A : Asset > LoadedAsset < A > {
@@ -166,7 +166,6 @@ impl<A: Asset> LoadedAsset<A> {
166
166
value,
167
167
dependencies,
168
168
loader_dependencies : HashMap :: default ( ) ,
169
- labeled_assets : HashMap :: default ( ) ,
170
169
}
171
170
}
172
171
@@ -179,19 +178,6 @@ impl<A: Asset> LoadedAsset<A> {
179
178
pub fn get ( & self ) -> & A {
180
179
& self . value
181
180
}
182
-
183
- /// Returns the [`ErasedLoadedAsset`] for the given label, if it exists.
184
- pub fn get_labeled (
185
- & self ,
186
- label : impl Into < CowArc < ' static , str > > ,
187
- ) -> Option < & ErasedLoadedAsset > {
188
- self . labeled_assets . get ( & label. into ( ) ) . map ( |a| & a. asset )
189
- }
190
-
191
- /// Iterate over all labels for "labeled assets" in the loaded asset
192
- pub fn iter_labels ( & self ) -> impl Iterator < Item = & str > {
193
- self . labeled_assets . keys ( ) . map ( |s| & * * s)
194
- }
195
181
}
196
182
197
183
impl < A : Asset > From < A > for LoadedAsset < A > {
@@ -205,7 +191,6 @@ pub struct ErasedLoadedAsset {
205
191
pub ( crate ) value : Box < dyn AssetContainer > ,
206
192
pub ( crate ) dependencies : HashSet < UntypedAssetId > ,
207
193
pub ( crate ) loader_dependencies : HashMap < AssetPath < ' static > , AssetHash > ,
208
- pub ( crate ) labeled_assets : HashMap < CowArc < ' static , str > , LabeledAsset > ,
209
194
}
210
195
211
196
impl < A : Asset > From < LoadedAsset < A > > for ErasedLoadedAsset {
@@ -214,7 +199,6 @@ impl<A: Asset> From<LoadedAsset<A>> for ErasedLoadedAsset {
214
199
value : Box :: new ( asset. value ) ,
215
200
dependencies : asset. dependencies ,
216
201
loader_dependencies : asset. loader_dependencies ,
217
- labeled_assets : asset. labeled_assets ,
218
202
}
219
203
}
220
204
}
@@ -241,19 +225,6 @@ impl ErasedLoadedAsset {
241
225
self . value . asset_type_name ( )
242
226
}
243
227
244
- /// Returns the [`ErasedLoadedAsset`] for the given label, if it exists.
245
- pub fn get_labeled (
246
- & self ,
247
- label : impl Into < CowArc < ' static , str > > ,
248
- ) -> Option < & ErasedLoadedAsset > {
249
- self . labeled_assets . get ( & label. into ( ) ) . map ( |a| & a. asset )
250
- }
251
-
252
- /// Iterate over all labels for "labeled assets" in the loaded asset
253
- pub fn iter_labels ( & self ) -> impl Iterator < Item = & str > {
254
- self . labeled_assets . keys ( ) . map ( |s| & * * s)
255
- }
256
-
257
228
/// Cast this loaded asset as the given type. If the type does not match,
258
229
/// the original type-erased asset is returned.
259
230
pub fn downcast < A : Asset > ( mut self ) -> Result < LoadedAsset < A > , ErasedLoadedAsset > {
@@ -262,7 +233,6 @@ impl ErasedLoadedAsset {
262
233
value : * value,
263
234
dependencies : self . dependencies ,
264
235
loader_dependencies : self . loader_dependencies ,
265
- labeled_assets : self . labeled_assets ,
266
236
} ) ,
267
237
Err ( value) => {
268
238
self . value = value;
@@ -290,6 +260,100 @@ impl<A: Asset> AssetContainer for A {
290
260
}
291
261
}
292
262
263
+ /// A loaded asset and all its loaded subassets.
264
+ pub struct CompleteLoadedAsset < A : Asset > {
265
+ /// The loaded asset.
266
+ pub ( crate ) asset : LoadedAsset < A > ,
267
+ /// The subassets by their label.
268
+ pub ( crate ) labeled_assets : HashMap < CowArc < ' static , str > , LabeledAsset > ,
269
+ }
270
+
271
+ impl < A : Asset > CompleteLoadedAsset < A > {
272
+ /// Take ownership of the stored [`Asset`] value.
273
+ pub fn take ( self ) -> A {
274
+ self . asset . value
275
+ }
276
+
277
+ /// Returns the stored asset.
278
+ pub fn get_asset ( & self ) -> & LoadedAsset < A > {
279
+ & self . asset
280
+ }
281
+
282
+ /// Returns the [`ErasedLoadedAsset`] for the given label, if it exists.
283
+ pub fn get_labeled (
284
+ & self ,
285
+ label : impl Into < CowArc < ' static , str > > ,
286
+ ) -> Option < & ErasedLoadedAsset > {
287
+ self . labeled_assets . get ( & label. into ( ) ) . map ( |a| & a. asset )
288
+ }
289
+
290
+ /// Iterate over all labels for "labeled assets" in the loaded asset
291
+ pub fn iter_labels ( & self ) -> impl Iterator < Item = & str > {
292
+ self . labeled_assets . keys ( ) . map ( |s| & * * s)
293
+ }
294
+ }
295
+
296
+ /// A "type erased / boxed" counterpart to [`CompleteLoadedAsset`]. This is used in places where the
297
+ /// loaded type is not statically known.
298
+ pub struct CompleteErasedLoadedAsset {
299
+ /// The loaded asset.
300
+ pub ( crate ) asset : ErasedLoadedAsset ,
301
+ /// The subassets by their label.
302
+ pub ( crate ) labeled_assets : HashMap < CowArc < ' static , str > , LabeledAsset > ,
303
+ }
304
+
305
+ impl CompleteErasedLoadedAsset {
306
+ /// Cast (and take ownership) of the [`Asset`] value of the given type. This will return
307
+ /// [`Some`] if the stored type matches `A` and [`None`] if it does not.
308
+ pub fn take < A : Asset > ( self ) -> Option < A > {
309
+ self . asset . take ( )
310
+ }
311
+
312
+ /// Returns the stored asset.
313
+ pub fn get_asset ( & self ) -> & ErasedLoadedAsset {
314
+ & self . asset
315
+ }
316
+
317
+ /// Returns the [`ErasedLoadedAsset`] for the given label, if it exists.
318
+ pub fn get_labeled (
319
+ & self ,
320
+ label : impl Into < CowArc < ' static , str > > ,
321
+ ) -> Option < & ErasedLoadedAsset > {
322
+ self . labeled_assets . get ( & label. into ( ) ) . map ( |a| & a. asset )
323
+ }
324
+
325
+ /// Iterate over all labels for "labeled assets" in the loaded asset
326
+ pub fn iter_labels ( & self ) -> impl Iterator < Item = & str > {
327
+ self . labeled_assets . keys ( ) . map ( |s| & * * s)
328
+ }
329
+
330
+ /// Cast this loaded asset as the given type. If the type does not match,
331
+ /// the original type-erased asset is returned.
332
+ pub fn downcast < A : Asset > (
333
+ mut self ,
334
+ ) -> Result < CompleteLoadedAsset < A > , CompleteErasedLoadedAsset > {
335
+ match self . asset . downcast :: < A > ( ) {
336
+ Ok ( asset) => Ok ( CompleteLoadedAsset {
337
+ asset,
338
+ labeled_assets : self . labeled_assets ,
339
+ } ) ,
340
+ Err ( asset) => {
341
+ self . asset = asset;
342
+ Err ( self )
343
+ }
344
+ }
345
+ }
346
+ }
347
+
348
+ impl < A : Asset > From < CompleteLoadedAsset < A > > for CompleteErasedLoadedAsset {
349
+ fn from ( value : CompleteLoadedAsset < A > ) -> Self {
350
+ Self {
351
+ asset : value. asset . into ( ) ,
352
+ labeled_assets : value. labeled_assets ,
353
+ }
354
+ }
355
+ }
356
+
293
357
/// An error that occurs when attempting to call [`NestedLoader::load`] which
294
358
/// is configured to work [immediately].
295
359
///
@@ -397,8 +461,8 @@ impl<'a> LoadContext<'a> {
397
461
) -> Handle < A > {
398
462
let mut context = self . begin_labeled_asset ( ) ;
399
463
let asset = load ( & mut context) ;
400
- let loaded_asset = context. finish ( asset) ;
401
- self . add_loaded_labeled_asset ( label, loaded_asset )
464
+ let complete_asset = context. finish ( asset) ;
465
+ self . add_loaded_labeled_asset ( label, complete_asset )
402
466
}
403
467
404
468
/// This will add the given `asset` as a "labeled [`Asset`]" with the `label` label.
@@ -423,10 +487,14 @@ impl<'a> LoadContext<'a> {
423
487
pub fn add_loaded_labeled_asset < A : Asset > (
424
488
& mut self ,
425
489
label : impl Into < CowArc < ' static , str > > ,
426
- loaded_asset : LoadedAsset < A > ,
490
+ loaded_asset : CompleteLoadedAsset < A > ,
427
491
) -> Handle < A > {
428
492
let label = label. into ( ) ;
429
- let loaded_asset: ErasedLoadedAsset = loaded_asset. into ( ) ;
493
+ let CompleteLoadedAsset {
494
+ asset,
495
+ labeled_assets,
496
+ } = loaded_asset;
497
+ let loaded_asset: ErasedLoadedAsset = asset. into ( ) ;
430
498
let labeled_path = self . asset_path . clone ( ) . with_label ( label. clone ( ) ) ;
431
499
let handle = self
432
500
. asset_server
@@ -438,6 +506,11 @@ impl<'a> LoadContext<'a> {
438
506
handle : handle. clone ( ) . untyped ( ) ,
439
507
} ,
440
508
) ;
509
+ for ( label, asset) in labeled_assets {
510
+ if self . labeled_assets . insert ( label. clone ( ) , asset) . is_some ( ) {
511
+ warn ! ( "A labeled asset with the label \" {label}\" already exists. Replacing with the new asset." ) ;
512
+ }
513
+ }
441
514
handle
442
515
}
443
516
@@ -450,11 +523,13 @@ impl<'a> LoadContext<'a> {
450
523
}
451
524
452
525
/// "Finishes" this context by populating the final [`Asset`] value.
453
- pub fn finish < A : Asset > ( self , value : A ) -> LoadedAsset < A > {
454
- LoadedAsset {
455
- value,
456
- dependencies : self . dependencies ,
457
- loader_dependencies : self . loader_dependencies ,
526
+ pub fn finish < A : Asset > ( self , value : A ) -> CompleteLoadedAsset < A > {
527
+ CompleteLoadedAsset {
528
+ asset : LoadedAsset {
529
+ value,
530
+ dependencies : self . dependencies ,
531
+ loader_dependencies : self . loader_dependencies ,
532
+ } ,
458
533
labeled_assets : self . labeled_assets ,
459
534
}
460
535
}
@@ -525,8 +600,8 @@ impl<'a> LoadContext<'a> {
525
600
meta : & dyn AssetMetaDyn ,
526
601
loader : & dyn ErasedAssetLoader ,
527
602
reader : & mut dyn Reader ,
528
- ) -> Result < ErasedLoadedAsset , LoadDirectError > {
529
- let loaded_asset = self
603
+ ) -> Result < CompleteErasedLoadedAsset , LoadDirectError > {
604
+ let complete_asset = self
530
605
. asset_server
531
606
. load_with_meta_loader_and_reader (
532
607
& path,
@@ -544,7 +619,7 @@ impl<'a> LoadContext<'a> {
544
619
let info = meta. processed_info ( ) . as_ref ( ) ;
545
620
let hash = info. map ( |i| i. full_hash ) . unwrap_or_default ( ) ;
546
621
self . loader_dependencies . insert ( path, hash) ;
547
- Ok ( loaded_asset )
622
+ Ok ( complete_asset )
548
623
}
549
624
550
625
/// Create a builder for loading nested assets in this context.
0 commit comments