How can I determine that I am looking at the block I need?
I want to execute a command if I am looking at a specific block. A command should only be executed if it is targeted.
There is currently no command that simply tells you the block, so you need to emulate that with a datapack. This requires something called "raytracing". There are two popular variants of this, one is pretty straightforward (even literally), but can miss blocks in some rare occasions, the other one has perfect accuracy, but requires a bunch of Maths.
Both versions have the problem that you can look at a block that has a smaller hitbox, like a flower pot, at another block, but raytracing will not "see" that. It will only tell you the first non-air block you look at (or also not water etc., if you specify that). The only way to prevent this would be to do even more Maths and logic and to program in the hitbox of every single block into your datapack. I do not know if this has ever been done before. I might do it one day when I'm bored.
In this answer I will describe the simpler of the two versions.
You should always use a datapack for raytracing, because it requires iteratively stepping forwards a little bit at a time and checking the block that the imagined ray is currently in. If you did this with a repeating command block, you could only go as many steps forwards as you have command blocks in a chain. Functions however can call each other recursively, so you can run (almost) as many repetitions as you want in a single game tick.
In the simpler version of raycasting, you need to choose a step size, which is the distance gone forwards in every iteration. If this step size is too big, you can more easily miss blocks when the player looks at a corner of it, if the step size is too small, you either don't get as far or cause too much lag, depending on the value of the maxCommandChainLength
gamerule. A good balance is usually 0.02, with that you can reach all blocks within render distance 32 with the default command chain length of 65536 and you usually only need a few hundred commands executed per tick. (With the maximum possible command chain length that you can set, you could use a step size of 0.0000005, but I would advise against that, since for example on my computer it would cause one server tick to take about 7 minutes on average.)
Firstly, the file structure of the datapack called "raycasting" that uses the namespace "raycasting":
raycasting
└pack.mcmeta
└data
├minecraft
│└tags
│ └functions
│ └tick.json
└raycasting
└functions
├init.mcfunction
├raycast.mcfunction
└check_block.mcfunction
pack.mcmeta
This is a file for metadata about the datapack, like version, description, etc. It is required to exist and needs to fulfil some conditions. The minimum possible is this:
{"pack":{"pack_format":5,"description":""}}
tick.json
This is a built-in function tag that is empty by default and executed every tick. If you include the function raycasting:init
in it, that function will be executed every tick. This is done like this:
{"values":["raycasting:init"]}
Of course you could alternatively also run the function manually or in a command block or under other conditions. With the tick tag you can check whether the player is looking at a block at all times.
init.mcfunction
This function is just there to start the raycasting process:
execute as @a at @s anchored eyes positioned ^ ^ ^ run function raycasting:raycast
This loops over all players and starts the raycasting at their eye position. anchored
seems to only work once "local coordinates" (^ ^ ^) have been used (I assume this is a bug), so the workaround is positioned ^ ^ ^
, which does not change the position at all, but makes it so that anchored
actually does what it's supposed to do.
raycast.mcfunction
This function recursively calls itself a little bit further forwards as long as it's still in air, otherwise calls check_block
. Don't worry about a stack overflow (not the website), Minecraft functions have "recursion tail optimisation". If you don't understand this, you haven't worried anyway, so everything is fine.
execute unless block ~ ~ ~ air run function raycasting:check_block
execute if block ~ ~ ~ air positioned ^ ^ ^.2 run function raycasting:raycast
check_block.mcfunction
This function does whatever you want at the position of the first non-air block you look at. For example you can let it increase a score in every tick in which you look at a stone:
execute if block ~ ~ ~ stone run scoreboard players add @s test 1
Of course this has the already mentioned problem that if you look at a stone through water or the empty part of a sign block or anything like that, it will detect the water/sign/…, not the stone. If you want to exclude more blocks than just air, I recommend a block tag (archive) for that, otherwise your commands get a bit more complicated and you reach the command chain limit earlier. It probably also improves performance.
Example datapack download: https://drive.google.com/file/d/1OSA04r0zHwH1boJNXcRry7TPtG9C2jUU
Relevant Minecraft wiki articles and gamingSE answers:
- Minecraft wiki: Commands#Tilde and caret notation (archive)
- Minecraft wiki: Datapack (archive)
- Minecraft wiki: Commands/execute (archive)
- Minecraft wiki: Tag (archive)
- GamingSE: How to tag a function? (because the "Tag" article on the wiki is a bit hard to interpret and apply)
- GamingSE: (Java Minecraft 1.14.2) How to recursively (or otherwise) determine if a closed 2D arbitrarily sized rectangle of blocks has been placed? (the first time I used raycasting, already includes all the optimisations that I reused for this answer)