Implement chunk loading
This commit is contained in:
parent
8476f992e1
commit
ce1c286801
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -309,6 +309,16 @@ impl Serializable for u16 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Serializable for u64 {
|
||||
fn read_from(buf: &mut io::Read) -> Result<u64, io::Error> {
|
||||
Result::Ok(try!(buf.read_u64::<BigEndian>()))
|
||||
}
|
||||
fn write_to(&self, buf: &mut io::Write) -> Result<(), io::Error> {
|
||||
try!(buf.write_u64::<BigEndian>(*self));
|
||||
Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Serializable for f32 {
|
||||
fn read_from(buf: &mut io::Read) -> Result<f32, io::Error> {
|
||||
Result::Ok(try!(buf.read_f32::<BigEndian>()))
|
||||
|
|
|
@ -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<protocol::Conn>,
|
||||
read_queue: Option<mpsc::Receiver<Result<packet::Packet, protocol::Error>>>,
|
||||
pub world: world::World,
|
||||
|
||||
resources: Arc<RwLock<resources::Manager>>,
|
||||
console: Arc<Mutex<console::Console>>,
|
||||
version: usize,
|
||||
|
||||
position: cgmath::Vector3<f64>,
|
||||
}
|
||||
|
||||
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<T: protocol::PacketType>(&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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,13 @@ impl Map {
|
|||
}
|
||||
map
|
||||
}
|
||||
pub fn from_raw(bits: Vec<u64>, 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);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
|
||||
pub struct Array {
|
||||
data: Vec<u8>,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Array {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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<CPos, Chunk>,
|
||||
|
@ -148,6 +149,66 @@ impl World {
|
|||
|
||||
snapshot
|
||||
}
|
||||
|
||||
pub fn load_chunk(&mut self, x: i32, z: i32, new: bool, mask: u16, data: Vec<u8>) -> 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::<VarInt, u64>::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 {
|
||||
|
|
Loading…
Reference in New Issue