Spectator style movement + chunk unloading
This commit is contained in:
parent
8d141b1310
commit
e6477bd186
|
@ -14,7 +14,7 @@ pub struct ChunkBuilder {
|
||||||
free_builders: Vec<usize>,
|
free_builders: Vec<usize>,
|
||||||
built_recv: mpsc::Receiver<(usize, BuildReply)>,
|
built_recv: mpsc::Receiver<(usize, BuildReply)>,
|
||||||
|
|
||||||
sections: Vec<(i32, i32, i32)>,
|
sections: Vec<(i32, i32, i32, Arc<world::SectionKey>)>,
|
||||||
next_collection: f64,
|
next_collection: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ impl ChunkBuilder {
|
||||||
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);
|
||||||
|
|
||||||
renderer.update_chunk_solid(val.position, &val.solid_buffer, val.solid_count);
|
renderer.update_chunk_solid(val.position, val.key, &val.solid_buffer, val.solid_count);
|
||||||
|
|
||||||
self.free_builders.push(id);
|
self.free_builders.push(id);
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ impl ChunkBuilder {
|
||||||
self.sections = sections;
|
self.sections = sections;
|
||||||
self.next_collection = 60.0;
|
self.next_collection = 60.0;
|
||||||
}
|
}
|
||||||
while let Some((x, y, z)) = self.sections.pop() {
|
while let Some((x, y, z, key)) = self.sections.pop() {
|
||||||
let t_id = self.free_builders.pop().unwrap();
|
let t_id = self.free_builders.pop().unwrap();
|
||||||
world.set_building_flag((x, y, z));
|
world.set_building_flag((x, y, z));
|
||||||
let (cx, cy, cz) = (x << 4, y << 4, z << 4);
|
let (cx, cy, cz) = (x << 4, y << 4, z << 4);
|
||||||
|
@ -91,6 +91,7 @@ impl ChunkBuilder {
|
||||||
self.threads[t_id].0.send(BuildReq {
|
self.threads[t_id].0.send(BuildReq {
|
||||||
snapshot: snapshot,
|
snapshot: snapshot,
|
||||||
position: (x, y, z),
|
position: (x, y, z),
|
||||||
|
key: key,
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
if self.free_builders.is_empty() {
|
if self.free_builders.is_empty() {
|
||||||
return;
|
return;
|
||||||
|
@ -102,20 +103,22 @@ impl ChunkBuilder {
|
||||||
struct BuildReq {
|
struct BuildReq {
|
||||||
snapshot: world::Snapshot,
|
snapshot: world::Snapshot,
|
||||||
position: (i32, i32, i32),
|
position: (i32, i32, i32),
|
||||||
|
key: Arc<world::SectionKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BuildReply {
|
struct BuildReply {
|
||||||
position: (i32, i32, i32),
|
position: (i32, i32, i32),
|
||||||
solid_buffer: Vec<u8>,
|
solid_buffer: Vec<u8>,
|
||||||
solid_count: usize,
|
solid_count: usize,
|
||||||
|
key: Arc<world::SectionKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_recv: mpsc::Receiver<BuildReq>, built_send: mpsc::Sender<(usize, BuildReply)>) {
|
fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_recv: mpsc::Receiver<BuildReq>, built_send: mpsc::Sender<(usize, BuildReply)>) {
|
||||||
use rand::{self, Rng};
|
|
||||||
loop {
|
loop {
|
||||||
let BuildReq {
|
let BuildReq {
|
||||||
snapshot,
|
snapshot,
|
||||||
position,
|
position,
|
||||||
|
key,
|
||||||
} = match work_recv.recv() {
|
} = match work_recv.recv() {
|
||||||
Ok(val) => val,
|
Ok(val) => val,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
|
@ -124,8 +127,6 @@ fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_rec
|
||||||
let mut solid_buffer = vec![];
|
let mut solid_buffer = vec![];
|
||||||
let mut solid_count = 0;
|
let mut solid_count = 0;
|
||||||
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
|
|
||||||
for y in 0 .. 16 {
|
for y in 0 .. 16 {
|
||||||
for x in 0 .. 16 {
|
for x in 0 .. 16 {
|
||||||
for z in 0 .. 16 {
|
for z in 0 .. 16 {
|
||||||
|
@ -149,12 +150,7 @@ fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_rec
|
||||||
cb = ((cb as f64) * 0.8) as u8;
|
cb = ((cb as f64) * 0.8) as u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
let stone = render::Renderer::get_texture(&textures, rng.choose(&[
|
let stone = render::Renderer::get_texture(&textures, "minecraft:blocks/stone");
|
||||||
"minecraft:blocks/lava_flow",
|
|
||||||
"minecraft:blocks/stone",
|
|
||||||
"minecraft:blocks/melon_side",
|
|
||||||
"minecraft:blocks/sand",
|
|
||||||
]).unwrap());
|
|
||||||
solid_count += 6;
|
solid_count += 6;
|
||||||
for vert in dir.get_verts() {
|
for vert in dir.get_verts() {
|
||||||
let mut vert = vert.clone();
|
let mut vert = vert.clone();
|
||||||
|
@ -201,6 +197,7 @@ fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_rec
|
||||||
position: position,
|
position: position,
|
||||||
solid_buffer: solid_buffer,
|
solid_buffer: solid_buffer,
|
||||||
solid_count: solid_count,
|
solid_count: solid_count,
|
||||||
|
key: key,
|
||||||
})).unwrap();
|
})).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,8 +206,11 @@ fn calculate_light(snapshot: &world::Snapshot, orig_x: i32, orig_y: i32, orig_z:
|
||||||
x: f64, y: f64, z: f64, face: Direction, smooth: bool, force: bool) -> (u16, u16) {
|
x: f64, y: f64, z: f64, face: Direction, smooth: bool, force: bool) -> (u16, u16) {
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use world::block;
|
use world::block;
|
||||||
let (ox, oy, oz) = face.get_offset();
|
let (ox, oy, oz) = if !snapshot.get_block(orig_x, orig_y, orig_z).renderable() { // TODO: cull check
|
||||||
// TODO: Cull against check
|
(0, 0, 0)
|
||||||
|
} else {
|
||||||
|
face.get_offset()
|
||||||
|
};
|
||||||
|
|
||||||
let s_block_light = snapshot.get_block_light(orig_x + ox, orig_y + oy, orig_z + oz);
|
let s_block_light = snapshot.get_block_light(orig_x + ox, orig_y + oy, orig_z + oz);
|
||||||
let s_sky_light = snapshot.get_sky_light(orig_x + ox, orig_y + oy, orig_z + oz);
|
let s_sky_light = snapshot.get_sky_light(orig_x + ox, orig_y + oy, orig_z + oz);
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#![recursion_limit="200"]
|
#![recursion_limit="200"]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
|
#![feature(arc_counts)]
|
||||||
|
|
||||||
extern crate glutin;
|
extern crate glutin;
|
||||||
extern crate image;
|
extern crate image;
|
||||||
|
@ -107,7 +108,6 @@ impl Game {
|
||||||
match server {
|
match server {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
self.screen_sys.pop_screen();
|
self.screen_sys.pop_screen();
|
||||||
self.renderer.clear_chunks();
|
|
||||||
self.chunk_builder.wait_for_builders();
|
self.chunk_builder.wait_for_builders();
|
||||||
self.focused = true;
|
self.focused = true;
|
||||||
self.server = val;
|
self.server = val;
|
||||||
|
@ -292,10 +292,18 @@ fn handle_window_event(window: &glutin::Window,
|
||||||
game.console.lock().unwrap().toggle();
|
game.console.lock().unwrap().toggle();
|
||||||
}
|
}
|
||||||
Event::KeyboardInput(state, key, virt) => {
|
Event::KeyboardInput(state, key, virt) => {
|
||||||
ui_container.key_press(game, virt, key, state == glutin::ElementState::Pressed);
|
if game.focused {
|
||||||
|
if let Some(virt) = virt {
|
||||||
|
game.server.key_press(state == glutin::ElementState::Pressed, virt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ui_container.key_press(game, virt, key, state == glutin::ElementState::Pressed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Event::ReceivedCharacter(c) => {
|
Event::ReceivedCharacter(c) => {
|
||||||
ui_container.key_type(game, c);
|
if !game.focused {
|
||||||
|
ui_container.key_type(game, c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ use image::GenericImage;
|
||||||
use byteorder::{WriteBytesExt, NativeEndian};
|
use byteorder::{WriteBytesExt, NativeEndian};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use cgmath::{self, Vector, Point};
|
use cgmath::{self, Vector, Point};
|
||||||
|
use world;
|
||||||
|
|
||||||
const ATLAS_SIZE: usize = 1024;
|
const ATLAS_SIZE: usize = 1024;
|
||||||
|
|
||||||
|
@ -67,9 +68,12 @@ pub struct Renderer {
|
||||||
|
|
||||||
last_width: u32,
|
last_width: u32,
|
||||||
last_height: u32,
|
last_height: u32,
|
||||||
|
|
||||||
|
chunk_gc_timer: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ChunkBuffer {
|
struct ChunkBuffer {
|
||||||
|
key: Arc<world::SectionKey>,
|
||||||
position: (i32, i32, i32),
|
position: (i32, i32, i32),
|
||||||
|
|
||||||
solid: Option<ChunkRenderInfo>,
|
solid: Option<ChunkRenderInfo>,
|
||||||
|
@ -199,6 +203,8 @@ impl Renderer {
|
||||||
perspective_matrix: cgmath::Matrix4::zero(),
|
perspective_matrix: cgmath::Matrix4::zero(),
|
||||||
|
|
||||||
trans: None,
|
trans: None,
|
||||||
|
|
||||||
|
chunk_gc_timer: 120.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,6 +238,20 @@ impl Renderer {
|
||||||
self.init_trans(width, height);
|
self.init_trans(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.chunk_gc_timer -= delta;
|
||||||
|
if self.chunk_gc_timer <= 0.0 {
|
||||||
|
self.chunk_gc_timer = 120.0;
|
||||||
|
let mut unload_queue = vec![];
|
||||||
|
for (pos, info) in &self.chunks {
|
||||||
|
if Arc::strong_count(&info.key) == 1 {
|
||||||
|
unload_queue.push(*pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for unload in unload_queue {
|
||||||
|
self.chunks.remove(&unload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let trans = self.trans.as_mut().unwrap();
|
let trans = self.trans.as_mut().unwrap();
|
||||||
trans.main.bind();
|
trans.main.bind();
|
||||||
|
|
||||||
|
@ -317,10 +337,6 @@ impl Renderer {
|
||||||
self.ui.tick(width, height);
|
self.ui.tick(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_chunks(&mut self) {
|
|
||||||
self.chunks.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ensure_element_buffer(&mut self, size: usize) {
|
fn ensure_element_buffer(&mut self, size: usize) {
|
||||||
if self.element_buffer_size < size {
|
if self.element_buffer_size < size {
|
||||||
let (data, ty) = self::generate_element_buffer(size);
|
let (data, ty) = self::generate_element_buffer(size);
|
||||||
|
@ -331,13 +347,15 @@ impl Renderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_chunk_solid(&mut self, pos: (i32, i32, i32), data: &[u8], count: usize) {
|
pub fn update_chunk_solid(&mut self, pos: (i32, i32, i32), key: Arc<world::SectionKey>, data: &[u8], count: usize) {
|
||||||
self.ensure_element_buffer(count);
|
self.ensure_element_buffer(count);
|
||||||
let buffer = self.chunks.entry(pos).or_insert(ChunkBuffer {
|
let buffer = self.chunks.entry(pos).or_insert_with(||ChunkBuffer {
|
||||||
|
key: key.clone(),
|
||||||
position: pos,
|
position: pos,
|
||||||
solid: None,
|
solid: None,
|
||||||
trans: None,
|
trans: None,
|
||||||
});
|
});
|
||||||
|
buffer.key = key;
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
if buffer.solid.is_some() {
|
if buffer.solid.is_some() {
|
||||||
buffer.solid = None;
|
buffer.solid = None;
|
||||||
|
|
|
@ -19,12 +19,14 @@ use rand::{self, Rng};
|
||||||
use std::sync::{Arc, RwLock, Mutex};
|
use std::sync::{Arc, RwLock, Mutex};
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use std::collections::HashMap;
|
||||||
use resources;
|
use resources;
|
||||||
use openssl;
|
use openssl;
|
||||||
use console;
|
use console;
|
||||||
use render;
|
use render;
|
||||||
use auth;
|
use auth;
|
||||||
use cgmath::{self, Vector};
|
use cgmath::{self, Vector};
|
||||||
|
use glutin::VirtualKeyCode;
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
conn: Option<protocol::Conn>,
|
conn: Option<protocol::Conn>,
|
||||||
|
@ -39,6 +41,8 @@ pub struct Server {
|
||||||
pub yaw: f64,
|
pub yaw: f64,
|
||||||
pub pitch: f64,
|
pub pitch: f64,
|
||||||
|
|
||||||
|
pressed_keys: HashMap<VirtualKeyCode, bool>,
|
||||||
|
|
||||||
tick_timer: f64,
|
tick_timer: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +150,8 @@ impl Server {
|
||||||
console: console,
|
console: console,
|
||||||
version: version,
|
version: version,
|
||||||
|
|
||||||
|
pressed_keys: HashMap::new(),
|
||||||
|
|
||||||
position: cgmath::Vector3::zero(),
|
position: cgmath::Vector3::zero(),
|
||||||
yaw: 0.0,
|
yaw: 0.0,
|
||||||
pitch: 0.0,
|
pitch: 0.0,
|
||||||
|
@ -175,6 +181,8 @@ impl Server {
|
||||||
resources: resources,
|
resources: resources,
|
||||||
console: console,
|
console: console,
|
||||||
|
|
||||||
|
pressed_keys: HashMap::new(),
|
||||||
|
|
||||||
position: cgmath::Vector3::new(0.5, 13.2, 0.5),
|
position: cgmath::Vector3::new(0.5, 13.2, 0.5),
|
||||||
yaw: 0.0,
|
yaw: 0.0,
|
||||||
pitch: 0.0,
|
pitch: 0.0,
|
||||||
|
@ -201,6 +209,7 @@ impl Server {
|
||||||
self pck {
|
self pck {
|
||||||
KeepAliveClientbound => on_keep_alive,
|
KeepAliveClientbound => on_keep_alive,
|
||||||
ChunkData => on_chunk_data,
|
ChunkData => on_chunk_data,
|
||||||
|
ChunkUnload => on_chunk_unload,
|
||||||
TeleportPlayer => on_teleport,
|
TeleportPlayer => on_teleport,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -210,6 +219,26 @@ impl Server {
|
||||||
self.read_queue = Some(rx);
|
self.read_queue = Some(rx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (forward, yaw) = self.calculate_movement();
|
||||||
|
|
||||||
|
if self.world.is_chunk_loaded((self.position.x as i32) >> 4, (self.position.z as i32) >> 4) {
|
||||||
|
let mut speed = 4.317 / 60.0;
|
||||||
|
if self.is_key_pressed(VirtualKeyCode::LShift) {
|
||||||
|
speed = 5.612 / 60.0;
|
||||||
|
}
|
||||||
|
// TODO: only do this for flying
|
||||||
|
speed *= 2.5;
|
||||||
|
|
||||||
|
if self.is_key_pressed(VirtualKeyCode::Space) {
|
||||||
|
self.position.y += speed * delta;
|
||||||
|
}
|
||||||
|
if self.is_key_pressed(VirtualKeyCode::LControl) {
|
||||||
|
self.position.y -= speed * delta;
|
||||||
|
}
|
||||||
|
self.position.x += forward * yaw.cos() * delta * speed;
|
||||||
|
self.position.z -= forward * yaw.sin() * delta * speed;
|
||||||
|
}
|
||||||
|
|
||||||
self.tick_timer += delta;
|
self.tick_timer += delta;
|
||||||
while self.tick_timer >= 3.0 && self.is_connected() {
|
while self.tick_timer >= 3.0 && self.is_connected() {
|
||||||
self.minecraft_tick();
|
self.minecraft_tick();
|
||||||
|
@ -222,6 +251,35 @@ impl Server {
|
||||||
renderer.camera.pitch = self.pitch;
|
renderer.camera.pitch = self.pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn calculate_movement(&self) -> (f64, f64) {
|
||||||
|
use std::f64::consts::PI;
|
||||||
|
let mut forward = 0.0f64;
|
||||||
|
let mut yaw = self.yaw - (PI/2.0);
|
||||||
|
if self.is_key_pressed(VirtualKeyCode::W) || self.is_key_pressed(VirtualKeyCode::S) {
|
||||||
|
forward = 1.0;
|
||||||
|
if self.is_key_pressed(VirtualKeyCode::S) {
|
||||||
|
yaw += PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut change = 0.0;
|
||||||
|
if self.is_key_pressed(VirtualKeyCode::A) {
|
||||||
|
change = (PI / 2.0) / (forward.abs() + 1.0);
|
||||||
|
}
|
||||||
|
if self.is_key_pressed(VirtualKeyCode::D) {
|
||||||
|
change = -(PI / 2.0) / (forward.abs() + 1.0);
|
||||||
|
}
|
||||||
|
if self.is_key_pressed(VirtualKeyCode::A) || self.is_key_pressed(VirtualKeyCode::D) {
|
||||||
|
forward = 1.0;
|
||||||
|
}
|
||||||
|
if self.is_key_pressed(VirtualKeyCode::S) {
|
||||||
|
yaw -= change;
|
||||||
|
} else {
|
||||||
|
yaw += change;
|
||||||
|
}
|
||||||
|
|
||||||
|
(forward, yaw)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn minecraft_tick(&mut self) {
|
pub fn minecraft_tick(&mut self) {
|
||||||
|
|
||||||
// Sync our position to the server
|
// Sync our position to the server
|
||||||
|
@ -236,17 +294,25 @@ impl Server {
|
||||||
self.write_packet(packet);
|
self.write_packet(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn key_press(&mut self, down: bool, key: VirtualKeyCode) {
|
||||||
|
self.pressed_keys.insert(key, down);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_key_pressed(&self, key: VirtualKeyCode) -> bool {
|
||||||
|
self.pressed_keys.get(&key).map(|v| *v).unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_packet<T: protocol::PacketType>(&mut self, p: T) {
|
pub fn write_packet<T: protocol::PacketType>(&mut self, p: T) {
|
||||||
self.conn.as_mut().unwrap().write_packet(p).unwrap(); // TODO handle errors
|
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) {
|
fn on_keep_alive(&mut self, keep_alive: packet::play::clientbound::KeepAliveClientbound) {
|
||||||
self.write_packet(packet::play::serverbound::KeepAliveServerbound {
|
self.write_packet(packet::play::serverbound::KeepAliveServerbound {
|
||||||
id: keep_alive.id,
|
id: keep_alive.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_teleport(&mut self, teleport: packet::play::clientbound::TeleportPlayer) {
|
fn on_teleport(&mut self, teleport: packet::play::clientbound::TeleportPlayer) {
|
||||||
// TODO: relative teleports
|
// TODO: relative teleports
|
||||||
self.position.x = teleport.x;
|
self.position.x = teleport.x;
|
||||||
self.position.y = teleport.y;
|
self.position.y = teleport.y;
|
||||||
|
@ -264,7 +330,7 @@ impl Server {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_chunk_data(&mut self, chunk_data: packet::play::clientbound::ChunkData) {
|
fn on_chunk_data(&mut self, chunk_data: packet::play::clientbound::ChunkData) {
|
||||||
self.world.load_chunk(
|
self.world.load_chunk(
|
||||||
chunk_data.chunk_x,
|
chunk_data.chunk_x,
|
||||||
chunk_data.chunk_z,
|
chunk_data.chunk_z,
|
||||||
|
@ -273,4 +339,8 @@ impl Server {
|
||||||
chunk_data.data.data
|
chunk_data.data.data
|
||||||
).unwrap();
|
).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_chunk_unload(&mut self, chunk_unload: packet::play::clientbound::ChunkUnload) {
|
||||||
|
self.world.unload_chunk(chunk_unload.x, chunk_unload.z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
pub mod block;
|
pub mod block;
|
||||||
use self::block::BlockSet;
|
use self::block::BlockSet;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use types::bit;
|
use types::bit;
|
||||||
use types::nibble;
|
use types::nibble;
|
||||||
|
@ -31,6 +32,10 @@ impl World {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_chunk_loaded(&self, x: i32, z: i32) -> bool {
|
||||||
|
self.chunks.contains_key(&CPos(x, z))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_block(&mut self, x: i32, y: i32, z: i32, b: &'static block::Block) {
|
pub fn set_block(&mut self, x: i32, y: i32, z: i32, b: &'static block::Block) {
|
||||||
let cpos = CPos(x >> 4, z >> 4);
|
let cpos = CPos(x >> 4, z >> 4);
|
||||||
if !self.chunks.contains_key(&cpos) {
|
if !self.chunks.contains_key(&cpos) {
|
||||||
|
@ -47,13 +52,13 @@ impl World {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_dirty_chunk_sections(&mut self) -> Vec<(i32, i32, i32)> {
|
pub fn get_dirty_chunk_sections(&mut self) -> Vec<(i32, i32, i32, Arc<SectionKey>)> {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
for (_, chunk) in &mut self.chunks {
|
for (_, chunk) in &mut self.chunks {
|
||||||
for sec in &mut chunk.sections {
|
for sec in &mut chunk.sections {
|
||||||
if let Some(sec) = sec.as_mut() {
|
if let Some(sec) = sec.as_mut() {
|
||||||
if !sec.building && sec.dirty {
|
if !sec.building && sec.dirty {
|
||||||
out.push((chunk.position.0, sec.y as i32, chunk.position.1));
|
out.push((chunk.position.0, sec.y as i32, chunk.position.1, sec.key.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,6 +163,10 @@ impl World {
|
||||||
snapshot
|
snapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn unload_chunk(&mut self, x: i32, z: i32) {
|
||||||
|
self.chunks.remove(&CPos(x, z));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_chunk(&mut self, x: i32, z: i32, new: bool, mask: u16, data: Vec<u8>) -> Result<(), protocol::Error> {
|
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 std::io::{Cursor, Read};
|
||||||
use byteorder::ReadBytesExt;
|
use byteorder::ReadBytesExt;
|
||||||
|
@ -182,7 +191,7 @@ impl World {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if chunk.sections[i].is_none() {
|
if chunk.sections[i].is_none() {
|
||||||
chunk.sections[i] = Some(Section::new(i as u8));
|
chunk.sections[i] = Some(Section::new(x, i as u8, z));
|
||||||
}
|
}
|
||||||
let section = chunk.sections[i as usize].as_mut().unwrap();
|
let section = chunk.sections[i as usize].as_mut().unwrap();
|
||||||
section.dirty = true;
|
section.dirty = true;
|
||||||
|
@ -332,7 +341,7 @@ impl Chunk {
|
||||||
if b.in_set(&*block::AIR) {
|
if b.in_set(&*block::AIR) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.sections[s_idx as usize] = Some(Section::new(s_idx as u8));
|
self.sections[s_idx as usize] = Some(Section::new(self.position.0, s_idx as u8, self.position.1));
|
||||||
}
|
}
|
||||||
let section = self.sections[s_idx as usize].as_mut().unwrap();
|
let section = self.sections[s_idx as usize].as_mut().unwrap();
|
||||||
section.set_block(x, y & 0xF, z, b);
|
section.set_block(x, y & 0xF, z, b);
|
||||||
|
@ -350,7 +359,13 @@ impl Chunk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash)]
|
||||||
|
pub struct SectionKey {
|
||||||
|
pos: (i32, u8, i32),
|
||||||
|
}
|
||||||
|
|
||||||
struct Section {
|
struct Section {
|
||||||
|
key: Arc<SectionKey>,
|
||||||
y: u8,
|
y: u8,
|
||||||
|
|
||||||
blocks: bit::Map,
|
blocks: bit::Map,
|
||||||
|
@ -365,8 +380,11 @@ struct Section {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Section {
|
impl Section {
|
||||||
fn new(y: u8) -> Section {
|
fn new(x: i32, y: u8, z: i32) -> Section {
|
||||||
let mut section = Section {
|
let mut section = Section {
|
||||||
|
key: Arc::new(SectionKey{
|
||||||
|
pos: (x, y, z),
|
||||||
|
}),
|
||||||
y: y,
|
y: y,
|
||||||
|
|
||||||
blocks: bit::Map::new(4096, 4),
|
blocks: bit::Map::new(4096, 4),
|
||||||
|
|
Loading…
Reference in New Issue