bevy-playground/src/map.rs

168 lines
5.8 KiB
Rust

use crate::View;
use crate::{inspector::HideFromInspector, prelude::*};
use bevy::ecs::system::SystemState;
use bevy::ecs::world::CommandQueue;
use bevy::tasks::{block_on, futures_lite::future, AsyncComputeTaskPool, Task};
use bevy_ecs_tilemap::prelude::*;
use rand::prelude::*;
use rand_pcg::Pcg64;
use rand_seeder::Seeder;
use std::sync::mpsc::{channel, Receiver};
use std::sync::Mutex;
#[derive(Component, Debug)]
pub struct Tilemap;
#[derive(Component, Debug)]
pub struct TileChan(Mutex<Receiver<TileBundle>>);
#[derive(Component, Debug)]
pub struct TileLoaderTask(Task<()>);
pub fn init(mut commands: Commands, assets: Res<AssetServer>) {
// 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 tile_size = TilemapTileSize::new(16., 16.);
let grid_size = TilemapGridSize::new(16., 16.);
let map_type = TilemapType::Square;
let texture = TilemapTexture::Single(assets.load("img/Tileset Grass.png"));
let storage = TileStorage::empty(size);
let tilemap = commands
.spawn((
Tilemap,
Name::new("Tilemap"),
TilemapBundle {
grid_size,
map_type,
size,
storage,
texture,
tile_size,
transform: get_tilemap_center_transform(&size, &grid_size, &map_type, f32::MIN),
..Default::default()
},
))
.id();
let pool = AsyncComputeTaskPool::get();
let (tx, rx) = channel::<TileBundle>();
let task = pool.spawn(async move {
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
});
tx.send(TileBundle {
position,
tilemap_id: TilemapId(tilemap),
texture_index,
..Default::default()
})
.unwrap();
}
}
return ();
});
commands
.entity(tilemap)
.insert((TileLoaderTask(task), TileChan(Mutex::new(rx))));
}
const MAX_TILES_TO_LOAD_IN_ONE_UPDATE: usize = 5_000;
pub fn tile_loaders(
world: &mut World,
tilemap: QueryState<Entity, With<Tilemap>>,
storage: &mut QueryState<&mut TileStorage, With<Tilemap>>,
chan: QueryState<&TileChan, With<Tilemap>>,
task: QueryState<&mut TileLoaderTask, With<Tilemap>>,
params: &mut SystemState<ResMut<NextState<View>>>,
) {
// TODO: this state should maybe be converted to a resource or something?
let mut tiles_done = false;
let mut task_done = false;
type AddingTile = (HideFromInspector, TileBundle);
type AddedTile<'a> = (Entity, &'a TilePos);
let mut tiles_to_add: Vec<AddingTile> = Vec::with_capacity(MAX_TILES_TO_LOAD_IN_ONE_UPDATE);
let mut added_tiles: Vec<AddedTile> = Vec::with_capacity(MAX_TILES_TO_LOAD_IN_ONE_UPDATE);
// let mut task = task;
// {
// task_done = true;
// let mut task = task_query.get_single();
// if let Ok(task) = task {
// let poll = future::poll_once(task.0);
// if block_on(poll).is_some() {
// task_done = true;
// // task is done, remove it so we don't poll it again
// world.entity_mut(tilemap).remove::<TileLoaderTask>();
// }
// } else {
// next_view.set(View::InGame)
// }
// let (tilemap, mut storage) = entity_query.single_mut();
// let tiles: Vec<TileBundle> = vec![];
// if let Ok(channel) = channel_query.get_single_mut() {
// let channel = channel.0.lock().unwrap();
// tiles_done = false;
// let mut counter = 0;
// loop {
// match channel.recv() {
// Ok(tile) => {
// let position = &tile.position;
// let tile = world.spawn((HideFromInspector, tile)).id();
// storage.set(position, tile);
// counter += 1;
// if counter >= MAX_TILES_TO_LOAD_IN_ONE_UPDATE {
// info!("Finished {}!", counter);
// break;
// }
// }
// Err(_) => {
// world.entity_mut(tilemap).remove::<TileChan>();
// if counter > 0 {
// info!("Finished {counter}! Probably finishing mapgen soon...");
// }
// // the channel is likely closed, so let's note that and be done
// tiles_done = true;
// break;
// }
// }
// }
// }
for tile in tiles_to_add {
added_tiles.push((id, &tile.1.position));
let id = world.spawn(tile).id();
}
// world.spawn_batch(
// tiles
// .into_iter()
// .map(|t| (HideFromInspector, t))
// .into_iter(),
// );
{
let mut storage = storage.single_mut(world);
// storage.set(&
let mut next_view = params.get_mut(world);
if task_done && tiles_done {
next_view.set(View::InGame)
}
}
}
pub fn exit(mut commands: Commands, q: Query<Entity, With<Tilemap>>) {
for id in q.iter() {
commands.entity(id).despawn_recursive();
}
}