mirror of
https://github.com/orange-cpp/omath.git
synced 2026-04-18 19:03:28 +00:00
added events
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "omath/linear_algebra/vector3.hpp"
|
#include "omath/linear_algebra/vector3.hpp"
|
||||||
#include <expected>
|
#include <expected>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -29,10 +30,20 @@ namespace omath::pathfinding
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
|
|
||||||
|
// Events -- per-vertex optional tag (e.g. "jump", "teleport")
|
||||||
|
void set_event(const Vector3<float>& vertex, std::string event_id);
|
||||||
|
void clear_event(const Vector3<float>& vertex);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
std::optional<std::string> get_event(const Vector3<float>& vertex) const noexcept;
|
||||||
|
|
||||||
[[nodiscard]] std::string serialize() const noexcept;
|
[[nodiscard]] std::string serialize() const noexcept;
|
||||||
|
|
||||||
void deserialize(const std::string& raw);
|
void deserialize(const std::string& raw);
|
||||||
|
|
||||||
std::unordered_map<Vector3<float>, std::vector<Vector3<float>>> m_vertex_map;
|
std::unordered_map<Vector3<float>, std::vector<Vector3<float>>> m_vertex_map;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<Vector3<float>, std::string> m_vertex_events;
|
||||||
};
|
};
|
||||||
} // namespace omath::pathfinding
|
} // namespace omath::pathfinding
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace omath::pathfinding
|
namespace omath::pathfinding
|
||||||
{
|
{
|
||||||
std::expected<Vector3<float>, std::string>
|
std::expected<Vector3<float>, std::string>
|
||||||
@@ -29,13 +30,40 @@ namespace omath::pathfinding
|
|||||||
return m_vertex_map.empty();
|
return m_vertex_map.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NavigationMesh::set_event(const Vector3<float>& vertex, std::string event_id)
|
||||||
|
{
|
||||||
|
m_vertex_events[vertex] = std::move(event_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavigationMesh::clear_event(const Vector3<float>& vertex)
|
||||||
|
{
|
||||||
|
m_vertex_events.erase(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> NavigationMesh::get_event(const Vector3<float>& vertex) const noexcept
|
||||||
|
{
|
||||||
|
const auto it = m_vertex_events.find(vertex);
|
||||||
|
if (it == m_vertex_events.end())
|
||||||
|
return std::nullopt;
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialization format per vertex line:
|
||||||
|
// x y z neighbor_count event_id
|
||||||
|
// where event_id is "-" when no event is set.
|
||||||
|
// Neighbor lines follow: nx ny nz
|
||||||
|
|
||||||
std::string NavigationMesh::serialize() const noexcept
|
std::string NavigationMesh::serialize() const noexcept
|
||||||
{
|
{
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
for (const auto& [vertex, neighbors] : m_vertex_map)
|
for (const auto& [vertex, neighbors] : m_vertex_map)
|
||||||
{
|
{
|
||||||
|
const auto event_it = m_vertex_events.find(vertex);
|
||||||
|
const std::string& event = (event_it != m_vertex_events.end()) ? event_it->second : "-";
|
||||||
|
|
||||||
oss << vertex.x << ' ' << vertex.y << ' ' << vertex.z
|
oss << vertex.x << ' ' << vertex.y << ' ' << vertex.z
|
||||||
<< ' ' << neighbors.size() << '\n';
|
<< ' ' << neighbors.size() << ' ' << event << '\n';
|
||||||
|
|
||||||
for (const auto& n : neighbors)
|
for (const auto& n : neighbors)
|
||||||
oss << n.x << ' ' << n.y << ' ' << n.z << '\n';
|
oss << n.x << ' ' << n.y << ' ' << n.z << '\n';
|
||||||
}
|
}
|
||||||
@@ -45,11 +73,13 @@ namespace omath::pathfinding
|
|||||||
void NavigationMesh::deserialize(const std::string& raw)
|
void NavigationMesh::deserialize(const std::string& raw)
|
||||||
{
|
{
|
||||||
m_vertex_map.clear();
|
m_vertex_map.clear();
|
||||||
|
m_vertex_events.clear();
|
||||||
std::istringstream iss(raw);
|
std::istringstream iss(raw);
|
||||||
|
|
||||||
Vector3<float> vertex;
|
Vector3<float> vertex;
|
||||||
std::size_t neighbors_count;
|
std::size_t neighbors_count;
|
||||||
while (iss >> vertex.x >> vertex.y >> vertex.z >> neighbors_count)
|
std::string event;
|
||||||
|
while (iss >> vertex.x >> vertex.y >> vertex.z >> neighbors_count >> event)
|
||||||
{
|
{
|
||||||
std::vector<Vector3<float>> neighbors;
|
std::vector<Vector3<float>> neighbors;
|
||||||
neighbors.reserve(neighbors_count);
|
neighbors.reserve(neighbors_count);
|
||||||
@@ -61,6 +91,9 @@ namespace omath::pathfinding
|
|||||||
neighbors.push_back(n);
|
neighbors.push_back(n);
|
||||||
}
|
}
|
||||||
m_vertex_map.emplace(vertex, std::move(neighbors));
|
m_vertex_map.emplace(vertex, std::move(neighbors));
|
||||||
|
|
||||||
|
if (event != "-")
|
||||||
|
m_vertex_events.emplace(vertex, std::move(event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace omath::pathfinding
|
} // namespace omath::pathfinding
|
||||||
|
|||||||
@@ -140,3 +140,102 @@ TEST(NavigationMeshTests, VertexWithNoNeighborsRoundTrip)
|
|||||||
ASSERT_EQ(nav2.m_vertex_map.count(v), 1u);
|
ASSERT_EQ(nav2.m_vertex_map.count(v), 1u);
|
||||||
EXPECT_TRUE(nav2.get_neighbors(v).empty());
|
EXPECT_TRUE(nav2.get_neighbors(v).empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Vertex events
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TEST(NavigationMeshTests, EventNotSetByDefault)
|
||||||
|
{
|
||||||
|
NavigationMesh nav;
|
||||||
|
const Vector3<float> v{0.f, 0.f, 0.f};
|
||||||
|
nav.m_vertex_map.emplace(v, std::vector<Vector3<float>>{});
|
||||||
|
|
||||||
|
EXPECT_FALSE(nav.get_event(v).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NavigationMeshTests, SetAndGetEvent)
|
||||||
|
{
|
||||||
|
NavigationMesh nav;
|
||||||
|
const Vector3<float> v{1.f, 0.f, 0.f};
|
||||||
|
nav.m_vertex_map.emplace(v, std::vector<Vector3<float>>{});
|
||||||
|
nav.set_event(v, "jump");
|
||||||
|
|
||||||
|
const auto event = nav.get_event(v);
|
||||||
|
ASSERT_TRUE(event.has_value());
|
||||||
|
EXPECT_EQ(event.value(), "jump");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NavigationMeshTests, OverwriteEvent)
|
||||||
|
{
|
||||||
|
NavigationMesh nav;
|
||||||
|
const Vector3<float> v{1.f, 0.f, 0.f};
|
||||||
|
nav.m_vertex_map.emplace(v, std::vector<Vector3<float>>{});
|
||||||
|
nav.set_event(v, "jump");
|
||||||
|
nav.set_event(v, "teleport");
|
||||||
|
|
||||||
|
EXPECT_EQ(nav.get_event(v).value(), "teleport");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NavigationMeshTests, ClearEvent)
|
||||||
|
{
|
||||||
|
NavigationMesh nav;
|
||||||
|
const Vector3<float> v{1.f, 0.f, 0.f};
|
||||||
|
nav.m_vertex_map.emplace(v, std::vector<Vector3<float>>{});
|
||||||
|
nav.set_event(v, "jump");
|
||||||
|
nav.clear_event(v);
|
||||||
|
|
||||||
|
EXPECT_FALSE(nav.get_event(v).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NavigationMeshTests, EventRoundTripSerialization)
|
||||||
|
{
|
||||||
|
NavigationMesh nav;
|
||||||
|
const Vector3<float> a{0.f, 0.f, 0.f};
|
||||||
|
const Vector3<float> b{1.f, 0.f, 0.f};
|
||||||
|
nav.m_vertex_map.emplace(a, std::vector<Vector3<float>>{b});
|
||||||
|
nav.m_vertex_map.emplace(b, std::vector<Vector3<float>>{});
|
||||||
|
nav.set_event(b, "jump");
|
||||||
|
|
||||||
|
NavigationMesh nav2;
|
||||||
|
nav2.deserialize(nav.serialize());
|
||||||
|
|
||||||
|
ASSERT_FALSE(nav2.get_event(a).has_value());
|
||||||
|
ASSERT_TRUE(nav2.get_event(b).has_value());
|
||||||
|
EXPECT_EQ(nav2.get_event(b).value(), "jump");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NavigationMeshTests, MultipleEventsRoundTrip)
|
||||||
|
{
|
||||||
|
NavigationMesh nav;
|
||||||
|
const Vector3<float> a{0.f, 0.f, 0.f};
|
||||||
|
const Vector3<float> b{1.f, 0.f, 0.f};
|
||||||
|
const Vector3<float> c{2.f, 0.f, 0.f};
|
||||||
|
nav.m_vertex_map.emplace(a, std::vector<Vector3<float>>{});
|
||||||
|
nav.m_vertex_map.emplace(b, std::vector<Vector3<float>>{});
|
||||||
|
nav.m_vertex_map.emplace(c, std::vector<Vector3<float>>{});
|
||||||
|
nav.set_event(a, "spawn");
|
||||||
|
nav.set_event(c, "teleport");
|
||||||
|
|
||||||
|
NavigationMesh nav2;
|
||||||
|
nav2.deserialize(nav.serialize());
|
||||||
|
|
||||||
|
EXPECT_EQ(nav2.get_event(a).value(), "spawn");
|
||||||
|
EXPECT_FALSE(nav2.get_event(b).has_value());
|
||||||
|
EXPECT_EQ(nav2.get_event(c).value(), "teleport");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NavigationMeshTests, DeserializeClearsOldEvents)
|
||||||
|
{
|
||||||
|
NavigationMesh nav;
|
||||||
|
const Vector3<float> v{0.f, 0.f, 0.f};
|
||||||
|
nav.m_vertex_map.emplace(v, std::vector<Vector3<float>>{});
|
||||||
|
nav.set_event(v, "jump");
|
||||||
|
|
||||||
|
// Deserialize a mesh that has no events
|
||||||
|
NavigationMesh empty_events;
|
||||||
|
empty_events.m_vertex_map.emplace(v, std::vector<Vector3<float>>{});
|
||||||
|
|
||||||
|
nav.deserialize(empty_events.serialize());
|
||||||
|
EXPECT_FALSE(nav.get_event(v).has_value());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user