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,
TallGrass,
Planks,
Torch,
Wood,
Leaf,
}
impl Block {
@ -90,6 +93,24 @@ impl Block {
collision: CollisionType::Solid,
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 {
None,
SolidBlock(CubeTexture),
BinaryTransparency(CubeTexture),
CrossShape(CrossTexture),
}

View file

@ -29,10 +29,27 @@ fn local_y_position(height: i32, chunk_position: IVec3) -> Option<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 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);
height_noise.set_fractal_type(FractalType::FBM);
height_noise.set_fractal_octaves(4);
@ -46,10 +63,10 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData {
let mut rng = Xoshiro256StarStar::seed_from_u64(
seed
^ ((chunk_position.x as u32 as u64) << 0)
^ ((chunk_position.y as u32 as u64) << 16)
^ ((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));
// 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;
}
//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) {
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,8 +139,8 @@ pub fn generate_world(chunk_position: IVec3, seed: u64) -> BlockData {
// }
}
blocks
(blocks, queue)
// let mut cave_noise = FastNoise::seeded(seed);
// cave_noise.set_fractal_type(FractalType::FBM);
// cave_noise.set_frequency(0.1);

View file

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

View file

@ -11,7 +11,8 @@ use crate::{
use super::{
ChunkStorage, ChunkMeshStorage,
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;
@ -170,12 +171,13 @@ fn process_completed_tasks(
mut world: UniqueViewMut<ChunkStorage>,
mut meshes: NonSendSync<UniqueViewMut<ChunkMeshStorage>>,
renderer: NonSendSync<UniqueView<Renderer>>,
state: UniqueView<GameState>
state: UniqueView<GameState>,
mut queue: UniqueViewMut<BlockUpdateQueue>,
) {
let mut ops: usize = 0;
while let Some(res) = task_manager.receive() {
match res {
ChunkTaskResponse::LoadedChunk { position, chunk_data } => {
ChunkTaskResponse::LoadedChunk { position, chunk_data, queued } => {
//check if chunk exists
let Some(chunk) = world.chunks.get_mut(&position) else {
log::warn!("blocks data discarded: chunk doesn't exist");
@ -196,6 +198,14 @@ fn process_completed_tasks(
//update chunk state
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
ops += 1;
},

View file

@ -39,12 +39,16 @@ pub fn generate_mesh(data: MeshGenData) -> (Vec<ChunkVertex>, Vec<u32>) {
let descriptor = block.descriptor();
match descriptor.render {
RenderType::None => continue,
RenderType::SolidBlock(textures) => {
RenderType::SolidBlock(textures) | RenderType::BinaryTransparency(textures) => {
for face in CubeFace::iter() {
let facing_direction = face.normal();
let facing_coord = coord + facing_direction;
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 {
let face_texture = match face {
CubeFace::Top => textures.top,

View file

@ -1,6 +1,9 @@
use flume::{Sender, Receiver};
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 rayon::{ThreadPool, ThreadPoolBuilder};
use super::{
@ -8,7 +11,10 @@ use super::{
mesh::{generate_mesh, data::MeshGenData},
worldgen::generate_world,
};
use crate::{rendering::world::ChunkVertex, networking::{UdpClient, NetworkEvent}};
use crate::{
rendering::world::ChunkVertex,
networking::{UdpClient, NetworkEvent}
};
use kubi_udp::client::ClientEvent;
pub enum ChunkTask {
@ -25,6 +31,7 @@ pub enum ChunkTaskResponse {
LoadedChunk {
position: IVec3,
chunk_data: BlockData,
queued: Vec<QueuedBlock>
},
GeneratedMesh {
position: IVec3,
@ -59,8 +66,8 @@ impl ChunkTaskManager {
ChunkTaskResponse::GeneratedMesh { position, vertices, indexes }
},
ChunkTask::LoadChunk { position, seed } => {
let chunk_data = generate_world(position, seed);
ChunkTaskResponse::LoadedChunk { position, chunk_data }
let (chunk_data, queued) = generate_world(position, seed);
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 {
let position = IVec3::from_array(*chunk);
manager.add_sussy_response(ChunkTaskResponse::LoadedChunk {
position, chunk_data: data.clone()
position,
chunk_data: data.clone(),
queued: Vec::with_capacity(0)
});
}
}