use glam::IVec3;
use crate::block_entity::BlockEntity;
use crate::block::material::Material;
use crate::util::default as def;
use crate::geom::Face;
use crate::block;
use super::World;
impl World {
pub fn can_place_block(&mut self, pos: IVec3, face: Face, id: u8) -> bool {
let base = match id {
block::BUTTON if face.is_y() => false,
block::BUTTON => self.is_block_opaque_cube(pos + face.delta()),
block::LEVER if face == Face::PosY => false,
block::LEVER => self.is_block_opaque_cube(pos + face.delta()),
block::LADDER => self.is_block_opaque_around(pos),
block::TRAPDOOR if face.is_y() => false,
block::TRAPDOOR => self.is_block_opaque_cube(pos + face.delta()),
block::PISTON_EXT |
block::PISTON_MOVING => false,
block::DEAD_BUSH => matches!(self.get_block(pos - IVec3::Y), Some((block::SAND, _))),
block::DANDELION |
block::POPPY |
block::SAPLING |
block::TALL_GRASS => matches!(self.get_block(pos - IVec3::Y), Some((block::GRASS | block::DIRT | block::FARMLAND, _))),
block::WHEAT => matches!(self.get_block(pos - IVec3::Y), Some((block::FARMLAND, _))),
block::CACTUS => self.can_place_cactus(pos),
block::SUGAR_CANES => self.can_place_sugar_canes(pos),
block::CAKE => self.is_block_solid(pos - IVec3::Y),
block::CHEST => self.can_place_chest(pos),
block::WOOD_DOOR |
block::IRON_DOOR => self.can_place_door(pos),
block::FENCE => matches!(self.get_block(pos - IVec3::Y), Some((block::FENCE, _))) || self.is_block_solid(pos - IVec3::Y),
block::FIRE => self.can_place_fire(pos),
block::TORCH |
block::REDSTONE_TORCH |
block::REDSTONE_TORCH_LIT => self.is_block_opaque_cube(pos + face.delta()),
block::RED_MUSHROOM | block::BROWN_MUSHROOM | block::WOOD_PRESSURE_PLATE |
block::STONE_PRESSURE_PLATE |
block::PUMPKIN |
block::PUMPKIN_LIT |
block::RAIL |
block::POWERED_RAIL |
block::DETECTOR_RAIL |
block::REPEATER |
block::REPEATER_LIT |
block::REDSTONE |
block::SNOW => self.is_block_opaque_cube(pos - IVec3::Y),
_ => true,
};
if let Some(bb) = self.get_block_exclusion_box(pos, id) {
if self.has_entity_colliding(bb, true) {
return false;
}
}
base && self.is_block_replaceable(pos)
}
fn can_place_cactus(&mut self, pos: IVec3) -> bool {
for face in Face::HORIZONTAL {
if self.is_block_solid(pos + face.delta()) {
return false;
}
}
matches!(self.get_block(pos - IVec3::Y), Some((block::CACTUS | block::SAND, _)))
}
fn can_place_sugar_canes(&mut self, pos: IVec3) -> bool {
let below_pos = pos - IVec3::Y;
if let Some((block::SUGAR_CANES | block::GRASS | block::DIRT, _)) = self.get_block(below_pos) {
for face in Face::HORIZONTAL {
if self.get_block_material(below_pos + face.delta()) == Material::Water {
return true;
}
}
}
false
}
fn can_place_chest(&mut self, pos: IVec3) -> bool {
let mut found_single_chest = false;
for face in Face::HORIZONTAL {
let neighbor_pos = pos + face.delta();
if matches!(self.get_block(neighbor_pos), Some((block::CHEST, _))) {
if found_single_chest {
return false;
}
for neighbor_face in Face::HORIZONTAL {
if face != neighbor_face.opposite() {
if matches!(self.get_block(neighbor_pos + neighbor_face.delta()), Some((block::CHEST, _))) {
return false; }
}
}
found_single_chest = true;
}
}
true
}
fn can_place_door(&mut self, pos: IVec3) -> bool {
self.is_block_opaque_cube(pos - IVec3::Y) && self.is_block_replaceable(pos + IVec3::Y)
}
fn can_place_fire(&mut self, pos: IVec3) -> bool {
if self.is_block_opaque_cube(pos - IVec3::Y) {
true
} else {
for face in Face::ALL {
if let Some((block, _)) = self.get_block(pos + face.delta()) {
if block::material::get_fire_flammability(block) != 0 {
return true;
}
}
}
false
}
}
pub fn place_block(&mut self, pos: IVec3, face: Face, id: u8, metadata: u8) {
match id {
block::BUTTON => self.place_faced(pos, face, id, metadata, block::button::set_face),
block::TRAPDOOR => self.place_faced(pos, face, id, metadata, block::trapdoor::set_face),
block::PISTON => self.place_faced(pos, face, id, metadata, block::piston::set_face),
block::WOOD_STAIR |
block::COBBLESTONE_STAIR => self.place_faced(pos, face, id, metadata, block::stair::set_face),
block::REPEATER |
block::REPEATER_LIT => self.place_faced(pos, face, id, metadata, block::repeater::set_face),
block::PUMPKIN |
block::PUMPKIN_LIT => self.place_faced(pos, face, id, metadata, block::pumpkin::set_face),
block::FURNACE |
block::FURNACE_LIT |
block::DISPENSER => self.place_faced(pos, face, id, metadata, block::dispenser::set_face),
block::TORCH |
block::REDSTONE_TORCH |
block::REDSTONE_TORCH_LIT => self.place_faced(pos, face, id, metadata, block::torch::set_face),
block::LEVER => self.place_lever(pos, face, metadata),
block::LADDER => self.place_ladder(pos, face, metadata),
_ => {
self.set_block_notify(pos, id, metadata);
}
}
match id {
block::CHEST => self.set_block_entity(pos, BlockEntity::Chest(def())),
block::FURNACE => self.set_block_entity(pos, BlockEntity::Furnace(def())),
block::DISPENSER => self.set_block_entity(pos, BlockEntity::Dispenser(def())),
block::SPAWNER => self.set_block_entity(pos, BlockEntity::Spawner(def())),
block::NOTE_BLOCK => self.set_block_entity(pos, BlockEntity::NoteBlock(def())),
block::JUKEBOX => self.set_block_entity(pos, BlockEntity::Jukebox(def())),
_ => {}
}
}
fn place_faced(&mut self, pos: IVec3, face: Face, id: u8, mut metadata: u8, func: impl FnOnce(&mut u8, Face)) {
func(&mut metadata, face);
self.set_block_notify(pos, id, metadata);
}
fn place_lever(&mut self, pos: IVec3, face: Face, mut metadata: u8) {
block::lever::set_face(&mut metadata, face, match face {
Face::NegY => self.rand.next_choice(&[Face::PosZ, Face::PosX]),
_ => Face::PosY,
});
self.set_block_notify(pos, block::LEVER, metadata);
}
fn place_ladder(&mut self, pos: IVec3, mut face: Face, mut metadata: u8) {
if face.is_y() || !self.is_block_opaque_cube(pos + face.delta()) {
for around_face in [Face::PosZ, Face::NegZ, Face::PosX, Face::NegX] {
if self.is_block_opaque_cube(pos + around_face.delta()) {
face = around_face;
break;
}
}
}
block::ladder::set_face(&mut metadata, face);
self.set_block_notify(pos, block::LADDER, metadata);
}
fn is_block_opaque_around(&mut self, pos: IVec3) -> bool {
for face in Face::HORIZONTAL {
if self.is_block_opaque_cube(pos + face.delta()) {
return true;
}
}
false
}
}