From cfdfd304f1ad08b0498eda97b502aaccd95f559d Mon Sep 17 00:00:00 2001
From: smix8 <52464204+smix8@users.noreply.github.com>
Date: Mon, 6 Jun 2022 05:24:11 +0200
Subject: [PATCH] Add NavigationRegion costs for pathfinding
Add NavigationRegion costs for pathfinding.
---
doc/classes/NavigationRegion2D.xml | 9 ++++++
doc/classes/NavigationRegion3D.xml | 10 +++++++
doc/classes/NavigationServer2D.xml | 30 +++++++++++++++++++
doc/classes/NavigationServer3D.xml | 30 +++++++++++++++++++
.../navigation/godot_navigation_server.cpp | 30 +++++++++++++++++++
modules/navigation/godot_navigation_server.h | 6 ++++
modules/navigation/nav_map.cpp | 16 ++++++++--
modules/navigation/nav_region.h | 8 +++++
scene/2d/navigation_region_2d.cpp | 30 +++++++++++++++++++
scene/2d/navigation_region_2d.h | 9 ++++++
scene/3d/navigation_region_3d.cpp | 30 +++++++++++++++++++
scene/3d/navigation_region_3d.h | 9 ++++++
servers/navigation_server_2d.cpp | 10 +++++++
servers/navigation_server_2d.h | 8 +++++
servers/navigation_server_3d.cpp | 4 +++
servers/navigation_server_3d.h | 8 +++++
16 files changed, 244 insertions(+), 3 deletions(-)
diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml
index 5cd2e035b65f..542aa8f61997 100644
--- a/doc/classes/NavigationRegion2D.xml
+++ b/doc/classes/NavigationRegion2D.xml
@@ -7,6 +7,9 @@
A region of the navigation map. It tells the [NavigationServer2D] what can be navigated and what cannot, based on its [NavigationPolygon] resource.
Two regions can be connected to each other if they share a similar edge. You can set the minimum distance between two vertices required to connect two edges by using [method NavigationServer2D.map_set_edge_connection_margin].
[b]Note:[/b] Overlapping two regions' polygons is not enough for connecting two regions. They must share a similar edge.
+ The pathfinding cost of entering this region from another region can be controlled with the [member enter_cost] value.
+ [b]Note[/b]: This value is not added to the path cost when the start position is already inside this region.
+ The pathfinding cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier.
@@ -22,11 +25,17 @@
Determines if the [NavigationRegion2D] is enabled or disabled.
+
+ When pathfinding enters this regions navmesh from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
+
A bitfield determining all layers the region belongs to. These layers can be checked upon when requesting a path with [method NavigationServer2D.map_get_path].
The [NavigationPolygon] resource to use.
+
+ When pathfinding moves inside this regions navmesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path.
+
diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml
index 42f0e0c5d9cd..e45bca7f8ba1 100644
--- a/doc/classes/NavigationRegion3D.xml
+++ b/doc/classes/NavigationRegion3D.xml
@@ -6,6 +6,10 @@
A region of the navigation map. It tells the [NavigationServer3D] what can be navigated and what cannot, based on its [NavigationMesh] resource.
Two regions can be connected to each other if they share a similar edge. You can set the minimum distance between two vertices required to connect two edges by using [method NavigationServer3D.map_set_edge_connection_margin].
+ [b]Note:[/b] Overlapping two regions' navmeshes is not enough for connecting two regions. They must share a similar edge.
+ The cost of entering this region from another region can be controlled with the [member enter_cost] value.
+ [b]Note[/b]: This value is not added to the path cost when the start position is already inside this region.
+ The cost of traveling distances inside this region can be controlled with the [member travel_cost] multiplier.
@@ -28,12 +32,18 @@
Determines if the [NavigationRegion3D] is enabled or disabled.
+
+ When pathfinding enters this regions navmesh from another regions navmesh the [code]enter_cost[/code] value is added to the path distance for determining the shortest path.
+
A bitfield determining all layers the region belongs to. These layers can be checked upon when requesting a path with [method NavigationServer3D.map_get_path].
The [NavigationMesh] resource to use.
+
+ When pathfinding moves inside this regions navmesh the traveled distances are multiplied with [code]travel_cost[/code] for determining the shortest path.
+
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 1994a7a4c466..7b0dac99c3d9 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -247,6 +247,13 @@
Returns how many connections this [code]region[/code] has with other regions in the map.
+
+
+
+
+ Returns the [code]enter_cost[/code] of this [code]region[/code].
+
+
@@ -261,6 +268,21 @@
Returns the navigation map [RID] the requested [code]region[/code] is currently assigned to.
+
+
+
+
+ Returns the [code]travel_cost[/code] of this [code]region[/code].
+
+
+
+
+
+
+
+ Sets the [code]enter_cost[/code] for this [code]region[/code].
+
+
@@ -293,6 +315,14 @@
Sets the global transformation for the region.
+
+
+
+
+
+ Sets the [code]travel_cost[/code] for this [code]region[/code].
+
+
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index 2a729e71083d..d6574dd69a71 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -297,6 +297,13 @@
Returns how many connections this [code]region[/code] has with other regions in the map.
+
+
+
+
+ Returns the [code]enter_cost[/code] of this [code]region[/code].
+
+
@@ -311,6 +318,21 @@
Returns the navigation map [RID] the requested [code]region[/code] is currently assigned to.
+
+
+
+
+ Returns the [code]travel_cost[/code] of this [code]region[/code].
+
+
+
+
+
+
+
+ Sets the [code]enter_cost[/code] for this [code]region[/code].
+
+
@@ -343,6 +365,14 @@
Sets the global transformation for the region.
+
+
+
+
+
+ Sets the [code]travel_cost[/code] for this [code]region[/code].
+
+
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index cc9d05da4792..f4e719b0c17a 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -309,6 +309,36 @@ COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform) {
region->set_transform(p_transform);
}
+COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost) {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND(region == nullptr);
+ ERR_FAIL_COND(p_enter_cost < 0.0);
+
+ region->set_enter_cost(p_enter_cost);
+}
+
+real_t GodotNavigationServer::region_get_enter_cost(RID p_region) const {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND_V(region == nullptr, 0);
+
+ return region->get_enter_cost();
+}
+
+COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost) {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND(region == nullptr);
+ ERR_FAIL_COND(p_travel_cost < 0.0);
+
+ region->set_travel_cost(p_travel_cost);
+}
+
+real_t GodotNavigationServer::region_get_travel_cost(RID p_region) const {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND_V(region == nullptr, 0);
+
+ return region->get_travel_cost();
+}
+
COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers) {
NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND(region == nullptr);
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index 89e7311e51fb..1a7fddb7e673 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -109,6 +109,12 @@ class GodotNavigationServer : public NavigationServer3D {
virtual Array map_get_agents(RID p_map) const override;
virtual RID region_create() const override;
+
+ COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost);
+ virtual real_t region_get_enter_cost(RID p_region) const override;
+ COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost);
+ virtual real_t region_get_travel_cost(RID p_region) const override;
+
COMMAND_2(region_set_map, RID, p_region, RID, p_map);
virtual RID region_get_map(RID p_region) const override;
COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers);
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 344475fb377e..059dc989a871 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -140,6 +140,8 @@ Vector NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
float reachable_d = 1e30;
bool is_reachable = true;
+ gd::NavigationPoly *prev_least_cost_poly = nullptr;
+
while (true) {
// Takes the current least_cost_poly neighbors (iterating over its edges) and compute the traveled_distance.
for (size_t i = 0; i < navigation_polys[least_cost_id].poly->edges.size(); i++) {
@@ -156,9 +158,17 @@ Vector NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
continue;
}
+ float region_enter_cost = 0.0;
+ float region_travel_cost = least_cost_poly->poly->owner->get_travel_cost();
+
+ if (prev_least_cost_poly != nullptr && !(prev_least_cost_poly->poly->owner->get_self() == least_cost_poly->poly->owner->get_self())) {
+ region_enter_cost = least_cost_poly->poly->owner->get_enter_cost();
+ }
+ prev_least_cost_poly = least_cost_poly;
+
Vector3 pathway[2] = { connection.pathway_start, connection.pathway_end };
const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly->entry, pathway);
- const float new_distance = least_cost_poly->entry.distance_to(new_entry) + least_cost_poly->traveled_distance;
+ const float new_distance = (least_cost_poly->entry.distance_to(new_entry) * region_travel_cost) + region_enter_cost + least_cost_poly->traveled_distance;
const std::vector::iterator it = std::find(
navigation_polys.begin(),
@@ -238,7 +248,7 @@ Vector NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
for (List::Element *element = to_visit.front(); element != nullptr; element = element->next()) {
gd::NavigationPoly *np = &navigation_polys[element->get()];
float cost = np->traveled_distance;
- cost += np->entry.distance_to(end_point);
+ cost += (np->entry.distance_to(end_point) * np->poly->owner->get_travel_cost());
if (cost < least_cost) {
least_cost_id = np->self_id;
least_cost = cost;
@@ -249,7 +259,7 @@ Vector NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Stores the further reachable end polygon, in case our goal is not reachable.
if (is_reachable) {
- float d = navigation_polys[least_cost_id].entry.distance_to(p_destination);
+ float d = navigation_polys[least_cost_id].entry.distance_to(p_destination) * navigation_polys[least_cost_id].poly->owner->get_travel_cost();
if (reachable_d > d) {
reachable_d = d;
reachable_end = navigation_polys[least_cost_id].poly;
diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h
index 7a6da281c088..acde5de834e7 100644
--- a/modules/navigation/nav_region.h
+++ b/modules/navigation/nav_region.h
@@ -46,6 +46,8 @@ class NavRegion : public NavRid {
Transform3D transform;
Ref mesh;
uint32_t layers = 1;
+ float enter_cost = 0.0;
+ float travel_cost = 1.0;
Vector connections;
bool polygons_dirty = true;
@@ -65,6 +67,12 @@ class NavRegion : public NavRid {
return map;
}
+ void set_enter_cost(float p_enter_cost) { enter_cost = MAX(p_enter_cost, 0.0); }
+ float get_enter_cost() const { return enter_cost; }
+
+ void set_travel_cost(float p_travel_cost) { travel_cost = MAX(p_travel_cost, 0.0); }
+ float get_travel_cost() const { return travel_cost; }
+
void set_layers(uint32_t p_layers);
uint32_t get_layers() const;
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 41773d81c576..6f3222f27e1a 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -388,6 +388,26 @@ uint32_t NavigationRegion2D::get_layers() const {
return NavigationServer2D::get_singleton()->region_get_layers(region);
}
+void NavigationRegion2D::set_enter_cost(real_t p_enter_cost) {
+ ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
+ enter_cost = MAX(p_enter_cost, 0.0);
+ NavigationServer2D::get_singleton()->region_set_enter_cost(region, p_enter_cost);
+}
+
+real_t NavigationRegion2D::get_enter_cost() const {
+ return enter_cost;
+}
+
+void NavigationRegion2D::set_travel_cost(real_t p_travel_cost) {
+ ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
+ travel_cost = MAX(p_travel_cost, 0.0);
+ NavigationServer2D::get_singleton()->region_set_enter_cost(region, travel_cost);
+}
+
+real_t NavigationRegion2D::get_travel_cost() const {
+ return travel_cost;
+}
+
RID NavigationRegion2D::get_region_rid() const {
return region;
}
@@ -544,16 +564,26 @@ void NavigationRegion2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion2D::get_region_rid);
+ ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationRegion2D::set_enter_cost);
+ ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationRegion2D::get_enter_cost);
+
+ ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationRegion2D::set_travel_cost);
+ ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion2D::get_travel_cost);
+
ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_layers", "get_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");
}
NavigationRegion2D::NavigationRegion2D() {
set_notify_transform(true);
region = NavigationServer2D::get_singleton()->region_create();
+ NavigationServer2D::get_singleton()->region_set_enter_cost(region, get_enter_cost());
+ NavigationServer2D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
}
NavigationRegion2D::~NavigationRegion2D() {
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 3c4a4e81d989..31574749f7b9 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -98,6 +98,9 @@ class NavigationRegion2D : public Node2D {
RID region;
Ref navpoly;
+ real_t enter_cost = 0.0;
+ real_t travel_cost = 1.0;
+
void _navpoly_changed();
void _map_changed(RID p_RID);
@@ -119,6 +122,12 @@ class NavigationRegion2D : public Node2D {
RID get_region_rid() const;
+ void set_enter_cost(real_t p_enter_cost);
+ real_t get_enter_cost() const;
+
+ void set_travel_cost(real_t p_travel_cost);
+ real_t get_travel_cost() const;
+
void set_navigation_polygon(const Ref &p_navpoly);
Ref get_navigation_polygon() const;
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index cb8da182eeab..dda138281475 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -73,6 +73,26 @@ uint32_t NavigationRegion3D::get_layers() const {
return NavigationServer3D::get_singleton()->region_get_layers(region);
}
+void NavigationRegion3D::set_enter_cost(real_t p_enter_cost) {
+ ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive.");
+ enter_cost = MAX(p_enter_cost, 0.0);
+ NavigationServer3D::get_singleton()->region_set_enter_cost(region, p_enter_cost);
+}
+
+real_t NavigationRegion3D::get_enter_cost() const {
+ return enter_cost;
+}
+
+void NavigationRegion3D::set_travel_cost(real_t p_travel_cost) {
+ ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
+ travel_cost = MAX(p_travel_cost, 0.0);
+ NavigationServer3D::get_singleton()->region_set_enter_cost(region, travel_cost);
+}
+
+real_t NavigationRegion3D::get_travel_cost() const {
+ return travel_cost;
+}
+
RID NavigationRegion3D::get_region_rid() const {
return region;
}
@@ -224,12 +244,20 @@ void NavigationRegion3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_region_rid"), &NavigationRegion3D::get_region_rid);
+ ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationRegion3D::set_enter_cost);
+ ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationRegion3D::get_enter_cost);
+
+ ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationRegion3D::set_travel_cost);
+ ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationRegion3D::get_travel_cost);
+
ClassDB::bind_method(D_METHOD("bake_navigation_mesh", "on_thread"), &NavigationRegion3D::bake_navigation_mesh, DEFVAL(true));
ClassDB::bind_method(D_METHOD("_bake_finished", "nav_mesh"), &NavigationRegion3D::_bake_finished);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_layers", "get_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");
ADD_SIGNAL(MethodInfo("navigation_mesh_changed"));
ADD_SIGNAL(MethodInfo("bake_finished"));
@@ -243,6 +271,8 @@ void NavigationRegion3D::_navigation_changed() {
NavigationRegion3D::NavigationRegion3D() {
set_notify_transform(true);
region = NavigationServer3D::get_singleton()->region_create();
+ NavigationServer3D::get_singleton()->region_set_enter_cost(region, get_enter_cost());
+ NavigationServer3D::get_singleton()->region_set_travel_cost(region, get_travel_cost());
}
NavigationRegion3D::~NavigationRegion3D() {
diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h
index 140dfebf6afb..042684c5b7b5 100644
--- a/scene/3d/navigation_region_3d.h
+++ b/scene/3d/navigation_region_3d.h
@@ -41,6 +41,9 @@ class NavigationRegion3D : public Node3D {
RID region;
Ref navmesh;
+ real_t enter_cost = 0.0;
+ real_t travel_cost = 1.0;
+
Node *debug_view = nullptr;
Thread bake_thread;
@@ -59,6 +62,12 @@ class NavigationRegion3D : public Node3D {
RID get_region_rid() const;
+ void set_enter_cost(real_t p_enter_cost);
+ real_t get_enter_cost() const;
+
+ void set_travel_cost(real_t p_travel_cost);
+ real_t get_travel_cost() const;
+
void set_navigation_mesh(const Ref &p_navmesh);
Ref get_navigation_mesh() const;
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index 901d33501724..ab323e76e8dc 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -174,6 +174,10 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer2D::map_get_agents);
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer2D::region_create);
+ ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer2D::region_set_enter_cost);
+ ClassDB::bind_method(D_METHOD("region_get_enter_cost", "region"), &NavigationServer2D::region_get_enter_cost);
+ ClassDB::bind_method(D_METHOD("region_set_travel_cost", "region", "travel_cost"), &NavigationServer2D::region_set_travel_cost);
+ ClassDB::bind_method(D_METHOD("region_get_travel_cost", "region"), &NavigationServer2D::region_get_travel_cost);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer2D::region_set_map);
ClassDB::bind_method(D_METHOD("region_get_map", "region"), &NavigationServer2D::region_get_map);
ClassDB::bind_method(D_METHOD("region_set_layers", "region", "layers"), &NavigationServer2D::region_set_layers);
@@ -239,6 +243,12 @@ Vector2 FORWARD_2_R_C(v3_to_v2, map_get_closest_point, RID, p_map, const Vector2
RID FORWARD_2_C(map_get_closest_point_owner, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
RID FORWARD_0_C(region_create);
+
+void FORWARD_2_C(region_set_enter_cost, RID, p_region, real_t, p_enter_cost, rid_to_rid, real_to_real);
+real_t FORWARD_1_C(region_get_enter_cost, RID, p_region, rid_to_rid);
+void FORWARD_2_C(region_set_travel_cost, RID, p_region, real_t, p_travel_cost, rid_to_rid, real_to_real);
+real_t FORWARD_1_C(region_get_travel_cost, RID, p_region, rid_to_rid);
+
void FORWARD_2_C(region_set_map, RID, p_region, RID, p_map, rid_to_rid, rid_to_rid);
void FORWARD_2_C(region_set_layers, RID, p_region, uint32_t, p_layers, rid_to_rid, uint32_to_uint32);
uint32_t FORWARD_1_C(region_get_layers, RID, p_region, rid_to_rid);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index dfdcf5fca853..8e285147b15e 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -86,6 +86,14 @@ class NavigationServer2D : public Object {
/// Creates a new region.
virtual RID region_create() const;
+ /// Set the enter_cost of a region
+ virtual void region_set_enter_cost(RID p_region, real_t p_enter_cost) const;
+ virtual real_t region_get_enter_cost(RID p_region) const;
+
+ /// Set the travel_cost of a region
+ virtual void region_set_travel_cost(RID p_region, real_t p_travel_cost) const;
+ virtual real_t region_get_travel_cost(RID p_region) const;
+
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const;
virtual RID region_get_map(RID p_region) const;
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 0ce869ad1ab8..6d99f6dfbb37 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -52,6 +52,10 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer3D::map_get_agents);
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer3D::region_create);
+ ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer3D::region_set_enter_cost);
+ ClassDB::bind_method(D_METHOD("region_get_enter_cost", "region"), &NavigationServer3D::region_get_enter_cost);
+ ClassDB::bind_method(D_METHOD("region_set_travel_cost", "region", "travel_cost"), &NavigationServer3D::region_set_travel_cost);
+ ClassDB::bind_method(D_METHOD("region_get_travel_cost", "region"), &NavigationServer3D::region_get_travel_cost);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer3D::region_set_map);
ClassDB::bind_method(D_METHOD("region_get_map", "region"), &NavigationServer3D::region_get_map);
ClassDB::bind_method(D_METHOD("region_set_layers", "region", "layers"), &NavigationServer3D::region_set_layers);
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index c3d3a589a9f6..9b7e48e8d1cf 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -97,6 +97,14 @@ class NavigationServer3D : public Object {
/// Creates a new region.
virtual RID region_create() const = 0;
+ /// Set the enter_cost of a region
+ virtual void region_set_enter_cost(RID p_region, real_t p_enter_cost) const = 0;
+ virtual real_t region_get_enter_cost(RID p_region) const = 0;
+
+ /// Set the travel_cost of a region
+ virtual void region_set_travel_cost(RID p_region, real_t p_travel_cost) const = 0;
+ virtual real_t region_get_travel_cost(RID p_region) const = 0;
+
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const = 0;
virtual RID region_get_map(RID p_region) const = 0;