stevenarella/src/world/block/mod.rs

290 lines
8.4 KiB
Rust
Raw Normal View History

2016-03-23 17:07:49 -04:00
use std::fmt::{Display, Formatter, Error};
2016-03-23 17:07:49 -04:00
pub use self::Block::*;
2016-03-23 17:07:49 -04:00
macro_rules! consume_token { ($i:tt) => (0) }
2016-03-23 17:07:49 -04:00
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 {
(
$(
2016-03-23 17:07:49 -04:00
$name:ident {
props {
$(
$fname:ident : $ftype:ty = [$($val:expr),+],
)*
},
data $datafunc:expr,
material $mat:expr,
2016-03-24 11:39:57 -04:00
model $model:expr,
variant $variant:expr,
2016-03-23 17:07:49 -04:00
}
)+
) => (
2016-03-23 17:07:49 -04:00
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Block {
$(
2016-03-23 17:07:49 -04:00
$name {
$(
2016-03-23 17:07:49 -04:00
$fname : $ftype,
)*
2016-03-23 17:07:49 -04:00
},
)+
}
2016-03-23 17:07:49 -04:00
mod internal_ids {
create_ids!(usize, $($name),+);
}
2016-03-23 17:07:49 -04:00
mod internal_sizes {
$(
2016-03-23 17:07:49 -04:00
#[allow(non_upper_case_globals)]
pub const $name : usize = $(($(1 + consume_token!($val) + )+ 0) * )* 1;
)+
}
2016-03-23 17:07:49 -04:00
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;
)+
}
2016-03-23 17:07:49 -04:00
impl Block {
#[allow(unused_variables, unused_mut, unused_assignments)]
pub fn get_steven_id(&self) -> usize {
match *self {
$(
2016-03-23 17:07:49 -04:00
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
},
)+
}
2016-03-23 17:07:49 -04:00
}
2016-03-23 17:07:49 -04:00
#[allow(unused_variables, unused_assignments)]
pub fn by_steven_id(id: usize) -> Block {
match id {
$(
2016-03-23 17:07:49 -04:00
mut data @ internal_offsets::$name ... internal_offset_max::$name=> {
data -= internal_offsets::$name;
$(
2016-03-23 17:07:49 -04:00
let vals = [$($val),+];
let $fname = vals[data % vals.len()];
data /= vals.len();
)*
Block::$name {
$(
2016-03-23 17:07:49 -04:00
$fname: $fname,
)*
}
2016-03-23 17:07:49 -04:00
},
)*
_ => Block::Missing {}
}
2016-03-23 17:07:49 -04:00
}
2016-03-23 17:07:49 -04:00
pub fn get_vanilla_id(&self) -> Option<usize> {
match *self {
$(
2016-03-23 17:07:49 -04:00
Block::$name {
$($fname,)*
} => {
($datafunc).map(|v| v + (internal_ids::$name << 4))
}
)+
}
}
2016-03-23 17:07:49 -04:00
pub fn by_vanilla_id(id: usize) -> Block {
VANILLA_ID_MAP.get(id).and_then(|v| *v).unwrap_or(Block::Missing{})
}
2016-03-23 17:07:49 -04:00
pub fn get_material(&self) -> Material {
match *self {
$(
Block::$name {
$($fname,)*
} => {
$mat
}
)+
}
}
2016-03-24 11:39:57 -04:00
pub fn get_model(&self) -> (String, String) {
match *self {
$(
Block::$name {
$($fname,)*
} => {
let parts = $model;
(String::from(parts.0), String::from(parts.1))
}
)+
}
}
pub fn get_model_variant(&self) -> String {
match *self {
$(
Block::$name {
$($fname,)*
} => {
String::from($variant)
}
)+
}
}
}
2016-03-23 17:07:49 -04:00
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
};
}
);
}
2016-03-23 17:07:49 -04:00
pub struct Material {
pub renderable: bool,
}
define_blocks! {
2016-03-23 17:07:49 -04:00
Air {
props {},
data { Some(0) },
material Material {
renderable: false,
},
2016-03-24 11:39:57 -04:00
model { ("minecraft", "air" ) },
variant "normal",
}
2016-03-23 17:07:49 -04:00
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,
},
2016-03-24 11:39:57 -04:00
model { ("minecraft", variant.as_string() ) },
variant "normal",
2016-03-23 17:07:49 -04:00
}
Grass {
props {
},
data { Some(0) },
material Material {
renderable: true,
},
2016-03-24 11:39:57 -04:00
model { ("minecraft", "grass" ) },
variant "normal",
2016-03-23 17:07:49 -04:00
}
Dirt {
props {
},
data { Some(0) },
material Material {
renderable: true,
},
2016-03-24 11:39:57 -04:00
model { ("minecraft", "dirt" ) },
variant "normal",
2016-03-23 17:07:49 -04:00
}
Missing {
props {},
data { None::<usize> },
material Material {
renderable: true,
},
2016-03-24 11:39:57 -04:00
model { ("steven", "missing_block" ) },
variant "normal",
}
}
2016-03-23 17:07:49 -04:00
#[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> {
2016-03-24 11:39:57 -04:00
write!(f, "{}", self.as_string())
}
}
impl StoneVariant {
fn as_string(&self) -> &'static str {
match *self {
2016-03-23 17:07:49 -04:00
StoneVariant::Normal => "stone",
StoneVariant::Granite => "granite",
StoneVariant::SmoothGranite => "smooth_granite",
StoneVariant::Diorite => "diorite",
StoneVariant::SmoothDiorite => "smooth_diorite",
StoneVariant::Andesite => "andesite",
StoneVariant::SmoothAndesite => "smooth_andesite",
2016-03-24 11:39:57 -04:00
}
}
2016-03-23 17:07:49 -04:00
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,
}
}
}