bevy/crates/bevy_asset/src/lib.rs
James Liu 012ae07dc8 Add global init and get accessors for all newtyped TaskPools (#2250)
Right now, a direct reference to the target TaskPool is required to launch tasks on the pools, despite the three newtyped pools (AsyncComputeTaskPool, ComputeTaskPool, and IoTaskPool) effectively acting as global instances. The need to pass a TaskPool reference adds notable friction to spawning subtasks within existing tasks. Possible use cases for this may include chaining tasks within the same pool like spawning separate send/receive I/O tasks after waiting on a network connection to be established, or allowing cross-pool dependent tasks like starting dependent multi-frame computations following a long I/O load. 

Other task execution runtimes provide static access to spawning tasks (i.e. `tokio::spawn`), which is notably easier to use than the reference passing required by `bevy_tasks` right now.

This PR makes does the following:

 * Adds `*TaskPool::init` which initializes a `OnceCell`'ed with a provided TaskPool. Failing if the pool has already been initialized.
 * Adds `*TaskPool::get` which fetches the initialized global pool of the respective type or panics. This generally should not be an issue in normal Bevy use, as the pools are initialized before they are accessed.
 * Updated default task pool initialization to either pull the global handles and save them as resources, or if they are already initialized, pull the a cloned global handle as the resource.

This should make it notably easier to build more complex task hierarchies for dependent tasks. It should also make writing bevy-adjacent, but not strictly bevy-only plugin crates easier, as the global pools ensure it's all running on the same threads.

One alternative considered is keeping a thread-local reference to the pool for all threads in each pool to enable the same `tokio::spawn` interface. This would spawn tasks on the same pool that a task is currently running in. However this potentially leads to potential footgun situations where long running blocking tasks run on `ComputeTaskPool`.
2022-06-09 02:43:24 +00:00

112 lines
3.3 KiB
Rust

mod asset_server;
mod assets;
#[cfg(feature = "debug_asset_server")]
pub mod debug_asset_server;
pub mod diagnostic;
#[cfg(all(
feature = "filesystem_watcher",
all(not(target_arch = "wasm32"), not(target_os = "android"))
))]
mod filesystem_watcher;
mod handle;
mod info;
mod io;
mod loader;
mod path;
pub mod prelude {
#[doc(hidden)]
pub use crate::{AddAsset, AssetEvent, AssetServer, Assets, Handle, HandleUntyped};
}
pub use asset_server::*;
pub use assets::*;
pub use bevy_utils::BoxedFuture;
pub use handle::*;
pub use info::*;
pub use io::*;
pub use loader::*;
pub use path::*;
use bevy_app::{prelude::Plugin, App};
use bevy_ecs::schedule::{StageLabel, SystemStage};
/// The names of asset stages in an App Schedule
#[derive(Debug, Hash, PartialEq, Eq, Clone, StageLabel)]
pub enum AssetStage {
LoadAssets,
AssetEvents,
}
/// Adds support for Assets to an App. Assets are typed collections with change tracking, which are
/// added as App Resources. Examples of assets: textures, sounds, 3d models, maps, scenes
#[derive(Default)]
pub struct AssetPlugin;
pub struct AssetServerSettings {
pub asset_folder: String,
/// Whether to watch for changes in asset files. Requires the `filesystem_watcher` feature,
/// and cannot be supported on the wasm32 arch nor android os.
pub watch_for_changes: bool,
}
impl Default for AssetServerSettings {
fn default() -> Self {
Self {
asset_folder: "assets".to_string(),
watch_for_changes: false,
}
}
}
/// Create an instance of the platform default `AssetIo`
///
/// This is useful when providing a custom `AssetIo` instance that needs to
/// delegate to the default `AssetIo` for the platform.
pub fn create_platform_default_asset_io(app: &mut App) -> Box<dyn AssetIo> {
let settings = app
.world
.get_resource_or_insert_with(AssetServerSettings::default);
#[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))]
let source = FileAssetIo::new(&settings.asset_folder, settings.watch_for_changes);
#[cfg(target_arch = "wasm32")]
let source = WasmAssetIo::new(&settings.asset_folder);
#[cfg(target_os = "android")]
let source = AndroidAssetIo::new(&settings.asset_folder);
Box::new(source)
}
impl Plugin for AssetPlugin {
fn build(&self, app: &mut App) {
if !app.world.contains_resource::<AssetServer>() {
let source = create_platform_default_asset_io(app);
let asset_server = AssetServer::with_boxed_io(source);
app.insert_resource(asset_server);
}
app.add_stage_before(
bevy_app::CoreStage::PreUpdate,
AssetStage::LoadAssets,
SystemStage::parallel(),
)
.add_stage_after(
bevy_app::CoreStage::PostUpdate,
AssetStage::AssetEvents,
SystemStage::parallel(),
)
.register_type::<HandleId>()
.add_system_to_stage(
bevy_app::CoreStage::PreUpdate,
asset_server::free_unused_assets_system,
);
#[cfg(all(
feature = "filesystem_watcher",
all(not(target_arch = "wasm32"), not(target_os = "android"))
))]
app.add_system_to_stage(AssetStage::LoadAssets, io::filesystem_watcher_system);
}
}