Rework block system
This commit is contained in:
parent
2969dfe799
commit
baeb6b94aa
|
@ -127,16 +127,16 @@ fn build_func(id: usize, textures: Arc<RwLock<render::TextureManager>>, work_rec
|
||||||
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 {
|
||||||
let block = snapshot.get_block(x, y, z);
|
let block = snapshot.get_block(x, y, z).get_material();
|
||||||
if !block.renderable() {
|
if !block.renderable {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for dir in Direction::all() {
|
for dir in Direction::all() {
|
||||||
|
|
||||||
let offset = dir.get_offset();
|
let offset = dir.get_offset();
|
||||||
let other = snapshot.get_block(x + offset.0, y + offset.1, z + offset.2);
|
let other = snapshot.get_block(x + offset.0, y + offset.1, z + offset.2).get_material();
|
||||||
if other.renderable() {
|
if other.renderable {
|
||||||
continue;
|
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;
|
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;
|
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();
|
||||||
|
@ -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) {
|
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) = 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)
|
(0, 0, 0)
|
||||||
} else {
|
} else {
|
||||||
face.get_offset()
|
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 lz = (z + oz + dz).round() as i32;
|
||||||
let mut bl = snapshot.get_block_light(lx, ly, lz);
|
let mut bl = snapshot.get_block_light(lx, ly, lz);
|
||||||
let mut sl = snapshot.get_sky_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){
|
|| (sl == 0 && bl == 0){
|
||||||
bl = s_block_light;
|
bl = s_block_light;
|
||||||
sl = s_sky_light;
|
sl = s_sky_light;
|
||||||
|
|
|
@ -35,6 +35,7 @@ extern crate collision;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
||||||
pub mod ecs;
|
pub mod ecs;
|
||||||
pub mod protocol;
|
pub mod protocol;
|
||||||
pub mod format;
|
pub mod format;
|
||||||
|
@ -135,7 +136,6 @@ impl Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
world::block::force_init();
|
|
||||||
let con = Arc::new(Mutex::new(console::Console::new()));
|
let con = Arc::new(Mutex::new(console::Console::new()));
|
||||||
{
|
{
|
||||||
let mut con = con.lock().unwrap();
|
let mut con = con.lock().unwrap();
|
||||||
|
|
|
@ -152,7 +152,7 @@ fn twos_compliment(data: &mut Vec<u8>) {
|
||||||
data[i] = !data[i];
|
data[i] = !data[i];
|
||||||
if carry {
|
if carry {
|
||||||
carry = data[i] == 0xFF;
|
carry = data[i] == 0xFF;
|
||||||
data[i] += 1;
|
data[i].wrapping_add(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
use protocol::{self, mojang, packet};
|
use protocol::{self, mojang, packet};
|
||||||
use world;
|
use world;
|
||||||
use world::block::{self, BlockSet};
|
use world::block;
|
||||||
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::sync::mpsc;
|
||||||
|
@ -168,7 +168,7 @@ impl Server {
|
||||||
for z in -7*16 .. 7*16 {
|
for z in -7*16 .. 7*16 {
|
||||||
let h = rng.gen_range(3, 10);
|
let h = rng.gen_range(3, 10);
|
||||||
for y in 0 .. h {
|
for y in 0 .. h {
|
||||||
world.set_block(x, y, z, block::MISSING.base());
|
world.set_block(x, y, z, block::Dirt{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,373 +1,264 @@
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::fmt::{Display, Formatter, Error};
|
||||||
use std::cell::UnsafeCell;
|
|
||||||
|
|
||||||
pub trait BlockSet {
|
pub use self::Block::*;
|
||||||
fn plugin(&self) -> &'static str {
|
|
||||||
"minecraft"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn name(&self) -> &'static str;
|
macro_rules! consume_token { ($i:tt) => (0) }
|
||||||
fn blocks(&'static self) -> Vec<&'static Block>;
|
|
||||||
|
|
||||||
fn base(&'static self) -> &'static Block {
|
macro_rules! offsets {
|
||||||
self.blocks()[0]
|
($first:ident, $($other:ident),*) => (
|
||||||
}
|
#[allow(non_upper_case_globals)]
|
||||||
}
|
pub const $first: usize = 0;
|
||||||
|
offsets!(prev($first), $($other),*);
|
||||||
pub trait Block: Sync + ::std::fmt::Debug {
|
);
|
||||||
fn steven_id(&'static self) -> usize;
|
(prev($prev:ident), $first:ident, $($other:ident),*) => (
|
||||||
fn vanilla_id(&'static self) -> Option<usize>;
|
#[allow(non_upper_case_globals)]
|
||||||
fn set_steven_id(&'static self, id: usize);
|
pub const $first: usize = $prev + internal_sizes::$prev;
|
||||||
fn set_vanilla_id(&'static self, id: usize);
|
offsets!(prev($first), $($other),*);
|
||||||
fn plugin(&self) -> &'static str;
|
);
|
||||||
fn name(&self) -> &'static str;
|
(prev($prev:ident), $first:ident) => (
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
fn equals(&'static self, other: &'static Block) -> bool {
|
pub const $first: usize = $prev + internal_sizes::$prev;
|
||||||
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 {
|
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;
|
$name {
|
||||||
)*
|
$(
|
||||||
static ref MANAGER: BlockManager = {
|
$fname : $ftype,
|
||||||
let mut manager = BlockManager {
|
)*
|
||||||
vanilla_id: vec![None; 0xFFFF],
|
},
|
||||||
steven_id: vec![],
|
)+
|
||||||
next_id: 0,
|
}
|
||||||
};
|
mod internal_ids {
|
||||||
$(
|
create_ids!(usize, $($name),+);
|
||||||
manager.register_set(&*$internal_name);
|
}
|
||||||
)*
|
mod internal_sizes {
|
||||||
manager
|
$(
|
||||||
|
#[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]
|
pub struct Material {
|
||||||
fn temp_test() {
|
pub renderable: bool,
|
||||||
force_init();
|
// TEMP
|
||||||
|
pub texture: &'static str,
|
||||||
println!("{:?}", STONE.blocks());
|
|
||||||
unimplemented!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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! {
|
define_blocks! {
|
||||||
AIR InvisibleBlockSet = InvisibleBlockSet::new("air");
|
Air {
|
||||||
STONE stone::StoneBlockSet = stone::StoneBlockSet::new("stone");
|
props {},
|
||||||
GRASS simple::SimpleBlockSet = simple::SimpleBlockSet::new("grass");
|
data { Some(0) },
|
||||||
DIRT simple::SimpleBlockSet = simple::SimpleBlockSet::new("dirt");
|
material Material {
|
||||||
MISSING simple::SimpleBlockSet = simple::SimpleBlockSet::new("missing");
|
renderable: false,
|
||||||
}
|
texture: "none",
|
||||||
|
},
|
||||||
/// 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 {
|
|
||||||
}
|
}
|
||||||
);
|
Stone {
|
||||||
|
props {
|
||||||
impl InvisibleBlockSet {
|
variant: StoneVariant = [
|
||||||
fn new(name: &'static str) -> InvisibleBlockSet {
|
StoneVariant::Normal,
|
||||||
let mut set = InvisibleBlockSet {
|
StoneVariant::Granite, StoneVariant::SmoothGranite,
|
||||||
name: name,
|
StoneVariant::Diorite, StoneVariant::SmoothDiorite,
|
||||||
sub_blocks: vec![],
|
StoneVariant::Andesite, StoneVariant::SmoothAndesite
|
||||||
};
|
],
|
||||||
set.gen_combos();
|
},
|
||||||
set
|
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> {
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
self.sub_blocks.iter().map(|v| v as &Block).collect()
|
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 {
|
impl StoneVariant {
|
||||||
block_impl!();
|
fn data(&self) -> usize {
|
||||||
fn renderable(&'static self) -> bool {
|
match *self {
|
||||||
false
|
StoneVariant::Normal => 0,
|
||||||
|
StoneVariant::Granite => 1,
|
||||||
|
StoneVariant::SmoothGranite => 2,
|
||||||
|
StoneVariant::Diorite => 3,
|
||||||
|
StoneVariant::SmoothDiorite => 4,
|
||||||
|
StoneVariant::Andesite => 5,
|
||||||
|
StoneVariant::SmoothAndesite => 6,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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!();
|
|
||||||
}
|
|
|
@ -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!();
|
|
||||||
}
|
|
|
@ -13,7 +13,6 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
pub mod block;
|
pub mod block;
|
||||||
use self::block::BlockSet;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -37,7 +36,7 @@ impl World {
|
||||||
self.chunks.contains_key(&CPos(x, z))
|
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);
|
let cpos = CPos(x >> 4, z >> 4);
|
||||||
if !self.chunks.contains_key(&cpos) {
|
if !self.chunks.contains_key(&cpos) {
|
||||||
self.chunks.insert(cpos, Chunk::new(cpos));
|
self.chunks.insert(cpos, Chunk::new(cpos));
|
||||||
|
@ -46,10 +45,10 @@ impl World {
|
||||||
chunk.set_block(x & 0xF, y, z & 0xF, b);
|
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)) {
|
match self.chunks.get(&CPos(x >> 4, z >> 4)) {
|
||||||
Some(ref chunk) => chunk.get_block(x & 0xF, y, z & 0xF),
|
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 {
|
for i in 0 .. (w * h * d) as usize {
|
||||||
snapshot.sky_light.set(i, 0xF);
|
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;
|
let cx1 = x >> 4;
|
||||||
|
@ -150,7 +149,7 @@ impl World {
|
||||||
snapshot.set_sky_light(ox, oy, oz, sec.get_sky_light(xx, yy, zz));
|
snapshot.set_sky_light(ox, oy, oz, sec.get_sky_light(xx, yy, zz));
|
||||||
},
|
},
|
||||||
None => {
|
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 {
|
for i in 0 .. 4096 {
|
||||||
let val = m.get(i);
|
let val = m.get(i);
|
||||||
let block_id = block_map.get(&val).map(|v| *v as usize).unwrap_or(val);
|
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;
|
let i = i as i32;
|
||||||
section.set_block(
|
section.set_block(
|
||||||
i & 0xF,
|
i & 0xF,
|
||||||
|
@ -276,13 +275,13 @@ impl Snapshot {
|
||||||
self.z = z;
|
self.z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
block::get_block_by_steven_id(self.blocks[self.index(x, y, z)] as usize)
|
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);
|
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 {
|
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;
|
let s_idx = y >> 4;
|
||||||
if s_idx < 0 || s_idx > 15 {
|
if s_idx < 0 || s_idx > 15 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.sections[s_idx as usize].is_none() {
|
if self.sections[s_idx as usize].is_none() {
|
||||||
if b.in_set(&*block::AIR) {
|
if let block::Air {} = b {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.sections[s_idx as usize] = Some(Section::new(self.position.0, s_idx as u8, self.position.1));
|
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);
|
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;
|
let s_idx = y >> 4;
|
||||||
if s_idx < 0 || s_idx > 15 {
|
if s_idx < 0 || s_idx > 15 {
|
||||||
return block::MISSING.base();
|
return block::Missing{};
|
||||||
}
|
}
|
||||||
match self.sections[s_idx as usize].as_ref() {
|
match self.sections[s_idx as usize].as_ref() {
|
||||||
Some(sec) => sec.get_block(x, y & 0xF, z),
|
Some(sec) => sec.get_block(x, y & 0xF, z),
|
||||||
None => block::AIR.base(),
|
None => block::Air{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -391,8 +390,8 @@ struct Section {
|
||||||
y: u8,
|
y: u8,
|
||||||
|
|
||||||
blocks: bit::Map,
|
blocks: bit::Map,
|
||||||
block_map: Vec<(&'static block::Block, u32)>,
|
block_map: Vec<(block::Block, u32)>,
|
||||||
rev_block_map: HashMap<usize, usize, BuildHasherDefault<FNVHash>>,
|
rev_block_map: HashMap<block::Block, usize, BuildHasherDefault<FNVHash>>,
|
||||||
|
|
||||||
block_light: nibble::Array,
|
block_light: nibble::Array,
|
||||||
sky_light: nibble::Array,
|
sky_light: nibble::Array,
|
||||||
|
@ -411,7 +410,7 @@ impl Section {
|
||||||
|
|
||||||
blocks: bit::Map::new(4096, 4),
|
blocks: bit::Map::new(4096, 4),
|
||||||
block_map: vec![
|
block_map: vec![
|
||||||
(block::AIR.base(), 0xFFFFFFFF)
|
(block::Air{}, 0xFFFFFFFF)
|
||||||
],
|
],
|
||||||
rev_block_map: HashMap::with_hasher(BuildHasherDefault::default()),
|
rev_block_map: HashMap::with_hasher(BuildHasherDefault::default()),
|
||||||
|
|
||||||
|
@ -424,36 +423,36 @@ impl Section {
|
||||||
for i in 0 .. 16*16*16 {
|
for i in 0 .. 16*16*16 {
|
||||||
section.sky_light.set(i, 0xF);
|
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
|
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);
|
let idx = self.blocks.get(((y << 8) | (z << 4) | x) as usize);
|
||||||
self.block_map[idx].0
|
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);
|
let old = self.get_block(x, y, z);
|
||||||
if old.equals(b) {
|
if old == b {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Clean up old block
|
// 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];
|
let info = &mut self.block_map[idx];
|
||||||
info.1 -= 1;
|
info.1 -= 1;
|
||||||
if info.1 == 0 { // None left of this type
|
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;
|
let mut found = false;
|
||||||
for (i, ref mut info) in self.block_map.iter_mut().enumerate() {
|
for (i, ref mut info) in self.block_map.iter_mut().enumerate() {
|
||||||
if info.1 == 0 {
|
if info.1 == 0 {
|
||||||
info.0 = b;
|
info.0 = b;
|
||||||
self.rev_block_map.insert(b.steven_id(), i);
|
self.rev_block_map.insert(b, i);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -464,12 +463,12 @@ impl Section {
|
||||||
let new_blocks = self.blocks.resize(new_size);
|
let new_blocks = self.blocks.resize(new_size);
|
||||||
self.blocks = new_blocks;
|
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));
|
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];
|
let info = &mut self.block_map[idx];
|
||||||
info.1 += 1;
|
info.1 += 1;
|
||||||
self.blocks.set(((y << 8) | (z << 4) | x) as usize, idx);
|
self.blocks.set(((y << 8) | (z << 4) | x) as usize, idx);
|
||||||
|
|
Loading…
Reference in New Issue