mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-12 22:53:27 +00:00
Initial plan Initial exploration and analysis complete Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com> Optimize performance: A* pathfinding, Vector3 hash, pattern scanner, AVX2 code, and serialization Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com> Add bounds check for navigation mesh serialization Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com> Document serialization limitation for large neighbor counts Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com> Add _codeql_build_dir to gitignore Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com> Removes codeql detected source root Eliminates the automatically generated file that was causing issues. This file was added by codeql and no longer needed. revert cleaned up gitignore moved to anon namespace Improves navigation mesh serialization and clamping Ensures correct serialization of navigation meshes by clamping neighbor counts to prevent data corruption when exceeding uint16_t limits. Updates data types to `std::uint8_t` and `std::size_t` for consistency. Uses `std::copy_n` instead of `std::memcpy` for deserialization.
116 lines
3.4 KiB
C++
116 lines
3.4 KiB
C++
//
|
|
// Created by Vlad on 28.07.2024.
|
|
//
|
|
#include "omath/pathfinding/a_star.hpp"
|
|
#include <algorithm>
|
|
#include <optional>
|
|
#include <queue>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
|
|
namespace
|
|
{
|
|
struct OpenListNode final
|
|
{
|
|
omath::Vector3<float> position;
|
|
float f_cost;
|
|
|
|
[[nodiscard]]
|
|
bool operator>(const OpenListNode& other) const noexcept
|
|
{
|
|
return f_cost > other.f_cost;
|
|
}
|
|
};
|
|
}
|
|
|
|
namespace omath::pathfinding
|
|
{
|
|
struct PathNode final
|
|
{
|
|
std::optional<Vector3<float>> came_from;
|
|
float g_cost = 0.f;
|
|
};
|
|
|
|
std::vector<Vector3<float>>
|
|
Astar::reconstruct_final_path(const std::unordered_map<Vector3<float>, PathNode>& closed_list,
|
|
const Vector3<float>& current) noexcept
|
|
{
|
|
std::vector<Vector3<float>> path;
|
|
std::optional current_opt = current;
|
|
|
|
while (current_opt)
|
|
{
|
|
path.push_back(*current_opt);
|
|
|
|
auto it = closed_list.find(*current_opt);
|
|
|
|
if (it == closed_list.end())
|
|
break;
|
|
|
|
current_opt = it->second.came_from;
|
|
}
|
|
|
|
std::ranges::reverse(path);
|
|
return path;
|
|
}
|
|
|
|
std::vector<Vector3<float>> Astar::find_path(const Vector3<float>& start, const Vector3<float>& end,
|
|
const NavigationMesh& nav_mesh) noexcept
|
|
{
|
|
std::unordered_map<Vector3<float>, PathNode> closed_list;
|
|
std::unordered_map<Vector3<float>, PathNode> node_data;
|
|
std::priority_queue<OpenListNode, std::vector<OpenListNode>, std::greater<>> open_list;
|
|
|
|
auto maybe_start_vertex = nav_mesh.get_closest_vertex(start);
|
|
auto maybe_end_vertex = nav_mesh.get_closest_vertex(end);
|
|
|
|
if (!maybe_start_vertex || !maybe_end_vertex)
|
|
return {};
|
|
|
|
const auto start_vertex = maybe_start_vertex.value();
|
|
const auto end_vertex = maybe_end_vertex.value();
|
|
|
|
node_data.emplace(start_vertex, PathNode{std::nullopt, 0.f});
|
|
open_list.push({start_vertex, start_vertex.distance_to(end_vertex)});
|
|
|
|
while (!open_list.empty())
|
|
{
|
|
auto current = open_list.top().position;
|
|
open_list.pop();
|
|
|
|
if (closed_list.contains(current))
|
|
continue;
|
|
|
|
auto current_node_it = node_data.find(current);
|
|
if (current_node_it == node_data.end())
|
|
continue;
|
|
|
|
const auto current_node = current_node_it->second;
|
|
|
|
if (current == end_vertex)
|
|
return reconstruct_final_path(closed_list, current);
|
|
|
|
closed_list.emplace(current, current_node);
|
|
|
|
for (const auto& neighbor: nav_mesh.get_neighbors(current))
|
|
{
|
|
if (closed_list.contains(neighbor))
|
|
continue;
|
|
|
|
const float tentative_g_cost = current_node.g_cost + neighbor.distance_to(current);
|
|
|
|
auto node_it = node_data.find(neighbor);
|
|
|
|
if (node_it == node_data.end() || tentative_g_cost < node_it->second.g_cost)
|
|
{
|
|
node_data[neighbor] = PathNode{current, tentative_g_cost};
|
|
const float f_cost = tentative_g_cost + neighbor.distance_to(end_vertex);
|
|
open_list.push({neighbor, f_cost});
|
|
}
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
} // namespace omath::pathfinding
|