use std::{cmp::Eq, hash::Hash};
use crate::{
chunks::{Chunk, ChunkCoord, InMap},
coords::{calculate_chunk_coordinate, calculate_tile_index},
maps::TileMap,
tiles::{InChunk, TileCoord, TileIndex},
};
use bevy::{
ecs::system::EntityCommands,
prelude::{Bundle, Commands, Entity, World},
utils::{hashbrown::hash_map::Entry, HashMap},
};
mod chunk_batch;
mod chunk_single;
mod map;
mod tile_batch;
mod tile_single;
use chunk_batch::*;
use chunk_single::*;
use map::*;
use tile_batch::*;
use tile_single::*;
pub struct TileMapCommands<'a, 'w, 's, const N: usize> {
commands: &'a mut Commands<'w, 's>,
map_id: Entity,
}
impl<'a, 'w, 's, const N: usize> TileMapCommands<'a, 'w, 's, N> {
pub fn spawn_tile(
&mut self,
tile_c: impl Into<[i32; N]>,
bundle: impl Bundle,
) -> EntityCommands<'_> {
let tile_c = tile_c.into();
self.commands.spawn_tile(self.map_id, tile_c, bundle)
}
pub fn spawn_tile_batch<F, B, IC>(&mut self, tile_cs: IC, bundle_f: F) -> &mut Self
where
F: Fn([i32; N]) -> B + Send + 'static,
B: Bundle + Send + 'static,
IC: IntoIterator<Item = [i32; N]> + Send + 'static,
{
self.commands
.spawn_tile_batch(self.map_id, tile_cs, bundle_f);
self
}
pub fn despawn_tile(&mut self, tile_c: impl Into<[i32; N]>) -> &mut Self {
let tile_c = tile_c.into();
self.commands.despawn_tile(self.map_id, tile_c);
self
}
pub fn despawn_tile_batch<IC>(&mut self, tile_cs: IC) -> &mut Self
where
IC: IntoIterator<Item = [i32; N]> + Send + 'static,
{
self.commands.despawn_tile_batch(self.map_id, tile_cs);
self
}
pub fn move_tile(
&mut self,
old_c: impl Into<[i32; N]>,
new_c: impl Into<[i32; N]>,
) -> &mut Self {
let old_c = old_c.into();
let new_c = new_c.into();
self.commands.move_tile(self.map_id, old_c, new_c);
self
}
pub fn move_tile_batch<IC>(&mut self, tile_cs: IC) -> &mut Self
where
IC: IntoIterator<Item = ([i32; N], [i32; N])> + Send + 'static,
{
self.commands.move_tile_batch(self.map_id, tile_cs);
self
}
pub fn swap_tiles(
&mut self,
tile_c_1: impl Into<[i32; N]>,
tile_c_2: impl Into<[i32; N]>,
) -> &mut Self {
let tile_c_1 = tile_c_1.into();
let tile_c_2 = tile_c_2.into();
self.commands.swap_tiles(self.map_id, tile_c_1, tile_c_2);
self
}
pub fn swap_tile_batch<IC>(&mut self, tile_cs: IC) -> &mut Self
where
IC: IntoIterator<Item = ([i32; N], [i32; N])> + Send + 'static,
{
self.commands.swap_tile_batch(self.map_id, tile_cs);
self
}
pub fn spawn_chunk(
&mut self,
chunk_c: impl Into<[i32; N]>,
bundle: impl Bundle,
) -> EntityCommands<'_> {
let chunk_c = chunk_c.into();
self.commands.spawn_chunk(self.map_id, chunk_c, bundle)
}
pub fn spawn_chunk_batch_with<F, B, IC>(&mut self, chunk_cs: IC, bundle_f: F) -> &mut Self
where
F: Fn([i32; N]) -> B + Send + 'static,
B: Bundle + Send + 'static,
IC: IntoIterator<Item = [i32; N]> + Send + 'static,
{
self.commands
.spawn_chunk_batch_with(self.map_id, chunk_cs, bundle_f);
self
}
pub fn despawn_chunk(&mut self, chunk_c: impl Into<[i32; N]>) -> &mut Self {
let chunk_c = chunk_c.into();
self.commands.despawn_chunk(self.map_id, chunk_c);
self
}
pub fn despawn_chunk_batch<IC>(&mut self, chunk_cs: IC) -> &mut Self
where
IC: IntoIterator<Item = [i32; N]> + Send + 'static,
{
self.commands.despawn_chunk_batch(self.map_id, chunk_cs);
self
}
pub fn despawn_map(self) {
TileCommandExt::<N>::despawn_map(self.commands, self.map_id);
}
pub fn id(&self) -> Entity {
self.map_id
}
pub fn insert(&mut self, bundle: impl Bundle) -> &mut Self {
self.commands.entity(self.map_id).insert(bundle);
self
}
}
pub trait TileCommandExt<'w, 's, const N: usize> {
fn tile_map<'a>(&'a mut self, map_id: Entity) -> TileMapCommands<'a, 'w, 's, N>;
fn spawn_tile(
&mut self,
map_id: Entity,
tile_c: [i32; N],
bundle: impl Bundle,
) -> EntityCommands<'_>;
fn spawn_tile_batch<F, B, IC>(&mut self, map_id: Entity, tile_cs: IC, bundle_f: F)
where
F: Fn([i32; N]) -> B + Send + 'static,
B: Bundle + Send + 'static,
IC: IntoIterator<Item = [i32; N]> + Send + 'static;
fn despawn_tile(&mut self, map_id: Entity, tile_c: [i32; N]) -> &mut Self;
fn despawn_tile_batch<IC>(&mut self, map_id: Entity, tile_cs: IC)
where
IC: IntoIterator<Item = [i32; N]> + Send + 'static;
fn move_tile(
&mut self,
map_id: Entity,
old_c: impl Into<[i32; N]>,
new_c: impl Into<[i32; N]>,
) -> &mut Self;
fn move_tile_batch<IC>(&mut self, map_id: Entity, tile_cs: IC)
where
IC: IntoIterator<Item = ([i32; N], [i32; N])> + Send + 'static;
fn swap_tiles(&mut self, map_id: Entity, tile_c_1: [i32; N], tile_c_2: [i32; N]) -> &mut Self;
fn swap_tile_batch<IC>(&mut self, map_id: Entity, tile_cs: IC)
where
IC: IntoIterator<Item = ([i32; N], [i32; N])> + Send + 'static;
fn spawn_chunk(
&mut self,
map_id: Entity,
chunk_c: [i32; N],
bundle: impl Bundle,
) -> EntityCommands<'_>;
fn spawn_chunk_batch_with<F, B, IC>(&mut self, map_id: Entity, chunk_cs: IC, bundle_f: F)
where
F: Fn([i32; N]) -> B + Send + 'static,
B: Bundle + Send + 'static,
IC: IntoIterator<Item = [i32; N]> + Send + 'static;
fn despawn_chunk(&mut self, map_id: Entity, chunk_c: [i32; N]) -> &mut Self;
fn despawn_chunk_batch<IC>(&mut self, map_id: Entity, chunk_cs: IC)
where
IC: IntoIterator<Item = [i32; N]> + Send + 'static;
fn spawn_map(
&mut self,
chunk_size: usize,
bundle: impl Bundle,
) -> TileMapCommands<'_, 'w, 's, N>;
fn despawn_map(&mut self, map_id: Entity) -> &mut Self;
}
impl<'w, 's, const N: usize> TileCommandExt<'w, 's, N> for Commands<'w, 's> {
fn tile_map(&mut self, map_id: Entity) -> TileMapCommands<'_, 'w, 's, N> {
TileMapCommands {
commands: self,
map_id,
}
}
fn spawn_tile(
&mut self,
map_id: Entity,
tile_c: [i32; N],
bundle: impl Bundle,
) -> EntityCommands<'_> {
let tile_id = self.spawn(bundle).id();
self.add(SpawnTile::<N> {
map_id,
tile_c,
tile_id,
});
self.entity(tile_id)
}
fn spawn_tile_batch<F, B, IC>(&mut self, map_id: Entity, tile_cs: IC, bundle_f: F)
where
F: Fn([i32; N]) -> B + Send + 'static,
B: Bundle + Send + 'static,
IC: IntoIterator<Item = [i32; N]> + Send + 'static,
{
self.add(SpawnTileBatch::<F, B, IC, N> {
map_id,
tile_cs,
bundle_f,
});
}
fn despawn_tile(&mut self, map_id: Entity, tile_c: [i32; N]) -> &mut Self {
self.add(DespawnTile::<N> { map_id, tile_c });
self
}
fn despawn_tile_batch<IC>(&mut self, map_id: Entity, tile_cs: IC)
where
IC: IntoIterator<Item = [i32; N]> + Send + 'static,
{
self.add(DespawnTileBatch::<IC, N> { map_id, tile_cs });
}
fn move_tile(
&mut self,
map_id: Entity,
old_c: impl Into<[i32; N]>,
new_c: impl Into<[i32; N]>,
) -> &mut Self {
let old_c = old_c.into();
let new_c = new_c.into();
self.add(MoveTile::<N> {
map_id,
old_c,
new_c,
});
self
}
fn move_tile_batch<IC>(&mut self, map_id: Entity, tile_cs: IC)
where
IC: IntoIterator<Item = ([i32; N], [i32; N])> + Send + 'static,
{
self.add(MoveTileBatch::<IC, N> { map_id, tile_cs });
}
fn swap_tiles(&mut self, map_id: Entity, tile_c_1: [i32; N], tile_c_2: [i32; N]) -> &mut Self {
self.add(SwapTile::<N> {
map_id,
tile_c_1,
tile_c_2,
});
self
}
fn swap_tile_batch<IC>(&mut self, map_id: Entity, tile_cs: IC)
where
IC: IntoIterator<Item = ([i32; N], [i32; N])> + Send + 'static,
{
self.add(SwapTileBatch::<IC, N> { map_id, tile_cs });
}
fn spawn_chunk(
&mut self,
map_id: Entity,
chunk_c: [i32; N],
bundle: impl Bundle,
) -> EntityCommands<'_> {
let chunk_id = self.spawn(bundle).id();
self.add(SpawnChunk::<N> {
map_id,
chunk_c,
chunk_id,
});
self.entity(chunk_id)
}
fn spawn_chunk_batch_with<F, B, IC>(&mut self, map_id: Entity, chunk_cs: IC, bundle_f: F)
where
F: Fn([i32; N]) -> B + Send + 'static,
B: Bundle + Send + 'static,
IC: IntoIterator<Item = [i32; N]> + Send + 'static,
{
self.add(SpawnChunkBatch::<F, B, IC, N> {
map_id,
chunk_cs,
bundle_f,
});
}
fn despawn_chunk(&mut self, map_id: Entity, chunk_c: [i32; N]) -> &mut Self {
self.add(DespawnChunk::<N> { map_id, chunk_c });
self
}
fn despawn_chunk_batch<IC>(&mut self, map_id: Entity, chunk_cs: IC)
where
IC: IntoIterator<Item = [i32; N]> + Send + 'static,
{
self.add(DespawnChunkBatch::<IC, N> { map_id, chunk_cs });
}
fn spawn_map(
&mut self,
chunk_size: usize,
bundle: impl Bundle,
) -> TileMapCommands<'_, 'w, 's, N> {
let map_id = self.spawn(bundle).id();
self.add(SpawnMap::<N> { map_id, chunk_size });
TileMapCommands {
map_id,
commands: self,
}
}
fn despawn_map(&mut self, map_id: Entity) -> &mut Self {
self.add(DespawnMap::<N> { map_id });
self
}
}
#[inline]
fn spawn_or_remove_chunk<const N: usize>(
world: &mut World,
map: &mut TileMap<N>,
map_id: Entity,
chunk_c: [i32; N],
) -> (Entity, Chunk) {
if let Some(chunk_info) = remove_chunk::<N>(world, map, chunk_c) {
chunk_info
} else {
let chunk_c = ChunkCoord(chunk_c);
let chunk_id = world.spawn((ChunkCoord(chunk_c.0), InMap(map_id))).id();
map.get_chunks_mut().insert(chunk_c, chunk_id);
(chunk_id, Chunk::new(map.get_chunk_size().pow(N as u32)))
}
}
#[inline]
fn remove_chunk<const N: usize>(
world: &mut World,
map: &mut TileMap<N>,
chunk_c: [i32; N],
) -> Option<(Entity, Chunk)> {
map.get_chunks_mut()
.get::<ChunkCoord<N>>(&ChunkCoord(chunk_c))
.cloned()
.and_then(|chunk_id| world.get_entity_mut(chunk_id))
.map(|mut chunk_e| (chunk_e.id(), chunk_e.take::<Chunk>().unwrap()))
}
#[inline]
fn remove_map<const N: usize>(world: &mut World, map_id: Entity) -> Option<TileMap<N>> {
world
.get_entity_mut(map_id)
.and_then(|mut map_e| map_e.take::<TileMap<N>>())
}
pub fn insert_tile_into_map<const N: usize>(
world: &mut World,
map: &mut TileMap<N>,
map_id: Entity,
tile_c: [i32; N],
tile_id: Entity,
) {
let chunk_size = map.get_chunk_size();
let chunk_c = calculate_chunk_coordinate(tile_c, chunk_size);
let (chunk_id, mut chunk) = spawn_or_remove_chunk::<N>(world, map, map_id, chunk_c);
let tile_i = calculate_tile_index(tile_c, chunk_size);
if let Some(tile) = chunk.0.get_mut(tile_i) {
if let Some(old_tile_id) = tile.replace(tile_id) {
world.despawn(old_tile_id);
}
}
world.get_entity_mut(tile_id).unwrap().insert((
TileIndex(tile_i),
TileCoord::<N>(tile_c),
InChunk(chunk_id),
));
world.get_entity_mut(chunk_id).unwrap().insert(chunk);
}
pub fn insert_tile<const N: usize>(
world: &mut World,
map_id: Entity,
tile_c: [i32; N],
tile_id: Entity,
) {
let mut map = remove_map::<N>(world, map_id)
.unwrap_or_else(|| panic!("Could not find tile map with id '{:?}'", map_id));
insert_tile_into_map(world, &mut map, map_id, tile_c, tile_id);
world.get_entity_mut(map_id).unwrap().insert(map);
}
pub fn take_tile_from_map<const N: usize>(
world: &mut World,
map: &mut TileMap<N>,
tile_c: [i32; N],
) -> Option<Entity> {
let chunk_size = map.get_chunk_size();
let chunk_c = calculate_chunk_coordinate(tile_c, chunk_size);
let (chunk_id, mut chunk) = remove_chunk::<N>(world, map, chunk_c)?;
let tile_i = calculate_tile_index(tile_c, chunk_size);
let tile = if let Some(mut tile_e) = chunk
.0
.get_mut(tile_i)
.and_then(|tile| tile.take())
.and_then(|tile_id| world.get_entity_mut(tile_id))
{
tile_e.remove::<(TileIndex, TileCoord<2>, InChunk)>();
let tile_id = tile_e.id();
Some(tile_id)
} else {
None
};
world.get_entity_mut(chunk_id).unwrap().insert(chunk);
tile
}
pub fn take_tile<const N: usize>(
world: &mut World,
map_id: Entity,
tile_c: [i32; N],
) -> Option<Entity> {
let mut map = remove_map::<N>(world, map_id)?;
let tile = take_tile_from_map(world, &mut map, tile_c);
world.get_entity_mut(map_id).unwrap().insert(map);
tile
}
pub fn insert_tile_batch<const N: usize>(
world: &mut World,
map_id: Entity,
tiles: impl IntoIterator<Item = ([i32; N], Entity)>,
) {
let mut map = remove_map::<N>(world, map_id)
.unwrap_or_else(|| panic!("Could not find tile map with id '{:?}'", map_id));
let chunk_size = map.get_chunk_size();
let chunked_tiles = tiles
.into_iter()
.group_by(|(tile_c, _)| calculate_chunk_coordinate(*tile_c, chunk_size));
let tiles_with_chunk = Vec::from_iter(chunked_tiles.into_iter().map(|(chunk_c, tiles)| {
let (chunk_id, chunk) = spawn_or_remove_chunk::<N>(world, &mut map, map_id, chunk_c);
(chunk_id, chunk, tiles)
}));
for (chunk_id, mut chunk, tiles) in tiles_with_chunk {
for (tile_c, tile_id) in tiles {
let tile_i = calculate_tile_index(tile_c, chunk_size);
if let Some(tile) = chunk.0.get_mut(tile_i) {
if let Some(old_tile_id) = tile.replace(tile_id) {
world.despawn(old_tile_id);
}
}
world.get_entity_mut(tile_id).unwrap().insert((
TileIndex(tile_i),
TileCoord::<N>(tile_c),
InChunk(chunk_id),
));
}
world.get_entity_mut(chunk_id).unwrap().insert(chunk);
}
world.get_entity_mut(map_id).unwrap().insert(map);
}
pub fn take_tile_batch<const N: usize>(
world: &mut World,
map_id: Entity,
tiles: impl IntoIterator<Item = [i32; N]>,
) -> Vec<([i32; N], Entity)> {
let Some(mut map) = remove_map::<N>(world, map_id) else {
return Vec::new();
};
let chunk_size = map.get_chunk_size();
let chunked_tiles = tiles
.into_iter()
.group_by(|tile_c| calculate_chunk_coordinate(*tile_c, chunk_size));
let tiles_with_chunk = chunked_tiles
.into_iter()
.filter_map(|(chunk_c, tiles)| {
remove_chunk::<N>(world, &mut map, chunk_c)
.map(|chunk_info| (chunk_info.0, chunk_info.1, tiles))
})
.map(|(chunk_id, chunk, tiles)| {
(
chunk_id,
chunk,
tiles.into_iter().collect::<Vec<[i32; N]>>(),
)
})
.collect::<Vec<(Entity, Chunk, Vec<[i32; N]>)>>();
let mut tile_ids = Vec::new();
for (chunk_id, mut chunk, tiles) in tiles_with_chunk {
for tile_c in tiles {
let tile_i = calculate_tile_index(tile_c, chunk_size);
if let Some(mut tile_e) = chunk
.0
.get_mut(tile_i)
.and_then(|tile| tile.take())
.and_then(|tile_id| world.get_entity_mut(tile_id))
{
tile_e.remove::<(TileIndex, TileCoord<N>, InChunk)>();
let tile_id = tile_e.id();
tile_ids.push((tile_c, tile_id));
}
}
world.get_entity_mut(chunk_id).unwrap().insert(chunk);
}
world.get_entity_mut(map_id).unwrap().insert(map);
tile_ids
}
pub fn insert_chunk<const N: usize>(
world: &mut World,
map_id: Entity,
chunk_c: [i32; N],
chunk_id: Entity,
) {
let mut map = remove_map::<N>(world, map_id)
.unwrap_or_else(|| panic!("Could not find tile map with id '{:?}'", map_id));
let chunk_size = map.get_chunk_size();
if let Some(old_chunk) = take_chunk_despawn_tiles_inner::<N>(world, &mut map, chunk_c) {
world.despawn(old_chunk);
}
let chunk_c = ChunkCoord(chunk_c);
world.get_entity_mut(chunk_id).unwrap().insert((
Chunk::new(chunk_size.pow(N as u32)),
ChunkCoord(chunk_c.0),
InMap(map_id),
));
map.get_chunks_mut().insert(chunk_c, chunk_id);
world.entity_mut(map_id).insert(map);
}
pub fn take_chunk<const N: usize>(
world: &mut World,
map_id: Entity,
chunk_c: [i32; N],
) -> Option<Entity> {
let mut map = remove_map::<N>(world, map_id)?;
let chunk_id = if let Some(mut chunk_e) = map
.get_chunks_mut()
.remove::<ChunkCoord<N>>(&ChunkCoord(chunk_c))
.and_then(|chunk_id| world.get_entity_mut(chunk_id))
{
let (chunk, _, _) = chunk_e.take::<(Chunk, ChunkCoord<2>, InMap)>().unwrap();
let chunk_id = chunk_e.id();
for tile_id in chunk.0.into_iter().flatten() {
if let Some(mut tile) = world.get_entity_mut(tile_id) {
tile.remove::<InChunk>();
}
}
Some(chunk_id)
} else {
None
};
world.entity_mut(map_id).insert(map);
chunk_id
}
pub fn take_chunk_despawn_tiles<const N: usize>(
world: &mut World,
map_id: Entity,
chunk_c: [i32; N],
) -> Option<Entity> {
let mut map = remove_map::<N>(world, map_id)?;
let chunk_id = take_chunk_despawn_tiles_inner::<N>(world, &mut map, chunk_c);
world.entity_mut(map_id).insert(map);
chunk_id
}
pub(crate) fn take_chunk_despawn_tiles_inner<const N: usize>(
world: &mut World,
map: &mut TileMap<N>,
chunk_c: [i32; N],
) -> Option<Entity> {
let chunk_c = ChunkCoord(chunk_c);
if let Some(chunk_id) = map.get_chunks_mut().remove::<ChunkCoord<N>>(&chunk_c) {
despawn_chunk_tiles::<N>(world, chunk_id)
} else {
None
}
}
pub(crate) fn despawn_chunk_tiles<const N: usize>(
world: &mut World,
chunk_id: Entity,
) -> Option<Entity> {
let mut chunk_e = world.get_entity_mut(chunk_id)?;
let (chunk, _, _) = chunk_e.take::<(Chunk, ChunkCoord<N>, InMap)>().unwrap();
let chunk_id = chunk_e.id();
for tile_id in chunk.0.into_iter().flatten() {
world.despawn(tile_id);
}
Some(chunk_id)
}
pub fn insert_chunk_batch<const N: usize>(
world: &mut World,
map_id: Entity,
chunks: impl IntoIterator<Item = ([i32; N], Entity)>,
) {
let mut map = remove_map::<N>(world, map_id)
.unwrap_or_else(|| panic!("Could not find tile map with id '{:?}'", map_id));
let chunk_size = map.get_chunk_size();
for (chunk_c, chunk_id) in chunks.into_iter() {
if let Some(old_chunk) = take_chunk_despawn_tiles_inner::<N>(world, &mut map, chunk_c) {
world.despawn(old_chunk);
}
let chunk_c = ChunkCoord(chunk_c);
world.get_entity_mut(chunk_id).unwrap().insert((
Chunk::new(chunk_size.pow(N as u32)),
ChunkCoord(chunk_c.0),
InMap(map_id),
));
map.get_chunks_mut().insert(chunk_c, chunk_id);
}
world.get_entity_mut(map_id).unwrap().insert(map);
}
pub fn take_chunk_batch<const N: usize>(
world: &mut World,
map_id: Entity,
chunks: impl IntoIterator<Item = [i32; N]>,
) -> Vec<([i32; N], Entity)> {
let mut map = if let Some(map_info) = remove_map::<N>(world, map_id) {
map_info
} else {
return Vec::new();
};
let mut chunk_ids = Vec::new();
for chunk_c in chunks.into_iter() {
if let Some(mut chunk_e) = map
.get_chunks_mut()
.remove::<ChunkCoord<N>>(&ChunkCoord(chunk_c))
.and_then(|chunk_id| world.get_entity_mut(chunk_id))
{
let (chunk, _, _) = chunk_e.take::<(Chunk, ChunkCoord<2>, InMap)>().unwrap();
let chunk_id = chunk_e.id();
for tile_id in chunk.0.into_iter().flatten() {
if let Some(mut tile) = world.get_entity_mut(tile_id) {
tile.remove::<InChunk>();
}
}
chunk_ids.push((chunk_c, chunk_id));
};
}
world.get_entity_mut(map_id).unwrap().insert(map);
chunk_ids
}
pub fn take_chunk_batch_despawn_tiles<const N: usize>(
world: &mut World,
map_id: Entity,
chunks: impl IntoIterator<Item = [i32; N]>,
) -> Vec<([i32; N], Entity)> {
let mut map = if let Some(map_info) = remove_map::<N>(world, map_id) {
map_info
} else {
return Vec::new();
};
let mut chunk_ids = Vec::new();
for chunk_c in chunks.into_iter() {
if let Some(mut chunk_e) = map
.get_chunks_mut()
.remove::<ChunkCoord<N>>(&ChunkCoord(chunk_c))
.and_then(|chunk_id| world.get_entity_mut(chunk_id))
{
let (chunk, _, _) = chunk_e.take::<(Chunk, ChunkCoord<2>, InMap)>().unwrap();
let chunk_id = chunk_e.id();
for tile_id in chunk.0.into_iter().flatten() {
world.despawn(tile_id);
}
chunk_ids.push((chunk_c, chunk_id));
};
}
world.get_entity_mut(map_id).unwrap().insert(map);
chunk_ids
}
pub fn insert_map<const N: usize>(world: &mut World, map_id: Entity, chunk_size: usize) {
if let Some(mut map) = remove_map::<N>(world, map_id) {
despawn_children::<N>(world, &mut map);
}
world
.entity_mut(map_id)
.insert(TileMap::<N>::with_chunk_size(chunk_size));
}
pub fn despawn_children<const N: usize>(world: &mut World, map: &mut TileMap<N>) {
for (_, chunk_id) in map.get_chunks_mut().drain() {
if let Some(chunk_id) = despawn_chunk_tiles::<N>(world, chunk_id) {
world.despawn(chunk_id);
}
}
}
trait GroupBy: Iterator {
fn group_by<F, K>(
self,
f: F,
) -> bevy::utils::hashbrown::hash_map::IntoIter<
K,
std::vec::Vec<<Self as std::iter::Iterator>::Item>,
>
where
F: Fn(&Self::Item) -> K,
K: Eq + Hash;
}
impl<T> GroupBy for T
where
T: Iterator,
{
fn group_by<F, K>(
self,
f: F,
) -> bevy::utils::hashbrown::hash_map::IntoIter<
K,
std::vec::Vec<<T as std::iter::Iterator>::Item>,
>
where
F: Fn(&Self::Item) -> K,
K: Eq + Hash,
{
let mut map = HashMap::new();
for item in self {
let key = f(&item);
match map.entry(key) {
Entry::Vacant(v) => {
v.insert(vec![item]);
}
Entry::Occupied(mut o) => o.get_mut().push(item),
}
}
map.into_iter()
}
}