/******************************************************************************* * AbyssalCraft * Copyright (c) 2012 - 2017 Shinoow. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v3 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl-3.0.txt * * Contributors: * Shinoow - implementation ******************************************************************************/ package com.shinoow.abyssalcraft.common.world; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectIterator; import java.util.Random; import net.minecraft.block.Block; import net.minecraft.block.BlockPortal; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.MathHelper; import net.minecraft.world.Teleporter; import net.minecraft.world.WorldServer; import net.minecraftforge.fml.relauncher.ReflectionHelper; public class TeleporterAC extends Teleporter { private final WorldServer worldServerInstance; private final Random random; private final Long2ObjectMap<Teleporter.PortalPosition> destinationCoordinateCache = new Long2ObjectOpenHashMap(4096); private final Block portal, frame; public TeleporterAC(WorldServer par1WorldServer, Block portal, Block frame) { super(par1WorldServer); worldServerInstance = par1WorldServer; random = new Random(par1WorldServer.getSeed()); this.portal = portal; this.frame = frame; } @Override public void placeInPortal(Entity entityIn, float rotationYaw) { if (worldServerInstance.provider.getDimension() != 1) { if (entityIn instanceof EntityPlayerMP && !((EntityPlayerMP)entityIn).capabilities.isCreativeMode) ReflectionHelper.setPrivateValue(EntityPlayerMP.class, (EntityPlayerMP)entityIn, true, "invulnerableDimensionChange", "field_184851_cj"); if (!placeInExistingPortal(entityIn, rotationYaw)) { makePortal(entityIn); placeInExistingPortal(entityIn, rotationYaw); } } else { int i = MathHelper.floor(entityIn.posX); int j = MathHelper.floor(entityIn.posY) - 1; int k = MathHelper.floor(entityIn.posZ); int l = 1; int i1 = 0; for (int j1 = -2; j1 <= 2; ++j1) for (int k1 = -2; k1 <= 2; ++k1) for (int l1 = -1; l1 < 3; ++l1) { int i2 = i + k1 * l + j1 * i1; int j2 = j + l1; int k2 = k + k1 * i1 - j1 * l; boolean flag = l1 < 0; worldServerInstance.setBlockState(new BlockPos(i2, j2, k2), flag ? frame.getDefaultState() : Blocks.AIR.getDefaultState()); } entityIn.setLocationAndAngles(i, j, k, entityIn.rotationYaw, 0.0F); entityIn.motionX = entityIn.motionY = entityIn.motionZ = 0.0D; } } @SuppressWarnings("unchecked") @Override public boolean placeInExistingPortal(Entity entityIn, float p_180620_2_) { double d0 = -1.0D; int i = MathHelper.floor(entityIn.posX); int j = MathHelper.floor(entityIn.posZ); boolean flag1 = true; Object object = BlockPos.ORIGIN; long k = ChunkPos.asLong(i, j); if (destinationCoordinateCache.containsKey(k)) { Teleporter.PortalPosition portalposition = destinationCoordinateCache.get(k); d0 = 0.0D; object = portalposition; portalposition.lastUpdateTime = worldServerInstance.getTotalWorldTime(); flag1 = false; } else { BlockPos blockpos4 = new BlockPos(entityIn); for (int l = -128; l <= 128; ++l) { BlockPos blockpos1; for (int i1 = -128; i1 <= 128; ++i1) for (BlockPos blockpos = blockpos4.add(l, worldServerInstance.getActualHeight() - 1 - blockpos4.getY(), i1); blockpos.getY() >= 0; blockpos = blockpos1) { blockpos1 = blockpos.down(); if (worldServerInstance.getBlockState(blockpos).getBlock() == portal) { while (worldServerInstance.getBlockState(blockpos1 = blockpos.down()).getBlock() == portal) blockpos = blockpos1; double d1 = blockpos.distanceSq(blockpos4); if (d0 < 0.0D || d1 < d0) { d0 = d1; object = blockpos; } } } } } if (d0 >= 0.0D) { if (flag1) destinationCoordinateCache.put(k, new Teleporter.PortalPosition((BlockPos) object, worldServerInstance.getTotalWorldTime())); double d4 = ((BlockPos) object).getX() + 0.5D; double d5 = ((BlockPos) object).getY() + 0.5D; double d6 = ((BlockPos) object).getZ() + 0.5D; EnumFacing enumfacing = null; if (worldServerInstance.getBlockState(((BlockPos) object).west()).getBlock() == portal) enumfacing = EnumFacing.NORTH; if (worldServerInstance.getBlockState(((BlockPos) object).east()).getBlock() == portal) enumfacing = EnumFacing.SOUTH; if (worldServerInstance.getBlockState(((BlockPos) object).north()).getBlock() == portal) enumfacing = EnumFacing.EAST; if (worldServerInstance.getBlockState(((BlockPos) object).south()).getBlock() == portal) enumfacing = EnumFacing.WEST; EnumFacing enumfacing1 = EnumFacing.getHorizontal(MathHelper.floor(entityIn.rotationYaw * 4.0F / 360.0F + 0.5D) & 3); if (enumfacing != null) { EnumFacing enumfacing2 = enumfacing.rotateYCCW(); BlockPos blockpos2 = ((BlockPos) object).offset(enumfacing); boolean flag2 = func_180265_a(blockpos2); boolean flag3 = func_180265_a(blockpos2.offset(enumfacing2)); if (flag3 && flag2) { object = ((BlockPos) object).offset(enumfacing2); enumfacing = enumfacing.getOpposite(); enumfacing2 = enumfacing2.getOpposite(); BlockPos blockpos3 = ((BlockPos) object).offset(enumfacing); flag2 = func_180265_a(blockpos3); flag3 = func_180265_a(blockpos3.offset(enumfacing2)); } float f6 = 0.5F; float f1 = 0.5F; if (!flag3 && flag2) f6 = 1.0F; else if (flag3 && !flag2) f6 = 0.0F; else if (flag3) f1 = 0.0F; d4 = ((BlockPos) object).getX() + 0.5D; d5 = ((BlockPos) object).getY() + 0.5D; d6 = ((BlockPos) object).getZ() + 0.5D; d4 += enumfacing2.getFrontOffsetX() * f6 + enumfacing.getFrontOffsetX() * f1; d6 += enumfacing2.getFrontOffsetZ() * f6 + enumfacing.getFrontOffsetZ() * f1; float f2 = 0.0F; float f3 = 0.0F; float f4 = 0.0F; float f5 = 0.0F; if (enumfacing == enumfacing1) { f2 = 1.0F; f3 = 1.0F; } else if (enumfacing == enumfacing1.getOpposite()) { f2 = -1.0F; f3 = -1.0F; } else if (enumfacing == enumfacing1.rotateY()) { f4 = 1.0F; f5 = -1.0F; } else { f4 = -1.0F; f5 = 1.0F; } double d2 = entityIn.motionX; double d3 = entityIn.motionZ; entityIn.motionX = d2 * f2 + d3 * f5; entityIn.motionZ = d2 * f4 + d3 * f3; entityIn.rotationYaw = p_180620_2_ - enumfacing1.getHorizontalIndex() * 90 + enumfacing.getHorizontalIndex() * 90; } else entityIn.motionX = entityIn.motionY = entityIn.motionZ = 0.0D; entityIn.setLocationAndAngles(d4, d5, d6, entityIn.rotationYaw, entityIn.rotationPitch); return true; } else return false; } private boolean func_180265_a(BlockPos p_180265_1_) { return !worldServerInstance.isAirBlock(p_180265_1_) || !worldServerInstance.isAirBlock(p_180265_1_.up()); } @Override public boolean makePortal(Entity p_85188_1_) { int i = 16; double d0 = -1.0D; int j = MathHelper.floor(p_85188_1_.posX); int k = MathHelper.floor(p_85188_1_.posY); int l = MathHelper.floor(p_85188_1_.posZ); int i1 = j; int j1 = k; int k1 = l; int l1 = 0; int i2 = random.nextInt(4); BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(); for (int j2 = j - i; j2 <= j + i; ++j2) { double d1 = j2 + 0.5D - p_85188_1_.posX; for (int l2 = l - i; l2 <= l + i; ++l2) { double d2 = l2 + 0.5D - p_85188_1_.posZ; label142: for (int j3 = worldServerInstance.getActualHeight() - 1; j3 >= 0; --j3) if (worldServerInstance.isAirBlock(blockpos$mutableblockpos.setPos(j2, j3, l2))) { while (j3 > 0 && worldServerInstance.isAirBlock(blockpos$mutableblockpos.setPos(j2, j3 - 1, l2))) --j3; for (int k3 = i2; k3 < i2 + 4; ++k3) { int l3 = k3 % 2; int i4 = 1 - l3; if (k3 % 4 >= 2) { l3 = -l3; i4 = -i4; } for (int j4 = 0; j4 < 3; ++j4) for (int k4 = 0; k4 < 4; ++k4) for (int l4 = -1; l4 < 4; ++l4) { int i5 = j2 + (k4 - 1) * l3 + j4 * i4; int j5 = j3 + l4; int k5 = l2 + (k4 - 1) * i4 - j4 * l3; blockpos$mutableblockpos.setPos(i5, j5, k5); if (l4 < 0 && !worldServerInstance.getBlockState(blockpos$mutableblockpos).getMaterial().isSolid() || l4 >= 0 && !worldServerInstance.isAirBlock(blockpos$mutableblockpos)) continue label142; } double d5 = j3 + 0.5D - p_85188_1_.posY; double d7 = d1 * d1 + d5 * d5 + d2 * d2; if (d0 < 0.0D || d7 < d0) { d0 = d7; i1 = j2; j1 = j3; k1 = l2; l1 = k3 % 4; } } } } } if (d0 < 0.0D) for (int l5 = j - i; l5 <= j + i; ++l5) { double d3 = l5 + 0.5D - p_85188_1_.posX; for (int j6 = l - i; j6 <= l + i; ++j6) { double d4 = j6 + 0.5D - p_85188_1_.posZ; label562: for (int i7 = worldServerInstance.getActualHeight() - 1; i7 >= 0; --i7) if (worldServerInstance.isAirBlock(blockpos$mutableblockpos.setPos(l5, i7, j6))) { while (i7 > 0 && worldServerInstance.isAirBlock(blockpos$mutableblockpos.setPos(l5, i7 - 1, j6))) --i7; for (int k7 = i2; k7 < i2 + 2; ++k7) { int j8 = k7 % 2; int j9 = 1 - j8; for (int j10 = 0; j10 < 4; ++j10) for (int j11 = -1; j11 < 4; ++j11) { int j12 = l5 + (j10 - 1) * j8; int i13 = i7 + j11; int j13 = j6 + (j10 - 1) * j9; blockpos$mutableblockpos.setPos(j12, i13, j13); if (j11 < 0 && !worldServerInstance.getBlockState(blockpos$mutableblockpos).getMaterial().isSolid() || j11 >= 0 && !worldServerInstance.isAirBlock(blockpos$mutableblockpos)) continue label562; } double d6 = i7 + 0.5D - p_85188_1_.posY; double d8 = d3 * d3 + d6 * d6 + d4 * d4; if (d0 < 0.0D || d8 < d0) { d0 = d8; i1 = l5; j1 = i7; k1 = j6; l1 = k7 % 2; } } } } } int i6 = i1; int k2 = j1; int k6 = k1; int l6 = l1 % 2; int i3 = 1 - l6; if (l1 % 4 >= 2) { l6 = -l6; i3 = -i3; } if (d0 < 0.0D) { j1 = MathHelper.clamp(j1, 70, worldServerInstance.getActualHeight() - 10); k2 = j1; for (int j7 = -1; j7 <= 1; ++j7) for (int l7 = 1; l7 < 3; ++l7) for (int k8 = -1; k8 < 3; ++k8) { int k9 = i6 + (l7 - 1) * l6 + j7 * i3; int k10 = k2 + k8; int k11 = k6 + (l7 - 1) * i3 - j7 * l6; boolean flag = k8 < 0; worldServerInstance.setBlockState(new BlockPos(k9, k10, k11), flag ? frame.getDefaultState() : Blocks.AIR.getDefaultState()); } } IBlockState iblockstate = portal.getDefaultState().withProperty(BlockPortal.AXIS, l6 != 0 ? EnumFacing.Axis.X : EnumFacing.Axis.Z); for (int i8 = 0; i8 < 4; ++i8) { for (int l8 = 0; l8 < 4; ++l8) for (int l9 = -1; l9 < 4; ++l9) { int l10 = i6 + (l8 - 1) * l6; int l11 = k2 + l9; int k12 = k6 + (l8 - 1) * i3; boolean flag1 = l8 == 0 || l8 == 3 || l9 == -1 || l9 == 3; worldServerInstance.setBlockState(new BlockPos(l10, l11, k12), flag1 ? frame.getDefaultState() : iblockstate, 2); } for (int i9 = 0; i9 < 4; ++i9) for (int i10 = -1; i10 < 4; ++i10) { int i11 = i6 + (i9 - 1) * l6; int i12 = k2 + i10; int l12 = k6 + (i9 - 1) * i3; BlockPos blockpos = new BlockPos(i11, i12, l12); worldServerInstance.notifyNeighborsOfStateChange(blockpos, worldServerInstance.getBlockState(blockpos).getBlock(), false); } } return true; } @SuppressWarnings("rawtypes") @Override public void removeStalePortalLocations(long worldTime) { if (worldTime % 100L == 0L) { long i = worldTime - 300L; ObjectIterator<Teleporter.PortalPosition> objectiterator = destinationCoordinateCache.values().iterator(); while (objectiterator.hasNext()) { Teleporter.PortalPosition teleporter$portalposition = objectiterator.next(); if (teleporter$portalposition == null || teleporter$portalposition.lastUpdateTime < i) objectiterator.remove(); } } } }