package net.minecraft.world.level.block; import com.mojang.serialization.MapCodec; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.RandomSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.feature.EndPlatformFeature; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.portal.DimensionTransition; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.BooleanOp; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; public class EndPortalBlock extends BaseEntityBlock implements Portal { public static final MapCodec CODEC = simpleCodec(EndPortalBlock::new); protected static final VoxelShape SHAPE = Block.box(0.0, 6.0, 0.0, 16.0, 12.0, 16.0); @Override public MapCodec codec() { return CODEC; } protected EndPortalBlock(BlockBehaviour.Properties properties) { super(properties); } @Override public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { return new TheEndPortalBlockEntity(pos, state); } @Override protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { return SHAPE; } @Override protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) { if (entity.canUsePortal(false) && Shapes.joinIsNotEmpty(Shapes.create(entity.getBoundingBox().move(-pos.getX(), -pos.getY(), -pos.getZ())), state.getShape(level, pos), BooleanOp.AND)) { if (!level.isClientSide && level.dimension() == Level.END && entity instanceof ServerPlayer serverPlayer && !serverPlayer.seenCredits) { serverPlayer.showEndCredits(); } else { entity.setAsInsidePortal(this, pos); } } } @Override public DimensionTransition getPortalDestination(ServerLevel level, Entity entity, BlockPos pos) { ResourceKey resourceKey = level.dimension() == Level.END ? Level.OVERWORLD : Level.END; ServerLevel serverLevel = level.getServer().getLevel(resourceKey); if (serverLevel == null) { return null; } else { boolean bl = resourceKey == Level.END; BlockPos blockPos = bl ? ServerLevel.END_SPAWN_POINT : serverLevel.getSharedSpawnPos(); Vec3 vec3 = blockPos.getBottomCenter(); float f = entity.getYRot(); if (bl) { EndPlatformFeature.createEndPlatform(serverLevel, BlockPos.containing(vec3).below(), true); f = Direction.WEST.toYRot(); if (entity instanceof ServerPlayer) { vec3 = vec3.subtract(0.0, 1.0, 0.0); } } else { if (entity instanceof ServerPlayer serverPlayer) { return serverPlayer.findRespawnPositionAndUseSpawnBlock(false, DimensionTransition.DO_NOTHING); } vec3 = entity.adjustSpawnLocation(serverLevel, blockPos).getBottomCenter(); } return new DimensionTransition( serverLevel, vec3, entity.getDeltaMovement(), f, entity.getXRot(), DimensionTransition.PLAY_PORTAL_SOUND.then(DimensionTransition.PLACE_PORTAL_TICKET) ); } } @Override public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) { double d = pos.getX() + random.nextDouble(); double e = pos.getY() + 0.8; double f = pos.getZ() + random.nextDouble(); level.addParticle(ParticleTypes.SMOKE, d, e, f, 0.0, 0.0, 0.0); } @Override public ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState state) { return ItemStack.EMPTY; } @Override protected boolean canBeReplaced(BlockState state, Fluid fluid) { return false; } }