diff --git a/doc/en/scripting/builtins/libblock.md b/doc/en/scripting/builtins/libblock.md index c93735f78..b2528c364 100644 --- a/doc/en/scripting/builtins/libblock.md +++ b/doc/en/scripting/builtins/libblock.md @@ -136,7 +136,9 @@ Set specified bits. ## Raycast ```lua -block.raycast(start: vec3, dir: vec3, max_distance: number, [optional] dest: table, [optional] filter: table) -> { +block.raycast(start: vec3, dir: vec3, max_distance: number, [optional] dest: table, + [optional] filter: table, [optional] include_non_selectable = false +) -> { block: int, -- block id endpoint: vec3, -- point of the ray hit point iendpoint: vec3, -- position of the block hit by the ray @@ -150,6 +152,9 @@ Casts a ray from the start point in the direction of *dir*. Max_distance specifi Argument `filter` can be used to tell ray what blocks can be skipped(passed through) during ray-casting. To use filter `dest` argument must be filled with some value(can be nil), it's done for backwards compatability +The `include_non_selectable` argument determines whether blocks that cannot be selected by the cursor will be included. +Example - `base:water` + The function returns a table with the results or nil if the ray does not hit any block. The result will use the destination table instead of creating a new one if the optional argument specified. diff --git a/doc/en/scripting/builtins/libentities.md b/doc/en/scripting/builtins/libentities.md index 3fc242579..d65d95f05 100644 --- a/doc/en/scripting/builtins/libentities.md +++ b/doc/en/scripting/builtins/libentities.md @@ -63,8 +63,9 @@ entities.get_all_in_radius(center: vec3, radius: number) -> array ``` ```lua -entities.raycast(start: vec3, dir: vec3, max_distance: number, - ignore: int, [optional] destination: table, [optional] filter: table) -> table or nil +entities.raycast(start: vec3, dir: vec3, max_distance: number, ignore: int, [optional] destination: table, + [optional] filter: table, [optional] include_non_selectable = false +) -> table or nil ``` The function is an extended version of [block.raycast](libblock.md#raycast). Returns a table with the results if the ray touches a block or entity. diff --git a/doc/ru/scripting/builtins/libblock.md b/doc/ru/scripting/builtins/libblock.md index 4e20e696c..a82d2ff66 100644 --- a/doc/ru/scripting/builtins/libblock.md +++ b/doc/ru/scripting/builtins/libblock.md @@ -92,7 +92,9 @@ block.material(blockid: int) -> string ## Raycast ```lua -block.raycast(start: vec3, dir: vec3, max_distance: number, [опционально] dest: table, [опционально] filter: table) -> { +block.raycast(start: vec3, dir: vec3, max_distance: number, [опционально] dest: table, + [опционально] filter: table, [опционально] include_non_selectable = false +) -> { block: int, -- id блока endpoint: vec3, -- точка касания луча iendpoint: vec3, -- позиция блока, которого касается луч @@ -106,6 +108,9 @@ block.raycast(start: vec3, dir: vec3, max_distance: number, [опциональ Аргумент `filter` позволяет указать какие блоки являются "прозрачными" для луча, прим.: {"base:glass","base:water"}. Для использования агрумент `dest` нужно чем-то заполнить(можно nil), это сделано для обратной совместимости +Аргумент `include_non_selectable` определяет, будут ли учтены блоки, которые нельзя выбрать курсором. +Пример - `base:water` + Функция возвращает таблицу с результатами или nil, если луч не касается блока. Для результата будет использоваться целевая (dest) таблица вместо создания новой, если указан опциональный аргумент. diff --git a/doc/ru/scripting/builtins/libentities.md b/doc/ru/scripting/builtins/libentities.md index a66bc83b8..f37dc1b32 100644 --- a/doc/ru/scripting/builtins/libentities.md +++ b/doc/ru/scripting/builtins/libentities.md @@ -62,8 +62,9 @@ entities.get_all_in_radius(center: vec3, radius: number) -> table ``` ```lua -entities.raycast(start: vec3, dir: vec3, max_distance: number, - ignore: int, [optional] destination: table, [optional] filter: table) -> table или nil +entities.raycast(start: vec3, dir: vec3, max_distance: number, ignore: int, [optional] destination: table, + [optional] filter: table, [optional] include_non_selectable = false +) -> table или nil ``` Функция является расширенным вариантом [block.raycast](libblock.md#raycast). Возвращает таблицу с результатами если луч касается блока, либо сущности. diff --git a/src/logic/scripting/lua/libs/libblock.cpp b/src/logic/scripting/lua/libs/libblock.cpp index b87020536..6a84b4113 100644 --- a/src/logic/scripting/lua/libs/libblock.cpp +++ b/src/logic/scripting/lua/libs/libblock.cpp @@ -476,8 +476,10 @@ static int l_raycast(lua::State* L) { auto start = lua::tovec<3>(L, 1); auto dir = lua::tovec<3>(L, 2); auto maxDistance = lua::tonumber(L, 3); + bool includeNonSelectable = false; std::set filteredBlocks {}; - if (lua::gettop(L) >= 5) { + const int luaStackSize = lua::gettop(L); + if (luaStackSize >= 5) { if (lua::istable(L, 5)) { int addLen = lua::objlen(L, 5); for (int i = 0; i < addLen; i++) { @@ -493,6 +495,9 @@ static int l_raycast(lua::State* L) { throw std::runtime_error("table expected for filter"); } } + if (luaStackSize >= 6) { + includeNonSelectable = lua::toboolean(L, 6); + } glm::vec3 end; glm::ivec3 normal; glm::ivec3 iend; @@ -504,9 +509,10 @@ static int l_raycast(lua::State* L) { end, normal, iend, - filteredBlocks + filteredBlocks, + includeNonSelectable )) { - if (lua::gettop(L) >= 4 && !lua::isnil(L, 4)) { + if (luaStackSize >= 4 && !lua::isnil(L, 4)) { lua::pushvalue(L, 4); } else { lua::createtable(L, 0, 5); diff --git a/src/logic/scripting/lua/libs/libentity.cpp b/src/logic/scripting/lua/libs/libentity.cpp index 5cab675a0..5bf3e4d74 100644 --- a/src/logic/scripting/lua/libs/libentity.cpp +++ b/src/logic/scripting/lua/libs/libentity.cpp @@ -141,8 +141,10 @@ static int l_raycast(lua::State* L) { auto dir = lua::tovec<3>(L, 2); auto maxDistance = lua::tonumber(L, 3); auto ignoreEntityId = lua::tointeger(L, 4); + bool includeNonSelectable = false; std::set filteredBlocks {}; - if (lua::gettop(L) >= 6) { + const int luaStackSize = lua::gettop(L); + if (luaStackSize >= 6) { if (lua::istable(L, 6)) { int addLen = lua::objlen(L, 6); for (int i = 0; i < addLen; i++) { @@ -158,6 +160,9 @@ static int l_raycast(lua::State* L) { throw std::runtime_error("table expected for filter"); } } + if (luaStackSize >= 7) { + includeNonSelectable = lua::toboolean(L, 6); + } glm::vec3 end; glm::ivec3 normal; @@ -173,14 +178,15 @@ static int l_raycast(lua::State* L) { end, normal, iend, - filteredBlocks + filteredBlocks, + includeNonSelectable )) { maxDistance = glm::distance(start, end); block = voxel->id; } if (auto ray = level->entities->rayCast(start, dir, maxDistance, ignoreEntityId)) { - if (lua::gettop(L) >= 5 && !lua::isnil(L, 5)) { + if (luaStackSize >= 5 && !lua::isnil(L, 5)) { lua::pushvalue(L, 5); } else { lua::createtable(L, 0, 6); diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index a4b693829..7c4246cad 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -215,10 +215,11 @@ voxel* Chunks::rayCast( glm::vec3& end, glm::ivec3& norm, glm::ivec3& iend, - std::set filter + std::set filter, + bool includeNonSelectable ) const { return blocks_agent::raycast( - *this, start, dir, maxDist, end, norm, iend, std::move(filter) + *this, start, dir, maxDist, end, norm, iend, std::move(filter), includeNonSelectable ); } diff --git a/src/voxels/Chunks.hpp b/src/voxels/Chunks.hpp index e185ce584..5b8866bfc 100644 --- a/src/voxels/Chunks.hpp +++ b/src/voxels/Chunks.hpp @@ -111,7 +111,8 @@ public: glm::vec3& end, glm::ivec3& norm, glm::ivec3& iend, - std::set filter = {} + std::set filter = {}, + bool includeNonSelectable = false ) const; glm::vec3 rayCastToObstacle( diff --git a/src/voxels/blocks_agent.cpp b/src/voxels/blocks_agent.cpp index 723e01d24..b2a16a886 100644 --- a/src/voxels/blocks_agent.cpp +++ b/src/voxels/blocks_agent.cpp @@ -221,7 +221,8 @@ static inline voxel* raycast_blocks( glm::vec3& end, glm::ivec3& norm, glm::ivec3& iend, - std::set filter + std::set filter, + bool includeNonSelectable ) { const auto& blocks = chunks.getContentIndices().blocks; float px = start.x; @@ -264,7 +265,8 @@ static inline voxel* raycast_blocks( } const auto& def = blocks.require(voxel->id); - if (def.selectable && (filter.empty() || filter.find(def.rt.id) == filter.end())) { + if (voxel->id != BLOCK_AIR && (def.selectable || includeNonSelectable) && + (filter.empty() || filter.find(def.rt.id) == filter.end())) { end.x = px + t * dx; end.y = py + t * dy; end.z = pz + t * dz; @@ -361,9 +363,10 @@ voxel* blocks_agent::raycast( glm::vec3& end, glm::ivec3& norm, glm::ivec3& iend, - std::set filter + std::set filter, + bool includeNonSelectable ) { - return raycast_blocks(chunks, start, dir, maxDist, end, norm, iend, filter); + return raycast_blocks(chunks, start, dir, maxDist, end, norm, iend, filter, includeNonSelectable); } voxel* blocks_agent::raycast( @@ -374,9 +377,10 @@ voxel* blocks_agent::raycast( glm::vec3& end, glm::ivec3& norm, glm::ivec3& iend, - std::set filter + std::set filter, + bool includeNonSelectable ) { - return raycast_blocks(chunks, start, dir, maxDist, end, norm, iend, filter); + return raycast_blocks(chunks, start, dir, maxDist, end, norm, iend, filter, includeNonSelectable); } // reduce nesting on next modification diff --git a/src/voxels/blocks_agent.hpp b/src/voxels/blocks_agent.hpp index 7c0223cbd..9ffac7f93 100644 --- a/src/voxels/blocks_agent.hpp +++ b/src/voxels/blocks_agent.hpp @@ -419,6 +419,7 @@ inline void set_rotation( /// @param norm [out] surface normal vector /// @param iend [out] ray end integer position (voxel position + normal) /// @param filter filtered ids +/// @param includeNonSelectable will non-selectable blocks be included /// @return voxel pointer or nullptr voxel* raycast( const Chunks& chunks, @@ -428,7 +429,8 @@ voxel* raycast( glm::vec3& end, glm::ivec3& norm, glm::ivec3& iend, - std::set filter + std::set filter, + bool includeNonSelectable ); /// @brief Cast ray to a selectable block with filter based on id. @@ -440,6 +442,7 @@ voxel* raycast( /// @param norm [out] surface normal vector /// @param iend [out] ray end integer position (voxel position + normal) /// @param filter filtered ids +/// @param includeNonSelectable will non-selectable blocks be included /// @return voxel pointer or nullptr voxel* raycast( const GlobalChunks& chunks, @@ -449,7 +452,8 @@ voxel* raycast( glm::vec3& end, glm::ivec3& norm, glm::ivec3& iend, - std::set filter + std::set filter, + bool includeNonSelectable ); void get_voxels(const Chunks& chunks, VoxelsVolume* volume, bool backlight=false);