First attempt at block handling rework

This commit is contained in:
Thinkofname 2016-03-20 00:29:35 +00:00
parent edee182bf9
commit 189c063f67
7 changed files with 252 additions and 35 deletions

1
Cargo.lock generated
View File

@ -8,6 +8,7 @@ dependencies = [
"glutin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -17,6 +17,7 @@ rand = "0.3.14"
rustc-serialize = "0.3.18"
log = "0.3.5"
cgmath = "0.7.0"
lazy_static = "0.1.15"
[dependencies.steven_gl]
path = "./gl"

View File

@ -90,7 +90,7 @@ fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_rec
for x in 0 .. 16 {
for z in 0 .. 16 {
let block = snapshot.get_block(x, y, z);
if !block.render {
if !block.renderable() {
continue;
}

View File

@ -15,6 +15,22 @@
#![recursion_limit="200"]
#![feature(const_fn)]
extern crate glutin;
extern crate image;
extern crate time;
extern crate byteorder;
extern crate serde_json;
extern crate steven_openssl as openssl;
extern crate hyper;
extern crate flate2;
extern crate rand;
extern crate rustc_serialize;
extern crate cgmath;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;
#[macro_use]
pub mod macros;
pub mod ecs;
@ -34,20 +50,6 @@ pub mod server;
pub mod world;
pub mod chunk_builder;
extern crate glutin;
extern crate image;
extern crate time;
extern crate byteorder;
extern crate serde_json;
extern crate steven_openssl as openssl;
extern crate hyper;
extern crate flate2;
extern crate rand;
extern crate rustc_serialize;
extern crate cgmath;
#[macro_use]
extern crate log;
use std::sync::{Arc, RwLock, Mutex};
use std::marker::PhantomData;
@ -74,6 +76,7 @@ pub struct Game {
}
fn main() {
world::block::force_init();
let con = Arc::new(Mutex::new(console::Console::new()));
{
let mut con = con.lock().unwrap();

View File

@ -14,7 +14,7 @@
use protocol;
use world;
use world::block;
use world::block::{self, BlockSet};
use rand::{self, Rng};
use std::sync::{Arc, RwLock};
use resources;
@ -35,7 +35,7 @@ impl Server {
for z in -7*16 .. 7*16 {
let h = rng.gen_range(3, 10);
for y in 0 .. h {
world.set_block(x, y, z, block::MISSING);
world.set_block(x, y, z, block::MISSING.base());
}
}
}

View File

@ -1,4 +1,214 @@
use std::collections::HashMap;
use std::cell::UnsafeCell;
pub trait BlockSet {
fn plugin(&'static self) -> &'static str {
"minecraft"
}
fn name(&'static self) -> &'static str;
fn blocks(&'static self) -> Vec<&'static Block>;
fn base(&'static self) -> &'static Block {
self.blocks()[0]
}
}
pub trait Block: Sync {
fn steven_id(&'static self) -> usize;
fn vanilla_id(&'static self) -> Option<usize>;
fn set_steven_id(&'static self, id: usize);
fn set_vanilla_id(&'static self, id: usize);
fn equals(&'static self, other: &'static Block) -> bool {
self.steven_id() == other.steven_id()
}
fn in_set(&'static self, set: &'static BlockSet) -> bool {
// TODO: Make faster
for block in set.blocks() {
if self.equals(block) {
return true
}
}
false
}
fn renderable(&'static self) -> bool {
true
}
fn data(&'static self) -> Option<u8> {
Some(0)
}
}
pub struct BlockManager {
vanilla_id: Vec<Option<&'static Block>>,
steven_id: Vec<&'static Block>,
next_id: usize,
}
macro_rules! define_blocks {
(
$(
$internal_name:ident $ty:ty = $bl:expr;
)*
) => (
lazy_static! {
$(
pub static ref $internal_name: $ty = $bl;
)*
static ref MANAGER: BlockManager = {
let mut manager = BlockManager {
vanilla_id: vec![None; 0xFFFF],
steven_id: vec![],
next_id: 0,
};
$(
manager.register_set(&*$internal_name);
)*
manager
};
}
)
}
// TODO: Replace this with trait fields when supported by rust
macro_rules! block_impl {
() => (
fn steven_id(&'static self) -> usize {
unsafe { *self.steven_id_storage.get() }
}
fn vanilla_id(&'static self) -> Option<usize> {
unsafe { *self.vanilla_id_storage.get() }
}
fn set_steven_id(&'static self, id: usize) {
unsafe { *self.steven_id_storage.get() = id; }
}
fn set_vanilla_id(&'static self, id: usize) {
unsafe { *self.vanilla_id_storage.get() = Some(id); }
}
)
}
impl BlockManager {
fn force_init(&self) {}
fn register_set(&mut self, set: &'static BlockSet) {
for block in set.blocks() {
if let Some(data) = block.data() {
let id = (self.next_id<<4) | (data as usize);
self.vanilla_id[id] = Some(block);
block.set_vanilla_id(id);
}
block.set_steven_id(self.steven_id.len());
self.steven_id.push(block);
}
self.next_id += 1;
}
fn get_block_by_steven_id(&self, id: usize) -> &'static Block {
self.steven_id[id]
}
}
pub fn force_init() {
MANAGER.force_init();
}
pub fn get_block_by_steven_id(id: usize) -> &'static Block {
MANAGER.get_block_by_steven_id(id)
}
define_blocks! {
AIR InvisibleBlockSet = InvisibleBlockSet::new("air");
MISSING SimpleBlockSet = SimpleBlockSet::new("missing");
}
pub struct InvisibleBlockSet {
name: &'static str,
sub_blocks: Vec<InvisibleBlock>,
}
impl InvisibleBlockSet {
fn new(name: &'static str) -> InvisibleBlockSet {
let sub_blocks = vec![InvisibleBlock {
steven_id_storage: UnsafeCell::new(0),
vanilla_id_storage: UnsafeCell::new(None),
}];
InvisibleBlockSet {
name: name,
sub_blocks: sub_blocks,
}
}
}
impl BlockSet for InvisibleBlockSet {
fn name(&'static self) -> &'static str {
self.name
}
fn blocks(&'static self) -> Vec<&'static Block> {
self.sub_blocks.iter().map(|v| v as &Block).collect()
}
}
struct InvisibleBlock {
steven_id_storage: UnsafeCell<usize>,
vanilla_id_storage: UnsafeCell<Option<usize>>,
}
unsafe impl Sync for InvisibleBlock {}
impl Block for InvisibleBlock {
block_impl!();
fn renderable(&'static self) -> bool {
false
}
}
pub struct SimpleBlockSet {
name: &'static str,
sub_blocks: Vec<SimpleBlock>,
}
impl SimpleBlockSet {
fn new(name: &'static str) -> SimpleBlockSet {
let sub_blocks = vec![SimpleBlock {
steven_id_storage: UnsafeCell::new(0),
vanilla_id_storage: UnsafeCell::new(None),
}];
SimpleBlockSet {
name: name,
sub_blocks: sub_blocks,
}
}
}
impl BlockSet for SimpleBlockSet {
fn name(&'static self) -> &'static str {
self.name
}
fn blocks(&'static self) -> Vec<&'static Block> {
self.sub_blocks.iter().map(|v| v as &Block).collect()
}
}
struct SimpleBlock {
steven_id_storage: UnsafeCell<usize>,
vanilla_id_storage: UnsafeCell<Option<usize>>,
}
unsafe impl Sync for SimpleBlock {}
impl Block for SimpleBlock {
block_impl!();
fn renderable(&'static self) -> bool {
true
}
}
/*
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Block {
pub render: bool,
@ -46,3 +256,4 @@ pub fn get_block_by_id(id: usize) -> &'static Block {
}
&BLOCKS[id]
}
*/

View File

@ -13,6 +13,7 @@
// limitations under the License.
pub mod block;
use self::block::BlockSet;
use std::collections::HashMap;
use types::bit;
@ -41,7 +42,7 @@ impl World {
pub fn get_block(&self, x: i32, y: i32, z: i32) -> &'static block::Block {
match self.chunks.get(&CPos(x >> 4, z >> 4)) {
Some(ref chunk) => chunk.get_block(x & 0xF, y, z & 0xF),
None => block::AIR,
None => block::AIR.base(),
}
}
@ -91,7 +92,7 @@ impl World {
};
for i in 0 .. (w * h * d) as usize {
snapshot.sky_light.set(i, 0xF);
snapshot.blocks[i] = block::MISSING.get_id() as u16;
snapshot.blocks[i] = block::MISSING.base().steven_id() as u16;
}
let cx1 = x >> 4;
@ -134,7 +135,7 @@ impl World {
snapshot.set_sky_light(ox, oy, oz, sec.get_sky_light(xx, yy, zz));
},
None => {
snapshot.set_block(ox, oy, oz, block::AIR);
snapshot.set_block(ox, oy, oz, block::AIR.base());
},
}
}
@ -172,12 +173,12 @@ impl Snapshot {
}
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)
block::get_block_by_steven_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;
self.blocks[idx] = b.steven_id() as u16;
}
pub fn get_block_light(&self, x: i32, y: i32, z: i32) -> u8 {
@ -234,7 +235,7 @@ impl Chunk {
return;
}
if self.sections[s_idx as usize].is_none() {
if b == block::AIR {
if b.in_set(&*block::AIR) {
return;
}
self.sections[s_idx as usize] = Some(Section::new(s_idx as u8));
@ -246,11 +247,11 @@ impl Chunk {
fn get_block(&self, x: i32, y: i32, z: i32) -> &'static block::Block {
let s_idx = y >> 4;
if s_idx < 0 || s_idx > 15 {
return block::AIR;
return block::AIR.base();
}
match self.sections[s_idx as usize].as_ref() {
Some(sec) => sec.get_block(x, y & 0xF, z),
None => block::AIR,
None => block::AIR.base(),
}
}
}
@ -260,7 +261,7 @@ struct Section {
blocks: bit::Map,
block_map: Vec<(&'static block::Block, u32)>,
rev_block_map: HashMap<&'static block::Block, usize>,
rev_block_map: HashMap<usize, usize>,
block_light: nibble::Array,
sky_light: nibble::Array,
@ -276,7 +277,7 @@ impl Section {
blocks: bit::Map::new(4096, 4),
block_map: vec![
(block::AIR, 0xFFFFFFFF)
(block::AIR.base(), 0xFFFFFFFF)
],
rev_block_map: HashMap::new(),
@ -289,7 +290,7 @@ impl Section {
for i in 0 .. 16*16*16 {
section.sky_light.set(i, 0xF);
}
section.rev_block_map.insert(block::AIR, 0);
section.rev_block_map.insert(block::AIR.base().steven_id(), 0);
section
}
@ -300,25 +301,25 @@ impl Section {
fn set_block(&mut self, x: i32, y: i32, z: i32, b: &'static block::Block) {
let old = self.get_block(x, y, z);
if old == b {
if old.equals(b) {
return;
}
// Clean up old block
{
let idx = self.rev_block_map[old];
let idx = self.rev_block_map[&old.steven_id()];
let info = &mut self.block_map[idx];
info.1 -= 1;
if info.1 == 0 { // None left of this type
self.rev_block_map.remove(old);
self.rev_block_map.remove(&old.steven_id());
}
}
if !self.rev_block_map.contains_key(b) {
if !self.rev_block_map.contains_key(&b.steven_id()) {
let mut found = false;
for (i, ref mut info) in self.block_map.iter_mut().enumerate() {
if info.1 == 0 {
info.0 = b;
self.rev_block_map.insert(b, i);
self.rev_block_map.insert(b.steven_id(), i);
found = true;
break;
}
@ -329,12 +330,12 @@ impl Section {
let new_blocks = self.blocks.resize(new_size);
self.blocks = new_blocks;
}
self.rev_block_map.insert(b, self.block_map.len());
self.rev_block_map.insert(b.steven_id(), self.block_map.len());
self.block_map.push((b, 0));
}
}
let idx = self.rev_block_map[b];
let idx = self.rev_block_map[&b.steven_id()];
let info = &mut self.block_map[idx];
info.1 += 1;
self.blocks.set(((y << 8) | (z << 4) | x) as usize, idx);