diff --git a/doc/en/scripting/builtins/libblock.md b/doc/en/scripting/builtins/libblock.md index 2c2c0182..87176e20 100644 --- a/doc/en/scripting/builtins/libblock.md +++ b/doc/en/scripting/builtins/libblock.md @@ -115,17 +115,20 @@ Set specified bits. ## Raycast ```lua -block.raycast(start: vec3, dir: vec3, max_distance: number, [optional] dest: table) -> { +block.raycast(start: vec3, dir: vec3, max_distance: number, [optional] dest: table, [optional] filter: table) -> { block: int, -- block id endpoint: vec3, -- point of the ray hit point iendpoint: vec3, -- position of the block hit by the ray length: number, -- ray length - normal: vec3 -- normal vector of the surface hit by the ray + normal: vec3, -- normal vector of the surface hit by the ray } or nil ``` Casts a ray from the start point in the direction of *dir*. Max_distance specifies the maximum ray length. +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 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 bd50c0e1..c0a5d260 100644 --- a/doc/en/scripting/builtins/libentities.md +++ b/doc/en/scripting/builtins/libentities.md @@ -51,7 +51,7 @@ 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) -> table or nil + ignore: int, [optional] destination: table, [optional] filter: table) -> 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 d4d28a28..150e776e 100644 --- a/doc/ru/scripting/builtins/libblock.md +++ b/doc/ru/scripting/builtins/libblock.md @@ -60,17 +60,20 @@ block.get_picking_item(id: int) -> int ### Raycast ```lua -block.raycast(start: vec3, dir: vec3, max_distance: number, [опционально] dest: table) -> { +block.raycast(start: vec3, dir: vec3, max_distance: number, [опционально] dest: table, [опционально] filter: table) -> { block: int, -- id блока endpoint: vec3, -- точка касания луча iendpoint: vec3, -- позиция блока, которого касается луч length: number, -- длина луча - normal: vec3 -- вектор нормали поверхности, которой касается луч + normal: vec3, -- вектор нормали поверхности, которой касается луч } или nil ``` Бросает луч из точки start в направлении dir. Max_distance указывает максимальную длину луча. +Аргумент `filter` позволяет указать какие блоки являются "прозрачными" для луча, прим.: {"base:glass","base:water"}. +Для использования агрумент `dest` нужно чем-то заполнить(можно nil), это сделано для обратной совместимости + Функция возвращает таблицу с результатами или nil, если луч не касается блока. Для результата будет использоваться целевая (dest) таблица вместо создания новой, если указан опциональный аргумент. diff --git a/doc/ru/scripting/builtins/libentities.md b/doc/ru/scripting/builtins/libentities.md index ebb23497..93275e5b 100644 --- a/doc/ru/scripting/builtins/libentities.md +++ b/doc/ru/scripting/builtins/libentities.md @@ -51,7 +51,7 @@ 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) -> table или nil + ignore: int, [optional] destination: table, [optional] filter: table) -> table или nil ``` Функция является расширенным вариантом [block.raycast](libblock.md#raycast). Возвращает таблицу с результатами если луч касается блока, либо сущности. diff --git a/src/logic/scripting/lua/libblock.cpp b/src/logic/scripting/lua/libblock.cpp index f346098a..342f7899 100644 --- a/src/logic/scripting/lua/libblock.cpp +++ b/src/logic/scripting/lua/libblock.cpp @@ -353,13 +353,30 @@ 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); + std::set filteredBlocks {}; + if (lua::gettop(L) >= 5) { + if (lua::istable(L, 5)) { + int addLen = lua::objlen(L, 5); + for (int i = 0; i < addLen; i++) { + lua::rawgeti(L, i + 1, 5); + auto blockName = std::string(lua::tostring(L, -1)); + Block* block = content->blocks.find(blockName); + if (block != nullptr) { + filteredBlocks.insert(block->rt.id); + } + lua::pop(L); + } + } else { + throw std::runtime_error("table expected for filter"); + } + } glm::vec3 end; glm::ivec3 normal; glm::ivec3 iend; if (auto voxel = level->chunks->rayCast( - start, dir, maxDistance, end, normal, iend + start, dir, maxDistance, end, normal, iend, filteredBlocks )) { - if (lua::gettop(L) >= 4) { + if (lua::gettop(L) >= 4 && !lua::isnil(L, 4)) { lua::pushvalue(L, 4); } else { lua::createtable(L, 0, 5); @@ -452,4 +469,5 @@ const luaL_Reg blocklib[] = { {"raycast", lua::wrap}, {"compose_state", lua::wrap}, {"decompose_state", lua::wrap}, - {NULL, NULL}}; + {NULL, NULL} +}; diff --git a/src/logic/scripting/lua/libentity.cpp b/src/logic/scripting/lua/libentity.cpp index f952a83d..1d21c6ef 100644 --- a/src/logic/scripting/lua/libentity.cpp +++ b/src/logic/scripting/lua/libentity.cpp @@ -8,6 +8,7 @@ #include "objects/rigging.hpp" #include "physics/Hitbox.hpp" #include "voxels/Chunks.hpp" +#include "voxels/Block.hpp" #include "window/Camera.hpp" using namespace scripting; @@ -118,7 +119,25 @@ 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); - auto ignore = lua::tointeger(L, 4); + auto ignoreEntityId = lua::tointeger(L, 4); + std::set filteredBlocks {}; + if (lua::gettop(L) >= 6) { + if (lua::istable(L, 6)) { + int addLen = lua::objlen(L, 6); + for (int i = 0; i < addLen; i++) { + lua::rawgeti(L, i + 1, 6); + auto blockName = std::string(lua::tostring(L, -1)); + Block* block = content->blocks.find(blockName); + if (block != nullptr) { + filteredBlocks.insert(block->rt.id); + } + lua::pop(L); + } + } else { + throw std::runtime_error("table expected for filter"); + } + } + glm::vec3 end; glm::ivec3 normal; glm::ivec3 iend; @@ -126,13 +145,14 @@ static int l_raycast(lua::State* L) { blockid_t block = BLOCK_VOID; if (auto voxel = level->chunks->rayCast( - start, dir, maxDistance, end, normal, iend + start, dir, maxDistance, end, normal, iend, filteredBlocks )) { maxDistance = glm::distance(start, end); block = voxel->id; } - if (auto ray = level->entities->rayCast(start, dir, maxDistance, ignore)) { - if (lua::gettop(L) >= 5) { + if (auto ray = + level->entities->rayCast(start, dir, maxDistance, ignoreEntityId)) { + if (lua::gettop(L) >= 5 && !lua::isnil(L, 5)) { lua::pushvalue(L, 5); } else { lua::createtable(L, 0, 6); @@ -157,7 +177,7 @@ static int l_raycast(lua::State* L) { lua::setfield(L, "entity"); return 1; } else if (block != BLOCK_VOID) { - if (lua::gettop(L) >= 5) { + if (lua::gettop(L) >= 5 && !lua::isnil(L, 5)) { lua::pushvalue(L, 5); } else { lua::createtable(L, 0, 5); @@ -194,4 +214,5 @@ const luaL_Reg entitylib[] = { {"get_all_in_box", lua::wrap}, {"get_all_in_radius", lua::wrap}, {"raycast", lua::wrap}, - {NULL, NULL}}; + {NULL, NULL} +}; diff --git a/src/logic/scripting/lua/lua_extensions.cpp b/src/logic/scripting/lua/lua_extensions.cpp index cb095e9f..51185898 100644 --- a/src/logic/scripting/lua/lua_extensions.cpp +++ b/src/logic/scripting/lua/lua_extensions.cpp @@ -1,5 +1,7 @@ -#include "debug/Logger.hpp" +#include + #include "api_lua.hpp" +#include "debug/Logger.hpp" static debug::Logger logger("lua-debug"); @@ -21,6 +23,128 @@ static int l_debug_log(lua::State* L) { return 0; } +const int MAX_DEPTH = 10; + +int l_debug_print(lua::State* L) { + auto addIndentation = [](int depth) { + for (int i = 0; i < depth; ++i) std::cout << " "; + }; + + auto printHexData = [](const void* ptr, size_t size) { + const auto* bytePtr = reinterpret_cast(ptr); + for (size_t i = 0; i < size; ++i) { + std::cout << std::hex << std::setw(2) << std::setfill('0') + << static_cast(bytePtr[i]) + << ((i + 1) % 8 == 0 && i + 1 < size ? "\n" : " "); + } + }; + + auto printEscapedString = [](const char* str) { + while (*str) { + switch (*str) { + case '\\': std::cout << "\\\\"; break; + case '\"': std::cout << "\\\""; break; + case '\n': std::cout << "\\n"; break; + case '\t': std::cout << "\\t"; break; + case '\r': std::cout << "\\r"; break; + case '\b': std::cout << "\\b"; break; + case '\f': std::cout << "\\f"; break; + default: + if (iscntrl(static_cast(*str))) { + // Print other control characters in \xHH format + std::cout << "\\x" << std::hex << std::setw(2) << std::setfill('0') + << static_cast(static_cast(*str)) << std::dec; + } else { + std::cout << *str; + } + break; + } + ++str; + } + }; + + std::function debugPrint = [&](int index, + int depth, + bool is_key) { + if (depth > MAX_DEPTH) { + std::cout << "{...}"; + return; + } + switch (lua::type(L, index)) { + case LUA_TSTRING: + if (is_key){ + std::cout << lua::tostring(L, index); + }else{ + std::cout << "\""; + printEscapedString(lua::tostring(L, index)); + std::cout << "\""; + } + break; + case LUA_TBOOLEAN: + std::cout << (lua::toboolean(L, index) ? "true" : "false"); + break; + case LUA_TNUMBER: + std::cout << lua::tonumber(L, index); + break; + case LUA_TTABLE: { + bool is_list = lua::objlen(L, index) > 0, hadItems = false; + int absTableIndex = + index > 0 ? index : lua::gettop(L) + index + 1; + std::cout << "{"; + lua::pushnil(L); + while (lua::next(L, absTableIndex) != 0) { + if (hadItems) + std::cout << "," << '\n'; + else + std::cout << '\n'; + + addIndentation(depth + 1); + if (!is_list) { + debugPrint(-2, depth, true); + std::cout << " = "; + } + debugPrint(-1, depth + 1, false); + lua::pop(L, 1); + hadItems = true; + } + if (hadItems) std::cout << '\n'; + addIndentation(depth); + std::cout << "}"; + break; + } + case LUA_TFUNCTION: + std::cout << "function(0x" << std::hex + << lua::topointer(L, index) << std::dec << ")"; + break; + case LUA_TUSERDATA: + std::cout << "userdata:\n"; + printHexData(lua::topointer(L, index), lua::objlen(L, index)); + break; + case LUA_TLIGHTUSERDATA: + std::cout << "lightuserdata:\n"; + printHexData(lua::topointer(L, index), sizeof(void*)); + break; + case LUA_TNIL: + std::cout << "nil"; + break; + default: + std::cout << lua::type_name(L, lua::type(L, index)); + break; + } + }; + + int n = lua::gettop(L); + std::cout << "debug.print(" << '\n'; + for (int i = 1; i <= n; ++i) { + addIndentation(1); + debugPrint(i, 1, false); + if (i < n) std::cout << "," << '\n'; + } + std::cout << '\n' << ")" << std::endl; + lua::pop(L, n); + return 0; +} + void initialize_libs_extends(lua::State* L) { if (lua::getglobal(L, "debug")) { lua::pushcfunction(L, lua::wrap); @@ -32,6 +156,9 @@ void initialize_libs_extends(lua::State* L) { lua::pushcfunction(L, lua::wrap); lua::setfield(L, "log"); + lua::pushcfunction(L, lua::wrap); + lua::setfield(L, "print"); + lua::pop(L); } } diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index 6725074a..f8b1b19d 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -413,7 +413,8 @@ voxel* Chunks::rayCast( float maxDist, glm::vec3& end, glm::ivec3& norm, - glm::ivec3& iend + glm::ivec3& iend, + std::set filter ) { float px = start.x; float py = start.y; @@ -453,8 +454,10 @@ voxel* Chunks::rayCast( if (voxel == nullptr) { return nullptr; } + const auto& def = indices->blocks.require(voxel->id); - if (def.selectable) { + if ((filter.empty() && def.selectable) || + (!filter.empty() && filter.find(def.rt.id) == filter.end())) { end.x = px + t * dx; end.y = py + t * dy; end.z = pz + t * dz; diff --git a/src/voxels/Chunks.hpp b/src/voxels/Chunks.hpp index d17cf9b9..0d3e07e4 100644 --- a/src/voxels/Chunks.hpp +++ b/src/voxels/Chunks.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "typedefs.hpp" @@ -93,7 +94,8 @@ public: float maxLength, glm::vec3& end, glm::ivec3& norm, - glm::ivec3& iend + glm::ivec3& iend, + std::set filter = {} ); glm::vec3 rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDist);