Multipart model support
This commit is contained in:
parent
35d9a2aefa
commit
480b7afd3b
|
@ -159,17 +159,13 @@ fn build_func(id: usize, models: Arc<RwLock<model::Factory>>, work_recv: mpsc::R
|
|||
_ => {},
|
||||
}
|
||||
|
||||
let model_name = block.get_model();
|
||||
let variant = block.get_model_variant();
|
||||
if !mat.transparent {
|
||||
solid_count += model::Factory::get_state_model(
|
||||
&models, &model_name.0, &model_name.1, &variant, &mut rng,
|
||||
&snapshot, x, y, z, &mut solid_buffer
|
||||
&models, block, &mut rng, &snapshot, x, y, z, &mut solid_buffer
|
||||
);
|
||||
} else {
|
||||
trans_count += model::Factory::get_state_model(
|
||||
&models, &model_name.0, &model_name.1, &variant, &mut rng,
|
||||
&snapshot, x, y, z, &mut trans_buffer
|
||||
&models, block, &mut rng, &snapshot, x, y, z, &mut trans_buffer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
161
src/model/mod.rs
161
src/model/mod.rs
|
@ -3,12 +3,13 @@ pub mod liquid;
|
|||
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::collections::HashMap;
|
||||
use std::cell::RefCell;
|
||||
use std::io::Write;
|
||||
use byteorder::{WriteBytesExt, NativeEndian};
|
||||
use resources;
|
||||
use render;
|
||||
use world;
|
||||
use world::block::TintType;
|
||||
use world::block::{Block, TintType};
|
||||
use types::Direction;
|
||||
use serde_json;
|
||||
|
||||
|
@ -52,6 +53,10 @@ macro_rules! try_log {
|
|||
);
|
||||
}
|
||||
|
||||
thread_local!(
|
||||
static MULTIPART_CACHE: RefCell<HashMap<(Key, Block), Model, BuildHasherDefault<FNVHash>>> = RefCell::new(HashMap::with_hasher(BuildHasherDefault::default()))
|
||||
);
|
||||
|
||||
impl Factory {
|
||||
pub fn new(resources: Arc<RwLock<resources::Manager>>, textures: Arc<RwLock<render::TextureManager>>) -> Factory {
|
||||
Factory {
|
||||
|
@ -80,35 +85,97 @@ impl Factory {
|
|||
self.foliage_colors = Factory::load_biome_colors(self.resources.clone(), "foliage");
|
||||
}
|
||||
|
||||
pub fn get_state_model<R: Rng, W: Write>(models: &Arc<RwLock<Factory>>, plugin: &str, name: &str, variant: &str, rng: &mut R,
|
||||
fn get_model<R: Rng, W: Write>(&self, key: Key, block: Block, rng: &mut R, snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> Result<usize, bool> {
|
||||
use std::collections::hash_map::Entry;
|
||||
if let Some(model) = self.models.get(&key) {
|
||||
if model.multipart.is_empty() {
|
||||
let variant = block.get_model_variant();
|
||||
if let Some(var) = model.get_variants(&variant) {
|
||||
let model = var.choose_model(rng);
|
||||
return Ok(model.render(self, snapshot, x, y, z, buf));
|
||||
}
|
||||
} else {
|
||||
return MULTIPART_CACHE.with(|cache| {
|
||||
let mut cache = cache.borrow_mut();
|
||||
let entry = cache.entry((key.clone(), block));
|
||||
match entry {
|
||||
Entry::Occupied(e) => {
|
||||
return Ok(e.get().render(self, snapshot, x, y, z, buf));
|
||||
},
|
||||
Entry::Vacant(e) => {
|
||||
let mut res: Option<Model> = None;
|
||||
for rule in &model.multipart {
|
||||
let ok = Self::eval_rules(block, &rule.rules);
|
||||
if ok {
|
||||
if res.is_some() {
|
||||
res.as_mut().unwrap().join(&rule.apply.choose_model(rng));
|
||||
} else {
|
||||
res = Some(rule.apply.choose_model(rng).clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(mdl) = res {
|
||||
return Ok(e.insert(mdl).render(self, snapshot, x, y, z, buf));
|
||||
}
|
||||
},
|
||||
};
|
||||
return Err(true);
|
||||
});
|
||||
}
|
||||
return Err(true);
|
||||
}
|
||||
Err(false)
|
||||
}
|
||||
|
||||
fn eval_rules(block: Block, rules: &[Rule]) -> bool {
|
||||
for mrule in rules {
|
||||
match *mrule {
|
||||
Rule::Or(ref sub_rules) => {
|
||||
let mut ok = false;
|
||||
for srule in sub_rules {
|
||||
if Self::eval_rules(block, srule) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
Rule::Match(ref key, ref val) => {
|
||||
if !block.match_multipart(&key, &val) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn get_state_model<R: Rng, W: Write>(models: &Arc<RwLock<Factory>>, block: Block, rng: &mut R,
|
||||
snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> usize {
|
||||
let (plugin, name) = block.get_model();
|
||||
let key = Key(plugin.to_owned(), name.to_owned());
|
||||
let mut missing_variant = false;
|
||||
let mut missing_variant;
|
||||
{
|
||||
let m = models.read().unwrap();
|
||||
if let Some(model) = m.models.get(&key) {
|
||||
if let Some(var) = model.get_variants(variant) {
|
||||
let model = var.choose_model(rng);
|
||||
return model.render(&*m, snapshot, x, y, z, buf);
|
||||
}
|
||||
missing_variant = true;
|
||||
}
|
||||
match m.get_model(key.clone(), block, rng, snapshot, x, y, z, buf) {
|
||||
Ok(val) => return val,
|
||||
Err(val) => missing_variant = val,
|
||||
};
|
||||
}
|
||||
if !missing_variant {
|
||||
// Whole model not loaded, try and load
|
||||
let mut m = models.write().unwrap();
|
||||
if !m.models.contains_key(&key) && !m.load_model(plugin, name) {
|
||||
if !m.models.contains_key(&key) && !m.load_model(&plugin, &name) {
|
||||
error!("Error loading model {}:{}", plugin, name);
|
||||
}
|
||||
if let Some(model) = m.models.get(&key) {
|
||||
if let Some(var) = model.get_variants(variant) {
|
||||
let model = var.choose_model(rng);
|
||||
return model.render(&*m, snapshot, x, y, z, buf);
|
||||
}
|
||||
missing_variant = true;
|
||||
}
|
||||
match m.get_model(key.clone(), block, rng, snapshot, x, y, z, buf) {
|
||||
Ok(val) => return val,
|
||||
Err(val) => missing_variant = val,
|
||||
};
|
||||
}
|
||||
let ret = Factory::get_state_model(models, "steven", "missing_block", "normal", rng, snapshot, x, y, z, buf);
|
||||
let ret = Factory::get_state_model(models, Block::Missing{}, rng, snapshot, x, y, z, buf);
|
||||
if !missing_variant {
|
||||
// Still no model, replace with placeholder
|
||||
let mut m = models.write().unwrap();
|
||||
|
@ -130,6 +197,7 @@ impl Factory {
|
|||
|
||||
let mut model = StateModel {
|
||||
variants: HashMap::with_hasher(BuildHasherDefault::default()),
|
||||
multipart: vec![],
|
||||
};
|
||||
|
||||
if let Some(variants) = mdl.find("variants").and_then(|v| v.as_object()) {
|
||||
|
@ -141,14 +209,48 @@ impl Factory {
|
|||
model.variants.insert(k.clone(), vars);
|
||||
}
|
||||
}
|
||||
if let Some(_multipart) = mdl.find("multipart").and_then(|v| v.as_array()) {
|
||||
warn!("Found unhandled multipart for {}:{}", plugin, name);
|
||||
if let Some(multipart) = mdl.find("multipart").and_then(|v| v.as_array()) {
|
||||
for rule in multipart {
|
||||
let apply = self.parse_model_list(plugin, rule.find("apply").unwrap());
|
||||
let mut rules = vec![];
|
||||
if let Some(when) = rule.find("when").and_then(|v| v.as_object()) {
|
||||
Self::parse_rules(when, &mut rules);
|
||||
}
|
||||
model.multipart.push(MultipartRule {
|
||||
apply: apply,
|
||||
rules: rules,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
self.models.insert(Key(plugin.to_owned(), name.to_owned()), model);
|
||||
true
|
||||
}
|
||||
|
||||
fn parse_rules(when: &::std::collections::BTreeMap<String, serde_json::Value>, rules: &mut Vec<Rule>) {
|
||||
for (name, val) in when {
|
||||
if name == "OR" {
|
||||
let mut or_rules = vec![];
|
||||
for sub in val.as_array().unwrap() {
|
||||
let mut sub_rules = vec![];
|
||||
Self::parse_rules(sub.as_object().unwrap(), &mut sub_rules);
|
||||
or_rules.push(sub_rules);
|
||||
}
|
||||
rules.push(Rule::Or(or_rules));
|
||||
} else {
|
||||
let v = match *val {
|
||||
serde_json::Value::Bool(v) => v.to_string(),
|
||||
serde_json::Value::I64(v) => v.to_string(),
|
||||
serde_json::Value::U64(v) => v.to_string(),
|
||||
serde_json::Value::F64(v) => v.to_string(),
|
||||
serde_json::Value::String(ref v) => v.to_owned(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
rules.push(Rule::Match(name.to_owned(), v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_model_list(&self, plugin: &str, v: &serde_json::Value) -> Variants {
|
||||
let mut variants = Variants {
|
||||
models: vec![]
|
||||
|
@ -638,6 +740,7 @@ fn rotate_direction(val: Direction, offset: i32, rots: &[Direction], invalid: &[
|
|||
#[derive(Clone)]
|
||||
pub struct StateModel {
|
||||
variants: HashMap<String, Variants, BuildHasherDefault<FNVHash>>,
|
||||
multipart: Vec<MultipartRule>,
|
||||
}
|
||||
|
||||
impl StateModel {
|
||||
|
@ -646,6 +749,18 @@ impl StateModel {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct MultipartRule {
|
||||
apply: Variants,
|
||||
rules: Vec<Rule>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Rule {
|
||||
Match(String, String),
|
||||
Or(Vec<Vec<Rule>>),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Variants {
|
||||
models: Vec<Model>,
|
||||
|
@ -745,6 +860,10 @@ struct Face {
|
|||
}
|
||||
|
||||
impl Model {
|
||||
fn join(&mut self, other: &Model) {
|
||||
self.faces.extend_from_slice(&other.faces);
|
||||
}
|
||||
|
||||
fn render<W: Write>(&self, factory: &Factory, snapshot: &world::Snapshot, x: i32, y: i32, z: i32, buf: &mut W) -> usize {
|
||||
let this = snapshot.get_block(x, y, z);
|
||||
let this_mat = this.get_material();
|
||||
|
|
|
@ -51,6 +51,7 @@ macro_rules! define_blocks {
|
|||
$(tint $tint:expr,)*
|
||||
$(collision $collision:expr,)*
|
||||
$(update_state ($world:ident, $x:ident, $y:ident, $z:ident) => $update_state:expr,)*
|
||||
$(multipart ($mkey:ident, $mval:ident) => $multipart:expr,)*
|
||||
}
|
||||
)+
|
||||
) => (
|
||||
|
@ -242,6 +243,24 @@ macro_rules! define_blocks {
|
|||
)+
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables, unreachable_code)]
|
||||
pub fn match_multipart(&self, key: &str, val: &str) -> bool{
|
||||
match *self {
|
||||
$(
|
||||
Block::$name {
|
||||
$($fname,)*
|
||||
} => {
|
||||
$(
|
||||
let $mkey = key;
|
||||
let $mval = val;
|
||||
return $multipart;
|
||||
)*
|
||||
false
|
||||
}
|
||||
)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
|
@ -343,7 +362,7 @@ define_blocks! {
|
|||
snowy: match world.get_block(x, y + 1, z) {
|
||||
Block::Snow { .. } | Block::SnowLayer { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -366,7 +385,7 @@ define_blocks! {
|
|||
},
|
||||
model { ("minecraft", variant.as_string()) },
|
||||
variant {
|
||||
if variant == DirtVariant::Podzol {
|
||||
if variant == DirtVariant::Podzol {
|
||||
format!("snowy={}", snowy)
|
||||
} else {
|
||||
"normal".to_owned()
|
||||
|
@ -377,7 +396,7 @@ define_blocks! {
|
|||
snowy: match world.get_block(x, y + 1, z) {
|
||||
Block::Snow{ .. } | Block::SnowLayer { .. } => true,
|
||||
_ => false,
|
||||
},
|
||||
},
|
||||
variant: variant
|
||||
}
|
||||
} else {
|
||||
|
@ -939,7 +958,7 @@ define_blocks! {
|
|||
Direction::East => 0x5,
|
||||
_ => unreachable!(),
|
||||
} | if variant == PistonType::Sticky { 0x8 } else { 0x0 }
|
||||
)} else {
|
||||
)} else {
|
||||
None
|
||||
},
|
||||
material Material {
|
||||
|
@ -1928,6 +1947,19 @@ define_blocks! {
|
|||
transparent: false,
|
||||
},
|
||||
model { ("minecraft", "fence") },
|
||||
update_state (world, x, y, z) => Block::Fence {
|
||||
north: can_connect(world, x, y, z, Direction::North),
|
||||
south: can_connect(world, x, y, z, Direction::South),
|
||||
east: can_connect(world, x, y, z, Direction::East),
|
||||
west: can_connect(world, x, y, z, Direction::West),
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"north" => north == (val == "true"),
|
||||
"south" => south == (val == "true"),
|
||||
"east" => east == (val == "true"),
|
||||
"west" => west == (val == "true"),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
Pumpkin {
|
||||
props {
|
||||
|
@ -2008,7 +2040,7 @@ define_blocks! {
|
|||
model { ("minecraft", "portal") },
|
||||
variant format!("axis={}", axis.as_string()),
|
||||
update_state (world, x, y, z) => {
|
||||
let axis = match (world.get_block(x - 1, y, z), world.get_block(x + 1, y, z),
|
||||
let axis = match (world.get_block(x - 1, y, z), world.get_block(x + 1, y, z),
|
||||
world.get_block(x, y, z - 1), world.get_block(x, y, z + 1)) {
|
||||
(Block::Portal{ .. }, _, _, _) | (_, Block::Portal{ .. }, _, _) => Axis::X,
|
||||
(_, _, Block::Portal{ .. }, _) | (_, _, _, Block::Portal{ .. }) => Axis::Z,
|
||||
|
@ -2311,9 +2343,28 @@ define_blocks! {
|
|||
transparent: false,
|
||||
},
|
||||
model { ("minecraft", "iron_bars") },
|
||||
update_state (world, x, y, z) => Block::IronBars {
|
||||
north: can_connect(world, x, y, z, Direction::North),
|
||||
south: can_connect(world, x, y, z, Direction::South),
|
||||
east: can_connect(world, x, y, z, Direction::East),
|
||||
west: can_connect(world, x, y, z, Direction::West),
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"north" => north == (val == "true"),
|
||||
"south" => south == (val == "true"),
|
||||
"east" => east == (val == "true"),
|
||||
"west" => west == (val == "true"),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
GlassPane {
|
||||
props {},
|
||||
props {
|
||||
north: bool = [false, true],
|
||||
south: bool = [false, true],
|
||||
east: bool = [false, true],
|
||||
west: bool = [false, true],
|
||||
},
|
||||
data if !north && !south && !east && !west { Some(0) } else { None },
|
||||
material Material {
|
||||
renderable: true,
|
||||
never_cull: false,
|
||||
|
@ -2322,6 +2373,19 @@ define_blocks! {
|
|||
transparent: false,
|
||||
},
|
||||
model { ("minecraft", "glass_pane") },
|
||||
update_state (world, x, y, z) => Block::GlassPane {
|
||||
north: can_connect(world, x, y, z, Direction::North),
|
||||
south: can_connect(world, x, y, z, Direction::South),
|
||||
east: can_connect(world, x, y, z, Direction::East),
|
||||
west: can_connect(world, x, y, z, Direction::West),
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"north" => north == (val == "true"),
|
||||
"south" => south == (val == "true"),
|
||||
"east" => east == (val == "true"),
|
||||
"west" => west == (val == "true"),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
MelonBlock {
|
||||
props {},
|
||||
|
@ -2363,8 +2427,8 @@ define_blocks! {
|
|||
},
|
||||
tint TintType::Foliage,
|
||||
update_state (world, x, y, z) => {
|
||||
let facing = match (world.get_block(x - 1, y, z), world.get_block(x + 1, y, z),
|
||||
world.get_block(x, y, z - 1), world.get_block(x, y, z + 1)) {
|
||||
let facing = match (world.get_block(x - 1, y, z), world.get_block(x + 1, y, z),
|
||||
world.get_block(x, y, z - 1), world.get_block(x, y, z + 1)) {
|
||||
(Block::Pumpkin{ .. }, _, _, _) => Direction::East,
|
||||
(_, Block::Pumpkin{ .. }, _, _) => Direction::West,
|
||||
(_, _, Block::Pumpkin{ .. }, _) => Direction::North,
|
||||
|
@ -2404,8 +2468,8 @@ define_blocks! {
|
|||
},
|
||||
tint TintType::Foliage,
|
||||
update_state (world, x, y, z) => {
|
||||
let facing = match (world.get_block(x - 1, y, z), world.get_block(x + 1, y, z),
|
||||
world.get_block(x, y, z - 1), world.get_block(x, y, z + 1)) {
|
||||
let facing = match (world.get_block(x - 1, y, z), world.get_block(x + 1, y, z),
|
||||
world.get_block(x, y, z - 1), world.get_block(x, y, z + 1)) {
|
||||
(Block::MelonBlock{ .. }, _, _, _) => Direction::East,
|
||||
(_, Block::MelonBlock{ .. }, _, _) => Direction::West,
|
||||
(_, _, Block::MelonBlock{ .. }, _) => Direction::North,
|
||||
|
@ -2574,6 +2638,19 @@ define_blocks! {
|
|||
transparent: false,
|
||||
},
|
||||
model { ("minecraft", "nether_brick_fence") },
|
||||
update_state (world, x, y, z) => Block::NetherBrickFence {
|
||||
north: can_connect(world, x, y, z, Direction::North),
|
||||
south: can_connect(world, x, y, z, Direction::South),
|
||||
east: can_connect(world, x, y, z, Direction::East),
|
||||
west: can_connect(world, x, y, z, Direction::West),
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"north" => north == (val == "true"),
|
||||
"south" => south == (val == "true"),
|
||||
"east" => east == (val == "true"),
|
||||
"west" => west == (val == "true"),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
NetherBrickStairs {
|
||||
props {
|
||||
|
@ -3636,8 +3713,12 @@ define_blocks! {
|
|||
ColoredVariant::Red,
|
||||
ColoredVariant::Black
|
||||
],
|
||||
north: bool = [false, true],
|
||||
south: bool = [false, true],
|
||||
east: bool = [false, true],
|
||||
west: bool = [false, true],
|
||||
},
|
||||
data Some(color.data()),
|
||||
data if !north && !south && !east && !west { Some(color.data()) } else { None },
|
||||
material Material {
|
||||
renderable: true,
|
||||
never_cull: false,
|
||||
|
@ -3646,6 +3727,20 @@ define_blocks! {
|
|||
transparent: true,
|
||||
},
|
||||
model { ("minecraft", format!("{}_stained_glass_pane", color.as_string()) ) },
|
||||
update_state (world, x, y, z) => Block::StainedGlassPane {
|
||||
color: color,
|
||||
north: can_connect(world, x, y, z, Direction::North),
|
||||
south: can_connect(world, x, y, z, Direction::South),
|
||||
east: can_connect(world, x, y, z, Direction::East),
|
||||
west: can_connect(world, x, y, z, Direction::West),
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"north" => north == (val == "true"),
|
||||
"south" => south == (val == "true"),
|
||||
"east" => east == (val == "true"),
|
||||
"west" => west == (val == "true"),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
Leaves2 {
|
||||
props {
|
||||
|
@ -4221,6 +4316,19 @@ define_blocks! {
|
|||
transparent: false,
|
||||
},
|
||||
model { ("minecraft", "spruce_fence") },
|
||||
update_state (world, x, y, z) => Block::SpruceFence {
|
||||
north: can_connect(world, x, y, z, Direction::North),
|
||||
south: can_connect(world, x, y, z, Direction::South),
|
||||
east: can_connect(world, x, y, z, Direction::East),
|
||||
west: can_connect(world, x, y, z, Direction::West),
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"north" => north == (val == "true"),
|
||||
"south" => south == (val == "true"),
|
||||
"east" => east == (val == "true"),
|
||||
"west" => west == (val == "true"),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
BirchFence {
|
||||
props {
|
||||
|
@ -4238,6 +4346,19 @@ define_blocks! {
|
|||
transparent: false,
|
||||
},
|
||||
model { ("minecraft", "birch_fence") },
|
||||
update_state (world, x, y, z) => Block::BirchFence {
|
||||
north: can_connect(world, x, y, z, Direction::North),
|
||||
south: can_connect(world, x, y, z, Direction::South),
|
||||
east: can_connect(world, x, y, z, Direction::East),
|
||||
west: can_connect(world, x, y, z, Direction::West),
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"north" => north == (val == "true"),
|
||||
"south" => south == (val == "true"),
|
||||
"east" => east == (val == "true"),
|
||||
"west" => west == (val == "true"),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
JungleFence {
|
||||
props {
|
||||
|
@ -4255,6 +4376,19 @@ define_blocks! {
|
|||
transparent: false,
|
||||
},
|
||||
model { ("minecraft", "jungle_fence") },
|
||||
update_state (world, x, y, z) => Block::JungleFence {
|
||||
north: can_connect(world, x, y, z, Direction::North),
|
||||
south: can_connect(world, x, y, z, Direction::South),
|
||||
east: can_connect(world, x, y, z, Direction::East),
|
||||
west: can_connect(world, x, y, z, Direction::West),
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"north" => north == (val == "true"),
|
||||
"south" => south == (val == "true"),
|
||||
"east" => east == (val == "true"),
|
||||
"west" => west == (val == "true"),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
DarkOakFence {
|
||||
props {
|
||||
|
@ -4272,6 +4406,19 @@ define_blocks! {
|
|||
transparent: false,
|
||||
},
|
||||
model { ("minecraft", "dark_oak_fence") },
|
||||
update_state (world, x, y, z) => Block::DarkOakFence {
|
||||
north: can_connect(world, x, y, z, Direction::North),
|
||||
south: can_connect(world, x, y, z, Direction::South),
|
||||
east: can_connect(world, x, y, z, Direction::East),
|
||||
west: can_connect(world, x, y, z, Direction::West),
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"north" => north == (val == "true"),
|
||||
"south" => south == (val == "true"),
|
||||
"east" => east == (val == "true"),
|
||||
"west" => west == (val == "true"),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
AcaciaFence {
|
||||
props {
|
||||
|
@ -4289,6 +4436,19 @@ define_blocks! {
|
|||
transparent: false,
|
||||
},
|
||||
model { ("minecraft", "acacia_fence") },
|
||||
update_state (world, x, y, z) => Block::AcaciaFence {
|
||||
north: can_connect(world, x, y, z, Direction::North),
|
||||
south: can_connect(world, x, y, z, Direction::South),
|
||||
east: can_connect(world, x, y, z, Direction::East),
|
||||
west: can_connect(world, x, y, z, Direction::West),
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"north" => north == (val == "true"),
|
||||
"south" => south == (val == "true"),
|
||||
"east" => east == (val == "true"),
|
||||
"west" => west == (val == "true"),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
SpruceDoor {
|
||||
props {
|
||||
|
@ -4480,6 +4640,23 @@ define_blocks! {
|
|||
transparent: false,
|
||||
},
|
||||
model { ("minecraft", "chorus_plant") },
|
||||
update_state (world, x, y, z) => Block::ChorusPlant {
|
||||
north: match world.get_block(x, y, z - 1) { Block::ChorusPlant{..} | Block::ChorusFlower{..} => true, _ => false,},
|
||||
south: match world.get_block(x, y, z + 1) { Block::ChorusPlant{..} | Block::ChorusFlower{..} => true, _ => false,},
|
||||
west: match world.get_block(x - 1, y, z) { Block::ChorusPlant{..} | Block::ChorusFlower{..} => true, _ => false,},
|
||||
east: match world.get_block(x + 1, y, z) { Block::ChorusPlant{..} | Block::ChorusFlower{..} => true, _ => false,},
|
||||
up: match world.get_block(x, y + 1, z) { Block::ChorusPlant{..} | Block::ChorusFlower{..} => true, _ => false,},
|
||||
down: match world.get_block(x, y - 1, z) { Block::ChorusPlant{..} | Block::ChorusFlower{..} | Block::EndStone{..} => true, _ => false,},
|
||||
},
|
||||
multipart (key, val) => match key {
|
||||
"north" => north == (val == "true"),
|
||||
"south" => south == (val == "true"),
|
||||
"east" => east == (val == "true"),
|
||||
"west" => west == (val == "true"),
|
||||
"up" => up == (val == "true"),
|
||||
"down" => down == (val == "true"),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
ChorusFlower {
|
||||
props {
|
||||
|
@ -4703,6 +4880,11 @@ define_blocks! {
|
|||
}
|
||||
}
|
||||
|
||||
fn can_connect(world: &super::World, x: i32, y: i32, z: i32, dir: Direction) -> bool {
|
||||
let (ox, oy, oz) = dir.get_offset();
|
||||
world.get_block(x + ox, y + oy, z + oz).get_material().renderable
|
||||
}
|
||||
|
||||
fn fence_gate_data(facing: Direction, in_wall: bool, open: bool, powered: bool) -> Option<usize> {
|
||||
if in_wall || powered {
|
||||
return None;
|
||||
|
@ -4783,7 +4965,7 @@ fn update_double_plant_state(world: &super::World, x: i32, y: i32, z: i32, ohalf
|
|||
}
|
||||
|
||||
match world.get_block(x, y - 1, z) {
|
||||
Block::DoublePlant{half, variant} => (ohalf, variant),
|
||||
Block::DoublePlant{variant, ..} => (ohalf, variant),
|
||||
_ => (ohalf, ovariant),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue