parent
958907228d
commit
5013ded7c9
7 changed files with 193 additions and 54 deletions
@ -1,24 +1,10 @@ |
|||||||
use bevy::{platform::collections::HashMap, prelude::*}; |
use bevy::{platform::collections::HashMap, prelude::*}; |
||||||
|
|
||||||
use super::{ |
use crate::bloxel::math::ChunkPos; |
||||||
math::{ChunkPos, USize3, CHUNK_LENGTH}, |
|
||||||
storage::PaletteBloxelStorage, |
|
||||||
}; |
|
||||||
|
|
||||||
#[derive(Component, Default)] |
#[derive(Component, Default)] |
||||||
pub struct Chunk; |
pub struct Chunk; |
||||||
|
|
||||||
#[derive(Component, Deref, DerefMut)] |
|
||||||
#[require(Chunk)] |
|
||||||
pub struct ChunkData(PaletteBloxelStorage<Entity>); |
|
||||||
|
|
||||||
impl ChunkData { |
|
||||||
pub fn new(default: Entity) -> Self { |
|
||||||
let len = (CHUNK_LENGTH as u32).try_into().unwrap(); |
|
||||||
Self(PaletteBloxelStorage::new(USize3::splat(len), default)) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
#[derive(Component, Default, Deref, DerefMut)] |
#[derive(Component, Default, Deref, DerefMut)] |
||||||
#[require(Transform, Visibility)] |
#[require(Transform, Visibility)] |
||||||
pub struct ChunkMap(HashMap<ChunkPos, Entity>); |
pub struct ChunkMap(HashMap<ChunkPos, Entity>); |
||||||
|
@ -0,0 +1,90 @@ |
|||||||
|
use bevy::{platform::collections::HashMap, prelude::*}; |
||||||
|
|
||||||
|
use crate::bloxel::prelude::*; |
||||||
|
|
||||||
|
pub struct ChunkedBloxelView<'a, T: BloxelStore<Entity>> { |
||||||
|
region: BlockRegion, |
||||||
|
map: HashMap<ChunkPos, &'a T>, |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a, T: BloxelStore<Entity>> ChunkedBloxelView<'a, T> { |
||||||
|
pub fn new(region: BlockRegion) -> Self { |
||||||
|
let map = HashMap::new(); |
||||||
|
Self { region, map } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn insert(&mut self, chunk_pos: ChunkPos, data: &'a T) { |
||||||
|
self.map.insert(chunk_pos, data); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get(&self, pos: BlockPos) -> Option<Entity> { |
||||||
|
let (chunk_pos, rel_pos) = ChunkPos::from_block_pos(pos); |
||||||
|
self.map.get(&chunk_pos).and_then(|d| d.get(rel_pos)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T: BloxelStore<Entity>> BloxelStore<Entity> for ChunkedBloxelView<'_, T> { |
||||||
|
fn size(&self) -> USize3 { |
||||||
|
self.region.size() |
||||||
|
} |
||||||
|
|
||||||
|
fn get(&self, pos: IVec3) -> Option<Entity> { |
||||||
|
ChunkedBloxelView::get(self, self.region.min() + pos) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub struct ChunkedBloxelViewSingleMut<'a, T: BloxelStore<Entity>, M: BloxelStoreMut<Entity>> { |
||||||
|
region: BlockRegion, |
||||||
|
main: (ChunkPos, &'a mut M), |
||||||
|
map: HashMap<ChunkPos, &'a T>, |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a, T: BloxelStore<Entity>, M: BloxelStoreMut<Entity>> ChunkedBloxelViewSingleMut<'a, T, M> { |
||||||
|
pub fn new(region: BlockRegion, main: (ChunkPos, &'a mut M)) -> Self { |
||||||
|
let map = HashMap::new(); |
||||||
|
Self { region, main, map } |
||||||
|
} |
||||||
|
|
||||||
|
pub fn insert(&mut self, chunk_pos: ChunkPos, data: &'a T) { |
||||||
|
assert!(chunk_pos != self.main.0); |
||||||
|
self.map.insert(chunk_pos, data); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn get(&self, pos: BlockPos) -> Option<Entity> { |
||||||
|
let (chunk_pos, rel_pos) = ChunkPos::from_block_pos(pos); |
||||||
|
if chunk_pos == self.main.0 { |
||||||
|
self.main.1.get(rel_pos) |
||||||
|
} else { |
||||||
|
self.map.get(&chunk_pos).and_then(|d| d.get(rel_pos)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn set(&mut self, pos: BlockPos, value: Entity) -> Result<Entity, ()> { |
||||||
|
let (chunk_pos, rel_pos) = ChunkPos::from_block_pos(pos); |
||||||
|
if chunk_pos == self.main.0 { |
||||||
|
self.main.1.set(rel_pos, value) |
||||||
|
} else { |
||||||
|
Err(()) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a, T: BloxelStore<Entity>, M: BloxelStoreMut<Entity>> BloxelStore<Entity> |
||||||
|
for ChunkedBloxelViewSingleMut<'a, T, M> |
||||||
|
{ |
||||||
|
fn size(&self) -> USize3 { |
||||||
|
self.region.size() |
||||||
|
} |
||||||
|
|
||||||
|
fn get(&self, pos: IVec3) -> Option<Entity> { |
||||||
|
ChunkedBloxelViewSingleMut::get(self, self.region.min() + pos) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<'a, T: BloxelStore<Entity>, M: BloxelStoreMut<Entity>> BloxelStoreMut<Entity> |
||||||
|
for ChunkedBloxelViewSingleMut<'a, T, M> |
||||||
|
{ |
||||||
|
fn set(&mut self, pos: IVec3, value: Entity) -> Result<Entity, ()> { |
||||||
|
ChunkedBloxelViewSingleMut::set(self, self.region.min() + pos, value) |
||||||
|
} |
||||||
|
} |
@ -1,10 +1,12 @@ |
|||||||
mod bloxel_array; |
mod bloxel_array; |
||||||
mod bloxel_store; |
mod bloxel_store; |
||||||
|
mod chunked_bloxel_view; |
||||||
mod chunked_octree; |
mod chunked_octree; |
||||||
mod palette_bloxel_storage; |
mod palette_bloxel_storage; |
||||||
mod palette_storage; |
mod palette_storage; |
||||||
|
|
||||||
pub use bloxel_array::*; |
pub use bloxel_array::*; |
||||||
pub use bloxel_store::*; |
pub use bloxel_store::*; |
||||||
|
pub use chunked_bloxel_view::*; |
||||||
pub use chunked_octree::*; |
pub use chunked_octree::*; |
||||||
pub use palette_bloxel_storage::*; |
pub use palette_bloxel_storage::*; |
||||||
|
@ -0,0 +1,70 @@ |
|||||||
|
use std::ops::{Deref, DerefMut}; |
||||||
|
|
||||||
|
use bevy::prelude::*; |
||||||
|
use cart_prod::specs::Hom2FCartProd; |
||||||
|
|
||||||
|
use crate::{ |
||||||
|
bloxel::{ |
||||||
|
prelude::*, |
||||||
|
storage::{ChunkedBloxelViewSingleMut, PaletteBloxelStorage}, |
||||||
|
worldgen::TerrainShape, |
||||||
|
}, |
||||||
|
TerrainBlocks, |
||||||
|
}; |
||||||
|
|
||||||
|
#[derive(Component, Deref, DerefMut)] |
||||||
|
#[require(Chunk)] |
||||||
|
pub struct TopLayer(PaletteBloxelStorage<Entity>); |
||||||
|
|
||||||
|
pub fn generate_top_layer( |
||||||
|
mut commands: Commands, |
||||||
|
terrain_blocks: Option<Res<TerrainBlocks>>, |
||||||
|
|
||||||
|
mut chunks_without_top_layer: Query< |
||||||
|
(Entity, &ChunkPos, &TerrainShape), |
||||||
|
(With<Chunk>, Without<TopLayer>), |
||||||
|
>, |
||||||
|
|
||||||
|
chunk_map: Single<&ChunkMap>, |
||||||
|
chunks_with_shape: Query<&TerrainShape>, |
||||||
|
) { |
||||||
|
let Some(terrain) = terrain_blocks else { |
||||||
|
return; |
||||||
|
}; |
||||||
|
|
||||||
|
for (entity, chunk_pos, shape) in chunks_without_top_layer.iter_mut() { |
||||||
|
let above_pos = chunk_pos + Neighbor::Top; |
||||||
|
let Some(above_entity) = chunk_map.get(&above_pos).copied() else { |
||||||
|
continue; |
||||||
|
}; |
||||||
|
let Ok(above_shape) = chunks_with_shape.get(above_entity) else { |
||||||
|
continue; |
||||||
|
}; |
||||||
|
|
||||||
|
let region = BlockRegion::new_unchecked( |
||||||
|
chunk_pos.to_block_pos(IVec3::ZERO), |
||||||
|
above_pos.to_block_pos(CHUNK_MAX), |
||||||
|
); |
||||||
|
let mut data = TopLayer((*shape.deref()).clone()); |
||||||
|
let mut chunks = ChunkedBloxelViewSingleMut::new(region, (*chunk_pos, data.deref_mut())); |
||||||
|
chunks.insert(above_pos, above_shape.deref()); |
||||||
|
|
||||||
|
for [x, z] in Hom2FCartProd::new(0..CHUNK_LENGTH as i32, 0..CHUNK_LENGTH as i32) { |
||||||
|
let mut air = CHUNK_LENGTH; // Some large value.
|
||||||
|
for y in (0..20).rev() { |
||||||
|
let pos = chunk_pos.to_block_pos(IVec3::new(x, y, z)); |
||||||
|
let existing = chunks.get(pos).unwrap(); |
||||||
|
if existing == terrain.air { |
||||||
|
air = 0; |
||||||
|
} else if y < CHUNK_LENGTH as i32 && air <= 4 { |
||||||
|
let new = (air == 1).then_some(terrain.grass).unwrap_or(terrain.dirt); |
||||||
|
chunks.set(pos, new).unwrap(); |
||||||
|
} |
||||||
|
air += 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
drop(chunks); // Unsure why this is required.
|
||||||
|
commands.entity(entity).insert(data); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue