diff --git a/src/chunk_builder.rs b/src/chunk_builder.rs index 2622a64..509f0bf 100644 --- a/src/chunk_builder.rs +++ b/src/chunk_builder.rs @@ -35,6 +35,13 @@ impl ChunkBuilder { } } + pub fn wait_for_builders(&mut self) { + while self.free_builders.len() != NUM_WORKERS { + let (id, _) = self.built_recv.recv().unwrap(); + self.free_builders.push(id); + } + } + pub fn tick(&mut self, world: &mut world::World, renderer: &mut render::Renderer) { while let Ok((id, val)) = self.built_recv.try_recv() { world.reset_building_flag(val.position); diff --git a/src/main.rs b/src/main.rs index 025cf91..11d1bd0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -107,6 +107,7 @@ impl Game { Ok(val) => { self.screen_sys.pop_screen(); self.renderer.clear_chunks(); + self.chunk_builder.wait_for_builders(); self.server = val; }, Err(err) => { @@ -194,9 +195,6 @@ fn main() { chunk_builder: chunk_builder::ChunkBuilder::new(textures), connect_reply: None, }; - game.renderer.camera.pos.x = 0.5; - game.renderer.camera.pos.z = 0.5; - game.renderer.camera.pos.y = 15.0; while !game.should_close { { @@ -210,7 +208,7 @@ fn main() { let (width, height) = window.get_inner_size_pixels().unwrap(); game.tick(delta); - game.server.tick(delta); + game.server.tick(&mut game.renderer, delta); game.chunk_builder.tick(&mut game.server.world, &mut game.renderer); diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 6dc7667..7d6d9fd 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -309,6 +309,16 @@ impl Serializable for u16 { } } +impl Serializable for u64 { + fn read_from(buf: &mut io::Read) -> Result { + Result::Ok(try!(buf.read_u64::())) + } + fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> { + try!(buf.write_u64::(*self)); + Result::Ok(()) + } +} + impl Serializable for f32 { fn read_from(buf: &mut io::Read) -> Result { Result::Ok(try!(buf.read_f32::())) diff --git a/src/server.rs b/src/server.rs index 673892f..155d90f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -12,24 +12,43 @@ // See the License for the specific language governing permissions and // limitations under the License. -use protocol::{self, mojang}; +use protocol::{self, mojang, packet}; use world; use world::block::{self, BlockSet}; use rand::{self, Rng}; use std::sync::{Arc, RwLock, Mutex}; +use std::sync::mpsc; use std::thread; use resources; use openssl; use console; +use render; use auth; +use cgmath::{self, Vector}; pub struct Server { conn: Option, + read_queue: Option>>, pub world: world::World, resources: Arc>, console: Arc>, version: usize, + + position: cgmath::Vector3, +} + +macro_rules! handle_packet { + ($s:ident $pck:ident { + $($packet:ident => $func:ident,)* + }) => ( + match $pck { + $( + protocol::packet::Packet::$packet(val) => $s.$func(val), + )* + _ => {}, + } + ) } impl Server { @@ -100,13 +119,29 @@ impl Server { } } + let (tx, rx) = mpsc::channel(); + thread::spawn(move || { + loop { + let pck = read.read_packet(); + let was_error = pck.is_err(); + if let Err(_) = tx.send(pck) { + return; + } + if was_error { + return; + } + } + }); + let version = resources.read().unwrap().version(); Ok(Server { conn: Some(write), + read_queue: Some(rx), world: world::World::new(), resources: resources, console: console, version: version, + position: cgmath::Vector3::zero(), }) } @@ -124,11 +159,13 @@ impl Server { let version = resources.read().unwrap().version(); Server { conn: None, + read_queue: None, world: world, version: version, resources: resources, console: console, + position: cgmath::Vector3::new(0.5, 13.2, 0.5), } } @@ -136,11 +173,66 @@ impl Server { self.conn.is_some() } - pub fn tick(&mut self, delta: f64) { + pub fn tick(&mut self, renderer: &mut render::Renderer, _delta: f64) { let version = self.resources.read().unwrap().version(); if version != self.version { self.version = version; self.world.flag_dirty_all(); } + + if let Some(rx) = self.read_queue.take() { + while let Ok(pck) = rx.try_recv() { + match pck { + Ok(pck) => handle_packet!{ + self pck { + KeepAliveClientbound => on_keep_alive, + ChunkData => on_chunk_data, + TeleportPlayer => on_teleport, + } + }, + Err(err) => panic!("Err: {:?}", err), + } + } + self.read_queue = Some(rx); + } + + // Copy to camera + renderer.camera.pos = cgmath::Point::from_vec(self.position + cgmath::Vector3::new(0.0, 1.8, 0.0)); + } + + pub fn write_packet(&mut self, p: T) { + self.conn.as_mut().unwrap().write_packet(p).unwrap(); // TODO handle errors + } + + pub fn on_keep_alive(&mut self, keep_alive: packet::play::clientbound::KeepAliveClientbound) { + self.write_packet(packet::play::serverbound::KeepAliveServerbound { + id: keep_alive.id, + }); + } + + pub fn on_teleport(&mut self, teleport: packet::play::clientbound::TeleportPlayer) { + // TODO: relative teleports + self.position.x = teleport.x; + self.position.y = teleport.y; + self.position.z = teleport.z; + + self.write_packet(packet::play::serverbound::PlayerPositionLook { + x: teleport.x, + y: teleport.y, + z: teleport.z, + yaw: teleport.yaw, + pitch: teleport.pitch, + on_ground: false, + }); + } + + pub fn on_chunk_data(&mut self, chunk_data: packet::play::clientbound::ChunkData) { + self.world.load_chunk( + chunk_data.chunk_x, + chunk_data.chunk_z, + chunk_data.new, + chunk_data.bitmask.0 as u16, + chunk_data.data.data + ).unwrap(); } } diff --git a/src/types/bit/map.rs b/src/types/bit/map.rs index a847bb3..ece65fd 100644 --- a/src/types/bit/map.rs +++ b/src/types/bit/map.rs @@ -59,6 +59,13 @@ impl Map { } map } + pub fn from_raw(bits: Vec, size: usize) -> Map { + Map { + length: (bits.len()*64 + 63) / size, + bit_size: size, + bits: bits, + } + } pub fn resize(&self, size: usize) -> Map { let mut n = Map::new(self.length, size); diff --git a/src/types/nibble.rs b/src/types/nibble.rs index 1b62d2e..91ecdc8 100644 --- a/src/types/nibble.rs +++ b/src/types/nibble.rs @@ -14,7 +14,7 @@ pub struct Array { - data: Vec, + pub data: Vec, } impl Array { diff --git a/src/world/block.rs b/src/world/block.rs index 06cc4ff..f10ff16 100644 --- a/src/world/block.rs +++ b/src/world/block.rs @@ -111,6 +111,10 @@ impl BlockManager { fn get_block_by_steven_id(&self, id: usize) -> &'static Block { self.steven_id[id] } + + fn get_block_by_vanilla_id(&self, id: usize) -> &'static Block { + self.vanilla_id.get(id).and_then(|v| *v).unwrap_or(MISSING.base()) + } } pub fn force_init() { @@ -121,6 +125,10 @@ pub fn get_block_by_steven_id(id: usize) -> &'static Block { MANAGER.get_block_by_steven_id(id) } +pub fn get_block_by_vanilla_id(id: usize) -> &'static Block { + MANAGER.get_block_by_vanilla_id(id) +} + define_blocks! { AIR InvisibleBlockSet = InvisibleBlockSet::new("air"); MISSING SimpleBlockSet = SimpleBlockSet::new("missing"); diff --git a/src/world/mod.rs b/src/world/mod.rs index 7839432..b251bdb 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -18,6 +18,7 @@ use self::block::BlockSet; use std::collections::HashMap; use types::bit; use types::nibble; +use protocol; pub struct World { chunks: HashMap, @@ -148,6 +149,66 @@ impl World { snapshot } + + pub fn load_chunk(&mut self, x: i32, z: i32, new: bool, mask: u16, data: Vec) -> Result<(), protocol::Error> { + use std::io::{Cursor, Read}; + use byteorder::ReadBytesExt; + use protocol::{VarInt, Serializable, LenPrefixed}; + + let mut data = Cursor::new(data); + + let cpos = CPos(x, z); + let chunk = if new { + self.chunks.insert(cpos, Chunk::new(cpos)); + self.chunks.get_mut(&cpos).unwrap() + } else { + if !self.chunks.contains_key(&cpos) { + return Ok(()); + } + self.chunks.get_mut(&cpos).unwrap() + }; + + for i in 0 .. 16 { + if mask & (1 << i) == 0 { + continue; + } + if chunk.sections[i].is_none() { + chunk.sections[i] = Some(Section::new(i as u8)); + } + let section = chunk.sections[i as usize].as_mut().unwrap(); + + let bit_size = try!(data.read_u8()); + let mut block_map = HashMap::new(); + if bit_size <= 8 { + let count = try!(VarInt::read_from(&mut data)).0; + for i in 0 .. count { + let id = try!(VarInt::read_from(&mut data)).0; + block_map.insert(i as usize, id); + } + } + + let bits = try!(LenPrefixed::::read_from(&mut data)).data; + let m = bit::Map::from_raw(bits, bit_size as usize); + + for i in 0 .. 4096 { + let val = m.get(i); + let block_id = block_map.get(&val).map(|v| *v as usize).unwrap_or(val); + let block = block::get_block_by_vanilla_id(block_id); + let i = i as i32; + section.set_block( + i & 0xF, + i >> 8, + (i >> 4) & 0xF, + block + ); + } + + try!(data.read_exact(&mut section.block_light.data)); + try!(data.read_exact(&mut section.sky_light.data)); + } + + Ok(()) + } } pub struct Snapshot {