Raycasts are used to simulate rays and determine which selection boxes they intersect with. With some limitations, they work almost exactly like the player pointing at things. [toc] ## Pointed Thing Pointed things in-game as passed to various callbacks are either * Nothing (`{type = "nothing"}`), or * Objects (entities or players), or * Nodes (solids or liquids) Pointed thing tables are thus a "tagged union" type, taking the following forms for objects & nodes: ### Objects - `type` - `{type-string}`: `"object"` - `ref` - ObjectRef: The pointed ObjectRef ### Nodes - `type` - `{type-string}`: `"node"` - `under` - `{type-vector}`: The position of the pointed node (the node which would be dug if using an appropriate tool) - `above` - `{type-vector}`: The position of the pointed node plus the pointed face normal (the position of the node which would be placed if you were building) ### Additional Raycast Fields These fields are only available in pointed things returned by raycasts. - `box_id` - `{type-number}`: Only relevant for nodes: 1-indexed ID of the pointed selection box of the node - `intersection_normal` - `{type-vector}`: Normal vector pointing out of the face of the pointed thing the ray first hit - `intersection_point` - `{type-vector}`: Point on both face & ray where the ray & the selection box(es) of the pointed thing first intersect (may be in the selection box if the raycast starts in the box) Raycasts do not emit "nothing" pointed things. ## `minetest.line_of_sight(pos1, pos2)` Checks whether any non-air node is blocking the line of sight between two positions. You may use this to determine e.g. whether a target would be visible to a mob. Raycasts will often be preferable since they provide more fine-grained control (objects, liquids, looping over possibly blocking things in the line of sight). **Arguments:** - `pos1` - `{type-vector}`: Starting position of the line ("segment") of sight - `pos2` - `{type-vector}`: Ending position of the line ("segment") of sight **Returns:** - `free_sight` - `{type-bool}`: Whether any node is blocking the sight - `pos` - `{type-vector}`: Position of the "first" node (the node closest to `pos1`) blocking the sight (only returned if `free_sight` is `false`) ## `Raycast(from_pos, to_pos, include_objects, include_liquid_nodes)` Creates a raycast object; OOP-constructor-style alias for `minetest.raycast`. IMPORTANT: [Raycasts work on selection-, not collision boxes, making them coherent with player pointing but not physics (collisions) unless selection- and collision boxes are identical.](https://github.com/minetest/minetest/issues/12673) TIP: Have selection boxes, collision boxes (and ideally even visuals) match for all nodes & entities if possible. IMPORTANT: [Serverside raycasts do not support attachments properly; the server is unaware of model specificities, doesn't keep track of automatic rotation etc.](https://github.com/minetest/minetest/issues/10304) **Arguments:** - `from_pos` - `{type-vector}`: Starting position of the raycast (usually eye position) - `to_pos` - `{type-vector}`: Ending position of the raycast (usually eye position + look direction times range) - `include_objects` - `{type-bool}`: Whether objects are included (considered pointable). Optional, defaults to `true`. - `include_liquids` - `{type-bool}`: Whether liquids are included (considered pointable). Optional, defaults to `true`. **Returns:** - `ray` - Raycast iterator object: Non-restartable, stateful iterator of pointed things The Raycast iterator object is callable. Calling `ray()` is syntactic sugar for `ray:next()`. `ray:next()` returns the next pointed thing or `{type-nil}` if there is none and advances the iterator state. Pointed things are returned sorted by the intersection point, from `from_pos` to `to_pos`, from nearest to farthest. ### Usage Since raycasts are iterators, you can loop over them using a `for`-loop. You will usually use the concise ```lua local ray = Raycast(...) for pointed_thing in ray do -- do something end ``` which is just shorthand for ```lua local ray = Raycast(...) for pointed_thing in ray.next, ray do -- do something end ``` which again is syntactic sugar for ```lua local ray = Raycast(...) local pointed_thing = ray:next() while pointed_thing ~= nil do -- do something pointed_thing = ray:next() end ``` There is absolutely no need to manually step through raycasts using the latter two more verbose loops. IMPORTANT: Restartability is the ability of an iterator to start again. For example, `ipairs` is resumable: ```lua local t = {1, 2, 3} for _ = 1, 3 do for i, v in ipairs(t) do print(i, v) end end ``` will work just expected, printing the contents of `t` three times. *Raycasts are not restartable.* Iterating them _"consumes"_ the pointed things; they can't be iterated again. The following will not work as expected: ```lua local ray = Raycast(...) for _ = 1, 3 do for pt in ray do print(pt) end end ``` this will print the pointed things (table addresses) exactly once: after the first run of the inner `for` loop, all pointed things have been consumed; subsequent runs exit immediately, not entering the `for` loop at all. One advantage of this is that Raycasts remember their looping state. The following is thus possible: ```lua local ray = Raycast(...) for pt in ray do if ... then break end end for pt in ray do -- will resume looping with the next pointed thing end ``` ## Examples ### Redo tool raycasts Useful to obtain the additional raycast pointed thing fields, to dynamically decide what is pointable and what is not, to determine the pointed thing periodically ("what am I looking at?") etc. ```lua -- Calculate eye position including eye offset local eye_pos = player:get_pos() eye_pos.y = eye_pos.y + player:get_properties().eye_height local first, third = player:get_eye_offset() if not vector.equals(first, third) then minetest.log("warning", "First & third person eye offsets don't match, assuming first person") end eye_pos = vector.add(eye_pos, vector.divide(first, 10)) -- eye offsets are in block space (10x), transform them back to metric local def = player:get_wielded_item():get_definition() for pointed_thing in minetest.raycast(eye_pos, vector.add(eye_pos, vector.multiply(player:get_look_dir(), def.range or 4)), true, def.liquids_pointable) do if pointed_thing.ref ~= player then -- exclude the player -- do something end end ``` (TODO: compare players by player name rather than by reference in the above example?) --- *This article is originally based on an article from the minetest_docs project: [Raycast.adoc](https://github.com/minetest/minetest_docs/blob/master/doc/classes/Raycast.adoc) by Lars Müller, licensed under CC-BY 4.0*