Skip to content

Commit

Permalink
Add navigation source geometry parser callbacks
Browse files Browse the repository at this point in the history
Adds navigation source geometry parser callbacks so that externals can hook their own geometry into the navigation mesh baking process.
  • Loading branch information
smix8 committed Apr 19, 2024
1 parent 9bc49a6 commit 58593d1
Show file tree
Hide file tree
Showing 16 changed files with 257 additions and 1 deletion.
17 changes: 17 additions & 0 deletions doc/classes/NavigationServer2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -956,6 +956,23 @@
Path simplification can be helpful to mitigate various path following issues that can arise with certain agent types and script behaviors. E.g. "steering" agents or avoidance in "open fields".
</description>
</method>
<method name="source_geometry_parser_create">
<return type="RID" />
<description>
Creates a new source geometry parser. If a [Callable] is set for the parser with [method source_geometry_parser_set_callback] the callback will be called for every single node that gets parsed whenever [method parse_source_geometry_data] is used.
</description>
</method>
<method name="source_geometry_parser_set_callback">
<return type="void" />
<param index="0" name="parser" type="RID" />
<param index="1" name="callback" type="Callable" />
<description>
Sets the [param callback] [Callable] for the specific source geometry [param parser]. The [Callable] will receive a call with the following parameters:
- [code]navigation_mesh[/code] - The [NavigationPolygon] reference used to define the parse settings. Do NOT edit or add directly to the navigation mesh.
- [code]source_geometry_data[/code] - The [NavigationMeshSourceGeometryData2D] reference. Add custom source geometry for navigation mesh baking to this object.
- [code]node[/code] - The [Node] that is parsed.
</description>
</method>
</methods>
<signals>
<signal name="map_changed">
Expand Down
17 changes: 17 additions & 0 deletions doc/classes/NavigationServer3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,23 @@
Path simplification can be helpful to mitigate various path following issues that can arise with certain agent types and script behaviors. E.g. "steering" agents or avoidance in "open fields".
</description>
</method>
<method name="source_geometry_parser_create">
<return type="RID" />
<description>
Creates a new source geometry parser. If a [Callable] is set for the parser with [method source_geometry_parser_set_callback] the callback will be called for every single node that gets parsed whenever [method parse_source_geometry_data] is used.
</description>
</method>
<method name="source_geometry_parser_set_callback">
<return type="void" />
<param index="0" name="parser" type="RID" />
<param index="1" name="callback" type="Callable" />
<description>
Sets the [param callback] [Callable] for the specific source geometry [param parser]. The [Callable] will receive a call with the following parameters:
- [code]navigation_mesh[/code] - The [NavigationMesh] reference used to define the parse settings. Do NOT edit or add directly to the navigation mesh.
- [code]source_geometry_data[/code] - The [NavigationMeshSourceGeometryData3D] reference. Add custom source geometry for navigation mesh baking to this object.
- [code]node[/code] - The [Node] that is parsed.
</description>
</method>
</methods>
<signals>
<signal name="avoidance_debug_changed">
Expand Down
28 changes: 27 additions & 1 deletion modules/navigation/2d/godot_navigation_server_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,16 @@ bool FORWARD_1_C(agent_is_map_changed, RID, p_agent, rid_to_rid);
void FORWARD_2(agent_set_paused, RID, p_agent, bool, p_paused, rid_to_rid, bool_to_bool);
bool FORWARD_1_C(agent_get_paused, RID, p_agent, rid_to_rid);

void FORWARD_1(free, RID, p_object, rid_to_rid);
void GodotNavigationServer2D::free(RID p_object) {
#ifdef CLIPPER2_ENABLED
if (navmesh_generator_2d && navmesh_generator_2d->owns(p_object)) {
navmesh_generator_2d->free(p_object);
return;
}
#endif // CLIPPER2_ENABLED
NavigationServer3D::get_singleton()->free(p_object);
}

void FORWARD_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback, rid_to_rid, callable_to_callable);
bool GodotNavigationServer2D::agent_has_avoidance_callback(RID p_agent) const {
return NavigationServer3D::get_singleton()->agent_has_avoidance_callback(p_agent);
Expand Down Expand Up @@ -453,3 +462,20 @@ void GodotNavigationServer2D::query_path(const Ref<NavigationPathQueryParameters
p_query_result->set_path_rids(_query_result.path_rids);
p_query_result->set_path_owner_ids(_query_result.path_owner_ids);
}

RID GodotNavigationServer2D::source_geometry_parser_create() {
#ifdef CLIPPER2_ENABLED
if (navmesh_generator_2d) {
return navmesh_generator_2d->source_geometry_parser_create();
}
#endif // CLIPPER2_ENABLED
return RID();
}

void GodotNavigationServer2D::source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) {
#ifdef CLIPPER2_ENABLED
if (navmesh_generator_2d) {
navmesh_generator_2d->source_geometry_parser_set_callback(p_parser, p_callback);
}
#endif // CLIPPER2_ENABLED
}
3 changes: 3 additions & 0 deletions modules/navigation/2d/godot_navigation_server_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,9 @@ class GodotNavigationServer2D : public NavigationServer2D {
virtual void bake_from_source_geometry_data_async(const Ref<NavigationPolygon> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData2D> &p_source_geometry_data, const Callable &p_callback = Callable()) override;
virtual bool is_baking_navigation_polygon(Ref<NavigationPolygon> p_navigation_polygon) const override;

virtual RID source_geometry_parser_create() override;
virtual void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) override;

virtual Vector<Vector2> simplify_path(const Vector<Vector2> &p_path, real_t p_epsilon) override;
};

Expand Down
60 changes: 60 additions & 0 deletions modules/navigation/2d/nav_mesh_generator_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,14 @@
NavMeshGenerator2D *NavMeshGenerator2D::singleton = nullptr;
Mutex NavMeshGenerator2D::baking_navmesh_mutex;
Mutex NavMeshGenerator2D::generator_task_mutex;
RWLock NavMeshGenerator2D::generator_rid_rwlock;
bool NavMeshGenerator2D::use_threads = true;
bool NavMeshGenerator2D::baking_use_multiple_threads = true;
bool NavMeshGenerator2D::baking_use_high_priority_threads = true;
HashSet<Ref<NavigationPolygon>> NavMeshGenerator2D::baking_navmeshes;
HashMap<WorkerThreadPool::TaskID, NavMeshGenerator2D::NavMeshGeneratorTask2D *> NavMeshGenerator2D::generator_tasks;
RID_Owner<NavMeshGenerator2D::NavMeshGeometryParser2D> NavMeshGenerator2D::generator_parser_owner;
LocalVector<NavMeshGenerator2D::NavMeshGeometryParser2D *> NavMeshGenerator2D::generator_parsers;

NavMeshGenerator2D *NavMeshGenerator2D::get_singleton() {
return singleton;
Expand Down Expand Up @@ -126,6 +129,13 @@ void NavMeshGenerator2D::cleanup() {
}
generator_tasks.clear();

generator_rid_rwlock.write_lock();
for (NavMeshGeometryParser2D *parser : generator_parsers) {
generator_parser_owner.free(parser->self);
}
generator_parsers.clear();
generator_rid_rwlock.write_unlock();

generator_task_mutex.unlock();
baking_navmesh_mutex.unlock();
}
Expand Down Expand Up @@ -236,6 +246,15 @@ void NavMeshGenerator2D::generator_parse_geometry_node(Ref<NavigationPolygon> p_
generator_parse_tilemap_node(p_navigation_mesh, p_source_geometry_data, p_node);
generator_parse_navigationobstacle_node(p_navigation_mesh, p_source_geometry_data, p_node);

generator_rid_rwlock.read_lock();
for (const NavMeshGeometryParser2D *parser : generator_parsers) {
if (!parser->callback.is_valid()) {
continue;
}
parser->callback.call(p_navigation_mesh, p_source_geometry_data, p_node);
}
generator_rid_rwlock.read_unlock();

if (p_recurse_children) {
for (int i = 0; i < p_node->get_child_count(); i++) {
generator_parse_geometry_node(p_navigation_mesh, p_source_geometry_data, p_node->get_child(i), p_recurse_children);
Expand Down Expand Up @@ -813,6 +832,47 @@ bool NavMeshGenerator2D::generator_emit_callback(const Callable &p_callback) {
return ce.error == Callable::CallError::CALL_OK;
}

RID NavMeshGenerator2D::source_geometry_parser_create() {
RWLockWrite write_lock(generator_rid_rwlock);

RID rid = generator_parser_owner.make_rid();

NavMeshGeometryParser2D *parser = generator_parser_owner.get_or_null(rid);
parser->self = rid;

generator_parsers.push_back(parser);

return rid;
}

void NavMeshGenerator2D::source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) {
RWLockWrite write_lock(generator_rid_rwlock);

NavMeshGeometryParser2D *parser = generator_parser_owner.get_or_null(p_parser);
ERR_FAIL_NULL(parser);

parser->callback = p_callback;
}

bool NavMeshGenerator2D::owns(RID p_object) {
RWLockRead read_lock(generator_rid_rwlock);
return generator_parser_owner.owns(p_object);
}

void NavMeshGenerator2D::free(RID p_object) {
RWLockWrite write_lock(generator_rid_rwlock);

if (generator_parser_owner.owns(p_object)) {
NavMeshGeometryParser2D *parser = generator_parser_owner.get_or_null(p_object);

generator_parsers.erase(parser);

generator_parser_owner.free(p_object);
} else {
ERR_PRINT("Attempted to free a NavMeshGenerator2D RID that did not exist (or was already freed).");
}
}

void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<NavigationPolygon> p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data) {
if (p_navigation_mesh.is_null() || p_source_geometry_data.is_null()) {
return;
Expand Down
15 changes: 15 additions & 0 deletions modules/navigation/2d/nav_mesh_generator_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#include "core/object/class_db.h"
#include "core/object/worker_thread_pool.h"
#include "core/templates/rid_owner.h"

class Node;
class NavigationPolygon;
Expand All @@ -46,6 +47,14 @@ class NavMeshGenerator2D : public Object {
static Mutex baking_navmesh_mutex;
static Mutex generator_task_mutex;

static RWLock generator_rid_rwlock;
struct NavMeshGeometryParser2D {
RID self;
Callable callback;
};
static RID_Owner<NavMeshGeometryParser2D> generator_parser_owner;
static LocalVector<NavMeshGeometryParser2D *> generator_parsers;

static bool use_threads;
static bool baking_use_multiple_threads;
static bool baking_use_high_priority_threads;
Expand Down Expand Up @@ -97,6 +106,12 @@ class NavMeshGenerator2D : public Object {
static void bake_from_source_geometry_data_async(Ref<NavigationPolygon> p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, const Callable &p_callback = Callable());
static bool is_baking(Ref<NavigationPolygon> p_navigation_polygon);

static RID source_geometry_parser_create();
static void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback);

static bool owns(RID p_object);
static void free(RID p_object);

NavMeshGenerator2D();
~NavMeshGenerator2D();
};
Expand Down
22 changes: 22 additions & 0 deletions modules/navigation/3d/godot_navigation_server_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,11 @@ COMMAND_1(free, RID, p_object) {
} else if (obstacle_owner.owns(p_object)) {
internal_free_obstacle(p_object);

#ifndef _3D_DISABLED
} else if (navmesh_generator_3d && navmesh_generator_3d->owns(p_object)) {
navmesh_generator_3d->free(p_object);
#endif // _3D_DISABLED

} else {
ERR_PRINT("Attempted to free a NavigationServer RID that did not exist (or was already freed).");
}
Expand Down Expand Up @@ -1428,6 +1433,23 @@ PathQueryResult GodotNavigationServer3D::_query_path(const PathQueryParameters &
return r_query_result;
}

RID GodotNavigationServer3D::source_geometry_parser_create() {
#ifndef _3D_DISABLED
if (navmesh_generator_3d) {
return navmesh_generator_3d->source_geometry_parser_create();
}
#endif // _3D_DISABLED
return RID();
}

void GodotNavigationServer3D::source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) {
#ifndef _3D_DISABLED
if (navmesh_generator_3d) {
navmesh_generator_3d->source_geometry_parser_set_callback(p_parser, p_callback);
}
#endif // _3D_DISABLED
}

Vector<Vector3> GodotNavigationServer3D::simplify_path(const Vector<Vector3> &p_path, real_t p_epsilon) {
if (p_path.size() <= 2) {
return p_path;
Expand Down
3 changes: 3 additions & 0 deletions modules/navigation/3d/godot_navigation_server_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,9 @@ class GodotNavigationServer3D : public NavigationServer3D {
virtual void bake_from_source_geometry_data_async(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable()) override;
virtual bool is_baking_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh) const override;

virtual RID source_geometry_parser_create() override;
virtual void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) override;

virtual Vector<Vector3> simplify_path(const Vector<Vector3> &p_path, real_t p_epsilon) override;

private:
Expand Down
60 changes: 60 additions & 0 deletions modules/navigation/3d/nav_mesh_generator_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,14 @@
NavMeshGenerator3D *NavMeshGenerator3D::singleton = nullptr;
Mutex NavMeshGenerator3D::baking_navmesh_mutex;
Mutex NavMeshGenerator3D::generator_task_mutex;
RWLock NavMeshGenerator3D::generator_rid_rwlock;
bool NavMeshGenerator3D::use_threads = true;
bool NavMeshGenerator3D::baking_use_multiple_threads = true;
bool NavMeshGenerator3D::baking_use_high_priority_threads = true;
HashSet<Ref<NavigationMesh>> NavMeshGenerator3D::baking_navmeshes;
HashMap<WorkerThreadPool::TaskID, NavMeshGenerator3D::NavMeshGeneratorTask3D *> NavMeshGenerator3D::generator_tasks;
RID_Owner<NavMeshGenerator3D::NavMeshGeometryParser3D> NavMeshGenerator3D::generator_parser_owner;
LocalVector<NavMeshGenerator3D::NavMeshGeometryParser3D *> NavMeshGenerator3D::generator_parsers;

NavMeshGenerator3D *NavMeshGenerator3D::get_singleton() {
return singleton;
Expand Down Expand Up @@ -139,6 +142,13 @@ void NavMeshGenerator3D::cleanup() {
}
generator_tasks.clear();

generator_rid_rwlock.write_lock();
for (NavMeshGeometryParser3D *parser : generator_parsers) {
generator_parser_owner.free(parser->self);
}
generator_parsers.clear();
generator_rid_rwlock.write_unlock();

generator_task_mutex.unlock();
baking_navmesh_mutex.unlock();
}
Expand Down Expand Up @@ -254,6 +264,15 @@ void NavMeshGenerator3D::generator_parse_geometry_node(const Ref<NavigationMesh>
#endif
generator_parse_navigationobstacle_node(p_navigation_mesh, p_source_geometry_data, p_node);

generator_rid_rwlock.read_lock();
for (const NavMeshGeometryParser3D *parser : generator_parsers) {
if (!parser->callback.is_valid()) {
continue;
}
parser->callback.call(p_navigation_mesh, p_source_geometry_data, p_node);
}
generator_rid_rwlock.read_unlock();

if (p_recurse_children) {
for (int i = 0; i < p_node->get_child_count(); i++) {
generator_parse_geometry_node(p_navigation_mesh, p_source_geometry_data, p_node->get_child(i), p_recurse_children);
Expand Down Expand Up @@ -920,4 +939,45 @@ bool NavMeshGenerator3D::generator_emit_callback(const Callable &p_callback) {
return ce.error == Callable::CallError::CALL_OK;
}

RID NavMeshGenerator3D::source_geometry_parser_create() {
RWLockWrite write_lock(generator_rid_rwlock);

RID rid = generator_parser_owner.make_rid();

NavMeshGeometryParser3D *parser = generator_parser_owner.get_or_null(rid);
parser->self = rid;

generator_parsers.push_back(parser);

return rid;
}

void NavMeshGenerator3D::source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) {
RWLockWrite write_lock(generator_rid_rwlock);

NavMeshGeometryParser3D *parser = generator_parser_owner.get_or_null(p_parser);
ERR_FAIL_NULL(parser);

parser->callback = p_callback;
}

bool NavMeshGenerator3D::owns(RID p_object) {
RWLockRead read_lock(generator_rid_rwlock);
return generator_parser_owner.owns(p_object);
}

void NavMeshGenerator3D::free(RID p_object) {
RWLockWrite write_lock(generator_rid_rwlock);

if (generator_parser_owner.owns(p_object)) {
NavMeshGeometryParser3D *parser = generator_parser_owner.get_or_null(p_object);

generator_parsers.erase(parser);

generator_parser_owner.free(p_object);
} else {
ERR_PRINT("Attempted to free a NavMeshGenerator3D RID that did not exist (or was already freed).");
}
}

#endif // _3D_DISABLED
15 changes: 15 additions & 0 deletions modules/navigation/3d/nav_mesh_generator_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#include "core/object/class_db.h"
#include "core/object/worker_thread_pool.h"
#include "core/templates/rid_owner.h"
#include "modules/modules_enabled.gen.h" // For csg, gridmap.

class Node;
Expand All @@ -47,6 +48,14 @@ class NavMeshGenerator3D : public Object {
static Mutex baking_navmesh_mutex;
static Mutex generator_task_mutex;

static RWLock generator_rid_rwlock;
struct NavMeshGeometryParser3D {
RID self;
Callable callback;
};
static RID_Owner<NavMeshGeometryParser3D> generator_parser_owner;
static LocalVector<NavMeshGeometryParser3D *> generator_parsers;

static bool use_threads;
static bool baking_use_multiple_threads;
static bool baking_use_high_priority_threads;
Expand Down Expand Up @@ -102,6 +111,12 @@ class NavMeshGenerator3D : public Object {
static void bake_from_source_geometry_data_async(Ref<NavigationMesh> p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, const Callable &p_callback = Callable());
static bool is_baking(Ref<NavigationMesh> p_navigation_mesh);

static RID source_geometry_parser_create();
static void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback);

static bool owns(RID p_object);
static void free(RID p_object);

NavMeshGenerator3D();
~NavMeshGenerator3D();
};
Expand Down
Loading

0 comments on commit 58593d1

Please sign in to comment.