From b5d10bfb3e81fd3b1f91f00cc41d40f0cb01a926 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Fri, 2 Aug 2019 15:37:26 +0100 Subject: [PATCH] Added worldgen npcs --- server/src/lib.rs | 25 +++++++++++++++--- world/src/lib.rs | 66 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 74 insertions(+), 17 deletions(-) diff --git a/server/src/lib.rs b/server/src/lib.rs index b264d809b2..2ca2234fda 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -34,7 +34,7 @@ use std::{ }; use uvth::{ThreadPool, ThreadPoolBuilder}; use vek::*; -use world::World; +use world::{ChunkSupplement, World}; const CLIENT_TIMEOUT: f64 = 20.0; // Seconds @@ -62,8 +62,8 @@ pub struct Server { clients: Clients, thread_pool: ThreadPool, - chunk_tx: mpsc::Sender<(Vec2, TerrainChunk)>, - chunk_rx: mpsc::Receiver<(Vec2, TerrainChunk)>, + chunk_tx: mpsc::Sender<(Vec2, (TerrainChunk, ChunkSupplement))>, + chunk_rx: mpsc::Receiver<(Vec2, (TerrainChunk, ChunkSupplement))>, pending_chunks: HashSet>, server_settings: ServerSettings, @@ -237,7 +237,7 @@ impl Server { // 5) Fetch any generated `TerrainChunk`s and insert them into the terrain. // Also, send the chunk data to anybody that is close by. - if let Ok((key, chunk)) = self.chunk_rx.try_recv() { + if let Ok((key, (chunk, supplement))) = self.chunk_rx.try_recv() { // Send the chunk to all nearby players. for (entity, view_distance, pos) in ( &self.state.ecs().entities(), @@ -267,6 +267,23 @@ impl Server { self.state.insert_chunk(key, chunk); self.pending_chunks.remove(&key); + + // Handle chunk supplement + for npc in supplement.npcs { + self.state + .ecs_mut() + .create_entity_synced() + .with(comp::Pos(npc.pos)) + .with(comp::Vel(Vec3::zero())) + .with(comp::Ori(Vec3::unit_y())) + .with(comp::Controller::default()) + .with(comp::Body::Humanoid(comp::humanoid::Body::random())) + .with(comp::Stats::new("Test".to_string())) + .with(comp::ActionState::default()) + .with(comp::Agent::Enemy { target: None }) + .with(comp::ForceUpdate) + .build(); + } } fn chunk_in_vd( diff --git a/world/src/lib.rs b/world/src/lib.rs index 32603d93dd..927b65103c 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -17,8 +17,9 @@ use crate::{ }; use common::{ terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize}, - vol::{VolSize, Vox, WriteVol}, + vol::{ReadVol, VolSize, Vox, WriteVol}, }; +use rand::Rng; use std::time::Duration; use vek::*; @@ -56,7 +57,7 @@ impl World { BlockGen::new(self, ColumnGen::new(self)) } - pub fn generate_chunk(&self, chunk_pos: Vec2) -> TerrainChunk { + pub fn generate_chunk(&self, chunk_pos: Vec2) -> (TerrainChunk, ChunkSupplement) { let air = Block::empty(); let stone = Block::new(2, Rgb::new(200, 220, 255)); let water = Block::new(5, Rgb::new(100, 150, 255)); @@ -72,21 +73,24 @@ impl World { { Some((base_z, sim_chunk)) => (base_z as i32, sim_chunk), None => { - return TerrainChunk::new( - CONFIG.sea_level as i32, - water, - air, - TerrainChunkMeta::void(), + return ( + TerrainChunk::new( + CONFIG.sea_level as i32, + water, + air, + TerrainChunkMeta::void(), + ), + ChunkSupplement::default(), ) } }; let meta = TerrainChunkMeta::new(sim_chunk.get_name(&self.sim), sim_chunk.get_biome()); - - let mut chunk = TerrainChunk::new(base_z, stone, air, meta); - let mut sampler = self.sample_blocks(); + let chunk_block_pos = Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32); + + let mut chunk = TerrainChunk::new(base_z, stone, air, meta); for x in 0..TerrainChunkSize::SIZE.x as i32 { for y in 0..TerrainChunkSize::SIZE.y as i32 { let wpos2d = Vec2::new(x, y) @@ -105,8 +109,7 @@ impl World { for z in min_z as i32..max_z as i32 { let lpos = Vec3::new(x, y, z); - let wpos = - lpos + Vec3::from(chunk_pos) * TerrainChunkSize::SIZE.map(|e| e as i32); + let wpos = chunk_block_pos + lpos; if let Some(block) = sampler.get_with_z_cache(wpos, Some(&z_cache)) { let _ = chunk.set(lpos, block); @@ -115,6 +118,43 @@ impl World { } } - chunk + let gen_entity_pos = || { + let lpos2d = Vec2::from(TerrainChunkSize::SIZE) + .map(|sz| rand::thread_rng().gen::().rem_euclid(sz)); + let mut lpos = Vec3::new(lpos2d.x as i32, lpos2d.y as i32, 0); + + while chunk.get(lpos).map(|vox| !vox.is_empty()).unwrap_or(false) { + lpos.z += 1; + } + + (chunk_block_pos + lpos).map(|e| e as f32) + 0.5 + }; + + const SPAWN_RATE: f32 = 0.1; + let supplement = ChunkSupplement { + npcs: if rand::thread_rng().gen::() < SPAWN_RATE { + vec![NpcInfo { + pos: gen_entity_pos(), + }] + } else { + Vec::new() + }, + }; + + (chunk, supplement) + } +} + +pub struct NpcInfo { + pub pos: Vec3, +} + +pub struct ChunkSupplement { + pub npcs: Vec, +} + +impl Default for ChunkSupplement { + fn default() -> Self { + Self { npcs: Vec::new() } } }