- Steal `asset_loading` from `bevy_new_2d` - Rename `BlockResources` to `BlockAssets` - Remove `common::blocks::*` re-exports - Turn `Args` into a resource and insert it - Add `Screen` state to see when loading finishes - Run gameplay systems only in `Gameplay` state - Start server / connect when loading finishes
parent
2c7d27311b
commit
9b77a07aa5
8 changed files with 226 additions and 82 deletions
@ -1,31 +0,0 @@ |
||||
use bevy::prelude::*; |
||||
|
||||
pub use common::block::*; |
||||
|
||||
#[derive(Resource)] |
||||
pub struct BlockResources { |
||||
mesh: Handle<Mesh>, |
||||
material: Handle<StandardMaterial>, |
||||
} |
||||
|
||||
pub fn setup_blocks( |
||||
mut commands: Commands, |
||||
mut meshes: ResMut<Assets<Mesh>>, |
||||
mut materials: ResMut<Assets<StandardMaterial>>, |
||||
) { |
||||
commands.insert_resource(BlockResources { |
||||
mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0)), |
||||
material: materials.add(Color::srgb_u8(124, 144, 255)), |
||||
}); |
||||
} |
||||
|
||||
pub fn add_block_visuals( |
||||
add: On<Add, Block>, |
||||
mut commands: Commands, |
||||
resources: Res<BlockResources>, |
||||
) { |
||||
commands.entity(add.entity).insert(( |
||||
Mesh3d(resources.mesh.clone()), |
||||
MeshMaterial3d(resources.material.clone()), |
||||
)); |
||||
} |
||||
@ -0,0 +1,41 @@ |
||||
use bevy::prelude::*; |
||||
|
||||
use common::asset_loading::LoadResource; |
||||
use common::block::Block; |
||||
|
||||
pub fn plugin(app: &mut App) { |
||||
app.add_observer(insert_block_visuals); |
||||
app.load_resource::<BlockAssets>(); |
||||
} |
||||
|
||||
#[derive(Resource, Asset, Reflect, Clone)] |
||||
#[reflect(Resource)] |
||||
pub struct BlockAssets { |
||||
#[dependency] |
||||
mesh: Handle<Mesh>, |
||||
#[dependency] |
||||
material: Handle<StandardMaterial>, |
||||
} |
||||
|
||||
impl FromWorld for BlockAssets { |
||||
fn from_world(world: &mut World) -> Self { |
||||
let assets = world.resource::<AssetServer>(); |
||||
Self { |
||||
mesh: assets.add(Cuboid::new(1.0, 1.0, 1.0).into()), |
||||
material: assets.add(Color::srgb_u8(124, 144, 255).into()), |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// Observer which automatically inserts block visuals (mesh and
|
||||
/// material) when an entity has the `Block` component added to it.
|
||||
fn insert_block_visuals( |
||||
add: On<Add, Block>, |
||||
mut commands: Commands, |
||||
block_assets: Res<BlockAssets>, |
||||
) { |
||||
commands.entity(add.entity).insert(( |
||||
Mesh3d(block_assets.mesh.clone()), |
||||
MeshMaterial3d(block_assets.material.clone()), |
||||
)); |
||||
} |
||||
@ -0,0 +1,20 @@ |
||||
use bevy::prelude::*; |
||||
|
||||
use common::asset_loading::ResourceHandles; |
||||
|
||||
use crate::Screen; |
||||
|
||||
pub fn plugin(app: &mut App) { |
||||
app.add_systems( |
||||
Update, |
||||
enter_gameplay_screen.run_if(in_state(Screen::Loading).and(all_assets_loaded)), |
||||
); |
||||
} |
||||
|
||||
fn enter_gameplay_screen(mut next_screen: ResMut<NextState<Screen>>) { |
||||
next_screen.set(Screen::Gameplay); |
||||
} |
||||
|
||||
fn all_assets_loaded(resource_handles: Res<ResourceHandles>) -> bool { |
||||
resource_handles.is_all_done() |
||||
} |
||||
@ -0,0 +1,72 @@ |
||||
//! 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::<ResourceHandles>(); |
||||
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<T: Resource + Asset + Clone + FromWorld>(&mut self) -> &mut Self; |
||||
} |
||||
|
||||
impl LoadResource for App { |
||||
fn load_resource<T: Resource + Asset + Clone + FromWorld>(&mut self) -> &mut Self { |
||||
self.init_asset::<T>(); |
||||
let world = self.world_mut(); |
||||
let value = T::from_world(world); |
||||
let assets = world.resource::<AssetServer>(); |
||||
let handle = assets.add(value); |
||||
let mut handles = world.resource_mut::<ResourceHandles>(); |
||||
handles |
||||
.waiting |
||||
.push_back((handle.untyped(), |world, handle| { |
||||
let assets = world.resource::<Assets<T>>(); |
||||
if let Some(value) = assets.get(handle.id().typed::<T>()) { |
||||
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<UntypedHandle>, |
||||
} |
||||
|
||||
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<ResourceHandles>| { |
||||
world.resource_scope(|world, assets: Mut<AssetServer>| { |
||||
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)); |
||||
} |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
@ -1,2 +1,3 @@ |
||||
pub mod asset_loading; |
||||
pub mod block; |
||||
pub mod network; |
||||
|
||||
Loading…
Reference in new issue