Skip to content

Commit 58593d1

Browse files
committed
Add navigation source geometry parser callbacks
Adds navigation source geometry parser callbacks so that externals can hook their own geometry into the navigation mesh baking process.
1 parent 9bc49a6 commit 58593d1

16 files changed

+257
-1
lines changed

doc/classes/NavigationServer2D.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,23 @@
956956
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".
957957
</description>
958958
</method>
959+
<method name="source_geometry_parser_create">
960+
<return type="RID" />
961+
<description>
962+
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.
963+
</description>
964+
</method>
965+
<method name="source_geometry_parser_set_callback">
966+
<return type="void" />
967+
<param index="0" name="parser" type="RID" />
968+
<param index="1" name="callback" type="Callable" />
969+
<description>
970+
Sets the [param callback] [Callable] for the specific source geometry [param parser]. The [Callable] will receive a call with the following parameters:
971+
- [code]navigation_mesh[/code] - The [NavigationPolygon] reference used to define the parse settings. Do NOT edit or add directly to the navigation mesh.
972+
- [code]source_geometry_data[/code] - The [NavigationMeshSourceGeometryData2D] reference. Add custom source geometry for navigation mesh baking to this object.
973+
- [code]node[/code] - The [Node] that is parsed.
974+
</description>
975+
</method>
959976
</methods>
960977
<signals>
961978
<signal name="map_changed">

doc/classes/NavigationServer3D.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,23 @@
11031103
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".
11041104
</description>
11051105
</method>
1106+
<method name="source_geometry_parser_create">
1107+
<return type="RID" />
1108+
<description>
1109+
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.
1110+
</description>
1111+
</method>
1112+
<method name="source_geometry_parser_set_callback">
1113+
<return type="void" />
1114+
<param index="0" name="parser" type="RID" />
1115+
<param index="1" name="callback" type="Callable" />
1116+
<description>
1117+
Sets the [param callback] [Callable] for the specific source geometry [param parser]. The [Callable] will receive a call with the following parameters:
1118+
- [code]navigation_mesh[/code] - The [NavigationMesh] reference used to define the parse settings. Do NOT edit or add directly to the navigation mesh.
1119+
- [code]source_geometry_data[/code] - The [NavigationMeshSourceGeometryData3D] reference. Add custom source geometry for navigation mesh baking to this object.
1120+
- [code]node[/code] - The [Node] that is parsed.
1121+
</description>
1122+
</method>
11061123
</methods>
11071124
<signals>
11081125
<signal name="avoidance_debug_changed">

modules/navigation/2d/godot_navigation_server_2d.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,16 @@ bool FORWARD_1_C(agent_is_map_changed, RID, p_agent, rid_to_rid);
389389
void FORWARD_2(agent_set_paused, RID, p_agent, bool, p_paused, rid_to_rid, bool_to_bool);
390390
bool FORWARD_1_C(agent_get_paused, RID, p_agent, rid_to_rid);
391391

392-
void FORWARD_1(free, RID, p_object, rid_to_rid);
392+
void GodotNavigationServer2D::free(RID p_object) {
393+
#ifdef CLIPPER2_ENABLED
394+
if (navmesh_generator_2d && navmesh_generator_2d->owns(p_object)) {
395+
navmesh_generator_2d->free(p_object);
396+
return;
397+
}
398+
#endif // CLIPPER2_ENABLED
399+
NavigationServer3D::get_singleton()->free(p_object);
400+
}
401+
393402
void FORWARD_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback, rid_to_rid, callable_to_callable);
394403
bool GodotNavigationServer2D::agent_has_avoidance_callback(RID p_agent) const {
395404
return NavigationServer3D::get_singleton()->agent_has_avoidance_callback(p_agent);
@@ -453,3 +462,20 @@ void GodotNavigationServer2D::query_path(const Ref<NavigationPathQueryParameters
453462
p_query_result->set_path_rids(_query_result.path_rids);
454463
p_query_result->set_path_owner_ids(_query_result.path_owner_ids);
455464
}
465+
466+
RID GodotNavigationServer2D::source_geometry_parser_create() {
467+
#ifdef CLIPPER2_ENABLED
468+
if (navmesh_generator_2d) {
469+
return navmesh_generator_2d->source_geometry_parser_create();
470+
}
471+
#endif // CLIPPER2_ENABLED
472+
return RID();
473+
}
474+
475+
void GodotNavigationServer2D::source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) {
476+
#ifdef CLIPPER2_ENABLED
477+
if (navmesh_generator_2d) {
478+
navmesh_generator_2d->source_geometry_parser_set_callback(p_parser, p_callback);
479+
}
480+
#endif // CLIPPER2_ENABLED
481+
}

modules/navigation/2d/godot_navigation_server_2d.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ class GodotNavigationServer2D : public NavigationServer2D {
253253
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;
254254
virtual bool is_baking_navigation_polygon(Ref<NavigationPolygon> p_navigation_polygon) const override;
255255

256+
virtual RID source_geometry_parser_create() override;
257+
virtual void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) override;
258+
256259
virtual Vector<Vector2> simplify_path(const Vector<Vector2> &p_path, real_t p_epsilon) override;
257260
};
258261

modules/navigation/2d/nav_mesh_generator_2d.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,14 @@
5353
NavMeshGenerator2D *NavMeshGenerator2D::singleton = nullptr;
5454
Mutex NavMeshGenerator2D::baking_navmesh_mutex;
5555
Mutex NavMeshGenerator2D::generator_task_mutex;
56+
RWLock NavMeshGenerator2D::generator_rid_rwlock;
5657
bool NavMeshGenerator2D::use_threads = true;
5758
bool NavMeshGenerator2D::baking_use_multiple_threads = true;
5859
bool NavMeshGenerator2D::baking_use_high_priority_threads = true;
5960
HashSet<Ref<NavigationPolygon>> NavMeshGenerator2D::baking_navmeshes;
6061
HashMap<WorkerThreadPool::TaskID, NavMeshGenerator2D::NavMeshGeneratorTask2D *> NavMeshGenerator2D::generator_tasks;
62+
RID_Owner<NavMeshGenerator2D::NavMeshGeometryParser2D> NavMeshGenerator2D::generator_parser_owner;
63+
LocalVector<NavMeshGenerator2D::NavMeshGeometryParser2D *> NavMeshGenerator2D::generator_parsers;
6164

6265
NavMeshGenerator2D *NavMeshGenerator2D::get_singleton() {
6366
return singleton;
@@ -126,6 +129,13 @@ void NavMeshGenerator2D::cleanup() {
126129
}
127130
generator_tasks.clear();
128131

132+
generator_rid_rwlock.write_lock();
133+
for (NavMeshGeometryParser2D *parser : generator_parsers) {
134+
generator_parser_owner.free(parser->self);
135+
}
136+
generator_parsers.clear();
137+
generator_rid_rwlock.write_unlock();
138+
129139
generator_task_mutex.unlock();
130140
baking_navmesh_mutex.unlock();
131141
}
@@ -236,6 +246,15 @@ void NavMeshGenerator2D::generator_parse_geometry_node(Ref<NavigationPolygon> p_
236246
generator_parse_tilemap_node(p_navigation_mesh, p_source_geometry_data, p_node);
237247
generator_parse_navigationobstacle_node(p_navigation_mesh, p_source_geometry_data, p_node);
238248

249+
generator_rid_rwlock.read_lock();
250+
for (const NavMeshGeometryParser2D *parser : generator_parsers) {
251+
if (!parser->callback.is_valid()) {
252+
continue;
253+
}
254+
parser->callback.call(p_navigation_mesh, p_source_geometry_data, p_node);
255+
}
256+
generator_rid_rwlock.read_unlock();
257+
239258
if (p_recurse_children) {
240259
for (int i = 0; i < p_node->get_child_count(); i++) {
241260
generator_parse_geometry_node(p_navigation_mesh, p_source_geometry_data, p_node->get_child(i), p_recurse_children);
@@ -813,6 +832,47 @@ bool NavMeshGenerator2D::generator_emit_callback(const Callable &p_callback) {
813832
return ce.error == Callable::CallError::CALL_OK;
814833
}
815834

835+
RID NavMeshGenerator2D::source_geometry_parser_create() {
836+
RWLockWrite write_lock(generator_rid_rwlock);
837+
838+
RID rid = generator_parser_owner.make_rid();
839+
840+
NavMeshGeometryParser2D *parser = generator_parser_owner.get_or_null(rid);
841+
parser->self = rid;
842+
843+
generator_parsers.push_back(parser);
844+
845+
return rid;
846+
}
847+
848+
void NavMeshGenerator2D::source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) {
849+
RWLockWrite write_lock(generator_rid_rwlock);
850+
851+
NavMeshGeometryParser2D *parser = generator_parser_owner.get_or_null(p_parser);
852+
ERR_FAIL_NULL(parser);
853+
854+
parser->callback = p_callback;
855+
}
856+
857+
bool NavMeshGenerator2D::owns(RID p_object) {
858+
RWLockRead read_lock(generator_rid_rwlock);
859+
return generator_parser_owner.owns(p_object);
860+
}
861+
862+
void NavMeshGenerator2D::free(RID p_object) {
863+
RWLockWrite write_lock(generator_rid_rwlock);
864+
865+
if (generator_parser_owner.owns(p_object)) {
866+
NavMeshGeometryParser2D *parser = generator_parser_owner.get_or_null(p_object);
867+
868+
generator_parsers.erase(parser);
869+
870+
generator_parser_owner.free(p_object);
871+
} else {
872+
ERR_PRINT("Attempted to free a NavMeshGenerator2D RID that did not exist (or was already freed).");
873+
}
874+
}
875+
816876
void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<NavigationPolygon> p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data) {
817877
if (p_navigation_mesh.is_null() || p_source_geometry_data.is_null()) {
818878
return;

modules/navigation/2d/nav_mesh_generator_2d.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include "core/object/class_db.h"
3737
#include "core/object/worker_thread_pool.h"
38+
#include "core/templates/rid_owner.h"
3839

3940
class Node;
4041
class NavigationPolygon;
@@ -46,6 +47,14 @@ class NavMeshGenerator2D : public Object {
4647
static Mutex baking_navmesh_mutex;
4748
static Mutex generator_task_mutex;
4849

50+
static RWLock generator_rid_rwlock;
51+
struct NavMeshGeometryParser2D {
52+
RID self;
53+
Callable callback;
54+
};
55+
static RID_Owner<NavMeshGeometryParser2D> generator_parser_owner;
56+
static LocalVector<NavMeshGeometryParser2D *> generator_parsers;
57+
4958
static bool use_threads;
5059
static bool baking_use_multiple_threads;
5160
static bool baking_use_high_priority_threads;
@@ -97,6 +106,12 @@ class NavMeshGenerator2D : public Object {
97106
static void bake_from_source_geometry_data_async(Ref<NavigationPolygon> p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, const Callable &p_callback = Callable());
98107
static bool is_baking(Ref<NavigationPolygon> p_navigation_polygon);
99108

109+
static RID source_geometry_parser_create();
110+
static void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback);
111+
112+
static bool owns(RID p_object);
113+
static void free(RID p_object);
114+
100115
NavMeshGenerator2D();
101116
~NavMeshGenerator2D();
102117
};

modules/navigation/3d/godot_navigation_server_3d.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,11 @@ COMMAND_1(free, RID, p_object) {
12021202
} else if (obstacle_owner.owns(p_object)) {
12031203
internal_free_obstacle(p_object);
12041204

1205+
#ifndef _3D_DISABLED
1206+
} else if (navmesh_generator_3d && navmesh_generator_3d->owns(p_object)) {
1207+
navmesh_generator_3d->free(p_object);
1208+
#endif // _3D_DISABLED
1209+
12051210
} else {
12061211
ERR_PRINT("Attempted to free a NavigationServer RID that did not exist (or was already freed).");
12071212
}
@@ -1428,6 +1433,23 @@ PathQueryResult GodotNavigationServer3D::_query_path(const PathQueryParameters &
14281433
return r_query_result;
14291434
}
14301435

1436+
RID GodotNavigationServer3D::source_geometry_parser_create() {
1437+
#ifndef _3D_DISABLED
1438+
if (navmesh_generator_3d) {
1439+
return navmesh_generator_3d->source_geometry_parser_create();
1440+
}
1441+
#endif // _3D_DISABLED
1442+
return RID();
1443+
}
1444+
1445+
void GodotNavigationServer3D::source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) {
1446+
#ifndef _3D_DISABLED
1447+
if (navmesh_generator_3d) {
1448+
navmesh_generator_3d->source_geometry_parser_set_callback(p_parser, p_callback);
1449+
}
1450+
#endif // _3D_DISABLED
1451+
}
1452+
14311453
Vector<Vector3> GodotNavigationServer3D::simplify_path(const Vector<Vector3> &p_path, real_t p_epsilon) {
14321454
if (p_path.size() <= 2) {
14331455
return p_path;

modules/navigation/3d/godot_navigation_server_3d.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ class GodotNavigationServer3D : public NavigationServer3D {
264264
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;
265265
virtual bool is_baking_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh) const override;
266266

267+
virtual RID source_geometry_parser_create() override;
268+
virtual void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) override;
269+
267270
virtual Vector<Vector3> simplify_path(const Vector<Vector3> &p_path, real_t p_epsilon) override;
268271

269272
private:

modules/navigation/3d/nav_mesh_generator_3d.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,14 @@
6666
NavMeshGenerator3D *NavMeshGenerator3D::singleton = nullptr;
6767
Mutex NavMeshGenerator3D::baking_navmesh_mutex;
6868
Mutex NavMeshGenerator3D::generator_task_mutex;
69+
RWLock NavMeshGenerator3D::generator_rid_rwlock;
6970
bool NavMeshGenerator3D::use_threads = true;
7071
bool NavMeshGenerator3D::baking_use_multiple_threads = true;
7172
bool NavMeshGenerator3D::baking_use_high_priority_threads = true;
7273
HashSet<Ref<NavigationMesh>> NavMeshGenerator3D::baking_navmeshes;
7374
HashMap<WorkerThreadPool::TaskID, NavMeshGenerator3D::NavMeshGeneratorTask3D *> NavMeshGenerator3D::generator_tasks;
75+
RID_Owner<NavMeshGenerator3D::NavMeshGeometryParser3D> NavMeshGenerator3D::generator_parser_owner;
76+
LocalVector<NavMeshGenerator3D::NavMeshGeometryParser3D *> NavMeshGenerator3D::generator_parsers;
7477

7578
NavMeshGenerator3D *NavMeshGenerator3D::get_singleton() {
7679
return singleton;
@@ -139,6 +142,13 @@ void NavMeshGenerator3D::cleanup() {
139142
}
140143
generator_tasks.clear();
141144

145+
generator_rid_rwlock.write_lock();
146+
for (NavMeshGeometryParser3D *parser : generator_parsers) {
147+
generator_parser_owner.free(parser->self);
148+
}
149+
generator_parsers.clear();
150+
generator_rid_rwlock.write_unlock();
151+
142152
generator_task_mutex.unlock();
143153
baking_navmesh_mutex.unlock();
144154
}
@@ -254,6 +264,15 @@ void NavMeshGenerator3D::generator_parse_geometry_node(const Ref<NavigationMesh>
254264
#endif
255265
generator_parse_navigationobstacle_node(p_navigation_mesh, p_source_geometry_data, p_node);
256266

267+
generator_rid_rwlock.read_lock();
268+
for (const NavMeshGeometryParser3D *parser : generator_parsers) {
269+
if (!parser->callback.is_valid()) {
270+
continue;
271+
}
272+
parser->callback.call(p_navigation_mesh, p_source_geometry_data, p_node);
273+
}
274+
generator_rid_rwlock.read_unlock();
275+
257276
if (p_recurse_children) {
258277
for (int i = 0; i < p_node->get_child_count(); i++) {
259278
generator_parse_geometry_node(p_navigation_mesh, p_source_geometry_data, p_node->get_child(i), p_recurse_children);
@@ -920,4 +939,45 @@ bool NavMeshGenerator3D::generator_emit_callback(const Callable &p_callback) {
920939
return ce.error == Callable::CallError::CALL_OK;
921940
}
922941

942+
RID NavMeshGenerator3D::source_geometry_parser_create() {
943+
RWLockWrite write_lock(generator_rid_rwlock);
944+
945+
RID rid = generator_parser_owner.make_rid();
946+
947+
NavMeshGeometryParser3D *parser = generator_parser_owner.get_or_null(rid);
948+
parser->self = rid;
949+
950+
generator_parsers.push_back(parser);
951+
952+
return rid;
953+
}
954+
955+
void NavMeshGenerator3D::source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) {
956+
RWLockWrite write_lock(generator_rid_rwlock);
957+
958+
NavMeshGeometryParser3D *parser = generator_parser_owner.get_or_null(p_parser);
959+
ERR_FAIL_NULL(parser);
960+
961+
parser->callback = p_callback;
962+
}
963+
964+
bool NavMeshGenerator3D::owns(RID p_object) {
965+
RWLockRead read_lock(generator_rid_rwlock);
966+
return generator_parser_owner.owns(p_object);
967+
}
968+
969+
void NavMeshGenerator3D::free(RID p_object) {
970+
RWLockWrite write_lock(generator_rid_rwlock);
971+
972+
if (generator_parser_owner.owns(p_object)) {
973+
NavMeshGeometryParser3D *parser = generator_parser_owner.get_or_null(p_object);
974+
975+
generator_parsers.erase(parser);
976+
977+
generator_parser_owner.free(p_object);
978+
} else {
979+
ERR_PRINT("Attempted to free a NavMeshGenerator3D RID that did not exist (or was already freed).");
980+
}
981+
}
982+
923983
#endif // _3D_DISABLED

modules/navigation/3d/nav_mesh_generator_3d.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include "core/object/class_db.h"
3737
#include "core/object/worker_thread_pool.h"
38+
#include "core/templates/rid_owner.h"
3839
#include "modules/modules_enabled.gen.h" // For csg, gridmap.
3940

4041
class Node;
@@ -47,6 +48,14 @@ class NavMeshGenerator3D : public Object {
4748
static Mutex baking_navmesh_mutex;
4849
static Mutex generator_task_mutex;
4950

51+
static RWLock generator_rid_rwlock;
52+
struct NavMeshGeometryParser3D {
53+
RID self;
54+
Callable callback;
55+
};
56+
static RID_Owner<NavMeshGeometryParser3D> generator_parser_owner;
57+
static LocalVector<NavMeshGeometryParser3D *> generator_parsers;
58+
5059
static bool use_threads;
5160
static bool baking_use_multiple_threads;
5261
static bool baking_use_high_priority_threads;
@@ -102,6 +111,12 @@ class NavMeshGenerator3D : public Object {
102111
static void bake_from_source_geometry_data_async(Ref<NavigationMesh> p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, const Callable &p_callback = Callable());
103112
static bool is_baking(Ref<NavigationMesh> p_navigation_mesh);
104113

114+
static RID source_geometry_parser_create();
115+
static void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback);
116+
117+
static bool owns(RID p_object);
118+
static void free(RID p_object);
119+
105120
NavMeshGenerator3D();
106121
~NavMeshGenerator3D();
107122
};

0 commit comments

Comments
 (0)