package erebus.world.teleporter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.entity.Entity;
import net.minecraft.init.Blocks;
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;
final class TeleporterErebus extends Teleporter {
private final WorldServer worldServerInstance;
private final Long2ObjectMap<Teleporter.PortalPosition> destinationCoordinateCache = new Long2ObjectOpenHashMap<Teleporter.PortalPosition>(4096);
private final List<Long> destinationCoordinateKeys = new ArrayList<Long>();
TeleporterErebus(WorldServer worldServer) {
super(worldServer);
worldServerInstance = worldServer;
}
@Override
public void placeInPortal(Entity entityIn, float rotationYaw) {
if (!placeInExistingPortal(entityIn, rotationYaw)) {
makePortal(entityIn);
placeInExistingPortal(entityIn, rotationYaw);
}
}
@Override
public boolean placeInExistingPortal(Entity entityIn, float rotationYaw) {
int checkRadius = 32;
double distToPortal = -1.0;
int posX = 0;
int posY = 0;
int posZ = 0;
int roundX = MathHelper.floor_double(entityIn.posX);
int roundZ = MathHelper.floor_double(entityIn.posZ);
long coordPair = ChunkPos.chunkXZ2Int(roundX, roundZ);
boolean portalNotSaved = true;
BlockPos blockpos = BlockPos.ORIGIN;
if (destinationCoordinateCache.containsKey(coordPair)) {
PortalPosition pos = destinationCoordinateCache.get(coordPair);
distToPortal = 0.0;
posX = pos.getX();
posY = pos.getY();
posZ = pos.getZ();
pos.lastUpdateTime = worldServerInstance.getTotalWorldTime();
portalNotSaved = false;
} else
for (int i = roundX - checkRadius; i <= roundX + checkRadius; i++)
for (int j = roundZ - checkRadius; j <= roundZ + checkRadius; j++)
for (int h = worldServerInstance.getActualHeight() - 1; h >= 0; h--)
if (worldServerInstance.getBlockState(new BlockPos(i, h, j)).getBlock() == Blocks.STONE) { //ModBlocks.gaeanKeystone
double X = i + 0.5 - entityIn.posX;
double Z = j + 0.5 - entityIn.posZ;
double Y = h - 2 + 0.5 - entityIn.posY;
double dist = X * X + Z * Z + Y * Y;
if (distToPortal < 0.0 || dist < distToPortal) {
distToPortal = dist;
blockpos.add(i, h, j);
posX = i;
posY = h;
posZ = j;
}
}
if (distToPortal >= 0.0) {
if (portalNotSaved) {
destinationCoordinateCache.put(coordPair, new Teleporter.PortalPosition(blockpos, worldServerInstance.getTotalWorldTime()));
destinationCoordinateKeys.add(Long.valueOf(coordPair));
}
entityIn.motionX = entityIn.motionY = entityIn.motionZ = 0.0;
int entityFacing = MathHelper.floor_double(entityIn.rotationYaw * 4.0F / 360.0F + 0.5D) & 3;
float entityRotation = 0;
double offsetX = 0;
double offsetZ = 0;
switch (entityFacing) {
case 0:
entityRotation = 180;
offsetX = 0.5D;
offsetZ = -0.5D;
break;
case 1:
entityRotation = 270;
offsetX = 1.5D;
offsetZ = 0.5D;
break;
case 2:
entityRotation = 0;
offsetX = 0.5D;
offsetZ = 1.5D;
break;
case 3:
entityRotation = 90;
offsetX = -0.5D;
offsetZ = 0.5D;
break;
}
entityIn.setLocationAndAngles(posX + offsetX, posY, posZ + offsetZ, entityRotation, entityIn.rotationPitch);
return true;
}
return false;
}
@Override
public boolean makePortal(Entity entity) {
//attempt at constraining the portal height in the Erebus
double safeHeight = Math.min(Math.max(entity.posY * 0.5D, 12), 116);
int x = MathHelper.floor_double(entity.posX);
int y = MathHelper.floor_double(safeHeight) - 2;
int z = MathHelper.floor_double(entity.posZ);
for (int i = -2; i <= 2; i++)
for (int j = 0; j <= 3; j++)
for (int k = -2; k <= 2; k++)
worldServerInstance.setBlockToAir(new BlockPos(x + i, y + j, z + k));
/*
// Layer -1
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
if (worldServerInstance.getBlockState(x + i, y - 1, z + j).getBlockHardness(worldServerInstance, x + i, y - 2, z + j) >= 0)
worldServerInstance.setBlock(x + i, y - 2, z + j, Blocks.stonebrick, 3, 3);
// Layer 0
worldServerInstance.setBlock(x, y - 1, z, Blocks.stonebrick, 3, 3);
worldServerInstance.setBlock(x - 1, y - 1, z, ModBlocks.redGem);
worldServerInstance.setBlock(x, y - 1, z - 1, ModBlocks.redGem);
worldServerInstance.setBlock(x + 1, y - 1, z, ModBlocks.redGem);
worldServerInstance.setBlock(x, y - 1, z + 1, ModBlocks.redGem);
worldServerInstance.setBlock(x - 1, y - 1, z + 1, Blocks.stonebrick);
worldServerInstance.setBlock(x + 1, y - 1, z - 1, Blocks.stonebrick);
worldServerInstance.setBlock(x - 1, y - 1, z - 1, Blocks.stonebrick);
worldServerInstance.setBlock(x + 1, y - 1, z + 1, Blocks.stonebrick);
// Layer 1
worldServerInstance.setBlock(x - 1, y, z + 1, Blocks.stonebrick);
worldServerInstance.setBlock(x + 1, y, z - 1, Blocks.stonebrick);
worldServerInstance.setBlock(x - 1, y, z - 1, Blocks.stonebrick);
worldServerInstance.setBlock(x + 1, y, z + 1, Blocks.stonebrick);
// Layer 2
worldServerInstance.setBlock(x - 1, y + 1, z + 1, Blocks.stonebrick);
worldServerInstance.setBlock(x + 1, y + 1, z - 1, Blocks.stonebrick);
worldServerInstance.setBlock(x - 1, y + 1, z - 1, Blocks.stonebrick);
worldServerInstance.setBlock(x + 1, y + 1, z + 1, Blocks.stonebrick);
// Layer 3
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
if (i == 0 && j == 0)
worldServerInstance.setBlock(x + i, y + 2, z + j, ModBlocks.gaeanKeystone);
else
worldServerInstance.setBlock(x + i, y + 2, z + j, Blocks.stone_slab, 5, 3);
int height = y + 3;
while (worldServerInstance.getBlockState(x, height, z).getBlockHardness(worldServerInstance, x, height, z) >= 0) {
worldServerInstance.setBlockToAir(x, height, z);
height++;
}
*/
return true;
}
@Override
public void removeStalePortalLocations(long timer) {
if (timer % 100L == 0L) {
Iterator<Long> iterator = destinationCoordinateKeys.iterator();
while (iterator.hasNext()) {
Long hashedPortalPos = iterator.next();
PortalPosition position = destinationCoordinateCache.get(hashedPortalPos.longValue());
if (position == null || position.lastUpdateTime < timer - 600L) {
iterator.remove();
destinationCoordinateCache.remove(hashedPortalPos.longValue());
}
}
}
}
}