Struct bevy::asset::prelude::AssetServer
source · pub struct AssetServer { /* private fields */ }
Expand description
Loads and tracks the state of Asset
values from a configured AssetReader
. This can be used to kick off new asset loads and
retrieve their current load states.
The general process to load an asset is:
- Initialize a new
Asset
type with theAssetServer
viaAssetApp::init_asset
, which will internally callAssetServer::register_asset
and set up related ECSAssets
storage and systems. - Register one or more
AssetLoader
s for that asset withAssetApp::init_asset_loader
- Add the asset to your asset folder (defaults to
assets
). - Call
AssetServer::load
with a path to your asset.
AssetServer
can be cloned. It is backed by an Arc
so clones will share state. Clones can be freely used in parallel.
Implementations§
source§impl AssetServer
impl AssetServer
sourcepub fn new(
sources: AssetSources,
mode: AssetServerMode,
watching_for_changes: bool
) -> AssetServer
pub fn new( sources: AssetSources, mode: AssetServerMode, watching_for_changes: bool ) -> AssetServer
Create a new instance of AssetServer
. If watch_for_changes
is true, the AssetReader
storage will watch for changes to
asset sources and hot-reload them.
sourcepub fn new_with_meta_check(
sources: AssetSources,
mode: AssetServerMode,
meta_check: AssetMetaCheck,
watching_for_changes: bool
) -> AssetServer
pub fn new_with_meta_check( sources: AssetSources, mode: AssetServerMode, meta_check: AssetMetaCheck, watching_for_changes: bool ) -> AssetServer
Create a new instance of AssetServer
. If watch_for_changes
is true, the AssetReader
storage will watch for changes to
asset sources and hot-reload them.
sourcepub fn get_source<'a>(
&'a self,
source: impl Into<AssetSourceId<'a>>
) -> Result<&'a AssetSource, MissingAssetSourceError>
pub fn get_source<'a>( &'a self, source: impl Into<AssetSourceId<'a>> ) -> Result<&'a AssetSource, MissingAssetSourceError>
Retrieves the AssetSource
for the given source
.
sourcepub fn watching_for_changes(&self) -> bool
pub fn watching_for_changes(&self) -> bool
Returns true if the AssetServer
watches for changes.
sourcepub fn register_loader<L>(&self, loader: L)where
L: AssetLoader,
pub fn register_loader<L>(&self, loader: L)where
L: AssetLoader,
Registers a new AssetLoader
. AssetLoader
s must be registered before they can be used.
sourcepub fn register_asset<A>(&self, assets: &Assets<A>)where
A: Asset,
pub fn register_asset<A>(&self, assets: &Assets<A>)where
A: Asset,
sourcepub async fn get_asset_loader_with_extension(
&self,
extension: &str
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForExtensionError>
pub async fn get_asset_loader_with_extension( &self, extension: &str ) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForExtensionError>
Returns the registered AssetLoader
associated with the given extension, if it exists.
sourcepub async fn get_asset_loader_with_type_name(
&self,
type_name: &str
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeNameError>
pub async fn get_asset_loader_with_type_name( &self, type_name: &str ) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeNameError>
Returns the registered AssetLoader
associated with the given std::any::type_name
, if it exists.
sourcepub async fn get_path_asset_loader<'a>(
&self,
path: impl Into<AssetPath<'a>>
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForExtensionError>
pub async fn get_path_asset_loader<'a>( &self, path: impl Into<AssetPath<'a>> ) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForExtensionError>
Retrieves the default AssetLoader
for the given path, if one can be found.
sourcepub async fn get_asset_loader_with_asset_type_id<'a>(
&self,
type_id: TypeId
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeIdError>
pub async fn get_asset_loader_with_asset_type_id<'a>( &self, type_id: TypeId ) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeIdError>
Retrieves the default AssetLoader
for the given Asset
TypeId
, if one can be found.
sourcepub async fn get_asset_loader_with_asset_type<'a, A>(
&self
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeIdError>where
A: Asset,
pub async fn get_asset_loader_with_asset_type<'a, A>(
&self
) -> Result<Arc<dyn ErasedAssetLoader>, MissingAssetLoaderForTypeIdError>where
A: Asset,
Retrieves the default AssetLoader
for the given Asset
type, if one can be found.
sourcepub fn load<'a, A>(&self, path: impl Into<AssetPath<'a>>) -> Handle<A>where
A: Asset,
pub fn load<'a, A>(&self, path: impl Into<AssetPath<'a>>) -> Handle<A>where
A: Asset,
Begins loading an Asset
of type A
stored at path
. This will not block on the asset load. Instead,
it returns a “strong” Handle
. When the Asset
is loaded (and enters LoadState::Loaded
), it will be added to the
associated Assets
resource.
You can check the asset’s load state by reading AssetEvent
events, calling AssetServer::load_state
, or checking
the Assets
storage to see if the Asset
exists yet.
The asset load will fail and an error will be printed to the logs if the asset stored at path
is not of type A
.
Examples found in repository?
More examples
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
fn spawn_scene(commands: &mut Commands, asset_server: &AssetServer) {
commands.spawn(SceneBundle {
scene: asset_server.load("models/cubes/Cubes.glb#Scene0"),
..SceneBundle::default()
});
}
// Spawns the camera.
fn spawn_camera(commands: &mut Commands) {
commands.spawn(Camera3dBundle {
camera: Camera {
hdr: true,
..default()
},
transform: Transform::from_xyz(-6.483, 0.325, 4.381).looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
}
// Creates the sphere mesh and spawns it.
fn spawn_sphere(
commands: &mut Commands,
meshes: &mut Assets<Mesh>,
materials: &mut Assets<StandardMaterial>,
) {
// Create a sphere mesh.
let sphere_mesh = meshes.add(Sphere::new(1.0).mesh().ico(7).unwrap());
// Create a sphere.
commands.spawn(PbrBundle {
mesh: sphere_mesh.clone(),
material: materials.add(StandardMaterial {
base_color: Color::hex("#ffd891").unwrap(),
metallic: 1.0,
perceptual_roughness: 0.0,
..StandardMaterial::default()
}),
transform: Transform::default(),
..PbrBundle::default()
});
}
// Spawns the reflection probe.
fn spawn_reflection_probe(commands: &mut Commands, cubemaps: &Cubemaps) {
commands.spawn(ReflectionProbeBundle {
spatial: SpatialBundle {
// 2.0 because the sphere's radius is 1.0 and we want to fully enclose it.
transform: Transform::from_scale(Vec3::splat(2.0)),
..SpatialBundle::default()
},
light_probe: LightProbe,
environment_map: EnvironmentMapLight {
diffuse_map: cubemaps.diffuse.clone(),
specular_map: cubemaps.specular_reflection_probe.clone(),
intensity: 5000.0,
},
});
}
// Spawns the help text.
fn spawn_text(commands: &mut Commands, asset_server: &AssetServer, app_status: &AppStatus) {
// Create the text.
commands.spawn(
TextBundle {
text: app_status.create_text(asset_server),
..TextBundle::default()
}
.with_style(Style {
position_type: PositionType::Absolute,
bottom: Val::Px(10.0),
left: Val::Px(10.0),
..default()
}),
);
}
// Adds a world environment map to the camera. This separate system is needed because the camera is
// managed by the scene spawner, as it's part of the glTF file with the cubes, so we have to add
// the environment map after the fact.
fn add_environment_map_to_camera(
mut commands: Commands,
query: Query<Entity, Added<Camera3d>>,
cubemaps: Res<Cubemaps>,
) {
for camera_entity in query.iter() {
commands
.entity(camera_entity)
.insert(create_camera_environment_map_light(&cubemaps))
.insert(Skybox {
image: cubemaps.skybox.clone(),
brightness: 5000.0,
});
}
}
// A system that handles switching between different reflection modes.
fn change_reflection_type(
mut commands: Commands,
light_probe_query: Query<Entity, With<LightProbe>>,
camera_query: Query<Entity, With<Camera3d>>,
keyboard: Res<ButtonInput<KeyCode>>,
mut app_status: ResMut<AppStatus>,
cubemaps: Res<Cubemaps>,
) {
// Only do anything if space was pressed.
if !keyboard.just_pressed(KeyCode::Space) {
return;
}
// Switch reflection mode.
app_status.reflection_mode =
ReflectionMode::try_from((app_status.reflection_mode as u32 + 1) % 3).unwrap();
// Add or remove the light probe.
for light_probe in light_probe_query.iter() {
commands.entity(light_probe).despawn();
}
match app_status.reflection_mode {
ReflectionMode::None | ReflectionMode::EnvironmentMap => {}
ReflectionMode::ReflectionProbe => spawn_reflection_probe(&mut commands, &cubemaps),
}
// Add or remove the environment map from the camera.
for camera in camera_query.iter() {
match app_status.reflection_mode {
ReflectionMode::None => {
commands.entity(camera).remove::<EnvironmentMapLight>();
}
ReflectionMode::EnvironmentMap | ReflectionMode::ReflectionProbe => {
commands
.entity(camera)
.insert(create_camera_environment_map_light(&cubemaps));
}
}
}
}
// A system that handles enabling and disabling rotation.
fn toggle_rotation(keyboard: Res<ButtonInput<KeyCode>>, mut app_status: ResMut<AppStatus>) {
if keyboard.just_pressed(KeyCode::Enter) {
app_status.rotating = !app_status.rotating;
}
}
// A system that updates the help text.
fn update_text(
mut text_query: Query<&mut Text>,
app_status: Res<AppStatus>,
asset_server: Res<AssetServer>,
) {
for mut text in text_query.iter_mut() {
*text = app_status.create_text(&asset_server);
}
}
impl TryFrom<u32> for ReflectionMode {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
match value {
0 => Ok(ReflectionMode::None),
1 => Ok(ReflectionMode::EnvironmentMap),
2 => Ok(ReflectionMode::ReflectionProbe),
_ => Err(()),
}
}
}
impl Display for ReflectionMode {
fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
let text = match *self {
ReflectionMode::None => "No reflections",
ReflectionMode::EnvironmentMap => "Environment map",
ReflectionMode::ReflectionProbe => "Reflection probe",
};
formatter.write_str(text)
}
}
impl AppStatus {
// Constructs the help text at the bottom of the screen based on the
// application status.
fn create_text(&self, asset_server: &AssetServer) -> Text {
let rotation_help_text = if self.rotating {
STOP_ROTATION_HELP_TEXT
} else {
START_ROTATION_HELP_TEXT
};
Text::from_section(
format!(
"{}\n{}\n{}",
self.reflection_mode, rotation_help_text, REFLECTION_MODE_HELP_TEXT
),
TextStyle {
font: asset_server.load("fonts/FiraMono-Medium.ttf"),
font_size: 24.0,
color: Color::ANTIQUE_WHITE,
},
)
}
}
// Creates the world environment map light, used as a fallback if no reflection
// probe is applicable to a mesh.
fn create_camera_environment_map_light(cubemaps: &Cubemaps) -> EnvironmentMapLight {
EnvironmentMapLight {
diffuse_map: cubemaps.diffuse.clone(),
specular_map: cubemaps.specular_environment_map.clone(),
intensity: 5000.0,
}
}
// Rotates the camera a bit every frame.
fn rotate_camera(
mut camera_query: Query<&mut Transform, With<Camera3d>>,
app_status: Res<AppStatus>,
) {
if !app_status.rotating {
return;
}
for mut transform in camera_query.iter_mut() {
transform.translation = Vec2::from_angle(ROTATION_SPEED)
.rotate(transform.translation.xz())
.extend(transform.translation.y)
.xzy();
transform.look_at(Vec3::ZERO, Vec3::Y);
}
}
// Loads the cubemaps from the assets directory.
impl FromWorld for Cubemaps {
fn from_world(world: &mut World) -> Self {
let asset_server = world.resource::<AssetServer>();
// Just use the specular map for the skybox since it's not too blurry.
// In reality you wouldn't do this--you'd use a real skybox texture--but
// reusing the textures like this saves space in the Bevy repository.
let specular_map = asset_server.load("environment_maps/pisa_specular_rgb9e5_zstd.ktx2");
Cubemaps {
diffuse: asset_server.load("environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2"),
specular_reflection_probe: asset_server
.load("environment_maps/cubes_reflection_probe_specular_rgb9e5_zstd.ktx2"),
specular_environment_map: specular_map.clone(),
skybox: specular_map,
}
}
- examples/2d/sprite.rs
- examples/ecs/removal_detection.rs
- examples/3d/lightmaps.rs
- examples/2d/move_sprite.rs
- examples/shader/shader_instancing.rs
- examples/asset/asset_decompression.rs
- examples/scene/scene.rs
- examples/2d/sprite_flipping.rs
- examples/animation/gltf_skinned_mesh.rs
- examples/asset/custom_asset.rs
- examples/2d/sprite_tile.rs
- examples/ecs/parallel_query.rs
- examples/2d/2d_gizmos.rs
- examples/2d/custom_gltf_vertex_attribute.rs
- examples/shader/shader_material_2d.rs
- examples/shader/array_texture.rs
- examples/shader/shader_material.rs
- examples/animation/morph_targets.rs
- examples/shader/texture_binding_array.rs
- examples/2d/pixel_grid_snap.rs
- examples/2d/sprite_slice.rs
- examples/ui/font_atlas_debug.rs
- examples/ui/window_fallthrough.rs
- examples/2d/transparency_2d.rs
- examples/asset/embedded_asset.rs
- examples/2d/sprite_sheet.rs
- examples/3d/animated_material.rs
- examples/shader/shader_material_screenspace_texture.rs
- examples/stress_tests/text_pipeline.rs
- examples/shader/compute_shader_game_of_life.rs
- examples/games/game_menu.rs
- examples/3d/tonemapping.rs
- examples/3d/skybox.rs
- examples/3d/irradiance_volumes.rs
- examples/3d/load_gltf.rs
- examples/3d/update_gltf_scene.rs
- examples/3d/atmospheric_fog.rs
- examples/stress_tests/many_sprites.rs
- examples/2d/mesh2d_vertex_color_texture.rs
- examples/ecs/hierarchy.rs
- examples/ui/button.rs
- examples/math/render_primitives.rs
- examples/3d/generate_custom_mesh.rs
- examples/ui/relative_cursor_position.rs
- examples/window/multiple_windows.rs
- examples/ui/ui_texture_atlas.rs
- examples/animation/animated_fox.rs
- examples/stress_tests/many_animated_sprites.rs
- examples/games/contributors.rs
- examples/ui/ui_scaling.rs
- examples/2d/rotation.rs
- examples/2d/bloom_2d.rs
- examples/stress_tests/many_buttons.rs
- examples/audio/spatial_audio_2d.rs
- examples/ui/ui_texture_slice.rs
- examples/audio/spatial_audio_3d.rs
- examples/input/text_input.rs
- examples/2d/bounding_2d.rs
- examples/ui/overflow_debug.rs
- examples/3d/texture.rs
- examples/games/alien_cake_addict.rs
- examples/3d/ssao.rs
- examples/ui/transparency_ui.rs
- examples/ui/size_constraints.rs
- examples/games/stepping.rs
- examples/shader/post_processing.rs
- examples/time/virtual_time.rs
- examples/3d/anti_aliasing.rs
- examples/stress_tests/bevymark.rs
- examples/ui/text.rs
- examples/asset/asset_loading.rs
- examples/ui/text_wrap_debug.rs
- examples/3d/pbr.rs
- examples/ui/flex_layout.rs
- examples/stress_tests/many_foxes.rs
- examples/shader/shader_prepass.rs
- examples/ui/overflow.rs
- examples/ui/display_and_visibility.rs
- examples/2d/text2d.rs
- examples/games/breakout.rs
- examples/2d/texture_atlas.rs
- examples/3d/parallax_mapping.rs
- examples/3d/split_screen.rs
- examples/ui/text_debug.rs
- examples/3d/deferred_rendering.rs
- examples/3d/blend_modes.rs
- examples/3d/lighting.rs
- examples/ui/grid.rs
- examples/3d/transmission.rs
- examples/ui/ui.rs
sourcepub fn load_with_settings<'a, A, S>(
&self,
path: impl Into<AssetPath<'a>>,
settings: impl Fn(&mut S) + Send + Sync + 'static
) -> Handle<A>
pub fn load_with_settings<'a, A, S>( &self, path: impl Into<AssetPath<'a>>, settings: impl Fn(&mut S) + Send + Sync + 'static ) -> Handle<A>
Begins loading an Asset
of type A
stored at path
. The given settings
function will override the asset’s
AssetLoader
settings. The type S
must match the configured AssetLoader::Settings
or settings
changes
will be ignored and an error will be printed to the log.
sourcepub async fn load_untyped_async<'a>(
&self,
path: impl Into<AssetPath<'a>>
) -> Result<UntypedHandle, AssetLoadError>
pub async fn load_untyped_async<'a>( &self, path: impl Into<AssetPath<'a>> ) -> Result<UntypedHandle, AssetLoadError>
Asynchronously load an asset that you do not know the type of statically. If you do know the type of the asset,
you should use AssetServer::load
. If you don’t know the type of the asset, but you can’t use an async method,
consider using AssetServer::load_untyped
.
sourcepub fn load_untyped<'a>(
&self,
path: impl Into<AssetPath<'a>>
) -> Handle<LoadedUntypedAsset>
pub fn load_untyped<'a>( &self, path: impl Into<AssetPath<'a>> ) -> Handle<LoadedUntypedAsset>
Load an asset without knowing its type. The method returns a handle to a LoadedUntypedAsset
.
Once the LoadedUntypedAsset
is loaded, an untyped handle for the requested path can be
retrieved from it.
use bevy_asset::{Assets, Handle, LoadedUntypedAsset};
use bevy_ecs::system::{Res, Resource};
#[derive(Resource)]
struct LoadingUntypedHandle(Handle<LoadedUntypedAsset>);
fn resolve_loaded_untyped_handle(loading_handle: Res<LoadingUntypedHandle>, loaded_untyped_assets: Res<Assets<LoadedUntypedAsset>>) {
if let Some(loaded_untyped_asset) = loaded_untyped_assets.get(&loading_handle.0) {
let handle = loaded_untyped_asset.handle.clone();
// continue working with `handle` which points to the asset at the originally requested path
}
}
This indirection enables a non blocking load of an untyped asset, since I/O is required to figure out the asset type before a handle can be created.
sourcepub fn reload<'a>(&self, path: impl Into<AssetPath<'a>>)
pub fn reload<'a>(&self, path: impl Into<AssetPath<'a>>)
Kicks off a reload of the asset stored at the given path. This will only reload the asset if it currently loaded.
sourcepub fn add<A>(&self, asset: A) -> Handle<A>where
A: Asset,
pub fn add<A>(&self, asset: A) -> Handle<A>where
A: Asset,
Queues a new asset to be tracked by the AssetServer
and returns a Handle
to it. This can be used to track
dependencies of assets created at runtime.
After the asset has been fully loaded by the AssetServer
, it will show up in the relevant Assets
storage.
Examples found in repository?
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
fn decompress<A: Asset>(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut compressed_assets: ResMut<Assets<GzAsset>>,
query: Query<(Entity, &Compressed<A>)>,
) {
for (entity, Compressed { compressed, .. }) in query.iter() {
let Some(GzAsset { uncompressed }) = compressed_assets.remove(compressed) else {
continue;
};
let uncompressed = uncompressed.take::<A>().unwrap();
commands
.entity(entity)
.remove::<Compressed<A>>()
.insert(asset_server.add(uncompressed));
}
}
sourcepub fn load_folder<'a>(
&self,
path: impl Into<AssetPath<'a>>
) -> Handle<LoadedFolder>
pub fn load_folder<'a>( &self, path: impl Into<AssetPath<'a>> ) -> Handle<LoadedFolder>
Loads all assets from the specified folder recursively. The LoadedFolder
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
RecursiveDependencyLoadState
.
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
removed, added or moved. This includes files in subdirectories and moving, adding,
or removing complete subdirectories.
Examples found in repository?
More examples
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
meshes: Res<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// By default AssetServer will load assets from inside the "assets" folder.
// For example, the next line will load "ROOT/assets/models/cube/cube.gltf#Mesh0/Primitive0",
// where "ROOT" is the directory of the Application.
//
// This can be overridden by setting the "CARGO_MANIFEST_DIR" environment variable (see
// https://doc.rust-lang.org/cargo/reference/environment-variables.html)
// to another directory. When the Application is run through Cargo, "CARGO_MANIFEST_DIR" is
// automatically set to your crate (workspace) root directory.
let cube_handle = asset_server.load("models/cube/cube.gltf#Mesh0/Primitive0");
let sphere_handle = asset_server.load("models/sphere/sphere.gltf#Mesh0/Primitive0");
// All assets end up in their Assets<T> collection once they are done loading:
if let Some(sphere) = meshes.get(&sphere_handle) {
// You might notice that this doesn't run! This is because assets load in parallel without
// blocking. When an asset has loaded, it will appear in relevant Assets<T>
// collection.
info!("{:?}", sphere.primitive_topology());
} else {
info!("sphere hasn't loaded yet");
}
// You can load all assets in a folder like this. They will be loaded in parallel without
// blocking. The LoadedFolder asset holds handles to each asset in the folder. These are all
// dependencies of the LoadedFolder asset, meaning you can wait for the LoadedFolder asset to
// fire AssetEvent::LoadedWithDependencies if you want to wait for all assets in the folder
// to load.
// If you want to keep the assets in the folder alive, make sure you store the returned handle
// somewhere.
let _loaded_folder: Handle<LoadedFolder> = asset_server.load_folder("models/torus");
// 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.
// The LoadedFolder asset will ultimately also hold handles to the assets, but waiting for it to load
// and finding the right handle is more work!
let torus_handle = asset_server.load("models/torus/torus.gltf#Mesh0/Primitive0");
// You can also add assets directly to their Assets<T> storage:
let material_handle = materials.add(StandardMaterial {
base_color: Color::rgb(0.8, 0.7, 0.6),
..default()
});
// torus
commands.spawn(PbrBundle {
mesh: torus_handle,
material: material_handle.clone(),
transform: Transform::from_xyz(-3.0, 0.0, 0.0),
..default()
});
// cube
commands.spawn(PbrBundle {
mesh: cube_handle,
material: material_handle.clone(),
transform: Transform::from_xyz(0.0, 0.0, 0.0),
..default()
});
// sphere
commands.spawn(PbrBundle {
mesh: sphere_handle,
material: material_handle,
transform: Transform::from_xyz(3.0, 0.0, 0.0),
..default()
});
// light
commands.spawn(PointLightBundle {
transform: Transform::from_xyz(4.0, 5.0, 4.0),
..default()
});
// camera
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(0.0, 3.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
}
sourcepub fn get_load_states(
&self,
id: impl Into<UntypedAssetId>
) -> Option<(LoadState, DependencyLoadState, RecursiveDependencyLoadState)>
pub fn get_load_states( &self, id: impl Into<UntypedAssetId> ) -> Option<(LoadState, DependencyLoadState, RecursiveDependencyLoadState)>
Retrieves all loads states for the given asset id.
sourcepub fn get_load_state(&self, id: impl Into<UntypedAssetId>) -> Option<LoadState>
pub fn get_load_state(&self, id: impl Into<UntypedAssetId>) -> Option<LoadState>
Retrieves the main LoadState
of a given asset id
.
Note that this is “just” the root asset load state. To check if an asset and its recursive
dependencies have loaded, see AssetServer::is_loaded_with_dependencies
.
sourcepub fn get_recursive_dependency_load_state(
&self,
id: impl Into<UntypedAssetId>
) -> Option<RecursiveDependencyLoadState>
pub fn get_recursive_dependency_load_state( &self, id: impl Into<UntypedAssetId> ) -> Option<RecursiveDependencyLoadState>
Retrieves the RecursiveDependencyLoadState
of a given asset id
.
sourcepub fn load_state(&self, id: impl Into<UntypedAssetId>) -> LoadState
pub fn load_state(&self, id: impl Into<UntypedAssetId>) -> LoadState
Retrieves the main LoadState
of a given asset id
.
Examples found in repository?
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
fn environment_map_load_finish(
mut commands: Commands,
asset_server: Res<AssetServer>,
environment_maps: Query<&EnvironmentMapLight>,
label_query: Query<Entity, With<EnvironmentMapLabel>>,
) {
if let Ok(environment_map) = environment_maps.get_single() {
if asset_server.load_state(&environment_map.diffuse_map) == LoadState::Loaded
&& asset_server.load_state(&environment_map.specular_map) == LoadState::Loaded
{
if let Ok(label_entity) = label_query.get_single() {
commands.entity(label_entity).despawn();
}
}
}
}
More examples
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
fn asset_loaded(
asset_server: Res<AssetServer>,
mut images: ResMut<Assets<Image>>,
mut cubemap: ResMut<Cubemap>,
mut skyboxes: Query<&mut Skybox>,
) {
if !cubemap.is_loaded && asset_server.load_state(&cubemap.image_handle) == LoadState::Loaded {
info!("Swapping to {}...", CUBEMAPS[cubemap.index].0);
let image = images.get_mut(&cubemap.image_handle).unwrap();
// NOTE: PNGs do not have any metadata that could indicate they contain a cubemap texture,
// so they appear as one texture. The following code reconfigures the texture as necessary.
if image.texture_descriptor.array_layer_count() == 1 {
image.reinterpret_stacked_2d_as_array(image.height() / image.width());
image.texture_view_descriptor = Some(TextureViewDescriptor {
dimension: Some(TextureViewDimension::Cube),
..default()
});
}
for mut skybox in &mut skyboxes {
skybox.image = cubemap.image_handle.clone();
}
cubemap.is_loaded = true;
}
}
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
fn create_array_texture(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut loading_texture: ResMut<LoadingTexture>,
mut images: ResMut<Assets<Image>>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ArrayTextureMaterial>>,
) {
if loading_texture.is_loaded
|| asset_server.load_state(loading_texture.handle.clone()) != LoadState::Loaded
{
return;
}
loading_texture.is_loaded = true;
let image = images.get_mut(&loading_texture.handle).unwrap();
// Create a new array texture asset from the loaded texture.
let array_layers = 4;
image.reinterpret_stacked_2d_as_array(array_layers);
// Spawn some cubes using the array texture
let mesh_handle = meshes.add(Cuboid::default());
let material_handle = materials.add(ArrayTextureMaterial {
array_texture: loading_texture.handle.clone(),
});
for x in -5..=5 {
commands.spawn(MaterialMeshBundle {
mesh: mesh_handle.clone(),
material: material_handle.clone(),
transform: Transform::from_xyz(x as f32 + 0.5, 0.0, 0.0),
..Default::default()
});
}
}
sourcepub fn recursive_dependency_load_state(
&self,
id: impl Into<UntypedAssetId>
) -> RecursiveDependencyLoadState
pub fn recursive_dependency_load_state( &self, id: impl Into<UntypedAssetId> ) -> RecursiveDependencyLoadState
Retrieves the RecursiveDependencyLoadState
of a given asset id
.
sourcepub fn is_loaded_with_dependencies(&self, id: impl Into<UntypedAssetId>) -> bool
pub fn is_loaded_with_dependencies(&self, id: impl Into<UntypedAssetId>) -> bool
Returns true if the asset and all of its dependencies (recursive) have been loaded.
sourcepub fn get_handle<'a, A>(
&self,
path: impl Into<AssetPath<'a>>
) -> Option<Handle<A>>where
A: Asset,
pub fn get_handle<'a, A>(
&self,
path: impl Into<AssetPath<'a>>
) -> Option<Handle<A>>where
A: Asset,
Returns an active handle for the given path, if the asset at the given path has already started loading, or is still “alive”.
Examples found in repository?
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
fn setup(
mut commands: Commands,
rpg_sprite_handles: Res<RpgSpriteFolder>,
asset_server: Res<AssetServer>,
mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
loaded_folders: Res<Assets<LoadedFolder>>,
mut textures: ResMut<Assets<Image>>,
) {
let loaded_folder = loaded_folders.get(&rpg_sprite_handles.0).unwrap();
// create texture atlases with different padding and sampling
let (texture_atlas_linear, linear_texture) = create_texture_atlas(
loaded_folder,
None,
Some(ImageSampler::linear()),
&mut textures,
);
let atlas_linear_handle = texture_atlases.add(texture_atlas_linear.clone());
let (texture_atlas_nearest, nearest_texture) = create_texture_atlas(
loaded_folder,
None,
Some(ImageSampler::nearest()),
&mut textures,
);
let atlas_nearest_handle = texture_atlases.add(texture_atlas_nearest);
let (texture_atlas_linear_padded, linear_padded_texture) = create_texture_atlas(
loaded_folder,
Some(UVec2::new(6, 6)),
Some(ImageSampler::linear()),
&mut textures,
);
let atlas_linear_padded_handle = texture_atlases.add(texture_atlas_linear_padded.clone());
let (texture_atlas_nearest_padded, nearest_padded_texture) = create_texture_atlas(
loaded_folder,
Some(UVec2::new(6, 6)),
Some(ImageSampler::nearest()),
&mut textures,
);
let atlas_nearest_padded_handle = texture_atlases.add(texture_atlas_nearest_padded);
// setup 2d scene
commands.spawn(Camera2dBundle::default());
// padded textures are to the right, unpadded to the left
// draw unpadded texture atlas
commands.spawn(SpriteBundle {
texture: linear_texture.clone(),
transform: Transform {
translation: Vec3::new(-250.0, -130.0, 0.0),
scale: Vec3::splat(0.8),
..default()
},
..default()
});
// draw padded texture atlas
commands.spawn(SpriteBundle {
texture: linear_padded_texture.clone(),
transform: Transform {
translation: Vec3::new(250.0, -130.0, 0.0),
scale: Vec3::splat(0.8),
..default()
},
..default()
});
let font = asset_server.load("fonts/FiraSans-Bold.ttf");
// padding label text style
let text_style: TextStyle = TextStyle {
font: font.clone(),
font_size: 50.0,
color: Color::WHITE,
};
// labels to indicate padding
// No padding
create_label(
&mut commands,
(-250.0, 330.0, 0.0),
"No padding",
text_style.clone(),
);
// Padding
create_label(&mut commands, (250.0, 330.0, 0.0), "Padding", text_style);
// get handle to a sprite to render
let vendor_handle: Handle<Image> = asset_server
.get_handle("textures/rpg/chars/vendor/generic-rpg-vendor.png")
.unwrap();
// get index of the sprite in the texture atlas, this is used to render the sprite
// the index is the same for all the texture atlases, since they are created from the same folder
let vendor_index = texture_atlas_linear
.get_texture_index(&vendor_handle)
.unwrap();
// configuration array to render sprites through iteration
let configurations: [(&str, Handle<TextureAtlasLayout>, Handle<Image>, f32); 4] = [
("Linear", atlas_linear_handle, linear_texture, -350.0),
("Nearest", atlas_nearest_handle, nearest_texture, -150.0),
(
"Linear",
atlas_linear_padded_handle,
linear_padded_texture,
150.0,
),
(
"Nearest",
atlas_nearest_padded_handle,
nearest_padded_texture,
350.0,
),
];
// label text style
let sampling_label_style = TextStyle {
font,
font_size: 30.0,
color: Color::WHITE,
};
let base_y = 170.0; // y position of the sprites
for (sampling, atlas_handle, image_handle, x) in configurations {
// render a sprite from the texture_atlas
create_sprite_from_atlas(
&mut commands,
(x, base_y, 0.0),
vendor_index,
atlas_handle,
image_handle,
);
// render a label to indicate the sampling setting
create_label(
&mut commands,
(x, base_y + 110.0, 0.0), // offset to y position of the sprite
sampling,
sampling_label_style.clone(),
);
}
}
pub fn get_id_handle<A>(&self, id: AssetId<A>) -> Option<Handle<A>>where
A: Asset,
pub fn get_id_handle_untyped(&self, id: UntypedAssetId) -> Option<UntypedHandle>
sourcepub fn is_managed(&self, id: impl Into<UntypedAssetId>) -> bool
pub fn is_managed(&self, id: impl Into<UntypedAssetId>) -> bool
Returns true
if the given id
corresponds to an asset that is managed by this AssetServer
.
Otherwise, returns false.
sourcepub fn get_path_id<'a>(
&self,
path: impl Into<AssetPath<'a>>
) -> Option<UntypedAssetId>
pub fn get_path_id<'a>( &self, path: impl Into<AssetPath<'a>> ) -> Option<UntypedAssetId>
Returns an active untyped asset id for the given path, if the asset at the given path has already started loading, or is still “alive”. Returns the first ID in the event of multiple assets being registered against a single path.
§See also
get_path_ids
for all handles.
sourcepub fn get_path_ids<'a>(
&self,
path: impl Into<AssetPath<'a>>
) -> Vec<UntypedAssetId>
pub fn get_path_ids<'a>( &self, path: impl Into<AssetPath<'a>> ) -> Vec<UntypedAssetId>
Returns all active untyped asset IDs for the given path, if the assets at the given path have already started loading,
or are still “alive”.
Multiple IDs will be returned in the event that a single path is used by multiple AssetLoader
’s.
sourcepub fn get_handle_untyped<'a>(
&self,
path: impl Into<AssetPath<'a>>
) -> Option<UntypedHandle>
pub fn get_handle_untyped<'a>( &self, path: impl Into<AssetPath<'a>> ) -> Option<UntypedHandle>
Returns an active untyped handle for the given path, if the asset at the given path has already started loading, or is still “alive”. Returns the first handle in the event of multiple assets being registered against a single path.
§See also
get_handles_untyped
for all handles.
sourcepub fn get_handles_untyped<'a>(
&self,
path: impl Into<AssetPath<'a>>
) -> Vec<UntypedHandle>
pub fn get_handles_untyped<'a>( &self, path: impl Into<AssetPath<'a>> ) -> Vec<UntypedHandle>
Returns all active untyped handles for the given path, if the assets at the given path have already started loading,
or are still “alive”.
Multiple handles will be returned in the event that a single path is used by multiple AssetLoader
’s.
sourcepub fn get_path_and_type_id_handle(
&self,
path: &AssetPath<'_>,
type_id: TypeId
) -> Option<UntypedHandle>
pub fn get_path_and_type_id_handle( &self, path: &AssetPath<'_>, type_id: TypeId ) -> Option<UntypedHandle>
Returns an active untyped handle for the given path and TypeId
, if the asset at the given path has already started loading,
or is still “alive”.
sourcepub fn get_path(&self, id: impl Into<UntypedAssetId>) -> Option<AssetPath<'_>>
pub fn get_path(&self, id: impl Into<UntypedAssetId>) -> Option<AssetPath<'_>>
Returns the path for the given id
, if it has one.
sourcepub fn mode(&self) -> AssetServerMode
pub fn mode(&self) -> AssetServerMode
Returns the AssetServerMode
this server is currently in.
sourcepub fn preregister_loader<L>(&self, extensions: &[&str])where
L: AssetLoader,
pub fn preregister_loader<L>(&self, extensions: &[&str])where
L: AssetLoader,
Pre-register a loader that will later be added.
Assets loaded with matching extensions will be blocked until the real loader is added.
Trait Implementations§
source§impl Clone for AssetServer
impl Clone for AssetServer
source§fn clone(&self) -> AssetServer
fn clone(&self) -> AssetServer
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl Debug for AssetServer
impl Debug for AssetServer
impl Resource for AssetServer
Auto Trait Implementations§
impl Freeze for AssetServer
impl !RefUnwindSafe for AssetServer
impl Send for AssetServer
impl Sync for AssetServer
impl Unpin for AssetServer
impl !UnwindSafe for AssetServer
Blanket Implementations§
source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<Image>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<Image>) -> U
T
ShaderType
for self
. When used in AsBindGroup
derives, it is safe to assume that all images in self
exist.source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.