use crate::{inspector::HideFromInspector, prelude::*}; use bevy::{ ecs::{system::SystemState, world::CommandQueue}, tasks::{block_on, futures_lite::future, AsyncComputeTaskPool, Task}, }; // use bevy::{ // ecs::world::CommandQueue, // tasks::{AsyncComputeTaskPool, Task}, // }; use bevy_ecs_tilemap::prelude::*; use rand::prelude::*; use rand_pcg::Pcg64; use rand_seeder::Seeder; #[derive(Component, Debug)] pub struct Tilemap; #[derive(Component)] struct MapGenTask(Task); #[derive(Resource, Deref, DerefMut)] struct TileStorageHandle(TileStorage); pub fn spawn(mut commands: Commands, assets: Res) { // TODO: I'm pretty determined to not have this sieze up the game despite the large number of entities being added. Should work with a "loading" screen and doing this in the background? let mut rng: Pcg64 = Seeder::from("default_seed").make_rng(); let size = TilemapSize::new(1024, 1024); let tilemap = commands.spawn((Tilemap, Name::new("Tilemap"))).id(); commands.insert_resource(TileStorageHandle(TileStorage::empty(size))); let pool = AsyncComputeTaskPool::get(); // this task is for generating tilebundles for x in 0..size.x { for y in 0..size.y { let position = TilePos::new(x, y); let texture_index = TileTextureIndex(if rng.gen_range(0..1000) > 925 { rng.gen_range(0..(16 * 8)) } else { 0 }); let task = pool.spawn(async move { let mut command_queue = CommandQueue::default(); command_queue.push(move |world: &mut World| { let mut state = SystemState::>::new(world); let entity = world .spawn(( HideFromInspector, TileBundle { position, tilemap_id: TilemapId(tilemap), texture_index, ..Default::default() }, )) .id(); let mut storage = state.get_mut(world); storage.set(&position, entity); }); command_queue }); commands.entity(tilemap).insert(MapGenTask(task)); } } } fn load(mut commands: Commands, mut tasks: Query<&mut MapGenTask>) { // to avoid locking up the universe we only want to handle a certain number per iteration (Update) for mut task in &mut tasks { if let Some(mut commands_queue) = block_on(future::poll_once(&mut task.0)) { // append the returned command queue to have it execute later commands.append(&mut commands_queue); } } } pub fn finalize( // mut commands: Commands, // mut storage: Res, // tilemap: Query>, // assets: Res, world: &mut World, ) { let storage = world.remove_resource::().unwrap(); // TODO: dedupe with load let size = TilemapSize::new(1024, 1024); let tile_size = TilemapTileSize::new(16., 16.); let grid_size = TilemapGridSize::new(16., 16.); let map_type = TilemapType::Square; let storage = storage.0; let mut query = world.query_filtered::>(); let tilemap = query.single(world); let assets = world.resource::(); let texture = TilemapTexture::Single(assets.load("img/Tileset Grass.png")); let mut commands = world.commands(); commands.entity(tilemap).insert(TilemapBundle { grid_size, map_type, size, storage, texture, tile_size, transform: get_tilemap_center_transform(&size, &grid_size, &map_type, f32::MIN), ..Default::default() }); } pub fn exit(mut commands: Commands, q: Query>) { for id in q.iter() { commands.entity(id).despawn_recursive(); } }