feat(chunk-gen) add scattered ore, twisting vines, blue ice
This commit is contained in:
parent
852057aaf6
commit
fd56a5be7a
@ -226,7 +226,9 @@ pub fn value_to_configured_feature(v: &Value) -> TokenStream {
|
|||||||
if type_str == "minecraft:scattered_ore" {
|
if type_str == "minecraft:scattered_ore" {
|
||||||
quote! {
|
quote! {
|
||||||
ConfiguredFeature::ScatteredOre(crate::generation::feature::features::scattered_ore::ScatteredOreFeature {
|
ConfiguredFeature::ScatteredOre(crate::generation::feature::features::scattered_ore::ScatteredOreFeature {
|
||||||
// TODO
|
size: #size,
|
||||||
|
discard_chance_on_air_exposure: #discard,
|
||||||
|
targets: vec![#(#targets),*],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -701,7 +703,16 @@ pub fn value_to_configured_feature(v: &Value) -> TokenStream {
|
|||||||
quote! { ConfiguredFeature::WeepingVines(crate::generation::feature::features::weeping_vines::WeepingVinesFeature {}) }
|
quote! { ConfiguredFeature::WeepingVines(crate::generation::feature::features::weeping_vines::WeepingVinesFeature {}) }
|
||||||
}
|
}
|
||||||
"minecraft:twisting_vines" => {
|
"minecraft:twisting_vines" => {
|
||||||
quote! { ConfiguredFeature::TwistingVines(crate::generation::feature::features::twisting_vines::TwistingVinesFeature {}) }
|
let spread_width = config["spread_width"].as_i64().unwrap_or(0) as i32;
|
||||||
|
let spread_height = config["spread_height"].as_i64().unwrap_or(0) as i32;
|
||||||
|
let max_height = config["max_height"].as_i64().unwrap_or(0) as i32;
|
||||||
|
quote! {
|
||||||
|
ConfiguredFeature::TwistingVines(crate::generation::feature::features::twisting_vines::TwistingVinesFeature {
|
||||||
|
spread_width: #spread_width,
|
||||||
|
spread_height: #spread_height,
|
||||||
|
max_height: #max_height,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"minecraft:delta_feature" => {
|
"minecraft:delta_feature" => {
|
||||||
quote! { ConfiguredFeature::DeltaFeature(crate::generation::feature::features::delta_feature::DeltaFeatureFeature {}) }
|
quote! { ConfiguredFeature::DeltaFeature(crate::generation::feature::features::delta_feature::DeltaFeatureFeature {}) }
|
||||||
|
|||||||
@ -2738,13 +2738,31 @@ fn build_configured_features() -> std::collections::HashMap<String, ConfiguredFe
|
|||||||
map.insert(
|
map.insert(
|
||||||
"ore_ancient_debris_large".to_string(),
|
"ore_ancient_debris_large".to_string(),
|
||||||
ConfiguredFeature::ScatteredOre(
|
ConfiguredFeature::ScatteredOre(
|
||||||
crate::generation::feature::features::scattered_ore::ScatteredOreFeature {},
|
crate::generation::feature::features::scattered_ore::ScatteredOreFeature {
|
||||||
|
size: 3i32,
|
||||||
|
discard_chance_on_air_exposure: 1f32,
|
||||||
|
targets: vec![OreTarget {
|
||||||
|
target: RuleTest::TagMatch(TagMatchRuleTest {
|
||||||
|
tag: pumpkin_data::tag::Block::MINECRAFT_BASE_STONE_NETHER,
|
||||||
|
}),
|
||||||
|
state: pumpkin_data::Block::ANCIENT_DEBRIS.default_state,
|
||||||
|
}],
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
map.insert(
|
map.insert(
|
||||||
"ore_ancient_debris_small".to_string(),
|
"ore_ancient_debris_small".to_string(),
|
||||||
ConfiguredFeature::ScatteredOre(
|
ConfiguredFeature::ScatteredOre(
|
||||||
crate::generation::feature::features::scattered_ore::ScatteredOreFeature {},
|
crate::generation::feature::features::scattered_ore::ScatteredOreFeature {
|
||||||
|
size: 2i32,
|
||||||
|
discard_chance_on_air_exposure: 1f32,
|
||||||
|
targets: vec![OreTarget {
|
||||||
|
target: RuleTest::TagMatch(TagMatchRuleTest {
|
||||||
|
tag: pumpkin_data::tag::Block::MINECRAFT_BASE_STONE_NETHER,
|
||||||
|
}),
|
||||||
|
state: pumpkin_data::Block::ANCIENT_DEBRIS.default_state,
|
||||||
|
}],
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
map.insert(
|
map.insert(
|
||||||
@ -4234,13 +4252,21 @@ fn build_configured_features() -> std::collections::HashMap<String, ConfiguredFe
|
|||||||
map.insert(
|
map.insert(
|
||||||
"twisting_vines".to_string(),
|
"twisting_vines".to_string(),
|
||||||
ConfiguredFeature::TwistingVines(
|
ConfiguredFeature::TwistingVines(
|
||||||
crate::generation::feature::features::twisting_vines::TwistingVinesFeature {},
|
crate::generation::feature::features::twisting_vines::TwistingVinesFeature {
|
||||||
|
spread_width: 8i32,
|
||||||
|
spread_height: 4i32,
|
||||||
|
max_height: 8i32,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
map.insert(
|
map.insert(
|
||||||
"twisting_vines_bonemeal".to_string(),
|
"twisting_vines_bonemeal".to_string(),
|
||||||
ConfiguredFeature::TwistingVines(
|
ConfiguredFeature::TwistingVines(
|
||||||
crate::generation::feature::features::twisting_vines::TwistingVinesFeature {},
|
crate::generation::feature::features::twisting_vines::TwistingVinesFeature {
|
||||||
|
spread_width: 3i32,
|
||||||
|
spread_height: 1i32,
|
||||||
|
max_height: 2i32,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
map.insert(
|
map.insert(
|
||||||
|
|||||||
@ -317,6 +317,9 @@ impl ConfiguredFeature {
|
|||||||
Self::Seagrass(feature) => {
|
Self::Seagrass(feature) => {
|
||||||
feature.generate(chunk, min_y, height, feature_name, random, pos)
|
feature.generate(chunk, min_y, height, feature_name, random, pos)
|
||||||
}
|
}
|
||||||
|
Self::TwistingVines(feature) => {
|
||||||
|
feature.generate(chunk, min_y, height, feature_name, random, pos)
|
||||||
|
}
|
||||||
Self::UnderwaterMagma(feature) => {
|
Self::UnderwaterMagma(feature) => {
|
||||||
feature.generate(chunk, min_y, height, feature_name, random, pos)
|
feature.generate(chunk, min_y, height, feature_name, random, pos)
|
||||||
}
|
}
|
||||||
@ -344,9 +347,19 @@ impl ConfiguredFeature {
|
|||||||
random,
|
random,
|
||||||
pos,
|
pos,
|
||||||
),
|
),
|
||||||
|
Self::ScatteredOre(feature) => feature.generate(
|
||||||
|
chunk,
|
||||||
|
block_registry,
|
||||||
|
min_y,
|
||||||
|
height,
|
||||||
|
feature_name,
|
||||||
|
random,
|
||||||
|
pos,
|
||||||
|
),
|
||||||
Self::MonsterRoom(feature) => {
|
Self::MonsterRoom(feature) => {
|
||||||
feature.generate(chunk, min_y, height, feature_name, random, pos)
|
feature.generate(chunk, min_y, height, feature_name, random, pos)
|
||||||
}
|
}
|
||||||
|
Self::BlueIce(feature) => feature.generate(chunk, random, pos),
|
||||||
Self::GlowstoneBlob(feature) => {
|
Self::GlowstoneBlob(feature) => {
|
||||||
feature.generate(chunk, min_y, height, feature_name, random, pos)
|
feature.generate(chunk, min_y, height, feature_name, random, pos)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,95 @@
|
|||||||
pub struct BlueIceFeature {
|
use pumpkin_data::Block;
|
||||||
// TODO
|
use pumpkin_util::{
|
||||||
|
math::position::BlockPos,
|
||||||
|
random::{RandomGenerator, RandomImpl},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::generation::proto_chunk::GenerationCache;
|
||||||
|
|
||||||
|
const SEA_LEVEL: i32 = 63; // TODO: use getSeaLevel() instead of hardcoding
|
||||||
|
|
||||||
|
pub struct BlueIceFeature {}
|
||||||
|
|
||||||
|
impl BlueIceFeature {
|
||||||
|
pub fn generate<T: GenerationCache>(
|
||||||
|
&self,
|
||||||
|
chunk: &mut T,
|
||||||
|
random: &mut RandomGenerator,
|
||||||
|
pos: BlockPos,
|
||||||
|
) -> bool {
|
||||||
|
if pos.0.y >= SEA_LEVEL - 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let block = GenerationCache::get_block_state(chunk, &pos.0).to_state();
|
||||||
|
let block_below = GenerationCache::get_block_state(chunk, &pos.down().0).to_state();
|
||||||
|
|
||||||
|
if block != Block::WATER.default_state && block_below != Block::WATER.default_state {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut has_ice_neighbor = false;
|
||||||
|
for neighbor_pos in [
|
||||||
|
pos.up(),
|
||||||
|
pos.down(),
|
||||||
|
pos.north(),
|
||||||
|
pos.south(),
|
||||||
|
pos.east(),
|
||||||
|
pos.west(),
|
||||||
|
] {
|
||||||
|
if GenerationCache::get_block_state(chunk, &neighbor_pos.0).to_state()
|
||||||
|
== Block::ICE.default_state
|
||||||
|
{
|
||||||
|
has_ice_neighbor = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !has_ice_neighbor {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk.set_block_state(&pos.0, Block::BLUE_ICE.default_state);
|
||||||
|
|
||||||
|
for _ in 0..200 {
|
||||||
|
let offset_x = random.next_bounded_i32(8) - random.next_bounded_i32(8);
|
||||||
|
let offset_y = random.next_bounded_i32(8) - random.next_bounded_i32(8);
|
||||||
|
let offset_z = random.next_bounded_i32(8) - random.next_bounded_i32(8);
|
||||||
|
let target_pos = pos.add(offset_x, offset_y, offset_z);
|
||||||
|
|
||||||
|
if chunk.out_of_height(target_pos.0.y as i16) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let target_state = GenerationCache::get_block_state(chunk, &target_pos.0).to_state();
|
||||||
|
if target_state.is_air()
|
||||||
|
|| target_state == Block::WATER.default_state
|
||||||
|
|| target_state == Block::ICE.default_state
|
||||||
|
|| target_state == Block::PACKED_ICE.default_state
|
||||||
|
{
|
||||||
|
let mut has_blue_ice_neighbor = false;
|
||||||
|
for neighbor_pos in [
|
||||||
|
target_pos.up(),
|
||||||
|
target_pos.down(),
|
||||||
|
target_pos.north(),
|
||||||
|
target_pos.south(),
|
||||||
|
target_pos.east(),
|
||||||
|
target_pos.west(),
|
||||||
|
] {
|
||||||
|
if GenerationCache::get_block_state(chunk, &neighbor_pos.0).to_state()
|
||||||
|
== Block::BLUE_ICE.default_state
|
||||||
|
{
|
||||||
|
has_blue_ice_neighbor = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if has_blue_ice_neighbor {
|
||||||
|
chunk.set_block_state(&target_pos.0, Block::BLUE_ICE.default_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -184,7 +184,14 @@ impl OreFeature {
|
|||||||
let block_state = GenerationCache::get_block_state(chunk, &pos_vec);
|
let block_state = GenerationCache::get_block_state(chunk, &pos_vec);
|
||||||
|
|
||||||
for target in &self.targets {
|
for target in &self.targets {
|
||||||
if self.should_place(chunk, block_state, random, target, &mutable_pos) {
|
if Self::should_place(
|
||||||
|
self.discard_chance_on_air_exposure,
|
||||||
|
chunk,
|
||||||
|
block_state,
|
||||||
|
random,
|
||||||
|
target,
|
||||||
|
&mutable_pos,
|
||||||
|
) {
|
||||||
chunk.set_block_state(&pos_vec, target.state);
|
chunk.set_block_state(&pos_vec, target.state);
|
||||||
placed_blocks_count += 1;
|
placed_blocks_count += 1;
|
||||||
break; // Equivalent to 'continue block11;'
|
break; // Equivalent to 'continue block11;'
|
||||||
@ -197,8 +204,8 @@ impl OreFeature {
|
|||||||
placed_blocks_count > 0
|
placed_blocks_count > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_place<T: GenerationCache>(
|
pub fn should_place<T: GenerationCache>(
|
||||||
&self,
|
discard_chance: f32,
|
||||||
chunk: &T,
|
chunk: &T,
|
||||||
state: RawBlockState,
|
state: RawBlockState,
|
||||||
random: &mut RandomGenerator,
|
random: &mut RandomGenerator,
|
||||||
@ -208,13 +215,13 @@ impl OreFeature {
|
|||||||
if !target.target.test(state, random) {
|
if !target.target.test(state, random) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if Self::should_not_discard(random, self.discard_chance_on_air_exposure) {
|
if Self::should_not_discard(random, discard_chance) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
!Self::is_exposed_to_air(chunk, pos)
|
!Self::is_exposed_to_air(chunk, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_not_discard(random: &mut RandomGenerator, chance: f32) -> bool {
|
pub fn should_not_discard(random: &mut RandomGenerator, chance: f32) -> bool {
|
||||||
if chance <= 0.0f32 {
|
if chance <= 0.0f32 {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -224,7 +231,7 @@ impl OreFeature {
|
|||||||
random.next_f32() >= chance
|
random.next_f32() >= chance
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_exposed_to_air<T: GenerationCache>(chunk: &T, pos: &BlockPos) -> bool {
|
pub fn is_exposed_to_air<T: GenerationCache>(chunk: &T, pos: &BlockPos) -> bool {
|
||||||
for dir in BlockDirection::all() {
|
for dir in BlockDirection::all() {
|
||||||
if GenerationCache::get_block_state(chunk, &pos.offset(dir.to_offset()).0)
|
if GenerationCache::get_block_state(chunk, &pos.offset(dir.to_offset()).0)
|
||||||
.to_state()
|
.to_state()
|
||||||
|
|||||||
@ -1,3 +1,69 @@
|
|||||||
|
use pumpkin_util::{
|
||||||
|
math::position::BlockPos,
|
||||||
|
random::{RandomGenerator, RandomImpl},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::generation::proto_chunk::GenerationCache;
|
||||||
|
use crate::world::BlockRegistryExt;
|
||||||
|
|
||||||
|
use super::ore::{OreFeature, OreTarget};
|
||||||
|
|
||||||
pub struct ScatteredOreFeature {
|
pub struct ScatteredOreFeature {
|
||||||
// TODO
|
pub size: i32,
|
||||||
|
pub discard_chance_on_air_exposure: f32,
|
||||||
|
pub targets: Vec<OreTarget>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScatteredOreFeature {
|
||||||
|
#[expect(clippy::too_many_arguments)]
|
||||||
|
pub fn generate<T: GenerationCache>(
|
||||||
|
&self,
|
||||||
|
chunk: &mut T,
|
||||||
|
_block_registry: &dyn BlockRegistryExt,
|
||||||
|
_min_y: i8,
|
||||||
|
_height: u16,
|
||||||
|
_feature: &str,
|
||||||
|
random: &mut RandomGenerator,
|
||||||
|
pos: BlockPos,
|
||||||
|
) -> bool {
|
||||||
|
let count = random.next_bounded_i32(self.size + 1);
|
||||||
|
let mut placed = false;
|
||||||
|
|
||||||
|
for _ in 0..count {
|
||||||
|
let offset_x = self.get_random_offset(random);
|
||||||
|
let offset_y = self.get_random_offset(random);
|
||||||
|
let offset_z = self.get_random_offset(random);
|
||||||
|
|
||||||
|
let target_pos = pos.add(offset_x, offset_y, offset_z);
|
||||||
|
|
||||||
|
if chunk.out_of_height(target_pos.0.y as i16) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let block_state = GenerationCache::get_block_state(chunk, &target_pos.0);
|
||||||
|
|
||||||
|
for target in &self.targets {
|
||||||
|
if OreFeature::should_place(
|
||||||
|
self.discard_chance_on_air_exposure,
|
||||||
|
chunk,
|
||||||
|
block_state,
|
||||||
|
random,
|
||||||
|
target,
|
||||||
|
&target_pos,
|
||||||
|
) {
|
||||||
|
chunk.set_block_state(&target_pos.0, target.state);
|
||||||
|
placed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
placed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_random_offset(&self, random: &mut RandomGenerator) -> i32 {
|
||||||
|
let f1 = random.next_f32();
|
||||||
|
let f2 = random.next_f32();
|
||||||
|
((f1 - f2) * self.size as f32).round() as i32
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,133 @@
|
|||||||
|
use pumpkin_data::Block;
|
||||||
|
use pumpkin_util::{
|
||||||
|
math::position::BlockPos,
|
||||||
|
random::{RandomGenerator, RandomImpl},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::generation::proto_chunk::GenerationCache;
|
||||||
|
|
||||||
pub struct TwistingVinesFeature {
|
pub struct TwistingVinesFeature {
|
||||||
// TODO
|
pub spread_width: i32,
|
||||||
|
pub spread_height: i32,
|
||||||
|
pub max_height: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TwistingVinesFeature {
|
||||||
|
pub fn generate<T: GenerationCache>(
|
||||||
|
&self,
|
||||||
|
chunk: &mut T,
|
||||||
|
_min_y: i8,
|
||||||
|
_height: u16,
|
||||||
|
_feature_name: &str,
|
||||||
|
random: &mut RandomGenerator,
|
||||||
|
pos: BlockPos,
|
||||||
|
) -> bool {
|
||||||
|
if self.is_invalid_location(chunk, &pos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut placed = false;
|
||||||
|
|
||||||
|
for _ in 0..self.spread_width * self.spread_width {
|
||||||
|
let offset_x = random.next_bounded_i32(self.spread_width)
|
||||||
|
- random.next_bounded_i32(self.spread_width);
|
||||||
|
let offset_y = random.next_bounded_i32(self.spread_height)
|
||||||
|
- random.next_bounded_i32(self.spread_height);
|
||||||
|
let offset_z = random.next_bounded_i32(self.spread_width)
|
||||||
|
- random.next_bounded_i32(self.spread_width);
|
||||||
|
|
||||||
|
let mut mutable_pos = pos.add(offset_x, offset_y, offset_z);
|
||||||
|
|
||||||
|
if self.find_target_y(chunk, &mut mutable_pos)
|
||||||
|
&& !self.is_invalid_location(chunk, &mutable_pos)
|
||||||
|
{
|
||||||
|
let mut height = random.next_bounded_i32(self.max_height) + 1;
|
||||||
|
if random.next_bounded_i32(6) == 0 {
|
||||||
|
height *= 2;
|
||||||
|
}
|
||||||
|
if random.next_bounded_i32(10) == 0 {
|
||||||
|
height = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.generate_column(chunk, random, &mutable_pos, height);
|
||||||
|
placed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
placed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_column<T: GenerationCache>(
|
||||||
|
&self,
|
||||||
|
chunk: &mut T,
|
||||||
|
random: &mut RandomGenerator,
|
||||||
|
pos: &BlockPos,
|
||||||
|
height: i32,
|
||||||
|
) {
|
||||||
|
let mut current_pos = *pos;
|
||||||
|
for i in 0..height {
|
||||||
|
if !GenerationCache::get_block_state(chunk, ¤t_pos.0)
|
||||||
|
.to_state()
|
||||||
|
.is_air()
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == height - 1
|
||||||
|
|| !GenerationCache::get_block_state(chunk, ¤t_pos.up().0)
|
||||||
|
.to_state()
|
||||||
|
.is_air()
|
||||||
|
{
|
||||||
|
// Top part
|
||||||
|
let _age = 17 + random.next_bounded_i32(25 - 17 + 1);
|
||||||
|
// We should set the age property here, but Pumpkin's BlockState might not support it easily yet or we just use default
|
||||||
|
// For now, let's just use the block.
|
||||||
|
// TODO: Set age property
|
||||||
|
chunk.set_block_state(¤t_pos.0, Block::TWISTING_VINES.default_state);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
chunk.set_block_state(¤t_pos.0, Block::TWISTING_VINES_PLANT.default_state);
|
||||||
|
}
|
||||||
|
current_pos = current_pos.up();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_invalid_location<T: GenerationCache>(&self, chunk: &T, pos: &BlockPos) -> bool {
|
||||||
|
if !GenerationCache::get_block_state(chunk, &pos.0)
|
||||||
|
.to_state()
|
||||||
|
.is_air()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let block_below = GenerationCache::get_block_state(chunk, &pos.down().0).to_state();
|
||||||
|
block_below != Block::WARPED_NYLIUM.default_state
|
||||||
|
&& block_below != Block::WARPED_WART_BLOCK.default_state
|
||||||
|
&& block_below != Block::TWISTING_VINES.default_state
|
||||||
|
&& block_below != Block::TWISTING_VINES_PLANT.default_state
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_target_y<T: GenerationCache>(&self, chunk: &T, pos: &mut BlockPos) -> bool {
|
||||||
|
// Try to find a valid floor by looking down
|
||||||
|
let mut current = *pos;
|
||||||
|
for _ in 0..self.spread_height {
|
||||||
|
if GenerationCache::get_block_state(chunk, ¤t.0)
|
||||||
|
.to_state()
|
||||||
|
.is_air()
|
||||||
|
{
|
||||||
|
let below = current.down();
|
||||||
|
let block_below = GenerationCache::get_block_state(chunk, &below.0).to_state();
|
||||||
|
if block_below == Block::WARPED_NYLIUM.default_state
|
||||||
|
|| block_below == Block::WARPED_WART_BLOCK.default_state
|
||||||
|
|| block_below == Block::TWISTING_VINES.default_state
|
||||||
|
|| block_below == Block::TWISTING_VINES_PLANT.default_state
|
||||||
|
{
|
||||||
|
*pos = current;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current = current.down();
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user