Jump to content

How to get the coordinates of a block the player is looking at


Bobblacksmith

Recommended Posts

I am trying to make a sword that can teleport you to the block you are looking at, except I keep teleporting into the void. I think what I am doing wrong is teleporting past the blocks, but I am not sure how to get the coords of a block the player is looking at. Here is what I have currently...

 

 	@Override
public ItemStack onItemRightClick(ItemStack item, World world, EntityPlayer user) {
	if(world.isDaytime() || !world.isDaytime() ){
		double x = user.getLookVec().xCoord;
		double y = user.getLookVec().yCoord;
		double z = user.getLookVec().zCoord;
		user.setPosition(x, y, z);
	}
	else if(world.isRaining()){
		user.addChatMessage("You may not use this Item in the rain!");
	}
	return item; 

I am Bobblacksmith and I approve this message!

Link to comment
Share on other sites

Not entirely sure whats wrong, but why are you checking if it is day or night and the else is if it is raining? Would it not just teleport the player anyway because you checked if it is day or night, which it will always be.

Don't be afraid to ask question when modding, there are no stupid question! Unless you don't know java then all your questions are stupid!

Link to comment
Share on other sites

1. I wanted it to not be allowed while it is raining

 

2. Currently this code teleports me into the void, I think I am not actually teleporting to a block with the code, I want to know how to teleport to a block. I need to know how to get a block's coordinates.

I am Bobblacksmith and I approve this message!

Link to comment
Share on other sites

Not sure why the getLookVec stuff isn't working right, but you've still structured your conditional wrong. Saying world.isDaytime() || !world.isDaytime() will always evaluate to true, so you may as well be writing:

 

if (true) {
    // teleport code
} else if (world.isRaining()) {
    // chat code
}

 

You want this instead:

 

if (!world.isRaining()) {
    // teleport code
} else {
    // chat code
}

I like to make mods, just like you. Here's one worth checking out

Link to comment
Share on other sites

50 is equal to 50D it is just 50 doubles.

I don't know, why don't you try Twinklez's method, by sending an object.

 

Have you even checked that you are looking at a block?

You could however send a MovingObjectPosition and get the coordinates of what it hits, whilst checking if it hits a block.

 

Psuedo code - open by Twinklez -- you can remove the print statements.

https://gist.github.com/Twinklez/9905161

 

Link to comment
Share on other sites

Hi there,

 

getLookVec() returns a normalized look vector, so all the coordinates (xCoord etc) squared and added together will equal one. It is not a real world position, but relative to your current position, so you need to add these values to your initial position (e.g. player.posX += vec.xCoord * 50D, etc.).

 

Like mentioned earlier, you can multiply each vector coordinate by some value that will extend the distance, so if you multiply by 50 you will be teleporting 50 blocks along the player's look vector, but that might be inside of a block.

 

You can either manually iterate along the vector path until you hit a block, or you can use the World#clip method with your multiplied look vector (plus the initial coordinates), and the player's initial position as a vector. This will return a moving object position which may be null or may contain the information on the block hit.

Link to comment
Share on other sites

*snip*

 

Ah, normalized vectors. Oh so handy!

 

Actually they are handy as they can be resolved into an actual direction.  The problem here is that the look vector is wrong for this purpose, there is other methods for returning the block your cursor is actually targeting.

 

I haven't used it in a while, but I think something like Minecraft.getMinecraft().objectMouseOver would be better.

 

In any case, Minecraft of course has methods for figuring out the block that you can interact with and you need to invoke those, rather than a look vector.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

*snip*

 

Ah, normalized vectors. Oh so handy!

 

Actually they are handy as they can be resolved into an actual direction.  The problem here is that the look vector is wrong for this purpose, there is other methods for returning the block your cursor is actually targeting.

 

I haven't used it in a while, but I think something like Minecraft.getMinecraft().objectMouseOver would be better.

 

In any case, Minecraft of course has methods for figuring out the block that you can interact with and you need to invoke those, rather than a look vector.

 

This crashed my game.

I am Bobblacksmith and I approve this message!

Link to comment
Share on other sites

Actually they are handy as they can be resolved into an actual direction.  The problem here is that the look vector is wrong for this purpose, there is other methods for returning the block your cursor is actually targeting.

 

I haven't used it in a while, but I think something like Minecraft.getMinecraft().objectMouseOver would be better.

 

In any case, Minecraft of course has methods for figuring out the block that you can interact with and you need to invoke those, rather than a look vector.

I beg to differ. Look vectors are exactly what is needed here. objectMouseOver is useful, but can only be used on the client, so if you want to be able to teleport on the server without sending a packet, the look vector is perfect. I've used it lots of times.

 

@OP accessing Minecraft.getMinecraft().anything will crash your game if you try to access it on the server side (i.e. when the world is NOT remote), since getMinecraft() is all client-side only. If you want to use objectMouseOver, you will need to do so only on the client and send a packet containing the coordinates you need, then resolve the teleport from the server side; otherwise, you can try using the look vector.

Link to comment
Share on other sites

Actually they are handy as they can be resolved into an actual direction.  The problem here is that the look vector is wrong for this purpose, there is other methods for returning the block your cursor is actually targeting.

 

I haven't used it in a while, but I think something like Minecraft.getMinecraft().objectMouseOver would be better.

 

In any case, Minecraft of course has methods for figuring out the block that you can interact with and you need to invoke those, rather than a look vector.

I beg to differ. Look vectors are exactly what is needed here. objectMouseOver is useful, but can only be used on the client, so if you want to be able to teleport on the server without sending a packet, the look vector is perfect. I've used it lots of times.

 

@OP accessing Minecraft.getMinecraft().anything will crash your game if you try to access it on the server side (i.e. when the world is NOT remote), since getMinecraft() is all client-side only. If you want to use objectMouseOver, you will need to do so only on the client and send a packet containing the coordinates you need, then resolve the teleport from the server side; otherwise, you can try using the look vector.

 

Yeah, this is the same mistake I made on separate topic you just helped me with (i.e. client versus server side)

 

I still think that the mouseOver is more specifically what this person wants though (says he wants to teleport to a block located in direction looking, not just in direction looking), so maybe doing it like you said -- use mouseOver in client but send packet from client to server.  I say this because the look vector doesn't directly give you a block position, whereas mouseOver already has all the "goodness" of figuring out if there is an object under your cursor that has a meaningful position in the world.  If you use lookvector then you'll have to do something to check positions in direction of the look until you find something.

 

I guess neither way is hard, but when modding since I'm a noob to Minecraft (obviously) I tend to try to make use of any vanilla code that is useful and it seems that mouseOver is sort of sophisticated.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

Figuring out the coordinates on the client would be a security hole though, because how do you know that the client is not just sending arbitrary coordinates? If you don't verify client data your mod becomes a target for hackers.

 

Yeah, but what the player is looking at is a client side thing so even the look vector at some point must accept client data, right?  But I guess you're saying that the look vector is somehow more secure?

 

(I'm not trying to be argumentative, as I'm pretty new to Minecraft and the server stuff still trips me up.  I just want to understand fully so I don't make the mistake later myself).

 

Maybe you're saying that the look vector isn't itself more secure, but rather it is relative to the player position so it couldn't be hacked to cause arbitrary teleport except to legitimate things that could be seen by the player anyway?

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

Method to find the block that a player is looking at: -- mostly adapted/copied from some old code in Item class so that it could be accessed outside of an item.

 

You can change reachLength to the maximum length you want to check.  If nothing is found in that range, it will return null.

 

If you don't want to hit entities, you can remove that section entirely leaving only the blocks portion.

 

offset parameter is if you want to offset for side hit, such as if you are placing a block (get the block clicked IN instead of the one clicked ON)

 

BlockPosition is a simple tuple/triplet class --- three int fields, x, y, z, and some utility methods.  Change this to your prefferred return data-type

 

(its actually been awhile since I've looked at that code...no idea what scaleFactor was supposed to do...but the rest should be fairly obvious)

 

 

/**
* will return null if nothing is in range
* @param player
* @param world
* @param offset
* @return
*/
public static BlockPosition getBlockClickedOn(EntityPlayer player, World world, boolean offset)
  {
  float scaleFactor = 1.0F;
  float rotPitch = player.prevRotationPitch + (player.rotationPitch - player.prevRotationPitch) * scaleFactor;
  float rotYaw = player.prevRotationYaw + (player.rotationYaw - player.prevRotationYaw) * scaleFactor;
  double testX = player.prevPosX + (player.posX - player.prevPosX) * scaleFactor;
  double testY = player.prevPosY + (player.posY - player.prevPosY) * scaleFactor + 1.62D - player.yOffset;//1.62 is player eye height
  double testZ = player.prevPosZ + (player.posZ - player.prevPosZ) * scaleFactor;
  Vec3 testVector = Vec3.createVectorHelper(testX, testY, testZ);
  float var14 = MathHelper.cos(-rotYaw * 0.017453292F - (float)Math.PI);
  float var15 = MathHelper.sin(-rotYaw * 0.017453292F - (float)Math.PI);
  float var16 = -MathHelper.cos(-rotPitch * 0.017453292F);
  float vectorY = MathHelper.sin(-rotPitch * 0.017453292F);
  float vectorX = var15 * var16;
  float vectorZ = var14 * var16;
  double reachLength = 5.0D;
  Vec3 testVectorFar = testVector.addVector(vectorX * reachLength, vectorY * reachLength, vectorZ * reachLength);
  MovingObjectPosition testHitPosition = world.rayTraceBlocks(testVector, testVectorFar, true);

  /**
   * if nothing was hit, return null
   */
  if (testHitPosition == null)
    {
    return null;
    }

  Vec3 var25 = player.getLook(scaleFactor);
  float var27 = 1.0F;
  List entitiesPossiblyHitByVector = world.getEntitiesWithinAABBExcludingEntity(player, player.boundingBox.addCoord(var25.xCoord * reachLength, var25.yCoord * reachLength, var25.zCoord * reachLength).expand(var27, var27, var27));
  Iterator entityIterator = entitiesPossiblyHitByVector.iterator();
  while (entityIterator.hasNext())
    {
    Entity testEntity = (Entity)entityIterator.next();
    if (testEntity.canBeCollidedWith())
      {
      float bbExpansionSize = testEntity.getCollisionBorderSize();
      AxisAlignedBB entityBB = testEntity.boundingBox.expand(bbExpansionSize, bbExpansionSize, bbExpansionSize);
      /**
       * if an entity is hit, return its position
       */
      if (entityBB.isVecInside(testVector))
        {
        return new BlockPosition(testEntity.posX, testEntity.posY, testEntity.posZ);         
        }
      }
    }
  /**
   * if no entity was hit, return the position impacted.
   */
  int var42 = testHitPosition.blockX;
  int var43 = testHitPosition.blockY;
  int var44 = testHitPosition.blockZ;
  /**
   * if should offset for side hit (block clicked IN)
   */
  if(offset)
    {
    switch (testHitPosition.sideHit)
      {
      case 0:
      --var43;
      break;
      case 1:
      ++var43;
      break;
      case 2:
      --var44;
      break;
      case 3:
      ++var44;
      break;
      case 4:
      --var42;
      break;
      case 5:
      ++var42;
      }
    }      
  return new BlockPosition(var42, var43, var44); 
  }

 

 

Link to comment
Share on other sites

Making this way more complicated than it is - there is no reason to copy the entire getLookVec method... just look at EntityLivingBase#canEntityBeSeen for inspiration on how to do it in a simple fashion:

public boolean canEntityBeSeen(Entity par1Entity) {
return this.worldObj.clip(
this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ),
this.worldObj.getWorldVec3Pool().getVecFromPool(par1Entity.posX, par1Entity.posY + (double)par1Entity.getEyeHeight(), par1Entity.posZ)) == null;
}

There you can see how one could easily modify this to return what you want; World#clip(Vec3, Vec3) returns a MovingObjectPosition if something was in the line of sight, either an entity or block, or null if the player is looking at air.

 

The first Vec3 is based on the player's current position, the second the position you want to teleport to. For that you can use the vector from the player's position (yes, the same one as the first) and add the normalized EntityPlayer#getLookVec() coordinates multiplied by whatever distance you want.

 

In sum, you have 2 Vec3, both based on player position and one modified by the look vector, and you throw those into World#clip. Done in 3-4 lines of code, using tools already available in Minecraft.

Link to comment
Share on other sites

Making this way more complicated than it is - there is no reason to copy the entire getLookVec method... just look at EntityLivingBase#canEntityBeSeen for inspiration on how to do it in a simple fashion:

public boolean canEntityBeSeen(Entity par1Entity) {
return this.worldObj.clip(
this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ),
this.worldObj.getWorldVec3Pool().getVecFromPool(par1Entity.posX, par1Entity.posY + (double)par1Entity.getEyeHeight(), par1Entity.posZ)) == null;
}

There you can see how one could easily modify this to return what you want; World#clip(Vec3, Vec3) returns a MovingObjectPosition if something was in the line of sight, either an entity or block, or null if the player is looking at air.

 

The first Vec3 is based on the player's current position, the second the position you want to teleport to. For that you can use the vector from the player's position (yes, the same one as the first) and add the normalized EntityPlayer#getLookVec() coordinates multiplied by whatever distance you want.

 

In sum, you have 2 Vec3, both based on player position and one modified by the look vector, and you throw those into World#clip. Done in 3-4 lines of code, using tools already available in Minecraft.

 

So how would you go about using this to extract block data to, say, teleport to using the x y z coords, or even spawn something like lightning, if its returning a boolean value? Would it go something like:

 

if(canEntityBeSeen(player) == true){
    //teleport/spawn entity code here?
}

 

I'm just not sure how this would work.

Link to comment
Share on other sites

Not sure if this has been answered already but I've found by far the easiest method to doing this is like so:

 

//entity player
    MovingObjectPosition lastPosition = player.rayTrace(100, 1.0F);
    player.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + "Position [ X: " + lastPosition.blockX + " Y: " + lastPosition.blockY + 1 + " Z: " + lastPosition.blockZ + " ]"));
    //I add 1 because when spawning things, it makes more sense to get the block above where they are focused so that the entity isn't spawned in the block

Link to comment
Share on other sites

  • 1 year later...

In case you also want to include liquids in your search, this would be one way to do it:

/**
*  This method is intended to be called right after an item was right-clicked, and no <i>'blockHit'</i> was found. <br>
*  It will search for the first occurrence of a block made of specific material in the direction where the player <br>
*  is looking, limiting the search with the specified range of item's reach.
*  
*  @param player EntityPlayer using the item <b>(unchecked)</b>
*  @param world Instance of the world the player and his item are in <b>(unchecked)</b>
*  @param material The material type to check if item is used on 
*  @param itemReach User defined reach of the item being used <i>(should be > 1)</i>
*  @return True if the block made from designated material has been found 
*  
*  @see EntityPlayer#rayTrace(double, float)
*  @throws java.lang.NullPointerException if EntityPlayer or World instances are <code>null</code>
*/
public static boolean willItemTouchMaterialOnUse(final EntityPlayer player, final World world, Material material, int itemReach)
{
final Vec3 vec3 = player.getPositionEyes(1.0F);
final Vec3 vec31 = player.getLook(1.0F); 
	     
for (int i = 1; i <= itemReach; i++)  // Manually traverse the vector
{
	Vec3 vec32 = vec3.addVector(vec31.xCoord * i, vec31.yCoord * i, vec31.zCoord * i);
	BlockPos blockpos = new BlockPos(vec32.xCoord, vec32.yCoord, vec32.zCoord);
	IBlockState iblockstate = world.getBlockState(blockpos);
	         
	if (iblockstate != null && iblockstate.getBlock().getMaterial() == material)
	    return true;
}

return false;
}

I still haven't published a mod because I can never get that in-dev version just right to warrant a public release. And yes, after two years of mod development I am still learning to speak Java.

 

Follow me on GitHub: https://github.com/yooksi

Contact me on Twitter: https://twitter.com/yooksi

Read my Minecraft blog: https://yooksidoesminecraft.blogspot.de/

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.