diff --git a/modules/navigation/nav_agent.cpp b/modules/navigation/nav_agent.cpp index 037b23732853..aef4d6da19f3 100644 --- a/modules/navigation/nav_agent.cpp +++ b/modules/navigation/nav_agent.cpp @@ -32,9 +32,6 @@ #include "nav_map.h" -NavAgent::NavAgent() { -} - void NavAgent::set_avoidance_enabled(bool p_enabled) { avoidance_enabled = p_enabled; _update_rvo_agent_properties(); @@ -87,6 +84,8 @@ void NavAgent::_update_rvo_agent_properties() { } } agent_dirty = true; + + request_sync(); } void NavAgent::set_map(NavMap *p_map) { @@ -94,6 +93,8 @@ void NavAgent::set_map(NavMap *p_map) { return; } + cancel_sync_request(); + if (map) { map->remove_agent(this); } @@ -106,6 +107,8 @@ void NavAgent::set_map(NavMap *p_map) { if (avoidance_enabled) { map->set_agent_as_controlled(this); } + + request_sync(); } } @@ -156,6 +159,8 @@ void NavAgent::set_neighbor_distance(real_t p_neighbor_distance) { rvo_agent_2d.neighborDist_ = neighbor_distance; } agent_dirty = true; + + request_sync(); } void NavAgent::set_max_neighbors(int p_max_neighbors) { @@ -166,6 +171,8 @@ void NavAgent::set_max_neighbors(int p_max_neighbors) { rvo_agent_2d.maxNeighbors_ = max_neighbors; } agent_dirty = true; + + request_sync(); } void NavAgent::set_time_horizon_agents(real_t p_time_horizon) { @@ -176,6 +183,8 @@ void NavAgent::set_time_horizon_agents(real_t p_time_horizon) { rvo_agent_2d.timeHorizon_ = time_horizon_agents; } agent_dirty = true; + + request_sync(); } void NavAgent::set_time_horizon_obstacles(real_t p_time_horizon) { @@ -186,6 +195,8 @@ void NavAgent::set_time_horizon_obstacles(real_t p_time_horizon) { rvo_agent_2d.timeHorizonObst_ = time_horizon_obstacles; } agent_dirty = true; + + request_sync(); } void NavAgent::set_radius(real_t p_radius) { @@ -196,6 +207,8 @@ void NavAgent::set_radius(real_t p_radius) { rvo_agent_2d.radius_ = radius; } agent_dirty = true; + + request_sync(); } void NavAgent::set_height(real_t p_height) { @@ -206,6 +219,8 @@ void NavAgent::set_height(real_t p_height) { rvo_agent_2d.height_ = height; } agent_dirty = true; + + request_sync(); } void NavAgent::set_max_speed(real_t p_max_speed) { @@ -218,6 +233,8 @@ void NavAgent::set_max_speed(real_t p_max_speed) { } } agent_dirty = true; + + request_sync(); } void NavAgent::set_position(const Vector3 p_position) { @@ -231,6 +248,8 @@ void NavAgent::set_position(const Vector3 p_position) { } } agent_dirty = true; + + request_sync(); } void NavAgent::set_target_position(const Vector3 p_target_position) { @@ -249,6 +268,8 @@ void NavAgent::set_velocity(const Vector3 p_velocity) { } } agent_dirty = true; + + request_sync(); } void NavAgent::set_velocity_forced(const Vector3 p_velocity) { @@ -265,6 +286,8 @@ void NavAgent::set_velocity_forced(const Vector3 p_velocity) { } } agent_dirty = true; + + request_sync(); } void NavAgent::update() { @@ -286,6 +309,8 @@ void NavAgent::set_avoidance_mask(uint32_t p_mask) { rvo_agent_2d.avoidance_mask_ = avoidance_mask; } agent_dirty = true; + + request_sync(); } void NavAgent::set_avoidance_layers(uint32_t p_layers) { @@ -296,6 +321,8 @@ void NavAgent::set_avoidance_layers(uint32_t p_layers) { rvo_agent_2d.avoidance_layers_ = avoidance_layers; } agent_dirty = true; + + request_sync(); } void NavAgent::set_avoidance_priority(real_t p_priority) { @@ -308,12 +335,16 @@ void NavAgent::set_avoidance_priority(real_t p_priority) { rvo_agent_2d.avoidance_priority_ = avoidance_priority; } agent_dirty = true; + + request_sync(); +} + +bool NavAgent::is_dirty() const { + return agent_dirty; } -bool NavAgent::check_dirty() { - const bool was_dirty = agent_dirty; +void NavAgent::sync() { agent_dirty = false; - return was_dirty; } const Dictionary NavAgent::get_avoidance_data() const { @@ -372,3 +403,23 @@ void NavAgent::set_paused(bool p_paused) { bool NavAgent::get_paused() const { return paused; } + +void NavAgent::request_sync() { + if (map && !sync_dirty_request_list_element.in_list()) { + map->add_agent_sync_dirty_request(&sync_dirty_request_list_element); + } +} + +void NavAgent::cancel_sync_request() { + if (map && sync_dirty_request_list_element.in_list()) { + map->remove_agent_sync_dirty_request(&sync_dirty_request_list_element); + } +} + +NavAgent::NavAgent() : + sync_dirty_request_list_element(this) { +} + +NavAgent::~NavAgent() { + cancel_sync_request(); +} diff --git a/modules/navigation/nav_agent.h b/modules/navigation/nav_agent.h index d56e053ac4cf..187929d46c44 100644 --- a/modules/navigation/nav_agent.h +++ b/modules/navigation/nav_agent.h @@ -35,6 +35,7 @@ #include "core/object/class_db.h" #include "core/templates/local_vector.h" +#include "core/templates/self_list.h" #include #include @@ -74,8 +75,11 @@ class NavAgent : public NavRid { uint32_t last_map_iteration_id = 0; bool paused = false; + SelfList sync_dirty_request_list_element; + public: NavAgent(); + ~NavAgent(); void set_avoidance_enabled(bool p_enabled); bool is_avoidance_enabled() { return avoidance_enabled; } @@ -141,7 +145,10 @@ class NavAgent : public NavRid { void set_paused(bool p_paused); bool get_paused() const; - bool check_dirty(); + bool is_dirty() const; + void sync(); + void request_sync(); + void cancel_sync_request(); // Updates this agent with rvo data after the rvo simulation avoidance step. void update(); diff --git a/modules/navigation/nav_link.cpp b/modules/navigation/nav_link.cpp index 61c3b59fab4e..51c59f45a039 100644 --- a/modules/navigation/nav_link.cpp +++ b/modules/navigation/nav_link.cpp @@ -37,6 +37,8 @@ void NavLink::set_map(NavMap *p_map) { return; } + cancel_sync_request(); + if (map) { map->remove_link(this); } @@ -46,6 +48,7 @@ void NavLink::set_map(NavMap *p_map) { if (map) { map->add_link(this); + request_sync(); } } @@ -57,6 +60,8 @@ void NavLink::set_enabled(bool p_enabled) { // TODO: This should not require a full rebuild as the link has not really changed. link_dirty = true; + + request_sync(); } void NavLink::set_bidirectional(bool p_bidirectional) { @@ -65,6 +70,8 @@ void NavLink::set_bidirectional(bool p_bidirectional) { } bidirectional = p_bidirectional; link_dirty = true; + + request_sync(); } void NavLink::set_start_position(const Vector3 p_position) { @@ -73,6 +80,8 @@ void NavLink::set_start_position(const Vector3 p_position) { } start_position = p_position; link_dirty = true; + + request_sync(); } void NavLink::set_end_position(const Vector3 p_position) { @@ -81,11 +90,35 @@ void NavLink::set_end_position(const Vector3 p_position) { } end_position = p_position; link_dirty = true; + + request_sync(); } -bool NavLink::check_dirty() { - const bool was_dirty = link_dirty; +bool NavLink::is_dirty() const { + return link_dirty; +} +void NavLink::sync() { link_dirty = false; - return was_dirty; +} + +void NavLink::request_sync() { + if (map && !sync_dirty_request_list_element.in_list()) { + map->add_link_sync_dirty_request(&sync_dirty_request_list_element); + } +} + +void NavLink::cancel_sync_request() { + if (map && sync_dirty_request_list_element.in_list()) { + map->remove_link_sync_dirty_request(&sync_dirty_request_list_element); + } +} + +NavLink::NavLink() : + sync_dirty_request_list_element(this) { + type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_LINK; +} + +NavLink::~NavLink() { + cancel_sync_request(); } diff --git a/modules/navigation/nav_link.h b/modules/navigation/nav_link.h index a7609831db26..eb2cbed35e30 100644 --- a/modules/navigation/nav_link.h +++ b/modules/navigation/nav_link.h @@ -34,6 +34,8 @@ #include "nav_base.h" #include "nav_utils.h" +#include "core/templates/self_list.h" + class NavLink : public NavBase { NavMap *map = nullptr; bool bidirectional = true; @@ -43,10 +45,11 @@ class NavLink : public NavBase { bool link_dirty = true; + SelfList sync_dirty_request_list_element; + public: - NavLink() { - type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_LINK; - } + NavLink(); + ~NavLink(); void set_map(NavMap *p_map); NavMap *get_map() const { @@ -71,7 +74,10 @@ class NavLink : public NavBase { return end_position; } - bool check_dirty(); + bool is_dirty() const; + void sync(); + void request_sync(); + void cancel_sync_request(); }; #endif // NAV_LINK_H diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp index d7b5ab87c5a5..1bd703238c94 100644 --- a/modules/navigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp @@ -56,7 +56,7 @@ void NavMap::set_up(Vector3 p_up) { return; } up = p_up; - regenerate_polygons = true; + map_settings_dirty = true; } void NavMap::set_cell_size(real_t p_cell_size) { @@ -65,7 +65,7 @@ void NavMap::set_cell_size(real_t p_cell_size) { } cell_size = p_cell_size; _update_merge_rasterizer_cell_dimensions(); - regenerate_polygons = true; + map_settings_dirty = true; } void NavMap::set_cell_height(real_t p_cell_height) { @@ -74,7 +74,7 @@ void NavMap::set_cell_height(real_t p_cell_height) { } cell_height = p_cell_height; _update_merge_rasterizer_cell_dimensions(); - regenerate_polygons = true; + map_settings_dirty = true; } void NavMap::set_merge_rasterizer_cell_scale(float p_value) { @@ -83,7 +83,7 @@ void NavMap::set_merge_rasterizer_cell_scale(float p_value) { } merge_rasterizer_cell_scale = p_value; _update_merge_rasterizer_cell_dimensions(); - regenerate_polygons = true; + map_settings_dirty = true; } void NavMap::set_use_edge_connections(bool p_enabled) { @@ -91,7 +91,7 @@ void NavMap::set_use_edge_connections(bool p_enabled) { return; } use_edge_connections = p_enabled; - regenerate_links = true; + iteration_dirty = true; } void NavMap::set_edge_connection_margin(real_t p_edge_connection_margin) { @@ -99,7 +99,7 @@ void NavMap::set_edge_connection_margin(real_t p_edge_connection_margin) { return; } edge_connection_margin = p_edge_connection_margin; - regenerate_links = true; + iteration_dirty = true; } void NavMap::set_link_connection_radius(real_t p_link_connection_radius) { @@ -107,7 +107,7 @@ void NavMap::set_link_connection_radius(real_t p_link_connection_radius) { return; } link_connection_radius = p_link_connection_radius; - regenerate_links = true; + iteration_dirty = true; } gd::PointKey NavMap::get_point_key(const Vector3 &p_pos) const { @@ -183,27 +183,27 @@ gd::ClosestPointQueryResult NavMap::get_closest_point_info(const Vector3 &p_poin void NavMap::add_region(NavRegion *p_region) { regions.push_back(p_region); - regenerate_links = true; + iteration_dirty = true; } void NavMap::remove_region(NavRegion *p_region) { int64_t region_index = regions.find(p_region); if (region_index >= 0) { regions.remove_at_unordered(region_index); - regenerate_links = true; + iteration_dirty = true; } } void NavMap::add_link(NavLink *p_link) { links.push_back(p_link); - regenerate_links = true; + iteration_dirty = true; } void NavMap::remove_link(NavLink *p_link) { int64_t link_index = links.find(p_link); if (link_index >= 0) { links.remove_at_unordered(link_index); - regenerate_links = true; + iteration_dirty = true; } } @@ -361,27 +361,9 @@ void NavMap::sync() { performance_data.pm_link_count = links.size(); performance_data.pm_obstacle_count = obstacles.size(); - // Check if we need to update the links. - if (regenerate_polygons) { - for (NavRegion *region : regions) { - region->scratch_polygons(); - } - regenerate_links = true; - } + _sync_dirty_map_update_requests(); - for (NavRegion *region : regions) { - if (region->sync()) { - regenerate_links = true; - } - } - - for (NavLink *link : links) { - if (link->check_dirty()) { - regenerate_links = true; - } - } - - if (regenerate_links) { + if (iteration_dirty) { performance_data.pm_polygon_count = 0; performance_data.pm_edge_count = 0; performance_data.pm_edge_merge_count = 0; @@ -659,26 +641,19 @@ void NavMap::sync() { iteration_id = iteration_id % UINT32_MAX + 1; } - // Do we have modified obstacle positions? - for (NavObstacle *obstacle : obstacles) { - if (obstacle->check_dirty()) { - obstacles_dirty = true; - } - } - // Do we have modified agent arrays? - for (NavAgent *agent : agents) { - if (agent->check_dirty()) { - agents_dirty = true; - } - } + map_settings_dirty = false; + iteration_dirty = false; + + _sync_avoidance(); +} + +void NavMap::_sync_avoidance() { + _sync_dirty_avoidance_update_requests(); - // Update avoidance worlds. if (obstacles_dirty || agents_dirty) { _update_rvo_simulation(); } - regenerate_polygons = false; - regenerate_links = false; obstacles_dirty = false; agents_dirty = false; } @@ -889,6 +864,104 @@ Vector3 NavMap::get_region_connection_pathway_end(NavRegion *p_region, int p_con return Vector3(); } +void NavMap::add_region_sync_dirty_request(SelfList *p_sync_request) { + if (p_sync_request->in_list()) { + return; + } + sync_dirty_requests.regions.add(p_sync_request); +} + +void NavMap::add_link_sync_dirty_request(SelfList *p_sync_request) { + if (p_sync_request->in_list()) { + return; + } + sync_dirty_requests.links.add(p_sync_request); +} + +void NavMap::add_agent_sync_dirty_request(SelfList *p_sync_request) { + if (p_sync_request->in_list()) { + return; + } + sync_dirty_requests.agents.add(p_sync_request); +} + +void NavMap::add_obstacle_sync_dirty_request(SelfList *p_sync_request) { + if (p_sync_request->in_list()) { + return; + } + sync_dirty_requests.obstacles.add(p_sync_request); +} + +void NavMap::remove_region_sync_dirty_request(SelfList *p_sync_request) { + if (!p_sync_request->in_list()) { + return; + } + sync_dirty_requests.regions.remove(p_sync_request); +} + +void NavMap::remove_link_sync_dirty_request(SelfList *p_sync_request) { + if (!p_sync_request->in_list()) { + return; + } + sync_dirty_requests.links.remove(p_sync_request); +} + +void NavMap::remove_agent_sync_dirty_request(SelfList *p_sync_request) { + if (!p_sync_request->in_list()) { + return; + } + sync_dirty_requests.agents.remove(p_sync_request); +} + +void NavMap::remove_obstacle_sync_dirty_request(SelfList *p_sync_request) { + if (!p_sync_request->in_list()) { + return; + } + sync_dirty_requests.obstacles.remove(p_sync_request); +} + +void NavMap::_sync_dirty_map_update_requests() { + // If entire map settings changed make all regions dirty. + if (map_settings_dirty) { + for (NavRegion *region : regions) { + region->scratch_polygons(); + } + iteration_dirty = true; + } + + if (!iteration_dirty) { + iteration_dirty = sync_dirty_requests.regions.first() || sync_dirty_requests.links.first(); + } + + // Sync NavRegions. + for (SelfList *element = sync_dirty_requests.regions.first(); element; element = element->next()) { + element->self()->sync(); + } + sync_dirty_requests.regions.clear(); + + // Sync NavLinks. + for (SelfList *element = sync_dirty_requests.links.first(); element; element = element->next()) { + element->self()->sync(); + } + sync_dirty_requests.links.clear(); +} + +void NavMap::_sync_dirty_avoidance_update_requests() { + // Sync NavAgents. + agents_dirty = sync_dirty_requests.agents.first(); + for (SelfList *element = sync_dirty_requests.agents.first(); element; element = element->next()) { + element->self()->sync(); + } + sync_dirty_requests.agents.clear(); + + // Sync NavObstacles. + obstacles_dirty = sync_dirty_requests.obstacles.first(); + for (SelfList *element = sync_dirty_requests.obstacles.first(); element; element = element->next()) { + element->self()->sync(); + } + sync_dirty_requests.obstacles.clear(); +} + NavMap::NavMap() { avoidance_use_multiple_threads = GLOBAL_GET("navigation/avoidance/thread_model/avoidance_use_multiple_threads"); avoidance_use_high_priority_threads = GLOBAL_GET("navigation/avoidance/thread_model/avoidance_use_high_priority_threads"); diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h index 7eaf2133b906..feeb2cc54834 100644 --- a/modules/navigation/nav_map.h +++ b/modules/navigation/nav_map.h @@ -72,8 +72,8 @@ class NavMap : public NavRid { /// This value is used to limit how far links search to find polygons to connect to. real_t link_connection_radius = NavigationDefaults3D::link_connection_radius; - bool regenerate_polygons = true; - bool regenerate_links = true; + bool map_settings_dirty = true; + bool iteration_dirty = true; /// Map regions LocalVector regions; @@ -128,6 +128,13 @@ class NavMap : public NavRid { HashMap connection_pairs_map; LocalVector free_edges; + struct { + SelfList::List regions; + SelfList::List links; + SelfList::List agents; + SelfList::List obstacles; + } sync_dirty_requests; + public: NavMap(); ~NavMap(); @@ -226,12 +233,26 @@ class NavMap : public NavRid { Vector3 get_region_connection_pathway_start(NavRegion *p_region, int p_connection_id) const; Vector3 get_region_connection_pathway_end(NavRegion *p_region, int p_connection_id) const; + void add_region_sync_dirty_request(SelfList *p_sync_request); + void add_link_sync_dirty_request(SelfList *p_sync_request); + void add_agent_sync_dirty_request(SelfList *p_sync_request); + void add_obstacle_sync_dirty_request(SelfList *p_sync_request); + + void remove_region_sync_dirty_request(SelfList *p_sync_request); + void remove_link_sync_dirty_request(SelfList *p_sync_request); + void remove_agent_sync_dirty_request(SelfList *p_sync_request); + void remove_obstacle_sync_dirty_request(SelfList *p_sync_request); + private: + void _sync_dirty_map_update_requests(); + void _sync_dirty_avoidance_update_requests(); + void compute_single_step(uint32_t index, NavAgent **agent); void compute_single_avoidance_step_2d(uint32_t index, NavAgent **agent); void compute_single_avoidance_step_3d(uint32_t index, NavAgent **agent); + void _sync_avoidance(); void _update_rvo_simulation(); void _update_rvo_obstacles_tree_2d(); void _update_rvo_agents_tree_2d(); diff --git a/modules/navigation/nav_obstacle.cpp b/modules/navigation/nav_obstacle.cpp index 14dfd4eae341..ced3e0650e57 100644 --- a/modules/navigation/nav_obstacle.cpp +++ b/modules/navigation/nav_obstacle.cpp @@ -33,10 +33,6 @@ #include "nav_agent.h" #include "nav_map.h" -NavObstacle::NavObstacle() {} - -NavObstacle::~NavObstacle() {} - void NavObstacle::set_agent(NavAgent *p_agent) { if (agent == p_agent) { return; @@ -45,6 +41,8 @@ void NavObstacle::set_agent(NavAgent *p_agent) { agent = p_agent; internal_update_agent(); + + request_sync(); } void NavObstacle::set_avoidance_enabled(bool p_enabled) { @@ -56,6 +54,8 @@ void NavObstacle::set_avoidance_enabled(bool p_enabled) { obstacle_dirty = true; internal_update_agent(); + + request_sync(); } void NavObstacle::set_use_3d_avoidance(bool p_enabled) { @@ -69,6 +69,8 @@ void NavObstacle::set_use_3d_avoidance(bool p_enabled) { if (agent) { agent->set_use_3d_avoidance(use_3d_avoidance); } + + request_sync(); } void NavObstacle::set_map(NavMap *p_map) { @@ -76,6 +78,8 @@ void NavObstacle::set_map(NavMap *p_map) { return; } + cancel_sync_request(); + if (map) { map->remove_obstacle(this); if (agent) { @@ -89,6 +93,8 @@ void NavObstacle::set_map(NavMap *p_map) { if (map) { map->add_obstacle(this); internal_update_agent(); + + request_sync(); } } @@ -103,6 +109,8 @@ void NavObstacle::set_position(const Vector3 p_position) { if (agent) { agent->set_position(position); } + + request_sync(); } void NavObstacle::set_radius(real_t p_radius) { @@ -128,6 +136,8 @@ void NavObstacle::set_height(const real_t p_height) { if (agent) { agent->set_height(height); } + + request_sync(); } void NavObstacle::set_velocity(const Vector3 p_velocity) { @@ -145,6 +155,8 @@ void NavObstacle::set_vertices(const Vector &p_vertices) { vertices = p_vertices; obstacle_dirty = true; + + request_sync(); } bool NavObstacle::is_map_changed() { @@ -168,12 +180,16 @@ void NavObstacle::set_avoidance_layers(uint32_t p_layers) { if (agent) { agent->set_avoidance_layers(avoidance_layers); } + + request_sync(); } -bool NavObstacle::check_dirty() { - const bool was_dirty = obstacle_dirty; +bool NavObstacle::is_dirty() const { + return obstacle_dirty; +} + +void NavObstacle::sync() { obstacle_dirty = false; - return was_dirty; } void NavObstacle::internal_update_agent() { @@ -216,3 +232,23 @@ void NavObstacle::set_paused(bool p_paused) { bool NavObstacle::get_paused() const { return paused; } + +void NavObstacle::request_sync() { + if (map && !sync_dirty_request_list_element.in_list()) { + map->add_obstacle_sync_dirty_request(&sync_dirty_request_list_element); + } +} + +void NavObstacle::cancel_sync_request() { + if (map && sync_dirty_request_list_element.in_list()) { + map->remove_obstacle_sync_dirty_request(&sync_dirty_request_list_element); + } +} + +NavObstacle::NavObstacle() : + sync_dirty_request_list_element(this) { +} + +NavObstacle::~NavObstacle() { + cancel_sync_request(); +} diff --git a/modules/navigation/nav_obstacle.h b/modules/navigation/nav_obstacle.h index a6aca9d63722..9836b1300a94 100644 --- a/modules/navigation/nav_obstacle.h +++ b/modules/navigation/nav_obstacle.h @@ -35,6 +35,7 @@ #include "core/object/class_db.h" #include "core/templates/local_vector.h" +#include "core/templates/self_list.h" class NavAgent; class NavMap; @@ -58,6 +59,8 @@ class NavObstacle : public NavRid { uint32_t last_map_iteration_id = 0; bool paused = false; + SelfList sync_dirty_request_list_element; + public: NavObstacle(); ~NavObstacle(); @@ -97,7 +100,10 @@ class NavObstacle : public NavRid { void set_paused(bool p_paused); bool get_paused() const; - bool check_dirty(); + bool is_dirty() const; + void sync(); + void request_sync(); + void cancel_sync_request(); private: void internal_update_agent(); diff --git a/modules/navigation/nav_region.cpp b/modules/navigation/nav_region.cpp index 679997b8e110..118970bc46c3 100644 --- a/modules/navigation/nav_region.cpp +++ b/modules/navigation/nav_region.cpp @@ -39,6 +39,8 @@ void NavRegion::set_map(NavMap *p_map) { return; } + cancel_sync_request(); + if (map) { map->remove_region(this); } @@ -48,6 +50,7 @@ void NavRegion::set_map(NavMap *p_map) { if (map) { map->add_region(this); + request_sync(); } } @@ -59,6 +62,8 @@ void NavRegion::set_enabled(bool p_enabled) { // TODO: This should not require a full rebuild as the region has not really changed. polygons_dirty = true; + + request_sync(); } void NavRegion::set_use_edge_connections(bool p_enabled) { @@ -66,6 +71,8 @@ void NavRegion::set_use_edge_connections(bool p_enabled) { use_edge_connections = p_enabled; polygons_dirty = true; } + + request_sync(); } void NavRegion::set_transform(Transform3D p_transform) { @@ -75,6 +82,8 @@ void NavRegion::set_transform(Transform3D p_transform) { transform = p_transform; polygons_dirty = true; + request_sync(); + #ifdef DEBUG_ENABLED if (map && Math::rad_to_deg(map->get_up().angle_to(transform.basis.get_column(1))) >= 90.0f) { ERR_PRINT_ONCE("Attempted to update a navigation region transform rotated 90 degrees or more away from the current navigation map UP orientation."); @@ -103,6 +112,8 @@ void NavRegion::set_navigation_mesh(Ref p_navigation_mesh) { } polygons_dirty = true; + + request_sync(); } Vector3 NavRegion::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const { @@ -220,3 +231,24 @@ void NavRegion::update_polygons() { surface_area = _new_region_surface_area; } + +void NavRegion::request_sync() { + if (map && !sync_dirty_request_list_element.in_list()) { + map->add_region_sync_dirty_request(&sync_dirty_request_list_element); + } +} + +void NavRegion::cancel_sync_request() { + if (map && sync_dirty_request_list_element.in_list()) { + map->remove_region_sync_dirty_request(&sync_dirty_request_list_element); + } +} + +NavRegion::NavRegion() : + sync_dirty_request_list_element(this) { + type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_REGION; +} + +NavRegion::~NavRegion() { + cancel_sync_request(); +} diff --git a/modules/navigation/nav_region.h b/modules/navigation/nav_region.h index d13f666e9afc..16e8bb1d8464 100644 --- a/modules/navigation/nav_region.h +++ b/modules/navigation/nav_region.h @@ -57,10 +57,11 @@ class NavRegion : public NavBase { Vector pending_navmesh_vertices; Vector> pending_navmesh_polygons; + SelfList sync_dirty_request_list_element; + public: - NavRegion() { - type = NavigationUtilities::PathSegmentType::PATH_SEGMENT_TYPE_REGION; - } + NavRegion(); + ~NavRegion(); void scratch_polygons() { polygons_dirty = true; @@ -97,6 +98,8 @@ class NavRegion : public NavBase { real_t get_surface_area() const { return surface_area; } bool sync(); + void request_sync(); + void cancel_sync_request(); private: void update_polygons();