Merge 5b6ac36b50
into f964ee1e3a
This commit is contained in:
commit
eee6dccff4
@ -62,6 +62,8 @@ uuid = { version = "1.13.1", default-features = false, features = [
|
|||||||
"v4",
|
"v4",
|
||||||
"serde",
|
"serde",
|
||||||
] }
|
] }
|
||||||
|
glob = "0.3.2"
|
||||||
|
|
||||||
tracing = { version = "0.1", default-features = false }
|
tracing = { version = "0.1", default-features = false }
|
||||||
|
|
||||||
[target.'cfg(target_os = "android")'.dependencies]
|
[target.'cfg(target_os = "android")'.dependencies]
|
||||||
|
31
crates/bevy_asset/src/batch.rs
Normal file
31
crates/bevy_asset/src/batch.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use crate::{Asset, AssetPath, UntypedHandle};
|
||||||
|
use bevy_reflect::TypePath;
|
||||||
|
|
||||||
|
pub struct LoadBatchRequest {
|
||||||
|
pub requests: Vec<AssetPath<'static>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LoadBatchRequest {
|
||||||
|
pub fn new<T>(requests: Vec<T>) -> Self
|
||||||
|
where
|
||||||
|
T: Into<AssetPath<'static>>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
requests: requests.into_iter().map(Into::into).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A "loaded batch" containing handles for all assets stored in a given [`AssetPath`].
|
||||||
|
///
|
||||||
|
/// This is produced by [`AssetServer::load_batch`](crate::prelude::AssetServer::load_batch).
|
||||||
|
///
|
||||||
|
/// [`AssetPath`]: crate::AssetPath
|
||||||
|
#[derive(Asset, TypePath)]
|
||||||
|
pub struct LoadedBatch {
|
||||||
|
/// The handles of all assets stored in the batch.
|
||||||
|
#[dependency]
|
||||||
|
pub handles: Vec<UntypedHandle>,
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
use alloc::vec::Vec;
|
|
||||||
|
|
||||||
use crate::{Asset, UntypedHandle};
|
|
||||||
use bevy_reflect::TypePath;
|
|
||||||
|
|
||||||
/// A "loaded folder" containing handles for all assets stored in a given [`AssetPath`].
|
|
||||||
///
|
|
||||||
/// This is produced by [`AssetServer::load_folder`](crate::prelude::AssetServer::load_folder).
|
|
||||||
///
|
|
||||||
/// [`AssetPath`]: crate::AssetPath
|
|
||||||
#[derive(Asset, TypePath)]
|
|
||||||
pub struct LoadedFolder {
|
|
||||||
/// The handles of all assets stored in the folder.
|
|
||||||
#[dependency]
|
|
||||||
pub handles: Vec<UntypedHandle>,
|
|
||||||
}
|
|
@ -174,9 +174,9 @@ pub mod prelude {
|
|||||||
|
|
||||||
mod asset_changed;
|
mod asset_changed;
|
||||||
mod assets;
|
mod assets;
|
||||||
|
mod batch;
|
||||||
mod direct_access_ext;
|
mod direct_access_ext;
|
||||||
mod event;
|
mod event;
|
||||||
mod folder;
|
|
||||||
mod handle;
|
mod handle;
|
||||||
mod id;
|
mod id;
|
||||||
mod loader;
|
mod loader;
|
||||||
@ -187,10 +187,10 @@ mod render_asset;
|
|||||||
mod server;
|
mod server;
|
||||||
|
|
||||||
pub use assets::*;
|
pub use assets::*;
|
||||||
|
pub use batch::*;
|
||||||
pub use bevy_asset_macros::Asset;
|
pub use bevy_asset_macros::Asset;
|
||||||
pub use direct_access_ext::DirectAssetAccessExt;
|
pub use direct_access_ext::DirectAssetAccessExt;
|
||||||
pub use event::*;
|
pub use event::*;
|
||||||
pub use folder::*;
|
|
||||||
pub use futures_lite::{AsyncReadExt, AsyncWriteExt};
|
pub use futures_lite::{AsyncReadExt, AsyncWriteExt};
|
||||||
pub use handle::*;
|
pub use handle::*;
|
||||||
pub use id::*;
|
pub use id::*;
|
||||||
@ -410,7 +410,7 @@ impl Plugin for AssetPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
app.insert_resource(embedded)
|
app.insert_resource(embedded)
|
||||||
.init_asset::<LoadedFolder>()
|
.init_asset::<LoadedBatch>()
|
||||||
.init_asset::<LoadedUntypedAsset>()
|
.init_asset::<LoadedUntypedAsset>()
|
||||||
.init_asset::<()>()
|
.init_asset::<()>()
|
||||||
.add_event::<UntypedAssetLoadFailedEvent>()
|
.add_event::<UntypedAssetLoadFailedEvent>()
|
||||||
@ -668,7 +668,7 @@ pub type AssetEvents = AssetEventSystems;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
folder::LoadedFolder,
|
batch::LoadedBatch,
|
||||||
handle::Handle,
|
handle::Handle,
|
||||||
io::{
|
io::{
|
||||||
gated::{GateOpener, GatedReader},
|
gated::{GateOpener, GatedReader},
|
||||||
@ -677,7 +677,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
loader::{AssetLoader, LoadContext},
|
loader::{AssetLoader, LoadContext},
|
||||||
Asset, AssetApp, AssetEvent, AssetId, AssetLoadError, AssetLoadFailedEvent, AssetPath,
|
Asset, AssetApp, AssetEvent, AssetId, AssetLoadError, AssetLoadFailedEvent, AssetPath,
|
||||||
AssetPlugin, AssetServer, Assets, LoadState, UnapprovedPathMode,
|
AssetPlugin, AssetServer, Assets, LoadBatchRequest, LoadState, UnapprovedPathMode,
|
||||||
};
|
};
|
||||||
use alloc::{
|
use alloc::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
@ -1574,7 +1574,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_folder() {
|
fn load_batch() {
|
||||||
// The particular usage of GatedReader in this test will cause deadlocking if running single-threaded
|
// The particular usage of GatedReader in this test will cause deadlocking if running single-threaded
|
||||||
#[cfg(not(feature = "multi_threaded"))]
|
#[cfg(not(feature = "multi_threaded"))]
|
||||||
panic!("This test requires the \"multi_threaded\" feature, otherwise it will deadlock.\ncargo test --package bevy_asset --features multi_threaded");
|
panic!("This test requires the \"multi_threaded\" feature, otherwise it will deadlock.\ncargo test --package bevy_asset --features multi_threaded");
|
||||||
@ -1618,21 +1618,22 @@ mod tests {
|
|||||||
.init_asset::<SubText>()
|
.init_asset::<SubText>()
|
||||||
.register_asset_loader(CoolTextLoader);
|
.register_asset_loader(CoolTextLoader);
|
||||||
let asset_server = app.world().resource::<AssetServer>().clone();
|
let asset_server = app.world().resource::<AssetServer>().clone();
|
||||||
let handle: Handle<LoadedFolder> = asset_server.load_folder("text");
|
let handle: Handle<LoadedBatch> =
|
||||||
|
asset_server.load_batch(LoadBatchRequest::new(vec!["text/*", "b.cool.ron"]));
|
||||||
gate_opener.open(a_path);
|
gate_opener.open(a_path);
|
||||||
gate_opener.open(b_path);
|
gate_opener.open(b_path);
|
||||||
gate_opener.open(c_path);
|
gate_opener.open(c_path);
|
||||||
|
|
||||||
let mut reader = EventCursor::default();
|
let mut reader = EventCursor::default();
|
||||||
run_app_until(&mut app, |world| {
|
run_app_until(&mut app, |world| {
|
||||||
let events = world.resource::<Events<AssetEvent<LoadedFolder>>>();
|
let events = world.resource::<Events<AssetEvent<LoadedBatch>>>();
|
||||||
let asset_server = world.resource::<AssetServer>();
|
let asset_server = world.resource::<AssetServer>();
|
||||||
let loaded_folders = world.resource::<Assets<LoadedFolder>>();
|
let loaded_batchs = world.resource::<Assets<LoadedBatch>>();
|
||||||
let cool_texts = world.resource::<Assets<CoolText>>();
|
let cool_texts = world.resource::<Assets<CoolText>>();
|
||||||
for event in reader.read(events) {
|
for event in reader.read(events) {
|
||||||
if let AssetEvent::LoadedWithDependencies { id } = event {
|
if let AssetEvent::LoadedWithDependencies { id } = event {
|
||||||
if *id == handle.id() {
|
if *id == handle.id() {
|
||||||
let loaded_folder = loaded_folders.get(&handle).unwrap();
|
let loaded_batch = loaded_batchs.get(&handle).unwrap();
|
||||||
let a_handle: Handle<CoolText> =
|
let a_handle: Handle<CoolText> =
|
||||||
asset_server.get_handle("text/a.cool.ron").unwrap();
|
asset_server.get_handle("text/a.cool.ron").unwrap();
|
||||||
let c_handle: Handle<CoolText> =
|
let c_handle: Handle<CoolText> =
|
||||||
@ -1640,7 +1641,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut found_a = false;
|
let mut found_a = false;
|
||||||
let mut found_c = false;
|
let mut found_c = false;
|
||||||
for asset_handle in &loaded_folder.handles {
|
for asset_handle in &loaded_batch.handles {
|
||||||
if asset_handle.id() == a_handle.id().untyped() {
|
if asset_handle.id() == a_handle.id().untyped() {
|
||||||
found_a = true;
|
found_a = true;
|
||||||
} else if asset_handle.id() == c_handle.id().untyped() {
|
} else if asset_handle.id() == c_handle.id().untyped() {
|
||||||
@ -1649,7 +1650,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
assert!(found_a);
|
assert!(found_a);
|
||||||
assert!(found_c);
|
assert!(found_c);
|
||||||
assert_eq!(loaded_folder.handles.len(), 2);
|
assert_eq!(loaded_batch.handles.len(), 2);
|
||||||
|
|
||||||
let a_text = cool_texts.get(&a_handle).unwrap();
|
let a_text = cool_texts.get(&a_handle).unwrap();
|
||||||
let b_text = cool_texts.get(&a_text.dependencies[0]).unwrap();
|
let b_text = cool_texts.get(&a_text.dependencies[0]).unwrap();
|
||||||
|
@ -2,10 +2,9 @@ mod info;
|
|||||||
mod loaders;
|
mod loaders;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
folder::LoadedFolder,
|
|
||||||
io::{
|
io::{
|
||||||
AssetReaderError, AssetSource, AssetSourceEvent, AssetSourceId, AssetSources,
|
AssetReaderError, AssetSource, AssetSourceEvent, AssetSourceId, AssetSources,
|
||||||
AssetWriterError, ErasedAssetReader, MissingAssetSourceError, MissingAssetWriterError,
|
AssetWriterError, MissingAssetSourceError, MissingAssetWriterError,
|
||||||
MissingProcessedAssetReaderError, Reader,
|
MissingProcessedAssetReaderError, Reader,
|
||||||
},
|
},
|
||||||
loader::{AssetLoader, ErasedAssetLoader, LoadContext, LoadedAsset},
|
loader::{AssetLoader, ErasedAssetLoader, LoadContext, LoadedAsset},
|
||||||
@ -15,8 +14,9 @@ use crate::{
|
|||||||
},
|
},
|
||||||
path::AssetPath,
|
path::AssetPath,
|
||||||
Asset, AssetEvent, AssetHandleProvider, AssetId, AssetLoadFailedEvent, AssetMetaCheck, Assets,
|
Asset, AssetEvent, AssetHandleProvider, AssetId, AssetLoadFailedEvent, AssetMetaCheck, Assets,
|
||||||
DeserializeMetaError, ErasedLoadedAsset, Handle, LoadedUntypedAsset, UnapprovedPathMode,
|
DeserializeMetaError, ErasedLoadedAsset, Handle, LoadBatchRequest, LoadedBatch,
|
||||||
UntypedAssetId, UntypedAssetLoadFailedEvent, UntypedHandle,
|
LoadedUntypedAsset, UnapprovedPathMode, UntypedAssetId, UntypedAssetLoadFailedEvent,
|
||||||
|
UntypedHandle,
|
||||||
};
|
};
|
||||||
use alloc::{borrow::ToOwned, boxed::Box, vec, vec::Vec};
|
use alloc::{borrow::ToOwned, boxed::Box, vec, vec::Vec};
|
||||||
use alloc::{
|
use alloc::{
|
||||||
@ -31,7 +31,7 @@ use bevy_tasks::IoTaskPool;
|
|||||||
use core::{any::TypeId, future::Future, panic::AssertUnwindSafe, task::Poll};
|
use core::{any::TypeId, future::Future, panic::AssertUnwindSafe, task::Poll};
|
||||||
use crossbeam_channel::{Receiver, Sender};
|
use crossbeam_channel::{Receiver, Sender};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use futures_lite::{FutureExt, StreamExt};
|
use futures_lite::FutureExt;
|
||||||
use info::*;
|
use info::*;
|
||||||
use loaders::*;
|
use loaders::*;
|
||||||
use parking_lot::{RwLock, RwLockWriteGuard};
|
use parking_lot::{RwLock, RwLockWriteGuard};
|
||||||
@ -954,59 +954,42 @@ impl AssetServer {
|
|||||||
handle.typed_debug_checked()
|
handle.typed_debug_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads all assets from the specified folder recursively. The [`LoadedFolder`] asset (when it loads) will
|
/// Loads all assets from the specified folder recursively with batch. The [`LoadedBatch`] 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
|
/// contain handles to all assets in the folder. You can wait for all assets to load by checking the [`LoadedBatch`]'s
|
||||||
/// [`RecursiveDependencyLoadState`].
|
/// [`RecursiveDependencyLoadState`].
|
||||||
///
|
///
|
||||||
/// Loading the same folder multiple times will return the same handle. If the `file_watcher`
|
/// Loading the same folder multiple times will return the same handle. If the `file_watcher`
|
||||||
/// feature is enabled, [`LoadedFolder`] handles will reload when a file in the folder is
|
/// feature is enabled, [`LoadedBatch`] handles will reload when a file in the folder is
|
||||||
/// removed, added or moved. This includes files in subdirectories and moving, adding,
|
/// removed, added or moved. This includes files in subdirectories and moving, adding,
|
||||||
/// or removing complete subdirectories.
|
/// or removing complete subdirectories.
|
||||||
#[must_use = "not using the returned strong handle may result in the unexpected release of the assets"]
|
#[must_use = "not using the returned strong handle may result in the unexpected release of the assets"]
|
||||||
pub fn load_folder<'a>(&self, path: impl Into<AssetPath<'a>>) -> Handle<LoadedFolder> {
|
pub fn load_batch(&self, load_batch_request: LoadBatchRequest) -> Handle<LoadedBatch> {
|
||||||
let path = path.into().into_owned();
|
let handle = self.data.infos.write().create_loading_handle_untyped(
|
||||||
let (handle, should_load) = self
|
TypeId::of::<LoadedBatch>(),
|
||||||
.data
|
core::any::type_name::<LoadedBatch>(),
|
||||||
.infos
|
|
||||||
.write()
|
|
||||||
.get_or_create_path_handle::<LoadedFolder>(
|
|
||||||
path.clone(),
|
|
||||||
HandleLoadingMode::Request,
|
|
||||||
None,
|
|
||||||
);
|
);
|
||||||
if !should_load {
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
let id = handle.id().untyped();
|
|
||||||
self.load_folder_internal(id, path);
|
|
||||||
|
|
||||||
handle
|
self.load_batch_internal(handle.id(), load_batch_request);
|
||||||
|
handle.typed_debug_checked()
|
||||||
}
|
}
|
||||||
|
pub(crate) fn load_batch_internal(
|
||||||
pub(crate) fn load_folder_internal(&self, id: UntypedAssetId, path: AssetPath) {
|
&self,
|
||||||
async fn load_folder<'a>(
|
id: UntypedAssetId,
|
||||||
|
load_batch_request: LoadBatchRequest,
|
||||||
|
) {
|
||||||
|
async fn load_file<'a>(
|
||||||
source: AssetSourceId<'static>,
|
source: AssetSourceId<'static>,
|
||||||
path: &'a Path,
|
path: &'a Path,
|
||||||
reader: &'a dyn ErasedAssetReader,
|
|
||||||
server: &'a AssetServer,
|
server: &'a AssetServer,
|
||||||
handles: &'a mut Vec<UntypedHandle>,
|
handles: &'a mut Vec<UntypedHandle>,
|
||||||
) -> Result<(), AssetLoadError> {
|
) -> Result<(), AssetLoadError> {
|
||||||
let is_dir = reader.is_directory(path).await?;
|
let path = path
|
||||||
if is_dir {
|
.strip_prefix("assets\\")
|
||||||
let mut path_stream = reader.read_directory(path.as_ref()).await?;
|
.unwrap()
|
||||||
while let Some(child_path) = path_stream.next().await {
|
.to_str()
|
||||||
if reader.is_directory(&child_path).await? {
|
.expect("Path should be a valid string.");
|
||||||
Box::pin(load_folder(
|
|
||||||
source.clone(),
|
|
||||||
&child_path,
|
|
||||||
reader,
|
|
||||||
server,
|
|
||||||
handles,
|
|
||||||
))
|
|
||||||
.await?;
|
|
||||||
} else {
|
|
||||||
let path = child_path.to_str().expect("Path should be a valid string.");
|
|
||||||
let asset_path = AssetPath::parse(path).with_source(source.clone());
|
let asset_path = AssetPath::parse(path).with_source(source.clone());
|
||||||
|
|
||||||
match server.load_untyped_async(asset_path).await {
|
match server.load_untyped_async(asset_path).await {
|
||||||
Ok(handle) => handles.push(handle),
|
Ok(handle) => handles.push(handle),
|
||||||
// skip assets that cannot be loaded
|
// skip assets that cannot be loaded
|
||||||
@ -1016,52 +999,64 @@ impl AssetServer {
|
|||||||
) => {}
|
) => {}
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = path.into_owned();
|
|
||||||
let server = self.clone();
|
let server = self.clone();
|
||||||
IoTaskPool::get()
|
IoTaskPool::get()
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
|
let mut handles = Vec::new();
|
||||||
|
for request_path in load_batch_request.requests.iter() {
|
||||||
|
let glob_pattern = format!("assets/{}", request_path);
|
||||||
|
let glob_result = match glob::glob(&glob_pattern) {
|
||||||
|
Ok(g) => g,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Invalid glob pattern {}: {}", request_path, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for entry in glob_result {
|
||||||
|
let path = match entry {
|
||||||
|
Ok(path) => path,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to read path matching {}: {}", request_path, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if path.is_dir() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = AssetPath::from_path_buf(path);
|
||||||
|
|
||||||
let Ok(source) = server.get_source(path.source()) else {
|
let Ok(source) = server.get_source(path.source()) else {
|
||||||
error!(
|
error!(
|
||||||
"Failed to load {path}. AssetSource {} does not exist",
|
"Failed to load {}. AssetSource {} does not exist",
|
||||||
|
path,
|
||||||
path.source()
|
path.source()
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let asset_reader = match server.data.mode {
|
if let Err(err) =
|
||||||
AssetServerMode::Unprocessed => source.reader(),
|
load_file(source.id(), path.path(), &server, &mut handles).await
|
||||||
AssetServerMode::Processed => match source.processed_reader() {
|
{
|
||||||
Ok(reader) => reader,
|
error!("Failed to load {}: {}", path, err);
|
||||||
Err(_) => {
|
server.send_asset_event(InternalAssetEvent::Failed {
|
||||||
error!(
|
|
||||||
"Failed to load {path}. AssetSource {} does not have a processed AssetReader",
|
|
||||||
path.source()
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut handles = Vec::new();
|
|
||||||
match load_folder(source.id(), path.path(), asset_reader, &server, &mut handles).await {
|
|
||||||
Ok(_) => server.send_asset_event(InternalAssetEvent::Loaded {
|
|
||||||
id,
|
id,
|
||||||
loaded_asset: LoadedAsset::new_with_dependencies(
|
error: err,
|
||||||
LoadedFolder { handles },
|
path: path.clone(),
|
||||||
)
|
});
|
||||||
.into(),
|
|
||||||
}),
|
|
||||||
Err(err) => {
|
|
||||||
error!("Failed to load folder. {err}");
|
|
||||||
server.send_asset_event(InternalAssetEvent::Failed { id, error: err, path });
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
server.send_asset_event(InternalAssetEvent::Loaded {
|
||||||
|
id,
|
||||||
|
loaded_asset: LoadedAsset::new_with_dependencies(LoadedBatch { handles })
|
||||||
|
.into(),
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
@ -1701,17 +1696,8 @@ pub fn handle_internal_asset_events(world: &mut World) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let reload_parent_folders = |path: PathBuf, source: &AssetSourceId<'static>| {
|
let reload_parent_folders = |_path: PathBuf, _source: &AssetSourceId<'static>| {
|
||||||
let mut current_folder = path;
|
info!("reload_parent_folders");
|
||||||
while let Some(parent) = current_folder.parent() {
|
|
||||||
current_folder = parent.to_path_buf();
|
|
||||||
let parent_asset_path =
|
|
||||||
AssetPath::from(current_folder.clone()).with_source(source.clone());
|
|
||||||
for folder_handle in infos.get_path_handles(&parent_asset_path) {
|
|
||||||
info!("Reloading folder {parent_asset_path} because the content has changed");
|
|
||||||
server.load_folder_internal(folder_handle.id(), parent_asset_path.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut paths_to_reload = <HashSet<_>>::default();
|
let mut paths_to_reload = <HashSet<_>>::default();
|
||||||
|
@ -7,7 +7,11 @@
|
|||||||
//! Only one padded and one unpadded texture atlas are rendered to the screen.
|
//! Only one padded and one unpadded texture atlas are rendered to the screen.
|
||||||
//! An upscaled sprite from each of the four atlases are rendered to the screen.
|
//! An upscaled sprite from each of the four atlases are rendered to the screen.
|
||||||
|
|
||||||
use bevy::{asset::LoadedFolder, image::ImageSampler, prelude::*};
|
use bevy::{
|
||||||
|
asset::{LoadBatchRequest, LoadedBatch},
|
||||||
|
image::ImageSampler,
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
@ -27,17 +31,19 @@ enum AppState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
struct RpgSpriteFolder(Handle<LoadedFolder>);
|
struct RpgSpriteFolder(Handle<LoadedBatch>);
|
||||||
|
|
||||||
fn load_textures(mut commands: Commands, asset_server: Res<AssetServer>) {
|
fn load_textures(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||||
// Load multiple, individual sprites from a folder
|
// Load multiple, individual sprites from a folder
|
||||||
commands.insert_resource(RpgSpriteFolder(asset_server.load_folder("textures/rpg")));
|
commands.insert_resource(RpgSpriteFolder(asset_server.load_batch(
|
||||||
|
LoadBatchRequest::new(vec!["textures/rpg/**/*", "textures/rpg/chars/**/*"]),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_textures(
|
fn check_textures(
|
||||||
mut next_state: ResMut<NextState<AppState>>,
|
mut next_state: ResMut<NextState<AppState>>,
|
||||||
rpg_sprite_folder: Res<RpgSpriteFolder>,
|
rpg_sprite_folder: Res<RpgSpriteFolder>,
|
||||||
mut events: EventReader<AssetEvent<LoadedFolder>>,
|
mut events: EventReader<AssetEvent<LoadedBatch>>,
|
||||||
) {
|
) {
|
||||||
// Advance the `AppState` once all sprite handles have been loaded by the `AssetServer`
|
// Advance the `AppState` once all sprite handles have been loaded by the `AssetServer`
|
||||||
for event in events.read() {
|
for event in events.read() {
|
||||||
@ -52,7 +58,7 @@ fn setup(
|
|||||||
rpg_sprite_handles: Res<RpgSpriteFolder>,
|
rpg_sprite_handles: Res<RpgSpriteFolder>,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
|
mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
|
||||||
loaded_folders: Res<Assets<LoadedFolder>>,
|
loaded_folders: Res<Assets<LoadedBatch>>,
|
||||||
mut textures: ResMut<Assets<Image>>,
|
mut textures: ResMut<Assets<Image>>,
|
||||||
) {
|
) {
|
||||||
let loaded_folder = loaded_folders.get(&rpg_sprite_handles.0).unwrap();
|
let loaded_folder = loaded_folders.get(&rpg_sprite_handles.0).unwrap();
|
||||||
@ -215,7 +221,7 @@ fn setup(
|
|||||||
/// Create a texture atlas with the given padding and sampling settings
|
/// Create a texture atlas with the given padding and sampling settings
|
||||||
/// from the individual sprites in the given folder.
|
/// from the individual sprites in the given folder.
|
||||||
fn create_texture_atlas(
|
fn create_texture_atlas(
|
||||||
folder: &LoadedFolder,
|
folder: &LoadedBatch,
|
||||||
padding: Option<UVec2>,
|
padding: Option<UVec2>,
|
||||||
sampling: Option<ImageSampler>,
|
sampling: Option<ImageSampler>,
|
||||||
textures: &mut ResMut<Assets<Image>>,
|
textures: &mut ResMut<Assets<Image>>,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! This example illustrates various ways to load assets.
|
//! This example illustrates various ways to load assets.
|
||||||
|
|
||||||
use bevy::{asset::LoadedFolder, prelude::*};
|
use bevy::{asset::LoadBatchRequest, prelude::*};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
@ -52,7 +52,8 @@ fn setup(
|
|||||||
// to load.
|
// to load.
|
||||||
// If you want to keep the assets in the folder alive, make sure you store the returned handle
|
// If you want to keep the assets in the folder alive, make sure you store the returned handle
|
||||||
// somewhere.
|
// somewhere.
|
||||||
let _loaded_folder: Handle<LoadedFolder> = asset_server.load_folder("models/torus");
|
let _loaded_folder =
|
||||||
|
asset_server.load_batch(LoadBatchRequest::new(vec!["models/torus/torus.gltf"]));
|
||||||
|
|
||||||
// If you want a handle to a specific asset in a loaded folder, the easiest way to get one is to call load.
|
// If you want a handle to a specific asset in a loaded folder, the easiest way to get one is to call load.
|
||||||
// It will _not_ be loaded a second time.
|
// It will _not_ be loaded a second time.
|
||||||
|
Loading…
Reference in New Issue
Block a user