From 2e0589f63aa472fa87fd27dc4856dd3fddfc9d19 Mon Sep 17 00:00:00 2001 From: Relintai Date: Fri, 29 Jul 2022 10:34:10 +0200 Subject: [PATCH] Ported: [3.5] Add NavigationAgent2D/3D set_navigation_map() function Add NavigationAgent2D/3D set_navigation_map() function. Also fixes some bugs from leftover code before the backport update. - smix8 https://github.com/godotengine/godot/commit/c6f9627c747fd989057c9f35c25b6d3472daab33 --- doc/classes/NavigationAgent.xml | 13 +++++++++ doc/classes/NavigationAgent2D.xml | 13 +++++++++ scene/2d/navigation_agent_2d.cpp | 44 ++++++++++++++++++++++++------- scene/2d/navigation_agent_2d.h | 4 +++ scene/3d/navigation_agent.cpp | 39 ++++++++++++++++++++------- scene/3d/navigation_agent.h | 4 +++ 6 files changed, 99 insertions(+), 18 deletions(-) diff --git a/doc/classes/NavigationAgent.xml b/doc/classes/NavigationAgent.xml index 8dafe7f4c..24dab7547 100644 --- a/doc/classes/NavigationAgent.xml +++ b/doc/classes/NavigationAgent.xml @@ -40,6 +40,12 @@ Returns the [Navigation] node that the agent is using for its navigation system. + + + + Returns the [RID] of the navigation map for this NavigationAgent node. This function returns always the map set on the NavigationAgent node and not the map of the abstract agent on the NavigationServer. If the agent map is changed directly with the NavigationServer API the NavigationAgent node will not be aware of the map change. Use [method set_navigation_map] to change the navigation map for the NavigationAgent and also update the agent on the NavigationServer. + + @@ -83,6 +89,13 @@ Sets the [Navigation] node used by the agent. Useful when you don't want to make the agent a child of a [Navigation] node. + + + + + Sets the [RID] of the navigation map this NavigationAgent node should use and also updates the [code]agent[/code] on the NavigationServer. + + diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml index 5bebf3c81..844f4e8bf 100644 --- a/doc/classes/NavigationAgent2D.xml +++ b/doc/classes/NavigationAgent2D.xml @@ -40,6 +40,12 @@ Returns the [Navigation2D] node that the agent is using for its navigation system. + + + + Returns the [RID] of the navigation map for this NavigationAgent node. This function returns always the map set on the NavigationAgent node and not the map of the abstract agent on the NavigationServer. If the agent map is changed directly with the NavigationServer API the NavigationAgent node will not be aware of the map change. Use [method set_navigation_map] to change the navigation map for the NavigationAgent and also update the agent on the NavigationServer. + + @@ -83,6 +89,13 @@ Sets the [Navigation2D] node used by the agent. Useful when you don't want to make the agent a child of a [Navigation2D] node. + + + + + Sets the [RID] of the navigation map this NavigationAgent node should use and also updates the [code]agent[/code] on the NavigationServer. + + diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index bf49e574c..952b65bd5 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -69,6 +69,9 @@ void NavigationAgent2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationAgent2D::set_navigation_layers); ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationAgent2D::get_navigation_layers); + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent2D::set_navigation_map); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent2D::get_navigation_map); + ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent2D::set_target_location); ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent2D::get_target_location); ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent2D::get_next_location); @@ -157,12 +160,9 @@ void NavigationAgent2D::_notification(int p_what) { } } break; case NOTIFICATION_EXIT_TREE: { - agent_parent = nullptr; + set_agent_parent(nullptr); set_navigation(nullptr); set_physics_process_internal(false); - // Want to call ready again when the node enters the tree again. We're not using enter_tree notification because - // the navigation map may not be ready at that time. This fixes issues with taking the agent out of the scene tree. - request_ready(); } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (agent_parent) { @@ -227,11 +227,13 @@ void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) { if (Object::cast_to(p_agent_parent) != nullptr) { // place agent on navigation map first or else the RVO agent callback creation fails silently later agent_parent = Object::cast_to(p_agent_parent); - if (navigation == nullptr) { + if (map_override.is_valid()) { + Navigation2DServer::get_singleton()->agent_set_map(get_rid(), map_override); + } else if (navigation != nullptr) { + Navigation2DServer::get_singleton()->agent_set_map(get_rid(), navigation->get_rid()); + } else { // no navigation node found in parent nodes, use default navigation map from world resource Navigation2DServer::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map()); - } else { - Navigation2DServer::get_singleton()->agent_set_map(get_rid(), navigation->get_rid()); } // create new avoidance callback if enabled set_avoidance_enabled(avoidance_enabled); @@ -272,6 +274,23 @@ uint32_t NavigationAgent2D::get_navigation_layers() const { return navigation_layers; } +void NavigationAgent2D::set_navigation_map(RID p_navigation_map) { + map_override = p_navigation_map; + Navigation2DServer::get_singleton()->agent_set_map(agent, map_override); + _request_repath(); +} + +RID NavigationAgent2D::get_navigation_map() const { + if (map_override.is_valid()) { + return map_override; + } else if (navigation != nullptr) { + return navigation->get_rid(); + } else if (agent_parent != nullptr) { + return agent_parent->get_world_2d()->get_navigation_map(); + } + return RID(); +} + void NavigationAgent2D::set_target_desired_distance(real_t p_dd) { target_desired_distance = p_dd; } @@ -386,7 +405,7 @@ void NavigationAgent2D::update_navigation() { if (agent_parent == nullptr) { return; } - if (navigation == nullptr) { + if (!agent_parent->is_inside_tree()) { return; } if (update_frame_id == Engine::get_singleton()->get_physics_frames()) { @@ -418,7 +437,14 @@ void NavigationAgent2D::update_navigation() { } if (reload_path) { - navigation_path = Navigation2DServer::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true); + if (map_override.is_valid()) { + navigation_path = Navigation2DServer::get_singleton()->map_get_path(map_override, o, target_location, true, navigation_layers); + } else if (navigation != nullptr) { + navigation_path = Navigation2DServer::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true, navigation_layers); + } else { + navigation_path = Navigation2DServer::get_singleton()->map_get_path(agent_parent->get_world_2d()->get_navigation_map(), o, target_location, true, navigation_layers); + } + navigation_finished = false; nav_path_index = 0; emit_signal("path_changed"); diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 64a02f270..c00f38f35 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -43,6 +43,7 @@ class NavigationAgent2D : public Node { RID agent; RID map_before_pause; + RID map_override; bool avoidance_enabled; uint32_t navigation_layers; @@ -96,6 +97,9 @@ public: void set_navigation_layers(uint32_t p_navigation_layers); uint32_t get_navigation_layers() const; + void set_navigation_map(RID p_navigation_map); + RID get_navigation_map() const; + void set_target_desired_distance(real_t p_dd); real_t get_target_desired_distance() const { return target_desired_distance; diff --git a/scene/3d/navigation_agent.cpp b/scene/3d/navigation_agent.cpp index 5cd55d418..f147b2f8d 100644 --- a/scene/3d/navigation_agent.cpp +++ b/scene/3d/navigation_agent.cpp @@ -57,6 +57,9 @@ void NavigationAgent::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationAgent::set_navigation_node); ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationAgent::get_navigation_node); + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent::set_navigation_map); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent::get_navigation_map); + ClassDB::bind_method(D_METHOD("set_neighbor_dist", "neighbor_dist"), &NavigationAgent::set_neighbor_dist); ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent::get_neighbor_dist); @@ -150,9 +153,6 @@ void NavigationAgent::_notification(int p_what) { set_agent_parent(nullptr); set_navigation(nullptr); set_physics_process_internal(false); - // Want to call ready again when the node enters the tree again. We're not using enter_tree notification because - // the navigation map may not be ready at that time. This fixes issues with taking the agent out of the scene tree. - request_ready(); } break; case NOTIFICATION_PAUSED: { if (agent_parent && !agent_parent->can_process()) { @@ -254,12 +254,15 @@ void NavigationAgent::set_agent_parent(Node *p_agent_parent) { if (Object::cast_to(p_agent_parent) != nullptr) { // place agent on navigation map first or else the RVO agent callback creation fails silently later agent_parent = Object::cast_to(p_agent_parent); - if (navigation == nullptr) { + if (map_override.is_valid()) { + NavigationServer::get_singleton()->agent_set_map(get_rid(), map_override); + } else if (navigation != nullptr) { + NavigationServer::get_singleton()->agent_set_map(get_rid(), navigation->get_rid()); + } else { // no navigation node found in parent nodes, use default navigation map from world resource NavigationServer::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world()->get_navigation_map()); - } else { - NavigationServer::get_singleton()->agent_set_map(get_rid(), navigation->get_rid()); } + // create new avoidance callback if enabled set_avoidance_enabled(avoidance_enabled); } else { @@ -280,6 +283,21 @@ uint32_t NavigationAgent::get_navigation_layers() const { return navigation_layers; } +void NavigationAgent::set_navigation_map(RID p_navigation_map) { + map_override = p_navigation_map; + NavigationServer::get_singleton()->agent_set_map(agent, map_override); + _request_repath(); +} + +RID NavigationAgent::get_navigation_map() const { + if (map_override.is_valid()) { + return map_override; + } else if (agent_parent != nullptr) { + return agent_parent->get_world()->get_navigation_map(); + } + return RID(); +} + void NavigationAgent::set_target_desired_distance(real_t p_dd) { target_desired_distance = p_dd; } @@ -440,11 +458,14 @@ void NavigationAgent::update_navigation() { } if (reload_path) { - if (navigation == nullptr) { - navigation_path = NavigationServer::get_singleton()->map_get_path(agent_parent->get_world()->get_navigation_map(), o, target_location, true, navigation_layers); - } else { + if (map_override.is_valid()) { + navigation_path = NavigationServer::get_singleton()->map_get_path(map_override, o, target_location, true, navigation_layers); + } else if (navigation != nullptr) { navigation_path = NavigationServer::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true, navigation_layers); + } else { + navigation_path = NavigationServer::get_singleton()->map_get_path(agent_parent->get_world()->get_navigation_map(), o, target_location, true, navigation_layers); } + navigation_finished = false; nav_path_index = 0; emit_signal("path_changed"); diff --git a/scene/3d/navigation_agent.h b/scene/3d/navigation_agent.h index c518181d0..dbe30bf22 100644 --- a/scene/3d/navigation_agent.h +++ b/scene/3d/navigation_agent.h @@ -44,6 +44,7 @@ class NavigationAgent : public Node { RID agent; RID map_before_pause; + RID map_override; bool avoidance_enabled; uint32_t navigation_layers; @@ -99,6 +100,9 @@ public: void set_navigation_layers(uint32_t p_navigation_layers); uint32_t get_navigation_layers() const; + void set_navigation_map(RID p_navigation_map); + RID get_navigation_map() const; + void set_target_desired_distance(real_t p_dd); real_t get_target_desired_distance() const { return target_desired_distance;