Rework block system

This commit is contained in:
Thinkofname 2016-03-23 21:07:49 +00:00
parent 2969dfe799
commit baeb6b94aa
8 changed files with 274 additions and 499 deletions

View File

@ -127,16 +127,16 @@ fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_rec
for y in 0 .. 16 {
for x in 0 .. 16 {
for z in 0 .. 16 {
let block = snapshot.get_block(x, y, z);
if !block.renderable() {
let block = snapshot.get_block(x, y, z).get_material();
if !block.renderable {
continue;
}
for dir in Direction::all() {
let offset = dir.get_offset();
let other = snapshot.get_block(x + offset.0, y + offset.1, z + offset.2);
if other.renderable() {
let other = snapshot.get_block(x + offset.0, y + offset.1, z + offset.2).get_material();
if other.renderable {
continue;
}
@ -147,7 +147,7 @@ fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_rec
cb = ((cb as f64) * 0.8) as u8;
}
let stone = render::Renderer::get_texture(&textures, &format!("minecraft:blocks/{}", "dirt"));
let stone = render::Renderer::get_texture(&textures, &format!("minecraft:blocks/{}", block.texture));
solid_count += 6;
for vert in dir.get_verts() {
let mut vert = vert.clone();
@ -203,7 +203,7 @@ 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) {
use std::cmp::max;
use world::block;
let (ox, oy, oz) = if !snapshot.get_block(orig_x, orig_y, orig_z).renderable() { // TODO: cull check
let (ox, oy, oz) = if !snapshot.get_block(orig_x, orig_y, orig_z).get_material().renderable { // TODO: cull check
(0, 0, 0)
} else {
face.get_offset()
@ -234,7 +234,7 @@ fn calculate_light(snapshot: &world::Snapshot, orig_x: i32, orig_y: i32, orig_z:
let lz = (z + oz + dz).round() as i32;
let mut bl = snapshot.get_block_light(lx, ly, lz);
let mut sl = snapshot.get_sky_light(lx, ly, lz);
if (force && !snapshot.get_block(lx, ly, lz).in_set(&*block::AIR))
if (force && match snapshot.get_block(lx, ly, lz) { block::Air{} => false, _ => true })
|| (sl == 0 && bl == 0){
bl = s_block_light;
sl = s_sky_light;

View File

@ -35,6 +35,7 @@ extern crate collision;
#[macro_use]
pub mod macros;
pub mod ecs;
pub mod protocol;
pub mod format;
@ -135,7 +136,6 @@ impl Game {
}
fn main() {
world::block::force_init();
let con = Arc::new(Mutex::new(console::Console::new()));
{
let mut con = con.lock().unwrap();

View File

@ -152,7 +152,7 @@ fn twos_compliment(data: &mut Vec<u8>) {
data[i] = !data[i];
if carry {
carry = data[i] == 0xFF;
data[i] += 1;
data[i].wrapping_add(1);
}
}
}

View File

@ -14,7 +14,7 @@
use protocol::{self, mojang, packet};
use world;
use world::block::{self, BlockSet};
use world::block;
use rand::{self, Rng};
use std::sync::{Arc, RwLock, Mutex};
use std::sync::mpsc;
@ -168,7 +168,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.base());
world.set_block(x, y, z, block::Dirt{});
}
}
}

View File

@ -1,373 +1,264 @@
use std::collections::HashMap;
use std::cell::UnsafeCell;
use std::fmt::{Display, Formatter, Error};
pub trait BlockSet {
fn plugin(&self) -> &'static str {
"minecraft"
}
pub use self::Block::*;
fn name(&self) -> &'static str;
fn blocks(&'static self) -> Vec<&'static Block>;
macro_rules! consume_token { ($i:tt) => (0) }
fn base(&'static self) -> &'static Block {
self.blocks()[0]
}
}
pub trait Block: Sync + ::std::fmt::Debug {
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 plugin(&self) -> &'static str;
fn name(&self) -> &'static str;
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! offsets {
($first:ident, $($other:ident),*) => (
#[allow(non_upper_case_globals)]
pub const $first: usize = 0;
offsets!(prev($first), $($other),*);
);
(prev($prev:ident), $first:ident, $($other:ident),*) => (
#[allow(non_upper_case_globals)]
pub const $first: usize = $prev + internal_sizes::$prev;
offsets!(prev($first), $($other),*);
);
(prev($prev:ident), $first:ident) => (
#[allow(non_upper_case_globals)]
pub const $first: usize = $prev + internal_sizes::$prev;
)
}
macro_rules! define_blocks {
(
$(
$internal_name:ident $ty:ty = $bl:expr;
)*
$name:ident {
props {
$(
$fname:ident : $ftype:ty = [$($val:expr),+],
)*
},
data $datafunc:expr,
material $mat:expr,
}
)+
) => (
lazy_static! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Block {
$(
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
$name {
$(
$fname : $ftype,
)*
},
)+
}
mod internal_ids {
create_ids!(usize, $($name),+);
}
mod internal_sizes {
$(
#[allow(non_upper_case_globals)]
pub const $name : usize = $(($(1 + consume_token!($val) + )+ 0) * )* 1;
)+
}
mod internal_offsets {
use super::internal_sizes;
offsets!($($name),+);
}
mod internal_offset_max {
use super::internal_sizes;
use super::internal_offsets;
$(
#[allow(non_upper_case_globals)]
pub const $name: usize = internal_offsets::$name + internal_sizes::$name - 1;
)+
}
impl Block {
#[allow(unused_variables, unused_mut, unused_assignments)]
pub fn get_steven_id(&self) -> usize {
match *self {
$(
Block::$name {
$($fname,)*
} => {
let mut offset = internal_offsets::$name;
let mut mul = 1;
$(
offset += [$($val),+].into_iter().position(|v| *v == $fname).unwrap() * mul;
mul *= $(1 + consume_token!($val) + )+ 0;
)*
offset
},
)+
}
}
#[allow(unused_variables, unused_assignments)]
pub fn by_steven_id(id: usize) -> Block {
match id {
$(
mut data @ internal_offsets::$name ... internal_offset_max::$name=> {
data -= internal_offsets::$name;
$(
let vals = [$($val),+];
let $fname = vals[data % vals.len()];
data /= vals.len();
)*
Block::$name {
$(
$fname: $fname,
)*
}
},
)*
_ => Block::Missing {}
}
}
pub fn get_vanilla_id(&self) -> Option<usize> {
match *self {
$(
Block::$name {
$($fname,)*
} => {
($datafunc).map(|v| v + (internal_ids::$name << 4))
}
)+
}
}
pub fn by_vanilla_id(id: usize) -> Block {
VANILLA_ID_MAP.get(id).and_then(|v| *v).unwrap_or(Block::Missing{})
}
pub fn get_material(&self) -> Material {
match *self {
$(
Block::$name {
$($fname,)*
} => {
$mat
}
)+
}
}
}
lazy_static! {
static ref VANILLA_ID_MAP: Vec<Option<Block>> = {
let mut blocks = vec![];
for i in 0 .. internal_offsets::Missing {
let block = Block::by_steven_id(i);
if let Some(id) = block.get_vanilla_id() {
if blocks.len() <= id {
blocks.resize(id + 1, None);
}
blocks[id] = Some(block);
}
}
blocks
};
}
)
}
// 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); }
}
fn plugin(&self) -> &'static str {
self.plugin
}
fn name(&self) -> &'static str {
self.name
}
)
}
macro_rules! block_combos {
(
$set:ty, params($($pname:ident : $pty:ty),*),
$bty:ident {
$(
$fname:ident : $fval:expr,
)*
}
) => (
struct $bty {
steven_id_storage: UnsafeCell<usize>,
vanilla_id_storage: UnsafeCell<Option<usize>>,
plugin: &'static str,
name: &'static str,
$(
$fname: $fty,
)*
}
unsafe impl Sync for $bty {}
impl ::std::fmt::Debug for $bty {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
write!(f, "{}:{}", self.plugin(), self.name())
}
}
impl $set {
fn gen_combos(&mut self, $($pname: $pty),*) {
let val = $bty {
steven_id_storage: UnsafeCell::new(0),
vanilla_id_storage: UnsafeCell::new(None),
name: self.name(),
plugin: self.plugin(),
$(
$fname: $fval,
)*
};
self.sub_blocks.push(val);
}
}
);
(
$set:ty, params($($pname:ident : $pty:ty),*),
types (
$(
$tname:ident : $tty:ty = [$($val:expr),+]
),+
),
$bty:ident {
$(
$fname:ident : $fty:ty = $fval:expr,
)*
}
) => (
struct $bty {
steven_id_storage: UnsafeCell<usize>,
vanilla_id_storage: UnsafeCell<Option<usize>>,
plugin: &'static str,
name: &'static str,
$(
$fname: $fty,
)*
}
unsafe impl Sync for $bty {}
impl ::std::fmt::Debug for $bty {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
try!(write!(f, "{}:{}[", self.plugin(), self.name()));
let mut s = String::new();
$(
s.push_str(&format!("{}={},", stringify!($tname), self.$tname));
)+
s.pop();
write!(f, "{}]", s)
}
}
impl $set {
fn gen_combos(&mut self, $($pname: $pty),*) {
use std::iter::Iterator;
#[allow(dead_code)]
#[allow(non_camel_case_types)]
struct CombinationIter<$($tname),+> {
$(
$tname: $tname,
)+
orig: CombinationIterOrig<$($tname),+> ,
last: Option<Wrapper>,
done: bool,
}
#[allow(non_camel_case_types)]
struct CombinationIterOrig<$($tname),+> {
$(
$tname: $tname,
)+
}
#[derive(Clone)]
struct Wrapper {
$(
$tname: $tty,
)+
}
#[allow(non_camel_case_types)]
impl <$($tname: Iterator<Item=$tty> + Clone),+> CombinationIter<$($tname),+> {
fn new($($tname: $tname),+) -> CombinationIter<$($tname),+> {
let orig = CombinationIterOrig {
$(
$tname: $tname
),+
};
CombinationIter {
$(
$tname: orig.$tname.clone(),
)+
orig: orig,
last: None,
done: false,
}
}
}
#[allow(non_camel_case_types)]
impl <$($tname: Iterator<Item=$tty> + Clone),+> Iterator for CombinationIter<$($tname),+> {
type Item = Wrapper;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None
}
if self.last.is_none() {
let wrapper = Wrapper {
$(
$tname: self.$tname.next().unwrap() // Shouldn't ever fail the first iter
),+
};
self.last = Some(wrapper.clone());
return Some(wrapper);
}
let mut ret = self.last.take().unwrap();
$(
if let Some(val) = self.$tname.next() {
ret.$tname = val;
self.last = Some(ret.clone());
return Some(ret)
}
self.$tname = self.orig.$tname.clone();
)+
self.done = true;
None
}
}
let iter = CombinationIter::new($(vec![$($val),+].into_iter()),+);
for val in iter {
$(
let $tname = val.$tname;
)+
let val = $bty {
steven_id_storage: UnsafeCell::new(0),
vanilla_id_storage: UnsafeCell::new(None),
name: self.name(),
plugin: self.plugin(),
$(
$fname: $fval,
)*
};
self.sub_blocks.push(val);
}
}
}
)
}
#[test]
fn temp_test() {
force_init();
println!("{:?}", STONE.blocks());
unimplemented!()
pub struct Material {
pub renderable: bool,
// TEMP
pub texture: &'static str,
}
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]
}
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() {
MANAGER.force_init();
}
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)
}
pub mod simple;
pub mod stone;
define_blocks! {
AIR InvisibleBlockSet = InvisibleBlockSet::new("air");
STONE stone::StoneBlockSet = stone::StoneBlockSet::new("stone");
GRASS simple::SimpleBlockSet = simple::SimpleBlockSet::new("grass");
DIRT simple::SimpleBlockSet = simple::SimpleBlockSet::new("dirt");
MISSING simple::SimpleBlockSet = simple::SimpleBlockSet::new("missing");
}
/// A block set that contains blocks which cannot be rendered.
pub struct InvisibleBlockSet {
name: &'static str,
sub_blocks: Vec<InvisibleBlock>,
}
block_combos!(InvisibleBlockSet, params(),
InvisibleBlock {
Air {
props {},
data { Some(0) },
material Material {
renderable: false,
texture: "none",
},
}
);
impl InvisibleBlockSet {
fn new(name: &'static str) -> InvisibleBlockSet {
let mut set = InvisibleBlockSet {
name: name,
sub_blocks: vec![],
};
set.gen_combos();
set
Stone {
props {
variant: StoneVariant = [
StoneVariant::Normal,
StoneVariant::Granite, StoneVariant::SmoothGranite,
StoneVariant::Diorite, StoneVariant::SmoothDiorite,
StoneVariant::Andesite, StoneVariant::SmoothAndesite
],
},
data { Some(variant.data()) },
material Material {
renderable: true,
texture: match variant {
StoneVariant::Normal => "stone",
StoneVariant::Granite => "stone_granite",
StoneVariant::SmoothGranite => "stone_granite_smooth",
StoneVariant::Diorite => "stone_diorite",
StoneVariant::SmoothDiorite => "stone_diorite_smooth",
StoneVariant::Andesite => "stone_andesite",
StoneVariant::SmoothAndesite => "stone_andesite_smooth",
},
},
}
Grass {
props {
},
data { Some(0) },
material Material {
renderable: true,
texture: "grass_path_top",
},
}
Dirt {
props {
},
data { Some(0) },
material Material {
renderable: true,
texture: "dirt",
},
}
Missing {
props {},
data { None::<usize> },
material Material {
renderable: true,
texture: "missing_texture",
},
}
}
impl BlockSet for InvisibleBlockSet {
fn name(&self) -> &'static str {
self.name
}
fn blocks(&'static self) -> Vec<&'static Block> {
self.sub_blocks.iter().map(|v| v as &Block).collect()
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum StoneVariant {
Normal,
Granite,
SmoothGranite,
Diorite,
SmoothDiorite,
Andesite,
SmoothAndesite,
}
impl Display for StoneVariant {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "{}", match *self {
StoneVariant::Normal => "stone",
StoneVariant::Granite => "granite",
StoneVariant::SmoothGranite => "smooth_granite",
StoneVariant::Diorite => "diorite",
StoneVariant::SmoothDiorite => "smooth_diorite",
StoneVariant::Andesite => "andesite",
StoneVariant::SmoothAndesite => "smooth_andesite",
})
}
}
impl Block for InvisibleBlock {
block_impl!();
fn renderable(&'static self) -> bool {
false
impl StoneVariant {
fn data(&self) -> usize {
match *self {
StoneVariant::Normal => 0,
StoneVariant::Granite => 1,
StoneVariant::SmoothGranite => 2,
StoneVariant::Diorite => 3,
StoneVariant::SmoothDiorite => 4,
StoneVariant::Andesite => 5,
StoneVariant::SmoothAndesite => 6,
}
}
}

View File

@ -1,39 +0,0 @@
use super::{Block, BlockSet};
use std::cell::UnsafeCell;
/// A block set for blocks which don't have any special features about them.
pub struct SimpleBlockSet {
name: &'static str,
sub_blocks: Vec<SimpleBlock>,
}
block_combos!(SimpleBlockSet, params(),
SimpleBlock {
}
);
impl SimpleBlockSet {
pub fn new(name: &'static str) -> SimpleBlockSet {
let mut set = SimpleBlockSet {
name: name,
sub_blocks: vec![],
};
set.gen_combos();
set
}
}
impl BlockSet for SimpleBlockSet {
fn name(&self) -> &'static str {
self.name
}
fn blocks(&'static self) -> Vec<&'static Block> {
self.sub_blocks.iter().map(|v| v as &Block).collect()
}
}
impl Block for SimpleBlock {
block_impl!();
}

View File

@ -1,76 +0,0 @@
use super::{Block, BlockSet};
use std::cell::UnsafeCell;
use std::fmt::{Display, Formatter, Error};
/// A block set for stone blocks.
pub struct StoneBlockSet {
name: &'static str,
sub_blocks: Vec<StoneBlock>,
}
block_combos!(StoneBlockSet, params(),
types (
variant: Variant = [
Variant::Normal,
Variant::Granite, Variant::SmoothGranite,
Variant::Diorite, Variant::SmoothDiorite,
Variant::Andesite, Variant::SmoothAndesite
],
test_num: u32 = [0, 1, 2, 3, 4, 5, 6]
),
StoneBlock {
variant: Variant = variant,
test_num: u32 = test_num,
}
);
#[derive(Clone, Copy, Debug)]
pub enum Variant {
Normal,
Granite,
SmoothGranite,
Diorite,
SmoothDiorite,
Andesite,
SmoothAndesite,
}
impl Display for Variant {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "{}", match *self {
Variant::Normal => "stone",
Variant::Granite => "granite",
Variant::SmoothGranite => "smooth_granite",
Variant::Diorite => "diorite",
Variant::SmoothDiorite => "smooth_diorite",
Variant::Andesite => "andesite",
Variant::SmoothAndesite => "smooth_andesite",
})
}
}
impl StoneBlockSet {
pub fn new(name: &'static str) -> StoneBlockSet {
let mut set = StoneBlockSet {
name: name,
sub_blocks: vec![],
};
set.gen_combos();
set
}
}
impl BlockSet for StoneBlockSet {
fn name(&self) -> &'static str {
self.name
}
fn blocks(&'static self) -> Vec<&'static Block> {
self.sub_blocks.iter().map(|v| v as &Block).collect()
}
}
impl Block for StoneBlock {
block_impl!();
}

View File

@ -13,7 +13,6 @@
// limitations under the License.
pub mod block;
use self::block::BlockSet;
use std::sync::Arc;
use std::collections::HashMap;
@ -37,7 +36,7 @@ impl World {
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: block::Block) {
let cpos = CPos(x >> 4, z >> 4);
if !self.chunks.contains_key(&cpos) {
self.chunks.insert(cpos, Chunk::new(cpos));
@ -46,10 +45,10 @@ impl World {
chunk.set_block(x & 0xF, y, z & 0xF, b);
}
pub fn get_block(&self, x: i32, y: i32, z: i32) -> &'static block::Block {
pub fn get_block(&self, x: i32, y: i32, z: i32) -> block::Block {
match self.chunks.get(&CPos(x >> 4, z >> 4)) {
Some(ref chunk) => chunk.get_block(x & 0xF, y, z & 0xF),
None => block::MISSING.base(),
None => block::Missing{},
}
}
@ -107,7 +106,7 @@ impl World {
};
for i in 0 .. (w * h * d) as usize {
snapshot.sky_light.set(i, 0xF);
snapshot.blocks[i] = block::MISSING.base().steven_id() as u16;
snapshot.blocks[i] = block::Missing{}.get_steven_id() as u16;
}
let cx1 = x >> 4;
@ -150,7 +149,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.base());
snapshot.set_block(ox, oy, oz, block::Air{});
},
}
}
@ -213,7 +212,7 @@ impl World {
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 block = block::Block::by_vanilla_id(block_id);
let i = i as i32;
section.set_block(
i & 0xF,
@ -276,13 +275,13 @@ impl Snapshot {
self.z = z;
}
pub fn get_block(&self, x: i32, y: i32, z: i32) -> &'static block::Block {
block::get_block_by_steven_id(self.blocks[self.index(x, y, z)] as usize)
pub fn get_block(&self, x: i32, y: i32, z: i32) -> block::Block {
block::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) {
pub fn set_block(&mut self, x: i32, y: i32, z: i32, b: block::Block) {
let idx = self.index(x, y, z);
self.blocks[idx] = b.steven_id() as u16;
self.blocks[idx] = b.get_steven_id() as u16;
}
pub fn get_block_light(&self, x: i32, y: i32, z: i32) -> u8 {
@ -333,13 +332,13 @@ impl Chunk {
}
}
fn set_block(&mut self, x: i32, y: i32, z: i32, b: &'static block::Block) {
fn set_block(&mut self, x: i32, y: i32, z: i32, b: block::Block) {
let s_idx = y >> 4;
if s_idx < 0 || s_idx > 15 {
return;
}
if self.sections[s_idx as usize].is_none() {
if b.in_set(&*block::AIR) {
if let block::Air {} = b {
return;
}
self.sections[s_idx as usize] = Some(Section::new(self.position.0, s_idx as u8, self.position.1));
@ -348,14 +347,14 @@ impl Chunk {
section.set_block(x, y & 0xF, z, b);
}
fn get_block(&self, x: i32, y: i32, z: i32) -> &'static block::Block {
fn get_block(&self, x: i32, y: i32, z: i32) -> block::Block {
let s_idx = y >> 4;
if s_idx < 0 || s_idx > 15 {
return block::MISSING.base();
return block::Missing{};
}
match self.sections[s_idx as usize].as_ref() {
Some(sec) => sec.get_block(x, y & 0xF, z),
None => block::AIR.base(),
None => block::Air{},
}
}
}
@ -391,8 +390,8 @@ struct Section {
y: u8,
blocks: bit::Map,
block_map: Vec<(&'static block::Block, u32)>,
rev_block_map: HashMap<usize, usize, BuildHasherDefault<FNVHash>>,
block_map: Vec<(block::Block, u32)>,
rev_block_map: HashMap<block::Block, usize, BuildHasherDefault<FNVHash>>,
block_light: nibble::Array,
sky_light: nibble::Array,
@ -411,7 +410,7 @@ impl Section {
blocks: bit::Map::new(4096, 4),
block_map: vec![
(block::AIR.base(), 0xFFFFFFFF)
(block::Air{}, 0xFFFFFFFF)
],
rev_block_map: HashMap::with_hasher(BuildHasherDefault::default()),
@ -424,36 +423,36 @@ impl Section {
for i in 0 .. 16*16*16 {
section.sky_light.set(i, 0xF);
}
section.rev_block_map.insert(block::AIR.base().steven_id(), 0);
section.rev_block_map.insert(block::Air{}, 0);
section
}
fn get_block(&self, x: i32, y: i32, z: i32) -> &'static block::Block {
fn get_block(&self, x: i32, y: i32, z: i32) -> block::Block {
let idx = self.blocks.get(((y << 8) | (z << 4) | x) as usize);
self.block_map[idx].0
}
fn set_block(&mut self, x: i32, y: i32, z: i32, b: &'static block::Block) {
fn set_block(&mut self, x: i32, y: i32, z: i32, b: block::Block) {
let old = self.get_block(x, y, z);
if old.equals(b) {
if old == b {
return;
}
// Clean up old block
{
let idx = self.rev_block_map[&old.steven_id()];
let idx = self.rev_block_map[&old];
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.steven_id());
self.rev_block_map.remove(&old);
}
}
if !self.rev_block_map.contains_key(&b.steven_id()) {
if !self.rev_block_map.contains_key(&b) {
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.steven_id(), i);
self.rev_block_map.insert(b, i);
found = true;
break;
}
@ -464,12 +463,12 @@ impl Section {
let new_blocks = self.blocks.resize(new_size);
self.blocks = new_blocks;
}
self.rev_block_map.insert(b.steven_id(), self.block_map.len());
self.rev_block_map.insert(b, self.block_map.len());
self.block_map.push((b, 0));
}
}
let idx = self.rev_block_map[&b.steven_id()];
let idx = self.rev_block_map[&b];
let info = &mut self.block_map[idx];
info.1 += 1;
self.blocks.set(((y << 8) | (z << 4) | x) as usize, idx);