From 325bf680410e8012394e5f3ba5ba947c69034899 Mon Sep 17 00:00:00 2001 From: =?utf8?q?D=C3=A1niel=20Juh=C3=A1sz?= Date: Thu, 16 Aug 2018 20:10:08 +0200 Subject: [PATCH] Raycast: export exact pointing location (#6304) * Return intersection point in node coordinates. * Clarify 'intersection_point' documentation --- doc/lua_api.txt | 20 ++++++++++++++++++-- src/environment.cpp | 14 +++++++++----- src/script/common/c_content.cpp | 11 ++++++++++- src/script/common/c_content.h | 8 +++++++- src/script/cpp_api/s_item.cpp | 4 ++-- src/script/cpp_api/s_item.h | 6 +++++- src/script/lua_api/l_env.cpp | 2 +- src/util/pointedthing.cpp | 3 ++- src/util/pointedthing.h | 12 +++++++++--- 9 files changed, 63 insertions(+), 17 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 0c331577b..ef70fe6f7 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1317,6 +1317,17 @@ For helper functions see [Spatial Vectors]. * `{type="node", under=pos, above=pos}` * `{type="object", ref=ObjectRef}` +Exact pointing location (currently only `Raycast` supports these fields): +* `pointed_thing.intersection_point`: The absolute world coordinates of the + point on the selection box which is pointed at. May be in the selection box + if the pointer is in the box too. +* `pointed_thing.box_id`: The ID of the pointed selection box (counting starts + from 1). +* `pointed_thing.intersection_normal`: Unit vector, points outwards of the + selected selection box. This specifies which face is pointed at. + Is a null vector `{x = 0, y = 0, z = 0}` when the pointer is inside the + selection box. + @@ -5323,7 +5334,12 @@ It can be created via `PseudoRandom(seed)`. --------- A raycast on the map. It works with selection boxes. -Can be used as an iterator in a for loop. +Can be used as an iterator in a for loop as: + + local ray = Raycast(...) + for pointed_thing in ray do + ... + end The map is loaded as the ray advances. If the map is modified after the `Raycast` is created, the changes may or may not have an effect on the object. @@ -5338,7 +5354,7 @@ It can be created via `Raycast(pos1, pos2, objects, liquids)` or ### Methods -* `next()`: returns a `pointed_thing` +* `next()`: returns a `pointed_thing` with exact pointing location * Returns the next thing pointed by the ray or nil. `SecureRandom` diff --git a/src/environment.cpp b/src/environment.cpp index c2227601a..ac7b7ce69 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -175,12 +175,12 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result) bool is_colliding = false; // Minimal distance of all collisions float min_distance_sq = 10000000; + // ID of the current box (loop counter) + u16 id = 0; v3f npf = intToFloat(np, BS); - for (std::vector::const_iterator i = boxes.begin(); - i != boxes.end(); ++i) { - // Get current collision box - aabb3f box = *i; + // This loop translates the boxes to their in-world place. + for (aabb3f &box : boxes) { box.MinEdge += npf; box.MaxEdge += npf; @@ -188,8 +188,10 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result) v3s16 intersection_normal; if (!boxLineCollision(box, state->m_shootline.start, state->m_shootline.getVector(), &intersection_point, - &intersection_normal)) + &intersection_normal)) { + ++id; continue; + } f32 distanceSq = (intersection_point - state->m_shootline.start).getLengthSQ(); @@ -198,9 +200,11 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result) min_distance_sq = distanceSq; result.intersection_point = intersection_point; result.intersection_normal = intersection_normal; + result.box_id = id; found_boxcenter = box.getCenter(); is_colliding = true; } + ++id; } // If there wasn't a collision, stop if (!is_colliding) { diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 889b94660..1d62ad98a 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -1757,7 +1757,8 @@ void read_json_value(lua_State *L, Json::Value &root, int index, u8 recursion) lua_pop(L, 1); // Pop value } -void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm) +void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm, + bool hitpoint) { lua_newtable(L); if (pointed.type == POINTEDTHING_NODE) { @@ -1782,6 +1783,14 @@ void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm) lua_pushstring(L, "nothing"); lua_setfield(L, -2, "type"); } + if (hitpoint && (pointed.type != POINTEDTHING_NOTHING)) { + push_v3f(L, pointed.intersection_point / BS); // convert to node coords + lua_setfield(L, -2, "intersection_point"); + push_v3s16(L, pointed.intersection_normal); + lua_setfield(L, -2, "intersection_normal"); + lua_pushinteger(L, pointed.box_id + 1); // change to Lua array index + lua_setfield(L, -2, "box_id"); + } } void push_objectRef(lua_State *L, const u16 id) diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h index 723253559..f3a653682 100644 --- a/src/script/common/c_content.h +++ b/src/script/common/c_content.h @@ -178,7 +178,13 @@ bool push_json_value (lua_State *L, void read_json_value (lua_State *L, Json::Value &root, int index, u8 recursion = 0); -void push_pointed_thing (lua_State *L, const PointedThing &pointed, bool csm = false); +/*! + * Pushes a Lua `pointed_thing` to the given Lua stack. + * \param csm If true, a client side pointed thing is pushed + * \param hitpoint If true, the exact pointing location is also pushed + */ +void push_pointed_thing(lua_State *L, const PointedThing &pointed, bool csm = + false, bool hitpoint = false); void push_objectRef (lua_State *L, const u16 id); diff --git a/src/script/cpp_api/s_item.cpp b/src/script/cpp_api/s_item.cpp index 94abe267b..cbdfcf1b1 100644 --- a/src/script/cpp_api/s_item.cpp +++ b/src/script/cpp_api/s_item.cpp @@ -255,10 +255,10 @@ bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname, return false; } -void ScriptApiItem::pushPointedThing(const PointedThing& pointed) +void ScriptApiItem::pushPointedThing(const PointedThing &pointed, bool hitpoint) { lua_State* L = getStack(); - push_pointed_thing(L, pointed); + push_pointed_thing(L, pointed, false, hitpoint); } diff --git a/src/script/cpp_api/s_item.h b/src/script/cpp_api/s_item.h index d91b5c1d6..6c7f286a9 100644 --- a/src/script/cpp_api/s_item.h +++ b/src/script/cpp_api/s_item.h @@ -54,6 +54,10 @@ protected: friend class LuaRaycast; bool getItemCallback(const char *name, const char *callbackname, const v3s16 *p = nullptr); - void pushPointedThing(const PointedThing& pointed); + /*! + * Pushes a `pointed_thing` tabe to the stack. + * \param hitpoint If true, the exact pointing location is also pushed + */ + void pushPointedThing(const PointedThing &pointed, bool hitpoint = false); }; diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 4944968da..1e5149f7a 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -150,7 +150,7 @@ int LuaRaycast::l_next(lua_State *L) if (pointed.type == POINTEDTHING_NOTHING) lua_pushnil(L); else - script->pushPointedThing(pointed); + script->pushPointedThing(pointed, true); return 1; } diff --git a/src/util/pointedthing.cpp b/src/util/pointedthing.cpp index c5961d56e..b906264d0 100644 --- a/src/util/pointedthing.cpp +++ b/src/util/pointedthing.cpp @@ -25,13 +25,14 @@ with this program; if not, write to the Free Software Foundation, Inc., PointedThing::PointedThing(const v3s16 &under, const v3s16 &above, const v3s16 &real_under, const v3f &point, const v3s16 &normal, - f32 distSq): + u16 box_id, f32 distSq): type(POINTEDTHING_NODE), node_undersurface(under), node_abovesurface(above), node_real_undersurface(real_under), intersection_point(point), intersection_normal(normal), + box_id(box_id), distanceSq(distSq) {} diff --git a/src/util/pointedthing.h b/src/util/pointedthing.h index 4c4c04234..5b30ed031 100644 --- a/src/util/pointedthing.h +++ b/src/util/pointedthing.h @@ -64,7 +64,8 @@ struct PointedThing s16 object_id = -1; /*! * Only valid if type isn't POINTEDTHING_NONE. - * First intersection point of the ray and the nodebox. + * First intersection point of the ray and the nodebox in irrlicht + * coordinates. */ v3f intersection_point; /*! @@ -74,9 +75,14 @@ struct PointedThing * points outside of the box and it's length is 1. */ v3s16 intersection_normal; + /*! + * Only valid if type isn't POINTEDTHING_NONE. + * Indicates which selection box is selected, if there are more of them. + */ + u16 box_id = 0; /*! * Square of the distance between the pointing - * ray's start point and the intersection point. + * ray's start point and the intersection point in irrlicht coordinates. */ f32 distanceSq = 0; @@ -85,7 +91,7 @@ struct PointedThing //! Constructor for POINTEDTHING_NODE PointedThing(const v3s16 &under, const v3s16 &above, const v3s16 &real_under, const v3f &point, const v3s16 &normal, - f32 distSq); + u16 box_id, f32 distSq); //! Constructor for POINTEDTHING_OBJECT PointedThing(s16 id, const v3f &point, const v3s16 &normal, f32 distSq); std::string dump() const; -- 2.25.1