diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index ed7bdc07fcf3..9883793c85b7 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1505,6 +1505,9 @@
The [NavigationServer2D] singleton.
+
+ The [NavigationServer3DManager] singleton.
+
The [OS] singleton.
diff --git a/doc/classes/NavigationServer3DExtension.xml b/doc/classes/NavigationServer3DExtension.xml
new file mode 100644
index 000000000000..0a78772a8df8
--- /dev/null
+++ b/doc/classes/NavigationServer3DExtension.xml
@@ -0,0 +1,583 @@
+
+
+
+ Enables GDExtension libraries to provide their own implementation of [NavigationServer3D].
+
+
+ To create your own implementation, derive from [NavigationServer3DExtension] and implement all of the virtual methods listed here.
+ Then, register your implementation with [method NavigationServer3DManager.register_server] and optionally mark it as the default with [method NavigationServer3DManager.set_default_server].
+ Make sure to register your implementation at the [constant GDExtension.INITIALIZATION_LEVEL_SERVERS] initialization level.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_create]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_get_map]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_is_map_changed]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_set_callback]. Required.
+
+
+
+
+
+
+
+ Invoked to disable movement along the Y axis for agents. Used primarily by [NavigationServer2D] to limit its agents to a 2D plane. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_set_map]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_set_max_neighbors]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_set_max_speed]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_set_neighbor_distance]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_set_position]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_set_radius]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_set_target_velocity]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_set_time_horizon]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.agent_set_velocity]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.free_rid]. Required.
+
+
+
+
+
+ Override to implement [method NavigationServer3D.get_maps]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.get_process_info]. Required.
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_create]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_get_end_position]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_get_enter_cost]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_get_map]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_get_navigation_layers]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_get_owner_id]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_get_start_position]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_get_travel_cost]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_is_bidirectional]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_set_bidirectional]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_set_end_position]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_set_enter_cost]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_set_map]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_set_navigation_layers]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_set_owner_id]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_set_start_position]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.link_set_travel_cost]. Required.
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_create]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_force_update]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_agents]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_cell_size]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_closest_point]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_closest_point_normal]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_closest_point_owner]. Required.
+
+
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_closest_point_to_segment]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_edge_connection_margin]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_link_connection_radius]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_links]. Required.
+
+
+
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_path]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_regions]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_get_up]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_is_active]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_set_active]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_set_cell_size]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_set_edge_connection_margin]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_set_link_connection_radius]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.map_set_up]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.process]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.query_path]. Required.
+ You are responsible for filling in the given [param result] with the results of the path finding operation.
+ This class will take care of creating the required structs for you.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_bake_navigation_mesh]. Required.
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_create]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_get_connection_pathway_end]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_get_connection_pathway_start]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_get_connections_count]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_get_enter_cost]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_get_map]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_get_navigation_layers]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_get_owner_id]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_get_travel_cost]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_owns_point]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_set_enter_cost]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_set_map]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_set_navigation_layers]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_set_navigation_mesh]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_set_owner_id]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_set_transform]. Required.
+
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.region_set_travel_cost]. Required.
+
+
+
+
+
+
+ Override to implement [method NavigationServer3D.set_active]. Required.
+
+
+
+
diff --git a/doc/classes/NavigationServer3DManager.xml b/doc/classes/NavigationServer3DManager.xml
new file mode 100644
index 000000000000..82a3e7364858
--- /dev/null
+++ b/doc/classes/NavigationServer3DManager.xml
@@ -0,0 +1,30 @@
+
+
+
+ Manager for 3D navigation server implementations.
+
+
+ [NavigationServer3DManager] is the API for registering [NavigationServer3D] implementations and for setting the default implementation.
+ [b]Note:[/b] It is not possible to switch navigation servers at runtime. This class is only used on startup at the server initialization level, by Godot itself and possibly by GDExtensions.
+
+
+
+
+
+
+
+
+
+ Register a [NavigationServer3D] implementation by passing a [param name] and a [Callable] that returns a [NavigationServer3D] instance.
+
+
+
+
+
+
+
+ Set the default [NavigationServer3D] implementation to the one identified by [param name] if [param priority] is greater than the priority of the current default implementation.
+
+
+
+
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 3177780a2686..0fbd0be980ab 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1729,6 +1729,10 @@
Default link connection radius for 3D navigation maps. See [method NavigationServer3D.map_set_link_connection_radius].
+
+ Sets which navigation server implementation to use.
+ "DEFAULT" is usually the same as "GodotNavigation3D" unless another module or extension overrides it.
+
Maximum number of characters allowed to send as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection.
diff --git a/main/main.cpp b/main/main.cpp
index 5bb37df3ca21..084bfd4fbd39 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -138,6 +138,7 @@ static PhysicsServer3DManager *physics_server_3d_manager = nullptr;
static PhysicsServer3D *physics_server_3d = nullptr;
static PhysicsServer2DManager *physics_server_2d_manager = nullptr;
static PhysicsServer2D *physics_server_2d = nullptr;
+static NavigationServer3DManager *navigation_server_3d_manager = nullptr;
static NavigationServer3D *navigation_server_3d = nullptr;
static NavigationServer2D *navigation_server_2d = nullptr;
static ThemeDB *theme_db = nullptr;
@@ -283,18 +284,22 @@ void finalize_display() {
}
void initialize_navigation_server() {
- ERR_FAIL_COND(navigation_server_3d != nullptr);
+ // Init chosen 3D Navigation Server
+ const String &server_name = GLOBAL_GET(NavigationServer3DManager::setting_property_name);
+ navigation_server_3d = NavigationServer3DManager::get_singleton()->new_server(server_name);
- // Init 3D Navigation Server
- navigation_server_3d = NavigationServer3DManager::new_default_server();
+ // Fall back to default if not found
+ if (!navigation_server_3d) {
+ // Navigation server not found, so use the default.
+ navigation_server_3d = NavigationServer3DManager::get_singleton()->new_default_server();
+ }
// Fall back to dummy if no default server has been registered.
if (!navigation_server_3d) {
- WARN_PRINT_ONCE("No NavigationServer3D implementation has been registered! Falling back to a dummy implementation: navigation features will be unavailable.");
+ ERR_PRINT("No NavigationServer3D implementation has been registered! Falling back to a dummy implementation: navigation features will be unavailable.");
navigation_server_3d = memnew(NavigationServer3DDummy);
}
- // Should be impossible, but make sure it's not null.
ERR_FAIL_NULL_MSG(navigation_server_3d, "Failed to initialize NavigationServer3D.");
// Init 2D Navigation Server
@@ -492,6 +497,8 @@ Error Main::test_setup() {
physics_server_3d_manager = memnew(PhysicsServer3DManager);
physics_server_2d_manager = memnew(PhysicsServer2DManager);
+ navigation_server_3d_manager = memnew(NavigationServer3DManager);
+
// From `Main::setup2()`.
initialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);
register_core_extensions();
@@ -605,6 +612,9 @@ void Main::test_cleanup() {
if (tsman) {
memdelete(tsman);
}
+ if (navigation_server_3d_manager) {
+ memdelete(navigation_server_3d_manager);
+ }
if (physics_server_3d_manager) {
memdelete(physics_server_3d_manager);
}
@@ -1949,6 +1959,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
physics_server_3d_manager = memnew(PhysicsServer3DManager);
physics_server_2d_manager = memnew(PhysicsServer2DManager);
+ navigation_server_3d_manager = memnew(NavigationServer3DManager);
+
register_server_types();
initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);
@@ -3384,6 +3396,9 @@ void Main::cleanup(bool p_force) {
if (tsman) {
memdelete(tsman);
}
+ if (navigation_server_3d_manager) {
+ memdelete(navigation_server_3d_manager);
+ }
if (physics_server_3d_manager) {
memdelete(physics_server_3d_manager);
}
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index ad6306bb41b2..458aae3dd397 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -115,7 +115,7 @@ StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) {
#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL ".ConvertSignalToManaged"
// Types that will be ignored by the generator and won't be available in C#.
-const Vector ignored_types = { "PhysicsServer2DExtension", "PhysicsServer3DExtension" };
+const Vector ignored_types = { "PhysicsServer2DExtension", "PhysicsServer3DExtension", "NavigationServer3DExtension" };
void BindingsGenerator::TypeInterface::postsetup_enum_type(BindingsGenerator::TypeInterface &r_enum_itype) {
// C interface for enums is the same as that of 'uint32_t'. Remember to apply
diff --git a/modules/navigation/register_types.cpp b/modules/navigation/register_types.cpp
index 6ba5e90c2ea6..ac50fdb53468 100644
--- a/modules/navigation/register_types.cpp
+++ b/modules/navigation/register_types.cpp
@@ -53,7 +53,8 @@ NavigationServer3D *new_server() {
void initialize_navigation_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
- NavigationServer3DManager::set_default_server(new_server);
+ NavigationServer3DManager::get_singleton()->register_server("GodotNavigation3D", callable_mp_static(new_server));
+ NavigationServer3DManager::get_singleton()->set_default_server("GodotNavigation3D");
#ifndef _3D_DISABLED
_nav_mesh_generator = memnew(NavigationMeshGenerator);
diff --git a/servers/extensions/navigation_server_3d_extension.cpp b/servers/extensions/navigation_server_3d_extension.cpp
new file mode 100644
index 000000000000..8e6c53f33a37
--- /dev/null
+++ b/servers/extensions/navigation_server_3d_extension.cpp
@@ -0,0 +1,113 @@
+/**************************************************************************/
+/* navigation_server_3d_extension.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_server_3d_extension.h"
+
+void NavigationServer3DExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_maps)
+ GDVIRTUAL_BIND(_map_create)
+ GDVIRTUAL_BIND(_map_set_active, "map", "active")
+ GDVIRTUAL_BIND(_map_is_active, "map")
+ GDVIRTUAL_BIND(_map_set_up, "map", "up")
+ GDVIRTUAL_BIND(_map_get_up, "map")
+ GDVIRTUAL_BIND(_map_set_cell_size, "map", "cell_size")
+ GDVIRTUAL_BIND(_map_get_cell_size, "map")
+ GDVIRTUAL_BIND(_map_set_edge_connection_margin, "map", "margin")
+ GDVIRTUAL_BIND(_map_get_edge_connection_margin, "map")
+ GDVIRTUAL_BIND(_map_set_link_connection_radius, "map", "radius")
+ GDVIRTUAL_BIND(_map_get_link_connection_radius, "map")
+ GDVIRTUAL_BIND(_map_get_path, "map", "origin", "destination", "optimize", "navigation_layers")
+ GDVIRTUAL_BIND(_map_get_closest_point_to_segment, "map", "start", "end", "use_collision")
+ GDVIRTUAL_BIND(_map_get_closest_point, "map", "to_point")
+ GDVIRTUAL_BIND(_map_get_closest_point_normal, "map", "to_point")
+ GDVIRTUAL_BIND(_map_get_closest_point_owner, "map", "to_point")
+ GDVIRTUAL_BIND(_map_get_links, "map")
+ GDVIRTUAL_BIND(_map_get_regions, "map")
+ GDVIRTUAL_BIND(_map_get_agents, "map")
+ GDVIRTUAL_BIND(_map_force_update, "map")
+ GDVIRTUAL_BIND(_query_path_extension, "parameters", "result")
+
+ GDVIRTUAL_BIND(_region_create)
+ GDVIRTUAL_BIND(_region_set_enter_cost, "region", "enter_cost")
+ GDVIRTUAL_BIND(_region_get_enter_cost, "region")
+ GDVIRTUAL_BIND(_region_set_travel_cost, "region", "travel_cost")
+ GDVIRTUAL_BIND(_region_get_travel_cost, "region")
+ GDVIRTUAL_BIND(_region_set_owner_id, "region", "owner_id")
+ GDVIRTUAL_BIND(_region_get_owner_id, "region")
+ GDVIRTUAL_BIND(_region_owns_point, "region", "point")
+ GDVIRTUAL_BIND(_region_set_map, "region", "map")
+ GDVIRTUAL_BIND(_region_get_map, "region")
+ GDVIRTUAL_BIND(_region_set_navigation_layers, "region", "navigation_layers")
+ GDVIRTUAL_BIND(_region_get_navigation_layers, "region")
+ GDVIRTUAL_BIND(_region_set_transform, "region", "transform")
+ GDVIRTUAL_BIND(_region_set_navigation_mesh, "region", "navigation_mesh")
+ GDVIRTUAL_BIND(_region_bake_navigation_mesh, "navigation_mesh", "root_node")
+ GDVIRTUAL_BIND(_region_get_connections_count, "region")
+ GDVIRTUAL_BIND(_region_get_connection_pathway_start, "region", "connection")
+ GDVIRTUAL_BIND(_region_get_connection_pathway_end, "region", "connection")
+
+ GDVIRTUAL_BIND(_link_create)
+ GDVIRTUAL_BIND(_link_set_map, "link", "map")
+ GDVIRTUAL_BIND(_link_get_map, "link")
+ GDVIRTUAL_BIND(_link_set_bidirectional, "link", "bidirectional")
+ GDVIRTUAL_BIND(_link_is_bidirectional, "link")
+ GDVIRTUAL_BIND(_link_set_navigation_layers, "link", "navigation_layers")
+ GDVIRTUAL_BIND(_link_get_navigation_layers, "link")
+ GDVIRTUAL_BIND(_link_set_start_position, "link", "position")
+ GDVIRTUAL_BIND(_link_get_start_position, "link")
+ GDVIRTUAL_BIND(_link_set_end_position, "link", "position")
+ GDVIRTUAL_BIND(_link_get_end_position, "link")
+ GDVIRTUAL_BIND(_link_set_enter_cost, "link", "enter_cost")
+ GDVIRTUAL_BIND(_link_get_enter_cost, "link")
+ GDVIRTUAL_BIND(_link_set_travel_cost, "link", "travel_cost")
+ GDVIRTUAL_BIND(_link_get_travel_cost, "link")
+ GDVIRTUAL_BIND(_link_set_owner_id, "link", "owner_id")
+ GDVIRTUAL_BIND(_link_get_owner_id, "link")
+
+ GDVIRTUAL_BIND(_agent_create)
+ GDVIRTUAL_BIND(_agent_set_map, "agent", "map")
+ GDVIRTUAL_BIND(_agent_get_map, "agent")
+ GDVIRTUAL_BIND(_agent_set_neighbor_distance, "agent", "distance")
+ GDVIRTUAL_BIND(_agent_set_max_neighbors, "agent", "count")
+ GDVIRTUAL_BIND(_agent_set_time_horizon, "agent", "time")
+ GDVIRTUAL_BIND(_agent_set_radius, "agent", "radius")
+ GDVIRTUAL_BIND(_agent_set_max_speed, "agent", "max_speed")
+ GDVIRTUAL_BIND(_agent_set_velocity, "agent", "velocity")
+ GDVIRTUAL_BIND(_agent_set_target_velocity, "agent", "target_velocity")
+ GDVIRTUAL_BIND(_agent_set_position, "agent", "position")
+ GDVIRTUAL_BIND(_agent_set_ignore_y, "agent", "ignore_y")
+ GDVIRTUAL_BIND(_agent_is_map_changed, "agent")
+ GDVIRTUAL_BIND(_agent_set_callback, "agent", "callback")
+
+ GDVIRTUAL_BIND(_free, "rid")
+ GDVIRTUAL_BIND(_set_active, "active")
+ GDVIRTUAL_BIND(_process, "delta_time")
+ GDVIRTUAL_BIND(_get_process_info, "info")
+}
diff --git a/servers/extensions/navigation_server_3d_extension.h b/servers/extensions/navigation_server_3d_extension.h
new file mode 100644
index 000000000000..ff22056f6880
--- /dev/null
+++ b/servers/extensions/navigation_server_3d_extension.h
@@ -0,0 +1,138 @@
+/**************************************************************************/
+/* navigation_server_3d_extension.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_3D_EXTENSION_H
+#define NAVIGATION_SERVER_3D_EXTENSION_H
+
+#include "core/extension/ext_wrappers.gen.inc"
+#include "core/object/script_language.h"
+#include "core/variant/native_ptr.h"
+#include "servers/navigation_server_3d.h"
+
+typedef NavigationUtilities::PathQueryParameters NavigationServer3DExtensionPathQueryParameters;
+typedef NavigationUtilities::PathQueryResult NavigationServer3DExtensionPathQueryResult;
+
+GDVIRTUAL_NATIVE_PTR(NavigationServer3DExtensionPathQueryParameters)
+GDVIRTUAL_NATIVE_PTR(NavigationServer3DExtensionPathQueryResult)
+
+class NavigationServer3DExtension : public NavigationServer3D {
+ GDCLASS(NavigationServer3DExtension, NavigationServer3D)
+
+protected:
+ static void _bind_methods();
+
+public:
+ EXBIND0RC(TypedArray, get_maps)
+ EXBIND0R(RID, map_create)
+ EXBIND2(map_set_active, RID, bool)
+ EXBIND1RC(bool, map_is_active, RID)
+ EXBIND2(map_set_up, RID, Vector3)
+ EXBIND1RC(Vector3, map_get_up, RID)
+ EXBIND2(map_set_cell_size, RID, real_t)
+ EXBIND1RC(real_t, map_get_cell_size, RID)
+ EXBIND2(map_set_edge_connection_margin, RID, real_t)
+ EXBIND1RC(real_t, map_get_edge_connection_margin, RID)
+ EXBIND2(map_set_link_connection_radius, RID, real_t)
+ EXBIND1RC(real_t, map_get_link_connection_radius, RID)
+ EXBIND5RC(Vector, map_get_path, RID, Vector3, Vector3, bool, uint32_t)
+ EXBIND4RC(Vector3, map_get_closest_point_to_segment, RID, const Vector3 &, const Vector3 &, bool)
+ EXBIND2RC(Vector3, map_get_closest_point, RID, const Vector3 &)
+ EXBIND2RC(Vector3, map_get_closest_point_normal, RID, const Vector3 &)
+ EXBIND2RC(RID, map_get_closest_point_owner, RID, const Vector3 &)
+ EXBIND1RC(TypedArray, map_get_links, RID)
+ EXBIND1RC(TypedArray, map_get_regions, RID)
+ EXBIND1RC(TypedArray, map_get_agents, RID)
+ EXBIND1(map_force_update, RID)
+ EXBIND0R(RID, region_create)
+ EXBIND2(region_set_enter_cost, RID, real_t)
+ EXBIND1RC(real_t, region_get_enter_cost, RID)
+ EXBIND2(region_set_travel_cost, RID, real_t)
+ EXBIND1RC(real_t, region_get_travel_cost, RID)
+ EXBIND2(region_set_owner_id, RID, ObjectID)
+ EXBIND1RC(ObjectID, region_get_owner_id, RID)
+ EXBIND2RC(bool, region_owns_point, RID, const Vector3 &)
+ EXBIND2(region_set_map, RID, RID)
+ EXBIND1RC(RID, region_get_map, RID)
+ EXBIND2(region_set_navigation_layers, RID, uint32_t)
+ EXBIND1RC(uint32_t, region_get_navigation_layers, RID)
+ EXBIND2(region_set_transform, RID, Transform3D)
+ EXBIND2(region_set_navigation_mesh, RID, Ref)
+ EXBIND2(region_bake_navigation_mesh, Ref, Node *)
+ EXBIND1RC(int, region_get_connections_count, RID)
+ EXBIND2RC(Vector3, region_get_connection_pathway_start, RID, int)
+ EXBIND2RC(Vector3, region_get_connection_pathway_end, RID, int)
+ EXBIND0R(RID, link_create)
+ EXBIND2(link_set_map, RID, RID)
+ EXBIND1RC(RID, link_get_map, RID)
+ EXBIND2(link_set_bidirectional, RID, bool)
+ EXBIND1RC(bool, link_is_bidirectional, RID)
+ EXBIND2(link_set_navigation_layers, RID, uint32_t)
+ EXBIND1RC(uint32_t, link_get_navigation_layers, RID)
+ EXBIND2(link_set_start_position, RID, Vector3)
+ EXBIND1RC(Vector3, link_get_start_position, RID)
+ EXBIND2(link_set_end_position, RID, Vector3)
+ EXBIND1RC(Vector3, link_get_end_position, RID)
+ EXBIND2(link_set_enter_cost, RID, real_t)
+ EXBIND1RC(real_t, link_get_enter_cost, RID)
+ EXBIND2(link_set_travel_cost, RID, real_t)
+ EXBIND1RC(real_t, link_get_travel_cost, RID)
+ EXBIND2(link_set_owner_id, RID, ObjectID)
+ EXBIND1RC(ObjectID, link_get_owner_id, RID)
+ EXBIND0R(RID, agent_create)
+ EXBIND2(agent_set_map, RID, RID)
+ EXBIND1RC(RID, agent_get_map, RID)
+ EXBIND2(agent_set_neighbor_distance, RID, real_t)
+ EXBIND2(agent_set_max_neighbors, RID, int)
+ EXBIND2(agent_set_time_horizon, RID, real_t)
+ EXBIND2(agent_set_radius, RID, real_t)
+ EXBIND2(agent_set_max_speed, RID, real_t)
+ EXBIND2(agent_set_velocity, RID, Vector3)
+ EXBIND2(agent_set_target_velocity, RID, Vector3)
+ EXBIND2(agent_set_position, RID, Vector3)
+ EXBIND2(agent_set_ignore_y, RID, bool)
+ EXBIND1RC(bool, agent_is_map_changed, RID)
+ EXBIND2(agent_set_callback, RID, Callable)
+ EXBIND1(free, RID)
+ EXBIND1(set_active, bool)
+ EXBIND1(process, real_t)
+ EXBIND1RC(int, get_process_info, ProcessInfo)
+
+ GDVIRTUAL2C(_query_path_extension, GDExtensionConstPtr, GDExtensionPtr)
+
+ NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const override {
+ NavigationUtilities::PathQueryResult res;
+
+ GDVIRTUAL_REQUIRED_CALL(_query_path_extension, &p_parameters, &res);
+
+ return res;
+ }
+};
+
+#endif // NAVIGATION_SERVER_3D_EXTENSION_H
diff --git a/servers/navigation/navigation_utilities.h b/servers/navigation/navigation_utilities.h
index 04d0ab0d98c2..c0672f7edc2c 100644
--- a/servers/navigation/navigation_utilities.h
+++ b/servers/navigation/navigation_utilities.h
@@ -36,11 +36,11 @@
namespace NavigationUtilities {
-enum PathfindingAlgorithm {
+enum PathfindingAlgorithm : int32_t {
PATHFINDING_ALGORITHM_ASTAR = 0,
};
-enum PathPostProcessing {
+enum PathPostProcessing : int32_t {
PATH_POSTPROCESSING_CORRIDORFUNNEL = 0,
PATH_POSTPROCESSING_EDGECENTERED,
};
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index e5cc426708e9..c9b40e53a5b8 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -600,16 +600,87 @@ void NavigationServer3D::query_path(const Ref &
///////////////////////////////////////////////////////
-NavigationServer3DCallback NavigationServer3DManager::create_callback = nullptr;
+NavigationServer3DManager *NavigationServer3DManager::singleton = nullptr;
+const String NavigationServer3DManager::setting_property_name(PNAME("navigation/3d/navigation_server"));
-void NavigationServer3DManager::set_default_server(NavigationServer3DCallback p_callback) {
- create_callback = p_callback;
+void NavigationServer3DManager::on_servers_changed() {
+ String nav_server_names("DEFAULT");
+ for (const ClassInfo &server : navigation_servers) {
+ nav_server_names += "," + server.name;
+ }
+
+ ProjectSettings::get_singleton()->set_custom_property_info(PropertyInfo(Variant::STRING, setting_property_name, PROPERTY_HINT_ENUM, nav_server_names));
+}
+
+void NavigationServer3DManager::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("register_server", "name", "create_callback"), &NavigationServer3DManager::register_server);
+ ClassDB::bind_method(D_METHOD("set_default_server", "name", "priority"), &NavigationServer3DManager::set_default_server);
+}
+
+NavigationServer3DManager *NavigationServer3DManager::get_singleton() {
+ return singleton;
+}
+
+void NavigationServer3DManager::register_server(const String &p_name, const Callable &p_create_callback) {
+ // TODO: Enable check when is_valid() is fixed for static functions.
+ //ERR_FAIL_COND(!p_create_callback.is_valid());
+ ERR_FAIL_COND_MSG(find_server_id(p_name) != -1, "Navigation server not found");
+
+ navigation_servers.push_back(ClassInfo{ p_name, p_create_callback });
+ on_servers_changed();
+}
+
+void NavigationServer3DManager::set_default_server(const String &p_name, int p_priority) {
+ const int id = find_server_id(p_name);
+ ERR_FAIL_COND_MSG(id == -1, "Navigation server not found"); // Not found
+
+ // Only change the server if it is registered with a higher priority
+ if (default_server_priority < p_priority) {
+ default_server_id = id;
+ default_server_priority = p_priority;
+ }
+}
+
+int NavigationServer3DManager::find_server_id(const String &p_name) const {
+ for (int i = 0; i < navigation_servers.size(); ++i) {
+ if (p_name == navigation_servers[i].name) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+NavigationServer3D *NavigationServer3DManager::new_default_server() const {
+ ERR_FAIL_COND_V(default_server_id == -1, nullptr);
+
+ Variant ret;
+ Callable::CallError ce;
+ navigation_servers[default_server_id].create_callback.callp(nullptr, 0, ret, ce);
+
+ ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
+ return Object::cast_to(ret.get_validated_object());
}
-NavigationServer3D *NavigationServer3DManager::new_default_server() {
- if (create_callback == nullptr) {
+NavigationServer3D *NavigationServer3DManager::new_server(const String &p_name) const {
+ const int id = find_server_id(p_name);
+
+ if (id == -1) {
return nullptr;
}
- return create_callback();
+ Variant ret;
+ Callable::CallError ce;
+ navigation_servers[id].create_callback.callp(nullptr, 0, ret, ce);
+
+ ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
+ return Object::cast_to(ret.get_validated_object());
+}
+
+NavigationServer3DManager::NavigationServer3DManager() {
+ singleton = this;
+}
+
+NavigationServer3DManager::~NavigationServer3DManager() {
+ singleton = nullptr;
}
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index 05df5ca0fe51..89e8c6ffaa78 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -384,15 +384,40 @@ class NavigationServer3D : public Object {
#endif // DEBUG_ENABLED
};
-typedef NavigationServer3D *(*NavigationServer3DCallback)();
-
/// Manager used for the server singleton registration
-class NavigationServer3DManager {
- static NavigationServer3DCallback create_callback;
+class NavigationServer3DManager : public Object {
+ GDCLASS(NavigationServer3DManager, Object);
+
+ static NavigationServer3DManager *singleton;
+
+ struct ClassInfo {
+ String name;
+ Callable create_callback;
+ };
+
+ Vector navigation_servers;
+ int default_server_id = -1;
+ int default_server_priority = -1;
+
+ void on_servers_changed();
+
+protected:
+ static void _bind_methods();
public:
- static void set_default_server(NavigationServer3DCallback p_callback);
- static NavigationServer3D *new_default_server();
+ static const String setting_property_name;
+
+ static NavigationServer3DManager *get_singleton();
+
+ void register_server(const String &p_name, const Callable &p_create_callback);
+ void set_default_server(const String &p_name, int p_priority = 0);
+ int find_server_id(const String &p_name) const;
+
+ NavigationServer3D *new_default_server() const;
+ NavigationServer3D *new_server(const String &p_name) const;
+
+ NavigationServer3DManager();
+ ~NavigationServer3DManager() override;
};
VARIANT_ENUM_CAST(NavigationServer3D::ProcessInfo);
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index 8cc2cc075602..8514dd70602a 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -72,6 +72,7 @@
#include "rendering/rendering_device.h"
#include "rendering/rendering_device_binds.h"
#include "rendering_server.h"
+#include "servers/extensions/navigation_server_3d_extension.h"
#include "servers/extensions/physics_server_2d_extension.h"
#include "servers/extensions/physics_server_3d_extension.h"
#include "servers/rendering/shader_types.h"
@@ -161,13 +162,20 @@ void register_server_types() {
GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionMotionCollision, "Vector3 position;Vector3 normal;Vector3 collider_velocity;real_t depth;int local_shape;ObjectID collider_id;RID collider;int collider_shape");
GDREGISTER_NATIVE_STRUCT(PhysicsServer3DExtensionMotionResult, "Vector3 travel;Vector3 remainder;real_t collision_safe_fraction;real_t collision_unsafe_fraction;PhysicsServer3DExtensionMotionCollision collisions[32];int collision_count");
+ GDREGISTER_CLASS(NavigationServer3DManager);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3DManager", NavigationServer3DManager::get_singleton(), "NavigationServer3DManager"));
+
GDREGISTER_ABSTRACT_CLASS(NavigationServer2D);
GDREGISTER_ABSTRACT_CLASS(NavigationServer3D);
+ GDREGISTER_VIRTUAL_CLASS(NavigationServer3DExtension);
GDREGISTER_CLASS(NavigationPathQueryParameters2D);
GDREGISTER_CLASS(NavigationPathQueryParameters3D);
GDREGISTER_CLASS(NavigationPathQueryResult2D);
GDREGISTER_CLASS(NavigationPathQueryResult3D);
+ GDREGISTER_NATIVE_STRUCT(NavigationServer3DExtensionPathQueryParameters, "int32_t pathfinding_algorithm;int32_t path_postprocessing;RID map;Vector3 start_position;Vector3 target_position;uint32_t navigation_layers;int64_t metadata_flags");
+ GDREGISTER_NATIVE_STRUCT(NavigationServer3DExtensionPathQueryResult, "PackedVector3Array path;PackedInt32Array path_types;Array path_rids;PackedInt64Array path_owner_ids");
+
GDREGISTER_CLASS(XRServer);
GDREGISTER_CLASS(CameraServer);
@@ -281,6 +289,10 @@ void register_server_types() {
PhysicsServer3DManager::get_singleton()->register_server("GodotPhysics3D", callable_mp_static(_createGodotPhysics3DCallback));
PhysicsServer3DManager::get_singleton()->set_default_server("GodotPhysics3D");
+ // Navigation 3D
+ GLOBAL_DEF(NavigationServer3DManager::setting_property_name, "DEFAULT");
+ ProjectSettings::get_singleton()->set_custom_property_info(PropertyInfo(Variant::STRING, NavigationServer3DManager::setting_property_name, PROPERTY_HINT_ENUM, "DEFAULT"));
+
writer_mjpeg = memnew(MovieWriterMJPEG);
MovieWriter::add_writer(writer_mjpeg);
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index e029ea719048..4027ff731d00 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -223,7 +223,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server();
physics_server_2d->init();
- navigation_server_3d = NavigationServer3DManager::new_default_server();
+ navigation_server_3d = NavigationServer3DManager::get_singleton()->new_default_server();
navigation_server_2d = memnew(NavigationServer2D);
memnew(InputMap);