package blusunrize.immersiveengineering.common.util;
import blusunrize.immersiveengineering.api.ApiUtils;
import blusunrize.immersiveengineering.api.energy.wires.IImmersiveConnectable;
import blusunrize.immersiveengineering.api.energy.wires.ImmersiveNetHandler;
import blusunrize.immersiveengineering.api.energy.wires.ImmersiveNetHandler.Connection;
import blusunrize.immersiveengineering.common.entities.EntitySkylineHook;
import blusunrize.immersiveengineering.common.items.ItemSkyhook;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import java.util.Set;
public class SkylineHelper
{
public static Connection getTargetConnection(World world, BlockPos pos, EntityLivingBase living, Connection invalidCon)
{
if(!(world.getTileEntity(pos) instanceof IImmersiveConnectable))
return null;
Set<Connection> outputs = ImmersiveNetHandler.INSTANCE.getConnections(world, pos);
if(outputs!=null && outputs.size()>0)
{
Vec3d vec = living.getLookVec();
vec = vec.normalize();
Connection line = null;
for(Connection c : outputs)
if(c!=null && !c.hasSameConnectors(invalidCon)) {
if(line==null)
line = c;
else
{
Vec3d lineVec = new Vec3d(line.end.getX()-line.start.getX(), line.end.getY()-line.start.getY(), line.end.getZ()-line.start.getZ()).normalize();
Vec3d conVec = new Vec3d(c.end.getX()-c.start.getX(), c.end.getY()-c.start.getY(), c.end.getZ()-c.start.getZ()).normalize();
if(conVec.distanceTo(vec)<lineVec.distanceTo(vec))
line = c;
}
}
return line;
}
return null;
}
public static EntitySkylineHook spawnHook(EntityPlayer player, TileEntity start, Connection connection)
{
BlockPos cc0 = connection.end==Utils.toCC(start)?connection.start:connection.end;
BlockPos cc1 = connection.end==Utils.toCC(start)?connection.end:connection.start;
IImmersiveConnectable iicStart = ApiUtils.toIIC(cc1, player.worldObj);
IImmersiveConnectable iicEnd = ApiUtils.toIIC(cc0, player.worldObj);
Vec3d vStart = new Vec3d(cc1);
Vec3d vEnd = new Vec3d(cc0);
if(iicStart!=null)
vStart = Utils.addVectors(vStart, iicStart.getConnectionOffset(connection));
if(iicEnd!=null)
vEnd = Utils.addVectors(vEnd, iicEnd.getConnectionOffset(connection));
Vec3d[] steps = getConnectionCatenary(connection,vStart,vEnd);
double dx = (steps[0].xCoord-vStart.xCoord);
double dy = (steps[0].yCoord-vStart.yCoord);
double dz = (steps[0].zCoord-vStart.zCoord);
double d = 1;//connection.length;
// Math.sqrt(dx*dx+dz*dz+dy*dy);
// Vec3 moveVec = Vec3.createVectorHelper(dx,dy,dz);
// Vec3 moveVec = Vec3.createVectorHelper(dx/d,dy/d,dz/d);
EntitySkylineHook hook = new EntitySkylineHook(player.worldObj, vStart.xCoord,vStart.yCoord,vStart.zCoord, connection, cc0, steps);
float speed = 1;
if(player.getActiveItemStack()!=null&&player.getActiveItemStack().getItem() instanceof ItemSkyhook)
speed = ((ItemSkyhook)player.getActiveItemStack().getItem()).getSkylineSpeed(player.getActiveItemStack());
Vec3d moveVec = getSubMovementVector(vStart, steps[0], speed);
hook.motionX = moveVec.xCoord;//*speed;
hook.motionY = moveVec.yCoord;//*speed;
hook.motionZ = moveVec.zCoord;//*speed;
// hook.motionX = (steps[0].xCoord-cc1.posX)*.5f;
// hook.motionY = (steps[0].yCoord-cc1.posY)*.5f;
// hook.motionZ = (steps[0].zCoord-cc1.posZ)*.5f;
// for(Vec3 v : steps)
// living.worldObj.spawnParticle("smoke", v.xCoord,v.yCoord,v.zCoord, 0,0,0 );
if(!player.worldObj.isRemote)
player.worldObj.spawnEntityInWorld(hook);
ItemSkyhook.existingHooks.put(player.getName(), hook);
player.startRiding(hook);
return hook;
}
public static Vec3d[] getConnectionCatenary(Connection connection, Vec3d start, Vec3d end)
{
boolean vertical = connection.end.getX()==connection.start.getX() && connection.end.getZ()==connection.start.getZ();
if(vertical)
return new Vec3d[]{new Vec3d(end.xCoord, end.yCoord, end.zCoord)};
double dx = (end.xCoord)-(start.xCoord);
double dy = (end.yCoord)-(start.yCoord);
double dz = (end.zCoord)-(start.zCoord);
double dw = Math.sqrt(dx*dx + dz*dz);
double k = Math.sqrt(dx*dx + dy*dy + dz*dz) * connection.cableType.getSlack();
double l = 0;
int limiter = 0;
while(!vertical && limiter<300)
{
limiter++;
l += 0.01;
if (Math.sinh(l)/l >= Math.sqrt(k*k - dy*dy)/dw)
break;
}
double a = dw/2/l;
double p = (0+dw-a*Math.log((k+dy)/(k-dy)))*0.5;
double q = (dy+0-k*Math.cosh(l)/Math.sinh(l))*0.5;
int vertices = 16;
Vec3d[] vex = new Vec3d[vertices];
for(int i=0; i<vertices; i++)
{
float n1 = (i+1)/(float)vertices;
double x1 = 0 + dx * n1;
double z1 = 0 + dz * n1;
double y1 = a * Math.cosh((( Math.sqrt(x1*x1+z1*z1) )-p)/a)+q;
vex[i] = new Vec3d(start.xCoord+x1, start.yCoord+y1, start.zCoord+z1);
}
return vex;
}
public static Vec3d getSubMovementVector(Vec3d start, Vec3d target, float speed)
{
Vec3d movementVec = new Vec3d(target.xCoord-start.xCoord, target.yCoord-start.yCoord, target.zCoord-start.zCoord);
int lPixel = (int)Math.max(1, (movementVec.lengthVector()/(.125*speed)));
return new Vec3d(movementVec.xCoord/lPixel, movementVec.yCoord/lPixel, movementVec.zCoord/lPixel);
}
public static boolean isInBlock(EntityPlayer player, World w)
{
BlockPos init = player.getPosition();
AxisAlignedBB hitbox = player.getEntityBoundingBox();
hitbox = new AxisAlignedBB(hitbox.minX-1, hitbox.minY-1, hitbox.minZ-1, hitbox.maxX, hitbox.maxY, hitbox.maxZ);
for (int xOff = 0;xOff<2;xOff++)
for (int yOff = 0;yOff<3;yOff++)
for (int zOff = 0;zOff<2;zOff++)
{
Vec3d v = new Vec3d(init.getX()+xOff, init.getY()+yOff, init.getZ()+zOff);
if (hitbox.isVecInside(v)&&!w.isAirBlock(new BlockPos(v)))
return true;
}
return false;
}
}