mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-11-22 06:48:43 -06:00
Placement queue, binary transparency, WIP trees
This commit is contained in:
parent
626e9e654d
commit
f8732abb5d
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
(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);
|
||||||
height_noise.set_fractal_octaves(4);
|
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(
|
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,8 +139,8 @@ 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);
|
||||||
// cave_noise.set_frequency(0.1);
|
// cave_noise.set_frequency(0.1);
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -11,7 +11,8 @@ use crate::{
|
||||||
use super::{
|
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;
|
||||||
},
|
},
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue