package net.minecraft.world.level.block; import com.mojang.serialization.MapCodec; import java.util.Set; 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.entity.InsideBlockEffectApplier; import net.minecraft.world.entity.Relative; 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.TeleportTransition; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; public class EndPortalBlock extends BaseEntityBlock implements Portal { public static final MapCodec CODEC = simpleCodec(EndPortalBlock::new); private static final VoxelShape SHAPE = Block.column(16.0, 6.0, 12.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 VoxelShape getEntityInsideCollisionShape(BlockState state, BlockGetter level, BlockPos pos, Entity entity) { return state.getShape(level, pos); } @Override protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier) { if (entity.canUsePortal(false)) { if (!level.isClientSide && level.dimension() == Level.END && entity instanceof ServerPlayer serverPlayer && !serverPlayer.seenCredits) { serverPlayer.showEndCredits(); } else { entity.setAsInsidePortal(this, pos); } } } @Override public TeleportTransition 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; Set set; if (bl) { EndPlatformFeature.createEndPlatform(serverLevel, BlockPos.containing(vec3).below(), true); f = Direction.WEST.toYRot(); set = Relative.union(Relative.DELTA, Set.of(Relative.X_ROT)); if (entity instanceof ServerPlayer) { vec3 = vec3.subtract(0.0, 1.0, 0.0); } } else { f = 0.0F; set = Relative.union(Relative.DELTA, Relative.ROTATION); if (entity instanceof ServerPlayer serverPlayer) { return serverPlayer.findRespawnPositionAndUseSpawnBlock(false, TeleportTransition.DO_NOTHING); } vec3 = entity.adjustSpawnLocation(serverLevel, blockPos).getBottomCenter(); } return new TeleportTransition(serverLevel, vec3, Vec3.ZERO, f, 0.0F, set, TeleportTransition.PLAY_PORTAL_SOUND.then(TeleportTransition.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 protected ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState state, boolean includeData) { return ItemStack.EMPTY; } @Override protected boolean canBeReplaced(BlockState state, Fluid fluid) { return false; } @Override protected RenderShape getRenderShape(BlockState state) { return RenderShape.INVISIBLE; } }