package com.thebrokenrail.energonrelics.block.portal; import com.thebrokenrail.energonrelics.EnergonRelics; import com.thebrokenrail.energonrelics.api.block.SimpleBlock; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.ShapeContext; import net.minecraft.block.piston.PistonBehavior; import net.minecraft.entity.Entity; import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; import net.minecraft.util.function.BooleanBiFunction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShapes; import net.minecraft.world.BlockView; import net.minecraft.world.World; import net.minecraft.world.WorldAccess; import java.util.Random; @SuppressWarnings("deprecation") public class EnergyPortalBlock extends SimpleBlock { public EnergyPortalBlock() { super(FabricBlockSettings.copy(Blocks.NETHER_PORTAL).dropsNothing().emissiveLighting((state, world, pos) -> true).noCollision()); } @Override protected boolean registerItem() { return false; } private static final VoxelShape SHAPE = createCuboidShape(0, 6, 0, 16, 10, 16); @Override public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) { return SHAPE; } public static boolean isValidDirection(Direction dir) { return dir != Direction.UP && dir != Direction.DOWN; } private static boolean isObsidian(BlockState state) { return state.getBlock() == Blocks.OBSIDIAN || state.getBlock() == EnergonRelics.ENERGIZED_OBSIDIAN_BLOCK; } public static boolean isValidFrame(WorldAccess world, BlockPos centerPos) { int validSides = 0; for (Direction side : Direction.values()) { if (isValidDirection(side)) { BlockPos energizedPos = centerPos.offset(side, 2); BlockState energizedObsidian = world.getBlockState(energizedPos); if (energizedObsidian.getBlock() == EnergonRelics.ENERGIZED_OBSIDIAN_BLOCK) { BlockState obsidian1 = world.getBlockState(energizedPos.offset(side.rotateYClockwise(), 1)); BlockState obsidian2 = world.getBlockState(energizedPos.offset(side.rotateYCounterclockwise(), 1)); if (isObsidian(obsidian1) && isObsidian(obsidian2)) { validSides++; } } } } return validSides == 4; } static BlockPos getCenterPos(WorldAccess world, BlockPos pos) { BlockPos centerPos = pos; for (Direction side : Direction.values()) { if (isValidDirection(side)) { if (world.getBlockState(pos.offset(side)).getBlock() != EnergonRelics.ENERGY_PORTAL_BLOCK) { centerPos = centerPos.offset(side.getOpposite()); } } } return centerPos; } private static boolean isValidCenter(WorldAccess world, BlockPos centerPos) { boolean valid = true; BlockPos startPos = centerPos.add(-1, 0, -1); for (int x = 0; x < 3; x++) { for (int z = 0; z < 3; z++) { if (world.getBlockState(startPos.add(x, 0, z)).getBlock() != EnergonRelics.ENERGY_PORTAL_BLOCK) { valid = false; break; } } } return valid; } public static void fillFrame(WorldAccess world, BlockPos centerPos) { BlockPos startPos = centerPos.add(-1, 0, -1); for (int x = 0; x < 3; x++) { for (int z = 0; z < 3; z++) { BlockState state = world.getBlockState(startPos.add(x, 0, z)); if (state.getBlock() != EnergonRelics.ENERGY_PORTAL_BLOCK && !state.isAir()) { return; } } } for (int x = 0; x < 3; x++) { for (int z = 0; z < 3; z++) { world.setBlockState(startPos.add(x, 0, z), EnergonRelics.ENERGY_PORTAL_BLOCK.getDefaultState(), 3 | 16); } } } @Override public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState newState, WorldAccess world, BlockPos pos, BlockPos posFrom) { boolean valid; if (isValidDirection(direction)) { BlockPos centerPos = getCenterPos(world, pos); boolean isValidFrame = isValidFrame(world, centerPos); boolean isValidCenter = isValidCenter(world, centerPos); valid = isValidCenter && isValidFrame; } else { valid = true; } if (valid) { return super.getStateForNeighborUpdate(state, direction, newState, world, pos, posFrom); } else { return Blocks.AIR.getDefaultState(); } } @Override public PistonBehavior getPistonBehavior(BlockState state) { return PistonBehavior.BLOCK; } @Override public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) { super.onEntityCollision(state, world, pos, entity); if (!world.isClient() && !entity.hasVehicle() && entity.canUsePortals() && !((PortalCooldownEntity) entity).isEnergyPortalCooldown() && VoxelShapes.matchesAnywhere(VoxelShapes.cuboid(entity.getBoundingBox().offset(-pos.getX(), -pos.getY(), -pos.getZ())), state.getOutlineShape(world, pos), BooleanBiFunction.AND)) { ((PortalCooldownEntity) entity).resetEnergyPortalCooldown(); EnergyTeleporter.teleport((ServerWorld) world, entity.getPos(), pos, entity); } } @Override @Environment(EnvType.CLIENT) public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) { super.randomDisplayTick(state, world, pos, random); if (random.nextInt(100) == 0) { world.playSound((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, SoundEvents.BLOCK_PORTAL_AMBIENT, SoundCategory.BLOCKS, 0.5f, random.nextFloat() * 0.4f + 0.8f, false); } } }