diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index 2c9ffdb1a050..c89dbcbdd477 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -355,6 +355,13 @@ Create a new link between two positions on a map. + + + + + Forces an immediate main thread synchronization of the specified navigation [param link] [RID]. Requires a navigation map synchronization afterwards as well to full register. Be aware that forcing a main thread synchronization can cause severe performance problems on more complex navigation setups. + + @@ -504,14 +511,11 @@ Create a new map. - + - This function immediately forces synchronization of the specified navigation [param map] [RID]. By default navigation maps are only synchronized at the end of each physics frame. This function can be used to immediately (re)calculate all the navigation meshes and region connections of the navigation map. This makes it possible to query a navigation path for a changed map immediately and in the same frame (multiple times if needed). - Due to technical restrictions the current NavigationServer command queue will be flushed. This means all already queued update commands for this physics frame will be executed, even those intended for other maps, regions and agents not part of the specified map. The expensive computation of the navigation meshes and region connections of a map will only be done for the specified map. Other maps will receive the normal synchronization at the end of the physics frame. Should the specified map receive changes after the forced update it will update again as well when the other maps receive their update. - Avoidance processing and dispatch of the [code]safe_velocity[/code] signals is unaffected by this function and continues to happen for all maps and agents at the end of the physics frame. - [b]Note:[/b] With great power comes great responsibility. This function should only be used by users that really know what they are doing and have a good reason for it. Forcing an immediate update of a navigation map requires locking the NavigationServer and flushing the entire NavigationServer command queue. Not only can this severely impact the performance of a game but it can also introduce bugs if used inappropriately without much foresight. + Forces an immediate main thread synchronization for the navigation mesh part of the specified navigation [param map] [RID]. Pending changes to regions or links need to be synchronized before map synchronization. Be aware that forcing a main thread synchronization can cause severe performance problems on more complex navigation setups. @@ -933,6 +937,13 @@ Creates a new region. + + + + + Forces an immediate main thread synchronization of the specified navigation [param region] [RID]. Requires a navigation map synchronization afterwards as well to full register. Be aware that forcing a main thread synchronization can cause severe performance problems on more complex navigation setups. + + diff --git a/modules/navigation_3d/3d/godot_navigation_server_3d.cpp b/modules/navigation_3d/3d/godot_navigation_server_3d.cpp index 35b076c874c0..5ec8cb02d22e 100644 --- a/modules/navigation_3d/3d/godot_navigation_server_3d.cpp +++ b/modules/navigation_3d/3d/godot_navigation_server_3d.cpp @@ -37,60 +37,9 @@ using namespace NavigationDefaults3D; -/// Creates a struct for each function and a function that once called creates -/// an instance of that struct with the submitted parameters. -/// Then, that struct is stored in an array; the `sync` function consume that array. - -#define COMMAND_1(F_NAME, T_0, D_0) \ - struct MERGE(F_NAME, _command_3d) : public SetCommand3D { \ - T_0 d_0; \ - MERGE(F_NAME, _command_3d) \ - (T_0 p_d_0) : \ - d_0(p_d_0) {} \ - virtual void exec(GodotNavigationServer3D *server) override { \ - server->MERGE(_cmd_, F_NAME)(d_0); \ - } \ - }; \ - void GodotNavigationServer3D::F_NAME(T_0 D_0) { \ - auto cmd = memnew(MERGE(F_NAME, _command_3d)( \ - D_0)); \ - add_command(cmd); \ - } \ - void GodotNavigationServer3D::MERGE(_cmd_, F_NAME)(T_0 D_0) - -#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \ - struct MERGE(F_NAME, _command_3d) : public SetCommand3D { \ - T_0 d_0; \ - T_1 d_1; \ - MERGE(F_NAME, _command_3d) \ - ( \ - T_0 p_d_0, \ - T_1 p_d_1) : \ - d_0(p_d_0), \ - d_1(p_d_1) {} \ - virtual void exec(GodotNavigationServer3D *server) override { \ - server->MERGE(_cmd_, F_NAME)(d_0, d_1); \ - } \ - }; \ - void GodotNavigationServer3D::F_NAME(T_0 D_0, T_1 D_1) { \ - auto cmd = memnew(MERGE(F_NAME, _command_3d)( \ - D_0, \ - D_1)); \ - add_command(cmd); \ - } \ - void GodotNavigationServer3D::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1) - GodotNavigationServer3D::GodotNavigationServer3D() {} -GodotNavigationServer3D::~GodotNavigationServer3D() { - flush_queries(); -} - -void GodotNavigationServer3D::add_command(SetCommand3D *command) { - MutexLock lock(commands_mutex); - - commands.push_back(command); -} +GodotNavigationServer3D::~GodotNavigationServer3D() {} TypedArray GodotNavigationServer3D::get_maps() const { TypedArray all_map_rids; @@ -114,7 +63,7 @@ RID GodotNavigationServer3D::map_create() { return rid; } -COMMAND_2(map_set_active, RID, p_map, bool, p_active) { +void GodotNavigationServer3D::map_set_active(RID p_map, bool p_active) { NavMap3D *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL(map); @@ -136,7 +85,7 @@ bool GodotNavigationServer3D::map_is_active(RID p_map) const { return active_maps.has(map); } -COMMAND_2(map_set_up, RID, p_map, Vector3, p_up) { +void GodotNavigationServer3D::map_set_up(RID p_map, Vector3 p_up) { NavMap3D *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL(map); @@ -150,7 +99,7 @@ Vector3 GodotNavigationServer3D::map_get_up(RID p_map) const { return map->get_up(); } -COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size) { +void GodotNavigationServer3D::map_set_cell_size(RID p_map, real_t p_cell_size) { NavMap3D *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL(map); @@ -164,7 +113,7 @@ real_t GodotNavigationServer3D::map_get_cell_size(RID p_map) const { return map->get_cell_size(); } -COMMAND_2(map_set_cell_height, RID, p_map, real_t, p_cell_height) { +void GodotNavigationServer3D::map_set_cell_height(RID p_map, real_t p_cell_height) { NavMap3D *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL(map); @@ -178,7 +127,7 @@ real_t GodotNavigationServer3D::map_get_cell_height(RID p_map) const { return map->get_cell_height(); } -COMMAND_2(map_set_merge_rasterizer_cell_scale, RID, p_map, float, p_value) { +void GodotNavigationServer3D::map_set_merge_rasterizer_cell_scale(RID p_map, float p_value) { NavMap3D *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL(map); @@ -192,7 +141,7 @@ float GodotNavigationServer3D::map_get_merge_rasterizer_cell_scale(RID p_map) co return map->get_merge_rasterizer_cell_scale(); } -COMMAND_2(map_set_use_edge_connections, RID, p_map, bool, p_enabled) { +void GodotNavigationServer3D::map_set_use_edge_connections(RID p_map, bool p_enabled) { NavMap3D *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL(map); @@ -206,7 +155,7 @@ bool GodotNavigationServer3D::map_get_use_edge_connections(RID p_map) const { return map->get_use_edge_connections(); } -COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin) { +void GodotNavigationServer3D::map_set_edge_connection_margin(RID p_map, real_t p_connection_margin) { NavMap3D *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL(map); @@ -220,7 +169,7 @@ real_t GodotNavigationServer3D::map_get_edge_connection_margin(RID p_map) const return map->get_edge_connection_margin(); } -COMMAND_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius) { +void GodotNavigationServer3D::map_set_link_connection_radius(RID p_map, real_t p_connection_radius) { NavMap3D *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL(map); @@ -361,7 +310,7 @@ RID GodotNavigationServer3D::agent_get_map(RID p_agent) const { return RID(); } -COMMAND_2(map_set_use_async_iterations, RID, p_map, bool, p_enabled) { +void GodotNavigationServer3D::map_set_use_async_iterations(RID p_map, bool p_enabled) { NavMap3D *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL(map); map->set_use_async_iterations(p_enabled); @@ -390,6 +339,14 @@ RID GodotNavigationServer3D::region_create() { return rid; } +void GodotNavigationServer3D::region_force_update(RID p_region) { + ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Forcing an update is only allowed from the main thread."); + NavRegion3D *region = region_owner.get_or_null(p_region); + ERR_FAIL_NULL(region); + + region->force_update(); +} + uint32_t GodotNavigationServer3D::region_get_iteration_id(RID p_region) const { NavRegion3D *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL_V(region, 0); @@ -397,7 +354,7 @@ uint32_t GodotNavigationServer3D::region_get_iteration_id(RID p_region) const { return region->get_iteration_id(); } -COMMAND_2(region_set_use_async_iterations, RID, p_region, bool, p_enabled) { +void GodotNavigationServer3D::region_set_use_async_iterations(RID p_region, bool p_enabled) { NavRegion3D *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL(region); region->set_use_async_iterations(p_enabled); @@ -410,7 +367,7 @@ bool GodotNavigationServer3D::region_get_use_async_iterations(RID p_region) cons return region->get_use_async_iterations(); } -COMMAND_2(region_set_enabled, RID, p_region, bool, p_enabled) { +void GodotNavigationServer3D::region_set_enabled(RID p_region, bool p_enabled) { NavRegion3D *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL(region); @@ -424,7 +381,7 @@ bool GodotNavigationServer3D::region_get_enabled(RID p_region) const { return region->get_enabled(); } -COMMAND_2(region_set_use_edge_connections, RID, p_region, bool, p_enabled) { +void GodotNavigationServer3D::region_set_use_edge_connections(RID p_region, bool p_enabled) { NavRegion3D *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL(region); @@ -438,7 +395,7 @@ bool GodotNavigationServer3D::region_get_use_edge_connections(RID p_region) cons return region->get_use_edge_connections(); } -COMMAND_2(region_set_map, RID, p_region, RID, p_map) { +void GodotNavigationServer3D::region_set_map(RID p_region, RID p_map) { NavRegion3D *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL(region); @@ -447,7 +404,7 @@ COMMAND_2(region_set_map, RID, p_region, RID, p_map) { region->set_map(map); } -COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform) { +void GodotNavigationServer3D::region_set_transform(RID p_region, Transform3D p_transform) { NavRegion3D *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL(region); @@ -461,7 +418,7 @@ Transform3D GodotNavigationServer3D::region_get_transform(RID p_region) const { return region->get_transform(); } -COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost) { +void GodotNavigationServer3D::region_set_enter_cost(RID p_region, real_t p_enter_cost) { NavRegion3D *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL(region); ERR_FAIL_COND(p_enter_cost < 0.0); @@ -476,7 +433,7 @@ real_t GodotNavigationServer3D::region_get_enter_cost(RID p_region) const { return region->get_enter_cost(); } -COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost) { +void GodotNavigationServer3D::region_set_travel_cost(RID p_region, real_t p_travel_cost) { NavRegion3D *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL(region); ERR_FAIL_COND(p_travel_cost < 0.0); @@ -491,7 +448,7 @@ real_t GodotNavigationServer3D::region_get_travel_cost(RID p_region) const { return region->get_travel_cost(); } -COMMAND_2(region_set_owner_id, RID, p_region, ObjectID, p_owner_id) { +void GodotNavigationServer3D::region_set_owner_id(RID p_region, ObjectID p_owner_id) { NavRegion3D *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL(region); @@ -516,7 +473,7 @@ bool GodotNavigationServer3D::region_owns_point(RID p_region, const Vector3 &p_p return false; } -COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers) { +void GodotNavigationServer3D::region_set_navigation_layers(RID p_region, uint32_t p_navigation_layers) { NavRegion3D *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL(region); @@ -530,7 +487,7 @@ uint32_t GodotNavigationServer3D::region_get_navigation_layers(RID p_region) con return region->get_navigation_layers(); } -COMMAND_2(region_set_navigation_mesh, RID, p_region, Ref, p_navigation_mesh) { +void GodotNavigationServer3D::region_set_navigation_mesh(RID p_region, Ref p_navigation_mesh) { NavRegion3D *region = region_owner.get_or_null(p_region); ERR_FAIL_NULL(region); @@ -626,6 +583,14 @@ RID GodotNavigationServer3D::link_create() { return rid; } +void GodotNavigationServer3D::link_force_update(RID p_link) { + ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Forcing an update is only allowed from the main thread."); + NavLink3D *link = link_owner.get_or_null(p_link); + ERR_FAIL_NULL(link); + + link->force_update(); +} + uint32_t GodotNavigationServer3D::link_get_iteration_id(RID p_link) const { NavLink3D *link = link_owner.get_or_null(p_link); ERR_FAIL_NULL_V(link, 0); @@ -633,7 +598,7 @@ uint32_t GodotNavigationServer3D::link_get_iteration_id(RID p_link) const { return link->get_iteration_id(); } -COMMAND_2(link_set_map, RID, p_link, RID, p_map) { +void GodotNavigationServer3D::link_set_map(RID p_link, RID p_map) { NavLink3D *link = link_owner.get_or_null(p_link); ERR_FAIL_NULL(link); @@ -652,7 +617,7 @@ RID GodotNavigationServer3D::link_get_map(const RID p_link) const { return RID(); } -COMMAND_2(link_set_enabled, RID, p_link, bool, p_enabled) { +void GodotNavigationServer3D::link_set_enabled(RID p_link, bool p_enabled) { NavLink3D *link = link_owner.get_or_null(p_link); ERR_FAIL_NULL(link); @@ -666,7 +631,7 @@ bool GodotNavigationServer3D::link_get_enabled(RID p_link) const { return link->get_enabled(); } -COMMAND_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional) { +void GodotNavigationServer3D::link_set_bidirectional(RID p_link, bool p_bidirectional) { NavLink3D *link = link_owner.get_or_null(p_link); ERR_FAIL_NULL(link); @@ -680,7 +645,7 @@ bool GodotNavigationServer3D::link_is_bidirectional(RID p_link) const { return link->is_bidirectional(); } -COMMAND_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers) { +void GodotNavigationServer3D::link_set_navigation_layers(RID p_link, uint32_t p_navigation_layers) { NavLink3D *link = link_owner.get_or_null(p_link); ERR_FAIL_NULL(link); @@ -694,7 +659,7 @@ uint32_t GodotNavigationServer3D::link_get_navigation_layers(const RID p_link) c return link->get_navigation_layers(); } -COMMAND_2(link_set_start_position, RID, p_link, Vector3, p_position) { +void GodotNavigationServer3D::link_set_start_position(RID p_link, Vector3 p_position) { NavLink3D *link = link_owner.get_or_null(p_link); ERR_FAIL_NULL(link); @@ -708,7 +673,7 @@ Vector3 GodotNavigationServer3D::link_get_start_position(RID p_link) const { return link->get_start_position(); } -COMMAND_2(link_set_end_position, RID, p_link, Vector3, p_position) { +void GodotNavigationServer3D::link_set_end_position(RID p_link, Vector3 p_position) { NavLink3D *link = link_owner.get_or_null(p_link); ERR_FAIL_NULL(link); @@ -722,7 +687,7 @@ Vector3 GodotNavigationServer3D::link_get_end_position(RID p_link) const { return link->get_end_position(); } -COMMAND_2(link_set_enter_cost, RID, p_link, real_t, p_enter_cost) { +void GodotNavigationServer3D::link_set_enter_cost(RID p_link, real_t p_enter_cost) { NavLink3D *link = link_owner.get_or_null(p_link); ERR_FAIL_NULL(link); @@ -736,7 +701,7 @@ real_t GodotNavigationServer3D::link_get_enter_cost(const RID p_link) const { return link->get_enter_cost(); } -COMMAND_2(link_set_travel_cost, RID, p_link, real_t, p_travel_cost) { +void GodotNavigationServer3D::link_set_travel_cost(RID p_link, real_t p_travel_cost) { NavLink3D *link = link_owner.get_or_null(p_link); ERR_FAIL_NULL(link); @@ -750,7 +715,7 @@ real_t GodotNavigationServer3D::link_get_travel_cost(const RID p_link) const { return link->get_travel_cost(); } -COMMAND_2(link_set_owner_id, RID, p_link, ObjectID, p_owner_id) { +void GodotNavigationServer3D::link_set_owner_id(RID p_link, ObjectID p_owner_id) { NavLink3D *link = link_owner.get_or_null(p_link); ERR_FAIL_NULL(link); @@ -773,7 +738,7 @@ RID GodotNavigationServer3D::agent_create() { return rid; } -COMMAND_2(agent_set_avoidance_enabled, RID, p_agent, bool, p_enabled) { +void GodotNavigationServer3D::agent_set_avoidance_enabled(RID p_agent, bool p_enabled) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -787,7 +752,7 @@ bool GodotNavigationServer3D::agent_get_avoidance_enabled(RID p_agent) const { return agent->is_avoidance_enabled(); } -COMMAND_2(agent_set_use_3d_avoidance, RID, p_agent, bool, p_enabled) { +void GodotNavigationServer3D::agent_set_use_3d_avoidance(RID p_agent, bool p_enabled) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -801,7 +766,7 @@ bool GodotNavigationServer3D::agent_get_use_3d_avoidance(RID p_agent) const { return agent->get_use_3d_avoidance(); } -COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) { +void GodotNavigationServer3D::agent_set_map(RID p_agent, RID p_map) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -810,7 +775,7 @@ COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) { agent->set_map(map); } -COMMAND_2(agent_set_paused, RID, p_agent, bool, p_paused) { +void GodotNavigationServer3D::agent_set_paused(RID p_agent, bool p_paused) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -824,7 +789,7 @@ bool GodotNavigationServer3D::agent_get_paused(RID p_agent) const { return agent->get_paused(); } -COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance) { +void GodotNavigationServer3D::agent_set_neighbor_distance(RID p_agent, real_t p_distance) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -838,7 +803,7 @@ real_t GodotNavigationServer3D::agent_get_neighbor_distance(RID p_agent) const { return agent->get_neighbor_distance(); } -COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count) { +void GodotNavigationServer3D::agent_set_max_neighbors(RID p_agent, int p_count) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -852,7 +817,7 @@ int GodotNavigationServer3D::agent_get_max_neighbors(RID p_agent) const { return agent->get_max_neighbors(); } -COMMAND_2(agent_set_time_horizon_agents, RID, p_agent, real_t, p_time_horizon) { +void GodotNavigationServer3D::agent_set_time_horizon_agents(RID p_agent, real_t p_time_horizon) { ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizon must be positive."); NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -867,7 +832,7 @@ real_t GodotNavigationServer3D::agent_get_time_horizon_agents(RID p_agent) const return agent->get_time_horizon_agents(); } -COMMAND_2(agent_set_time_horizon_obstacles, RID, p_agent, real_t, p_time_horizon) { +void GodotNavigationServer3D::agent_set_time_horizon_obstacles(RID p_agent, real_t p_time_horizon) { ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizon must be positive."); NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -882,7 +847,7 @@ real_t GodotNavigationServer3D::agent_get_time_horizon_obstacles(RID p_agent) co return agent->get_time_horizon_obstacles(); } -COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius) { +void GodotNavigationServer3D::agent_set_radius(RID p_agent, real_t p_radius) { ERR_FAIL_COND_MSG(p_radius < 0.0, "Radius must be positive."); NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -897,7 +862,7 @@ real_t GodotNavigationServer3D::agent_get_radius(RID p_agent) const { return agent->get_radius(); } -COMMAND_2(agent_set_height, RID, p_agent, real_t, p_height) { +void GodotNavigationServer3D::agent_set_height(RID p_agent, real_t p_height) { ERR_FAIL_COND_MSG(p_height < 0.0, "Height must be positive."); NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -912,7 +877,7 @@ real_t GodotNavigationServer3D::agent_get_height(RID p_agent) const { return agent->get_height(); } -COMMAND_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed) { +void GodotNavigationServer3D::agent_set_max_speed(RID p_agent, real_t p_max_speed) { ERR_FAIL_COND_MSG(p_max_speed < 0.0, "Max speed must be positive."); NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -927,7 +892,7 @@ real_t GodotNavigationServer3D::agent_get_max_speed(RID p_agent) const { return agent->get_max_speed(); } -COMMAND_2(agent_set_velocity, RID, p_agent, Vector3, p_velocity) { +void GodotNavigationServer3D::agent_set_velocity(RID p_agent, Vector3 p_velocity) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -941,14 +906,14 @@ Vector3 GodotNavigationServer3D::agent_get_velocity(RID p_agent) const { return agent->get_velocity(); } -COMMAND_2(agent_set_velocity_forced, RID, p_agent, Vector3, p_velocity) { +void GodotNavigationServer3D::agent_set_velocity_forced(RID p_agent, Vector3 p_velocity) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); agent->set_velocity_forced(p_velocity); } -COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position) { +void GodotNavigationServer3D::agent_set_position(RID p_agent, Vector3 p_position) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -969,7 +934,7 @@ bool GodotNavigationServer3D::agent_is_map_changed(RID p_agent) const { return agent->is_map_changed(); } -COMMAND_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback) { +void GodotNavigationServer3D::agent_set_avoidance_callback(RID p_agent, Callable p_callback) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); @@ -991,7 +956,7 @@ bool GodotNavigationServer3D::agent_has_avoidance_callback(RID p_agent) const { return agent->has_avoidance_callback(); } -COMMAND_2(agent_set_avoidance_layers, RID, p_agent, uint32_t, p_layers) { +void GodotNavigationServer3D::agent_set_avoidance_layers(RID p_agent, uint32_t p_layers) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); agent->set_avoidance_layers(p_layers); @@ -1004,7 +969,7 @@ uint32_t GodotNavigationServer3D::agent_get_avoidance_layers(RID p_agent) const return agent->get_avoidance_layers(); } -COMMAND_2(agent_set_avoidance_mask, RID, p_agent, uint32_t, p_mask) { +void GodotNavigationServer3D::agent_set_avoidance_mask(RID p_agent, uint32_t p_mask) { NavAgent3D *agent = agent_owner.get_or_null(p_agent); ERR_FAIL_NULL(agent); agent->set_avoidance_mask(p_mask); @@ -1017,7 +982,7 @@ uint32_t GodotNavigationServer3D::agent_get_avoidance_mask(RID p_agent) const { return agent->get_avoidance_mask(); } -COMMAND_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority) { +void GodotNavigationServer3D::agent_set_avoidance_priority(RID p_agent, real_t p_priority) { ERR_FAIL_COND_MSG(p_priority < 0.0, "Avoidance priority must be between 0.0 and 1.0 inclusive."); ERR_FAIL_COND_MSG(p_priority > 1.0, "Avoidance priority must be between 0.0 and 1.0 inclusive."); NavAgent3D *agent = agent_owner.get_or_null(p_agent); @@ -1048,7 +1013,7 @@ RID GodotNavigationServer3D::obstacle_create() { return rid; } -COMMAND_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled) { +void GodotNavigationServer3D::obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled) { NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); @@ -1062,7 +1027,7 @@ bool GodotNavigationServer3D::obstacle_get_avoidance_enabled(RID p_obstacle) con return obstacle->is_avoidance_enabled(); } -COMMAND_2(obstacle_set_use_3d_avoidance, RID, p_obstacle, bool, p_enabled) { +void GodotNavigationServer3D::obstacle_set_use_3d_avoidance(RID p_obstacle, bool p_enabled) { NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); @@ -1076,7 +1041,7 @@ bool GodotNavigationServer3D::obstacle_get_use_3d_avoidance(RID p_obstacle) cons return obstacle->get_use_3d_avoidance(); } -COMMAND_2(obstacle_set_map, RID, p_obstacle, RID, p_map) { +void GodotNavigationServer3D::obstacle_set_map(RID p_obstacle, RID p_map) { NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); @@ -1094,7 +1059,7 @@ RID GodotNavigationServer3D::obstacle_get_map(RID p_obstacle) const { return RID(); } -COMMAND_2(obstacle_set_paused, RID, p_obstacle, bool, p_paused) { +void GodotNavigationServer3D::obstacle_set_paused(RID p_obstacle, bool p_paused) { NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); @@ -1108,7 +1073,7 @@ bool GodotNavigationServer3D::obstacle_get_paused(RID p_obstacle) const { return obstacle->get_paused(); } -COMMAND_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius) { +void GodotNavigationServer3D::obstacle_set_radius(RID p_obstacle, real_t p_radius) { ERR_FAIL_COND_MSG(p_radius < 0.0, "Radius must be positive."); NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); @@ -1123,7 +1088,7 @@ real_t GodotNavigationServer3D::obstacle_get_radius(RID p_obstacle) const { return obstacle->get_radius(); } -COMMAND_2(obstacle_set_height, RID, p_obstacle, real_t, p_height) { +void GodotNavigationServer3D::obstacle_set_height(RID p_obstacle, real_t p_height) { NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); obstacle->set_height(p_height); @@ -1136,7 +1101,7 @@ real_t GodotNavigationServer3D::obstacle_get_height(RID p_obstacle) const { return obstacle->get_height(); } -COMMAND_2(obstacle_set_velocity, RID, p_obstacle, Vector3, p_velocity) { +void GodotNavigationServer3D::obstacle_set_velocity(RID p_obstacle, Vector3 p_velocity) { NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); @@ -1150,7 +1115,7 @@ Vector3 GodotNavigationServer3D::obstacle_get_velocity(RID p_obstacle) const { return obstacle->get_velocity(); } -COMMAND_2(obstacle_set_position, RID, p_obstacle, Vector3, p_position) { +void GodotNavigationServer3D::obstacle_set_position(RID p_obstacle, Vector3 p_position) { NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); obstacle->set_position(p_position); @@ -1176,7 +1141,7 @@ Vector GodotNavigationServer3D::obstacle_get_vertices(RID p_obstacle) c return obstacle->get_vertices(); } -COMMAND_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers) { +void GodotNavigationServer3D::obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) { NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_NULL(obstacle); obstacle->set_avoidance_layers(p_layers); @@ -1227,10 +1192,40 @@ String GodotNavigationServer3D::get_baking_navigation_mesh_state_msg(Refset_generator_parsers(generator_parsers); + geometry_parser_owner.free(parser->self); + + } else { + ERR_PRINT("Attempted to free a NavigationServer RID that did not exist (or was already freed)."); + } +} + +void GodotNavigationServer3D::internal_free_map(RID p_object) { + NavMap3D *map = map_owner.get_or_null(p_object); + if (map) { // Removes any assigned region for (NavRegion3D *region : map->get_regions()) { map->remove_region(region); @@ -1260,10 +1255,12 @@ COMMAND_1(free_rid, RID, p_object) { active_maps.remove_at(map_index); } map_owner.free(p_object); + } +} - } else if (region_owner.owns(p_object)) { - NavRegion3D *region = region_owner.get_or_null(p_object); - +void GodotNavigationServer3D::internal_free_region(RID p_object) { + NavRegion3D *region = region_owner.get_or_null(p_object); + if (region) { // Removes this region from the map if assigned if (region->get_map() != nullptr) { region->get_map()->remove_region(region); @@ -1271,10 +1268,12 @@ COMMAND_1(free_rid, RID, p_object) { } region_owner.free(p_object); + } +} - } else if (link_owner.owns(p_object)) { - NavLink3D *link = link_owner.get_or_null(p_object); - +void GodotNavigationServer3D::internal_free_link(RID p_object) { + NavLink3D *link = link_owner.get_or_null(p_object); + if (link) { // Removes this link from the map if assigned if (link->get_map() != nullptr) { link->get_map()->remove_link(link); @@ -1282,25 +1281,6 @@ COMMAND_1(free_rid, RID, p_object) { } link_owner.free(p_object); - - } else if (agent_owner.owns(p_object)) { - internal_free_agent(p_object); - - } else if (obstacle_owner.owns(p_object)) { - internal_free_obstacle(p_object); - - } else if (geometry_parser_owner.owns(p_object)) { - RWLockWrite write_lock(geometry_parser_rwlock); - - NavMeshGeometryParser3D *parser = geometry_parser_owner.get_or_null(p_object); - ERR_FAIL_NULL(parser); - - generator_parsers.erase(parser); - NavMeshGenerator3D::get_singleton()->set_generator_parsers(generator_parsers); - geometry_parser_owner.free(parser->self); - - } else { - ERR_PRINT("Attempted to free a NavigationServer RID that did not exist (or was already freed)."); } } @@ -1336,26 +1316,26 @@ void GodotNavigationServer3D::set_active(bool p_active) { MutexLock lock(operations_mutex); active = p_active; -} -void GodotNavigationServer3D::flush_queries() { - MutexLock lock(commands_mutex); - MutexLock lock2(operations_mutex); - - for (SetCommand3D *command : commands) { - command->exec(this); - memdelete(command); + if (!active) { + pm_region_count = 0; + pm_agent_count = 0; + pm_link_count = 0; + pm_polygon_count = 0; + pm_edge_count = 0; + pm_edge_merge_count = 0; + pm_edge_connection_count = 0; + pm_edge_free_count = 0; + pm_obstacle_count = 0; } - commands.clear(); } void GodotNavigationServer3D::map_force_update(RID p_map) { + ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Forcing an update is only allowed from the main thread."); NavMap3D *map = map_owner.get_or_null(p_map); ERR_FAIL_NULL(map); - flush_queries(); - - map->sync(); + map->force_update(); } uint32_t GodotNavigationServer3D::map_get_iteration_id(RID p_map) const { @@ -1365,11 +1345,7 @@ uint32_t GodotNavigationServer3D::map_get_iteration_id(RID p_map) const { return map->get_iteration_id(); } -void GodotNavigationServer3D::sync() { - if (navmesh_generator_3d) { - navmesh_generator_3d->sync(); - } -} +void GodotNavigationServer3D::sync() {} void GodotNavigationServer3D::process(double p_delta_time) { // Called for each main loop iteration AFTER node and user script process() and BEFORE RenderingServer sync. @@ -1377,18 +1353,9 @@ void GodotNavigationServer3D::process(double p_delta_time) { // Use for things that (only) need to update once per main loop iteration and rendered frame or is visible to the user. // E.g. (final) sync of objects for this main loop iteration, updating rendered debug visuals, updating debug statistics, ... - sync(); -} - -void GodotNavigationServer3D::physics_process(double p_delta_time) { - // Called for each physics process step AFTER node and user script physics_process() and BEFORE PhysicsServer sync. - // Will NOT run reliably every rendered frame. If there is no physics step this function will not run. - // Use for physics or step depending calculations and updates where the result affects the next step calculation. - // E.g. anything physics sync related, avoidance simulations, physics space state queries, ... - // If physics process needs to play catchup this function will be called multiple times per frame so it should not hold - // costly updates that are not important outside the stepped calculations to avoid causing a physics performance death spiral. - - flush_queries(); + if (navmesh_generator_3d) { + navmesh_generator_3d->sync(); + } if (!active) { return; @@ -1405,20 +1372,18 @@ void GodotNavigationServer3D::physics_process(double p_delta_time) { int _new_pm_obstacle_count = 0; MutexLock lock(operations_mutex); - for (uint32_t i(0); i < active_maps.size(); i++) { - active_maps[i]->sync(); - active_maps[i]->step(p_delta_time); - active_maps[i]->dispatch_callbacks(); - - _new_pm_region_count += active_maps[i]->get_pm_region_count(); - _new_pm_agent_count += active_maps[i]->get_pm_agent_count(); - _new_pm_link_count += active_maps[i]->get_pm_link_count(); - _new_pm_polygon_count += active_maps[i]->get_pm_polygon_count(); - _new_pm_edge_count += active_maps[i]->get_pm_edge_count(); - _new_pm_edge_merge_count += active_maps[i]->get_pm_edge_merge_count(); - _new_pm_edge_connection_count += active_maps[i]->get_pm_edge_connection_count(); - _new_pm_edge_free_count += active_maps[i]->get_pm_edge_free_count(); - _new_pm_obstacle_count += active_maps[i]->get_pm_obstacle_count(); + for (NavMap3D *map : active_maps) { + map->process(p_delta_time); + + _new_pm_region_count += map->get_pm_region_count(); + _new_pm_agent_count += map->get_pm_agent_count(); + _new_pm_link_count += map->get_pm_link_count(); + _new_pm_polygon_count += map->get_pm_polygon_count(); + _new_pm_edge_count += map->get_pm_edge_count(); + _new_pm_edge_merge_count += map->get_pm_edge_merge_count(); + _new_pm_edge_connection_count += map->get_pm_edge_connection_count(); + _new_pm_edge_free_count += map->get_pm_edge_free_count(); + _new_pm_obstacle_count += map->get_pm_obstacle_count(); } pm_region_count = _new_pm_region_count; @@ -1432,6 +1397,25 @@ void GodotNavigationServer3D::physics_process(double p_delta_time) { pm_obstacle_count = _new_pm_obstacle_count; } +void GodotNavigationServer3D::physics_process(double p_delta_time) { + // Called for each physics process step AFTER node and user script physics_process() and BEFORE PhysicsServer sync. + // Will NOT run reliably every rendered frame. If there is no physics step this function will not run. + // Use for physics or step depending calculations and updates where the result affects the next step calculation. + // E.g. anything physics sync related, avoidance simulations, physics space state queries, ... + // If physics process needs to play catchup this function will be called multiple times per frame so it should not hold + // costly updates that are not important outside the stepped calculations to avoid causing a physics performance death spiral. + + if (!active) { + return; + } + + MutexLock lock(operations_mutex); + for (NavMap3D *map : active_maps) { + map->step(p_delta_time); + map->dispatch_callbacks(); + } +} + void GodotNavigationServer3D::init() { navmesh_generator_3d = memnew(NavMeshGenerator3D); RWLockRead read_lock(geometry_parser_rwlock); @@ -1439,7 +1423,6 @@ void GodotNavigationServer3D::init() { } void GodotNavigationServer3D::finish() { - flush_queries(); if (navmesh_generator_3d) { navmesh_generator_3d->finish(); memdelete(navmesh_generator_3d); @@ -1548,6 +1531,3 @@ int GodotNavigationServer3D::get_process_info(ProcessInfo p_info) const { return 0; } - -#undef COMMAND_1 -#undef COMMAND_2 diff --git a/modules/navigation_3d/3d/godot_navigation_server_3d.h b/modules/navigation_3d/3d/godot_navigation_server_3d.h index 58ec19931e9a..d7885b1e0189 100644 --- a/modules/navigation_3d/3d/godot_navigation_server_3d.h +++ b/modules/navigation_3d/3d/godot_navigation_server_3d.h @@ -43,34 +43,11 @@ #include "servers/navigation_3d/navigation_path_query_result_3d.h" #include "servers/navigation_3d/navigation_server_3d.h" -/// The commands are functions executed during the `sync` phase. - -#define MERGE_INTERNAL(A, B) A##B -#define MERGE(A, B) MERGE_INTERNAL(A, B) - -#define COMMAND_1(F_NAME, T_0, D_0) \ - virtual void F_NAME(T_0 D_0) override; \ - void MERGE(_cmd_, F_NAME)(T_0 D_0) - -#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \ - virtual void F_NAME(T_0 D_0, T_1 D_1) override; \ - void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1) - -class GodotNavigationServer3D; class NavMeshGenerator3D; -struct SetCommand3D { - virtual ~SetCommand3D() {} - virtual void exec(GodotNavigationServer3D *server) = 0; -}; - class GodotNavigationServer3D : public NavigationServer3D { - Mutex commands_mutex; - /// Mutex used to make any operation threadsafe. Mutex operations_mutex; - LocalVector commands; - mutable RID_Owner link_owner; mutable RID_Owner map_owner; mutable RID_Owner region_owner; @@ -97,33 +74,31 @@ class GodotNavigationServer3D : public NavigationServer3D { GodotNavigationServer3D(); virtual ~GodotNavigationServer3D(); - void add_command(SetCommand3D *command); - virtual TypedArray get_maps() const override; virtual RID map_create() override; - COMMAND_2(map_set_active, RID, p_map, bool, p_active); + virtual void map_set_active(RID p_map, bool p_active) override; virtual bool map_is_active(RID p_map) const override; - COMMAND_2(map_set_up, RID, p_map, Vector3, p_up); + virtual void map_set_up(RID p_map, Vector3 p_up) override; virtual Vector3 map_get_up(RID p_map) const override; - COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size); + virtual void map_set_cell_size(RID p_map, real_t p_cell_size) override; virtual real_t map_get_cell_size(RID p_map) const override; - COMMAND_2(map_set_cell_height, RID, p_map, real_t, p_cell_height); + virtual void map_set_cell_height(RID p_map, real_t p_cell_height) override; virtual real_t map_get_cell_height(RID p_map) const override; - COMMAND_2(map_set_merge_rasterizer_cell_scale, RID, p_map, float, p_value); + virtual void map_set_merge_rasterizer_cell_scale(RID p_map, float p_value) override; virtual float map_get_merge_rasterizer_cell_scale(RID p_map) const override; - COMMAND_2(map_set_use_edge_connections, RID, p_map, bool, p_enabled); + virtual void map_set_use_edge_connections(RID p_map, bool p_enabled) override; virtual bool map_get_use_edge_connections(RID p_map) const override; - COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin); + virtual void map_set_edge_connection_margin(RID p_map, real_t p_connection_margin) override; virtual real_t map_get_edge_connection_margin(RID p_map) const override; - COMMAND_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius); + virtual void map_set_link_connection_radius(RID p_map, real_t p_connection_radius) override; virtual real_t map_get_link_connection_radius(RID p_map) const override; virtual Vector map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers = 1) override; @@ -141,40 +116,41 @@ class GodotNavigationServer3D : public NavigationServer3D { virtual void map_force_update(RID p_map) override; virtual uint32_t map_get_iteration_id(RID p_map) const override; - COMMAND_2(map_set_use_async_iterations, RID, p_map, bool, p_enabled); + virtual void map_set_use_async_iterations(RID p_map, bool p_enabled) override; virtual bool map_get_use_async_iterations(RID p_map) const override; virtual Vector3 map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const override; virtual RID region_create() override; + virtual void region_force_update(RID p_region) override; virtual uint32_t region_get_iteration_id(RID p_region) const override; - COMMAND_2(region_set_use_async_iterations, RID, p_region, bool, p_enabled); + virtual void region_set_use_async_iterations(RID p_region, bool p_enabled) override; virtual bool region_get_use_async_iterations(RID p_region) const override; - COMMAND_2(region_set_enabled, RID, p_region, bool, p_enabled); + virtual void region_set_enabled(RID p_region, bool p_enabled) override; virtual bool region_get_enabled(RID p_region) const override; - COMMAND_2(region_set_use_edge_connections, RID, p_region, bool, p_enabled); + virtual void region_set_use_edge_connections(RID p_region, bool p_enabled) override; virtual bool region_get_use_edge_connections(RID p_region) const override; - COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost); + virtual void region_set_enter_cost(RID p_region, real_t p_enter_cost) override; virtual real_t region_get_enter_cost(RID p_region) const override; - COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost); + virtual void region_set_travel_cost(RID p_region, real_t p_travel_cost) override; virtual real_t region_get_travel_cost(RID p_region) const override; - COMMAND_2(region_set_owner_id, RID, p_region, ObjectID, p_owner_id); + virtual void region_set_owner_id(RID p_region, ObjectID p_owner_id) override; virtual ObjectID region_get_owner_id(RID p_region) const override; virtual bool region_owns_point(RID p_region, const Vector3 &p_point) const override; - COMMAND_2(region_set_map, RID, p_region, RID, p_map); + virtual void region_set_map(RID p_region, RID p_map) override; virtual RID region_get_map(RID p_region) const override; - COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers); + virtual void region_set_navigation_layers(RID p_region, uint32_t p_navigation_layers) override; virtual uint32_t region_get_navigation_layers(RID p_region) const override; - COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform); + virtual void region_set_transform(RID p_region, Transform3D p_transform) override; virtual Transform3D region_get_transform(RID p_region) const override; - COMMAND_2(region_set_navigation_mesh, RID, p_region, Ref, p_navigation_mesh); + virtual void region_set_navigation_mesh(RID p_region, Ref p_navigation_mesh) override; #ifndef DISABLE_DEPRECATED virtual void region_bake_navigation_mesh(Ref p_navigation_mesh, Node *p_root_node) override; #endif // DISABLE_DEPRECATED @@ -188,84 +164,85 @@ class GodotNavigationServer3D : public NavigationServer3D { virtual AABB region_get_bounds(RID p_region) const override; virtual RID link_create() override; + virtual void link_force_update(RID p_link) override; virtual uint32_t link_get_iteration_id(RID p_link) const override; - COMMAND_2(link_set_map, RID, p_link, RID, p_map); + virtual void link_set_map(RID p_link, RID p_map) override; virtual RID link_get_map(RID p_link) const override; - COMMAND_2(link_set_enabled, RID, p_link, bool, p_enabled); + virtual void link_set_enabled(RID p_link, bool p_enabled) override; virtual bool link_get_enabled(RID p_link) const override; - COMMAND_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional); + virtual void link_set_bidirectional(RID p_link, bool p_bidirectional) override; virtual bool link_is_bidirectional(RID p_link) const override; - COMMAND_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers); + virtual void link_set_navigation_layers(RID p_link, uint32_t p_navigation_layers) override; virtual uint32_t link_get_navigation_layers(RID p_link) const override; - COMMAND_2(link_set_start_position, RID, p_link, Vector3, p_position); + virtual void link_set_start_position(RID p_link, Vector3 p_position) override; virtual Vector3 link_get_start_position(RID p_link) const override; - COMMAND_2(link_set_end_position, RID, p_link, Vector3, p_position); + virtual void link_set_end_position(RID p_link, Vector3 p_position) override; virtual Vector3 link_get_end_position(RID p_link) const override; - COMMAND_2(link_set_enter_cost, RID, p_link, real_t, p_enter_cost); + virtual void link_set_enter_cost(RID p_link, real_t p_enter_cost) override; virtual real_t link_get_enter_cost(RID p_link) const override; - COMMAND_2(link_set_travel_cost, RID, p_link, real_t, p_travel_cost); + virtual void link_set_travel_cost(RID p_link, real_t p_travel_cost) override; virtual real_t link_get_travel_cost(RID p_link) const override; - COMMAND_2(link_set_owner_id, RID, p_link, ObjectID, p_owner_id); + virtual void link_set_owner_id(RID p_link, ObjectID p_owner_id) override; virtual ObjectID link_get_owner_id(RID p_link) const override; virtual RID agent_create() override; - COMMAND_2(agent_set_avoidance_enabled, RID, p_agent, bool, p_enabled); + virtual void agent_set_avoidance_enabled(RID p_agent, bool p_enabled) override; virtual bool agent_get_avoidance_enabled(RID p_agent) const override; - COMMAND_2(agent_set_use_3d_avoidance, RID, p_agent, bool, p_enabled); + virtual void agent_set_use_3d_avoidance(RID p_agent, bool p_enabled) override; virtual bool agent_get_use_3d_avoidance(RID p_agent) const override; - COMMAND_2(agent_set_map, RID, p_agent, RID, p_map); + virtual void agent_set_map(RID p_agent, RID p_map) override; virtual RID agent_get_map(RID p_agent) const override; - COMMAND_2(agent_set_paused, RID, p_agent, bool, p_paused); + virtual void agent_set_paused(RID p_agent, bool p_paused) override; virtual bool agent_get_paused(RID p_agent) const override; - COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance); + virtual void agent_set_neighbor_distance(RID p_agent, real_t p_distance) override; virtual real_t agent_get_neighbor_distance(RID p_agent) const override; - COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count); + virtual void agent_set_max_neighbors(RID p_agent, int p_count) override; virtual int agent_get_max_neighbors(RID p_agent) const override; - COMMAND_2(agent_set_time_horizon_agents, RID, p_agent, real_t, p_time_horizon); + virtual void agent_set_time_horizon_agents(RID p_agent, real_t p_time_horizon) override; virtual real_t agent_get_time_horizon_agents(RID p_agent) const override; - COMMAND_2(agent_set_time_horizon_obstacles, RID, p_agent, real_t, p_time_horizon); + virtual void agent_set_time_horizon_obstacles(RID p_agent, real_t p_time_horizon) override; virtual real_t agent_get_time_horizon_obstacles(RID p_agent) const override; - COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius); + virtual void agent_set_radius(RID p_agent, real_t p_radius) override; virtual real_t agent_get_radius(RID p_agent) const override; - COMMAND_2(agent_set_height, RID, p_agent, real_t, p_height); + virtual void agent_set_height(RID p_agent, real_t p_height) override; virtual real_t agent_get_height(RID p_agent) const override; - COMMAND_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed); + virtual void agent_set_max_speed(RID p_agent, real_t p_max_speed) override; virtual real_t agent_get_max_speed(RID p_agent) const override; - COMMAND_2(agent_set_velocity, RID, p_agent, Vector3, p_velocity); + virtual void agent_set_velocity(RID p_agent, Vector3 p_velocity) override; virtual Vector3 agent_get_velocity(RID p_agent) const override; - COMMAND_2(agent_set_velocity_forced, RID, p_agent, Vector3, p_velocity); - COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position); + virtual void agent_set_velocity_forced(RID p_agent, Vector3 p_velocity) override; + virtual void agent_set_position(RID p_agent, Vector3 p_position) override; virtual Vector3 agent_get_position(RID p_agent) const override; virtual bool agent_is_map_changed(RID p_agent) const override; - COMMAND_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback); + virtual void agent_set_avoidance_callback(RID p_agent, Callable p_callback) override; virtual bool agent_has_avoidance_callback(RID p_agent) const override; - COMMAND_2(agent_set_avoidance_layers, RID, p_agent, uint32_t, p_layers); + virtual void agent_set_avoidance_layers(RID p_agent, uint32_t p_layers) override; virtual uint32_t agent_get_avoidance_layers(RID p_agent) const override; - COMMAND_2(agent_set_avoidance_mask, RID, p_agent, uint32_t, p_mask); + virtual void agent_set_avoidance_mask(RID p_agent, uint32_t p_mask) override; virtual uint32_t agent_get_avoidance_mask(RID p_agent) const override; - COMMAND_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority); + virtual void agent_set_avoidance_priority(RID p_agent, real_t p_priority) override; virtual real_t agent_get_avoidance_priority(RID p_agent) const override; virtual RID obstacle_create() override; - COMMAND_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled); + virtual void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled) override; virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const override; - COMMAND_2(obstacle_set_use_3d_avoidance, RID, p_obstacle, bool, p_enabled); + virtual void obstacle_set_use_3d_avoidance(RID p_obstacle, bool p_enabled) override; virtual bool obstacle_get_use_3d_avoidance(RID p_obstacle) const override; - COMMAND_2(obstacle_set_map, RID, p_obstacle, RID, p_map); + virtual void obstacle_set_map(RID p_obstacle, RID p_map) override; virtual RID obstacle_get_map(RID p_obstacle) const override; - COMMAND_2(obstacle_set_paused, RID, p_obstacle, bool, p_paused); + virtual void obstacle_set_paused(RID p_obstacle, bool p_paused) override; virtual bool obstacle_get_paused(RID p_obstacle) const override; - COMMAND_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius); + virtual void obstacle_set_radius(RID p_obstacle, real_t p_radius) override; virtual real_t obstacle_get_radius(RID p_obstacle) const override; - COMMAND_2(obstacle_set_velocity, RID, p_obstacle, Vector3, p_velocity); + virtual void obstacle_set_velocity(RID p_obstacle, Vector3 p_velocity) override; virtual Vector3 obstacle_get_velocity(RID p_obstacle) const override; - COMMAND_2(obstacle_set_position, RID, p_obstacle, Vector3, p_position); + virtual void obstacle_set_position(RID p_obstacle, Vector3 p_position) override; virtual Vector3 obstacle_get_position(RID p_obstacle) const override; - COMMAND_2(obstacle_set_height, RID, p_obstacle, real_t, p_height); + virtual void obstacle_set_height(RID p_obstacle, real_t p_height) override; virtual real_t obstacle_get_height(RID p_obstacle) const override; virtual void obstacle_set_vertices(RID p_obstacle, const Vector &p_vertices) override; virtual Vector obstacle_get_vertices(RID p_obstacle) const override; - COMMAND_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers); + virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) override; virtual uint32_t obstacle_get_avoidance_layers(RID p_obstacle) const override; virtual void parse_source_geometry_data(const Ref &p_navigation_mesh, const Ref &p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable()) override; @@ -280,12 +257,10 @@ class GodotNavigationServer3D : public NavigationServer3D { virtual Vector simplify_path(const Vector &p_path, real_t p_epsilon) override; public: - COMMAND_1(free_rid, RID, p_object); + virtual void free_rid(RID p_object) override; virtual void set_active(bool p_active) override; - void flush_queries(); - virtual void process(double p_delta_time) override; virtual void physics_process(double p_delta_time) override; virtual void init() override; @@ -297,9 +272,9 @@ class GodotNavigationServer3D : public NavigationServer3D { int get_process_info(ProcessInfo p_info) const override; private: + void internal_free_map(RID p_object); + void internal_free_region(RID p_object); + void internal_free_link(RID p_object); void internal_free_agent(RID p_object); void internal_free_obstacle(RID p_object); }; - -#undef COMMAND_1 -#undef COMMAND_2 diff --git a/modules/navigation_3d/nav_agent_3d.cpp b/modules/navigation_3d/nav_agent_3d.cpp index 8e30fa0d8b97..37e8b0e8f320 100644 --- a/modules/navigation_3d/nav_agent_3d.cpp +++ b/modules/navigation_3d/nav_agent_3d.cpp @@ -153,11 +153,6 @@ void NavAgent3D::dispatch_avoidance_callback() { void NavAgent3D::set_neighbor_distance(real_t p_neighbor_distance) { neighbor_distance = p_neighbor_distance; - if (use_3d_avoidance) { - rvo_agent_3d.neighborDist_ = neighbor_distance; - } else { - rvo_agent_2d.neighborDist_ = neighbor_distance; - } agent_dirty = true; request_sync(); @@ -165,11 +160,6 @@ void NavAgent3D::set_neighbor_distance(real_t p_neighbor_distance) { void NavAgent3D::set_max_neighbors(int p_max_neighbors) { max_neighbors = p_max_neighbors; - if (use_3d_avoidance) { - rvo_agent_3d.maxNeighbors_ = max_neighbors; - } else { - rvo_agent_2d.maxNeighbors_ = max_neighbors; - } agent_dirty = true; request_sync(); @@ -177,11 +167,6 @@ void NavAgent3D::set_max_neighbors(int p_max_neighbors) { void NavAgent3D::set_time_horizon_agents(real_t p_time_horizon) { time_horizon_agents = p_time_horizon; - if (use_3d_avoidance) { - rvo_agent_3d.timeHorizon_ = time_horizon_agents; - } else { - rvo_agent_2d.timeHorizon_ = time_horizon_agents; - } agent_dirty = true; request_sync(); @@ -189,11 +174,6 @@ void NavAgent3D::set_time_horizon_agents(real_t p_time_horizon) { void NavAgent3D::set_time_horizon_obstacles(real_t p_time_horizon) { time_horizon_obstacles = p_time_horizon; - if (use_3d_avoidance) { - rvo_agent_3d.timeHorizonObst_ = time_horizon_obstacles; - } else { - rvo_agent_2d.timeHorizonObst_ = time_horizon_obstacles; - } agent_dirty = true; request_sync(); @@ -201,11 +181,6 @@ void NavAgent3D::set_time_horizon_obstacles(real_t p_time_horizon) { void NavAgent3D::set_radius(real_t p_radius) { radius = p_radius; - if (use_3d_avoidance) { - rvo_agent_3d.radius_ = radius; - } else { - rvo_agent_2d.radius_ = radius; - } agent_dirty = true; request_sync(); @@ -213,11 +188,6 @@ void NavAgent3D::set_radius(real_t p_radius) { void NavAgent3D::set_height(real_t p_height) { height = p_height; - if (use_3d_avoidance) { - rvo_agent_3d.height_ = height; - } else { - rvo_agent_2d.height_ = height; - } agent_dirty = true; request_sync(); @@ -225,13 +195,6 @@ void NavAgent3D::set_height(real_t p_height) { void NavAgent3D::set_max_speed(real_t p_max_speed) { max_speed = p_max_speed; - if (avoidance_enabled) { - if (use_3d_avoidance) { - rvo_agent_3d.maxSpeed_ = max_speed; - } else { - rvo_agent_2d.maxSpeed_ = max_speed; - } - } agent_dirty = true; request_sync(); @@ -239,14 +202,6 @@ void NavAgent3D::set_max_speed(real_t p_max_speed) { void NavAgent3D::set_position(const Vector3 p_position) { position = p_position; - if (avoidance_enabled) { - if (use_3d_avoidance) { - rvo_agent_3d.position_ = RVO3D::Vector3(p_position.x, p_position.y, p_position.z); - } else { - rvo_agent_2d.elevation_ = p_position.y; - rvo_agent_2d.position_ = RVO2D::Vector2(p_position.x, p_position.z); - } - } agent_dirty = true; request_sync(); @@ -260,13 +215,6 @@ void NavAgent3D::set_velocity(const Vector3 p_velocity) { // Sets the "wanted" velocity for an agent as a suggestion // This velocity is not guaranteed, RVO simulation will only try to fulfill it velocity = p_velocity; - if (avoidance_enabled) { - if (use_3d_avoidance) { - rvo_agent_3d.prefVelocity_ = RVO3D::Vector3(velocity.x, velocity.y, velocity.z); - } else { - rvo_agent_2d.prefVelocity_ = RVO2D::Vector2(velocity.x, velocity.z); - } - } agent_dirty = true; request_sync(); @@ -303,11 +251,6 @@ void NavAgent3D::update() { void NavAgent3D::set_avoidance_mask(uint32_t p_mask) { avoidance_mask = p_mask; - if (use_3d_avoidance) { - rvo_agent_3d.avoidance_mask_ = avoidance_mask; - } else { - rvo_agent_2d.avoidance_mask_ = avoidance_mask; - } agent_dirty = true; request_sync(); @@ -315,11 +258,6 @@ void NavAgent3D::set_avoidance_mask(uint32_t p_mask) { void NavAgent3D::set_avoidance_layers(uint32_t p_layers) { avoidance_layers = p_layers; - if (use_3d_avoidance) { - rvo_agent_3d.avoidance_layers_ = avoidance_layers; - } else { - rvo_agent_2d.avoidance_layers_ = avoidance_layers; - } agent_dirty = true; request_sync(); @@ -329,11 +267,6 @@ void NavAgent3D::set_avoidance_priority(real_t p_priority) { ERR_FAIL_COND_MSG(p_priority < 0.0, "Avoidance priority must be between 0.0 and 1.0 inclusive."); ERR_FAIL_COND_MSG(p_priority > 1.0, "Avoidance priority must be between 0.0 and 1.0 inclusive."); avoidance_priority = p_priority; - if (use_3d_avoidance) { - rvo_agent_3d.avoidance_priority_ = avoidance_priority; - } else { - rvo_agent_2d.avoidance_priority_ = avoidance_priority; - } agent_dirty = true; request_sync(); @@ -345,6 +278,39 @@ bool NavAgent3D::is_dirty() const { void NavAgent3D::sync() { agent_dirty = false; + + if (use_3d_avoidance) { + rvo_agent_3d.neighborDist_ = neighbor_distance; + rvo_agent_3d.maxNeighbors_ = max_neighbors; + rvo_agent_3d.timeHorizon_ = time_horizon_agents; + rvo_agent_3d.timeHorizonObst_ = time_horizon_obstacles; + rvo_agent_3d.radius_ = radius; + rvo_agent_3d.maxSpeed_ = max_speed; + rvo_agent_3d.position_ = RVO3D::Vector3(position.x, position.y, position.z); + // Replacing the internal velocity directly causes major jitter / bugs due to unpredictable velocity jumps, left line here for testing. + //rvo_agent_3d.velocity_ = RVO3D::Vector3(velocity.x, velocity.y ,velocity.z); + rvo_agent_3d.prefVelocity_ = RVO3D::Vector3(velocity.x, velocity.y, velocity.z); + rvo_agent_3d.height_ = height; + rvo_agent_3d.avoidance_layers_ = avoidance_layers; + rvo_agent_3d.avoidance_mask_ = avoidance_mask; + rvo_agent_3d.avoidance_priority_ = avoidance_priority; + } else { + rvo_agent_2d.neighborDist_ = neighbor_distance; + rvo_agent_2d.maxNeighbors_ = max_neighbors; + rvo_agent_2d.timeHorizon_ = time_horizon_agents; + rvo_agent_2d.timeHorizonObst_ = time_horizon_obstacles; + rvo_agent_2d.radius_ = radius; + rvo_agent_2d.maxSpeed_ = max_speed; + rvo_agent_2d.position_ = RVO2D::Vector2(position.x, position.z); + rvo_agent_2d.elevation_ = position.y; + // Replacing the internal velocity directly causes major jitter / bugs due to unpredictable velocity jumps, left line here for testing. + //rvo_agent_2d.velocity_ = RVO2D::Vector2(velocity.x, velocity.z); + rvo_agent_2d.prefVelocity_ = RVO2D::Vector2(velocity.x, velocity.z); + rvo_agent_2d.height_ = height; + rvo_agent_2d.avoidance_layers_ = avoidance_layers; + rvo_agent_2d.avoidance_mask_ = avoidance_mask; + rvo_agent_2d.avoidance_priority_ = avoidance_priority; + } } const Dictionary NavAgent3D::get_avoidance_data() const { diff --git a/modules/navigation_3d/nav_link_3d.cpp b/modules/navigation_3d/nav_link_3d.cpp index 29682d1e2e0d..c9b178625f45 100644 --- a/modules/navigation_3d/nav_link_3d.cpp +++ b/modules/navigation_3d/nav_link_3d.cpp @@ -201,6 +201,14 @@ Ref NavLink3D::get_iteration() { return iteration; } +void NavLink3D::force_update() { + iteration_dirty = true; + iteration_building = false; + iteration_ready = false; + + sync(); +} + NavLink3D::NavLink3D() : sync_dirty_request_list_element(this) { type = NavigationEnums3D::PathSegmentType::PATH_SEGMENT_TYPE_LINK; diff --git a/modules/navigation_3d/nav_link_3d.h b/modules/navigation_3d/nav_link_3d.h index e6b54d2fa8b6..61e814cfeb19 100644 --- a/modules/navigation_3d/nav_link_3d.h +++ b/modules/navigation_3d/nav_link_3d.h @@ -115,4 +115,6 @@ class NavLink3D : public NavBase3D { void cancel_sync_request(); Ref get_iteration(); + + void force_update(); }; diff --git a/modules/navigation_3d/nav_map_3d.cpp b/modules/navigation_3d/nav_map_3d.cpp index 010bd8fa3600..ea49416d0229 100644 --- a/modules/navigation_3d/nav_map_3d.cpp +++ b/modules/navigation_3d/nav_map_3d.cpp @@ -233,11 +233,13 @@ ClosestPointQueryResult NavMap3D::get_closest_point_info(const Vector3 &p_point) void NavMap3D::add_region(NavRegion3D *p_region) { DEV_ASSERT(!regions.has(p_region)); + RWLockWrite write_lock(rwlock_regions); regions.push_back(p_region); iteration_dirty = true; } void NavMap3D::remove_region(NavRegion3D *p_region) { + RWLockWrite write_lock(rwlock_regions); if (regions.erase_unordered(p_region)) { iteration_dirty = true; } @@ -246,11 +248,13 @@ void NavMap3D::remove_region(NavRegion3D *p_region) { void NavMap3D::add_link(NavLink3D *p_link) { DEV_ASSERT(!links.has(p_link)); + RWLockWrite write_lock(rwlock_links); links.push_back(p_link); iteration_dirty = true; } void NavMap3D::remove_link(NavLink3D *p_link) { + RWLockWrite write_lock(rwlock_links); if (links.erase_unordered(p_link)) { iteration_dirty = true; } @@ -371,6 +375,9 @@ void NavMap3D::_build_iteration() { next_map_iteration.clear(); + rwlock_regions.read_lock(); + rwlock_links.read_lock(); + next_map_iteration.region_iterations.resize(regions.size()); next_map_iteration.link_iterations.resize(links.size()); @@ -387,6 +394,9 @@ void NavMap3D::_build_iteration() { next_map_iteration.link_iterations[link_id_count++] = link_iteration; } + rwlock_regions.read_unlock(); + rwlock_links.read_unlock(); + next_map_iteration.map_up = get_up(); iteration_build.map_iteration = &next_map_iteration; @@ -426,13 +436,27 @@ void NavMap3D::_sync_iteration() { iteration_ready = false; } -void NavMap3D::sync() { +void NavMap3D::process(double p_delta_time) { + sync_navigation(); + // Performance Monitor. performance_data.pm_region_count = regions.size(); performance_data.pm_agent_count = agents.size(); performance_data.pm_link_count = links.size(); performance_data.pm_obstacle_count = obstacles.size(); + performance_data.pm_polygon_count = 0; + performance_data.pm_edge_count = 0; + performance_data.pm_edge_merge_count = 0; + + for (NavRegion3D *region : regions) { + performance_data.pm_polygon_count += region->get_pm_polygon_count(); + performance_data.pm_edge_count += region->get_pm_edge_count(); + performance_data.pm_edge_merge_count += region->get_pm_edge_merge_count(); + } +} + +void NavMap3D::sync_navigation() { _sync_async_tasks(); _sync_dirty_map_update_requests(); @@ -456,21 +480,9 @@ void NavMap3D::sync() { } map_settings_dirty = false; - - _sync_avoidance(); - - performance_data.pm_polygon_count = 0; - performance_data.pm_edge_count = 0; - performance_data.pm_edge_merge_count = 0; - - for (NavRegion3D *region : regions) { - performance_data.pm_polygon_count += region->get_pm_polygon_count(); - performance_data.pm_edge_count += region->get_pm_edge_count(); - performance_data.pm_edge_merge_count += region->get_pm_edge_merge_count(); - } } -void NavMap3D::_sync_avoidance() { +void NavMap3D::sync_avoidance() { _sync_dirty_avoidance_update_requests(); if (obstacles_dirty || agents_dirty) { @@ -593,6 +605,7 @@ void NavMap3D::_update_rvo_simulation() { } void NavMap3D::compute_single_avoidance_step_2d(uint32_t index, NavAgent3D **agent) { + (*(agent + index))->sync(); (*(agent + index))->get_rvo_agent_2d()->computeNeighbors(&rvo_simulation_2d); (*(agent + index))->get_rvo_agent_2d()->computeNewVelocity(&rvo_simulation_2d); (*(agent + index))->get_rvo_agent_2d()->update(&rvo_simulation_2d); @@ -600,6 +613,7 @@ void NavMap3D::compute_single_avoidance_step_2d(uint32_t index, NavAgent3D **age } void NavMap3D::compute_single_avoidance_step_3d(uint32_t index, NavAgent3D **agent) { + (*(agent + index))->sync(); (*(agent + index))->get_rvo_agent_3d()->computeNeighbors(&rvo_simulation_3d); (*(agent + index))->get_rvo_agent_3d()->computeNewVelocity(&rvo_simulation_3d); (*(agent + index))->get_rvo_agent_3d()->update(&rvo_simulation_3d); @@ -607,6 +621,8 @@ void NavMap3D::compute_single_avoidance_step_3d(uint32_t index, NavAgent3D **age } void NavMap3D::step(double p_delta_time) { + sync_avoidance(); + rvo_simulation_2d.setTimeStep(float(p_delta_time)); rvo_simulation_3d.setTimeStep(float(p_delta_time)); @@ -616,6 +632,7 @@ void NavMap3D::step(double p_delta_time) { WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); } else { for (NavAgent3D *agent : active_2d_avoidance_agents) { + agent->sync(); agent->get_rvo_agent_2d()->computeNeighbors(&rvo_simulation_2d); agent->get_rvo_agent_2d()->computeNewVelocity(&rvo_simulation_2d); agent->get_rvo_agent_2d()->update(&rvo_simulation_2d); @@ -630,6 +647,7 @@ void NavMap3D::step(double p_delta_time) { WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task); } else { for (NavAgent3D *agent : active_3d_avoidance_agents) { + agent->sync(); agent->get_rvo_agent_3d()->computeNeighbors(&rvo_simulation_3d); agent->get_rvo_agent_3d()->computeNewVelocity(&rvo_simulation_3d); agent->get_rvo_agent_3d()->update(&rvo_simulation_3d); @@ -852,6 +870,26 @@ bool NavMap3D::get_use_async_iterations() const { return use_async_iterations; } +void NavMap3D::force_update() { + if (iteration_build_thread_task_id != WorkerThreadPool::INVALID_TASK_ID) { + WorkerThreadPool::get_singleton()->wait_for_task_completion(iteration_build_thread_task_id); + iteration_build_thread_task_id = WorkerThreadPool::INVALID_TASK_ID; + iteration_building = false; + iteration_ready = true; + } + + iteration_dirty = true; + iteration_building = false; + iteration_ready = false; + + bool used_use_async_iterations = use_async_iterations; + use_async_iterations = false; + + sync_navigation(); + + use_async_iterations = used_use_async_iterations; +} + NavMap3D::NavMap3D() { 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_3d/nav_map_3d.h b/modules/navigation_3d/nav_map_3d.h index 0f18dd3454de..505b2b118e55 100644 --- a/modules/navigation_3d/nav_map_3d.h +++ b/modules/navigation_3d/nav_map_3d.h @@ -75,9 +75,11 @@ class NavMap3D : public NavRid3D { /// Map regions LocalVector regions; + RWLock rwlock_regions; /// Map links LocalVector links; + RWLock rwlock_links; /// RVO avoidance worlds RVO2D::RVOSimulator2D rvo_simulation_2d; @@ -235,7 +237,9 @@ class NavMap3D : public NavRid3D { Vector3 get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const; - void sync(); + void sync_navigation(); + void sync_avoidance(); + void process(double p_delta_time); void step(double p_delta_time); void dispatch_callbacks(); @@ -270,6 +274,8 @@ class NavMap3D : public NavRid3D { void set_use_async_iterations(bool p_enabled); bool get_use_async_iterations() const; + void force_update(); + private: void _sync_dirty_map_update_requests(); void _sync_dirty_avoidance_update_requests(); @@ -280,7 +286,6 @@ class NavMap3D : public NavRid3D { void compute_single_avoidance_step_2d(uint32_t index, NavAgent3D **agent); void compute_single_avoidance_step_3d(uint32_t index, NavAgent3D **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_3d/nav_region_3d.cpp b/modules/navigation_3d/nav_region_3d.cpp index f4c2a46eb9b2..3bf9d040290f 100644 --- a/modules/navigation_3d/nav_region_3d.cpp +++ b/modules/navigation_3d/nav_region_3d.cpp @@ -354,6 +354,26 @@ bool NavRegion3D::get_use_async_iterations() const { return use_async_iterations; } +void NavRegion3D::force_update() { + if (iteration_build_thread_task_id != WorkerThreadPool::INVALID_TASK_ID) { + WorkerThreadPool::get_singleton()->wait_for_task_completion(iteration_build_thread_task_id); + iteration_build_thread_task_id = WorkerThreadPool::INVALID_TASK_ID; + iteration_building = false; + iteration_ready = true; + } + + iteration_dirty = true; + iteration_building = false; + iteration_ready = false; + + bool used_use_async_iterations = use_async_iterations; + use_async_iterations = false; + + sync(); + + use_async_iterations = used_use_async_iterations; +} + NavRegion3D::NavRegion3D() : sync_dirty_request_list_element(this), async_list_element(this) { type = NavigationEnums3D::PathSegmentType::PATH_SEGMENT_TYPE_REGION; diff --git a/modules/navigation_3d/nav_region_3d.h b/modules/navigation_3d/nav_region_3d.h index 756aefc4b3f1..dcf04b00a979 100644 --- a/modules/navigation_3d/nav_region_3d.h +++ b/modules/navigation_3d/nav_region_3d.h @@ -131,4 +131,6 @@ class NavRegion3D : public NavBase3D { void set_use_async_iterations(bool p_enabled); bool get_use_async_iterations() const; + + void force_update(); }; diff --git a/servers/navigation_3d/navigation_server_3d.cpp b/servers/navigation_3d/navigation_server_3d.cpp index ed0f05ef2f17..fa0cef749c09 100644 --- a/servers/navigation_3d/navigation_server_3d.cpp +++ b/servers/navigation_3d/navigation_server_3d.cpp @@ -82,6 +82,7 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("query_path", "parameters", "result", "callback"), &NavigationServer3D::query_path, DEFVAL(Callable())); ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer3D::region_create); + ClassDB::bind_method(D_METHOD("region_force_update", "region"), &NavigationServer3D::region_force_update); ClassDB::bind_method(D_METHOD("region_get_iteration_id", "region"), &NavigationServer3D::region_get_iteration_id); ClassDB::bind_method(D_METHOD("region_set_use_async_iterations", "region", "enabled"), &NavigationServer3D::region_set_use_async_iterations); ClassDB::bind_method(D_METHOD("region_get_use_async_iterations", "region"), &NavigationServer3D::region_get_use_async_iterations); @@ -116,6 +117,7 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("region_get_bounds", "region"), &NavigationServer3D::region_get_bounds); ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer3D::link_create); + ClassDB::bind_method(D_METHOD("link_force_update", "link"), &NavigationServer3D::link_force_update); ClassDB::bind_method(D_METHOD("link_get_iteration_id", "link"), &NavigationServer3D::link_get_iteration_id); ClassDB::bind_method(D_METHOD("link_set_map", "link", "map"), &NavigationServer3D::link_set_map); ClassDB::bind_method(D_METHOD("link_get_map", "link"), &NavigationServer3D::link_get_map); diff --git a/servers/navigation_3d/navigation_server_3d.h b/servers/navigation_3d/navigation_server_3d.h index cb02194a15ee..017c7aadd05b 100644 --- a/servers/navigation_3d/navigation_server_3d.h +++ b/servers/navigation_3d/navigation_server_3d.h @@ -107,6 +107,7 @@ class NavigationServer3D : public Object { /* REGION API */ virtual RID region_create() = 0; + virtual void region_force_update(RID p_region) = 0; virtual uint32_t region_get_iteration_id(RID p_region) const = 0; virtual void region_set_use_async_iterations(RID p_region, bool p_enabled) = 0; @@ -158,6 +159,7 @@ class NavigationServer3D : public Object { /* LINK API */ virtual RID link_create() = 0; + virtual void link_force_update(RID p_link) = 0; virtual uint32_t link_get_iteration_id(RID p_link) const = 0; virtual void link_set_map(RID p_link, RID p_map) = 0; diff --git a/servers/navigation_3d/navigation_server_3d_dummy.h b/servers/navigation_3d/navigation_server_3d_dummy.h index 686d91c8ebdb..c395203c0402 100644 --- a/servers/navigation_3d/navigation_server_3d_dummy.h +++ b/servers/navigation_3d/navigation_server_3d_dummy.h @@ -70,6 +70,7 @@ class NavigationServer3DDummy : public NavigationServer3D { bool map_get_use_async_iterations(RID p_map) const override { return false; } RID region_create() override { return RID(); } + void region_force_update(RID p_region) override {} uint32_t region_get_iteration_id(RID p_region) const override { return 0; } void region_set_use_async_iterations(RID p_region, bool p_enabled) override {} bool region_get_use_async_iterations(RID p_region) const override { return false; } @@ -104,6 +105,7 @@ class NavigationServer3DDummy : public NavigationServer3D { AABB region_get_bounds(RID p_region) const override { return AABB(); } RID link_create() override { return RID(); } + void link_force_update(RID p_link) override {} uint32_t link_get_iteration_id(RID p_link) const override { return 0; } void link_set_map(RID p_link, RID p_map) override {} RID link_get_map(RID p_link) const override { return RID(); } diff --git a/tests/servers/test_navigation_server_3d.h b/tests/servers/test_navigation_server_3d.h index f16ed014dd71..96ce3ceb0fe4 100644 --- a/tests/servers/test_navigation_server_3d.h +++ b/tests/servers/test_navigation_server_3d.h @@ -93,10 +93,12 @@ TEST_SUITE("[Navigation3D]") { navigation_server->map_set_active(map, true); navigation_server->agent_set_map(agent, map); navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_AGENT_COUNT), 1); navigation_server->agent_set_map(agent, RID()); navigation_server->free_rid(map); navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_AGENT_COUNT), 0); } @@ -158,11 +160,11 @@ TEST_SUITE("[Navigation3D]") { SUBCASE("'ProcessInfo' should report map iff active") { navigation_server->map_set_active(map, true); - navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. CHECK(navigation_server->map_is_active(map)); CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_ACTIVE_MAPS), 1); navigation_server->map_set_active(map, false); - navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_ACTIVE_MAPS), 0); } @@ -279,11 +281,11 @@ TEST_SUITE("[Navigation3D]") { CHECK(map.is_valid()); navigation_server->map_set_active(map, true); navigation_server->link_set_map(link, map); - navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_LINK_COUNT), 1); navigation_server->link_set_map(link, RID()); navigation_server->free_rid(map); - navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_LINK_COUNT), 0); } @@ -332,11 +334,11 @@ TEST_SUITE("[Navigation3D]") { CHECK(map.is_valid()); navigation_server->map_set_active(map, true); navigation_server->region_set_map(region, map); - navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_REGION_COUNT), 1); navigation_server->region_set_map(region, RID()); navigation_server->free_rid(map); - navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. CHECK_EQ(navigation_server->get_process_info(NavigationServer3D::INFO_REGION_COUNT), 0); } @@ -539,7 +541,7 @@ TEST_SUITE("[Navigation3D]") { navigation_server->region_set_use_async_iterations(region, false); navigation_server->region_set_map(region, map); navigation_server->region_set_navigation_mesh(region, navigation_mesh); - navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. CHECK_EQ(navigation_mesh->get_polygon_count(), 0); CHECK_EQ(navigation_mesh->get_vertices().size(), 0); @@ -555,7 +557,7 @@ TEST_SUITE("[Navigation3D]") { SUBCASE("Map should emit signal and take newly baked navigation mesh into account") { SIGNAL_WATCH(navigation_server, "map_changed"); SIGNAL_CHECK_FALSE("map_changed"); - navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. SIGNAL_CHECK("map_changed", { { map } }); SIGNAL_UNWATCH(navigation_server, "map_changed"); CHECK_NE(navigation_server->map_get_closest_point(map, Vector3(0, 0, 0)), Vector3(0, 0, 0)); @@ -636,7 +638,7 @@ TEST_SUITE("[Navigation3D]") { navigation_server->region_set_use_async_iterations(region, false); navigation_server->region_set_map(region, map); navigation_server->region_set_navigation_mesh(region, navigation_mesh); - navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. CHECK_EQ(navigation_mesh->get_polygon_count(), 0); CHECK_EQ(navigation_mesh->get_vertices().size(), 0); @@ -652,7 +654,7 @@ TEST_SUITE("[Navigation3D]") { SUBCASE("Map should emit signal and take newly baked navigation mesh into account") { SIGNAL_WATCH(navigation_server, "map_changed"); SIGNAL_CHECK_FALSE("map_changed"); - navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. SIGNAL_CHECK("map_changed", { { map } }); SIGNAL_UNWATCH(navigation_server, "map_changed"); CHECK_NE(navigation_server->map_get_closest_point(map, Vector3(0, 0, 0)), Vector3(0, 0, 0)); @@ -686,7 +688,7 @@ TEST_SUITE("[Navigation3D]") { navigation_server->region_set_use_async_iterations(region, false); navigation_server->region_set_map(region, map); navigation_server->region_set_navigation_mesh(region, navigation_mesh); - navigation_server->physics_process(0.0); // Give server some cycles to commit. + navigation_server->process(0.0); // Give server some cycles to commit. SUBCASE("Simple queries should return non-default values") { CHECK_NE(navigation_server->map_get_closest_point(map, Vector3(0, 0, 0)), Vector3(0, 0, 0));