Placement queue, binary transparency, WIP trees

This commit is contained in:
griffi-gh 2023-02-16 03:54:57 +01:00
parent 626e9e654d
commit f8732abb5d
6 changed files with 91 additions and 17 deletions

View file

@ -32,6 +32,9 @@ pub enum Block {
Cobblestone, Cobblestone,
TallGrass, TallGrass,
Planks, Planks,
Torch,
Wood,
Leaf,
} }
impl Block { impl Block {
@ -90,6 +93,24 @@ impl Block {
collision: CollisionType::Solid, collision: CollisionType::Solid,
raycast_collision: true, raycast_collision: true,
}, },
Self::Torch => BlockDescriptor {
name: "torch",
render: RenderType::CrossShape(CrossTexture::all(BlockTexture::Torch)),
collision: CollisionType::None,
raycast_collision: true,
},
Self::Wood => BlockDescriptor {
name: "leaf",
render: RenderType::SolidBlock(CubeTexture::horizontal_vertical(BlockTexture::Wood, BlockTexture::WoodTop)),
collision: CollisionType::Solid,
raycast_collision: true,
},
Self::Leaf => BlockDescriptor {
name: "leaf",
render: RenderType::BinaryTransparency(CubeTexture::all(BlockTexture::Leaf)),
collision: CollisionType::Solid,
raycast_collision: true,
},
} }
} }
} }
@ -170,5 +191,6 @@ pub enum CollisionType {
pub enum RenderType { pub enum RenderType {
None, None,
SolidBlock(CubeTexture), SolidBlock(CubeTexture),
BinaryTransparency(CubeTexture),
CrossShape(CrossTexture), CrossShape(CrossTexture),
} }

View file

@ -29,9 +29,26 @@ fn local_y_position(height: i32, chunk_position: IVec3) -> Option<usize> {
(0..CHUNK_SIZE as i32).contains(&position).then_some(position as usize) (0..CHUNK_SIZE as i32).contains(&position).then_some(position as usize)
} }
pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData { pub struct QueuedBlock {
pub position: IVec3,
pub block_type: Block,
}
pub fn generate_world(chunk_position: IVec3, seed: u64) -> (BlockData, Vec<QueuedBlock>) {
let offset = chunk_position * CHUNK_SIZE as i32; let offset = chunk_position * CHUNK_SIZE as i32;
let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]); let mut blocks = Box::new([[[Block::Air; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]);
let mut queue = Vec::with_capacity(0);
let mut smart_place = |blocks: &mut BlockData, position: IVec3, block: Block| {
if position.to_array().iter().any(|&x| !(0..CHUNK_SIZE).contains(&(x as usize))) {
queue.push(QueuedBlock {
position: offset + position,
block_type: block
});
} else {
blocks[position.x as usize][position.y as usize][position.z as usize] = block;
}
};
let mut height_noise = FastNoise::seeded(seed); let mut height_noise = FastNoise::seeded(seed);
height_noise.set_fractal_type(FractalType::FBM); height_noise.set_fractal_type(FractalType::FBM);
@ -46,10 +63,10 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData {
let mut rng = Xoshiro256StarStar::seed_from_u64( let mut rng = Xoshiro256StarStar::seed_from_u64(
seed seed
^ ((chunk_position.x as u32 as u64) << 0) ^ ((chunk_position.x as u32 as u64) << 0)
^ ((chunk_position.y as u32 as u64) << 16)
^ ((chunk_position.z as u32 as u64) << 32) ^ ((chunk_position.z as u32 as u64) << 32)
); );
let tall_grass_map: [[u8; CHUNK_SIZE]; CHUNK_SIZE] = rng.gen(); let rng_map_a: [[f32; CHUNK_SIZE]; CHUNK_SIZE] = rng.gen();
let rng_map_b: [[f32; CHUNK_SIZE]; CHUNK_SIZE] = rng.gen();
// let mut cave_noise = FastNoise::seeded(seed.rotate_left(1)); // let mut cave_noise = FastNoise::seeded(seed.rotate_left(1));
// cave_noise.set_fractal_type(FractalType::FBM); // cave_noise.set_fractal_type(FractalType::FBM);
@ -86,11 +103,22 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData {
blocks[x][y][z] = Block::Grass; blocks[x][y][z] = Block::Grass;
} }
//place tall grass //place tall grass
if tall_grass_map[x][z] < 10 { if rng_map_a[x][z] < 0.03 {
if let Some(y) = local_y_position(height + 1, chunk_position) { if let Some(y) = local_y_position(height + 1, chunk_position) {
blocks[x][y][z] = Block::TallGrass; blocks[x][y][z] = Block::TallGrass;
} }
} }
//place trees!
if rng_map_a[x][z] < 0.001 {
if let Some(y) = local_y_position(height + 1, chunk_position) {
let tree_pos = ivec3(x as i32, y as i32, z as i32);
let tree_height = 6 + (rng_map_b[x][z] * 6.).round() as i32;
for tree_y in 0..tree_height {
smart_place(&mut blocks, tree_pos + IVec3::Y * tree_y, Block::Wood);
}
smart_place(&mut blocks, tree_pos + IVec3::Y * tree_height, Block::Leaf);
}
}
} }
} }
@ -111,7 +139,7 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData {
// } // }
} }
blocks (blocks, queue)
// let mut cave_noise = FastNoise::seeded(seed); // let mut cave_noise = FastNoise::seeded(seed);
// cave_noise.set_fractal_type(FractalType::FBM); // cave_noise.set_fractal_type(FractalType::FBM);

View file

@ -23,6 +23,7 @@ const BLOCK_KEY_MAP: &[(VirtualKeyCode, Block)] = &[
(VirtualKeyCode::Key4, Block::Grass), (VirtualKeyCode::Key4, Block::Grass),
(VirtualKeyCode::Key5, Block::Sand), (VirtualKeyCode::Key5, Block::Sand),
(VirtualKeyCode::Key6, Block::Stone), (VirtualKeyCode::Key6, Block::Stone),
(VirtualKeyCode::Key7, Block::Torch),
]; ];
fn pick_block_with_number_keys( fn pick_block_with_number_keys(

View file

@ -12,6 +12,7 @@ use super::{
ChunkStorage, ChunkMeshStorage, ChunkStorage, ChunkMeshStorage,
chunk::{Chunk, DesiredChunkState, CHUNK_SIZE, ChunkMesh, CurrentChunkState, ChunkData}, chunk::{Chunk, DesiredChunkState, CHUNK_SIZE, ChunkMesh, CurrentChunkState, ChunkData},
tasks::{ChunkTaskManager, ChunkTaskResponse, ChunkTask}, tasks::{ChunkTaskManager, ChunkTaskResponse, ChunkTask},
queue::{BlockUpdateQueue, BlockUpdateEvent},
}; };
const MAX_CHUNK_OPS_INGAME: usize = 6; const MAX_CHUNK_OPS_INGAME: usize = 6;
@ -170,12 +171,13 @@ fn process_completed_tasks(
mut world: UniqueViewMut<ChunkStorage>, mut world: UniqueViewMut<ChunkStorage>,
mut meshes: NonSendSync<UniqueViewMut<ChunkMeshStorage>>, mut meshes: NonSendSync<UniqueViewMut<ChunkMeshStorage>>,
renderer: NonSendSync<UniqueView<Renderer>>, renderer: NonSendSync<UniqueView<Renderer>>,
state: UniqueView<GameState> state: UniqueView<GameState>,
mut queue: UniqueViewMut<BlockUpdateQueue>,
) { ) {
let mut ops: usize = 0; let mut ops: usize = 0;
while let Some(res) = task_manager.receive() { while let Some(res) = task_manager.receive() {
match res { match res {
ChunkTaskResponse::LoadedChunk { position, chunk_data } => { ChunkTaskResponse::LoadedChunk { position, chunk_data, queued } => {
//check if chunk exists //check if chunk exists
let Some(chunk) = world.chunks.get_mut(&position) else { let Some(chunk) = world.chunks.get_mut(&position) else {
log::warn!("blocks data discarded: chunk doesn't exist"); log::warn!("blocks data discarded: chunk doesn't exist");
@ -196,6 +198,14 @@ fn process_completed_tasks(
//update chunk state //update chunk state
chunk.current_state = CurrentChunkState::Loaded; chunk.current_state = CurrentChunkState::Loaded;
//push queued blocks
for event in queued {
queue.push(BlockUpdateEvent {
position: event.position,
value: event.block_type,
});
}
//increase ops counter //increase ops counter
ops += 1; ops += 1;
}, },

View file

@ -39,12 +39,16 @@ pub fn generate_mesh(data: MeshGenData) -> (Vec<ChunkVertex>, Vec<u32>) {
let descriptor = block.descriptor(); let descriptor = block.descriptor();
match descriptor.render { match descriptor.render {
RenderType::None => continue, RenderType::None => continue,
RenderType::SolidBlock(textures) => { RenderType::SolidBlock(textures) | RenderType::BinaryTransparency(textures) => {
for face in CubeFace::iter() { for face in CubeFace::iter() {
let facing_direction = face.normal(); let facing_direction = face.normal();
let facing_coord = coord + facing_direction; let facing_coord = coord + facing_direction;
let facing_descriptor = get_block(facing_coord).descriptor(); let facing_descriptor = get_block(facing_coord).descriptor();
let face_obstructed = matches!(facing_descriptor.render, RenderType::SolidBlock(_)); let face_obstructed = match descriptor.render {
RenderType::SolidBlock(_) => matches!(facing_descriptor.render, RenderType::SolidBlock(_)),
RenderType::BinaryTransparency(_) => matches!(facing_descriptor.render, RenderType::SolidBlock(_) | RenderType::BinaryTransparency(_)),
_ => unreachable!(),
};
if !face_obstructed { if !face_obstructed {
let face_texture = match face { let face_texture = match face {
CubeFace::Top => textures.top, CubeFace::Top => textures.top,

View file

@ -1,6 +1,9 @@
use flume::{Sender, Receiver}; use flume::{Sender, Receiver};
use glam::IVec3; use glam::IVec3;
use kubi_shared::networking::messages::{ClientToServerMessage, ServerToClientMessage}; use kubi_shared::{
networking::messages::{ClientToServerMessage, ServerToClientMessage},
worldgen::QueuedBlock
};
use shipyard::{Unique, UniqueView, View, IntoIter}; use shipyard::{Unique, UniqueView, View, IntoIter};
use rayon::{ThreadPool, ThreadPoolBuilder}; use rayon::{ThreadPool, ThreadPoolBuilder};
use super::{ use super::{
@ -8,7 +11,10 @@ use super::{
mesh::{generate_mesh, data::MeshGenData}, mesh::{generate_mesh, data::MeshGenData},
worldgen::generate_world, worldgen::generate_world,
}; };
use crate::{rendering::world::ChunkVertex, networking::{UdpClient, NetworkEvent}}; use crate::{
rendering::world::ChunkVertex,
networking::{UdpClient, NetworkEvent}
};
use kubi_udp::client::ClientEvent; use kubi_udp::client::ClientEvent;
pub enum ChunkTask { pub enum ChunkTask {
@ -25,6 +31,7 @@ pub enum ChunkTaskResponse {
LoadedChunk { LoadedChunk {
position: IVec3, position: IVec3,
chunk_data: BlockData, chunk_data: BlockData,
queued: Vec<QueuedBlock>
}, },
GeneratedMesh { GeneratedMesh {
position: IVec3, position: IVec3,
@ -59,8 +66,8 @@ impl ChunkTaskManager {
ChunkTaskResponse::GeneratedMesh { position, vertices, indexes } ChunkTaskResponse::GeneratedMesh { position, vertices, indexes }
}, },
ChunkTask::LoadChunk { position, seed } => { ChunkTask::LoadChunk { position, seed } => {
let chunk_data = generate_world(position, seed); let (chunk_data, queued) = generate_world(position, seed);
ChunkTaskResponse::LoadedChunk { position, chunk_data } ChunkTaskResponse::LoadedChunk { position, chunk_data, queued }
} }
}); });
}); });
@ -97,7 +104,9 @@ pub fn inject_network_responses_into_manager_queue(
if let ClientEvent::MessageReceived(ServerToClientMessage::ChunkResponse { chunk, data }) = &event.0 { if let ClientEvent::MessageReceived(ServerToClientMessage::ChunkResponse { chunk, data }) = &event.0 {
let position = IVec3::from_array(*chunk); let position = IVec3::from_array(*chunk);
manager.add_sussy_response(ChunkTaskResponse::LoadedChunk { manager.add_sussy_response(ChunkTaskResponse::LoadedChunk {
position, chunk_data: data.clone() position,
chunk_data: data.clone(),
queued: Vec::with_capacity(0)
}); });
} }
} }