168 lines
5.8 KiB
Rust
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();
|
|
}
|
|
}
|