//! A high-level way to load collections of asset handles as resources. // Taken from: https://github.com/TheBevyFlock/bevy_new_2d/blob/main/src/asset_tracking.rs use std::collections::VecDeque; use bevy::prelude::*; pub fn plugin(app: &mut App) { app.init_resource::(); app.add_systems(PreUpdate, load_resource_assets); } pub trait LoadResource { /// This will load the [`Resource`] as an [`Asset`]. When all of its asset dependencies /// have been loaded, it will be inserted as a resource. This ensures that the resource only /// exists when the assets are ready. fn load_resource(&mut self) -> &mut Self; } impl LoadResource for App { fn load_resource(&mut self) -> &mut Self { self.init_asset::(); let world = self.world_mut(); let value = T::from_world(world); let assets = world.resource::(); let handle = assets.add(value); let mut handles = world.resource_mut::(); handles .waiting .push_back((handle.untyped(), |world, handle| { let assets = world.resource::>(); if let Some(value) = assets.get(handle.id().typed::()) { world.insert_resource(value.clone()); } })); self } } /// A function that inserts a loaded resource. type InsertLoadedResource = fn(&mut World, &UntypedHandle); #[derive(Resource, Default)] pub struct ResourceHandles { // Use a queue for waiting assets so they can be cycled through and moved to // `finished` one at a time. waiting: VecDeque<(UntypedHandle, InsertLoadedResource)>, finished: Vec, } impl ResourceHandles { /// Returns true if all requested [`Asset`]s have finished loading and are available as [`Resource`]s. pub fn is_all_done(&self) -> bool { self.waiting.is_empty() } } fn load_resource_assets(world: &mut World) { world.resource_scope(|world, mut resource_handles: Mut| { world.resource_scope(|world, assets: Mut| { for _ in 0..resource_handles.waiting.len() { let (handle, insert_fn) = resource_handles.waiting.pop_front().unwrap(); if assets.is_loaded_with_dependencies(&handle) { insert_fn(world, &handle); resource_handles.finished.push(handle); } else { resource_handles.waiting.push_back((handle, insert_fn)); } } }); }); }