mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
Add Nether Portals
This commit is contained in:
@@ -72,7 +72,7 @@ pub struct SyncedRegistry {
|
|||||||
instrument: IndexMap<String, Instrument>,
|
instrument: IndexMap<String, Instrument>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum DimensionType {
|
pub enum DimensionType {
|
||||||
Overworld,
|
Overworld,
|
||||||
OverworldCaves,
|
OverworldCaves,
|
||||||
|
|||||||
@@ -9,6 +9,65 @@ use crate::math::vector2::Vector2;
|
|||||||
use num_traits::Euclid;
|
use num_traits::Euclid;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
pub struct BlockPosIterator {
|
||||||
|
start_x: i32,
|
||||||
|
start_y: i32,
|
||||||
|
start_z: i32,
|
||||||
|
end_x: i32,
|
||||||
|
end_y: i32,
|
||||||
|
index: usize,
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockPosIterator {
|
||||||
|
pub fn new(
|
||||||
|
start_x: i32,
|
||||||
|
start_y: i32,
|
||||||
|
start_z: i32,
|
||||||
|
end_x: i32,
|
||||||
|
end_y: i32,
|
||||||
|
end_z: i32,
|
||||||
|
) -> Self {
|
||||||
|
let count_x = end_x - start_x + 1;
|
||||||
|
let count_y = end_y - start_y + 1;
|
||||||
|
let count_z = end_z - start_z + 1;
|
||||||
|
let count = (count_x * count_y * count_z) as usize;
|
||||||
|
BlockPosIterator {
|
||||||
|
start_x,
|
||||||
|
start_y,
|
||||||
|
start_z,
|
||||||
|
end_x,
|
||||||
|
end_y,
|
||||||
|
index: 0,
|
||||||
|
count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for BlockPosIterator {
|
||||||
|
type Item = BlockPos;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.index >= self.count {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let size_x = (self.end_x - self.start_x + 1) as usize;
|
||||||
|
let size_y = (self.end_y - self.start_y + 1) as usize;
|
||||||
|
|
||||||
|
let x_offset = self.index % size_x;
|
||||||
|
let y_offset = (self.index / size_x) % size_y;
|
||||||
|
let z_offset = (self.index / size_x) / size_y;
|
||||||
|
|
||||||
|
let x = self.start_x + x_offset as i32;
|
||||||
|
let y = self.start_y + y_offset as i32;
|
||||||
|
let z = self.start_z + z_offset as i32;
|
||||||
|
|
||||||
|
self.index += 1;
|
||||||
|
Some(BlockPos::new(x, y, z))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
|
||||||
/// Aka Block Position
|
/// Aka Block Position
|
||||||
pub struct BlockPos(pub Vector3<i32>);
|
pub struct BlockPos(pub Vector3<i32>);
|
||||||
@@ -18,6 +77,28 @@ impl BlockPos {
|
|||||||
Self(Vector3::new(x, y, z))
|
Self(Vector3::new(x, y, z))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn iterate(start: BlockPos, end: BlockPos) -> BlockPosIterator {
|
||||||
|
BlockPosIterator::new(
|
||||||
|
start.0.x.min(end.0.x),
|
||||||
|
start.0.y.min(end.0.y),
|
||||||
|
start.0.z.min(end.0.z),
|
||||||
|
start.0.x.max(end.0.x),
|
||||||
|
start.0.y.max(end.0.y),
|
||||||
|
start.0.z.max(end.0.z),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iterate_block_pos(
|
||||||
|
start_x: i32,
|
||||||
|
start_y: i32,
|
||||||
|
start_z: i32,
|
||||||
|
end_x: i32,
|
||||||
|
end_y: i32,
|
||||||
|
end_z: i32,
|
||||||
|
) -> BlockPosIterator {
|
||||||
|
BlockPosIterator::new(start_x, start_y, start_z, end_x, end_y, end_z)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn chunk_and_chunk_relative_position(&self) -> (Vector2<i32>, Vector3<i32>) {
|
pub fn chunk_and_chunk_relative_position(&self) -> (Vector2<i32>, Vector3<i32>) {
|
||||||
let (z_chunk, z_rem) = self.0.z.div_rem_euclid(&16);
|
let (z_chunk, z_rem) = self.0.z.div_rem_euclid(&16);
|
||||||
let (x_chunk, x_rem) = self.0.x.div_rem_euclid(&16);
|
let (x_chunk, x_rem) = self.0.x.div_rem_euclid(&16);
|
||||||
@@ -75,6 +156,14 @@ impl BlockPos {
|
|||||||
BlockPos(self.0 + offset)
|
BlockPos(self.0 + offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn offset_dir(&self, offset: Vector3<i32>, direction: i32) -> Self {
|
||||||
|
BlockPos(Vector3::new(
|
||||||
|
self.0.x + offset.x * direction,
|
||||||
|
self.0.y + offset.y * direction,
|
||||||
|
self.0.z + offset.z * direction,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn up(&self) -> Self {
|
pub fn up(&self) -> Self {
|
||||||
self.offset(Vector3::new(0, 1, 0))
|
self.offset(Vector3::new(0, 1, 0))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ use crate::block::pumpkin_block::PumpkinBlock;
|
|||||||
use crate::entity::player::Player;
|
use crate::entity::player::Player;
|
||||||
use crate::server::Server;
|
use crate::server::Server;
|
||||||
use crate::world::World;
|
use crate::world::World;
|
||||||
|
use crate::world::portal::NetherPortal;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::block_properties::HorizontalAxis;
|
||||||
use pumpkin_data::world::WorldEvent;
|
use pumpkin_data::world::WorldEvent;
|
||||||
use pumpkin_data::{Block, BlockState};
|
use pumpkin_data::{Block, BlockState};
|
||||||
|
use pumpkin_registry::DimensionType;
|
||||||
use pumpkin_util::math::position::BlockPos;
|
use pumpkin_util::math::position::BlockPos;
|
||||||
use pumpkin_world::BlockStateId;
|
use pumpkin_world::BlockStateId;
|
||||||
use pumpkin_world::block::BlockDirection;
|
use pumpkin_world::block::BlockDirection;
|
||||||
@@ -33,16 +36,24 @@ impl FireBlockBase {
|
|||||||
impl PumpkinBlock for FireBlockBase {
|
impl PumpkinBlock for FireBlockBase {
|
||||||
async fn placed(
|
async fn placed(
|
||||||
&self,
|
&self,
|
||||||
_world: &Arc<World>,
|
world: &Arc<World>,
|
||||||
_block: &Block,
|
_block: &Block,
|
||||||
state_id: BlockStateId,
|
state_id: BlockStateId,
|
||||||
_pos: &BlockPos,
|
pos: &BlockPos,
|
||||||
old_state_id: BlockStateId,
|
old_state_id: BlockStateId,
|
||||||
_notify: bool,
|
_notify: bool,
|
||||||
) {
|
) {
|
||||||
if old_state_id == state_id {
|
if old_state_id == state_id {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let dimension = world.dimension_type;
|
||||||
|
// First lets check if we are in OverWorld or Nether, its not possible to place an Nether portal in other dimensions in Vanilla
|
||||||
|
if dimension == DimensionType::Overworld || dimension == DimensionType::TheNether {
|
||||||
|
if let Some(portal) = NetherPortal::get_new_portal(world, pos, HorizontalAxis::X).await
|
||||||
|
{
|
||||||
|
portal.create(world).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn can_place_at(
|
async fn can_place_at(
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ pub mod glass_panes;
|
|||||||
pub mod iron_bars;
|
pub mod iron_bars;
|
||||||
pub mod jukebox;
|
pub mod jukebox;
|
||||||
pub mod logs;
|
pub mod logs;
|
||||||
|
pub mod nether_portal;
|
||||||
pub mod redstone;
|
pub mod redstone;
|
||||||
pub mod signs;
|
pub mod signs;
|
||||||
pub mod slabs;
|
pub mod slabs;
|
||||||
|
|||||||
41
pumpkin/src/block/blocks/nether_portal.rs
Normal file
41
pumpkin/src/block/blocks/nether_portal.rs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
use crate::block::pumpkin_block::PumpkinBlock;
|
||||||
|
use crate::world::World;
|
||||||
|
use crate::world::portal::NetherPortal;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use pumpkin_data::Block;
|
||||||
|
use pumpkin_data::block_properties::{Axis, BlockProperties, NetherPortalLikeProperties};
|
||||||
|
use pumpkin_macros::pumpkin_block;
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use pumpkin_world::BlockStateId;
|
||||||
|
use pumpkin_world::block::BlockDirection;
|
||||||
|
|
||||||
|
#[pumpkin_block("minecraft:nether_portal")]
|
||||||
|
pub struct NetherPortalBlock;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl PumpkinBlock for NetherPortalBlock {
|
||||||
|
async fn get_state_for_neighbor_update(
|
||||||
|
&self,
|
||||||
|
world: &World,
|
||||||
|
_block: &Block,
|
||||||
|
state: BlockStateId,
|
||||||
|
pos: &BlockPos,
|
||||||
|
direction: BlockDirection,
|
||||||
|
_neighbor_pos: &BlockPos,
|
||||||
|
neighbor_state: BlockStateId,
|
||||||
|
) -> BlockStateId {
|
||||||
|
let axis = direction.to_axis();
|
||||||
|
let is_horizontal = axis == Axis::X && axis == Axis::Z;
|
||||||
|
let state_axis =
|
||||||
|
NetherPortalLikeProperties::from_state_id(state, &Block::NETHER_PORTAL).axis;
|
||||||
|
if is_horizontal
|
||||||
|
|| neighbor_state == state
|
||||||
|
|| NetherPortal::get_on_axis(world, pos, state_axis)
|
||||||
|
.await
|
||||||
|
.is_some_and(|e| e.was_already_valid())
|
||||||
|
{
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
Block::AIR.default_state_id
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ use blocks::fire::soul_fire::SoulFireBlock;
|
|||||||
use blocks::glass_panes::GlassPaneBlock;
|
use blocks::glass_panes::GlassPaneBlock;
|
||||||
use blocks::iron_bars::IronBarsBlock;
|
use blocks::iron_bars::IronBarsBlock;
|
||||||
use blocks::logs::LogBlock;
|
use blocks::logs::LogBlock;
|
||||||
|
use blocks::nether_portal::NetherPortalBlock;
|
||||||
use blocks::redstone::buttons::ButtonBlock;
|
use blocks::redstone::buttons::ButtonBlock;
|
||||||
use blocks::redstone::observer::ObserverBlock;
|
use blocks::redstone::observer::ObserverBlock;
|
||||||
use blocks::redstone::piston::PistonBlock;
|
use blocks::redstone::piston::PistonBlock;
|
||||||
@@ -85,6 +86,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
|||||||
manager.register(TNTBlock);
|
manager.register(TNTBlock);
|
||||||
manager.register(TorchBlock);
|
manager.register(TorchBlock);
|
||||||
manager.register(WallBlock);
|
manager.register(WallBlock);
|
||||||
|
manager.register(NetherPortalBlock);
|
||||||
|
|
||||||
// Fire
|
// Fire
|
||||||
manager.register(SoulFireBlock);
|
manager.register(SoulFireBlock);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use std::{
|
|||||||
|
|
||||||
pub mod chunker;
|
pub mod chunker;
|
||||||
pub mod explosion;
|
pub mod explosion;
|
||||||
|
pub mod portal;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|||||||
251
pumpkin/src/world/portal.rs
Normal file
251
pumpkin/src/world/portal.rs
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use pumpkin_data::{
|
||||||
|
Block, BlockState,
|
||||||
|
block_properties::{BlockProperties, HorizontalAxis, NetherPortalLikeProperties},
|
||||||
|
tag::Tagable,
|
||||||
|
};
|
||||||
|
use pumpkin_util::math::position::BlockPos;
|
||||||
|
use pumpkin_world::block::BlockDirection;
|
||||||
|
|
||||||
|
use super::{BlockFlags, World};
|
||||||
|
|
||||||
|
pub struct NetherPortal {
|
||||||
|
axis: HorizontalAxis,
|
||||||
|
found_portal_blocks: u32,
|
||||||
|
negative_direction: BlockDirection,
|
||||||
|
lower_conor: BlockPos,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NetherPortal {
|
||||||
|
/// This is Vanilla
|
||||||
|
const MIN_WIDTH: u32 = 2;
|
||||||
|
const MAX_WIDTH: u32 = 21;
|
||||||
|
|
||||||
|
const MAX_HEIGHT: u32 = 21;
|
||||||
|
const MIN_HEIGHT: u32 = 3;
|
||||||
|
|
||||||
|
const FRAME_BLOCK: Block = Block::OBSIDIAN;
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_valid(&self) -> bool {
|
||||||
|
self.width >= Self::MIN_WIDTH
|
||||||
|
&& self.width <= Self::MAX_WIDTH
|
||||||
|
&& self.height >= Self::MIN_WIDTH
|
||||||
|
&& self.height <= Self::MAX_HEIGHT
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn was_already_valid(&self) -> bool {
|
||||||
|
self.is_valid() && self.found_portal_blocks == self.width * self.height
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create(&self, world: &Arc<World>) {
|
||||||
|
let mut props = NetherPortalLikeProperties::default(&Block::NETHER_PORTAL);
|
||||||
|
props.axis = self.axis;
|
||||||
|
let state = props.to_state_id(&Block::NETHER_PORTAL);
|
||||||
|
// We remove 1 block because of the frame border
|
||||||
|
let blocks = BlockPos::iterate(
|
||||||
|
self.lower_conor,
|
||||||
|
self.lower_conor
|
||||||
|
.offset_dir(BlockDirection::Up.to_offset(), self.height as i32 - 1)
|
||||||
|
.offset_dir(self.negative_direction.to_offset(), self.width as i32 - 1),
|
||||||
|
);
|
||||||
|
for pos in blocks {
|
||||||
|
world
|
||||||
|
.set_block_state(
|
||||||
|
&pos,
|
||||||
|
state,
|
||||||
|
BlockFlags::NOTIFY_LISTENERS | BlockFlags::FORCE_STATE,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_new_portal(
|
||||||
|
world: &World,
|
||||||
|
pos: &BlockPos,
|
||||||
|
first_axis: HorizontalAxis,
|
||||||
|
) -> Option<Self> {
|
||||||
|
// We check both axis here X and Z
|
||||||
|
if let Some(portal) = Self::get_on_axis(world, pos, first_axis).await {
|
||||||
|
if portal.is_valid() && portal.found_portal_blocks == 0 {
|
||||||
|
return Some(portal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let next_axis = if first_axis == HorizontalAxis::X {
|
||||||
|
HorizontalAxis::Z
|
||||||
|
} else {
|
||||||
|
HorizontalAxis::X
|
||||||
|
};
|
||||||
|
if let Some(portal) = Self::get_on_axis(world, pos, next_axis).await {
|
||||||
|
if portal.is_valid() && portal.found_portal_blocks == 0 {
|
||||||
|
return Some(portal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_on_axis(world: &World, pos: &BlockPos, axis: HorizontalAxis) -> Option<Self> {
|
||||||
|
let direction = if axis == HorizontalAxis::X {
|
||||||
|
BlockDirection::West
|
||||||
|
} else {
|
||||||
|
BlockDirection::South
|
||||||
|
};
|
||||||
|
let cornor = Self::get_lower_cornor(world, direction, pos).await?;
|
||||||
|
let width = Self::get_width(world, &cornor, &direction).await;
|
||||||
|
if !(Self::MIN_WIDTH..=Self::MAX_WIDTH).contains(&width) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let mut found_portal_blocks = 0;
|
||||||
|
let height =
|
||||||
|
Self::get_height(world, &cornor, &direction, width, &mut found_portal_blocks).await?;
|
||||||
|
Some(Self {
|
||||||
|
axis,
|
||||||
|
found_portal_blocks,
|
||||||
|
negative_direction: direction,
|
||||||
|
lower_conor: cornor,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_lower_cornor(
|
||||||
|
world: &World,
|
||||||
|
direction: BlockDirection,
|
||||||
|
pos: &BlockPos,
|
||||||
|
) -> Option<BlockPos> {
|
||||||
|
// TODO: check max getBottomY
|
||||||
|
let limit_y = pos.0.y - Self::MAX_HEIGHT as i32;
|
||||||
|
let mut pos = *pos;
|
||||||
|
while pos.0.y > limit_y {
|
||||||
|
let (block, state) = world.get_block_and_block_state(&pos.down()).await.unwrap();
|
||||||
|
if !Self::valid_state_inside_portal(&block, &state) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos = pos.down();
|
||||||
|
}
|
||||||
|
let neg_dir = direction.opposite();
|
||||||
|
let width = (Self::get_width(world, &pos, &neg_dir).await as i32) - 1;
|
||||||
|
if width < 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(pos.offset_dir(neg_dir.to_offset(), width as i32))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_width(
|
||||||
|
world: &World,
|
||||||
|
original_lower_corner: &BlockPos,
|
||||||
|
negative_dir: &BlockDirection,
|
||||||
|
) -> u32 {
|
||||||
|
let mut lower_corner;
|
||||||
|
for i in 0..=Self::MAX_WIDTH {
|
||||||
|
lower_corner = original_lower_corner.offset_dir(negative_dir.to_offset(), i as i32);
|
||||||
|
let (block, block_state) = world
|
||||||
|
.get_block_and_block_state(&lower_corner)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
if !Self::valid_state_inside_portal(&block, &block_state) {
|
||||||
|
if Self::FRAME_BLOCK != block {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
let block = world.get_block(&lower_corner.down()).await.unwrap();
|
||||||
|
if Self::FRAME_BLOCK != block {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_height(
|
||||||
|
world: &World,
|
||||||
|
lower_corner: &BlockPos,
|
||||||
|
negative_dir: &BlockDirection,
|
||||||
|
width: u32,
|
||||||
|
found_portal_blocks: &mut u32,
|
||||||
|
) -> Option<u32> {
|
||||||
|
let height = Self::get_potential_height(
|
||||||
|
world,
|
||||||
|
lower_corner,
|
||||||
|
negative_dir,
|
||||||
|
width,
|
||||||
|
found_portal_blocks,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
if !(Self::MIN_HEIGHT..=Self::MAX_HEIGHT).contains(&height)
|
||||||
|
|| !Self::is_horizontal_frame_valid(world, lower_corner, negative_dir, width, height)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(height)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_potential_height(
|
||||||
|
world: &World,
|
||||||
|
lower_corner: &BlockPos,
|
||||||
|
negative_dir: &BlockDirection,
|
||||||
|
width: u32,
|
||||||
|
found_portal_blocks: &mut u32,
|
||||||
|
) -> u32 {
|
||||||
|
for i in 0..Self::MAX_HEIGHT as i32 {
|
||||||
|
let mut pos = lower_corner
|
||||||
|
.offset_dir(BlockDirection::Up.to_offset(), i)
|
||||||
|
.offset_dir(negative_dir.to_offset(), -1);
|
||||||
|
if world.get_block(&pos).await.unwrap() != Self::FRAME_BLOCK {
|
||||||
|
return i as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = lower_corner
|
||||||
|
.offset_dir(BlockDirection::Up.to_offset(), i)
|
||||||
|
.offset_dir(negative_dir.to_offset(), width as i32);
|
||||||
|
if world.get_block(&pos).await.unwrap() != Self::FRAME_BLOCK {
|
||||||
|
return i as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
for j in 0..width {
|
||||||
|
pos = lower_corner
|
||||||
|
.offset_dir(BlockDirection::Up.to_offset(), i)
|
||||||
|
.offset_dir(negative_dir.to_offset(), j as i32);
|
||||||
|
let (block, block_state) = world.get_block_and_block_state(&pos).await.unwrap();
|
||||||
|
if !Self::valid_state_inside_portal(&block, &block_state) {
|
||||||
|
return i as u32;
|
||||||
|
}
|
||||||
|
if block == Block::NETHER_PORTAL {
|
||||||
|
*found_portal_blocks += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
21
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_horizontal_frame_valid(
|
||||||
|
world: &World,
|
||||||
|
lower_corner: &BlockPos,
|
||||||
|
dir: &BlockDirection,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
) -> bool {
|
||||||
|
let mut pos;
|
||||||
|
for i in 0..width {
|
||||||
|
pos = lower_corner
|
||||||
|
.offset_dir(BlockDirection::Up.to_offset(), height as i32)
|
||||||
|
.offset_dir(dir.to_offset(), i as i32);
|
||||||
|
if Self::FRAME_BLOCK != world.get_block(&pos).await.unwrap() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// What is allowed to be inside the Portal frame
|
||||||
|
fn valid_state_inside_portal(block: &Block, state: &BlockState) -> bool {
|
||||||
|
state.is_air()
|
||||||
|
|| block.is_tagged_with("minecraft:fire").unwrap()
|
||||||
|
|| block == &Block::NETHER_PORTAL
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user