diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 3200eafa00d..ce9be3dd5e2 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -171,6 +171,11 @@ Comment: CA certificates
Copyright: Mozilla Contributors
License: MPL-2.0
+Files: ./thirdparty/clipper2/
+Comment: Clipper2
+Copyright: 2010-2013, Angus Johnson
+License: BSL-1.0
+
Files: ./thirdparty/cvtt/
Comment: Convection Texture Tools Stand-Alone Kernels
Copyright: 2018, Eric Lasota
diff --git a/SConstruct b/SConstruct
index d01062db8d3..a06dfc1bde5 100644
--- a/SConstruct
+++ b/SConstruct
@@ -226,6 +226,7 @@ opts.Add("scu_limit", "Max includes per SCU file when using scu_build (determine
# Thirdparty libraries
opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True))
opts.Add(BoolVariable("builtin_certs", "Use the built-in SSL certificates bundles", True))
+opts.Add(BoolVariable("builtin_clipper2", "Use the built-in Clipper2 library", True))
opts.Add(BoolVariable("builtin_embree", "Use the built-in Embree library", True))
opts.Add(BoolVariable("builtin_enet", "Use the built-in ENet library", True))
opts.Add(BoolVariable("builtin_freetype", "Use the built-in FreeType library", True))
diff --git a/core/SCsub b/core/SCsub
index ab78eeedc71..3b1a7ca79a1 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -89,6 +89,24 @@ if env["brotli"] and env["builtin_brotli"]:
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_brotli_sources)
+# Clipper2 Thirdparty source files used for polygon and polyline boolean operations.
+if env["builtin_clipper2"]:
+ thirdparty_clipper_dir = "#thirdparty/clipper2/"
+ thirdparty_clipper_sources = [
+ "src/clipper.engine.cpp",
+ "src/clipper.offset.cpp",
+ "src/clipper.rectclip.cpp",
+ ]
+ thirdparty_clipper_sources = [thirdparty_clipper_dir + file for file in thirdparty_clipper_sources]
+
+ env_thirdparty.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"])
+ env.Prepend(CPPPATH=[thirdparty_clipper_dir + "include"])
+
+ env_thirdparty.Append(CPPDEFINES=["CLIPPER2_ENABLED"])
+ env.Append(CPPDEFINES=["CLIPPER2_ENABLED"])
+
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_clipper_sources)
+
# Zlib library, can be unbundled
if env["builtin_zlib"]:
thirdparty_zlib_dir = "#thirdparty/zlib/"
diff --git a/doc/classes/NavigationMeshSourceGeometryData2D.xml b/doc/classes/NavigationMeshSourceGeometryData2D.xml
new file mode 100644
index 00000000000..4bf5213da7f
--- /dev/null
+++ b/doc/classes/NavigationMeshSourceGeometryData2D.xml
@@ -0,0 +1,65 @@
+
+
+
+ Container for parsed source geometry data used in navigation mesh baking.
+
+
+ Container for parsed source geometry data used in navigation mesh baking.
+
+
+
+
+
+
+
+
+ Adds the outline points of a shape as obstructed area.
+
+
+
+
+
+
+ Adds the outline points of a shape as traversable area.
+
+
+
+
+
+ Clears the internal data.
+
+
+
+
+
+ Returns all the obstructed area outlines arrays.
+
+
+
+
+
+ Returns all the traversable area outlines arrays.
+
+
+
+
+
+ Returns [code]true[/code] when parsed source geometry data exists.
+
+
+
+
+
+
+ Sets all the obstructed area outlines arrays.
+
+
+
+
+
+
+ Sets all the traversable area outlines arrays.
+
+
+
+
diff --git a/doc/classes/NavigationPolygon.xml b/doc/classes/NavigationPolygon.xml
index fe28c5a468b..e0ad6032def 100644
--- a/doc/classes/NavigationPolygon.xml
+++ b/doc/classes/NavigationPolygon.xml
@@ -1,44 +1,44 @@
- A navigation polygon that defines traversable areas and obstacles.
+ A 2D navigation mesh that describes a traversable surface for pathfinding.
- There are two ways to create polygons. Either by using the [method add_outline] method, or using the [method add_polygon] method.
- Using [method add_outline]:
+ A navigation mesh can be created either by baking it with the help of the [NavigationServer2D], or by adding vertices and convex polygon indices arrays manually.
+ To bake a navigation mesh at least one outline needs to be added that defines the outer bounds of the baked area.
[codeblocks]
[gdscript]
- var polygon = NavigationPolygon.new()
- var outline = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
- polygon.add_outline(outline)
- polygon.make_polygons_from_outlines()
- $NavigationRegion2D.navigation_polygon = polygon
+ var new_navigation_mesh = NavigationPolygon.new()
+ var bounding_outline = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
+ new_navigation_mesh.add_outline(bounding_outline)
+ NavigationServer2D.bake_from_source_geometry_data(new_navigation_mesh, NavigationMeshSourceGeometryData2D.new());
+ $NavigationRegion2D.navigation_polygon = new_navigation_mesh
[/gdscript]
[csharp]
- var polygon = new NavigationPolygon();
- var outline = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) };
- polygon.AddOutline(outline);
- polygon.MakePolygonsFromOutlines();
- GetNode<NavigationRegion2D>("NavigationRegion2D").NavigationPolygon = polygon;
+ var newNavigationMesh = new NavigationPolygon();
+ var boundingOutline = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) };
+ newNavigationMesh.AddOutline(boundingOutline);
+ NavigationServer2D.BakeFromSourceGeometryData(newNavigationMesh, new NavigationMeshSourceGeometryData2D());
+ GetNode<NavigationRegion2D>("NavigationRegion2D").NavigationPolygon = newNavigationMesh;
[/csharp]
[/codeblocks]
- Using [method add_polygon] and indices of the vertices array.
+ Adding vertices and polygon indices manually.
[codeblocks]
[gdscript]
- var polygon = NavigationPolygon.new()
- var vertices = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
- polygon.vertices = vertices
- var indices = PackedInt32Array([0, 1, 2, 3])
- polygon.add_polygon(indices)
- $NavigationRegion2D.navigation_polygon = polygon
+ var new_navigation_mesh = NavigationPolygon.new()
+ var new_vertices = PackedVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
+ new_navigation_mesh.vertices = new_vertices
+ var new_polygon_indices = PackedInt32Array([0, 1, 2, 3])
+ new_navigation_mesh.add_polygon(new_polygon_indices)
+ $NavigationRegion2D.navigation_polygon = new_navigation_mesh
[/gdscript]
[csharp]
- var polygon = new NavigationPolygon();
- var vertices = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) };
- polygon.Vertices = vertices;
- var indices = new int[] { 0, 1, 2, 3 };
- polygon.AddPolygon(indices);
- GetNode<NavigationRegion2D>("NavigationRegion2D").NavigationPolygon = polygon;
+ var newNavigationMesh = new NavigationPolygon();
+ var newVertices = new Vector2[] { new Vector2(0, 0), new Vector2(0, 50), new Vector2(50, 50), new Vector2(50, 0) };
+ newNavigationMesh.Vertices = newVertices;
+ var newPolygonIndices = new int[] { 0, 1, 2, 3 };
+ newNavigationMesh.AddPolygon(newPolygonIndices);
+ GetNode<NavigationRegion2D>("NavigationRegion2D").NavigationPolygon = newNavigationMesh;
[/csharp]
[/codeblocks]
@@ -51,7 +51,7 @@
- Appends a [PackedVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines. You have to call [method make_polygons_from_outlines] in order for this array to be converted to polygons that the engine will use.
+ Appends a [PackedVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines.
@@ -59,7 +59,7 @@
- Adds a [PackedVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines at a fixed position. You have to call [method make_polygons_from_outlines] in order for this array to be converted to polygons that the engine will use.
+ Adds a [PackedVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines at a fixed position.
@@ -106,6 +106,13 @@
Returns the number of outlines that were created in the editor or by script.
+
+
+
+
+ Returns whether or not the specified layer of the [member parsed_collision_mask] is enabled, given a [param layer_number] between 1 and 32.
+
+
@@ -125,10 +132,11 @@
Returns a [PackedVector2Array] containing all the vertices being used to create the polygons.
-
+
Creates polygons from the outlines added in the editor or by script.
+ [i]Deprecated.[/i] This function is deprecated, and might be removed in a future release. Use [method NavigationServer2D.parse_source_geometry_data] and [method NavigationServer2D.bake_from_source_geometry_data] instead.
@@ -146,6 +154,14 @@
Changes an outline created in the editor or by script. You have to call [method make_polygons_from_outlines] for the polygons to update.
+
+
+
+
+
+ Based on [param value], enables or disables the specified layer in the [member parsed_collision_mask], given a [param layer_number] between 1 and 32.
+
+
@@ -155,8 +171,52 @@
+
+ The distance to erode/shrink the walkable surface when baking the navigation mesh.
+
The cell size used to rasterize the navigation mesh vertices. Must match with the cell size on the navigation map.
+
+ The physics layers to scan for static colliders.
+ Only used when [member parsed_geometry_type] is [constant PARSED_GEOMETRY_STATIC_COLLIDERS] or [constant PARSED_GEOMETRY_BOTH].
+
+
+ Determines which type of nodes will be parsed as geometry. See [enum ParsedGeometryType] for possible values.
+
+
+ The group name of nodes that should be parsed for baking source geometry.
+ Only used when [member source_geometry_mode] is [constant SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN] or [constant SOURCE_GEOMETRY_GROUPS_EXPLICIT].
+
+
+ The source of the geometry used when baking. See [enum SourceGeometryMode] for possible values.
+
+
+
+ Parses mesh instances as obstruction geometry. This includes [Polygon2D], [MeshInstance2D], [MultiMeshInstance2D], and [TileMap] nodes.
+ Meshes are only parsed when they use a 2D vertices surface format.
+
+
+ Parses [StaticBody2D] and [TileMap] colliders as obstruction geometry. The collider should be in any of the layers specified by [member parsed_collision_mask].
+
+
+ Both [constant PARSED_GEOMETRY_MESH_INSTANCES] and [constant PARSED_GEOMETRY_STATIC_COLLIDERS].
+
+
+ Represents the size of the [enum ParsedGeometryType] enum.
+
+
+ Scans the child nodes of the root node recursively for geometry.
+
+
+ Scans nodes in a group and their child nodes recursively for geometry. The group is specified by [member source_geometry_group_name].
+
+
+ Uses nodes in a group for geometry. The group is specified by [member source_geometry_group_name].
+
+
+ Represents the size of the [enum SourceGeometryMode] enum.
+
+
diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml
index acd789cc22d..e023d8dd7fb 100644
--- a/doc/classes/NavigationRegion2D.xml
+++ b/doc/classes/NavigationRegion2D.xml
@@ -16,6 +16,13 @@
$DOCS_URL/tutorials/navigation/navigation_using_navigationregions.html
+
+
+
+
+ Bakes the [NavigationPolygon]. If [param on_thread] is set to [code]true[/code] (default), the baking is done on a separate thread.
+
+
@@ -93,4 +100,16 @@
If enabled the navigation region will use edge connections to connect with other navigation regions within proximity of the navigation map edge connection margin.
+
+
+
+ Emitted when a navigation polygon bake operation is completed.
+
+
+
+
+ Emitted when the used navigation polygon is replaced or changes to the internals of the current navigation polygon are committed.
+
+
+
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index a52c9abefdb..a25f048df3f 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -182,6 +182,24 @@
Replaces the internal velocity in the collision avoidance simulation with [param velocity] for the specified [param agent]. When an agent is teleported to a new position far away this function should be used in the same frame. If called frequently this function can get agents stuck.
+
+
+
+
+
+
+ Bakes the provided [param navigation_polygon] with the data from the provided [param source_geometry_data]. After the process is finished the optional [param callback] will be called.
+
+
+
+
+
+
+
+
+ Bakes the provided [param navigation_polygon] with the data from the provided [param source_geometry_data] as an async task running on a background thread. After the process is finished the optional [param callback] will be called.
+
+
@@ -579,6 +597,18 @@
Sets the outline vertices for the obstacle. If the vertices are winded in clockwise order agents will be pushed in by the obstacle, else they will be pushed out.
+
+
+
+
+
+
+
+ Parses the [SceneTree] for source geometry according to the properties of [param navigation_polygon]. Updates the provided [param source_geometry_data] resource with the resulting data. The resource can then be used to bake a navigation mesh with [method bake_from_source_geometry_data]. After the process is finished the optional [param callback] will be called.
+ [b]Note:[/b] This function needs to run on the main thread or with a deferred call as the SceneTree is not thread-safe.
+ [b]Performance:[/b] While convenient, reading data arrays from [Mesh] resources can affect the frame rate negatively. The data needs to be received from the GPU, stalling the [RenderingServer] in the process. For performance prefer the use of e.g. collision shapes or creating the data arrays entirely in code.
+
+
diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp
index 957a520d8ac..48335f3b948 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.cpp
+++ b/editor/plugins/navigation_polygon_editor_plugin.cpp
@@ -32,6 +32,8 @@
#include "editor/editor_node.h"
#include "editor/editor_undo_redo_manager.h"
+#include "scene/2d/navigation_region_2d.h"
+#include "scene/gui/dialogs.h"
Ref NavigationPolygonEditor::_ensure_navpoly() const {
Ref navpoly = node->get_navigation_polygon();
@@ -71,7 +73,6 @@ Variant NavigationPolygonEditor::_get_polygon(int p_idx) const {
void NavigationPolygonEditor::_set_polygon(int p_idx, const Variant &p_polygon) const {
Ref navpoly = _ensure_navpoly();
navpoly->set_outline(p_idx, p_polygon);
- navpoly->make_polygons_from_outlines();
}
void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) {
@@ -79,8 +80,6 @@ void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "add_outline", p_polygon);
undo_redo->add_undo_method(navpoly.ptr(), "remove_outline", navpoly->get_outline_count());
- undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines");
- undo_redo->add_undo_method(navpoly.ptr(), "make_polygons_from_outlines");
}
void NavigationPolygonEditor::_action_remove_polygon(int p_idx) {
@@ -88,8 +87,6 @@ void NavigationPolygonEditor::_action_remove_polygon(int p_idx) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "remove_outline", p_idx);
undo_redo->add_undo_method(navpoly.ptr(), "add_outline_at_index", navpoly->get_outline(p_idx), p_idx);
- undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines");
- undo_redo->add_undo_method(navpoly.ptr(), "make_polygons_from_outlines");
}
void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
@@ -97,8 +94,6 @@ void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_pr
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "set_outline", p_idx, p_polygon);
undo_redo->add_undo_method(navpoly.ptr(), "set_outline", p_idx, p_previous);
- undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines");
- undo_redo->add_undo_method(navpoly.ptr(), "make_polygons_from_outlines");
}
bool NavigationPolygonEditor::_has_resource() const {
@@ -119,7 +114,84 @@ void NavigationPolygonEditor::_create_resource() {
_menu_option(MODE_CREATE);
}
-NavigationPolygonEditor::NavigationPolygonEditor() {}
+NavigationPolygonEditor::NavigationPolygonEditor() {
+ bake_hbox = memnew(HBoxContainer);
+ add_child(bake_hbox);
+
+ button_bake = memnew(Button);
+ button_bake->set_flat(true);
+ bake_hbox->add_child(button_bake);
+ button_bake->set_toggle_mode(true);
+ button_bake->set_text(TTR("Bake NavigationPolygon"));
+ button_bake->set_tooltip_text(TTR("Bakes the NavigationPolygon by first parsing the scene for source geometry and then creating the navigation polygon vertices and polygons."));
+ button_bake->connect("pressed", callable_mp(this, &NavigationPolygonEditor::_bake_pressed));
+
+ button_reset = memnew(Button);
+ button_reset->set_flat(true);
+ bake_hbox->add_child(button_reset);
+ button_reset->set_text(TTR("Clear NavigationPolygon"));
+ button_reset->set_tooltip_text(TTR("Clears the internal NavigationPolygon outlines, vertices and polygons."));
+ button_reset->connect("pressed", callable_mp(this, &NavigationPolygonEditor::_clear_pressed));
+
+ bake_info = memnew(Label);
+ bake_hbox->add_child(bake_info);
+
+ err_dialog = memnew(AcceptDialog);
+ add_child(err_dialog);
+ node = nullptr;
+}
+
+void NavigationPolygonEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ button_bake->set_icon(get_theme_icon(SNAME("Bake"), SNAME("EditorIcons")));
+ button_reset->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
+ } break;
+ }
+}
+
+void NavigationPolygonEditor::_bake_pressed() {
+ button_bake->set_pressed(false);
+
+ ERR_FAIL_NULL(node);
+ Ref navigation_polygon = node->get_navigation_polygon();
+ if (!navigation_polygon.is_valid()) {
+ err_dialog->set_text(TTR("A NavigationPolygon resource must be set or created for this node to work."));
+ err_dialog->popup_centered();
+ return;
+ }
+
+ node->bake_navigation_polygon(true);
+
+ node->queue_redraw();
+}
+
+void NavigationPolygonEditor::_clear_pressed() {
+ if (node) {
+ if (node->get_navigation_polygon().is_valid()) {
+ node->get_navigation_polygon()->clear();
+ }
+ }
+
+ button_bake->set_pressed(false);
+ bake_info->set_text("");
+
+ if (node) {
+ node->queue_redraw();
+ }
+}
+
+void NavigationPolygonEditor::_update_polygon_editing_state() {
+ if (!_get_node()) {
+ return;
+ }
+
+ if (node != nullptr && node->get_navigation_polygon().is_valid()) {
+ bake_hbox->show();
+ } else {
+ bake_hbox->hide();
+ }
+}
NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin() :
AbstractPolygon2DEditorPlugin(memnew(NavigationPolygonEditor), "NavigationRegion2D") {
diff --git a/editor/plugins/navigation_polygon_editor_plugin.h b/editor/plugins/navigation_polygon_editor_plugin.h
index f43c052dd36..f1d0cd87517 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.h
+++ b/editor/plugins/navigation_polygon_editor_plugin.h
@@ -32,16 +32,38 @@
#define NAVIGATION_POLYGON_EDITOR_PLUGIN_H
#include "editor/plugins/abstract_polygon_2d_editor.h"
-#include "scene/2d/navigation_region_2d.h"
+
+#include "editor/editor_plugin.h"
+
+class AcceptDialog;
+class HBoxContainer;
+class NavigationPolygon;
+class NavigationRegion2D;
class NavigationPolygonEditor : public AbstractPolygon2DEditor {
+ friend class NavigationPolygonEditorPlugin;
+
GDCLASS(NavigationPolygonEditor, AbstractPolygon2DEditor);
NavigationRegion2D *node = nullptr;
Ref _ensure_navpoly() const;
+ AcceptDialog *err_dialog = nullptr;
+
+ HBoxContainer *bake_hbox = nullptr;
+ Button *button_bake = nullptr;
+ Button *button_reset = nullptr;
+ Label *bake_info = nullptr;
+
+ void _bake_pressed();
+ void _clear_pressed();
+
+ void _update_polygon_editing_state();
+
protected:
+ void _notification(int p_what);
+
virtual Node2D *_get_node() const override;
virtual void _set_node(Node *p_polygon) override;
@@ -63,6 +85,8 @@ public:
class NavigationPolygonEditorPlugin : public AbstractPolygon2DEditorPlugin {
GDCLASS(NavigationPolygonEditorPlugin, AbstractPolygon2DEditorPlugin);
+ NavigationPolygonEditor *navigation_polygon_editor = nullptr;
+
public:
NavigationPolygonEditorPlugin();
};
diff --git a/main/main.cpp b/main/main.cpp
index cd9bd6d1d34..2b2ed3d6ece 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -70,6 +70,7 @@
#include "servers/movie_writer/movie_writer.h"
#include "servers/movie_writer/movie_writer_mjpeg.h"
#include "servers/navigation_server_2d.h"
+#include "servers/navigation_server_2d_dummy.h"
#include "servers/navigation_server_3d.h"
#include "servers/navigation_server_3d_dummy.h"
#include "servers/physics_server_2d.h"
@@ -339,8 +340,14 @@ void initialize_navigation_server() {
navigation_server_3d->init();
// Init 2D Navigation Server
- navigation_server_2d = memnew(NavigationServer2D);
+ navigation_server_2d = NavigationServer2DManager::new_default_server();
+ if (!navigation_server_2d) {
+ WARN_PRINT_ONCE("No NavigationServer2D implementation has been registered! Falling back to a dummy implementation: navigation features will be unavailable.");
+ navigation_server_2d = memnew(NavigationServer2DDummy);
+ }
+
ERR_FAIL_NULL_MSG(navigation_server_2d, "Failed to initialize NavigationServer2D.");
+ navigation_server_2d->init();
}
void finalize_navigation_server() {
@@ -350,6 +357,7 @@ void finalize_navigation_server() {
navigation_server_3d = nullptr;
ERR_FAIL_NULL(navigation_server_2d);
+ navigation_server_2d->finish();
memdelete(navigation_server_2d);
navigation_server_2d = nullptr;
}
@@ -3490,6 +3498,9 @@ bool Main::iteration() {
// process all our active interfaces
XRServer::get_singleton()->_process();
+ NavigationServer2D::get_singleton()->sync();
+ NavigationServer3D::get_singleton()->sync();
+
for (int iters = 0; iters < advance.physics_steps; ++iters) {
if (Input::get_singleton()->is_using_input_buffering() && agile_input_event_flushing) {
Input::get_singleton()->flush_buffered_events();
diff --git a/modules/navigation/config.py b/modules/navigation/config.py
index d22f9454ed2..a42f27fbe12 100644
--- a/modules/navigation/config.py
+++ b/modules/navigation/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return True
+ return not env["disable_3d"]
def configure(env):
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index 9162fcf171a..32482e0c9d0 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -1086,6 +1086,14 @@ void GodotNavigationServer::map_force_update(RID p_map) {
map->sync();
}
+void GodotNavigationServer::sync() {
+#ifndef _3D_DISABLED
+ if (navmesh_generator_3d) {
+ navmesh_generator_3d->sync();
+ }
+#endif // _3D_DISABLED
+}
+
void GodotNavigationServer::process(real_t p_delta_time) {
flush_queries();
@@ -1093,16 +1101,6 @@ void GodotNavigationServer::process(real_t p_delta_time) {
return;
}
-#ifndef _3D_DISABLED
- // Sync finished navmesh bakes before doing NavMap updates.
- if (navmesh_generator_3d) {
- navmesh_generator_3d->sync();
- // Finished bakes emit callbacks and users might have reacted to those.
- // Flush queue again so users do not have to wait for the next sync.
- flush_queries();
- }
-#endif // _3D_DISABLED
-
int _new_pm_region_count = 0;
int _new_pm_agent_count = 0;
int _new_pm_link_count = 0;
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index c12605bc7af..4ead4fc398b 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -243,6 +243,7 @@ public:
void flush_queries();
virtual void process(real_t p_delta_time) override;
virtual void init() override;
+ virtual void sync() override;
virtual void finish() override;
virtual NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const override;
diff --git a/modules/navigation/godot_navigation_server_2d.cpp b/modules/navigation/godot_navigation_server_2d.cpp
new file mode 100644
index 00000000000..b54729e06fc
--- /dev/null
+++ b/modules/navigation/godot_navigation_server_2d.cpp
@@ -0,0 +1,369 @@
+/**************************************************************************/
+/* godot_navigation_server_2d.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "godot_navigation_server_2d.h"
+
+#ifdef CLIPPER2_ENABLED
+#include "nav_mesh_generator_2d.h"
+#endif // CLIPPER2_ENABLED
+
+#include "servers/navigation_server_3d.h"
+
+#define FORWARD_0(FUNC_NAME) \
+ GodotNavigationServer2D::FUNC_NAME() { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(); \
+ }
+
+#define FORWARD_0_C(FUNC_NAME) \
+ GodotNavigationServer2D::FUNC_NAME() \
+ const { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(); \
+ }
+
+#define FORWARD_1(FUNC_NAME, T_0, D_0, CONV_0) \
+ GodotNavigationServer2D::FUNC_NAME(T_0 D_0) { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0)); \
+ }
+
+#define FORWARD_1_C(FUNC_NAME, T_0, D_0, CONV_0) \
+ GodotNavigationServer2D::FUNC_NAME(T_0 D_0) \
+ const { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0)); \
+ }
+
+#define FORWARD_1_R_C(CONV_R, FUNC_NAME, T_0, D_0, CONV_0) \
+ GodotNavigationServer2D::FUNC_NAME(T_0 D_0) \
+ const { \
+ return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0))); \
+ }
+
+#define FORWARD_2(FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
+ GodotNavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1) { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1)); \
+ }
+
+#define FORWARD_2_C(FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
+ GodotNavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1) \
+ const { \
+ return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1)); \
+ }
+
+#define FORWARD_2_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
+ GodotNavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1) \
+ const { \
+ return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1))); \
+ }
+
+#define FORWARD_5_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, T_4, D_4, CONV_0, CONV_1, CONV_2, CONV_3, CONV_4) \
+ GodotNavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3, T_4 D_4) \
+ const { \
+ return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3), CONV_4(D_4))); \
+ }
+
+static RID rid_to_rid(const RID d) {
+ return d;
+}
+
+static bool bool_to_bool(const bool d) {
+ return d;
+}
+
+static int int_to_int(const int d) {
+ return d;
+}
+
+static uint32_t uint32_to_uint32(const uint32_t d) {
+ return d;
+}
+
+static real_t real_to_real(const real_t d) {
+ return d;
+}
+
+static Vector3 v2_to_v3(const Vector2 d) {
+ return Vector3(d.x, 0.0, d.y);
+}
+
+static Vector2 v3_to_v2(const Vector3 &d) {
+ return Vector2(d.x, d.z);
+}
+
+static Vector vector_v2_to_v3(const Vector &d) {
+ Vector nd;
+ nd.resize(d.size());
+ for (int i(0); i < nd.size(); i++) {
+ nd.write[i] = v2_to_v3(d[i]);
+ }
+ return nd;
+}
+
+static Vector vector_v3_to_v2(const Vector &d) {
+ Vector nd;
+ nd.resize(d.size());
+ for (int i(0); i < nd.size(); i++) {
+ nd.write[i] = v3_to_v2(d[i]);
+ }
+ return nd;
+}
+
+static Transform3D trf2_to_trf3(const Transform2D &d) {
+ Vector3 o(v2_to_v3(d.get_origin()));
+ Basis b;
+ b.rotate(Vector3(0, -1, 0), d.get_rotation());
+ b.scale(v2_to_v3(d.get_scale()));
+ return Transform3D(b, o);
+}
+
+static ObjectID id_to_id(const ObjectID &id) {
+ return id;
+}
+
+static Callable callable_to_callable(const Callable &c) {
+ return c;
+}
+
+static Ref poly_to_mesh(Ref d) {
+ if (d.is_valid()) {
+ return d->get_navigation_mesh();
+ } else {
+ return Ref();
+ }
+}
+
+void GodotNavigationServer2D::init() {
+#ifdef CLIPPER2_ENABLED
+ navmesh_generator_2d = memnew(NavMeshGenerator2D);
+ ERR_FAIL_NULL_MSG(navmesh_generator_2d, "Failed to init NavMeshGenerator2D.");
+#endif // CLIPPER2_ENABLED
+}
+
+void GodotNavigationServer2D::sync() {
+#ifdef CLIPPER2_ENABLED
+ if (navmesh_generator_2d) {
+ navmesh_generator_2d->sync();
+ }
+#endif // CLIPPER2_ENABLED
+}
+
+void GodotNavigationServer2D::finish() {
+#ifdef CLIPPER2_ENABLED
+ if (navmesh_generator_2d) {
+ navmesh_generator_2d->finish();
+ memdelete(navmesh_generator_2d);
+ navmesh_generator_2d = nullptr;
+ }
+#endif // CLIPPER2_ENABLED
+}
+
+void GodotNavigationServer2D::parse_source_geometry_data(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, Node *p_root_node, const Callable &p_callback) {
+ ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "The SceneTree can only be parsed on the main thread. Call this function from the main thread or use call_deferred().");
+ ERR_FAIL_COND_MSG(!p_navigation_mesh.is_valid(), "Invalid navigation polygon.");
+ ERR_FAIL_NULL_MSG(p_root_node, "No parsing root node specified.");
+ ERR_FAIL_COND_MSG(!p_root_node->is_inside_tree(), "The root node needs to be inside the SceneTree.");
+
+#ifdef CLIPPER2_ENABLED
+ ERR_FAIL_NULL(NavMeshGenerator2D::get_singleton());
+ NavMeshGenerator2D::get_singleton()->parse_source_geometry_data(p_navigation_mesh, p_source_geometry_data, p_root_node, p_callback);
+#endif // CLIPPER2_ENABLED
+}
+
+void GodotNavigationServer2D::bake_from_source_geometry_data(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, const Callable &p_callback) {
+ ERR_FAIL_COND_MSG(!p_navigation_mesh.is_valid(), "Invalid navigation polygon.");
+ ERR_FAIL_COND_MSG(!p_source_geometry_data.is_valid(), "Invalid NavigationMeshSourceGeometryData2D.");
+
+#ifdef CLIPPER2_ENABLED
+ ERR_FAIL_NULL(NavMeshGenerator2D::get_singleton());
+ NavMeshGenerator2D::get_singleton()->bake_from_source_geometry_data(p_navigation_mesh, p_source_geometry_data, p_callback);
+#endif // CLIPPER2_ENABLED
+}
+
+void GodotNavigationServer2D::bake_from_source_geometry_data_async(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, const Callable &p_callback) {
+ ERR_FAIL_COND_MSG(!p_navigation_mesh.is_valid(), "Invalid navigation mesh.");
+ ERR_FAIL_COND_MSG(!p_source_geometry_data.is_valid(), "Invalid NavigationMeshSourceGeometryData2D.");
+
+#ifdef CLIPPER2_ENABLED
+ ERR_FAIL_NULL(NavMeshGenerator2D::get_singleton());
+ NavMeshGenerator2D::get_singleton()->bake_from_source_geometry_data_async(p_navigation_mesh, p_source_geometry_data, p_callback);
+#endif // CLIPPER2_ENABLED
+}
+
+GodotNavigationServer2D::GodotNavigationServer2D() {}
+
+GodotNavigationServer2D::~GodotNavigationServer2D() {}
+
+TypedArray FORWARD_0_C(get_maps);
+
+TypedArray FORWARD_1_C(map_get_links, RID, p_map, rid_to_rid);
+
+TypedArray FORWARD_1_C(map_get_regions, RID, p_map, rid_to_rid);
+
+TypedArray FORWARD_1_C(map_get_agents, RID, p_map, rid_to_rid);
+
+TypedArray FORWARD_1_C(map_get_obstacles, RID, p_map, rid_to_rid);
+
+RID FORWARD_1_C(region_get_map, RID, p_region, rid_to_rid);
+
+RID FORWARD_1_C(agent_get_map, RID, p_agent, rid_to_rid);
+
+RID FORWARD_0(map_create);
+
+void FORWARD_2(map_set_active, RID, p_map, bool, p_active, rid_to_rid, bool_to_bool);
+
+bool FORWARD_1_C(map_is_active, RID, p_map, rid_to_rid);
+
+void GodotNavigationServer2D::map_force_update(RID p_map) {
+ NavigationServer3D::get_singleton()->map_force_update(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);
+
+void FORWARD_2(map_set_use_edge_connections, RID, p_map, bool, p_enabled, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(map_get_use_edge_connections, RID, p_map, rid_to_rid);
+
+void FORWARD_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin, rid_to_rid, real_to_real);
+real_t FORWARD_1_C(map_get_edge_connection_margin, RID, p_map, rid_to_rid);
+
+void FORWARD_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius, rid_to_rid, real_to_real);
+real_t FORWARD_1_C(map_get_link_connection_radius, RID, p_map, rid_to_rid);
+
+Vector FORWARD_5_R_C(vector_v3_to_v2, map_get_path, RID, p_map, Vector2, p_origin, Vector2, p_destination, bool, p_optimize, uint32_t, p_layers, rid_to_rid, v2_to_v3, v2_to_v3, bool_to_bool, uint32_to_uint32);
+
+Vector2 FORWARD_2_R_C(v3_to_v2, map_get_closest_point, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
+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(region_create);
+
+void FORWARD_2(region_set_enabled, RID, p_region, bool, p_enabled, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(region_get_enabled, RID, p_region, rid_to_rid);
+void FORWARD_2(region_set_use_edge_connections, RID, p_region, bool, p_enabled, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(region_get_use_edge_connections, RID, p_region, rid_to_rid);
+
+void FORWARD_2(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(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(region_set_owner_id, RID, p_region, ObjectID, p_owner_id, rid_to_rid, id_to_id);
+ObjectID FORWARD_1_C(region_get_owner_id, RID, p_region, rid_to_rid);
+bool FORWARD_2_C(region_owns_point, RID, p_region, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
+
+void FORWARD_2(region_set_map, RID, p_region, RID, p_map, rid_to_rid, rid_to_rid);
+void FORWARD_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers, rid_to_rid, uint32_to_uint32);
+uint32_t FORWARD_1_C(region_get_navigation_layers, RID, p_region, rid_to_rid);
+void FORWARD_2(region_set_transform, RID, p_region, Transform2D, p_transform, rid_to_rid, trf2_to_trf3);
+
+void GodotNavigationServer2D::region_set_navigation_polygon(RID p_region, Ref p_navigation_polygon) {
+ NavigationServer3D::get_singleton()->region_set_navigation_mesh(p_region, poly_to_mesh(p_navigation_polygon));
+}
+
+int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid);
+Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_start, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
+Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_end, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
+
+RID FORWARD_0(link_create);
+
+void FORWARD_2(link_set_map, RID, p_link, RID, p_map, rid_to_rid, rid_to_rid);
+RID FORWARD_1_C(link_get_map, RID, p_link, rid_to_rid);
+void FORWARD_2(link_set_enabled, RID, p_link, bool, p_enabled, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(link_get_enabled, RID, p_link, rid_to_rid);
+void FORWARD_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(link_is_bidirectional, RID, p_link, rid_to_rid);
+void FORWARD_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers, rid_to_rid, uint32_to_uint32);
+uint32_t FORWARD_1_C(link_get_navigation_layers, RID, p_link, rid_to_rid);
+void FORWARD_2(link_set_start_position, RID, p_link, Vector2, p_position, rid_to_rid, v2_to_v3);
+Vector2 FORWARD_1_R_C(v3_to_v2, link_get_start_position, RID, p_link, rid_to_rid);
+void FORWARD_2(link_set_end_position, RID, p_link, Vector2, p_position, rid_to_rid, v2_to_v3);
+Vector2 FORWARD_1_R_C(v3_to_v2, link_get_end_position, RID, p_link, rid_to_rid);
+void FORWARD_2(link_set_enter_cost, RID, p_link, real_t, p_enter_cost, rid_to_rid, real_to_real);
+real_t FORWARD_1_C(link_get_enter_cost, RID, p_link, rid_to_rid);
+void FORWARD_2(link_set_travel_cost, RID, p_link, real_t, p_travel_cost, rid_to_rid, real_to_real);
+real_t FORWARD_1_C(link_get_travel_cost, RID, p_link, rid_to_rid);
+void FORWARD_2(link_set_owner_id, RID, p_link, ObjectID, p_owner_id, rid_to_rid, id_to_id);
+ObjectID FORWARD_1_C(link_get_owner_id, RID, p_link, rid_to_rid);
+
+RID GodotNavigationServer2D::agent_create() {
+ RID agent = NavigationServer3D::get_singleton()->agent_create();
+ return agent;
+}
+
+void FORWARD_2(agent_set_avoidance_enabled, RID, p_agent, bool, p_enabled, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(agent_get_avoidance_enabled, RID, p_agent, rid_to_rid);
+void FORWARD_2(agent_set_map, RID, p_agent, RID, p_map, rid_to_rid, rid_to_rid);
+void FORWARD_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_dist, rid_to_rid, real_to_real);
+void FORWARD_2(agent_set_max_neighbors, RID, p_agent, int, p_count, rid_to_rid, int_to_int);
+void FORWARD_2(agent_set_time_horizon_agents, RID, p_agent, real_t, p_time_horizon, rid_to_rid, real_to_real);
+void FORWARD_2(agent_set_time_horizon_obstacles, RID, p_agent, real_t, p_time_horizon, rid_to_rid, real_to_real);
+void FORWARD_2(agent_set_radius, RID, p_agent, real_t, p_radius, rid_to_rid, real_to_real);
+void FORWARD_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed, rid_to_rid, real_to_real);
+void FORWARD_2(agent_set_velocity_forced, RID, p_agent, Vector2, p_velocity, rid_to_rid, v2_to_v3);
+void FORWARD_2(agent_set_velocity, RID, p_agent, Vector2, p_velocity, rid_to_rid, v2_to_v3);
+void FORWARD_2(agent_set_position, RID, p_agent, Vector2, p_position, rid_to_rid, v2_to_v3);
+
+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 FORWARD_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback, rid_to_rid, callable_to_callable);
+
+void FORWARD_2(agent_set_avoidance_layers, RID, p_agent, uint32_t, p_layers, rid_to_rid, uint32_to_uint32);
+void FORWARD_2(agent_set_avoidance_mask, RID, p_agent, uint32_t, p_mask, rid_to_rid, uint32_to_uint32);
+void FORWARD_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority, rid_to_rid, real_to_real);
+
+RID GodotNavigationServer2D::obstacle_create() {
+ RID obstacle = NavigationServer3D::get_singleton()->obstacle_create();
+ return obstacle;
+}
+void FORWARD_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(obstacle_get_avoidance_enabled, RID, p_obstacle, rid_to_rid);
+void FORWARD_2(obstacle_set_map, RID, p_obstacle, RID, p_map, rid_to_rid, rid_to_rid);
+RID FORWARD_1_C(obstacle_get_map, RID, p_obstacle, rid_to_rid);
+void FORWARD_2(obstacle_set_paused, RID, p_obstacle, bool, p_paused, rid_to_rid, bool_to_bool);
+bool FORWARD_1_C(obstacle_get_paused, RID, p_obstacle, rid_to_rid);
+void FORWARD_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius, rid_to_rid, real_to_real);
+void FORWARD_2(obstacle_set_velocity, RID, p_obstacle, Vector2, p_velocity, rid_to_rid, v2_to_v3);
+void FORWARD_2(obstacle_set_position, RID, p_obstacle, Vector2, p_position, rid_to_rid, v2_to_v3);
+void FORWARD_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers, rid_to_rid, uint32_to_uint32);
+
+void GodotNavigationServer2D::obstacle_set_vertices(RID p_obstacle, const Vector &p_vertices) {
+ NavigationServer3D::get_singleton()->obstacle_set_vertices(p_obstacle, vector_v2_to_v3(p_vertices));
+}
+
+void GodotNavigationServer2D::query_path(const Ref &p_query_parameters, Ref p_query_result) const {
+ ERR_FAIL_COND(!p_query_parameters.is_valid());
+ ERR_FAIL_COND(!p_query_result.is_valid());
+
+ const NavigationUtilities::PathQueryResult _query_result = NavigationServer3D::get_singleton()->_query_path(p_query_parameters->get_parameters());
+
+ p_query_result->set_path(vector_v3_to_v2(_query_result.path));
+ p_query_result->set_path_types(_query_result.path_types);
+ p_query_result->set_path_rids(_query_result.path_rids);
+ p_query_result->set_path_owner_ids(_query_result.path_owner_ids);
+}
diff --git a/modules/navigation/godot_navigation_server_2d.h b/modules/navigation/godot_navigation_server_2d.h
new file mode 100644
index 00000000000..337f5f40d8f
--- /dev/null
+++ b/modules/navigation/godot_navigation_server_2d.h
@@ -0,0 +1,234 @@
+/**************************************************************************/
+/* godot_navigation_server_2d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef GODOT_NAVIGATION_SERVER_2D_H
+#define GODOT_NAVIGATION_SERVER_2D_H
+
+#include "nav_agent.h"
+#include "nav_link.h"
+#include "nav_map.h"
+#include "nav_obstacle.h"
+#include "nav_region.h"
+
+#include "servers/navigation_server_2d.h"
+
+#ifdef CLIPPER2_ENABLED
+class NavMeshGenerator2D;
+#endif // CLIPPER2_ENABLED
+
+// This server exposes the `NavigationServer3D` features in the 2D world.
+class GodotNavigationServer2D : public NavigationServer2D {
+ GDCLASS(GodotNavigationServer2D, NavigationServer2D);
+
+#ifdef CLIPPER2_ENABLED
+ NavMeshGenerator2D *navmesh_generator_2d = nullptr;
+#endif // CLIPPER2_ENABLED
+
+public:
+ GodotNavigationServer2D();
+ virtual ~GodotNavigationServer2D();
+
+ virtual TypedArray get_maps() const override;
+
+ virtual RID map_create() override;
+ virtual void map_set_active(RID p_map, bool p_active) override;
+ virtual bool map_is_active(RID p_map) const override;
+ virtual void map_set_cell_size(RID p_map, real_t p_cell_size) override;
+ virtual real_t map_get_cell_size(RID p_map) const override;
+ virtual void map_set_use_edge_connections(RID p_map, bool p_enabled) override;
+ virtual bool map_get_use_edge_connections(RID p_map) const override;
+ virtual void map_set_edge_connection_margin(RID p_map, real_t p_connection_margin) override;
+ virtual real_t map_get_edge_connection_margin(RID p_map) const override;
+ virtual void map_set_link_connection_radius(RID p_map, real_t p_connection_radius) override;
+ virtual real_t map_get_link_connection_radius(RID p_map) const override;
+ virtual Vector map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const override;
+ virtual Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const override;
+ virtual RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const override;
+ virtual TypedArray map_get_links(RID p_map) const override;
+ virtual TypedArray map_get_regions(RID p_map) const override;
+ virtual TypedArray map_get_agents(RID p_map) const override;
+ virtual TypedArray map_get_obstacles(RID p_map) const override;
+ virtual void map_force_update(RID p_map) override;
+
+ virtual RID region_create() override;
+ virtual void region_set_enabled(RID p_region, bool p_enabled) override;
+ virtual bool region_get_enabled(RID p_region) const override;
+ virtual void region_set_use_edge_connections(RID p_region, bool p_enabled) override;
+ virtual bool region_get_use_edge_connections(RID p_region) const override;
+ virtual void region_set_enter_cost(RID p_region, real_t p_enter_cost) override;
+ virtual real_t region_get_enter_cost(RID p_region) const override;
+ virtual void region_set_travel_cost(RID p_region, real_t p_travel_cost) override;
+ virtual real_t region_get_travel_cost(RID p_region) const override;
+ virtual void region_set_owner_id(RID p_region, ObjectID p_owner_id) override;
+ virtual ObjectID region_get_owner_id(RID p_region) const override;
+ virtual bool region_owns_point(RID p_region, const Vector2 &p_point) const override;
+ virtual void region_set_map(RID p_region, RID p_map) override;
+ virtual RID region_get_map(RID p_region) const override;
+ virtual void region_set_navigation_layers(RID p_region, uint32_t p_navigation_layers) override;
+ virtual uint32_t region_get_navigation_layers(RID p_region) const override;
+ virtual void region_set_transform(RID p_region, Transform2D p_transform) override;
+ virtual void region_set_navigation_polygon(RID p_region, Ref p_navigation_polygon) override;
+ virtual int region_get_connections_count(RID p_region) const override;
+ virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override;
+ virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override;
+
+ virtual RID link_create() override;
+
+ /// Set the map of this link.
+ virtual void link_set_map(RID p_link, RID p_map) override;
+ virtual RID link_get_map(RID p_link) const override;
+
+ virtual void link_set_enabled(RID p_link, bool p_enabled) override;
+ virtual bool link_get_enabled(RID p_link) const override;
+
+ /// Set whether this link travels in both directions.
+ virtual void link_set_bidirectional(RID p_link, bool p_bidirectional) override;
+ virtual bool link_is_bidirectional(RID p_link) const override;
+
+ /// Set the link's layers.
+ virtual void link_set_navigation_layers(RID p_link, uint32_t p_navigation_layers) override;
+ virtual uint32_t link_get_navigation_layers(RID p_link) const override;
+
+ /// Set the start position of the link.
+ virtual void link_set_start_position(RID p_link, Vector2 p_position) override;
+ virtual Vector2 link_get_start_position(RID p_link) const override;
+
+ /// Set the end position of the link.
+ virtual void link_set_end_position(RID p_link, Vector2 p_position) override;
+ virtual Vector2 link_get_end_position(RID p_link) const override;
+
+ /// Set the enter cost of the link.
+ virtual void link_set_enter_cost(RID p_link, real_t p_enter_cost) override;
+ virtual real_t link_get_enter_cost(RID p_link) const override;
+
+ /// Set the travel cost of the link.
+ virtual void link_set_travel_cost(RID p_link, real_t p_travel_cost) override;
+ virtual real_t link_get_travel_cost(RID p_link) const override;
+
+ /// Set the node which manages this link.
+ virtual void link_set_owner_id(RID p_link, ObjectID p_owner_id) override;
+ virtual ObjectID link_get_owner_id(RID p_link) const override;
+
+ /// Creates the agent.
+ virtual RID agent_create() override;
+
+ /// Put the agent in the map.
+ virtual void agent_set_map(RID p_agent, RID p_map) override;
+ virtual RID agent_get_map(RID p_agent) const override;
+
+ virtual void agent_set_paused(RID p_agent, bool p_paused) override;
+ virtual bool agent_get_paused(RID p_agent) const override;
+
+ virtual void agent_set_avoidance_enabled(RID p_agent, bool p_enabled) override;
+ virtual bool agent_get_avoidance_enabled(RID p_agent) const override;
+
+ /// The maximum distance (center point to
+ /// center point) to other agents this agent
+ /// takes into account in the navigation. The
+ /// larger this number, the longer the running
+ /// time of the simulation. If the number is too
+ /// low, the simulation will not be safe.
+ /// Must be non-negative.
+ virtual void agent_set_neighbor_distance(RID p_agent, real_t p_distance) override;
+
+ /// The maximum number of other agents this
+ /// agent takes into account in the navigation.
+ /// The larger this number, the longer the
+ /// running time of the simulation. If the
+ /// number is too low, the simulation will not
+ /// be safe.
+ virtual void agent_set_max_neighbors(RID p_agent, int p_count) override;
+
+ /// The minimal amount of time for which this
+ /// agent's velocities that are computed by the
+ /// simulation are safe with respect to other
+ /// agents. The larger this number, the sooner
+ /// this agent will respond to the presence of
+ /// other agents, but the less freedom this
+ /// agent has in choosing its velocities.
+ /// Must be positive.
+
+ virtual void agent_set_time_horizon_agents(RID p_agent, real_t p_time_horizon) override;
+ virtual void agent_set_time_horizon_obstacles(RID p_agent, real_t p_time_horizon) override;
+
+ /// The radius of this agent.
+ /// Must be non-negative.
+ virtual void agent_set_radius(RID p_agent, real_t p_radius) override;
+
+ /// The maximum speed of this agent.
+ /// Must be non-negative.
+ virtual void agent_set_max_speed(RID p_agent, real_t p_max_speed) override;
+
+ /// forces and agent velocity change in the avoidance simulation, adds simulation instability if done recklessly
+ virtual void agent_set_velocity_forced(RID p_agent, Vector2 p_velocity) override;
+
+ /// The wanted velocity for the agent as a "suggestion" to the avoidance simulation.
+ /// The simulation will try to fulfill this velocity wish if possible but may change the velocity depending on other agent's and obstacles'.
+ virtual void agent_set_velocity(RID p_agent, Vector2 p_velocity) override;
+
+ /// Position of the agent in world space.
+ virtual void agent_set_position(RID p_agent, Vector2 p_position) override;
+
+ /// Returns true if the map got changed the previous frame.
+ virtual bool agent_is_map_changed(RID p_agent) const override;
+
+ /// Callback called at the end of the RVO process
+ virtual void agent_set_avoidance_callback(RID p_agent, Callable p_callback) override;
+
+ virtual void agent_set_avoidance_layers(RID p_agent, uint32_t p_layers) override;
+ virtual void agent_set_avoidance_mask(RID p_agent, uint32_t p_mask) override;
+ virtual void agent_set_avoidance_priority(RID p_agent, real_t p_priority) override;
+
+ virtual RID obstacle_create() override;
+ virtual void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled) override;
+ virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const override;
+ virtual void obstacle_set_map(RID p_obstacle, RID p_map) override;
+ virtual RID obstacle_get_map(RID p_obstacle) const override;
+ virtual void obstacle_set_paused(RID p_obstacle, bool p_paused) override;
+ virtual bool obstacle_get_paused(RID p_obstacle) const override;
+ virtual void obstacle_set_radius(RID p_obstacle, real_t p_radius) override;
+ virtual void obstacle_set_velocity(RID p_obstacle, Vector2 p_velocity) override;
+ virtual void obstacle_set_position(RID p_obstacle, Vector2 p_position) override;
+ virtual void obstacle_set_vertices(RID p_obstacle, const Vector &p_vertices) override;
+ virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) override;
+
+ virtual void query_path(const Ref &p_query_parameters, Ref p_query_result) const override;
+
+ virtual void init() override;
+ virtual void sync() override;
+ virtual void finish() override;
+ virtual void free(RID p_object) override;
+
+ virtual 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;
+ virtual void bake_from_source_geometry_data(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, const Callable &p_callback = Callable()) override;
+ virtual void bake_from_source_geometry_data_async(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, const Callable &p_callback = Callable()) override;
+};
+
+#endif // GODOT_NAVIGATION_SERVER_2D_H
diff --git a/modules/navigation/nav_mesh_generator_2d.cpp b/modules/navigation/nav_mesh_generator_2d.cpp
new file mode 100644
index 00000000000..0c9f7e80fbb
--- /dev/null
+++ b/modules/navigation/nav_mesh_generator_2d.cpp
@@ -0,0 +1,830 @@
+/**************************************************************************/
+/* nav_mesh_generator_2d.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "nav_mesh_generator_2d.h"
+
+#include "core/config/project_settings.h"
+#include "scene/2d/mesh_instance_2d.h"
+#include "scene/2d/multimesh_instance_2d.h"
+#include "scene/2d/physics_body_2d.h"
+#include "scene/2d/polygon_2d.h"
+#include "scene/2d/tile_map.h"
+#include "scene/resources/capsule_shape_2d.h"
+#include "scene/resources/circle_shape_2d.h"
+#include "scene/resources/concave_polygon_shape_2d.h"
+#include "scene/resources/convex_polygon_shape_2d.h"
+#include "scene/resources/navigation_mesh_source_geometry_data_2d.h"
+#include "scene/resources/navigation_polygon.h"
+#include "scene/resources/rectangle_shape_2d.h"
+
+#include "thirdparty/clipper2/include/clipper2/clipper.h"
+#include "thirdparty/misc/polypartition.h"
+
+NavMeshGenerator2D *NavMeshGenerator2D::singleton = nullptr;
+Mutex NavMeshGenerator2D::baking_navmesh_mutex;
+Mutex NavMeshGenerator2D::generator_task_mutex;
+bool NavMeshGenerator2D::use_threads = true;
+bool NavMeshGenerator2D::baking_use_multiple_threads = true;
+bool NavMeshGenerator2D::baking_use_high_priority_threads = true;
+HashSet[> NavMeshGenerator2D::baking_navmeshes;
+HashMap NavMeshGenerator2D::generator_tasks;
+
+NavMeshGenerator2D *NavMeshGenerator2D::get_singleton() {
+ return singleton;
+}
+
+NavMeshGenerator2D::NavMeshGenerator2D() {
+ ERR_FAIL_COND(singleton != nullptr);
+ singleton = this;
+
+ baking_use_multiple_threads = GLOBAL_GET("navigation/baking/thread_model/baking_use_multiple_threads");
+ baking_use_high_priority_threads = GLOBAL_GET("navigation/baking/thread_model/baking_use_high_priority_threads");
+
+ // Using threads might cause problems on certain exports or with the Editor on certain devices.
+ // This is the main switch to turn threaded navmesh baking off should the need arise.
+ use_threads = baking_use_multiple_threads && !Engine::get_singleton()->is_editor_hint();
+}
+
+NavMeshGenerator2D::~NavMeshGenerator2D() {
+ cleanup();
+}
+
+void NavMeshGenerator2D::sync() {
+ if (generator_tasks.size() == 0) {
+ return;
+ }
+
+ baking_navmesh_mutex.lock();
+ generator_task_mutex.lock();
+
+ LocalVector finished_task_ids;
+
+ for (KeyValue &E : generator_tasks) {
+ if (WorkerThreadPool::get_singleton()->is_task_completed(E.key)) {
+ WorkerThreadPool::get_singleton()->wait_for_task_completion(E.key);
+ finished_task_ids.push_back(E.key);
+
+ NavMeshGeneratorTask2D *generator_task = E.value;
+ DEV_ASSERT(generator_task->status = NavMeshGeneratorTask2D::TaskStatus::BAKING_FINISHED);
+
+ baking_navmeshes.erase(generator_task->navigation_mesh);
+ if (generator_task->callback.is_valid()) {
+ generator_emit_callback(generator_task->callback);
+ }
+ memdelete(generator_task);
+ }
+ }
+
+ for (WorkerThreadPool::TaskID finished_task_id : finished_task_ids) {
+ generator_tasks.erase(finished_task_id);
+ }
+
+ generator_task_mutex.unlock();
+ baking_navmesh_mutex.unlock();
+}
+
+void NavMeshGenerator2D::cleanup() {
+ baking_navmesh_mutex.lock();
+ generator_task_mutex.lock();
+
+ baking_navmeshes.clear();
+
+ for (KeyValue &E : generator_tasks) {
+ WorkerThreadPool::get_singleton()->wait_for_task_completion(E.key);
+ NavMeshGeneratorTask2D *generator_task = E.value;
+ memdelete(generator_task);
+ }
+ generator_tasks.clear();
+
+ generator_task_mutex.unlock();
+ baking_navmesh_mutex.unlock();
+}
+
+void NavMeshGenerator2D::finish() {
+ cleanup();
+}
+
+void NavMeshGenerator2D::parse_source_geometry_data(Ref p_navigation_mesh, Ref p_source_geometry_data, Node *p_root_node, const Callable &p_callback) {
+ ERR_FAIL_COND(!Thread::is_main_thread());
+ ERR_FAIL_COND(!p_navigation_mesh.is_valid());
+ ERR_FAIL_NULL(p_root_node);
+ ERR_FAIL_COND(!p_root_node->is_inside_tree());
+ ERR_FAIL_COND(!p_source_geometry_data.is_valid());
+
+ generator_parse_source_geometry_data(p_navigation_mesh, p_source_geometry_data, p_root_node);
+
+ if (p_callback.is_valid()) {
+ generator_emit_callback(p_callback);
+ }
+}
+
+void NavMeshGenerator2D::bake_from_source_geometry_data(Ref p_navigation_mesh, Ref p_source_geometry_data, const Callable &p_callback) {
+ ERR_FAIL_COND(!p_navigation_mesh.is_valid());
+ ERR_FAIL_COND(!p_source_geometry_data.is_valid());
+
+ if (p_navigation_mesh->get_outline_count() == 0 && !p_source_geometry_data->has_data()) {
+ p_navigation_mesh->clear();
+ if (p_callback.is_valid()) {
+ generator_emit_callback(p_callback);
+ }
+ return;
+ }
+
+ baking_navmesh_mutex.lock();
+ if (baking_navmeshes.has(p_navigation_mesh)) {
+ baking_navmesh_mutex.unlock();
+ ERR_FAIL_MSG("NavigationPolygon is already baking. Wait for current bake to finish.");
+ }
+ baking_navmeshes.insert(p_navigation_mesh);
+ baking_navmesh_mutex.unlock();
+
+ generator_bake_from_source_geometry_data(p_navigation_mesh, p_source_geometry_data);
+
+ baking_navmesh_mutex.lock();
+ baking_navmeshes.erase(p_navigation_mesh);
+ baking_navmesh_mutex.unlock();
+
+ if (p_callback.is_valid()) {
+ generator_emit_callback(p_callback);
+ }
+}
+
+void NavMeshGenerator2D::bake_from_source_geometry_data_async(Ref p_navigation_mesh, Ref p_source_geometry_data, const Callable &p_callback) {
+ ERR_FAIL_COND(!p_navigation_mesh.is_valid());
+ ERR_FAIL_COND(!p_source_geometry_data.is_valid());
+
+ if (p_navigation_mesh->get_outline_count() == 0 && !p_source_geometry_data->has_data()) {
+ p_navigation_mesh->clear();
+ if (p_callback.is_valid()) {
+ generator_emit_callback(p_callback);
+ }
+ return;
+ }
+
+ if (!use_threads) {
+ bake_from_source_geometry_data(p_navigation_mesh, p_source_geometry_data, p_callback);
+ return;
+ }
+
+ baking_navmesh_mutex.lock();
+ if (baking_navmeshes.has(p_navigation_mesh)) {
+ baking_navmesh_mutex.unlock();
+ ERR_FAIL_MSG("NavigationPolygon is already baking. Wait for current bake to finish.");
+ }
+ baking_navmeshes.insert(p_navigation_mesh);
+ baking_navmesh_mutex.unlock();
+
+ generator_task_mutex.lock();
+ NavMeshGeneratorTask2D *generator_task = memnew(NavMeshGeneratorTask2D);
+ generator_task->navigation_mesh = p_navigation_mesh;
+ generator_task->source_geometry_data = p_source_geometry_data;
+ generator_task->callback = p_callback;
+ generator_task->status = NavMeshGeneratorTask2D::TaskStatus::BAKING_STARTED;
+ generator_task->thread_task_id = WorkerThreadPool::get_singleton()->add_native_task(&NavMeshGenerator2D::generator_thread_bake, generator_task, NavMeshGenerator2D::baking_use_high_priority_threads, "NavMeshGeneratorBake2D");
+ generator_tasks.insert(generator_task->thread_task_id, generator_task);
+ generator_task_mutex.unlock();
+}
+
+void NavMeshGenerator2D::generator_thread_bake(void *p_arg) {
+ NavMeshGeneratorTask2D *generator_task = static_cast(p_arg);
+
+ generator_bake_from_source_geometry_data(generator_task->navigation_mesh, generator_task->source_geometry_data);
+
+ generator_task->status = NavMeshGeneratorTask2D::TaskStatus::BAKING_FINISHED;
+}
+
+void NavMeshGenerator2D::generator_parse_geometry_node(Ref p_navigation_mesh, Ref p_source_geometry_data, Node *p_node, bool p_recurse_children) {
+ generator_parse_meshinstance2d_node(p_navigation_mesh, p_source_geometry_data, p_node);
+ generator_parse_multimeshinstance2d_node(p_navigation_mesh, p_source_geometry_data, p_node);
+ generator_parse_polygon2d_node(p_navigation_mesh, p_source_geometry_data, p_node);
+ generator_parse_staticbody2d_node(p_navigation_mesh, p_source_geometry_data, p_node);
+ generator_parse_tilemap_node(p_navigation_mesh, p_source_geometry_data, p_node);
+
+ 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);
+ }
+ }
+}
+
+void NavMeshGenerator2D::generator_parse_meshinstance2d_node(const Ref &p_navigation_mesh, Ref p_source_geometry_data, Node *p_node) {
+ MeshInstance2D *mesh_instance = Object::cast_to(p_node);
+
+ if (mesh_instance == nullptr) {
+ return;
+ }
+
+ NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
+
+ if (!(parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_MESH_INSTANCES || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH)) {
+ return;
+ }
+
+ Ref mesh = mesh_instance->get_mesh();
+ if (!mesh.is_valid()) {
+ return;
+ }
+
+ const Transform2D mesh_instance_xform = p_source_geometry_data->root_node_transform * mesh_instance->get_global_transform();
+
+ using namespace Clipper2Lib;
+
+ Paths64 subject_paths, dummy_clip_paths;
+
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
+ continue;
+ }
+
+ if (!(mesh->surface_get_format(i) & Mesh::ARRAY_FLAG_USE_2D_VERTICES)) {
+ continue;
+ }
+
+ Path64 subject_path;
+
+ int index_count = 0;
+ if (mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
+ index_count = mesh->surface_get_array_index_len(i);
+ } else {
+ index_count = mesh->surface_get_array_len(i);
+ }
+
+ ERR_CONTINUE((index_count == 0 || (index_count % 3) != 0));
+
+ Array a = mesh->surface_get_arrays(i);
+
+ Vector mesh_vertices = a[Mesh::ARRAY_VERTEX];
+
+ if (mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
+ Vector mesh_indices = a[Mesh::ARRAY_INDEX];
+ for (int vertex_index : mesh_indices) {
+ const Vector2 &vertex = mesh_vertices[vertex_index];
+ const Point64 &point = Point64(vertex.x, vertex.y);
+ subject_path.push_back(point);
+ }
+ } else {
+ for (const Vector2 &vertex : mesh_vertices) {
+ const Point64 &point = Point64(vertex.x, vertex.y);
+ subject_path.push_back(point);
+ }
+ }
+ subject_paths.push_back(subject_path);
+ }
+
+ Paths64 path_solution;
+
+ path_solution = Union(subject_paths, dummy_clip_paths, FillRule::NonZero);
+
+ //path_solution = RamerDouglasPeucker(path_solution, 0.025);
+
+ Vector> polypaths;
+
+ for (const Path64 &scaled_path : path_solution) {
+ Vector shape_outline;
+ for (const Point64 &scaled_point : scaled_path) {
+ shape_outline.push_back(Point2(static_cast(scaled_point.x), static_cast(scaled_point.y)));
+ }
+
+ for (int i = 0; i < shape_outline.size(); i++) {
+ shape_outline.write[i] = mesh_instance_xform.xform(shape_outline[i]);
+ }
+
+ p_source_geometry_data->add_obstruction_outline(shape_outline);
+ }
+}
+
+void NavMeshGenerator2D::generator_parse_multimeshinstance2d_node(const Ref &p_navigation_mesh, Ref p_source_geometry_data, Node *p_node) {
+ MultiMeshInstance2D *multimesh_instance = Object::cast_to(p_node);
+
+ if (multimesh_instance == nullptr) {
+ return;
+ }
+
+ NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
+ if (!(parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_MESH_INSTANCES || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH)) {
+ return;
+ }
+
+ Ref multimesh = multimesh_instance->get_multimesh();
+ if (!(multimesh.is_valid() && multimesh->get_transform_format() == MultiMesh::TRANSFORM_2D)) {
+ return;
+ }
+
+ Ref mesh = multimesh->get_mesh();
+ if (!mesh.is_valid()) {
+ return;
+ }
+
+ using namespace Clipper2Lib;
+
+ Paths64 mesh_subject_paths, dummy_clip_paths;
+
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
+ continue;
+ }
+
+ if (!(mesh->surface_get_format(i) & Mesh::ARRAY_FLAG_USE_2D_VERTICES)) {
+ continue;
+ }
+
+ Path64 subject_path;
+
+ int index_count = 0;
+ if (mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
+ index_count = mesh->surface_get_array_index_len(i);
+ } else {
+ index_count = mesh->surface_get_array_len(i);
+ }
+
+ ERR_CONTINUE((index_count == 0 || (index_count % 3) != 0));
+
+ Array a = mesh->surface_get_arrays(i);
+
+ Vector mesh_vertices = a[Mesh::ARRAY_VERTEX];
+
+ if (mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_INDEX) {
+ Vector mesh_indices = a[Mesh::ARRAY_INDEX];
+ for (int vertex_index : mesh_indices) {
+ const Vector2 &vertex = mesh_vertices[vertex_index];
+ const Point64 &point = Point64(vertex.x, vertex.y);
+ subject_path.push_back(point);
+ }
+ } else {
+ for (const Vector2 &vertex : mesh_vertices) {
+ const Point64 &point = Point64(vertex.x, vertex.y);
+ subject_path.push_back(point);
+ }
+ }
+ mesh_subject_paths.push_back(subject_path);
+ }
+
+ Paths64 mesh_path_solution = Union(mesh_subject_paths, dummy_clip_paths, FillRule::NonZero);
+
+ //path_solution = RamerDouglasPeucker(path_solution, 0.025);
+
+ int multimesh_instance_count = multimesh->get_visible_instance_count();
+ if (multimesh_instance_count == -1) {
+ multimesh_instance_count = multimesh->get_instance_count();
+ }
+
+ const Transform2D multimesh_instance_xform = p_source_geometry_data->root_node_transform * multimesh_instance->get_global_transform();
+
+ for (int i = 0; i < multimesh_instance_count; i++) {
+ const Transform2D multimesh_instance_mesh_instance_xform = multimesh_instance_xform * multimesh->get_instance_transform_2d(i);
+
+ for (const Path64 &mesh_path : mesh_path_solution) {
+ Vector shape_outline;
+
+ for (const Point64 &mesh_path_point : mesh_path) {
+ shape_outline.push_back(Point2(static_cast(mesh_path_point.x), static_cast(mesh_path_point.y)));
+ }
+
+ for (int j = 0; j < shape_outline.size(); j++) {
+ shape_outline.write[j] = multimesh_instance_mesh_instance_xform.xform(shape_outline[j]);
+ }
+ p_source_geometry_data->add_obstruction_outline(shape_outline);
+ }
+ }
+}
+
+void NavMeshGenerator2D::generator_parse_polygon2d_node(const Ref &p_navigation_mesh, Ref p_source_geometry_data, Node *p_node) {
+ Polygon2D *polygon_2d = Object::cast_to(p_node);
+
+ if (polygon_2d == nullptr) {
+ return;
+ }
+
+ NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
+
+ if (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_MESH_INSTANCES || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) {
+ const Transform2D polygon_2d_xform = p_source_geometry_data->root_node_transform * polygon_2d->get_global_transform();
+
+ Vector shape_outline = polygon_2d->get_polygon();
+ for (int i = 0; i < shape_outline.size(); i++) {
+ shape_outline.write[i] = polygon_2d_xform.xform(shape_outline[i]);
+ }
+
+ p_source_geometry_data->add_obstruction_outline(shape_outline);
+ }
+}
+
+void NavMeshGenerator2D::generator_parse_staticbody2d_node(const Ref &p_navigation_mesh, Ref p_source_geometry_data, Node *p_node) {
+ StaticBody2D *static_body = Object::cast_to(p_node);
+
+ if (static_body == nullptr) {
+ return;
+ }
+
+ NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
+ if (!(parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH)) {
+ return;
+ }
+
+ uint32_t parsed_collision_mask = p_navigation_mesh->get_parsed_collision_mask();
+ if (!(static_body->get_collision_layer() & parsed_collision_mask)) {
+ return;
+ }
+
+ List shape_owners;
+ static_body->get_shape_owners(&shape_owners);
+
+ for (uint32_t shape_owner : shape_owners) {
+ if (static_body->is_shape_owner_disabled(shape_owner)) {
+ continue;
+ }
+
+ const int shape_count = static_body->shape_owner_get_shape_count(shape_owner);
+
+ for (int shape_index = 0; shape_index < shape_count; shape_index++) {
+ Ref s = static_body->shape_owner_get_shape(shape_owner, shape_index);
+
+ if (s.is_null()) {
+ continue;
+ }
+
+ const Transform2D static_body_xform = p_source_geometry_data->root_node_transform * static_body->get_global_transform() * static_body->shape_owner_get_transform(shape_owner);
+
+ RectangleShape2D *rectangle_shape = Object::cast_to(*s);
+ if (rectangle_shape) {
+ Vector shape_outline;
+
+ const Vector2 &rectangle_size = rectangle_shape->get_size();
+
+ shape_outline.resize(5);
+ shape_outline.write[0] = static_body_xform.xform(-rectangle_size * 0.5);
+ shape_outline.write[1] = static_body_xform.xform(Vector2(rectangle_size.x, -rectangle_size.y) * 0.5);
+ shape_outline.write[2] = static_body_xform.xform(rectangle_size * 0.5);
+ shape_outline.write[3] = static_body_xform.xform(Vector2(-rectangle_size.x, rectangle_size.y) * 0.5);
+ shape_outline.write[4] = static_body_xform.xform(-rectangle_size * 0.5);
+
+ p_source_geometry_data->add_obstruction_outline(shape_outline);
+ }
+
+ CapsuleShape2D *capsule_shape = Object::cast_to(*s);
+ if (capsule_shape) {
+ const real_t capsule_height = capsule_shape->get_height();
+ const real_t capsule_radius = capsule_shape->get_radius();
+
+ Vector shape_outline;
+ const real_t turn_step = Math_TAU / 12.0;
+ shape_outline.resize(14);
+ int shape_outline_inx = 0;
+ for (int i = 0; i < 12; i++) {
+ Vector2 ofs = Vector2(0, (i > 3 && i <= 9) ? -capsule_height * 0.5 + capsule_radius : capsule_height * 0.5 - capsule_radius);
+
+ shape_outline.write[shape_outline_inx] = static_body_xform.xform(Vector2(Math::sin(i * turn_step), Math::cos(i * turn_step)) * capsule_radius + ofs);
+ shape_outline_inx += 1;
+ if (i == 3 || i == 9) {
+ shape_outline.write[shape_outline_inx] = static_body_xform.xform(Vector2(Math::sin(i * turn_step), Math::cos(i * turn_step)) * capsule_radius - ofs);
+ shape_outline_inx += 1;
+ }
+ }
+
+ p_source_geometry_data->add_obstruction_outline(shape_outline);
+ }
+
+ CircleShape2D *circle_shape = Object::cast_to(*s);
+ if (circle_shape) {
+ const real_t circle_radius = circle_shape->get_radius();
+
+ Vector shape_outline;
+ int circle_edge_count = 12;
+ shape_outline.resize(circle_edge_count);
+
+ const real_t turn_step = Math_TAU / real_t(circle_edge_count);
+ for (int i = 0; i < circle_edge_count; i++) {
+ shape_outline.write[i] = static_body_xform.xform(Vector2(Math::cos(i * turn_step), Math::sin(i * turn_step)) * circle_radius);
+ }
+
+ p_source_geometry_data->add_obstruction_outline(shape_outline);
+ }
+
+ ConcavePolygonShape2D *concave_polygon_shape = Object::cast_to(*s);
+ if (concave_polygon_shape) {
+ Vector shape_outline = concave_polygon_shape->get_segments();
+
+ for (int i = 0; i < shape_outline.size(); i++) {
+ shape_outline.write[i] = static_body_xform.xform(shape_outline[i]);
+ }
+
+ p_source_geometry_data->add_obstruction_outline(shape_outline);
+ }
+
+ ConvexPolygonShape2D *convex_polygon_shape = Object::cast_to(*s);
+ if (convex_polygon_shape) {
+ Vector shape_outline = convex_polygon_shape->get_points();
+
+ for (int i = 0; i < shape_outline.size(); i++) {
+ shape_outline.write[i] = static_body_xform.xform(shape_outline[i]);
+ }
+
+ p_source_geometry_data->add_obstruction_outline(shape_outline);
+ }
+ }
+ }
+}
+
+void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref &p_navigation_mesh, Ref p_source_geometry_data, Node *p_node) {
+ TileMap *tilemap = Object::cast_to(p_node);
+
+ if (tilemap == nullptr) {
+ return;
+ }
+
+ NavigationPolygon::ParsedGeometryType parsed_geometry_type = p_navigation_mesh->get_parsed_geometry_type();
+ uint32_t parsed_collision_mask = p_navigation_mesh->get_parsed_collision_mask();
+
+ if (tilemap->get_layers_count() <= 0) {
+ return;
+ }
+
+ int tilemap_layer = 0; // only main tile map layer is supported
+
+ Ref tile_set = tilemap->get_tileset();
+ if (!tile_set.is_valid()) {
+ return;
+ }
+
+ int physics_layers_count = tile_set->get_physics_layers_count();
+ int navigation_layers_count = tile_set->get_navigation_layers_count();
+
+ if (physics_layers_count <= 0 && navigation_layers_count <= 0) {
+ return;
+ }
+
+ const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tilemap->get_global_transform();
+ TypedArray used_cells = tilemap->get_used_cells(tilemap_layer);
+
+ for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) {
+ const Vector2i &cell = used_cells[used_cell_index];
+
+ const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false);
+
+ Transform2D tile_transform;
+ tile_transform.set_origin(tilemap->map_to_local(cell));
+
+ const Transform2D tile_transform_offset = tilemap_xform * tile_transform;
+
+ if (navigation_layers_count > 0) {
+ Ref navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer);
+ if (navigation_polygon.is_valid()) {
+ for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
+ Vector traversable_outline = navigation_polygon->get_outline(outline_index);
+
+ for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) {
+ traversable_outline.write[traversable_outline_index] = tile_transform_offset.xform(traversable_outline[traversable_outline_index]);
+ }
+
+ p_source_geometry_data->_add_traversable_outline(traversable_outline);
+ }
+ }
+ }
+
+ if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) {
+ for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) {
+ Vector obstruction_outline = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
+
+ for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) {
+ obstruction_outline.write[obstruction_outline_index] = tile_transform_offset.xform(obstruction_outline[obstruction_outline_index]);
+ }
+
+ p_source_geometry_data->_add_obstruction_outline(obstruction_outline);
+ }
+ }
+ }
+}
+
+void NavMeshGenerator2D::generator_parse_source_geometry_data(Ref p_navigation_mesh, Ref p_source_geometry_data, Node *p_root_node) {
+ List parse_nodes;
+
+ if (p_navigation_mesh->get_source_geometry_mode() == NavigationPolygon::SOURCE_GEOMETRY_ROOT_NODE_CHILDREN) {
+ parse_nodes.push_back(p_root_node);
+ } else {
+ p_root_node->get_tree()->get_nodes_in_group(p_navigation_mesh->get_source_geometry_group_name(), &parse_nodes);
+ }
+
+ Transform2D root_node_transform = Transform2D();
+ if (Object::cast_to(p_root_node)) {
+ root_node_transform = Object::cast_to(p_root_node)->get_global_transform().affine_inverse();
+ }
+
+ p_source_geometry_data->clear();
+ p_source_geometry_data->root_node_transform = root_node_transform;
+
+ bool recurse_children = p_navigation_mesh->get_source_geometry_mode() != NavigationPolygon::SOURCE_GEOMETRY_GROUPS_EXPLICIT;
+
+ for (Node *E : parse_nodes) {
+ generator_parse_geometry_node(p_navigation_mesh, p_source_geometry_data, E, recurse_children);
+ }
+};
+
+static void generator_recursive_process_polytree_items(List &p_tppl_in_polygon, const Clipper2Lib::PolyPath64 *p_polypath_item) {
+ using namespace Clipper2Lib;
+
+ Vector polygon_vertices;
+
+ for (const Point64 &polypath_point : p_polypath_item->Polygon()) {
+ polygon_vertices.push_back(Vector2(static_cast(polypath_point.x), static_cast(polypath_point.y)));
+ }
+
+ TPPLPoly tp;
+ tp.Init(polygon_vertices.size());
+ for (int j = 0; j < polygon_vertices.size(); j++) {
+ tp[j] = polygon_vertices[j];
+ }
+
+ if (p_polypath_item->IsHole()) {
+ tp.SetOrientation(TPPL_ORIENTATION_CW);
+ tp.SetHole(true);
+ } else {
+ tp.SetOrientation(TPPL_ORIENTATION_CCW);
+ }
+ p_tppl_in_polygon.push_back(tp);
+
+ for (size_t i = 0; i < p_polypath_item->Count(); i++) {
+ const PolyPath64 *polypath_item = p_polypath_item->Child(i);
+ generator_recursive_process_polytree_items(p_tppl_in_polygon, polypath_item);
+ }
+}
+
+bool NavMeshGenerator2D::generator_emit_callback(const Callable &p_callback) {
+ ERR_FAIL_COND_V(!p_callback.is_valid(), false);
+
+ Callable::CallError ce;
+ Variant result;
+ p_callback.callp(nullptr, 0, result, ce);
+
+ return ce.error == Callable::CallError::CALL_OK;
+}
+
+void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref p_navigation_mesh, Ref p_source_geometry_data) {
+ if (p_navigation_mesh.is_null() || p_source_geometry_data.is_null()) {
+ return;
+ }
+
+ if (p_navigation_mesh->get_outline_count() == 0 && !p_source_geometry_data->has_data()) {
+ return;
+ }
+
+ int outline_count = p_navigation_mesh->get_outline_count();
+ const Vector> &traversable_outlines = p_source_geometry_data->_get_traversable_outlines();
+ const Vector> &obstruction_outlines = p_source_geometry_data->_get_obstruction_outlines();
+
+ if (outline_count == 0 && traversable_outlines.size() == 0) {
+ return;
+ }
+
+ using namespace Clipper2Lib;
+
+ Paths64 traversable_polygon_paths;
+ Paths64 obstruction_polygon_paths;
+
+ for (int i = 0; i < outline_count; i++) {
+ const Vector &traversable_outline = p_navigation_mesh->get_outline(i);
+ Path64 subject_path;
+ for (const Vector2 &traversable_point : traversable_outline) {
+ const Point64 &point = Point64(traversable_point.x, traversable_point.y);
+ subject_path.push_back(point);
+ }
+ traversable_polygon_paths.push_back(subject_path);
+ }
+
+ for (const Vector &traversable_outline : traversable_outlines) {
+ Path64 subject_path;
+ for (const Vector2 &traversable_point : traversable_outline) {
+ const Point64 &point = Point64(traversable_point.x, traversable_point.y);
+ subject_path.push_back(point);
+ }
+ traversable_polygon_paths.push_back(subject_path);
+ }
+
+ for (const Vector &obstruction_outline : obstruction_outlines) {
+ Path64 clip_path;
+ for (const Vector2 &obstruction_point : obstruction_outline) {
+ const Point64 &point = Point64(obstruction_point.x, obstruction_point.y);
+ clip_path.push_back(point);
+ }
+ obstruction_polygon_paths.push_back(clip_path);
+ }
+
+ Paths64 path_solution;
+
+ // first merge all traversable polygons according to user specified fill rule
+ Paths64 dummy_clip_path;
+ traversable_polygon_paths = Union(traversable_polygon_paths, dummy_clip_path, FillRule::NonZero);
+ // merge all obstruction polygons, don't allow holes for what is considered "solid" 2D geometry
+ obstruction_polygon_paths = Union(obstruction_polygon_paths, dummy_clip_path, FillRule::NonZero);
+
+ path_solution = Difference(traversable_polygon_paths, obstruction_polygon_paths, FillRule::NonZero);
+
+ real_t agent_radius_offset = p_navigation_mesh->get_agent_radius();
+ if (agent_radius_offset > 0.0) {
+ path_solution = InflatePaths(path_solution, -agent_radius_offset, JoinType::Miter, EndType::Polygon);
+ }
+ //path_solution = RamerDouglasPeucker(path_solution, 0.025); //
+
+ Vector> new_baked_outlines;
+
+ for (const Path64 &scaled_path : path_solution) {
+ Vector polypath;
+ for (const Point64 &scaled_point : scaled_path) {
+ polypath.push_back(Vector2(static_cast(scaled_point.x), static_cast(scaled_point.y)));
+ }
+ new_baked_outlines.push_back(polypath);
+ }
+
+ if (new_baked_outlines.size() == 0) {
+ p_navigation_mesh->set_vertices(Vector());
+ p_navigation_mesh->clear_polygons();
+ return;
+ }
+
+ Paths64 polygon_paths;
+
+ for (const Vector &baked_outline : new_baked_outlines) {
+ Path64 polygon_path;
+ for (const Vector2 &baked_outline_point : baked_outline) {
+ const Point64 &point = Point64(baked_outline_point.x, baked_outline_point.y);
+ polygon_path.push_back(point);
+ }
+ polygon_paths.push_back(polygon_path);
+ }
+
+ ClipType clipper_cliptype = ClipType::Union;
+
+ List tppl_in_polygon, tppl_out_polygon;
+
+ PolyTree64 polytree;
+ Clipper64 clipper_64;
+
+ clipper_64.AddSubject(polygon_paths);
+ clipper_64.Execute(clipper_cliptype, FillRule::NonZero, polytree);
+
+ for (size_t i = 0; i < polytree.Count(); i++) {
+ const PolyPath64 *polypath_item = polytree[i];
+ generator_recursive_process_polytree_items(tppl_in_polygon, polypath_item);
+ }
+
+ TPPLPartition tpart;
+ if (tpart.ConvexPartition_HM(&tppl_in_polygon, &tppl_out_polygon) == 0) { //failed!
+ ERR_PRINT("NavigationPolygon Convex partition failed. Unable to create a valid NavigationMesh from defined polygon outline paths.");
+ p_navigation_mesh->set_vertices(Vector());
+ p_navigation_mesh->clear_polygons();
+ return;
+ }
+
+ Vector new_vertices;
+ Vector> new_polygons;
+
+ HashMap points;
+ for (List::Element *I = tppl_out_polygon.front(); I; I = I->next()) {
+ TPPLPoly &tp = I->get();
+
+ Vector new_polygon;
+
+ for (int64_t i = 0; i < tp.GetNumPoints(); i++) {
+ HashMap::Iterator E = points.find(tp[i]);
+ if (!E) {
+ E = points.insert(tp[i], new_vertices.size());
+ new_vertices.push_back(tp[i]);
+ }
+ new_polygon.push_back(E->value);
+ }
+
+ new_polygons.push_back(new_polygon);
+ }
+
+ p_navigation_mesh->set_vertices(new_vertices);
+ p_navigation_mesh->clear_polygons();
+ for (int i = 0; i < new_polygons.size(); i++) {
+ p_navigation_mesh->add_polygon(new_polygons[i]);
+ }
+}
diff --git a/modules/navigation/nav_mesh_generator_2d.h b/modules/navigation/nav_mesh_generator_2d.h
new file mode 100644
index 00000000000..763ad246364
--- /dev/null
+++ b/modules/navigation/nav_mesh_generator_2d.h
@@ -0,0 +1,100 @@
+/**************************************************************************/
+/* nav_mesh_generator_2d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef NAV_MESH_GENERATOR_2D_H
+#define NAV_MESH_GENERATOR_2D_H
+
+#include "core/object/class_db.h"
+#include "core/object/worker_thread_pool.h"
+
+class Node;
+class NavigationPolygon;
+class NavigationMeshSourceGeometryData2D;
+
+class NavMeshGenerator2D : public Object {
+ static NavMeshGenerator2D *singleton;
+
+ static Mutex baking_navmesh_mutex;
+ static Mutex generator_task_mutex;
+
+ static bool use_threads;
+ static bool baking_use_multiple_threads;
+ static bool baking_use_high_priority_threads;
+
+ struct NavMeshGeneratorTask2D {
+ enum TaskStatus {
+ BAKING_STARTED,
+ BAKING_FINISHED,
+ BAKING_FAILED,
+ CALLBACK_DISPATCHED,
+ CALLBACK_FAILED,
+ };
+
+ Ref navigation_mesh;
+ Ref source_geometry_data;
+ Callable callback;
+ WorkerThreadPool::TaskID thread_task_id = WorkerThreadPool::INVALID_TASK_ID;
+ NavMeshGeneratorTask2D::TaskStatus status = NavMeshGeneratorTask2D::TaskStatus::BAKING_STARTED;
+ };
+
+ static HashMap generator_tasks;
+
+ static void generator_thread_bake(void *p_arg);
+
+ static HashSet][> baking_navmeshes;
+
+ static void generator_parse_geometry_node(Ref p_navigation_mesh, Ref p_source_geometry_data, Node *p_node, bool p_recurse_children);
+ static void generator_parse_source_geometry_data(Ref p_navigation_mesh, Ref p_source_geometry_data, Node *p_root_node);
+ static void generator_bake_from_source_geometry_data(Ref p_navigation_mesh, Ref p_source_geometry_data);
+
+ static void generator_parse_meshinstance2d_node(const Ref &p_navigation_mesh, Ref p_source_geometry_data, Node *p_node);
+ static void generator_parse_multimeshinstance2d_node(const Ref &p_navigation_mesh, Ref p_source_geometry_data, Node *p_node);
+ static void generator_parse_polygon2d_node(const Ref &p_navigation_mesh, Ref p_source_geometry_data, Node *p_node);
+ static void generator_parse_staticbody2d_node(const Ref &p_navigation_mesh, Ref p_source_geometry_data, Node *p_node);
+ static void generator_parse_tilemap_node(const Ref &p_navigation_mesh, Ref p_source_geometry_data, Node *p_node);
+
+ static bool generator_emit_callback(const Callable &p_callback);
+
+public:
+ static NavMeshGenerator2D *get_singleton();
+
+ static void sync();
+ static void cleanup();
+ static void finish();
+
+ static void parse_source_geometry_data(Ref p_navigation_mesh, Ref p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable());
+ static void bake_from_source_geometry_data(Ref p_navigation_mesh, Ref p_source_geometry_data, const Callable &p_callback = Callable());
+ static void bake_from_source_geometry_data_async(Ref p_navigation_mesh, Ref p_source_geometry_data, const Callable &p_callback = Callable());
+
+ NavMeshGenerator2D();
+ ~NavMeshGenerator2D();
+};
+
+#endif // NAV_MESH_GENERATOR_2D_H
diff --git a/modules/navigation/register_types.cpp b/modules/navigation/register_types.cpp
index 1548ff4b9ce..525fe71134f 100644
--- a/modules/navigation/register_types.cpp
+++ b/modules/navigation/register_types.cpp
@@ -31,6 +31,7 @@
#include "register_types.h"
#include "godot_navigation_server.h"
+#include "godot_navigation_server_2d.h"
#ifndef DISABLE_DEPRECATED
#ifndef _3D_DISABLED
@@ -43,6 +44,7 @@
#endif
#include "core/config/engine.h"
+#include "servers/navigation_server_2d.h"
#include "servers/navigation_server_3d.h"
#ifndef DISABLE_DEPRECATED
@@ -55,9 +57,14 @@ NavigationServer3D *new_server() {
return memnew(GodotNavigationServer);
}
+NavigationServer2D *new_navigation_server_2d() {
+ return memnew(GodotNavigationServer2D);
+}
+
void initialize_navigation_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
NavigationServer3DManager::set_default_server(new_server);
+ NavigationServer2DManager::set_default_server(new_navigation_server_2d);
#ifndef DISABLE_DEPRECATED
#ifndef _3D_DISABLED
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 670a2c641c5..706b26bd05c 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -179,10 +179,6 @@ void NavigationRegion2D::_notification(int p_what) {
}
void NavigationRegion2D::set_navigation_polygon(const Ref &p_navigation_polygon) {
- if (p_navigation_polygon == navigation_polygon) {
- return;
- }
-
if (navigation_polygon.is_valid()) {
navigation_polygon->disconnect_changed(callable_mp(this, &NavigationRegion2D::_navigation_polygon_changed));
}
@@ -226,6 +222,32 @@ RID NavigationRegion2D::get_navigation_map() const {
return RID();
}
+void NavigationRegion2D::bake_navigation_polygon(bool p_on_thread) {
+ ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "The SceneTree can only be parsed on the main thread. Call this function from the main thread or use call_deferred().");
+ ERR_FAIL_COND_MSG(!navigation_polygon.is_valid(), "Baking the navigation polygon requires a valid `NavigationPolygon` resource.");
+
+ Ref source_geometry_data;
+ source_geometry_data.instantiate();
+
+ NavigationServer2D::get_singleton()->parse_source_geometry_data(navigation_polygon, source_geometry_data, this);
+
+ if (p_on_thread) {
+ NavigationServer2D::get_singleton()->bake_from_source_geometry_data_async(navigation_polygon, source_geometry_data, callable_mp(this, &NavigationRegion2D::_bake_finished).bind(navigation_polygon));
+ } else {
+ NavigationServer2D::get_singleton()->bake_from_source_geometry_data(navigation_polygon, source_geometry_data, callable_mp(this, &NavigationRegion2D::_bake_finished).bind(navigation_polygon));
+ }
+}
+
+void NavigationRegion2D::_bake_finished(Ref p_navigation_polygon) {
+ if (!Thread::is_main_thread()) {
+ call_deferred(SNAME("_bake_finished"), p_navigation_polygon);
+ return;
+ }
+
+ set_navigation_polygon(p_navigation_polygon);
+ emit_signal(SNAME("bake_finished"));
+}
+
void NavigationRegion2D::_navigation_polygon_changed() {
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) {
queue_redraw();
@@ -290,6 +312,8 @@ void NavigationRegion2D::_bind_methods() {
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("bake_navigation_polygon", "on_thread"), &NavigationRegion2D::bake_navigation_polygon, DEFVAL(true));
+
ClassDB::bind_method(D_METHOD("_navigation_polygon_changed"), &NavigationRegion2D::_navigation_polygon_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navigation_polygon", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon");
@@ -300,6 +324,9 @@ void NavigationRegion2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "constrain_avoidance"), "set_constrain_avoidance", "get_constrain_avoidance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "avoidance_layers", PROPERTY_HINT_LAYERS_AVOIDANCE), "set_avoidance_layers", "get_avoidance_layers");
+
+ ADD_SIGNAL(MethodInfo("navigation_polygon_changed"));
+ ADD_SIGNAL(MethodInfo("bake_finished"));
}
#ifndef DISABLE_DEPRECATED
diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h
index 0a48b10f470..36e889877a1 100644
--- a/scene/2d/navigation_region_2d.h
+++ b/scene/2d/navigation_region_2d.h
@@ -114,6 +114,9 @@ public:
PackedStringArray get_configuration_warnings() const override;
+ void bake_navigation_polygon(bool p_on_thread);
+ void _bake_finished(Ref p_navigation_polygon);
+
NavigationRegion2D();
~NavigationRegion2D();
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 19c4b62eaf7..03085edb86a 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -172,6 +172,7 @@
#include "scene/resources/mesh_texture.h"
#include "scene/resources/multimesh.h"
#include "scene/resources/navigation_mesh.h"
+#include "scene/resources/navigation_mesh_source_geometry_data_2d.h"
#include "scene/resources/navigation_mesh_source_geometry_data_3d.h"
#include "scene/resources/navigation_polygon.h"
#include "scene/resources/packed_scene.h"
@@ -956,6 +957,7 @@ void register_scene_types() {
GDREGISTER_CLASS(PathFollow2D);
GDREGISTER_CLASS(NavigationMesh);
+ GDREGISTER_CLASS(NavigationMeshSourceGeometryData2D);
GDREGISTER_CLASS(NavigationMeshSourceGeometryData3D);
GDREGISTER_CLASS(NavigationPolygon);
GDREGISTER_CLASS(NavigationRegion2D);
diff --git a/scene/resources/navigation_mesh_source_geometry_data_2d.cpp b/scene/resources/navigation_mesh_source_geometry_data_2d.cpp
new file mode 100644
index 00000000000..3dde6dbff6f
--- /dev/null
+++ b/scene/resources/navigation_mesh_source_geometry_data_2d.cpp
@@ -0,0 +1,138 @@
+/**************************************************************************/
+/* navigation_mesh_source_geometry_data_2d.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "navigation_mesh_source_geometry_data_2d.h"
+
+#include "scene/resources/mesh.h"
+
+void NavigationMeshSourceGeometryData2D::clear() {
+ traversable_outlines.clear();
+ obstruction_outlines.clear();
+}
+
+void NavigationMeshSourceGeometryData2D::_set_traversable_outlines(const Vector> &p_traversable_outlines) {
+ traversable_outlines = p_traversable_outlines;
+}
+
+void NavigationMeshSourceGeometryData2D::_set_obstruction_outlines(const Vector> &p_obstruction_outlines) {
+ obstruction_outlines = p_obstruction_outlines;
+}
+
+void NavigationMeshSourceGeometryData2D::_add_traversable_outline(const Vector &p_shape_outline) {
+ if (p_shape_outline.size() > 1) {
+ traversable_outlines.push_back(p_shape_outline);
+ }
+}
+
+void NavigationMeshSourceGeometryData2D::_add_obstruction_outline(const Vector &p_shape_outline) {
+ if (p_shape_outline.size() > 1) {
+ obstruction_outlines.push_back(p_shape_outline);
+ }
+}
+
+void NavigationMeshSourceGeometryData2D::set_traversable_outlines(const TypedArray> &p_traversable_outlines) {
+ traversable_outlines.resize(p_traversable_outlines.size());
+ for (int i = 0; i < p_traversable_outlines.size(); i++) {
+ traversable_outlines.write[i] = p_traversable_outlines[i];
+ }
+}
+
+TypedArray> NavigationMeshSourceGeometryData2D::get_traversable_outlines() const {
+ TypedArray> typed_array_traversable_outlines;
+ typed_array_traversable_outlines.resize(traversable_outlines.size());
+ for (int i = 0; i < typed_array_traversable_outlines.size(); i++) {
+ typed_array_traversable_outlines[i] = traversable_outlines[i];
+ }
+
+ return typed_array_traversable_outlines;
+}
+
+void NavigationMeshSourceGeometryData2D::set_obstruction_outlines(const TypedArray> &p_obstruction_outlines) {
+ obstruction_outlines.resize(p_obstruction_outlines.size());
+ for (int i = 0; i < p_obstruction_outlines.size(); i++) {
+ obstruction_outlines.write[i] = p_obstruction_outlines[i];
+ }
+}
+
+TypedArray> NavigationMeshSourceGeometryData2D::get_obstruction_outlines() const {
+ TypedArray> typed_array_obstruction_outlines;
+ typed_array_obstruction_outlines.resize(obstruction_outlines.size());
+ for (int i = 0; i < typed_array_obstruction_outlines.size(); i++) {
+ typed_array_obstruction_outlines[i] = obstruction_outlines[i];
+ }
+
+ return typed_array_obstruction_outlines;
+}
+
+void NavigationMeshSourceGeometryData2D::add_traversable_outline(const PackedVector2Array &p_shape_outline) {
+ if (p_shape_outline.size() > 1) {
+ Vector traversable_outline;
+ traversable_outline.resize(p_shape_outline.size());
+ for (int i = 0; i < p_shape_outline.size(); i++) {
+ traversable_outline.write[i] = p_shape_outline[i];
+ }
+ traversable_outlines.push_back(traversable_outline);
+ }
+}
+
+void NavigationMeshSourceGeometryData2D::add_obstruction_outline(const PackedVector2Array &p_shape_outline) {
+ if (p_shape_outline.size() > 1) {
+ Vector obstruction_outline;
+ obstruction_outline.resize(p_shape_outline.size());
+ for (int i = 0; i < p_shape_outline.size(); i++) {
+ obstruction_outline.write[i] = p_shape_outline[i];
+ }
+ obstruction_outlines.push_back(obstruction_outline);
+ }
+}
+
+void NavigationMeshSourceGeometryData2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("clear"), &NavigationMeshSourceGeometryData2D::clear);
+ ClassDB::bind_method(D_METHOD("has_data"), &NavigationMeshSourceGeometryData2D::has_data);
+
+ ClassDB::bind_method(D_METHOD("set_traversable_outlines", "traversable_outlines"), &NavigationMeshSourceGeometryData2D::set_traversable_outlines);
+ ClassDB::bind_method(D_METHOD("get_traversable_outlines"), &NavigationMeshSourceGeometryData2D::get_traversable_outlines);
+
+ ClassDB::bind_method(D_METHOD("set_obstruction_outlines", "obstruction_outlines"), &NavigationMeshSourceGeometryData2D::set_obstruction_outlines);
+ ClassDB::bind_method(D_METHOD("get_obstruction_outlines"), &NavigationMeshSourceGeometryData2D::get_obstruction_outlines);
+
+ ClassDB::bind_method(D_METHOD("add_traversable_outline", "shape_outline"), &NavigationMeshSourceGeometryData2D::add_traversable_outline);
+ ClassDB::bind_method(D_METHOD("add_obstruction_outline", "shape_outline"), &NavigationMeshSourceGeometryData2D::add_obstruction_outline);
+
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "traversable_outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_traversable_outlines", "get_traversable_outlines");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "obstruction_outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_obstruction_outlines", "get_obstruction_outlines");
+}
+
+NavigationMeshSourceGeometryData2D::NavigationMeshSourceGeometryData2D() {
+}
+
+NavigationMeshSourceGeometryData2D::~NavigationMeshSourceGeometryData2D() {
+ clear();
+}
diff --git a/scene/resources/navigation_mesh_source_geometry_data_2d.h b/scene/resources/navigation_mesh_source_geometry_data_2d.h
new file mode 100644
index 00000000000..f26a4e9a2e1
--- /dev/null
+++ b/scene/resources/navigation_mesh_source_geometry_data_2d.h
@@ -0,0 +1,78 @@
+/**************************************************************************/
+/* navigation_mesh_source_geometry_data_2d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef NAVIGATION_MESH_SOURCE_GEOMETRY_DATA_2D_H
+#define NAVIGATION_MESH_SOURCE_GEOMETRY_DATA_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/resources/navigation_polygon.h"
+
+class NavigationMeshSourceGeometryData2D : public Resource {
+ GDCLASS(NavigationMeshSourceGeometryData2D, Resource);
+
+ Vector> traversable_outlines;
+ Vector> obstruction_outlines;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void _set_traversable_outlines(const Vector> &p_traversable_outlines);
+ const Vector> &_get_traversable_outlines() const { return traversable_outlines; }
+
+ void _set_obstruction_outlines(const Vector> &p_obstruction_outlines);
+ const Vector> &_get_obstruction_outlines() const { return obstruction_outlines; }
+
+ void _add_traversable_outline(const Vector &p_shape_outline);
+ void _add_obstruction_outline(const Vector &p_shape_outline);
+
+ // kept root node transform here on the geometry data
+ // if we add this transform to all exposed functions we need to break comp on all functions later
+ // when navmesh changes from global transform to relative to navregion
+ // but if it stays here we can just remove it and change the internal functions only
+ Transform2D root_node_transform;
+
+ void set_traversable_outlines(const TypedArray> &p_traversable_outlines);
+ TypedArray> get_traversable_outlines() const;
+
+ void set_obstruction_outlines(const TypedArray> &p_obstruction_outlines);
+ TypedArray> get_obstruction_outlines() const;
+
+ void add_traversable_outline(const PackedVector2Array &p_shape_outline);
+ void add_obstruction_outline(const PackedVector2Array &p_shape_outline);
+
+ bool has_data() { return traversable_outlines.size(); };
+ void clear();
+
+ NavigationMeshSourceGeometryData2D();
+ ~NavigationMeshSourceGeometryData2D();
+};
+
+#endif // NAVIGATION_MESH_SOURCE_GEOMETRY_DATA_2D_H
diff --git a/scene/resources/navigation_polygon.cpp b/scene/resources/navigation_polygon.cpp
index e521bfb2e04..6c0e1343ecd 100644
--- a/scene/resources/navigation_polygon.cpp
+++ b/scene/resources/navigation_polygon.cpp
@@ -32,6 +32,7 @@
#include "core/math/geometry_2d.h"
#include "core/os/mutex.h"
+#include "servers/navigation_server_2d.h"
#include "thirdparty/misc/polypartition.h"
@@ -229,7 +230,11 @@ void NavigationPolygon::clear_outlines() {
rect_cache_dirty = true;
}
+#ifndef DISABLE_DEPRECATED
void NavigationPolygon::make_polygons_from_outlines() {
+ WARN_PRINT("Function make_polygons_from_outlines() is deprecated."
+ "\nUse NavigationServer2D.parse_source_geometry_data() and NavigationServer2D.bake_from_source_geometry_data() instead.");
+
{
MutexLock lock(navigation_mesh_generation);
navigation_mesh.unref();
@@ -331,6 +336,7 @@ void NavigationPolygon::make_polygons_from_outlines() {
emit_changed();
}
+#endif // DISABLE_DEPRECATED
void NavigationPolygon::set_cell_size(real_t p_cell_size) {
cell_size = p_cell_size;
@@ -341,6 +347,69 @@ real_t NavigationPolygon::get_cell_size() const {
return cell_size;
}
+void NavigationPolygon::set_parsed_geometry_type(ParsedGeometryType p_geometry_type) {
+ ERR_FAIL_INDEX(p_geometry_type, PARSED_GEOMETRY_MAX);
+ parsed_geometry_type = p_geometry_type;
+ notify_property_list_changed();
+}
+
+NavigationPolygon::ParsedGeometryType NavigationPolygon::get_parsed_geometry_type() const {
+ return parsed_geometry_type;
+}
+
+void NavigationPolygon::set_parsed_collision_mask(uint32_t p_mask) {
+ parsed_collision_mask = p_mask;
+}
+
+uint32_t NavigationPolygon::get_parsed_collision_mask() const {
+ return parsed_collision_mask;
+}
+
+void NavigationPolygon::set_parsed_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
+ uint32_t mask = get_parsed_collision_mask();
+ if (p_value) {
+ mask |= 1 << (p_layer_number - 1);
+ } else {
+ mask &= ~(1 << (p_layer_number - 1));
+ }
+ set_parsed_collision_mask(mask);
+}
+
+bool NavigationPolygon::get_parsed_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_parsed_collision_mask() & (1 << (p_layer_number - 1));
+}
+
+void NavigationPolygon::set_source_geometry_mode(SourceGeometryMode p_geometry_mode) {
+ ERR_FAIL_INDEX(p_geometry_mode, SOURCE_GEOMETRY_MAX);
+ source_geometry_mode = p_geometry_mode;
+ notify_property_list_changed();
+}
+
+NavigationPolygon::SourceGeometryMode NavigationPolygon::get_source_geometry_mode() const {
+ return source_geometry_mode;
+}
+
+void NavigationPolygon::set_source_geometry_group_name(StringName p_group_name) {
+ source_geometry_group_name = p_group_name;
+}
+
+StringName NavigationPolygon::get_source_geometry_group_name() const {
+ return source_geometry_group_name;
+}
+
+void NavigationPolygon::set_agent_radius(real_t p_value) {
+ ERR_FAIL_COND(p_value < 0);
+ agent_radius = p_value;
+}
+
+real_t NavigationPolygon::get_agent_radius() const {
+ return agent_radius;
+}
+
void NavigationPolygon::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationPolygon::set_vertices);
ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationPolygon::get_vertices);
@@ -358,7 +427,9 @@ void NavigationPolygon::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_outline", "idx"), &NavigationPolygon::get_outline);
ClassDB::bind_method(D_METHOD("remove_outline", "idx"), &NavigationPolygon::remove_outline);
ClassDB::bind_method(D_METHOD("clear_outlines"), &NavigationPolygon::clear_outlines);
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("make_polygons_from_outlines"), &NavigationPolygon::make_polygons_from_outlines);
+#endif // DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("_set_polygons", "polygons"), &NavigationPolygon::_set_polygons);
ClassDB::bind_method(D_METHOD("_get_polygons"), &NavigationPolygon::_get_polygons);
@@ -369,10 +440,69 @@ void NavigationPolygon::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationPolygon::set_cell_size);
ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationPolygon::get_cell_size);
+ ClassDB::bind_method(D_METHOD("set_parsed_geometry_type", "geometry_type"), &NavigationPolygon::set_parsed_geometry_type);
+ ClassDB::bind_method(D_METHOD("get_parsed_geometry_type"), &NavigationPolygon::get_parsed_geometry_type);
+
+ ClassDB::bind_method(D_METHOD("set_parsed_collision_mask", "mask"), &NavigationPolygon::set_parsed_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_parsed_collision_mask"), &NavigationPolygon::get_parsed_collision_mask);
+
+ ClassDB::bind_method(D_METHOD("set_parsed_collision_mask_value", "layer_number", "value"), &NavigationPolygon::set_parsed_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_parsed_collision_mask_value", "layer_number"), &NavigationPolygon::get_parsed_collision_mask_value);
+
+ ClassDB::bind_method(D_METHOD("set_source_geometry_mode", "geometry_mode"), &NavigationPolygon::set_source_geometry_mode);
+ ClassDB::bind_method(D_METHOD("get_source_geometry_mode"), &NavigationPolygon::get_source_geometry_mode);
+
+ ClassDB::bind_method(D_METHOD("set_source_geometry_group_name", "group_name"), &NavigationPolygon::set_source_geometry_group_name);
+ ClassDB::bind_method(D_METHOD("get_source_geometry_group_name"), &NavigationPolygon::get_source_geometry_group_name);
+
+ ClassDB::bind_method(D_METHOD("set_agent_radius", "agent_radius"), &NavigationPolygon::set_agent_radius);
+ ClassDB::bind_method(D_METHOD("get_agent_radius"), &NavigationPolygon::get_agent_radius);
+
ClassDB::bind_method(D_METHOD("clear"), &NavigationPolygon::clear);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:px"), "set_cell_size", "get_cell_size");
+
+ ADD_GROUP("Geometry", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Meshes and Static Colliders"), "set_parsed_geometry_type", "get_parsed_geometry_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "parsed_collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_parsed_collision_mask", "get_parsed_collision_mask");
+ ADD_PROPERTY_DEFAULT("parsed_collision_mask", 0xFFFFFFFF);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "source_geometry_mode", PROPERTY_HINT_ENUM, "Root Node Children,Group With Children,Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_geometry_group_name"), "set_source_geometry_group_name", "get_source_geometry_group_name");
+ ADD_PROPERTY_DEFAULT("source_geometry_group_name", StringName("navigation_polygon_source_geometry_group"));
+ ADD_GROUP("Cells", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "1.0,50.0,1.0,or_greater,suffix:px"), "set_cell_size", "get_cell_size");
+ ADD_GROUP("Agents", "agent_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_radius", PROPERTY_HINT_RANGE, "0.0,500.0,0.01,or_greater,suffix:px"), "set_agent_radius", "get_agent_radius");
+
+ BIND_ENUM_CONSTANT(PARSED_GEOMETRY_MESH_INSTANCES);
+ BIND_ENUM_CONSTANT(PARSED_GEOMETRY_STATIC_COLLIDERS);
+ BIND_ENUM_CONSTANT(PARSED_GEOMETRY_BOTH);
+ BIND_ENUM_CONSTANT(PARSED_GEOMETRY_MAX);
+
+ BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_ROOT_NODE_CHILDREN);
+ BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN);
+ BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_GROUPS_EXPLICIT);
+ BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_MAX);
+}
+
+void NavigationPolygon::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "parsed_collision_mask") {
+ if (parsed_geometry_type == PARSED_GEOMETRY_MESH_INSTANCES) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ return;
+ }
+ }
+
+ if (p_property.name == "parsed_source_group_name") {
+ if (source_geometry_mode == SOURCE_GEOMETRY_ROOT_NODE_CHILDREN) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ return;
+ }
+ }
+}
+
+NavigationPolygon::NavigationPolygon() {
+ navigation_mesh.instantiate();
}
diff --git a/scene/resources/navigation_polygon.h b/scene/resources/navigation_polygon.h
index 7926709a9ef..4a6a97e2e72 100644
--- a/scene/resources/navigation_polygon.h
+++ b/scene/resources/navigation_polygon.h
@@ -43,6 +43,7 @@ class NavigationPolygon : public Resource {
};
Vector polygons;
Vector> outlines;
+ Vector> baked_outlines;
mutable Rect2 item_rect;
mutable bool rect_cache_dirty = true;
@@ -55,6 +56,7 @@ class NavigationPolygon : public Resource {
protected:
static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
void _set_polygons(const TypedArray> &p_array);
TypedArray> _get_polygons() const;
@@ -68,6 +70,28 @@ public:
bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
#endif
+ enum ParsedGeometryType {
+ PARSED_GEOMETRY_MESH_INSTANCES = 0,
+ PARSED_GEOMETRY_STATIC_COLLIDERS,
+ PARSED_GEOMETRY_BOTH,
+ PARSED_GEOMETRY_MAX
+ };
+
+ enum SourceGeometryMode {
+ SOURCE_GEOMETRY_ROOT_NODE_CHILDREN = 0,
+ SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN,
+ SOURCE_GEOMETRY_GROUPS_EXPLICIT,
+ SOURCE_GEOMETRY_MAX
+ };
+
+ real_t agent_radius = 10.0f;
+
+ ParsedGeometryType parsed_geometry_type = PARSED_GEOMETRY_BOTH;
+ uint32_t parsed_collision_mask = 0xFFFFFFFF;
+
+ SourceGeometryMode source_geometry_mode = SOURCE_GEOMETRY_ROOT_NODE_CHILDREN;
+ StringName source_geometry_group_name = "navigation_polygon_source_group";
+
void set_vertices(const Vector &p_vertices);
Vector get_vertices() const;
@@ -82,11 +106,33 @@ public:
int get_outline_count() const;
void clear_outlines();
+#ifndef DISABLE_DEPRECATED
void make_polygons_from_outlines();
+#endif // DISABLE_DEPRECATED
+ void set_polygons(const Vector> &p_polygons);
+ const Vector> &get_polygons() const;
Vector get_polygon(int p_idx);
void clear_polygons();
+ void set_parsed_geometry_type(ParsedGeometryType p_geometry_type);
+ ParsedGeometryType get_parsed_geometry_type() const;
+
+ void set_parsed_collision_mask(uint32_t p_mask);
+ uint32_t get_parsed_collision_mask() const;
+
+ void set_parsed_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_parsed_collision_mask_value(int p_layer_number) const;
+
+ void set_source_geometry_mode(SourceGeometryMode p_geometry_mode);
+ SourceGeometryMode get_source_geometry_mode() const;
+
+ void set_source_geometry_group_name(StringName p_group_name);
+ StringName get_source_geometry_group_name() const;
+
+ void set_agent_radius(real_t p_value);
+ real_t get_agent_radius() const;
+
Ref get_navigation_mesh();
void set_cell_size(real_t p_cell_size);
@@ -94,8 +140,11 @@ public:
void clear();
- NavigationPolygon() {}
+ NavigationPolygon();
~NavigationPolygon() {}
};
+VARIANT_ENUM_CAST(NavigationPolygon::ParsedGeometryType);
+VARIANT_ENUM_CAST(NavigationPolygon::SourceGeometryMode);
+
#endif // NAVIGATION_POLYGON_H
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index cd92d9dd2f3..3804b45e1a9 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -28,133 +28,153 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#include "servers/navigation_server_2d.h"
+#include "navigation_server_2d.h"
-#include "core/math/transform_2d.h"
-#include "core/math/transform_3d.h"
#include "servers/navigation_server_3d.h"
NavigationServer2D *NavigationServer2D::singleton = nullptr;
-#define FORWARD_0(FUNC_NAME) \
- NavigationServer2D::FUNC_NAME() { \
- return NavigationServer3D::get_singleton()->FUNC_NAME(); \
- }
+void NavigationServer2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_maps"), &NavigationServer2D::get_maps);
-#define FORWARD_0_C(FUNC_NAME) \
- NavigationServer2D::FUNC_NAME() \
- const { \
- return NavigationServer3D::get_singleton()->FUNC_NAME(); \
- }
+ ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer2D::map_create);
+ ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer2D::map_set_active);
+ ClassDB::bind_method(D_METHOD("map_is_active", "map"), &NavigationServer2D::map_is_active);
+ ClassDB::bind_method(D_METHOD("map_set_cell_size", "map", "cell_size"), &NavigationServer2D::map_set_cell_size);
+ ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer2D::map_get_cell_size);
+ ClassDB::bind_method(D_METHOD("map_set_use_edge_connections", "map", "enabled"), &NavigationServer2D::map_set_use_edge_connections);
+ ClassDB::bind_method(D_METHOD("map_get_use_edge_connections", "map"), &NavigationServer2D::map_get_use_edge_connections);
+ ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer2D::map_set_edge_connection_margin);
+ ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &NavigationServer2D::map_get_edge_connection_margin);
+ ClassDB::bind_method(D_METHOD("map_set_link_connection_radius", "map", "radius"), &NavigationServer2D::map_set_link_connection_radius);
+ ClassDB::bind_method(D_METHOD("map_get_link_connection_radius", "map"), &NavigationServer2D::map_get_link_connection_radius);
+ ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "navigation_layers"), &NavigationServer2D::map_get_path, DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &NavigationServer2D::map_get_closest_point);
+ ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &NavigationServer2D::map_get_closest_point_owner);
-#define FORWARD_1(FUNC_NAME, T_0, D_0, CONV_0) \
- NavigationServer2D::FUNC_NAME(T_0 D_0) { \
- return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0)); \
- }
+ ClassDB::bind_method(D_METHOD("map_get_links", "map"), &NavigationServer2D::map_get_links);
+ ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &NavigationServer2D::map_get_regions);
+ ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer2D::map_get_agents);
+ ClassDB::bind_method(D_METHOD("map_get_obstacles", "map"), &NavigationServer2D::map_get_obstacles);
-#define FORWARD_1_C(FUNC_NAME, T_0, D_0, CONV_0) \
- NavigationServer2D::FUNC_NAME(T_0 D_0) \
- const { \
- return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0)); \
- }
+ ClassDB::bind_method(D_METHOD("map_force_update", "map"), &NavigationServer2D::map_force_update);
-#define FORWARD_1_R_C(CONV_R, FUNC_NAME, T_0, D_0, CONV_0) \
- NavigationServer2D::FUNC_NAME(T_0 D_0) \
- const { \
- return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0))); \
- }
+ ClassDB::bind_method(D_METHOD("query_path", "parameters", "result"), &NavigationServer2D::query_path);
-#define FORWARD_2(FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
- NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1) { \
- return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1)); \
- }
+ ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer2D::region_create);
+ ClassDB::bind_method(D_METHOD("region_set_enabled", "region", "enabled"), &NavigationServer2D::region_set_enabled);
+ ClassDB::bind_method(D_METHOD("region_get_enabled", "region"), &NavigationServer2D::region_get_enabled);
+ ClassDB::bind_method(D_METHOD("region_set_use_edge_connections", "region", "enabled"), &NavigationServer2D::region_set_use_edge_connections);
+ ClassDB::bind_method(D_METHOD("region_get_use_edge_connections", "region"), &NavigationServer2D::region_get_use_edge_connections);
+ 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_owner_id", "region", "owner_id"), &NavigationServer2D::region_set_owner_id);
+ ClassDB::bind_method(D_METHOD("region_get_owner_id", "region"), &NavigationServer2D::region_get_owner_id);
+ ClassDB::bind_method(D_METHOD("region_owns_point", "region", "point"), &NavigationServer2D::region_owns_point);
+ 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_navigation_layers", "region", "navigation_layers"), &NavigationServer2D::region_set_navigation_layers);
+ ClassDB::bind_method(D_METHOD("region_get_navigation_layers", "region"), &NavigationServer2D::region_get_navigation_layers);
+ ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer2D::region_set_transform);
+ ClassDB::bind_method(D_METHOD("region_set_navigation_polygon", "region", "navigation_polygon"), &NavigationServer2D::region_set_navigation_polygon);
+ ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer2D::region_get_connections_count);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_start);
+ ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_end);
-#define FORWARD_2_C(FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
- NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1) \
- const { \
- return NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1)); \
- }
+ ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer2D::link_create);
+ ClassDB::bind_method(D_METHOD("link_set_map", "link", "map"), &NavigationServer2D::link_set_map);
+ ClassDB::bind_method(D_METHOD("link_get_map", "link"), &NavigationServer2D::link_get_map);
+ ClassDB::bind_method(D_METHOD("link_set_enabled", "link", "enabled"), &NavigationServer2D::link_set_enabled);
+ ClassDB::bind_method(D_METHOD("link_get_enabled", "link"), &NavigationServer2D::link_get_enabled);
+ ClassDB::bind_method(D_METHOD("link_set_bidirectional", "link", "bidirectional"), &NavigationServer2D::link_set_bidirectional);
+ ClassDB::bind_method(D_METHOD("link_is_bidirectional", "link"), &NavigationServer2D::link_is_bidirectional);
+ ClassDB::bind_method(D_METHOD("link_set_navigation_layers", "link", "navigation_layers"), &NavigationServer2D::link_set_navigation_layers);
+ ClassDB::bind_method(D_METHOD("link_get_navigation_layers", "link"), &NavigationServer2D::link_get_navigation_layers);
+ ClassDB::bind_method(D_METHOD("link_set_start_position", "link", "position"), &NavigationServer2D::link_set_start_position);
+ ClassDB::bind_method(D_METHOD("link_get_start_position", "link"), &NavigationServer2D::link_get_start_position);
+ ClassDB::bind_method(D_METHOD("link_set_end_position", "link", "position"), &NavigationServer2D::link_set_end_position);
+ ClassDB::bind_method(D_METHOD("link_get_end_position", "link"), &NavigationServer2D::link_get_end_position);
+ ClassDB::bind_method(D_METHOD("link_set_enter_cost", "link", "enter_cost"), &NavigationServer2D::link_set_enter_cost);
+ ClassDB::bind_method(D_METHOD("link_get_enter_cost", "link"), &NavigationServer2D::link_get_enter_cost);
+ ClassDB::bind_method(D_METHOD("link_set_travel_cost", "link", "travel_cost"), &NavigationServer2D::link_set_travel_cost);
+ ClassDB::bind_method(D_METHOD("link_get_travel_cost", "link"), &NavigationServer2D::link_get_travel_cost);
+ ClassDB::bind_method(D_METHOD("link_set_owner_id", "link", "owner_id"), &NavigationServer2D::link_set_owner_id);
+ ClassDB::bind_method(D_METHOD("link_get_owner_id", "link"), &NavigationServer2D::link_get_owner_id);
-#define FORWARD_2_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, CONV_0, CONV_1) \
- NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1) \
- const { \
- return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1))); \
- }
+ ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer2D::agent_create);
+ ClassDB::bind_method(D_METHOD("agent_set_avoidance_enabled", "agent", "enabled"), &NavigationServer2D::agent_set_avoidance_enabled);
+ ClassDB::bind_method(D_METHOD("agent_get_avoidance_enabled", "agent"), &NavigationServer2D::agent_get_avoidance_enabled);
+ ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer2D::agent_set_map);
+ ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &NavigationServer2D::agent_get_map);
+ ClassDB::bind_method(D_METHOD("agent_set_paused", "agent", "paused"), &NavigationServer2D::agent_set_paused);
+ ClassDB::bind_method(D_METHOD("agent_get_paused", "agent"), &NavigationServer2D::agent_get_paused);
+ ClassDB::bind_method(D_METHOD("agent_set_neighbor_distance", "agent", "distance"), &NavigationServer2D::agent_set_neighbor_distance);
+ ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer2D::agent_set_max_neighbors);
+ ClassDB::bind_method(D_METHOD("agent_set_time_horizon_agents", "agent", "time_horizon"), &NavigationServer2D::agent_set_time_horizon_agents);
+ ClassDB::bind_method(D_METHOD("agent_set_time_horizon_obstacles", "agent", "time_horizon"), &NavigationServer2D::agent_set_time_horizon_obstacles);
+ ClassDB::bind_method(D_METHOD("agent_set_radius", "agent", "radius"), &NavigationServer2D::agent_set_radius);
+ ClassDB::bind_method(D_METHOD("agent_set_max_speed", "agent", "max_speed"), &NavigationServer2D::agent_set_max_speed);
+ ClassDB::bind_method(D_METHOD("agent_set_velocity_forced", "agent", "velocity"), &NavigationServer2D::agent_set_velocity_forced);
+ ClassDB::bind_method(D_METHOD("agent_set_velocity", "agent", "velocity"), &NavigationServer2D::agent_set_velocity);
+ ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &NavigationServer2D::agent_set_position);
+ ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &NavigationServer2D::agent_is_map_changed);
+ ClassDB::bind_method(D_METHOD("agent_set_avoidance_callback", "agent", "callback"), &NavigationServer2D::agent_set_avoidance_callback);
+ ClassDB::bind_method(D_METHOD("agent_set_avoidance_layers", "agent", "layers"), &NavigationServer2D::agent_set_avoidance_layers);
+ ClassDB::bind_method(D_METHOD("agent_set_avoidance_mask", "agent", "mask"), &NavigationServer2D::agent_set_avoidance_mask);
+ ClassDB::bind_method(D_METHOD("agent_set_avoidance_priority", "agent", "priority"), &NavigationServer2D::agent_set_avoidance_priority);
-#define FORWARD_5_R_C(CONV_R, FUNC_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, T_4, D_4, CONV_0, CONV_1, CONV_2, CONV_3, CONV_4) \
- NavigationServer2D::FUNC_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3, T_4 D_4) \
- const { \
- return CONV_R(NavigationServer3D::get_singleton()->FUNC_NAME(CONV_0(D_0), CONV_1(D_1), CONV_2(D_2), CONV_3(D_3), CONV_4(D_4))); \
- }
+ ClassDB::bind_method(D_METHOD("obstacle_create"), &NavigationServer2D::obstacle_create);
+ ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_enabled", "obstacle", "enabled"), &NavigationServer2D::obstacle_set_avoidance_enabled);
+ ClassDB::bind_method(D_METHOD("obstacle_get_avoidance_enabled", "obstacle"), &NavigationServer2D::obstacle_get_avoidance_enabled);
+ ClassDB::bind_method(D_METHOD("obstacle_set_map", "obstacle", "map"), &NavigationServer2D::obstacle_set_map);
+ ClassDB::bind_method(D_METHOD("obstacle_get_map", "obstacle"), &NavigationServer2D::obstacle_get_map);
+ ClassDB::bind_method(D_METHOD("obstacle_set_paused", "obstacle", "paused"), &NavigationServer2D::obstacle_set_paused);
+ ClassDB::bind_method(D_METHOD("obstacle_get_paused", "obstacle"), &NavigationServer2D::obstacle_get_paused);
+ ClassDB::bind_method(D_METHOD("obstacle_set_radius", "obstacle", "radius"), &NavigationServer2D::obstacle_set_radius);
+ ClassDB::bind_method(D_METHOD("obstacle_set_velocity", "obstacle", "velocity"), &NavigationServer2D::obstacle_set_velocity);
+ ClassDB::bind_method(D_METHOD("obstacle_set_position", "obstacle", "position"), &NavigationServer2D::obstacle_set_position);
+ ClassDB::bind_method(D_METHOD("obstacle_set_vertices", "obstacle", "vertices"), &NavigationServer2D::obstacle_set_vertices);
+ ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_layers", "obstacle", "layers"), &NavigationServer2D::obstacle_set_avoidance_layers);
-static RID rid_to_rid(const RID d) {
- return d;
+ ClassDB::bind_method(D_METHOD("parse_source_geometry_data", "navigation_polygon", "source_geometry_data", "root_node", "callback"), &NavigationServer2D::parse_source_geometry_data, DEFVAL(Callable()));
+ ClassDB::bind_method(D_METHOD("bake_from_source_geometry_data", "navigation_polygon", "source_geometry_data", "callback"), &NavigationServer2D::bake_from_source_geometry_data, DEFVAL(Callable()));
+ ClassDB::bind_method(D_METHOD("bake_from_source_geometry_data_async", "navigation_polygon", "source_geometry_data", "callback"), &NavigationServer2D::bake_from_source_geometry_data_async, DEFVAL(Callable()));
+
+ ClassDB::bind_method(D_METHOD("free_rid", "rid"), &NavigationServer2D::free);
+
+ ClassDB::bind_method(D_METHOD("set_debug_enabled", "enabled"), &NavigationServer2D::set_debug_enabled);
+ ClassDB::bind_method(D_METHOD("get_debug_enabled"), &NavigationServer2D::get_debug_enabled);
+
+ ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map")));
+
+ ADD_SIGNAL(MethodInfo("navigation_debug_changed"));
}
-static bool bool_to_bool(const bool d) {
- return d;
+NavigationServer2D *NavigationServer2D::get_singleton() {
+ return singleton;
}
-static int int_to_int(const int d) {
- return d;
+NavigationServer2D::NavigationServer2D() {
+ ERR_FAIL_COND(singleton != nullptr);
+ singleton = this;
+ ERR_FAIL_NULL_MSG(NavigationServer3D::get_singleton(), "The Navigation3D singleton should be initialized before the 2D one.");
+ NavigationServer3D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationServer2D::_emit_map_changed));
+
+#ifdef DEBUG_ENABLED
+ NavigationServer3D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationServer2D::_emit_navigation_debug_changed_signal));
+#endif // DEBUG_ENABLED
}
-static uint32_t uint32_to_uint32(const uint32_t d) {
- return d;
+#ifdef DEBUG_ENABLED
+void NavigationServer2D::_emit_navigation_debug_changed_signal() {
+ emit_signal(SNAME("navigation_debug_changed"));
}
+#endif // DEBUG_ENABLED
-static real_t real_to_real(const real_t d) {
- return d;
-}
-
-static Vector3 v2_to_v3(const Vector2 d) {
- return Vector3(d.x, 0.0, d.y);
-}
-
-static Vector2 v3_to_v2(const Vector3 &d) {
- return Vector2(d.x, d.z);
-}
-
-static Vector vector_v2_to_v3(const Vector &d) {
- Vector nd;
- nd.resize(d.size());
- for (int i(0); i < nd.size(); i++) {
- nd.write[i] = v2_to_v3(d[i]);
- }
- return nd;
-}
-
-static Vector vector_v3_to_v2(const Vector &d) {
- Vector nd;
- nd.resize(d.size());
- for (int i(0); i < nd.size(); i++) {
- nd.write[i] = v3_to_v2(d[i]);
- }
- return nd;
-}
-
-static Transform3D trf2_to_trf3(const Transform2D &d) {
- Vector3 o(v2_to_v3(d.get_origin()));
- Basis b;
- b.rotate(Vector3(0, -1, 0), d.get_rotation());
- b.scale(v2_to_v3(d.get_scale()));
- return Transform3D(b, o);
-}
-
-static ObjectID id_to_id(const ObjectID &id) {
- return id;
-}
-
-static Callable callable_to_callable(const Callable &c) {
- return c;
-}
-
-static Ref poly_to_mesh(Ref d) {
- if (d.is_valid()) {
- return d->get_navigation_mesh();
- } else {
- return Ref();
- }
+NavigationServer2D::~NavigationServer2D() {
+ singleton = nullptr;
}
void NavigationServer2D::_emit_map_changed(RID p_map) {
@@ -363,286 +383,18 @@ bool NavigationServer2D::get_debug_navigation_avoidance_enable_obstacles_static(
}
#endif // DEBUG_ENABLED
-void NavigationServer2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_maps"), &NavigationServer2D::get_maps);
+///////////////////////////////////////////////////////
- ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer2D::map_create);
- ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer2D::map_set_active);
- ClassDB::bind_method(D_METHOD("map_is_active", "map"), &NavigationServer2D::map_is_active);
- ClassDB::bind_method(D_METHOD("map_set_cell_size", "map", "cell_size"), &NavigationServer2D::map_set_cell_size);
- ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer2D::map_get_cell_size);
- ClassDB::bind_method(D_METHOD("map_set_use_edge_connections", "map", "enabled"), &NavigationServer2D::map_set_use_edge_connections);
- ClassDB::bind_method(D_METHOD("map_get_use_edge_connections", "map"), &NavigationServer2D::map_get_use_edge_connections);
- ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer2D::map_set_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("map_get_edge_connection_margin", "map"), &NavigationServer2D::map_get_edge_connection_margin);
- ClassDB::bind_method(D_METHOD("map_set_link_connection_radius", "map", "radius"), &NavigationServer2D::map_set_link_connection_radius);
- ClassDB::bind_method(D_METHOD("map_get_link_connection_radius", "map"), &NavigationServer2D::map_get_link_connection_radius);
- ClassDB::bind_method(D_METHOD("map_get_path", "map", "origin", "destination", "optimize", "navigation_layers"), &NavigationServer2D::map_get_path, DEFVAL(1));
- ClassDB::bind_method(D_METHOD("map_get_closest_point", "map", "to_point"), &NavigationServer2D::map_get_closest_point);
- ClassDB::bind_method(D_METHOD("map_get_closest_point_owner", "map", "to_point"), &NavigationServer2D::map_get_closest_point_owner);
+NavigationServer2DCallback NavigationServer2DManager::create_callback = nullptr;
- ClassDB::bind_method(D_METHOD("map_get_links", "map"), &NavigationServer2D::map_get_links);
- ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &NavigationServer2D::map_get_regions);
- ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer2D::map_get_agents);
- 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("query_path", "parameters", "result"), &NavigationServer2D::query_path);
-
- ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer2D::region_create);
- ClassDB::bind_method(D_METHOD("region_set_enabled", "region", "enabled"), &NavigationServer2D::region_set_enabled);
- ClassDB::bind_method(D_METHOD("region_get_enabled", "region"), &NavigationServer2D::region_get_enabled);
- ClassDB::bind_method(D_METHOD("region_set_use_edge_connections", "region", "enabled"), &NavigationServer2D::region_set_use_edge_connections);
- ClassDB::bind_method(D_METHOD("region_get_use_edge_connections", "region"), &NavigationServer2D::region_get_use_edge_connections);
- 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_owner_id", "region", "owner_id"), &NavigationServer2D::region_set_owner_id);
- ClassDB::bind_method(D_METHOD("region_get_owner_id", "region"), &NavigationServer2D::region_get_owner_id);
- ClassDB::bind_method(D_METHOD("region_owns_point", "region", "point"), &NavigationServer2D::region_owns_point);
- 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_navigation_layers", "region", "navigation_layers"), &NavigationServer2D::region_set_navigation_layers);
- ClassDB::bind_method(D_METHOD("region_get_navigation_layers", "region"), &NavigationServer2D::region_get_navigation_layers);
- ClassDB::bind_method(D_METHOD("region_set_transform", "region", "transform"), &NavigationServer2D::region_set_transform);
- ClassDB::bind_method(D_METHOD("region_set_navigation_polygon", "region", "navigation_polygon"), &NavigationServer2D::region_set_navigation_polygon);
- ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer2D::region_get_connections_count);
- ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_start);
- ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_end);
-
- ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer2D::link_create);
- ClassDB::bind_method(D_METHOD("link_set_map", "link", "map"), &NavigationServer2D::link_set_map);
- ClassDB::bind_method(D_METHOD("link_get_map", "link"), &NavigationServer2D::link_get_map);
- ClassDB::bind_method(D_METHOD("link_set_enabled", "link", "enabled"), &NavigationServer2D::link_set_enabled);
- ClassDB::bind_method(D_METHOD("link_get_enabled", "link"), &NavigationServer2D::link_get_enabled);
- ClassDB::bind_method(D_METHOD("link_set_bidirectional", "link", "bidirectional"), &NavigationServer2D::link_set_bidirectional);
- ClassDB::bind_method(D_METHOD("link_is_bidirectional", "link"), &NavigationServer2D::link_is_bidirectional);
- ClassDB::bind_method(D_METHOD("link_set_navigation_layers", "link", "navigation_layers"), &NavigationServer2D::link_set_navigation_layers);
- ClassDB::bind_method(D_METHOD("link_get_navigation_layers", "link"), &NavigationServer2D::link_get_navigation_layers);
- ClassDB::bind_method(D_METHOD("link_set_start_position", "link", "position"), &NavigationServer2D::link_set_start_position);
- ClassDB::bind_method(D_METHOD("link_get_start_position", "link"), &NavigationServer2D::link_get_start_position);
- ClassDB::bind_method(D_METHOD("link_set_end_position", "link", "position"), &NavigationServer2D::link_set_end_position);
- ClassDB::bind_method(D_METHOD("link_get_end_position", "link"), &NavigationServer2D::link_get_end_position);
- ClassDB::bind_method(D_METHOD("link_set_enter_cost", "link", "enter_cost"), &NavigationServer2D::link_set_enter_cost);
- ClassDB::bind_method(D_METHOD("link_get_enter_cost", "link"), &NavigationServer2D::link_get_enter_cost);
- ClassDB::bind_method(D_METHOD("link_set_travel_cost", "link", "travel_cost"), &NavigationServer2D::link_set_travel_cost);
- ClassDB::bind_method(D_METHOD("link_get_travel_cost", "link"), &NavigationServer2D::link_get_travel_cost);
- ClassDB::bind_method(D_METHOD("link_set_owner_id", "link", "owner_id"), &NavigationServer2D::link_set_owner_id);
- ClassDB::bind_method(D_METHOD("link_get_owner_id", "link"), &NavigationServer2D::link_get_owner_id);
-
- ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer2D::agent_create);
- ClassDB::bind_method(D_METHOD("agent_set_avoidance_enabled", "agent", "enabled"), &NavigationServer2D::agent_set_avoidance_enabled);
- ClassDB::bind_method(D_METHOD("agent_get_avoidance_enabled", "agent"), &NavigationServer2D::agent_get_avoidance_enabled);
- ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer2D::agent_set_map);
- ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &NavigationServer2D::agent_get_map);
- ClassDB::bind_method(D_METHOD("agent_set_paused", "agent", "paused"), &NavigationServer2D::agent_set_paused);
- ClassDB::bind_method(D_METHOD("agent_get_paused", "agent"), &NavigationServer2D::agent_get_paused);
- ClassDB::bind_method(D_METHOD("agent_set_neighbor_distance", "agent", "distance"), &NavigationServer2D::agent_set_neighbor_distance);
- ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer2D::agent_set_max_neighbors);
- ClassDB::bind_method(D_METHOD("agent_set_time_horizon_agents", "agent", "time_horizon"), &NavigationServer2D::agent_set_time_horizon_agents);
- ClassDB::bind_method(D_METHOD("agent_set_time_horizon_obstacles", "agent", "time_horizon"), &NavigationServer2D::agent_set_time_horizon_obstacles);
- ClassDB::bind_method(D_METHOD("agent_set_radius", "agent", "radius"), &NavigationServer2D::agent_set_radius);
- ClassDB::bind_method(D_METHOD("agent_set_max_speed", "agent", "max_speed"), &NavigationServer2D::agent_set_max_speed);
- ClassDB::bind_method(D_METHOD("agent_set_velocity_forced", "agent", "velocity"), &NavigationServer2D::agent_set_velocity_forced);
- ClassDB::bind_method(D_METHOD("agent_set_velocity", "agent", "velocity"), &NavigationServer2D::agent_set_velocity);
- ClassDB::bind_method(D_METHOD("agent_set_position", "agent", "position"), &NavigationServer2D::agent_set_position);
- ClassDB::bind_method(D_METHOD("agent_is_map_changed", "agent"), &NavigationServer2D::agent_is_map_changed);
- ClassDB::bind_method(D_METHOD("agent_set_avoidance_callback", "agent", "callback"), &NavigationServer2D::agent_set_avoidance_callback);
- ClassDB::bind_method(D_METHOD("agent_set_avoidance_layers", "agent", "layers"), &NavigationServer2D::agent_set_avoidance_layers);
- ClassDB::bind_method(D_METHOD("agent_set_avoidance_mask", "agent", "mask"), &NavigationServer2D::agent_set_avoidance_mask);
- ClassDB::bind_method(D_METHOD("agent_set_avoidance_priority", "agent", "priority"), &NavigationServer2D::agent_set_avoidance_priority);
-
- ClassDB::bind_method(D_METHOD("obstacle_create"), &NavigationServer2D::obstacle_create);
- ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_enabled", "obstacle", "enabled"), &NavigationServer2D::obstacle_set_avoidance_enabled);
- ClassDB::bind_method(D_METHOD("obstacle_get_avoidance_enabled", "obstacle"), &NavigationServer2D::obstacle_get_avoidance_enabled);
- ClassDB::bind_method(D_METHOD("obstacle_set_map", "obstacle", "map"), &NavigationServer2D::obstacle_set_map);
- ClassDB::bind_method(D_METHOD("obstacle_get_map", "obstacle"), &NavigationServer2D::obstacle_get_map);
- ClassDB::bind_method(D_METHOD("obstacle_set_paused", "obstacle", "paused"), &NavigationServer2D::obstacle_set_paused);
- ClassDB::bind_method(D_METHOD("obstacle_get_paused", "obstacle"), &NavigationServer2D::obstacle_get_paused);
- ClassDB::bind_method(D_METHOD("obstacle_set_radius", "obstacle", "radius"), &NavigationServer2D::obstacle_set_radius);
- ClassDB::bind_method(D_METHOD("obstacle_set_velocity", "obstacle", "velocity"), &NavigationServer2D::obstacle_set_velocity);
- ClassDB::bind_method(D_METHOD("obstacle_set_position", "obstacle", "position"), &NavigationServer2D::obstacle_set_position);
- ClassDB::bind_method(D_METHOD("obstacle_set_vertices", "obstacle", "vertices"), &NavigationServer2D::obstacle_set_vertices);
- ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_layers", "obstacle", "layers"), &NavigationServer2D::obstacle_set_avoidance_layers);
-
- ClassDB::bind_method(D_METHOD("free_rid", "rid"), &NavigationServer2D::free);
-
- ClassDB::bind_method(D_METHOD("set_debug_enabled", "enabled"), &NavigationServer2D::set_debug_enabled);
- ClassDB::bind_method(D_METHOD("get_debug_enabled"), &NavigationServer2D::get_debug_enabled);
-
- ADD_SIGNAL(MethodInfo("map_changed", PropertyInfo(Variant::RID, "map")));
-
- ADD_SIGNAL(MethodInfo("navigation_debug_changed"));
+void NavigationServer2DManager::set_default_server(NavigationServer2DCallback p_callback) {
+ create_callback = p_callback;
}
-NavigationServer2D::NavigationServer2D() {
- singleton = this;
- ERR_FAIL_COND_MSG(!NavigationServer3D::get_singleton(), "The Navigation3D singleton should be initialized before the 2D one.");
- NavigationServer3D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationServer2D::_emit_map_changed));
+NavigationServer2D *NavigationServer2DManager::new_default_server() {
+ if (create_callback == nullptr) {
+ return nullptr;
+ }
-#ifdef DEBUG_ENABLED
- NavigationServer3D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationServer2D::_emit_navigation_debug_changed_signal));
-#endif // DEBUG_ENABLED
-}
-
-#ifdef DEBUG_ENABLED
-void NavigationServer2D::_emit_navigation_debug_changed_signal() {
- emit_signal(SNAME("navigation_debug_changed"));
-}
-#endif // DEBUG_ENABLED
-
-NavigationServer2D::~NavigationServer2D() {
- singleton = nullptr;
-}
-
-TypedArray FORWARD_0_C(get_maps);
-
-TypedArray FORWARD_1_C(map_get_links, RID, p_map, rid_to_rid);
-
-TypedArray FORWARD_1_C(map_get_regions, RID, p_map, rid_to_rid);
-
-TypedArray FORWARD_1_C(map_get_agents, RID, p_map, rid_to_rid);
-
-TypedArray FORWARD_1_C(map_get_obstacles, RID, p_map, rid_to_rid);
-
-RID FORWARD_1_C(region_get_map, RID, p_region, rid_to_rid);
-
-RID FORWARD_1_C(agent_get_map, RID, p_agent, rid_to_rid);
-
-RID FORWARD_0(map_create);
-
-void FORWARD_2(map_set_active, RID, p_map, bool, p_active, rid_to_rid, bool_to_bool);
-
-bool FORWARD_1_C(map_is_active, RID, p_map, rid_to_rid);
-
-void NavigationServer2D::map_force_update(RID p_map) {
- NavigationServer3D::get_singleton()->map_force_update(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);
-
-void FORWARD_2(map_set_use_edge_connections, RID, p_map, bool, p_enabled, rid_to_rid, bool_to_bool);
-bool FORWARD_1_C(map_get_use_edge_connections, RID, p_map, rid_to_rid);
-
-void FORWARD_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin, rid_to_rid, real_to_real);
-real_t FORWARD_1_C(map_get_edge_connection_margin, RID, p_map, rid_to_rid);
-
-void FORWARD_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius, rid_to_rid, real_to_real);
-real_t FORWARD_1_C(map_get_link_connection_radius, RID, p_map, rid_to_rid);
-
-Vector FORWARD_5_R_C(vector_v3_to_v2, map_get_path, RID, p_map, Vector2, p_origin, Vector2, p_destination, bool, p_optimize, uint32_t, p_layers, rid_to_rid, v2_to_v3, v2_to_v3, bool_to_bool, uint32_to_uint32);
-
-Vector2 FORWARD_2_R_C(v3_to_v2, map_get_closest_point, RID, p_map, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
-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(region_create);
-
-void FORWARD_2(region_set_enabled, RID, p_region, bool, p_enabled, rid_to_rid, bool_to_bool);
-bool FORWARD_1_C(region_get_enabled, RID, p_region, rid_to_rid);
-void FORWARD_2(region_set_use_edge_connections, RID, p_region, bool, p_enabled, rid_to_rid, bool_to_bool);
-bool FORWARD_1_C(region_get_use_edge_connections, RID, p_region, rid_to_rid);
-
-void FORWARD_2(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(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(region_set_owner_id, RID, p_region, ObjectID, p_owner_id, rid_to_rid, id_to_id);
-ObjectID FORWARD_1_C(region_get_owner_id, RID, p_region, rid_to_rid);
-bool FORWARD_2_C(region_owns_point, RID, p_region, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
-
-void FORWARD_2(region_set_map, RID, p_region, RID, p_map, rid_to_rid, rid_to_rid);
-void FORWARD_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers, rid_to_rid, uint32_to_uint32);
-uint32_t FORWARD_1_C(region_get_navigation_layers, RID, p_region, rid_to_rid);
-void FORWARD_2(region_set_transform, RID, p_region, Transform2D, p_transform, rid_to_rid, trf2_to_trf3);
-
-void NavigationServer2D::region_set_navigation_polygon(RID p_region, Ref p_navigation_polygon) {
- NavigationServer3D::get_singleton()->region_set_navigation_mesh(p_region, poly_to_mesh(p_navigation_polygon));
-}
-
-int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid);
-Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_start, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
-Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_end, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
-
-RID FORWARD_0(link_create);
-
-void FORWARD_2(link_set_map, RID, p_link, RID, p_map, rid_to_rid, rid_to_rid);
-RID FORWARD_1_C(link_get_map, RID, p_link, rid_to_rid);
-void FORWARD_2(link_set_enabled, RID, p_link, bool, p_enabled, rid_to_rid, bool_to_bool);
-bool FORWARD_1_C(link_get_enabled, RID, p_link, rid_to_rid);
-void FORWARD_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional, rid_to_rid, bool_to_bool);
-bool FORWARD_1_C(link_is_bidirectional, RID, p_link, rid_to_rid);
-void FORWARD_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers, rid_to_rid, uint32_to_uint32);
-uint32_t FORWARD_1_C(link_get_navigation_layers, RID, p_link, rid_to_rid);
-void FORWARD_2(link_set_start_position, RID, p_link, Vector2, p_position, rid_to_rid, v2_to_v3);
-Vector2 FORWARD_1_R_C(v3_to_v2, link_get_start_position, RID, p_link, rid_to_rid);
-void FORWARD_2(link_set_end_position, RID, p_link, Vector2, p_position, rid_to_rid, v2_to_v3);
-Vector2 FORWARD_1_R_C(v3_to_v2, link_get_end_position, RID, p_link, rid_to_rid);
-void FORWARD_2(link_set_enter_cost, RID, p_link, real_t, p_enter_cost, rid_to_rid, real_to_real);
-real_t FORWARD_1_C(link_get_enter_cost, RID, p_link, rid_to_rid);
-void FORWARD_2(link_set_travel_cost, RID, p_link, real_t, p_travel_cost, rid_to_rid, real_to_real);
-real_t FORWARD_1_C(link_get_travel_cost, RID, p_link, rid_to_rid);
-void FORWARD_2(link_set_owner_id, RID, p_link, ObjectID, p_owner_id, rid_to_rid, id_to_id);
-ObjectID FORWARD_1_C(link_get_owner_id, RID, p_link, rid_to_rid);
-
-RID NavigationServer2D::agent_create() {
- RID agent = NavigationServer3D::get_singleton()->agent_create();
- return agent;
-}
-
-void FORWARD_2(agent_set_avoidance_enabled, RID, p_agent, bool, p_enabled, rid_to_rid, bool_to_bool);
-bool FORWARD_1_C(agent_get_avoidance_enabled, RID, p_agent, rid_to_rid);
-void FORWARD_2(agent_set_map, RID, p_agent, RID, p_map, rid_to_rid, rid_to_rid);
-void FORWARD_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_dist, rid_to_rid, real_to_real);
-void FORWARD_2(agent_set_max_neighbors, RID, p_agent, int, p_count, rid_to_rid, int_to_int);
-void FORWARD_2(agent_set_time_horizon_agents, RID, p_agent, real_t, p_time_horizon, rid_to_rid, real_to_real);
-void FORWARD_2(agent_set_time_horizon_obstacles, RID, p_agent, real_t, p_time_horizon, rid_to_rid, real_to_real);
-void FORWARD_2(agent_set_radius, RID, p_agent, real_t, p_radius, rid_to_rid, real_to_real);
-void FORWARD_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed, rid_to_rid, real_to_real);
-void FORWARD_2(agent_set_velocity_forced, RID, p_agent, Vector2, p_velocity, rid_to_rid, v2_to_v3);
-void FORWARD_2(agent_set_velocity, RID, p_agent, Vector2, p_velocity, rid_to_rid, v2_to_v3);
-void FORWARD_2(agent_set_position, RID, p_agent, Vector2, p_position, rid_to_rid, v2_to_v3);
-
-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 FORWARD_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback, rid_to_rid, callable_to_callable);
-
-void FORWARD_2(agent_set_avoidance_layers, RID, p_agent, uint32_t, p_layers, rid_to_rid, uint32_to_uint32);
-void FORWARD_2(agent_set_avoidance_mask, RID, p_agent, uint32_t, p_mask, rid_to_rid, uint32_to_uint32);
-void FORWARD_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority, rid_to_rid, real_to_real);
-
-RID NavigationServer2D::obstacle_create() {
- RID obstacle = NavigationServer3D::get_singleton()->obstacle_create();
- return obstacle;
-}
-void FORWARD_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled, rid_to_rid, bool_to_bool);
-bool FORWARD_1_C(obstacle_get_avoidance_enabled, RID, p_obstacle, rid_to_rid);
-void FORWARD_2(obstacle_set_map, RID, p_obstacle, RID, p_map, rid_to_rid, rid_to_rid);
-RID FORWARD_1_C(obstacle_get_map, RID, p_obstacle, rid_to_rid);
-void FORWARD_2(obstacle_set_paused, RID, p_obstacle, bool, p_paused, rid_to_rid, bool_to_bool);
-bool FORWARD_1_C(obstacle_get_paused, RID, p_obstacle, rid_to_rid);
-void FORWARD_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius, rid_to_rid, real_to_real);
-void FORWARD_2(obstacle_set_velocity, RID, p_obstacle, Vector2, p_velocity, rid_to_rid, v2_to_v3);
-void FORWARD_2(obstacle_set_position, RID, p_obstacle, Vector2, p_position, rid_to_rid, v2_to_v3);
-void FORWARD_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers, rid_to_rid, uint32_to_uint32);
-
-void NavigationServer2D::obstacle_set_vertices(RID p_obstacle, const Vector &p_vertices) {
- NavigationServer3D::get_singleton()->obstacle_set_vertices(p_obstacle, vector_v2_to_v3(p_vertices));
-}
-
-void NavigationServer2D::query_path(const Ref &p_query_parameters, Ref p_query_result) const {
- ERR_FAIL_COND(!p_query_parameters.is_valid());
- ERR_FAIL_COND(!p_query_result.is_valid());
-
- const NavigationUtilities::PathQueryResult _query_result = NavigationServer3D::get_singleton()->_query_path(p_query_parameters->get_parameters());
-
- p_query_result->set_path(vector_v3_to_v2(_query_result.path));
- p_query_result->set_path_types(_query_result.path_types);
- p_query_result->set_path_rids(_query_result.path_rids);
- p_query_result->set_path_owner_ids(_query_result.path_owner_ids);
+ return create_callback();
}
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index c78edaf8788..0afd794c26c 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -34,10 +34,15 @@
#include "core/object/class_db.h"
#include "core/templates/rid.h"
+#include "scene/resources/navigation_mesh_source_geometry_data_2d.h"
#include "scene/resources/navigation_polygon.h"
#include "servers/navigation/navigation_path_query_parameters_2d.h"
#include "servers/navigation/navigation_path_query_result_2d.h"
+#ifdef CLIPPER2_ENABLED
+class NavMeshGenerator2D;
+#endif // CLIPPER2_ENABLED
+
// This server exposes the `NavigationServer3D` features in the 2D world.
class NavigationServer2D : public Object {
GDCLASS(NavigationServer2D, Object);
@@ -51,145 +56,145 @@ protected:
public:
/// Thread safe, can be used across many threads.
- static NavigationServer2D *get_singleton() { return singleton; }
+ static NavigationServer2D *get_singleton();
- virtual TypedArray get_maps() const;
+ virtual TypedArray get_maps() const = 0;
/// Create a new map.
- virtual RID map_create();
+ virtual RID map_create() = 0;
/// Set map active.
- virtual void map_set_active(RID p_map, bool p_active);
+ virtual void map_set_active(RID p_map, bool p_active) = 0;
/// Returns true if the map is active.
- virtual bool map_is_active(RID p_map) const;
+ virtual bool map_is_active(RID p_map) const = 0;
/// Set the map cell size used to weld the navigation mesh polygons.
- virtual void map_set_cell_size(RID p_map, real_t p_cell_size);
+ virtual void map_set_cell_size(RID p_map, real_t p_cell_size) = 0;
/// Returns the map cell size.
- virtual real_t map_get_cell_size(RID p_map) const;
+ virtual real_t map_get_cell_size(RID p_map) const = 0;
- virtual void map_set_use_edge_connections(RID p_map, bool p_enabled);
- virtual bool map_get_use_edge_connections(RID p_map) const;
+ virtual void map_set_use_edge_connections(RID p_map, bool p_enabled) = 0;
+ virtual bool map_get_use_edge_connections(RID p_map) const = 0;
/// Set the map edge connection margin used to weld the compatible region edges.
- virtual void map_set_edge_connection_margin(RID p_map, real_t p_connection_margin);
+ virtual void map_set_edge_connection_margin(RID p_map, real_t p_connection_margin) = 0;
/// Returns the edge connection margin of this map.
- virtual real_t map_get_edge_connection_margin(RID p_map) const;
+ virtual real_t map_get_edge_connection_margin(RID p_map) const = 0;
/// Set the map link connection radius used to attach links to the nav mesh.
- virtual void map_set_link_connection_radius(RID p_map, real_t p_connection_radius);
+ virtual void map_set_link_connection_radius(RID p_map, real_t p_connection_radius) = 0;
/// Returns the link connection radius of this map.
- virtual real_t map_get_link_connection_radius(RID p_map) const;
+ virtual real_t map_get_link_connection_radius(RID p_map) const = 0;
/// Returns the navigation path to reach the destination from the origin.
- virtual Vector map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const;
+ virtual Vector map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const = 0;
- virtual Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const;
- virtual RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const;
+ virtual Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const = 0;
+ virtual RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const = 0;
- virtual TypedArray map_get_links(RID p_map) const;
- virtual TypedArray map_get_regions(RID p_map) const;
- virtual TypedArray map_get_agents(RID p_map) const;
- virtual TypedArray map_get_obstacles(RID p_map) const;
+ virtual TypedArray map_get_links(RID p_map) const = 0;
+ virtual TypedArray map_get_regions(RID p_map) const = 0;
+ virtual TypedArray map_get_agents(RID p_map) const = 0;
+ virtual TypedArray map_get_obstacles(RID p_map) const = 0;
- virtual void map_force_update(RID p_map);
+ virtual void map_force_update(RID p_map) = 0;
/// Creates a new region.
- virtual RID region_create();
+ virtual RID region_create() = 0;
- virtual void region_set_enabled(RID p_region, bool p_enabled);
- virtual bool region_get_enabled(RID p_region) const;
+ virtual void region_set_enabled(RID p_region, bool p_enabled) = 0;
+ virtual bool region_get_enabled(RID p_region) const = 0;
- virtual void region_set_use_edge_connections(RID p_region, bool p_enabled);
- virtual bool region_get_use_edge_connections(RID p_region) const;
+ virtual void region_set_use_edge_connections(RID p_region, bool p_enabled) = 0;
+ virtual bool region_get_use_edge_connections(RID p_region) const = 0;
/// Set the enter_cost of a region
- virtual void region_set_enter_cost(RID p_region, real_t p_enter_cost);
- virtual real_t region_get_enter_cost(RID p_region) const;
+ virtual void region_set_enter_cost(RID p_region, real_t p_enter_cost) = 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);
- virtual real_t region_get_travel_cost(RID p_region) const;
+ virtual void region_set_travel_cost(RID p_region, real_t p_travel_cost) = 0;
+ virtual real_t region_get_travel_cost(RID p_region) const = 0;
/// Set the node which manages this region.
- virtual void region_set_owner_id(RID p_region, ObjectID p_owner_id);
- virtual ObjectID region_get_owner_id(RID p_region) const;
+ virtual void region_set_owner_id(RID p_region, ObjectID p_owner_id) = 0;
+ virtual ObjectID region_get_owner_id(RID p_region) const = 0;
- virtual bool region_owns_point(RID p_region, const Vector2 &p_point) const;
+ virtual bool region_owns_point(RID p_region, const Vector2 &p_point) const = 0;
/// Set the map of this region.
- virtual void region_set_map(RID p_region, RID p_map);
- virtual RID region_get_map(RID p_region) const;
+ virtual void region_set_map(RID p_region, RID p_map) = 0;
+ virtual RID region_get_map(RID p_region) const = 0;
/// Set the region's layers
- virtual void region_set_navigation_layers(RID p_region, uint32_t p_navigation_layers);
- virtual uint32_t region_get_navigation_layers(RID p_region) const;
+ virtual void region_set_navigation_layers(RID p_region, uint32_t p_navigation_layers) = 0;
+ virtual uint32_t region_get_navigation_layers(RID p_region) const = 0;
/// Set the global transformation of this region.
- virtual void region_set_transform(RID p_region, Transform2D p_transform);
+ virtual void region_set_transform(RID p_region, Transform2D p_transform) = 0;
/// Set the navigation poly of this region.
- virtual void region_set_navigation_polygon(RID p_region, Ref p_navigation_polygon);
+ virtual void region_set_navigation_polygon(RID p_region, Ref p_navigation_polygon) = 0;
/// Get a list of a region's connection to other regions.
- virtual int region_get_connections_count(RID p_region) const;
- virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const;
- virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const;
+ virtual int region_get_connections_count(RID p_region) const = 0;
+ virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const = 0;
+ virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const = 0;
/// Creates a new link between positions in the nav map.
- virtual RID link_create();
+ virtual RID link_create() = 0;
/// Set the map of this link.
- virtual void link_set_map(RID p_link, RID p_map);
- virtual RID link_get_map(RID p_link) const;
+ virtual void link_set_map(RID p_link, RID p_map) = 0;
+ virtual RID link_get_map(RID p_link) const = 0;
- virtual void link_set_enabled(RID p_link, bool p_enabled);
- virtual bool link_get_enabled(RID p_link) const;
+ virtual void link_set_enabled(RID p_link, bool p_enabled) = 0;
+ virtual bool link_get_enabled(RID p_link) const = 0;
/// Set whether this link travels in both directions.
- virtual void link_set_bidirectional(RID p_link, bool p_bidirectional);
- virtual bool link_is_bidirectional(RID p_link) const;
+ virtual void link_set_bidirectional(RID p_link, bool p_bidirectional) = 0;
+ virtual bool link_is_bidirectional(RID p_link) const = 0;
/// Set the link's layers.
- virtual void link_set_navigation_layers(RID p_link, uint32_t p_navigation_layers);
- virtual uint32_t link_get_navigation_layers(RID p_link) const;
+ virtual void link_set_navigation_layers(RID p_link, uint32_t p_navigation_layers) = 0;
+ virtual uint32_t link_get_navigation_layers(RID p_link) const = 0;
/// Set the start position of the link.
- virtual void link_set_start_position(RID p_link, Vector2 p_position);
- virtual Vector2 link_get_start_position(RID p_link) const;
+ virtual void link_set_start_position(RID p_link, Vector2 p_position) = 0;
+ virtual Vector2 link_get_start_position(RID p_link) const = 0;
/// Set the end position of the link.
- virtual void link_set_end_position(RID p_link, Vector2 p_position);
- virtual Vector2 link_get_end_position(RID p_link) const;
+ virtual void link_set_end_position(RID p_link, Vector2 p_position) = 0;
+ virtual Vector2 link_get_end_position(RID p_link) const = 0;
/// Set the enter cost of the link.
- virtual void link_set_enter_cost(RID p_link, real_t p_enter_cost);
- virtual real_t link_get_enter_cost(RID p_link) const;
+ virtual void link_set_enter_cost(RID p_link, real_t p_enter_cost) = 0;
+ virtual real_t link_get_enter_cost(RID p_link) const = 0;
/// Set the travel cost of the link.
- virtual void link_set_travel_cost(RID p_link, real_t p_travel_cost);
- virtual real_t link_get_travel_cost(RID p_link) const;
+ virtual void link_set_travel_cost(RID p_link, real_t p_travel_cost) = 0;
+ virtual real_t link_get_travel_cost(RID p_link) const = 0;
/// Set the node which manages this link.
- virtual void link_set_owner_id(RID p_link, ObjectID p_owner_id);
- virtual ObjectID link_get_owner_id(RID p_link) const;
+ virtual void link_set_owner_id(RID p_link, ObjectID p_owner_id) = 0;
+ virtual ObjectID link_get_owner_id(RID p_link) const = 0;
/// Creates the agent.
- virtual RID agent_create();
+ virtual RID agent_create() = 0;
/// Put the agent in the map.
- virtual void agent_set_map(RID p_agent, RID p_map);
- virtual RID agent_get_map(RID p_agent) const;
+ virtual void agent_set_map(RID p_agent, RID p_map) = 0;
+ virtual RID agent_get_map(RID p_agent) const = 0;
- virtual void agent_set_paused(RID p_agent, bool p_paused);
- virtual bool agent_get_paused(RID p_agent) const;
+ virtual void agent_set_paused(RID p_agent, bool p_paused) = 0;
+ virtual bool agent_get_paused(RID p_agent) const = 0;
- virtual void agent_set_avoidance_enabled(RID p_agent, bool p_enabled);
- virtual bool agent_get_avoidance_enabled(RID p_agent) const;
+ virtual void agent_set_avoidance_enabled(RID p_agent, bool p_enabled) = 0;
+ virtual bool agent_get_avoidance_enabled(RID p_agent) const = 0;
/// The maximum distance (center point to
/// center point) to other agents this agent
@@ -198,7 +203,7 @@ public:
/// time of the simulation. If the number is too
/// low, the simulation will not be safe.
/// Must be non-negative.
- virtual void agent_set_neighbor_distance(RID p_agent, real_t p_distance);
+ virtual void agent_set_neighbor_distance(RID p_agent, real_t p_distance) = 0;
/// The maximum number of other agents this
/// agent takes into account in the navigation.
@@ -206,7 +211,7 @@ public:
/// running time of the simulation. If the
/// number is too low, the simulation will not
/// be safe.
- virtual void agent_set_max_neighbors(RID p_agent, int p_count);
+ virtual void agent_set_max_neighbors(RID p_agent, int p_count) = 0;
/// The minimal amount of time for which this
/// agent's velocities that are computed by the
@@ -217,59 +222,67 @@ public:
/// agent has in choosing its velocities.
/// Must be positive.
- virtual void agent_set_time_horizon_agents(RID p_agent, real_t p_time_horizon);
- virtual void agent_set_time_horizon_obstacles(RID p_agent, real_t p_time_horizon);
+ virtual void agent_set_time_horizon_agents(RID p_agent, real_t p_time_horizon) = 0;
+ virtual void agent_set_time_horizon_obstacles(RID p_agent, real_t p_time_horizon) = 0;
/// The radius of this agent.
/// Must be non-negative.
- virtual void agent_set_radius(RID p_agent, real_t p_radius);
+ virtual void agent_set_radius(RID p_agent, real_t p_radius) = 0;
/// The maximum speed of this agent.
/// Must be non-negative.
- virtual void agent_set_max_speed(RID p_agent, real_t p_max_speed);
+ virtual void agent_set_max_speed(RID p_agent, real_t p_max_speed) = 0;
/// forces and agent velocity change in the avoidance simulation, adds simulation instability if done recklessly
- virtual void agent_set_velocity_forced(RID p_agent, Vector2 p_velocity);
+ virtual void agent_set_velocity_forced(RID p_agent, Vector2 p_velocity) = 0;
/// The wanted velocity for the agent as a "suggestion" to the avoidance simulation.
/// The simulation will try to fulfill this velocity wish if possible but may change the velocity depending on other agent's and obstacles'.
- virtual void agent_set_velocity(RID p_agent, Vector2 p_velocity);
+ virtual void agent_set_velocity(RID p_agent, Vector2 p_velocity) = 0;
/// Position of the agent in world space.
- virtual void agent_set_position(RID p_agent, Vector2 p_position);
+ virtual void agent_set_position(RID p_agent, Vector2 p_position) = 0;
/// Returns true if the map got changed the previous frame.
- virtual bool agent_is_map_changed(RID p_agent) const;
+ virtual bool agent_is_map_changed(RID p_agent) const = 0;
/// Callback called at the end of the RVO process
- virtual void agent_set_avoidance_callback(RID p_agent, Callable p_callback);
+ virtual void agent_set_avoidance_callback(RID p_agent, Callable p_callback) = 0;
- virtual void agent_set_avoidance_layers(RID p_agent, uint32_t p_layers);
- virtual void agent_set_avoidance_mask(RID p_agent, uint32_t p_mask);
- virtual void agent_set_avoidance_priority(RID p_agent, real_t p_priority);
+ virtual void agent_set_avoidance_layers(RID p_agent, uint32_t p_layers) = 0;
+ virtual void agent_set_avoidance_mask(RID p_agent, uint32_t p_mask) = 0;
+ virtual void agent_set_avoidance_priority(RID p_agent, real_t p_priority) = 0;
/// Creates the obstacle.
- virtual RID obstacle_create();
- virtual void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled);
- virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const;
- virtual void obstacle_set_map(RID p_obstacle, RID p_map);
- virtual RID obstacle_get_map(RID p_obstacle) const;
- virtual void obstacle_set_paused(RID p_obstacle, bool p_paused);
- virtual bool obstacle_get_paused(RID p_obstacle) const;
- virtual void obstacle_set_radius(RID p_obstacle, real_t p_radius);
- virtual void obstacle_set_velocity(RID p_obstacle, Vector2 p_velocity);
- virtual void obstacle_set_position(RID p_obstacle, Vector2 p_position);
- virtual void obstacle_set_vertices(RID p_obstacle, const Vector &p_vertices);
- virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers);
+ virtual RID obstacle_create() = 0;
+ virtual void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled) = 0;
+ virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const = 0;
+ virtual void obstacle_set_map(RID p_obstacle, RID p_map) = 0;
+ virtual RID obstacle_get_map(RID p_obstacle) const = 0;
+ virtual void obstacle_set_paused(RID p_obstacle, bool p_paused) = 0;
+ virtual bool obstacle_get_paused(RID p_obstacle) const = 0;
+ virtual void obstacle_set_radius(RID p_obstacle, real_t p_radius) = 0;
+ virtual void obstacle_set_velocity(RID p_obstacle, Vector2 p_velocity) = 0;
+ virtual void obstacle_set_position(RID p_obstacle, Vector2 p_position) = 0;
+ virtual void obstacle_set_vertices(RID p_obstacle, const Vector &p_vertices) = 0;
+ virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) = 0;
/// Returns a customized navigation path using a query parameters object
- virtual void query_path(const Ref &p_query_parameters, Ref p_query_result) const;
+ virtual void query_path(const Ref &p_query_parameters, Ref p_query_result) const = 0;
+
+ virtual void init() = 0;
+ virtual void sync() = 0;
+ virtual void finish() = 0;
/// Destroy the `RID`
- virtual void free(RID p_object);
+ virtual void free(RID p_object) = 0;
+
+ virtual 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()) = 0;
+ virtual void bake_from_source_geometry_data(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, const Callable &p_callback = Callable()) = 0;
+ virtual void bake_from_source_geometry_data_async(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, const Callable &p_callback = Callable()) = 0;
NavigationServer2D();
- virtual ~NavigationServer2D();
+ ~NavigationServer2D() override;
void set_debug_enabled(bool p_enabled);
bool get_debug_enabled() const;
@@ -354,4 +367,15 @@ private:
#endif // DEBUG_ENABLED
};
+typedef NavigationServer2D *(*NavigationServer2DCallback)();
+
+/// Manager used for the server singleton registration
+class NavigationServer2DManager {
+ static NavigationServer2DCallback create_callback;
+
+public:
+ static void set_default_server(NavigationServer2DCallback p_callback);
+ static NavigationServer2D *new_default_server();
+};
+
#endif // NAVIGATION_SERVER_2D_H
diff --git a/servers/navigation_server_2d_dummy.h b/servers/navigation_server_2d_dummy.h
new file mode 100644
index 00000000000..d64a9454aac
--- /dev/null
+++ b/servers/navigation_server_2d_dummy.h
@@ -0,0 +1,155 @@
+/**************************************************************************/
+/* navigation_server_2d_dummy.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef NAVIGATION_SERVER_2D_DUMMY_H
+#define NAVIGATION_SERVER_2D_DUMMY_H
+
+#include "servers/navigation_server_2d.h"
+
+class NavigationServer2DDummy : public NavigationServer2D {
+ GDCLASS(NavigationServer2DDummy, NavigationServer2D);
+
+public:
+ TypedArray get_maps() const override { return TypedArray(); }
+
+ RID map_create() override { return RID(); }
+ void map_set_active(RID p_map, bool p_active) override {}
+ bool map_is_active(RID p_map) const override { return false; }
+ void map_set_cell_size(RID p_map, real_t p_cell_size) override {}
+ real_t map_get_cell_size(RID p_map) const override { return 0; }
+ void map_set_use_edge_connections(RID p_map, bool p_enabled) override {}
+ bool map_get_use_edge_connections(RID p_map) const override { return false; }
+ void map_set_edge_connection_margin(RID p_map, real_t p_connection_margin) override {}
+ real_t map_get_edge_connection_margin(RID p_map) const override { return 0; }
+ void map_set_link_connection_radius(RID p_map, real_t p_connection_radius) override {}
+ real_t map_get_link_connection_radius(RID p_map) const override { return 0; }
+ Vector map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) const override { return Vector(); }
+ Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const override { return Vector2(); }
+ RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const override { return RID(); }
+ TypedArray map_get_links(RID p_map) const override { return TypedArray]