From debee6487d914aa3e709b1694b97eabf52868d7d Mon Sep 17 00:00:00 2001 From: Josh Jones Date: Sun, 20 Nov 2022 23:35:20 -0800 Subject: [PATCH] Expose NavigationServer3D to GDExtension --- doc/classes/@GlobalScope.xml | 3 + doc/classes/NavigationServer3DExtension.xml | 583 ++++++++++++++++++ doc/classes/NavigationServer3DManager.xml | 30 + doc/classes/ProjectSettings.xml | 4 + main/main.cpp | 25 +- modules/mono/editor/bindings_generator.cpp | 2 +- modules/navigation/register_types.cpp | 3 +- .../navigation_server_3d_extension.cpp | 113 ++++ .../navigation_server_3d_extension.h | 138 +++++ servers/navigation/navigation_utilities.h | 4 +- servers/navigation_server_3d.cpp | 83 ++- servers/navigation_server_3d.h | 37 +- servers/register_server_types.cpp | 12 + tests/test_main.cpp | 2 +- 14 files changed, 1017 insertions(+), 22 deletions(-) create mode 100644 doc/classes/NavigationServer3DExtension.xml create mode 100644 doc/classes/NavigationServer3DManager.xml create mode 100644 servers/extensions/navigation_server_3d_extension.cpp create mode 100644 servers/extensions/navigation_server_3d_extension.h 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);