570 lines
22 KiB
Java
570 lines
22 KiB
Java
package org.betterx.betterend.rituals;
|
|
|
|
import org.betterx.bclib.api.v2.dataexchange.DataExchangeAPI;
|
|
import org.betterx.bclib.blocks.BlockProperties;
|
|
import org.betterx.betterend.BetterEnd;
|
|
import org.betterx.betterend.advancements.BECriteria;
|
|
import org.betterx.betterend.blocks.EndPortalBlock;
|
|
import org.betterx.betterend.blocks.RunedFlavolite;
|
|
import org.betterx.betterend.blocks.entities.EternalPedestalEntity;
|
|
import org.betterx.betterend.network.RitualUpdate;
|
|
import org.betterx.betterend.portal.PortalBuilder;
|
|
import org.betterx.betterend.registry.EndBlocks;
|
|
import org.betterx.betterend.registry.EndPortals;
|
|
|
|
import net.minecraft.BlockUtil;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.core.particles.BlockParticleOption;
|
|
import net.minecraft.core.particles.ParticleOptions;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.core.registries.BuiltInRegistries;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.nbt.NbtUtils;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.server.level.ServerPlayer;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.Item;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.Block;
|
|
import net.minecraft.world.level.block.NetherPortalBlock;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
|
import net.minecraft.world.level.border.WorldBorder;
|
|
|
|
import com.google.common.collect.Sets;
|
|
|
|
import java.awt.*;
|
|
import java.util.Objects;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class EternalRitual {
|
|
private final static Set<Point> PEDESTAL_POSITIONS = Sets.newHashSet(
|
|
new Point(-4, -5),
|
|
new Point(-4, 5),
|
|
new Point(-6, 0),
|
|
new Point(4, -5),
|
|
new Point(4, 5),
|
|
new Point(6, 0)
|
|
);
|
|
|
|
private final static Block PEDESTAL = EndBlocks.ETERNAL_PEDESTAL;
|
|
public final static BooleanProperty ACTIVE = BlockProperties.ACTIVE;
|
|
|
|
private Level world;
|
|
private Direction.Axis axis;
|
|
private ResourceLocation targetWorldId;
|
|
private BlockPos center;
|
|
private BlockPos exit;
|
|
private boolean active = false;
|
|
private boolean willActivate = false;
|
|
|
|
public EternalRitual(Level world) {
|
|
this.world = world;
|
|
}
|
|
|
|
public EternalRitual(Level world, BlockPos initial) {
|
|
this(world);
|
|
this.configure(initial);
|
|
}
|
|
|
|
public BlockPos getCenter() {
|
|
return center;
|
|
}
|
|
|
|
public Direction.Axis getAxis() {
|
|
return axis;
|
|
}
|
|
|
|
public void setWorld(Level world) {
|
|
this.world = world;
|
|
}
|
|
|
|
public Level getWorld() {
|
|
return world;
|
|
}
|
|
|
|
@Nullable
|
|
public ResourceLocation getTargetWorldId() {
|
|
return targetWorldId;
|
|
}
|
|
|
|
private boolean isInvalid() {
|
|
return world == null || world.isClientSide() || center == null || axis == null;
|
|
}
|
|
|
|
public void checkStructure(Player player) {
|
|
if (isInvalid()) return;
|
|
Direction moveX, moveY;
|
|
if (Direction.Axis.X == axis) {
|
|
moveX = Direction.EAST;
|
|
moveY = Direction.NORTH;
|
|
} else {
|
|
moveX = Direction.SOUTH;
|
|
moveY = Direction.EAST;
|
|
}
|
|
boolean valid = checkFrame(world, center.below());
|
|
Item item = null;
|
|
for (Point pos : PEDESTAL_POSITIONS) {
|
|
BlockPos.MutableBlockPos checkPos = center.mutable();
|
|
checkPos.move(moveX, pos.x).move(moveY, pos.y);
|
|
valid &= isActive(checkPos);
|
|
if (valid) {
|
|
EternalPedestalEntity pedestal = (EternalPedestalEntity) world.getBlockEntity(checkPos);
|
|
if (pedestal != null) {
|
|
Item pItem = pedestal.getItem(0).getItem();
|
|
if (item == null) {
|
|
item = pItem;
|
|
} else if (!item.equals(pItem)) {
|
|
valid = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (valid && item != null) {
|
|
activatePortal(player, item);
|
|
if (player instanceof ServerPlayer sp) {
|
|
BECriteria.PORTAL_ON.trigger(sp);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void updateActiveStateOnPedestals() {
|
|
if (world == null) return;
|
|
updateActiveStateOnPedestals(center, axis, active, willActivate, world, this);
|
|
DataExchangeAPI.send(new RitualUpdate(this));
|
|
}
|
|
|
|
public static void updateActiveStateOnPedestals(
|
|
BlockPos center,
|
|
Direction.Axis axis,
|
|
boolean active,
|
|
boolean willActivate,
|
|
Level world,
|
|
EternalRitual fallback
|
|
) {
|
|
Direction moveX, moveY;
|
|
if (Direction.Axis.X == axis) {
|
|
moveX = Direction.EAST;
|
|
moveY = Direction.NORTH;
|
|
} else {
|
|
moveX = Direction.SOUTH;
|
|
moveY = Direction.EAST;
|
|
}
|
|
|
|
|
|
for (Point pos : PEDESTAL_POSITIONS) {
|
|
BlockPos.MutableBlockPos checkPos = center.mutable();
|
|
checkPos.move(moveX, pos.x).move(moveY, pos.y);
|
|
if (world.getBlockEntity(checkPos) instanceof EternalPedestalEntity pedestal) {
|
|
if (pedestal.hasRitual()) {
|
|
if (fallback == null) fallback = pedestal.getRitual();
|
|
pedestal.getRitual().active = active;
|
|
pedestal.getRitual().willActivate = willActivate;
|
|
} else {
|
|
if (fallback == null) {
|
|
fallback = new EternalRitual(world);
|
|
fallback.center = center;
|
|
fallback.axis = axis;
|
|
fallback.willActivate = willActivate;
|
|
fallback.active = active;
|
|
}
|
|
pedestal.linkRitual(fallback);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean checkFrame(Level world, BlockPos framePos) {
|
|
Direction moveDir = Direction.Axis.X == axis ? Direction.NORTH : Direction.EAST;
|
|
boolean valid = true;
|
|
for (Point point : PortalBuilder.FRAME_POSITIONS) {
|
|
BlockPos pos = framePos.mutable().move(moveDir, point.x).move(Direction.UP, point.y);
|
|
BlockState state = world.getBlockState(pos);
|
|
valid &= state.getBlock() instanceof RunedFlavolite;
|
|
pos = framePos.mutable().move(moveDir, -point.x).move(Direction.UP, point.y);
|
|
state = world.getBlockState(pos);
|
|
valid &= state.getBlock() instanceof RunedFlavolite;
|
|
}
|
|
return valid;
|
|
}
|
|
|
|
public boolean isActive() {
|
|
return active;
|
|
}
|
|
|
|
public boolean willActivate() {
|
|
return willActivate;
|
|
}
|
|
|
|
private void activatePortal(Player player, Item keyItem) {
|
|
if (active) return;
|
|
willActivate = true;
|
|
updateActiveStateOnPedestals();
|
|
|
|
ResourceLocation itemId = BuiltInRegistries.ITEM.getKey(keyItem);
|
|
int portalId = EndPortals.getPortalIdByItem(itemId);
|
|
Level targetWorld = getTargetWorld(portalId);
|
|
ResourceLocation worldId = targetWorld.dimension().location();
|
|
try {
|
|
if (exit == null) {
|
|
initPortal(player, worldId, portalId);
|
|
} else {
|
|
if (!worldId.equals(targetWorldId)) {
|
|
initPortal(player, worldId, portalId);
|
|
} else if (!checkFrame(targetWorld, exit.below())) {
|
|
Direction.Axis portalAxis = (Direction.Axis.X == axis) ? Direction.Axis.Z : Direction.Axis.X;
|
|
PortalBuilder.generatePortal(targetWorld, exit, portalAxis, portalId);
|
|
}
|
|
activatePortal(targetWorld, exit, portalId);
|
|
}
|
|
activatePortal(world, center, portalId);
|
|
if (world instanceof ServerLevel serverLevel) {
|
|
doEffects(serverLevel, center);
|
|
}
|
|
willActivate = false;
|
|
active = true;
|
|
updateActiveStateOnPedestals();
|
|
} catch (Exception ex) {
|
|
BetterEnd.LOGGER.error("Create End portals error.", ex);
|
|
removePortal(targetWorld, exit);
|
|
removePortal(world, center);
|
|
willActivate = false;
|
|
active = false;
|
|
updateActiveStateOnPedestals();
|
|
}
|
|
}
|
|
|
|
private void initPortal(Player player, ResourceLocation worldId, int portalId) {
|
|
targetWorldId = worldId;
|
|
if (world instanceof ServerLevel sourceWorld) {
|
|
ServerLevel targetLevel = (ServerLevel) getTargetWorld(portalId);
|
|
PortalBuilder builder = new PortalBuilder(world, targetLevel);
|
|
final WorldBorder worldBorder = targetLevel.getWorldBorder();
|
|
final Optional<BlockUtil.FoundRectangle> foundRectangle = builder.findPortalAround(
|
|
this.center,
|
|
worldBorder
|
|
);
|
|
|
|
if (!foundRectangle.isPresent()) {
|
|
Optional<BlockPos> centerPos;
|
|
centerPos = builder.createPortal(
|
|
PortalBuilder.getStartingPos(sourceWorld, targetLevel, player, worldBorder),
|
|
axis,
|
|
portalId
|
|
);
|
|
centerPos.ifPresent(blockPos -> this.exit = blockPos);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void doEffects(ServerLevel serverWorld, BlockPos center) {
|
|
Direction moveX, moveY;
|
|
if (Direction.Axis.X == axis) {
|
|
moveX = Direction.EAST;
|
|
moveY = Direction.NORTH;
|
|
} else {
|
|
moveX = Direction.SOUTH;
|
|
moveY = Direction.EAST;
|
|
}
|
|
for (Point pos : PEDESTAL_POSITIONS) {
|
|
BlockPos.MutableBlockPos p = center.mutable();
|
|
p.move(moveX, pos.x).move(moveY, pos.y);
|
|
serverWorld.sendParticles(
|
|
ParticleTypes.PORTAL,
|
|
p.getX() + 0.5, p.getY() + 1.5, p.getZ() + 0.5,
|
|
20,
|
|
0, 0, 0, 1
|
|
);
|
|
serverWorld.sendParticles(
|
|
ParticleTypes.REVERSE_PORTAL,
|
|
p.getX() + 0.5, p.getY() + 1.5, p.getZ() + 0.5,
|
|
20,
|
|
0, 0, 0, 0.3
|
|
);
|
|
}
|
|
serverWorld.playSound(null, center, SoundEvents.END_PORTAL_SPAWN, SoundSource.NEUTRAL, 16, 1);
|
|
}
|
|
|
|
private void activatePortal(Level world, BlockPos center, int portalId) {
|
|
BlockPos framePos = center.below();
|
|
Direction moveDir = Direction.Axis.X == axis ? Direction.NORTH : Direction.EAST;
|
|
BlockState frame = PortalBuilder.FRAME.defaultBlockState().setValue(ACTIVE, true);
|
|
PortalBuilder.FRAME_POSITIONS.forEach(point -> {
|
|
BlockPos pos = framePos.mutable().move(moveDir, point.x).move(Direction.UP, point.y);
|
|
BlockState state = world.getBlockState(pos);
|
|
if (state.hasProperty(ACTIVE) && !state.getValue(ACTIVE)) {
|
|
world.setBlockAndUpdate(pos, frame);
|
|
}
|
|
pos = framePos.mutable().move(moveDir, -point.x).move(Direction.UP, point.y);
|
|
state = world.getBlockState(pos);
|
|
if (state.hasProperty(ACTIVE) && !state.getValue(ACTIVE)) {
|
|
world.setBlockAndUpdate(pos, frame);
|
|
}
|
|
});
|
|
Direction.Axis portalAxis = Direction.Axis.X == axis ? Direction.Axis.Z : Direction.Axis.X;
|
|
BlockState portal = PortalBuilder.PORTAL.defaultBlockState()
|
|
.setValue(EndPortalBlock.AXIS, portalAxis)
|
|
.setValue(EndPortalBlock.PORTAL, portalId);
|
|
ParticleOptions effect = new BlockParticleOption(ParticleTypes.BLOCK, portal);
|
|
if (world instanceof ServerLevel serverWorld) {
|
|
PortalBuilder.PORTAL_POSITIONS.forEach(point -> {
|
|
BlockPos pos = center.mutable().move(moveDir, point.x).move(Direction.UP, point.y);
|
|
if (!world.getBlockState(pos).is(PortalBuilder.PORTAL)) {
|
|
world.setBlockAndUpdate(pos, portal);
|
|
serverWorld.sendParticles(
|
|
effect,
|
|
pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5,
|
|
10,
|
|
0.5, 0.5, 0.5, 0.1
|
|
);
|
|
serverWorld.sendParticles(
|
|
ParticleTypes.REVERSE_PORTAL,
|
|
pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5,
|
|
10,
|
|
0.5, 0.5, 0.5, 0.3
|
|
);
|
|
}
|
|
pos = center.mutable().move(moveDir, -point.x).move(Direction.UP, point.y);
|
|
if (!world.getBlockState(pos).is(PortalBuilder.PORTAL)) {
|
|
world.setBlockAndUpdate(pos, portal);
|
|
serverWorld.sendParticles(
|
|
effect,
|
|
pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5,
|
|
10,
|
|
0.5, 0.5, 0.5, 0.1
|
|
);
|
|
serverWorld.sendParticles(
|
|
ParticleTypes.REVERSE_PORTAL,
|
|
pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5,
|
|
10,
|
|
0.5, 0.5, 0.5, 0.3
|
|
);
|
|
}
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
public void disablePortal(int state) {
|
|
if (!active || isInvalid()) return;
|
|
if (!world.isClientSide())
|
|
removePortal(getTargetWorld(state), exit);
|
|
removePortal(world, center);
|
|
}
|
|
|
|
private void removePortal(Level world, BlockPos center) {
|
|
BlockPos framePos = center.below();
|
|
Direction moveDir = Direction.Axis.X == axis ? Direction.NORTH : Direction.EAST;
|
|
PortalBuilder.FRAME_POSITIONS.forEach(point -> {
|
|
BlockPos pos = framePos.mutable().move(moveDir, point.x).move(Direction.UP, point.y);
|
|
BlockState state = world.getBlockState(pos);
|
|
if (state.is(PortalBuilder.FRAME) && state.getValue(ACTIVE)) {
|
|
world.setBlockAndUpdate(pos, state.setValue(ACTIVE, false));
|
|
}
|
|
pos = framePos.mutable().move(moveDir, -point.x).move(Direction.UP, point.y);
|
|
state = world.getBlockState(pos);
|
|
if (state.is(PortalBuilder.FRAME) && state.getValue(ACTIVE)) {
|
|
world.setBlockAndUpdate(pos, state.setValue(ACTIVE, false));
|
|
}
|
|
});
|
|
PortalBuilder.PORTAL_POSITIONS.forEach(point -> {
|
|
BlockPos pos = center.mutable().move(moveDir, point.x).move(Direction.UP, point.y);
|
|
if (world.getBlockState(pos).is(PortalBuilder.PORTAL)) {
|
|
world.removeBlock(pos, false);
|
|
}
|
|
pos = center.mutable().move(moveDir, -point.x).move(Direction.UP, point.y);
|
|
if (world.getBlockState(pos).is(PortalBuilder.PORTAL)) {
|
|
world.removeBlock(pos, false);
|
|
}
|
|
});
|
|
this.active = false;
|
|
updateActiveStateOnPedestals();
|
|
}
|
|
|
|
private Level getTargetWorld(int state) {
|
|
if (world.dimension() == Level.END) {
|
|
return EndPortals.getWorld(world.getServer(), state);
|
|
}
|
|
return Objects.requireNonNull(world.getServer()).getLevel(Level.END);
|
|
}
|
|
|
|
public void configure(BlockPos initial) {
|
|
BlockPos checkPos = initial.east(12);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.axis = Direction.Axis.X;
|
|
this.center = initial.east(6);
|
|
return;
|
|
}
|
|
checkPos = initial.west(12);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.axis = Direction.Axis.X;
|
|
this.center = initial.west(6);
|
|
return;
|
|
}
|
|
checkPos = initial.south(12);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.axis = Direction.Axis.Z;
|
|
this.center = initial.south(6);
|
|
return;
|
|
}
|
|
checkPos = initial.north(12);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.axis = Direction.Axis.Z;
|
|
this.center = initial.north(6);
|
|
return;
|
|
}
|
|
checkPos = initial.north(10);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.axis = Direction.Axis.X;
|
|
checkPos = checkPos.east(8);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.center = initial.north(5).east(4);
|
|
} else {
|
|
this.center = initial.north(5).west(4);
|
|
}
|
|
return;
|
|
}
|
|
checkPos = initial.south(10);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.axis = Direction.Axis.X;
|
|
checkPos = checkPos.east(8);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.center = initial.south(5).east(4);
|
|
} else {
|
|
this.center = initial.south(5).west(4);
|
|
}
|
|
return;
|
|
}
|
|
checkPos = initial.east(10);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.axis = Direction.Axis.Z;
|
|
checkPos = checkPos.south(8);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.center = initial.east(5).south(4);
|
|
} else {
|
|
this.center = initial.east(5).north(4);
|
|
}
|
|
return;
|
|
}
|
|
checkPos = initial.west(10);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.axis = Direction.Axis.Z;
|
|
checkPos = checkPos.south(8);
|
|
if (this.hasPedestal(checkPos)) {
|
|
this.center = initial.west(5).south(4);
|
|
} else {
|
|
this.center = initial.west(5).north(4);
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean hasPedestal(BlockPos pos) {
|
|
return world.getBlockState(pos).is(PEDESTAL);
|
|
}
|
|
|
|
private boolean isActive(BlockPos pos) {
|
|
BlockState state = world.getBlockState(pos);
|
|
if (state.is(PEDESTAL)) {
|
|
EternalPedestalEntity pedestal = (EternalPedestalEntity) world.getBlockEntity(pos);
|
|
if (pedestal != null) {
|
|
if (!pedestal.hasRitual()) {
|
|
pedestal.linkRitual(this);
|
|
} else {
|
|
EternalRitual ritual = pedestal.getRitual();
|
|
if (!ritual.equals(this)) {
|
|
pedestal.linkRitual(this);
|
|
}
|
|
}
|
|
}
|
|
return state.getValue(ACTIVE);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public CompoundTag toTag(CompoundTag tag) {
|
|
if (this.center == null || this.axis == null || this.exit == null) return null;
|
|
tag.put("center", NbtUtils.writeBlockPos(center));
|
|
tag.putString("axis", axis.getName());
|
|
tag.putBoolean("active", active);
|
|
if (targetWorldId != null) {
|
|
tag.putString("key_item", targetWorldId.toString());
|
|
}
|
|
if (exit != null) {
|
|
tag.put("exit", NbtUtils.writeBlockPos(exit));
|
|
}
|
|
return tag;
|
|
}
|
|
|
|
public void fromTag(CompoundTag tag) {
|
|
axis = Direction.Axis.byName(tag.getString("axis"));
|
|
center = NbtUtils.readBlockPos(tag.getCompound("center"));
|
|
active = tag.getBoolean("active");
|
|
if (tag.contains("exit")) {
|
|
exit = NbtUtils.readBlockPos(tag.getCompound("exit"));
|
|
}
|
|
if (tag.contains("key_item")) {
|
|
targetWorldId = new ResourceLocation(tag.getString("key_item"));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object o) {
|
|
if (this == o) return true;
|
|
if (o == null || getClass() != o.getClass()) return false;
|
|
EternalRitual ritual = (EternalRitual) o;
|
|
return world.equals(ritual.world) && Objects.equals(center, ritual.center) && Objects.equals(exit, ritual.exit);
|
|
}
|
|
|
|
public static EternalRitual findRitualForActivePortal(Level world, BlockPos startPos) {
|
|
BlockState state = world.getBlockState(startPos);
|
|
|
|
if (isActivePortalBlock(state)) {
|
|
final var direction = state.getValue(NetherPortalBlock.AXIS) == Direction.Axis.X
|
|
? Direction.EAST
|
|
: Direction.NORTH;
|
|
while (world.getBlockState(startPos.below()).is(EndBlocks.END_PORTAL_BLOCK)) {
|
|
startPos = startPos.below();
|
|
}
|
|
|
|
// X O O O O O X
|
|
// X O O O O O X
|
|
// X a c O c b X
|
|
// X a O b X
|
|
// X X X
|
|
|
|
|
|
if (world.getBlockState(startPos.relative(direction, -1)).is(EndBlocks.FLAVOLITE_RUNED_ETERNAL))
|
|
startPos = startPos.relative(direction, 1); //pos (a)
|
|
else if (world.getBlockState(startPos.relative(direction, 1)).is(EndBlocks.FLAVOLITE_RUNED_ETERNAL))
|
|
startPos = startPos.relative(direction, -1); //pos (b)
|
|
|
|
if (!world.getBlockState(startPos.below()).is(EndBlocks.FLAVOLITE_RUNED_ETERNAL))
|
|
startPos = startPos.below(); //pos (c)
|
|
|
|
if (world.getBlockState(startPos.relative(direction, -1)).is(EndBlocks.FLAVOLITE_RUNED_ETERNAL))
|
|
startPos = startPos.relative(direction, 1); //pos (a)
|
|
else if (world.getBlockState(startPos.relative(direction, 1)).is(EndBlocks.FLAVOLITE_RUNED_ETERNAL))
|
|
startPos = startPos.relative(direction, -1); //pos (b)
|
|
|
|
startPos = startPos.relative(direction.getClockWise(), 6);
|
|
state = world.getBlockState(startPos);
|
|
if (state.is(EndBlocks.ETERNAL_PEDESTAL) && world.getBlockEntity(startPos) instanceof EternalPedestalEntity pedestal) {
|
|
return pedestal.getRitual();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static boolean isActivePortalBlock(BlockState state) {
|
|
return state.is(EndBlocks.END_PORTAL_BLOCK)
|
|
&& state.hasProperty(NetherPortalBlock.AXIS);
|
|
}
|
|
}
|