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) {
|
pub fn tick(&mut self, world: &mut world::World, renderer: &mut render::Renderer) {
|
||||||
while let Ok((id, val)) = self.built_recv.try_recv() {
|
while let Ok((id, val)) = self.built_recv.try_recv() {
|
||||||
world.reset_building_flag(val.position);
|
world.reset_building_flag(val.position);
|
||||||
|
|
|
@ -107,6 +107,7 @@ impl Game {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
self.screen_sys.pop_screen();
|
self.screen_sys.pop_screen();
|
||||||
self.renderer.clear_chunks();
|
self.renderer.clear_chunks();
|
||||||
|
self.chunk_builder.wait_for_builders();
|
||||||
self.server = val;
|
self.server = val;
|
||||||
},
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -194,9 +195,6 @@ fn main() {
|
||||||
chunk_builder: chunk_builder::ChunkBuilder::new(textures),
|
chunk_builder: chunk_builder::ChunkBuilder::new(textures),
|
||||||
connect_reply: None,
|
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 {
|
while !game.should_close {
|
||||||
{
|
{
|
||||||
|
@ -210,7 +208,7 @@ fn main() {
|
||||||
let (width, height) = window.get_inner_size_pixels().unwrap();
|
let (width, height) = window.get_inner_size_pixels().unwrap();
|
||||||
|
|
||||||
game.tick(delta);
|
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);
|
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 {
|
impl Serializable for f32 {
|
||||||
fn read_from(buf: &mut io::Read) -> Result<f32, io::Error> {
|
fn read_from(buf: &mut io::Read) -> Result<f32, io::Error> {
|
||||||
Result::Ok(try!(buf.read_f32::<BigEndian>()))
|
Result::Ok(try!(buf.read_f32::<BigEndian>()))
|
||||||
|
|
|
@ -12,24 +12,43 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use protocol::{self, mojang};
|
use protocol::{self, mojang, packet};
|
||||||
use world;
|
use world;
|
||||||
use world::block::{self, BlockSet};
|
use world::block::{self, BlockSet};
|
||||||
use rand::{self, Rng};
|
use rand::{self, Rng};
|
||||||
use std::sync::{Arc, RwLock, Mutex};
|
use std::sync::{Arc, RwLock, Mutex};
|
||||||
|
use std::sync::mpsc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use resources;
|
use resources;
|
||||||
use openssl;
|
use openssl;
|
||||||
use console;
|
use console;
|
||||||
|
use render;
|
||||||
use auth;
|
use auth;
|
||||||
|
use cgmath::{self, Vector};
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
conn: Option<protocol::Conn>,
|
conn: Option<protocol::Conn>,
|
||||||
|
read_queue: Option<mpsc::Receiver<Result<packet::Packet, protocol::Error>>>,
|
||||||
pub world: world::World,
|
pub world: world::World,
|
||||||
|
|
||||||
resources: Arc<RwLock<resources::Manager>>,
|
resources: Arc<RwLock<resources::Manager>>,
|
||||||
console: Arc<Mutex<console::Console>>,
|
console: Arc<Mutex<console::Console>>,
|
||||||
version: usize,
|
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 {
|
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();
|
let version = resources.read().unwrap().version();
|
||||||
Ok(Server {
|
Ok(Server {
|
||||||
conn: Some(write),
|
conn: Some(write),
|
||||||
|
read_queue: Some(rx),
|
||||||
world: world::World::new(),
|
world: world::World::new(),
|
||||||
resources: resources,
|
resources: resources,
|
||||||
console: console,
|
console: console,
|
||||||
version: version,
|
version: version,
|
||||||
|
position: cgmath::Vector3::zero(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,11 +159,13 @@ impl Server {
|
||||||
let version = resources.read().unwrap().version();
|
let version = resources.read().unwrap().version();
|
||||||
Server {
|
Server {
|
||||||
conn: None,
|
conn: None,
|
||||||
|
read_queue: None,
|
||||||
world: world,
|
world: world,
|
||||||
|
|
||||||
version: version,
|
version: version,
|
||||||
resources: resources,
|
resources: resources,
|
||||||
console: console,
|
console: console,
|
||||||
|
position: cgmath::Vector3::new(0.5, 13.2, 0.5),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,11 +173,66 @@ impl Server {
|
||||||
self.conn.is_some()
|
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();
|
let version = self.resources.read().unwrap().version();
|
||||||
if version != self.version {
|
if version != self.version {
|
||||||
self.version = version;
|
self.version = version;
|
||||||
self.world.flag_dirty_all();
|
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
|
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 {
|
pub fn resize(&self, size: usize) -> Map {
|
||||||
let mut n = Map::new(self.length, size);
|
let mut n = Map::new(self.length, size);
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
|
|
||||||
pub struct Array {
|
pub struct Array {
|
||||||
data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Array {
|
impl Array {
|
||||||
|
|
|
@ -111,6 +111,10 @@ impl BlockManager {
|
||||||
fn get_block_by_steven_id(&self, id: usize) -> &'static Block {
|
fn get_block_by_steven_id(&self, id: usize) -> &'static Block {
|
||||||
self.steven_id[id]
|
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() {
|
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)
|
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! {
|
define_blocks! {
|
||||||
AIR InvisibleBlockSet = InvisibleBlockSet::new("air");
|
AIR InvisibleBlockSet = InvisibleBlockSet::new("air");
|
||||||
MISSING SimpleBlockSet = SimpleBlockSet::new("missing");
|
MISSING SimpleBlockSet = SimpleBlockSet::new("missing");
|
||||||
|
|
|
@ -18,6 +18,7 @@ use self::block::BlockSet;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use types::bit;
|
use types::bit;
|
||||||
use types::nibble;
|
use types::nibble;
|
||||||
|
use protocol;
|
||||||
|
|
||||||
pub struct World {
|
pub struct World {
|
||||||
chunks: HashMap<CPos, Chunk>,
|
chunks: HashMap<CPos, Chunk>,
|
||||||
|
@ -148,6 +149,66 @@ impl World {
|
||||||
|
|
||||||
snapshot
|
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 {
|
pub struct Snapshot {
|
||||||
|
|
Loading…
Reference in New Issue