2013-07-16 17:58:02 +10:00
|
|
|
package codechicken.lib.raytracer;
|
|
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
import codechicken.lib.math.MathHelper;
|
|
|
|
|
import codechicken.lib.vec.BlockCoord;
|
|
|
|
|
import codechicken.lib.vec.Cuboid6;
|
|
|
|
|
import codechicken.lib.vec.Vector3;
|
|
|
|
|
import cpw.mods.fml.relauncher.Side;
|
|
|
|
|
import cpw.mods.fml.relauncher.SideOnly;
|
|
|
|
|
import net.minecraft.block.Block;
|
|
|
|
|
import net.minecraft.client.Minecraft;
|
|
|
|
|
import net.minecraft.entity.Entity;
|
|
|
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
|
|
|
import net.minecraft.entity.player.EntityPlayerMP;
|
|
|
|
|
import net.minecraft.util.EnumMovingObjectType;
|
|
|
|
|
import net.minecraft.util.MovingObjectPosition;
|
|
|
|
|
import net.minecraft.util.Vec3;
|
|
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
|
|
|
|
|
public class RayTracer
|
|
|
|
|
{
|
|
|
|
|
private Vector3 vec = new Vector3();
|
|
|
|
|
private Vector3 vec2 = new Vector3();
|
|
|
|
|
|
|
|
|
|
private Vector3 s_vec = new Vector3();
|
|
|
|
|
private double s_dist;
|
|
|
|
|
private int s_side;
|
|
|
|
|
private IndexedCuboid6 c_cuboid;
|
|
|
|
|
|
|
|
|
|
public static RayTracer instance = new RayTracer();
|
|
|
|
|
|
|
|
|
|
private void traceSide(int side, Vector3 start, Vector3 end, Cuboid6 cuboid)
|
|
|
|
|
{
|
|
|
|
|
vec.set(start);
|
|
|
|
|
Vector3 hit = null;
|
|
|
|
|
switch(side)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
hit = vec.XZintercept(end, cuboid.min.y);
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
hit = vec.XZintercept(end, cuboid.max.y);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
hit = vec.XYintercept(end, cuboid.min.z);
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
hit = vec.XYintercept(end, cuboid.max.z);
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
hit = vec.YZintercept(end, cuboid.min.x);
|
|
|
|
|
break;
|
|
|
|
|
case 5:
|
|
|
|
|
hit = vec.YZintercept(end, cuboid.max.x);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(hit == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
switch(side)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
if(!MathHelper.between(cuboid.min.x, hit.x, cuboid.max.x) || !MathHelper.between(cuboid.min.z, hit.z, cuboid.max.z)) return;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
if(!MathHelper.between(cuboid.min.x, hit.x, cuboid.max.x) || !MathHelper.between(cuboid.min.y, hit.y, cuboid.max.y)) return;
|
|
|
|
|
break;
|
|
|
|
|
case 4:
|
|
|
|
|
case 5:
|
|
|
|
|
if(!MathHelper.between(cuboid.min.y, hit.y, cuboid.max.y) || !MathHelper.between(cuboid.min.z, hit.z, cuboid.max.z)) return;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double dist = vec2.set(hit).subtract(start).magSquared();
|
|
|
|
|
if(dist < s_dist)
|
|
|
|
|
{
|
|
|
|
|
s_side = side;
|
|
|
|
|
s_dist = dist;
|
|
|
|
|
s_vec.set(vec);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public MovingObjectPosition rayTraceCuboid(Vector3 start, Vector3 end, Cuboid6 cuboid)
|
|
|
|
|
{
|
|
|
|
|
s_dist = Double.MAX_VALUE;
|
|
|
|
|
s_side = -1;
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < 6; i++)
|
|
|
|
|
traceSide(i, start, end, cuboid);
|
|
|
|
|
|
|
|
|
|
if(s_side < 0)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
MovingObjectPosition mop = new MovingObjectPosition(0, 0, 0, s_side, s_vec.toVec3D());
|
|
|
|
|
mop.typeOfHit = null;
|
|
|
|
|
return mop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public MovingObjectPosition rayTraceCuboid(Vector3 start, Vector3 end, Cuboid6 cuboid, BlockCoord pos)
|
|
|
|
|
{
|
|
|
|
|
MovingObjectPosition mop = rayTraceCuboid(start, end, cuboid);
|
|
|
|
|
if(mop != null)
|
|
|
|
|
{
|
|
|
|
|
mop.typeOfHit = EnumMovingObjectType.TILE;
|
|
|
|
|
mop.blockX = pos.x;
|
|
|
|
|
mop.blockY = pos.y;
|
|
|
|
|
mop.blockZ = pos.z;
|
|
|
|
|
}
|
|
|
|
|
return mop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public MovingObjectPosition rayTraceCuboid(Vector3 start, Vector3 end, Cuboid6 cuboid, Entity e)
|
|
|
|
|
{
|
|
|
|
|
MovingObjectPosition mop = rayTraceCuboid(start, end, cuboid);
|
|
|
|
|
if(mop != null)
|
|
|
|
|
{
|
|
|
|
|
mop.typeOfHit = EnumMovingObjectType.ENTITY;
|
|
|
|
|
mop.entityHit = e;
|
|
|
|
|
}
|
|
|
|
|
return mop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public MovingObjectPosition rayTraceCuboids(Vector3 start, Vector3 end, List<IndexedCuboid6> cuboids)
|
|
|
|
|
{
|
|
|
|
|
double c_dist = Double.MAX_VALUE;
|
|
|
|
|
MovingObjectPosition c_hit = null;
|
|
|
|
|
|
|
|
|
|
for(IndexedCuboid6 cuboid : cuboids)
|
|
|
|
|
{
|
|
|
|
|
MovingObjectPosition mop = rayTraceCuboid(start, end, cuboid);
|
|
|
|
|
if(mop != null && s_dist < c_dist)
|
|
|
|
|
{
|
|
|
|
|
mop = new ExtendedMOP(mop, cuboid.data);
|
|
|
|
|
c_dist = s_dist;
|
|
|
|
|
c_hit = mop;
|
|
|
|
|
c_cuboid = cuboid;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return c_hit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public MovingObjectPosition rayTraceCuboids(Vector3 start, Vector3 end, List<IndexedCuboid6> cuboids, BlockCoord pos, Block block)
|
|
|
|
|
{
|
|
|
|
|
MovingObjectPosition mop = rayTraceCuboids(start, end, cuboids);
|
|
|
|
|
if(mop != null)
|
|
|
|
|
{
|
|
|
|
|
mop.typeOfHit = EnumMovingObjectType.TILE;
|
|
|
|
|
mop.blockX = pos.x;
|
|
|
|
|
mop.blockY = pos.y;
|
|
|
|
|
mop.blockZ = pos.z;
|
|
|
|
|
if(block != null)
|
|
|
|
|
c_cuboid.add(new Vector3(-pos.x, -pos.y, -pos.z)).setBlockBounds(block);
|
|
|
|
|
}
|
|
|
|
|
return mop;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static MovingObjectPosition retraceBlock(World world, EntityPlayer player, int x, int y, int z)
|
|
|
|
|
{
|
2013-08-02 12:02:01 +10:00
|
|
|
Block block = Block.blocksList[world.getBlockId(x, y, z)];
|
|
|
|
|
if(block == null)
|
|
|
|
|
return null;
|
|
|
|
|
|
2013-07-16 17:58:02 +10:00
|
|
|
Vec3 headVec = Vec3.createVectorHelper(player.posX, (player.posY + 1.62) - player.yOffset, player.posZ);
|
|
|
|
|
Vec3 lookVec = player.getLook(1.0F);
|
|
|
|
|
double reach = world.isRemote ? getBlockReachDistance_client() : getBlockReachDistance_server((EntityPlayerMP) player);
|
|
|
|
|
Vec3 endVec = headVec.addVector(lookVec.xCoord * reach, lookVec.yCoord * reach, lookVec.zCoord * reach);
|
2013-08-02 12:02:01 +10:00
|
|
|
return block.collisionRayTrace(world, x, y, z, headVec, endVec);
|
2013-07-16 17:58:02 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static double getBlockReachDistance_server(EntityPlayerMP player)
|
|
|
|
|
{
|
|
|
|
|
return player.theItemInWorldManager.getBlockReachDistance();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SideOnly(Side.CLIENT)
|
|
|
|
|
private static double getBlockReachDistance_client()
|
|
|
|
|
{
|
|
|
|
|
return Minecraft.getMinecraft().playerController.getBlockReachDistance();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static MovingObjectPosition reTrace(World world, EntityPlayer player)
|
|
|
|
|
{
|
|
|
|
|
return reTrace(world, player, world.isRemote ? getBlockReachDistance_client() : getBlockReachDistance_server((EntityPlayerMP) player));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static MovingObjectPosition reTrace(World world, EntityPlayer player, double reach)
|
|
|
|
|
{
|
|
|
|
|
Vec3 headVec = Vec3.createVectorHelper(player.posX, (player.posY + 1.62) - player.yOffset, player.posZ);
|
|
|
|
|
Vec3 lookVec = player.getLook(1);
|
|
|
|
|
Vec3 endVec = headVec.addVector(lookVec.xCoord * reach, lookVec.yCoord * reach, lookVec.zCoord * reach);
|
|
|
|
|
return world.rayTraceBlocks_do_do(headVec, endVec, true, false);
|
|
|
|
|
}
|
|
|
|
|
}
|