How can I get the coordinates of a block the player is looking at?

Viewed 12049

I want to get the coordinates of the block the player is looking at. I tried to do it with:

double x = player.getLookVec().getX();
double y = player.getLookVec().getY();
double z = player.getLookVec().getZ();

But somehow these numbers are always between 0, 0, 0, and 1, 1, 1, so I didn't get the coordinates of the block. So how can I get the exact coordinates of a block?

More code:

@Mod.EventBusSubscriber (modid = FirstMod.MOD_ID, bus = Bus.FORGE)
public class RightClickBlock 
{           

    @SubscribeEvent 
    public static void on(FOVUpdateEvent event) 

    {
          if(player.getHeldItemMainhand().getItem() == Items.BEDROCK) 
        {   
             LivingEntity player = event.getEntity();
                 World worldIn = player.world;

                double x = player.getLookVec().getX();
                double y = player.getLookVec().getY();
                double z = player.getLookVec().getZ(); `

                worldIn.setBlockState(new BlockPos(x, y, z) , Blocks.BEDROCK.getDefaultState());   
         }
    }
}
5 Answers

I noticed (at least in 1.16) Minecraft.getInstance().objectMouseOver.getHitVec() returns as air if the player looks at the block from the south, east, or up side. It gives the block next to it, if the number is too big. This method uses the players position, and if the double ends in .0, and decides when the position needs to be -1.

Minecraft instance = Minecraft.getInstance();

if(instance.objectMouseOver.getType() != RayTraceResult.Type.BLOCK){return;}

Vector3d blockVector = instance.objectMouseOver.getHitVec();

double bX = blockVector.getX(); double bY = blockVector.getY(); double bZ = blockVector.getZ();
double pX = instance.player.getPosX(); double pY = instance.player.getPosY(); double pZ = instance.player.getPosZ();

if(bX == Math.floor(bX) && bX <= pX){bX--;}
if(bY == Math.floor(bY) && bY <= pY+1){bY--;} // +1 on Y to get y from player eyes instead of feet
if(bZ == Math.floor(bZ) && bZ <= pZ){bZ--;}

BlockState block = instance.world.getBlockState(new BlockPos(bX, bY, bZ));

for 1.16.5 this worked for me, i used this to for my item to spawn lightning everywhere where i look :D

@Override
public ActionResult<ItemStack> use(World world, PlayerEntity player, Hand p_77659_3_) {

    //RAY END POINT - TO WHERE IT WILL TRAVEL TO
    Double rayLength = new Double(100);
    Vector3d playerRotation = player.getViewVector(0);
    Vector3d rayPath = playerRotation.scale(rayLength);

    //RAY START AND END POINTS
    Vector3d from = player.getEyePosition(0);
    Vector3d to = from.add(rayPath);

    //CREATE THE RAY
    RayTraceContext rayCtx = new RayTraceContext(from, to, RayTraceContext.BlockMode.OUTLINE, RayTraceContext.FluidMode.ANY, null);
    //CAST THE RAY
    BlockRayTraceResult rayHit = world.clip(rayCtx);

    //CHECK THE RESULTS
    if (rayHit.getType() == RayTraceResult.Type.MISS){
        //IF RAY MISSED
    }
    else {
        //IF RAY HIT SOMETHING
        Vector3d hitLocation = rayHit.getLocation();
        //...
    }

    return super.use(world, player, p_77659_3_);
}

Your attempt didn't work because getLookVec tells you the direction the player is looking, not the position of what they're looking at. Anyway, you can only get what you want on the client, so if you want to use it on the server, you'll need to have the client send a packet to the server with it. With that said, here's how you get it:

RayTraceResult lookingAt = Minecraft.getMinecraft().objectMouseOver;
if (lookingAt != null && lookingAt.typeOfHit == RayTraceResult.Type.BLOCK) {
    BlockPos pos = lookingAt.getBlockPos();
    // now the coordinates you want are in pos. Example of use:
    worldIn.setBlockState(pos, Blocks.BEDROCK.getDefaultState());
    // this is a bit oversimplified - you have to send a packet to the server, since only the client knows the BlockPos, but only the server can change blocks
} else {
    // not looking at a block, or too far away from one to tell
}

For 1.15

RayTraceResult lookingAt = Minecraft.getInstance().objectMouseOver;
if (lookingAt != null && lookingAt.getType() == RayTraceResult.Type.BLOCK) {
    double x = lookingAt.getHitVec().getX();
    double y = lookingAt.getHitVec().getY();
    double z = lookingAt.getHitVec().getZ();
    //do whatever with x,y,z
}

i dont know if this works

Here's a class that I made for 1.13. You'll probably have to update it to 1.15. It's pretty similar to what Joseph Sible-Reinstate Monica was suggesting, but maybe it'll work better for your needs.

It takes a couple of parameters. You can leave partialTicks null, then set the range to how many blocks in a straight line you want to extend the path. Check out the RayTraceFluidMode class to figure out what you need.

You can use the Minecraft class to get that and the Entity you want to trace from.

import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.util.EntitySelectors;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.*;
import net.minecraft.world.chunk.IChunkProvider;

import javax.annotation.Nullable;
import java.util.List;

public class ExtendedRange
{

    private Minecraft mc;
    public RayTraceResult mcObjectMouseOver;
    private final double range;
    private final RayTraceFluidMode fluidMode;
    private final Entity requestingEntity;
    private Float partialTicks;
    public boolean airTargeted;
    public EnumFacing blockSideHit;

    private IChunkProvider chunkProvider;

    public ExtendedRange(@Nullable Float partialTicks, double range, RayTraceFluidMode fluidMode, Minecraft mc, Entity entity)
    {
        this.mc = mc;
        if (partialTicks == null)
        {
            this.partialTicks = 1.0F;
        }
        this.range = range;
        this.fluidMode = fluidMode;
        this.requestingEntity = entity;
    }

    public void getMouseOver()
    {
        if (requestingEntity != null)
        {
            if (this.mc.world != null)
            {
                this.mc.profiler.startSection("pick");
                Entity pointedEntity = null;
                double d0 = range; // block reach distance. default 5.0D, max 1024.0D;

                this.mcObjectMouseOver = requestingEntity.rayTrace(d0, partialTicks, fluidMode);
                BlockPos blockPos = this.mcObjectMouseOver.getBlockPos();
                IBlockState state = mc.world.getBlockState(blockPos);
                this.blockSideHit = mcObjectMouseOver.sideHit;

                this.airTargeted = state.isAir(mc.world, blockPos);

                Vec3d vec3d = requestingEntity.getEyePosition(partialTicks);
                boolean flag = false;
                int i = 3;
                double d1 = d0;
                if (d0 > 3.0D) // if range is larger than 3 blocks
                {
                    flag = true;
                }

                if (this.mcObjectMouseOver != null)
                {
                    d1 = this.mcObjectMouseOver.hitVec.distanceTo(vec3d); // distance between ray trace and eye position
                }

                Vec3d vec3d1 = requestingEntity.getLook(1.0F); // get vector from angle of look
                Vec3d vec3d2 = vec3d.add(vec3d1.x * d0, vec3d1.y * d0, vec3d1.z * d0); // add range multiplied by where entity is looking
                Vec3d vec3d3 = null;
                float f = 1.0F;
                List<Entity> list = this.mc.world.getEntitiesInAABBexcluding(requestingEntity, requestingEntity.getBoundingBox().expand(vec3d1.x * d0, vec3d1.y * d0, vec3d1.z * d0).grow(1.0D, 1.0D, 1.0D), EntitySelectors.NOT_SPECTATING.and(Entity::canBeCollidedWith));
                double d2 = d1; // d1 is either range or distance between ray trace and eye position

                for (Entity entity1 : list)
                {
                    AxisAlignedBB axisalignedbb = entity1.getBoundingBox().grow((double) entity1.getCollisionBorderSize());
                    RayTraceResult raytraceresult = axisalignedbb.calculateIntercept(vec3d, vec3d2); // vector between eye position and range location
                    if (axisalignedbb.contains(vec3d)) // if entity is intersected, set entity as intersected
                    {
                        if (d2 >= 0.0D)
                        {
                            pointedEntity = entity1;
                            this.airTargeted = false;

                            vec3d3 = raytraceresult == null ? vec3d : raytraceresult.hitVec;
                            d2 = 0.0D;
                        }
                    }
                    else if (raytraceresult != null) // run when entity is targeted...
                    {
                        double d3 = vec3d.distanceTo(raytraceresult.hitVec); // distance between eye position and range location
                        if (d3 < d2 || d2 == 0.0D)
                        {
                            if (entity1.getLowestRidingEntity() == requestingEntity.getLowestRidingEntity() && !entity1.canRiderInteract()) // if the entity found is what the requesting entity is riding
                            {
                                if (d2 == 0.0D)
                                {
                                    pointedEntity = entity1;
                                    this.airTargeted = false;

                                    vec3d3 = raytraceresult.hitVec;
                                }
                            }
                            else
                            {
                                pointedEntity = entity1;
                                this.airTargeted = false;

                                vec3d3 = raytraceresult.hitVec;
                                d2 = d3;
                            }
                        }
                    }

                }

                if (pointedEntity != null && flag && vec3d.distanceTo(vec3d3) > 3.0D) // if * AND reach is greater than 3 blocks AND
                {
                    this.mcObjectMouseOver = new RayTraceResult(RayTraceResult.Type.MISS, vec3d3, (EnumFacing) null, new BlockPos(vec3d3));
                }

                if (pointedEntity != null && (d2 < d1 || this.mcObjectMouseOver == null))
                {
                    this.mcObjectMouseOver = new RayTraceResult(pointedEntity, vec3d3);
                }

                this.mc.profiler.endSection();
            }
        }
    }
}

Then, to use the RayTraceResult, you can do something like this:

Entity user = /* you can get the player from the Minecraft class and then convert it to an Entity */

ExtendedRange extendedRange = new ExtendedRange(null, range, RayTraceFluidMode.NEVER, Minecraft.getInstance(), user);
extendedRange.getMouseOver();
if (!extendedRange.airTargeted)
{
    RayTraceResult result = extendedRange.mcObjectMouseOver;

    Double blockX;
    Double blockY;
    Double blockZ;

    if (result != null)
    {
        Entity hitEntity = result.entity;

        if (hitEntity != null)
        {
            blockX = hitEntity.posX;
            blockY = hitEntity.posY;
            blockZ = hitEntity.posZ;

        }
        else
        {
            EnumFacing blockSideHit = extendedRange.blockSideHit;

            Vec3d lookingAt = result.hitVec;

            blockX = lookingAt.x;
            blockY = lookingAt.y;
            blockZ = lookingAt.z;
        }
    }
}

This will get you the coordinates or the first entity it hits.

Just a reminder: this is made for 1.13, so you'll have to make some changes to fix it.

Related