diff --git a/doc/en/scripting/builtins/libpathfinding.md b/doc/en/scripting/builtins/libpathfinding.md index 106df755..19562177 100644 --- a/doc/en/scripting/builtins/libpathfinding.md +++ b/doc/en/scripting/builtins/libpathfinding.md @@ -55,6 +55,12 @@ pathfinding.pull_route(agent: int) --> table or nil --- Set the maximum number of visited blocks for the agent. Used to limit the amount of work of the pathfinding algorithm. pathfinding.set_max_visited(agent: int, max_visited: int) ---- Set a list of tags defining avoided blocks -pathfinding.set_avoided_tags(agent: int, tags: table) +--- Adding an avoided blocks tag +pathfinding.avoid_tag( + agent: int, + -- tag for avoided blocks + tag: string, [optional], + -- cost of crossing a block + cost: int = 10 +) ``` diff --git a/doc/ru/scripting/builtins/libpathfinding.md b/doc/ru/scripting/builtins/libpathfinding.md index fc39b16f..fe31c18e 100644 --- a/doc/ru/scripting/builtins/libpathfinding.md +++ b/doc/ru/scripting/builtins/libpathfinding.md @@ -55,6 +55,12 @@ pathfinding.pull_route(agent: int) --> table или nil --- Установка максимального количества посещенных блоков для агента. Используется для ограничения объема работы алгоритма поиска пути. pathfinding.set_max_visited(agent: int, max_visited: int) ---- Установка перечня тегов, определяющих избегаемые блоки -pathfinding.set_avoided_tags(agent: int, tags: table) +--- Добавление тега избегаемых блоков +pathfinding.avoid_tag( + agent: int, + -- тег избегаемых блоков + tag: string, [опционально], + -- стоимость пересечения блока + cost: int = 10 +) ``` diff --git a/res/scripts/components/pathfinding.lua b/res/scripts/components/pathfinding.lua index 0296c4c7..d5d68cd4 100644 --- a/res/scripts/components/pathfinding.lua +++ b/res/scripts/components/pathfinding.lua @@ -6,7 +6,7 @@ local tsf = entity.transform agent = pathfinding.create_agent() pathfinding.set_max_visited(agent, 1e4) -pathfinding.set_avoided_tags(agent, {"core:liquid"}) +pathfinding.avoid_tag(agent, "core:liquid", 8) function set_target(new_target) target = new_target diff --git a/src/logic/scripting/lua/libs/libpathfinding.cpp b/src/logic/scripting/lua/libs/libpathfinding.cpp index a52acea1..0381f6f8 100644 --- a/src/logic/scripting/lua/libs/libpathfinding.cpp +++ b/src/logic/scripting/lua/libs/libpathfinding.cpp @@ -100,22 +100,16 @@ static int l_set_jump_height(lua::State* L) { return 0; } -static int l_set_avoided_tags(lua::State* L) { +static int l_avoid_tag(lua::State* L) { if (auto agent = get_agent(L)) { - if (!lua::istable(L, 2)) { - throw std::runtime_error("array of tags expected"); - } - agent->avoidTags.clear(); - int len = lua::objlen(L, 2); - for (int i = 1; i <= len; i++) { - lua::rawgeti(L, i); - if (lua::isstring(L, -1)) { - int index = content->getTagIndex(lua::tostring(L, -1)); - if (index != -1) { - agent->avoidTags.insert(index); - } + int index = + content->getTagIndex(std::string(lua::require_lstring(L, 2))); + if (index != -1) { + int cost = lua::tonumber(L, 3); + if (cost == 0) { + cost = 10; } - lua::pop(L); + agent->avoidTags.insert({index, cost}); } } return 0; @@ -131,6 +125,6 @@ const luaL_Reg pathfindinglib[] = { {"pull_route", lua::wrap}, {"set_max_visited", lua::wrap}, {"set_jump_height", lua::wrap}, - {"set_avoided_tags", lua::wrap}, + {"avoid_tag", lua::wrap}, {NULL, NULL} }; diff --git a/src/voxels/Pathfinding.cpp b/src/voxels/Pathfinding.cpp index 6257cdb1..a7a43e0b 100644 --- a/src/voxels/Pathfinding.cpp +++ b/src/voxels/Pathfinding.cpp @@ -75,7 +75,7 @@ bool Pathfinding::removeAgent(int id) { } void Pathfinding::performAllAsync(int stepsPerAgent) { - for (auto& [id, agent] : agents) { + for (auto& [_, agent] : agents) { if (agent.state.finished) { continue; } @@ -215,7 +215,7 @@ const std::unordered_map& Pathfinding::getAgents() const { return agents; } -int Pathfinding::checkPoint(const Agent& agent, int x, int y, int z) { +int Pathfinding::checkPoint(const Agent& agent, int x, int y, int z, int& cost) { auto vox = blocks_agent::get(chunks, x, y, z); if (vox == nullptr) { return OBSTACLE; @@ -224,8 +224,9 @@ int Pathfinding::checkPoint(const Agent& agent, int x, int y, int z) { if (def.obstacle) { return OBSTACLE; } - for (int tagIndex : agent.avoidTags) { - if (def.rt.tags.find(tagIndex) != def.rt.tags.end()) { + for (const auto& pair : agent.avoidTags) { + if (def.rt.tags.find(pair.first) != def.rt.tags.end()) { + cost = pair.second; return NON_PASSABLE; } } @@ -239,23 +240,27 @@ int Pathfinding::getSurfaceAt( int status; int surface = pos.y; - if ((status = checkPoint(agent, pos.x, surface, pos.z)) == OBSTACLE) { - if ((status = checkPoint(agent, pos.x, surface + 1, pos.z)) == OBSTACLE) { + int ncost = 0; + if ((status = checkPoint(agent, pos.x, surface, pos.z, ncost)) == OBSTACLE) { + if ((status = checkPoint(agent, pos.x, surface + 1, pos.z, ncost)) == OBSTACLE) { return NON_PASSABLE; } else if (status == NON_PASSABLE) { - ++cost; + cost += 5; } + cost += ncost; return surface + 1; } else { if (status == NON_PASSABLE) { - ++cost; + cost += 5; } - if ((status = checkPoint(agent, pos.x, surface - 1, pos.z)) == OBSTACLE) { + if ((status = checkPoint(agent, pos.x, surface - 1, pos.z, ncost)) == OBSTACLE) { + cost += ncost; return surface; } else if (status == NON_PASSABLE) { - ++cost; + cost += 5; } - if ((status = checkPoint(agent, pos.x, surface - 2, pos.z)) == OBSTACLE) { + if ((status = checkPoint(agent, pos.x, surface - 2, pos.z, ncost)) == OBSTACLE) { + cost += ncost; return surface - 1; } return NON_PASSABLE; diff --git a/src/voxels/Pathfinding.hpp b/src/voxels/Pathfinding.hpp index f76db86a..9c172c7d 100644 --- a/src/voxels/Pathfinding.hpp +++ b/src/voxels/Pathfinding.hpp @@ -61,7 +61,7 @@ namespace voxels { glm::ivec3 target; Route route; State state {}; - std::set avoidTags; + std::set> avoidTags; }; class Pathfinding { @@ -90,6 +90,6 @@ namespace voxels { const Agent& agent, const glm::ivec3& pos, int maxDelta, float& cost ); - int checkPoint(const Agent& agent, int x, int y, int z); + int checkPoint(const Agent& agent, int x, int y, int z, int& cost); }; }