From ad81ef8f176c5e31c339ee97646f7466f4b2a0a9 Mon Sep 17 00:00:00 2001 From: Thinkofname Date: Sat, 19 Mar 2016 16:32:13 +0000 Subject: [PATCH] Basic chunk building (not rendering) --- Cargo.toml | 2 +- src/chunk_builder.rs | 209 +++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 7 ++ src/render/mod.rs | 12 +-- src/resources.rs | 4 +- src/server.rs | 2 +- src/world/mod.rs | 150 +++++++++++++++++++++++++++++++ 7 files changed, 378 insertions(+), 8 deletions(-) create mode 100644 src/chunk_builder.rs diff --git a/Cargo.toml b/Cargo.toml index c806c8a..8781d12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ path = "./resources" version = "0" [profile.dev] -opt-level = 2 +opt-level = 0 debug = true rpath = false lto = false diff --git a/src/chunk_builder.rs b/src/chunk_builder.rs new file mode 100644 index 0000000..591aa5f --- /dev/null +++ b/src/chunk_builder.rs @@ -0,0 +1,209 @@ + +use std::thread; +use std::sync::mpsc; +use std::sync::{Arc, RwLock}; +use std::io::Write; +use byteorder::{WriteBytesExt, NativeEndian}; +use world; +use render; + +const NUM_WORKERS: usize = 4; + +pub struct ChunkBuilder { + threads: Vec<(mpsc::Sender, thread::JoinHandle<()>)>, + free_builders: Vec, + built_recv: mpsc::Receiver<(usize, BuildReply)>, +} + +impl ChunkBuilder { + pub fn new(textures: Arc>) -> ChunkBuilder { + let mut threads = vec![]; + let mut free = vec![]; + let (built_send, built_recv) = mpsc::channel(); + for i in 0 .. NUM_WORKERS { + let built_send = built_send.clone(); + let (work_send, work_recv) = mpsc::channel(); + let textures = textures.clone(); + let id = i; + threads.push((work_send, thread::spawn(move || build_func(id, textures, work_recv, built_send)))); + free.push(i); + } + ChunkBuilder { + threads: threads, + free_builders: free, + built_recv: built_recv, + } + } + + pub fn tick(&mut self, world: &mut world::World) { + while let Ok((id, val)) = self.built_recv.try_recv() { + world.reset_building_flag(val.position); + self.free_builders.push(id); + } + if self.free_builders.is_empty() { + return; + } + while let Some((x, y, z)) = world.next_dirty_chunk_section() { + let t_id = self.free_builders.pop().unwrap(); + let (cx, cy, cz) = (x << 4, y << 4, z << 4); + let mut snapshot = world.capture_snapshot(cx - 2, cy - 2, cz - 2, 20, 20, 20); + snapshot.make_relative(-2, -2, -2); + self.threads[t_id].0.send(BuildReq { + snapshot: snapshot, + position: (x, y, z), + }).unwrap(); + if self.free_builders.is_empty() { + return; + } + } + } +} + +struct BuildReq { + snapshot: world::Snapshot, + position: (i32, i32, i32), +} + +struct BuildReply { + position: (i32, i32, i32), + solid_buffer: Vec, +} + +fn build_func(id: usize, textures: Arc>, work_recv: mpsc::Receiver, built_send: mpsc::Sender<(usize, BuildReply)>) { + loop { + let BuildReq { + snapshot, + position, + } = work_recv.recv().unwrap(); + println!("Build request for {:?}", position); + + let mut solid_buffer = vec![]; + + for y in 0 .. 16 { + for x in 0 .. 16 { + for z in 0 .. 16 { + let block = snapshot.get_block(x, y, z); + if !block.render { + continue; + } + + for verts in &PRECOMPUTED_VERTS { + for vert in verts { + let stone = render::Renderer::get_texture(&textures, "minecraft:blocks/stone"); + + let mut vert = vert.clone(); + // TODO + vert.r = 255; + vert.g = 255; + vert.b = 255; + + vert.x += x as f32; + vert.y += y as f32; + vert.z += z as f32; + + // TODO + vert.block_light = 15 * 4000; + vert.sky_light = 15 * 4000; + + // TODO + vert.tatlas = stone.atlas as i16; + vert.tx = stone.get_x() as u16; + vert.ty = stone.get_y() as u16; + vert.tw = stone.get_width() as u16; + vert.th = stone.get_height() as u16; + + vert.write(&mut solid_buffer); + } + } + } + } + } + + println!("> Build request for {:?}", position); + built_send.send((id, BuildReply { + position: position, + solid_buffer: solid_buffer, + })).unwrap(); + } +} + +const PRECOMPUTED_VERTS: [[BlockVertex; 4]; 6] = [ + [ // Up + BlockVertex::base(0.0, 1.0, 0.0, 0, 0), + BlockVertex::base(1.0, 1.0, 0.0, 1, 0), + BlockVertex::base(0.0, 1.0, 1.0, 0, 1), + BlockVertex::base(1.0, 1.0, 1.0, 1, 1), + ], + [ // Down + BlockVertex::base(0.0, 0.0, 0.0, 0, 1), + BlockVertex::base(0.0, 0.0, 1.0, 0, 0), + BlockVertex::base(1.0, 0.0, 0.0, 1, 1), + BlockVertex::base(1.0, 0.0, 1.0, 1, 1), + ], + [ // North + BlockVertex::base(0.0, 0.0, 0.0, 1, 1), + BlockVertex::base(1.0, 0.0, 0.0, 0, 1), + BlockVertex::base(0.0, 1.0, 0.0, 1, 0), + BlockVertex::base(1.0, 1.0, 0.0, 0, 0), + ], + [ // South + BlockVertex::base(0.0, 0.0, 1.0, 0, 1), + BlockVertex::base(0.0, 1.0, 1.0, 0, 0), + BlockVertex::base(1.0, 0.0, 1.0, 1, 1), + BlockVertex::base(1.0, 1.0, 1.0, 1, 0), + ], + [ // West + BlockVertex::base(0.0, 0.0, 0.0, 0, 1), + BlockVertex::base(0.0, 1.0, 0.0, 0, 0), + BlockVertex::base(0.0, 0.0, 1.0, 1, 1), + BlockVertex::base(0.0, 1.0, 1.0, 1, 0), + ], + [ // East + BlockVertex::base(1.0, 0.0, 0.0, 1, 1), + BlockVertex::base(1.0, 0.0, 1.0, 0, 1), + BlockVertex::base(1.0, 1.0, 0.0, 1, 0), + BlockVertex::base(1.0, 1.0, 1.0, 0, 0), + ], +]; + +#[derive(Clone)] +pub struct BlockVertex { + x: f32, y: f32, z: f32, + tx: u16, ty: u16, tw: u16, th: u16, + toffsetx: i16, toffsety: i16, tatlas: i16, + r: u8, g: u8, b: u8, + block_light: u16, sky_light: u16, +} + +impl BlockVertex { + const fn base(x: f32, y: f32, z: f32, tx: i16, ty: i16) -> BlockVertex { + BlockVertex { + x: x, y: y, z: z, + tx: 0, ty: 0, tw: 0, th: 0, + toffsetx: tx, toffsety: ty, tatlas: 0, + r: 0, g: 0, b: 0, + block_light: 0, sky_light: 0, + } + } + fn write(&self, w: &mut W) { + let _ = w.write_f32::(self.x); + let _ = w.write_f32::(self.y); + let _ = w.write_f32::(self.z); + let _ = w.write_u16::(self.tx); + let _ = w.write_u16::(self.ty); + let _ = w.write_u16::(self.tw); + let _ = w.write_u16::(self.th); + let _ = w.write_i16::(self.toffsetx); + let _ = w.write_i16::(self.toffsety); + let _ = w.write_i16::(self.tatlas); + let _ = w.write_i16::(0); + let _ = w.write_u8(self.r); + let _ = w.write_u8(self.g); + let _ = w.write_u8(self.b); + let _ = w.write_u8(255); + let _ = w.write_u16::(self.block_light); + let _ = w.write_u16::(self.sky_light); + let _ = w.write_u16::(0); + let _ = w.write_u16::(0); + } +} diff --git a/src/main.rs b/src/main.rs index 5f70fdd..e300a5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ // limitations under the License. #![recursion_limit="200"] +#![feature(const_fn)] #[macro_use] pub mod macros; @@ -31,6 +32,7 @@ pub mod screen; pub mod console; pub mod server; pub mod world; +pub mod chunk_builder; extern crate glutin; extern crate image; @@ -68,6 +70,7 @@ pub struct Game { mouse_pos: (i32, i32), server: server::Server, + chunk_builder: chunk_builder::ChunkBuilder, } fn main() { @@ -119,6 +122,7 @@ fn main() { let mut screen_sys = screen::ScreenSystem::new(); screen_sys.add_screen(Box::new(screen::Login::new())); + let textures = renderer.get_textures(); let mut game = Game { renderer: renderer, screen_sys: screen_sys, @@ -127,6 +131,7 @@ fn main() { should_close: false, mouse_pos: (0, 0), server: server::Server::dummy_server(), + chunk_builder: chunk_builder::ChunkBuilder::new(textures), }; while !game.should_close { @@ -140,6 +145,8 @@ fn main() { let delta = (diff.num_nanoseconds().unwrap() as f64) / frame_time; let (width, height) = window.get_inner_size_pixels().unwrap(); + game.chunk_builder.tick(&mut game.server.world); + game.screen_sys.tick(delta, &mut game.renderer, &mut ui_container); game.console .lock() diff --git a/src/render/mod.rs b/src/render/mod.rs index f9cb01b..c55a24d 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -601,7 +601,11 @@ impl TextureManager { } fn get_texture(&self, name: &str) -> Option { - self.textures.get(name).map(|v| v.clone()) + if let Some(_) = name.find(':') { + self.textures.get(name).map(|v| v.clone()) + } else { + self.textures.get(&format!("minecraft:{}", name)).map(|v| v.clone()) + } } fn load_texture(&mut self, name: &str) { @@ -702,10 +706,8 @@ impl TextureManager { self.pending_uploads.push((atlas, rect, data)); let mut full_name = String::new(); - if plugin != "minecraft" { - full_name.push_str(plugin); - full_name.push_str(":"); - } + full_name.push_str(plugin); + full_name.push_str(":"); full_name.push_str(name); let tex = Texture { diff --git a/src/resources.rs b/src/resources.rs index 91806e7..24b10b9 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -25,7 +25,7 @@ use std::sync::mpsc; const RESOURCES_VERSION: &'static str = "15w39c"; -pub trait Pack { +pub trait Pack: Sync + Send { fn open(&self, name: &str) -> Option>; } @@ -36,6 +36,8 @@ pub struct Manager { vanilla_chan: Option>, } +unsafe impl Sync for Manager {} + impl Manager { pub fn new() -> Manager { let mut m = Manager { diff --git a/src/server.rs b/src/server.rs index 6a21f32..24db244 100644 --- a/src/server.rs +++ b/src/server.rs @@ -19,7 +19,7 @@ use rand::{self, Rng}; pub struct Server { conn: Option, - world: world::World, + pub world: world::World, } impl Server { diff --git a/src/world/mod.rs b/src/world/mod.rs index 91848c7..b37c279 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -44,6 +44,154 @@ impl World { None => block::AIR, } } + + pub fn next_dirty_chunk_section(&mut self) -> Option<(i32, i32, i32)> { + for (_, chunk) in &mut self.chunks { + for sec in &mut chunk.sections { + if let Some(sec) = sec.as_mut() { + if !sec.building && sec.dirty { + sec.building = true; + sec.dirty = false; + return Some((chunk.position.0, sec.y as i32, chunk.position.1)); + } + } + } + } + None + } + + pub fn reset_building_flag(&mut self, pos: (i32, i32, i32)) { + if let Some(chunk) = self.chunks.get_mut(&CPos(pos.0, pos.2)) { + if let Some(section) = chunk.sections[pos.1 as usize].as_mut() { + section.building = false; + } + } + } + + pub fn capture_snapshot(&self, x: i32, y: i32, z: i32, w: i32, h: i32, d: i32) -> Snapshot { + use std::cmp::{min, max}; + let mut snapshot = Snapshot { + blocks: vec![0; (w * h * d) as usize], + block_light: nibble::Array::new((w * h * d) as usize), + sky_light: nibble::Array::new((w * h * d) as usize), + biomes: vec![0; (w * d) as usize], + + x: x, y: y, z: z, + w: w, h: h, d: d, + }; + for i in 0 .. (w * h * d) as usize { + snapshot.sky_light.set(i, 0xF); + snapshot.blocks[i] = block::MISSING.get_id() as u16; + } + + let cx1 = x >> 4; + let cy1 = y >> 4; + let cz1 = z >> 4; + let cx2 = (x + w + 15) >> 4; + let cy2 = (y + h + 15) >> 4; + let cz2 = (z + d + 15) >> 4; + + for cx in cx1 .. cx2 { + for cz in cz1 .. cz2 { + let chunk = match self.chunks.get(&CPos(cx, cz)) { + Some(val) => val, + None => continue, + }; + + let x1 = min(16, max(0, x - (cx<<4))); + let x2 = min(16, max(0, x + w - (cx<<4))); + let z1 = min(16, max(0, z - (cz<<4))); + let z2 = min(16, max(0, z + d - (cz<<4))); + + for cy in cy1 .. cy2 { + if cy < 0 || cy > 15 { + continue; + } + let section = &chunk.sections[cy as usize]; + let y1 = min(16, max(0, y - (cy<<4))); + let y2 = min(16, max(0, y + h - (cy<<4))); + + for yy in y1 .. y2 { + for zz in z1 .. z2 { + for xx in x1 .. x2 { + let ox = xx + (cx << 4); + let oy = yy + (cy << 4); + let oz = zz + (cz << 4); + match section.as_ref() { + Some(sec) => { + snapshot.set_block(ox, oy, oz, sec.get_block(xx, yy, zz)); + snapshot.set_block_light(ox, oy, oz, sec.get_block_light(xx, yy, zz)); + snapshot.set_sky_light(ox, oy, oz, sec.get_sky_light(xx, yy, zz)); + }, + None => { + snapshot.set_block(ox, oy, oz, block::AIR); + }, + } + } + } + } + } + // TODO: Biomes + } + } + + snapshot + } +} + +pub struct Snapshot { + blocks: Vec, + block_light: nibble::Array, + sky_light: nibble::Array, + biomes: Vec, + + x: i32, + y: i32, + z: i32, + w: i32, + h: i32, + d: i32, +} + +impl Snapshot { + + pub fn make_relative(&mut self, x: i32, y: i32, z: i32) { + self.x = x; + self.y = y; + self.z = z; + } + + pub fn get_block(&self, x: i32, y: i32, z: i32) -> &'static block::Block { + block::get_block_by_id(self.blocks[self.index(x, y, z)] as usize) + } + + pub fn set_block(&mut self, x: i32, y: i32, z: i32, b: &'static block::Block) { + let idx = self.index(x, y, z); + self.blocks[idx] = b.get_id() as u16; + } + + pub fn get_block_light(&self, x: i32, y: i32, z: i32) -> u8 { + self.block_light.get(self.index(x, y, z)) + } + + pub fn set_block_light(&mut self, x: i32, y: i32, z: i32, l: u8) { + let idx = self.index(x, y, z); + self.block_light.set(idx, l); + } + + pub fn get_sky_light(&self, x: i32, y: i32, z: i32) -> u8 { + self.sky_light.get(self.index(x, y, z)) + } + + pub fn set_sky_light(&mut self, x: i32, y: i32, z: i32, l: u8) { + let idx = self.index(x, y, z); + self.sky_light.set(idx, l); + } + + #[inline] + fn index(&self, x: i32, y: i32, z: i32) -> usize { + ((x - self.x) + ((z - self.z) * self.w) + ((y - self.y) * self.w * self.d)) as usize + } } #[derive(PartialEq, Eq, Hash, Clone, Copy)] @@ -108,6 +256,7 @@ struct Section { sky_light: nibble::Array, dirty: bool, + building: bool, } impl Section { @@ -125,6 +274,7 @@ impl Section { sky_light: nibble::Array::new(16 * 16 * 16), dirty: false, + building: false, }; for i in 0 .. 16*16*16 { section.sky_light.set(i, 0xF);