diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 39f0718a718..dccdd02d0af 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -504,6 +504,14 @@
Returns the edge connection margin of the map. The edge connection margin is a distance used to connect two regions.
+
+
+
+
+ Returns the current iteration id of the navigation map. Every time the navigation map changes and synchronizes the iteration id increases. An iteration id of 0 means the navigation map has never synchronized.
+ [b]Note:[/b] The iteration id will wrap back to 1 after reaching its range limit.
+
+
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index e88792cadee..4fc75461e78 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -568,6 +568,14 @@
Returns the edge connection margin of the map. This distance is the minimum vertex distance needed to connect two edges from different regions.
+
+
+
+
+ Returns the current iteration id of the navigation map. Every time the navigation map changes and synchronizes the iteration id increases. An iteration id of 0 means the navigation map has never synchronized.
+ [b]Note:[/b] The iteration id will wrap back to 1 after reaching its range limit.
+
+
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index 14c72f3db40..4bb9c27b1d7 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -121,13 +121,13 @@ COMMAND_2(map_set_active, RID, p_map, bool, p_active) {
if (p_active) {
if (!map_is_active(p_map)) {
active_maps.push_back(map);
- active_maps_update_id.push_back(map->get_map_update_id());
+ active_maps_iteration_id.push_back(map->get_iteration_id());
}
} else {
int map_index = active_maps.find(map);
ERR_FAIL_COND(map_index < 0);
active_maps.remove_at(map_index);
- active_maps_update_id.remove_at(map_index);
+ active_maps_iteration_id.remove_at(map_index);
}
}
@@ -1165,7 +1165,7 @@ COMMAND_1(free, RID, p_object) {
int map_index = active_maps.find(map);
if (map_index >= 0) {
active_maps.remove_at(map_index);
- active_maps_update_id.remove_at(map_index);
+ active_maps_iteration_id.remove_at(map_index);
}
map_owner.free(p_object);
@@ -1258,6 +1258,13 @@ void GodotNavigationServer::map_force_update(RID p_map) {
map->sync();
}
+uint32_t GodotNavigationServer::map_get_iteration_id(RID p_map) const {
+ NavMap *map = map_owner.get_or_null(p_map);
+ ERR_FAIL_NULL_V(map, 0);
+
+ return map->get_iteration_id();
+}
+
void GodotNavigationServer::sync() {
#ifndef _3D_DISABLED
if (navmesh_generator_3d) {
@@ -1300,10 +1307,10 @@ void GodotNavigationServer::process(real_t p_delta_time) {
_new_pm_edge_free_count += active_maps[i]->get_pm_edge_free_count();
// Emit a signal if a map changed.
- const uint32_t new_map_update_id = active_maps[i]->get_map_update_id();
- if (new_map_update_id != active_maps_update_id[i]) {
+ const uint32_t new_map_iteration_id = active_maps[i]->get_iteration_id();
+ if (new_map_iteration_id != active_maps_iteration_id[i]) {
emit_signal(SNAME("map_changed"), active_maps[i]->get_self());
- active_maps_update_id[i] = new_map_update_id;
+ active_maps_iteration_id[i] = new_map_iteration_id;
}
}
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index f3bc1185d82..8af0eb18747 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -80,7 +80,7 @@ class GodotNavigationServer : public NavigationServer3D {
bool active = true;
LocalVector active_maps;
- LocalVector active_maps_update_id;
+ LocalVector active_maps_iteration_id;
#ifndef _3D_DISABLED
NavMeshGenerator3D *navmesh_generator_3d = nullptr;
@@ -142,6 +142,7 @@ public:
virtual TypedArray map_get_obstacles(RID p_map) const override;
virtual void map_force_update(RID p_map) override;
+ virtual uint32_t map_get_iteration_id(RID p_map) const override;
virtual Vector3 map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const override;
diff --git a/modules/navigation/godot_navigation_server_2d.cpp b/modules/navigation/godot_navigation_server_2d.cpp
index 5bd4a37fd71..4b8640249d2 100644
--- a/modules/navigation/godot_navigation_server_2d.cpp
+++ b/modules/navigation/godot_navigation_server_2d.cpp
@@ -253,6 +253,10 @@ void GodotNavigationServer2D::map_force_update(RID p_map) {
NavigationServer3D::get_singleton()->map_force_update(p_map);
}
+uint32_t GodotNavigationServer2D::map_get_iteration_id(RID p_map) const {
+ return NavigationServer3D::get_singleton()->map_get_iteration_id(p_map);
+}
+
void FORWARD_2(map_set_cell_size, RID, p_map, real_t, p_cell_size, rid_to_rid, real_to_real);
real_t FORWARD_1_C(map_get_cell_size, RID, p_map, rid_to_rid);
diff --git a/modules/navigation/godot_navigation_server_2d.h b/modules/navigation/godot_navigation_server_2d.h
index 08f1730441a..225fd8f3a63 100644
--- a/modules/navigation/godot_navigation_server_2d.h
+++ b/modules/navigation/godot_navigation_server_2d.h
@@ -77,6 +77,7 @@ public:
virtual TypedArray map_get_obstacles(RID p_map) const override;
virtual void map_force_update(RID p_map) override;
virtual Vector2 map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const override;
+ virtual uint32_t map_get_iteration_id(RID p_map) const override;
virtual RID region_create() override;
virtual void region_set_enabled(RID p_region, bool p_enabled) override;
diff --git a/modules/navigation/nav_agent.cpp b/modules/navigation/nav_agent.cpp
index 5a87ff6c4bf..2dbe57eb4aa 100644
--- a/modules/navigation/nav_agent.cpp
+++ b/modules/navigation/nav_agent.cpp
@@ -111,8 +111,8 @@ void NavAgent::set_map(NavMap *p_map) {
bool NavAgent::is_map_changed() {
if (map) {
- bool is_changed = map->get_map_update_id() != map_update_id;
- map_update_id = map->get_map_update_id();
+ bool is_changed = map->get_iteration_id() != last_map_iteration_id;
+ last_map_iteration_id = map->get_iteration_id();
return is_changed;
} else {
return false;
diff --git a/modules/navigation/nav_agent.h b/modules/navigation/nav_agent.h
index 9ab6f555448..00b5bc13ab4 100644
--- a/modules/navigation/nav_agent.h
+++ b/modules/navigation/nav_agent.h
@@ -72,7 +72,7 @@ class NavAgent : public NavRid {
bool agent_dirty = true;
- uint32_t map_update_id = 0;
+ uint32_t last_map_iteration_id = 0;
bool paused = false;
public:
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 9482da39ef0..f163f4e5294 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -128,7 +128,7 @@ gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const {
Vector NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers, Vector *r_path_types, TypedArray *r_path_rids, Vector *r_path_owners) const {
RWLockRead read_lock(map_rwlock);
- if (map_update_id == 0) {
+ if (iteration_id == 0) {
ERR_FAIL_V_MSG(Vector(), "NavigationServer map query failed because it was made before first map synchronization.");
}
@@ -592,7 +592,7 @@ Vector NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const {
RWLockRead read_lock(map_rwlock);
- if (map_update_id == 0) {
+ if (iteration_id == 0) {
ERR_FAIL_V_MSG(Vector3(), "NavigationServer map query failed because it was made before first map synchronization.");
}
@@ -644,7 +644,7 @@ Vector3 NavMap::get_closest_point_to_segment(const Vector3 &p_from, const Vector
Vector3 NavMap::get_closest_point(const Vector3 &p_point) const {
RWLockRead read_lock(map_rwlock);
- if (map_update_id == 0) {
+ if (iteration_id == 0) {
ERR_FAIL_V_MSG(Vector3(), "NavigationServer map query failed because it was made before first map synchronization.");
}
gd::ClosestPointQueryResult cp = get_closest_point_info(p_point);
@@ -653,7 +653,7 @@ Vector3 NavMap::get_closest_point(const Vector3 &p_point) const {
Vector3 NavMap::get_closest_point_normal(const Vector3 &p_point) const {
RWLockRead read_lock(map_rwlock);
- if (map_update_id == 0) {
+ if (iteration_id == 0) {
ERR_FAIL_V_MSG(Vector3(), "NavigationServer map query failed because it was made before first map synchronization.");
}
gd::ClosestPointQueryResult cp = get_closest_point_info(p_point);
@@ -662,7 +662,7 @@ Vector3 NavMap::get_closest_point_normal(const Vector3 &p_point) const {
RID NavMap::get_closest_point_owner(const Vector3 &p_point) const {
RWLockRead read_lock(map_rwlock);
- if (map_update_id == 0) {
+ if (iteration_id == 0) {
ERR_FAIL_V_MSG(RID(), "NavigationServer map query failed because it was made before first map synchronization.");
}
gd::ClosestPointQueryResult cp = get_closest_point_info(p_point);
@@ -1160,9 +1160,8 @@ void NavMap::sync() {
}
}
- // Update the update ID.
- // Some code treats 0 as a failure case, so we avoid returning 0.
- map_update_id = map_update_id % 9999999 + 1;
+ // Some code treats 0 as a failure case, so we avoid returning 0 and modulo wrap UINT32_MAX manually.
+ iteration_id = iteration_id % UINT32_MAX + 1;
}
// Do we have modified obstacle positions?
diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h
index 311a265e0c9..d6215ea57f1 100644
--- a/modules/navigation/nav_map.h
+++ b/modules/navigation/nav_map.h
@@ -108,7 +108,7 @@ class NavMap : public NavRid {
real_t deltatime = 0.0;
/// Change the id each time the map is updated.
- uint32_t map_update_id = 0;
+ uint32_t iteration_id = 0;
bool use_threads = true;
bool avoidance_use_multiple_threads = true;
@@ -128,6 +128,8 @@ public:
NavMap();
~NavMap();
+ uint32_t get_iteration_id() const { return iteration_id; }
+
void set_up(Vector3 p_up);
Vector3 get_up() const {
return up;
@@ -199,10 +201,6 @@ public:
return obstacles;
}
- uint32_t get_map_update_id() const {
- return map_update_id;
- }
-
Vector3 get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const;
void sync();
diff --git a/modules/navigation/nav_obstacle.cpp b/modules/navigation/nav_obstacle.cpp
index 34e5f7aa851..14dfd4eae34 100644
--- a/modules/navigation/nav_obstacle.cpp
+++ b/modules/navigation/nav_obstacle.cpp
@@ -149,8 +149,8 @@ void NavObstacle::set_vertices(const Vector &p_vertices) {
bool NavObstacle::is_map_changed() {
if (map) {
- bool is_changed = map->get_map_update_id() != map_update_id;
- map_update_id = map->get_map_update_id();
+ bool is_changed = map->get_iteration_id() != last_map_iteration_id;
+ last_map_iteration_id = map->get_iteration_id();
return is_changed;
} else {
return false;
diff --git a/modules/navigation/nav_obstacle.h b/modules/navigation/nav_obstacle.h
index eb44f63d03d..e231e83836c 100644
--- a/modules/navigation/nav_obstacle.h
+++ b/modules/navigation/nav_obstacle.h
@@ -55,7 +55,7 @@ class NavObstacle : public NavRid {
bool obstacle_dirty = true;
- uint32_t map_update_id = 0;
+ uint32_t last_map_iteration_id = 0;
bool paused = false;
public:
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index 32c77195f88..d87ac00e327 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -58,6 +58,7 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_obstacles", "map"), &NavigationServer2D::map_get_obstacles);
ClassDB::bind_method(D_METHOD("map_force_update", "map"), &NavigationServer2D::map_force_update);
+ ClassDB::bind_method(D_METHOD("map_get_iteration_id", "map"), &NavigationServer2D::map_get_iteration_id);
ClassDB::bind_method(D_METHOD("map_get_random_point", "map", "navigation_layers", "uniformly"), &NavigationServer2D::map_get_random_point);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index c7d97c004b4..d7dc9d6526c 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -102,6 +102,7 @@ public:
virtual TypedArray map_get_obstacles(RID p_map) const = 0;
virtual void map_force_update(RID p_map) = 0;
+ virtual uint32_t map_get_iteration_id(RID p_map) const = 0;
virtual Vector2 map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const = 0;
diff --git a/servers/navigation_server_2d_dummy.h b/servers/navigation_server_2d_dummy.h
index 3ec6d113525..94c6dfd6a79 100644
--- a/servers/navigation_server_2d_dummy.h
+++ b/servers/navigation_server_2d_dummy.h
@@ -59,6 +59,7 @@ public:
TypedArray map_get_obstacles(RID p_map) const override { return TypedArray(); }
void map_force_update(RID p_map) override {}
Vector2 map_get_random_point(RID p_map, uint32_t p_naviation_layers, bool p_uniformly) const override { return Vector2(); };
+ uint32_t map_get_iteration_id(RID p_map) const override { return 0; }
RID region_create() override { return RID(); }
void region_set_enabled(RID p_region, bool p_enabled) override {}
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 7fc027284bc..00db1440f65 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -65,6 +65,7 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_obstacles", "map"), &NavigationServer3D::map_get_obstacles);
ClassDB::bind_method(D_METHOD("map_force_update", "map"), &NavigationServer3D::map_force_update);
+ ClassDB::bind_method(D_METHOD("map_get_iteration_id", "map"), &NavigationServer3D::map_get_iteration_id);
ClassDB::bind_method(D_METHOD("map_get_random_point", "map", "navigation_layers", "uniformly"), &NavigationServer3D::map_get_random_point);
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index 552e3185868..975ffdee945 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -116,6 +116,7 @@ public:
virtual TypedArray map_get_obstacles(RID p_map) const = 0;
virtual void map_force_update(RID p_map) = 0;
+ virtual uint32_t map_get_iteration_id(RID p_map) const = 0;
virtual Vector3 map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const = 0;
diff --git a/servers/navigation_server_3d_dummy.h b/servers/navigation_server_3d_dummy.h
index d595fcde7eb..9ba9b20d004 100644
--- a/servers/navigation_server_3d_dummy.h
+++ b/servers/navigation_server_3d_dummy.h
@@ -66,6 +66,8 @@ public:
TypedArray map_get_agents(RID p_map) const override { return TypedArray(); }
TypedArray map_get_obstacles(RID p_map) const override { return TypedArray(); }
void map_force_update(RID p_map) override {}
+ uint32_t map_get_iteration_id(RID p_map) const override { return 0; }
+
RID region_create() override { return RID(); }
void region_set_enabled(RID p_region, bool p_enabled) override {}
bool region_get_enabled(RID p_region) const override { return false; }
@@ -92,6 +94,7 @@ public:
Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override { return Vector3(); }
Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override { return Vector3(); }
Vector3 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override { return Vector3(); }
+
RID link_create() override { return RID(); }
void link_set_map(RID p_link, RID p_map) override {}
RID link_get_map(RID p_link) const override { return RID(); }
@@ -111,6 +114,7 @@ public:
real_t link_get_travel_cost(RID p_link) const override { return 0; }
void link_set_owner_id(RID p_link, ObjectID p_owner_id) override {}
ObjectID link_get_owner_id(RID p_link) const override { return ObjectID(); }
+
RID agent_create() override { return RID(); }
void agent_set_map(RID p_agent, RID p_map) override {}
RID agent_get_map(RID p_agent) const override { return RID(); }
@@ -148,6 +152,7 @@ public:
uint32_t agent_get_avoidance_mask(RID p_agent) const override { return 0; }
void agent_set_avoidance_priority(RID p_agent, real_t p_priority) override {}
real_t agent_get_avoidance_priority(RID p_agent) const override { return 0; }
+
RID obstacle_create() override { return RID(); }
void obstacle_set_map(RID p_obstacle, RID p_map) override {}
RID obstacle_get_map(RID p_obstacle) const override { return RID(); }
@@ -169,6 +174,7 @@ public:
Vector obstacle_get_vertices(RID p_obstacle) const override { return Vector(); }
void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) override {}
uint32_t obstacle_get_avoidance_layers(RID p_obstacle) const override { return 0; }
+
void parse_source_geometry_data(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable()) override {}
void bake_from_source_geometry_data(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, const Callable &p_callback = Callable()) override {}
void bake_from_source_geometry_data_async(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, const Callable &p_callback = Callable()) override {}
@@ -180,8 +186,10 @@ public:
void init() override {}
void sync() override {}
void finish() override {}
+
NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const override { return NavigationUtilities::PathQueryResult(); }
int get_process_info(ProcessInfo p_info) const override { return 0; }
+
void set_debug_enabled(bool p_enabled) {}
bool get_debug_enabled() const { return false; }
};