Path: blob/master/modules/navigation_2d/2d/godot_navigation_server_2d.cpp
10278 views
/**************************************************************************/1/* godot_navigation_server_2d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "godot_navigation_server_2d.h"3132#include "core/os/mutex.h"33#include "scene/main/node.h"34#include <cstdint>3536#ifdef CLIPPER2_ENABLED37#include "nav_mesh_generator_2d.h"38#endif // CLIPPER2_ENABLED3940#define COMMAND_1(F_NAME, T_0, D_0) \41struct MERGE(F_NAME, _command_2d) : public SetCommand2D { \42T_0 d_0; \43MERGE(F_NAME, _command_2d) \44(T_0 p_d_0) : \45d_0(p_d_0) {} \46virtual void exec(GodotNavigationServer2D *p_server) override { \47p_server->MERGE(_cmd_, F_NAME)(d_0); \48} \49}; \50void GodotNavigationServer2D::F_NAME(T_0 D_0) { \51auto cmd = memnew(MERGE(F_NAME, _command_2d)( \52D_0)); \53add_command(cmd); \54} \55void GodotNavigationServer2D::MERGE(_cmd_, F_NAME)(T_0 D_0)5657#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \58struct MERGE(F_NAME, _command_2d) : public SetCommand2D { \59T_0 d_0; \60T_1 d_1; \61MERGE(F_NAME, _command_2d) \62( \63T_0 p_d_0, \64T_1 p_d_1) : \65d_0(p_d_0), \66d_1(p_d_1) {} \67virtual void exec(GodotNavigationServer2D *p_server) override { \68p_server->MERGE(_cmd_, F_NAME)(d_0, d_1); \69} \70}; \71void GodotNavigationServer2D::F_NAME(T_0 D_0, T_1 D_1) { \72auto cmd = memnew(MERGE(F_NAME, _command_2d)( \73D_0, \74D_1)); \75add_command(cmd); \76} \77void GodotNavigationServer2D::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1)7879void GodotNavigationServer2D::init() {80#ifdef CLIPPER2_ENABLED81navmesh_generator_2d = memnew(NavMeshGenerator2D);82ERR_FAIL_NULL_MSG(navmesh_generator_2d, "Failed to init NavMeshGenerator2D.");83RWLockRead read_lock(geometry_parser_rwlock);84navmesh_generator_2d->set_generator_parsers(generator_parsers);85#endif // CLIPPER2_ENABLED86// TODO87}8889void GodotNavigationServer2D::sync() {90#ifdef CLIPPER2_ENABLED91if (navmesh_generator_2d) {92navmesh_generator_2d->sync();93}94#endif // CLIPPER2_ENABLED95// TODO96}9798void GodotNavigationServer2D::finish() {99#ifdef CLIPPER2_ENABLED100if (navmesh_generator_2d) {101navmesh_generator_2d->finish();102memdelete(navmesh_generator_2d);103navmesh_generator_2d = nullptr;104}105#endif // CLIPPER2_ENABLED106// TODO107}108109void GodotNavigationServer2D::parse_source_geometry_data(const Ref<NavigationPolygon> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData2D> &p_source_geometry_data, Node *p_root_node, const Callable &p_callback) {110ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "The SceneTree can only be parsed on the main thread. Call this function from the main thread or use call_deferred().");111ERR_FAIL_COND_MSG(p_navigation_mesh.is_null(), "Invalid navigation polygon.");112ERR_FAIL_NULL_MSG(p_root_node, "No parsing root node specified.");113ERR_FAIL_COND_MSG(!p_root_node->is_inside_tree(), "The root node needs to be inside the SceneTree.");114115#ifdef CLIPPER2_ENABLED116ERR_FAIL_NULL(NavMeshGenerator2D::get_singleton());117NavMeshGenerator2D::get_singleton()->parse_source_geometry_data(p_navigation_mesh, p_source_geometry_data, p_root_node, p_callback);118#endif // CLIPPER2_ENABLED119}120121void GodotNavigationServer2D::bake_from_source_geometry_data(const Ref<NavigationPolygon> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData2D> &p_source_geometry_data, const Callable &p_callback) {122ERR_FAIL_COND_MSG(p_navigation_mesh.is_null(), "Invalid navigation polygon.");123ERR_FAIL_COND_MSG(p_source_geometry_data.is_null(), "Invalid NavigationMeshSourceGeometryData2D.");124125#ifdef CLIPPER2_ENABLED126ERR_FAIL_NULL(NavMeshGenerator2D::get_singleton());127NavMeshGenerator2D::get_singleton()->bake_from_source_geometry_data(p_navigation_mesh, p_source_geometry_data, p_callback);128#endif // CLIPPER2_ENABLED129}130131void GodotNavigationServer2D::bake_from_source_geometry_data_async(const Ref<NavigationPolygon> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData2D> &p_source_geometry_data, const Callable &p_callback) {132ERR_FAIL_COND_MSG(p_navigation_mesh.is_null(), "Invalid navigation mesh.");133ERR_FAIL_COND_MSG(p_source_geometry_data.is_null(), "Invalid NavigationMeshSourceGeometryData2D.");134135#ifdef CLIPPER2_ENABLED136ERR_FAIL_NULL(NavMeshGenerator2D::get_singleton());137NavMeshGenerator2D::get_singleton()->bake_from_source_geometry_data_async(p_navigation_mesh, p_source_geometry_data, p_callback);138#endif // CLIPPER2_ENABLED139}140141bool GodotNavigationServer2D::is_baking_navigation_polygon(Ref<NavigationPolygon> p_navigation_polygon) const {142#ifdef CLIPPER2_ENABLED143return NavMeshGenerator2D::get_singleton()->is_baking(p_navigation_polygon);144#else145return false;146#endif147}148149Vector<Vector2> GodotNavigationServer2D::simplify_path(const Vector<Vector2> &p_path, real_t p_epsilon) {150if (p_path.size() <= 2) {151return p_path;152}153154p_epsilon = MAX(0.0, p_epsilon);155156LocalVector<Vector2> source_path;157{158source_path.resize(p_path.size());159const Vector2 *r = p_path.ptr();160for (uint32_t i = 0; i < p_path.size(); i++) {161source_path[i] = r[i];162}163}164165LocalVector<uint32_t> simplified_path_indices = NavMeshQueries2D::get_simplified_path_indices(source_path, p_epsilon);166167uint32_t index_count = simplified_path_indices.size();168169Vector<Vector2> simplified_path;170{171simplified_path.resize(index_count);172Vector2 *w = simplified_path.ptrw();173const Vector2 *r = source_path.ptr();174for (uint32_t i = 0; i < index_count; i++) {175w[i] = r[simplified_path_indices[i]];176}177}178179return simplified_path;180}181182GodotNavigationServer2D::GodotNavigationServer2D() {}183184GodotNavigationServer2D::~GodotNavigationServer2D() {185flush_queries();186}187188void GodotNavigationServer2D::add_command(SetCommand2D *p_command) {189MutexLock lock(commands_mutex);190191commands.push_back(p_command);192}193194TypedArray<RID> GodotNavigationServer2D::get_maps() const {195TypedArray<RID> all_map_rids;196LocalVector<RID> maps_owned = map_owner.get_owned_list();197uint32_t map_count = maps_owned.size();198if (map_count) {199all_map_rids.resize(map_count);200for (uint32_t i = 0; i < map_count; i++) {201all_map_rids[i] = maps_owned[i];202}203}204return all_map_rids;205}206207TypedArray<RID> GodotNavigationServer2D::map_get_links(RID p_map) const {208TypedArray<RID> link_rids;209const NavMap2D *map = map_owner.get_or_null(p_map);210ERR_FAIL_NULL_V(map, link_rids);211212const LocalVector<NavLink2D *> &links = map->get_links();213link_rids.resize(links.size());214215for (uint32_t i = 0; i < links.size(); i++) {216link_rids[i] = links[i]->get_self();217}218return link_rids;219}220221TypedArray<RID> GodotNavigationServer2D::map_get_regions(RID p_map) const {222TypedArray<RID> regions_rids;223const NavMap2D *map = map_owner.get_or_null(p_map);224ERR_FAIL_NULL_V(map, regions_rids);225226const LocalVector<NavRegion2D *> ®ions = map->get_regions();227regions_rids.resize(regions.size());228229for (uint32_t i = 0; i < regions.size(); i++) {230regions_rids[i] = regions[i]->get_self();231}232return regions_rids;233}234235TypedArray<RID> GodotNavigationServer2D::map_get_agents(RID p_map) const {236TypedArray<RID> agents_rids;237const NavMap2D *map = map_owner.get_or_null(p_map);238ERR_FAIL_NULL_V(map, agents_rids);239240const LocalVector<NavAgent2D *> &agents = map->get_agents();241agents_rids.resize(agents.size());242243for (uint32_t i = 0; i < agents.size(); i++) {244agents_rids[i] = agents[i]->get_self();245}246return agents_rids;247}248249TypedArray<RID> GodotNavigationServer2D::map_get_obstacles(RID p_map) const {250TypedArray<RID> obstacles_rids;251const NavMap2D *map = map_owner.get_or_null(p_map);252ERR_FAIL_NULL_V(map, obstacles_rids);253const LocalVector<NavObstacle2D *> obstacles = map->get_obstacles();254obstacles_rids.resize(obstacles.size());255for (uint32_t i = 0; i < obstacles.size(); i++) {256obstacles_rids[i] = obstacles[i]->get_self();257}258return obstacles_rids;259}260261RID GodotNavigationServer2D::region_get_map(RID p_region) const {262NavRegion2D *region = region_owner.get_or_null(p_region);263ERR_FAIL_NULL_V(region, RID());264265if (region->get_map()) {266return region->get_map()->get_self();267}268return RID();269}270271RID GodotNavigationServer2D::agent_get_map(RID p_agent) const {272NavAgent2D *agent = agent_owner.get_or_null(p_agent);273ERR_FAIL_NULL_V(agent, RID());274275if (agent->get_map()) {276return agent->get_map()->get_self();277}278return RID();279}280281RID GodotNavigationServer2D::map_create() {282MutexLock lock(operations_mutex);283284RID rid = map_owner.make_rid();285NavMap2D *map = map_owner.get_or_null(rid);286map->set_self(rid);287return rid;288}289290COMMAND_2(map_set_active, RID, p_map, bool, p_active) {291NavMap2D *map = map_owner.get_or_null(p_map);292ERR_FAIL_NULL(map);293294if (p_active) {295if (!map_is_active(p_map)) {296active_maps.push_back(map);297}298} else {299int map_index = active_maps.find(map);300ERR_FAIL_COND(map_index < 0);301active_maps.remove_at(map_index);302}303}304305bool GodotNavigationServer2D::map_is_active(RID p_map) const {306NavMap2D *map = map_owner.get_or_null(p_map);307ERR_FAIL_NULL_V(map, false);308309return active_maps.has(map);310}311312void GodotNavigationServer2D::map_force_update(RID p_map) {313NavMap2D *map = map_owner.get_or_null(p_map);314ERR_FAIL_NULL(map);315316flush_queries();317318map->sync();319}320321uint32_t GodotNavigationServer2D::map_get_iteration_id(RID p_map) const {322NavMap2D *map = map_owner.get_or_null(p_map);323ERR_FAIL_NULL_V(map, 0);324325return map->get_iteration_id();326}327328COMMAND_2(map_set_use_async_iterations, RID, p_map, bool, p_enabled) {329NavMap2D *map = map_owner.get_or_null(p_map);330ERR_FAIL_NULL(map);331map->set_use_async_iterations(p_enabled);332}333334bool GodotNavigationServer2D::map_get_use_async_iterations(RID p_map) const {335const NavMap2D *map = map_owner.get_or_null(p_map);336ERR_FAIL_NULL_V(map, false);337338return map->get_use_async_iterations();339}340341COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size) {342NavMap2D *map = map_owner.get_or_null(p_map);343ERR_FAIL_NULL(map);344345map->set_cell_size(p_cell_size);346}347348real_t GodotNavigationServer2D::map_get_cell_size(RID p_map) const {349const NavMap2D *map = map_owner.get_or_null(p_map);350ERR_FAIL_NULL_V(map, 0);351352return map->get_cell_size();353}354355COMMAND_2(map_set_merge_rasterizer_cell_scale, RID, p_map, float, p_value) {356NavMap2D *map = map_owner.get_or_null(p_map);357ERR_FAIL_NULL(map);358359map->set_merge_rasterizer_cell_scale(p_value);360}361362float GodotNavigationServer2D::map_get_merge_rasterizer_cell_scale(RID p_map) const {363NavMap2D *map = map_owner.get_or_null(p_map);364ERR_FAIL_NULL_V(map, false);365366return map->get_merge_rasterizer_cell_scale();367}368369COMMAND_2(map_set_use_edge_connections, RID, p_map, bool, p_enabled) {370NavMap2D *map = map_owner.get_or_null(p_map);371ERR_FAIL_NULL(map);372373map->set_use_edge_connections(p_enabled);374}375376bool GodotNavigationServer2D::map_get_use_edge_connections(RID p_map) const {377NavMap2D *map = map_owner.get_or_null(p_map);378ERR_FAIL_NULL_V(map, false);379380return map->get_use_edge_connections();381}382383COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin) {384NavMap2D *map = map_owner.get_or_null(p_map);385ERR_FAIL_NULL(map);386387map->set_edge_connection_margin(p_connection_margin);388}389390real_t GodotNavigationServer2D::map_get_edge_connection_margin(RID p_map) const {391const NavMap2D *map = map_owner.get_or_null(p_map);392ERR_FAIL_NULL_V(map, 0);393394return map->get_edge_connection_margin();395}396397COMMAND_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius) {398NavMap2D *map = map_owner.get_or_null(p_map);399ERR_FAIL_NULL(map);400401map->set_link_connection_radius(p_connection_radius);402}403404real_t GodotNavigationServer2D::map_get_link_connection_radius(RID p_map) const {405const NavMap2D *map = map_owner.get_or_null(p_map);406ERR_FAIL_NULL_V(map, 0);407408return map->get_link_connection_radius();409}410411Vector<Vector2> GodotNavigationServer2D::map_get_path(RID p_map, Vector2 p_origin, Vector2 p_destination, bool p_optimize, uint32_t p_navigation_layers) {412const NavMap2D *map = map_owner.get_or_null(p_map);413ERR_FAIL_NULL_V(map, Vector<Vector2>());414415Ref<NavigationPathQueryParameters2D> query_parameters;416query_parameters.instantiate();417418query_parameters->set_map(p_map);419query_parameters->set_start_position(p_origin);420query_parameters->set_target_position(p_destination);421query_parameters->set_navigation_layers(p_navigation_layers);422query_parameters->set_pathfinding_algorithm(NavigationPathQueryParameters2D::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR);423query_parameters->set_path_postprocessing(NavigationPathQueryParameters2D::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL);424if (!p_optimize) {425query_parameters->set_path_postprocessing(NavigationPathQueryParameters2D::PATH_POSTPROCESSING_EDGECENTERED);426}427428Ref<NavigationPathQueryResult2D> query_result;429query_result.instantiate();430431query_path(query_parameters, query_result);432433return query_result->get_path();434}435436Vector2 GodotNavigationServer2D::map_get_closest_point(RID p_map, const Vector2 &p_point) const {437const NavMap2D *map = map_owner.get_or_null(p_map);438ERR_FAIL_NULL_V(map, Vector2());439440return map->get_closest_point(p_point);441}442443RID GodotNavigationServer2D::map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const {444const NavMap2D *map = map_owner.get_or_null(p_map);445ERR_FAIL_NULL_V(map, RID());446447return map->get_closest_point_owner(p_point);448}449450Vector2 GodotNavigationServer2D::map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const {451const NavMap2D *map = map_owner.get_or_null(p_map);452ERR_FAIL_NULL_V(map, Vector2());453454return map->get_random_point(p_navigation_layers, p_uniformly);455}456457RID GodotNavigationServer2D::region_create() {458MutexLock lock(operations_mutex);459460RID rid = region_owner.make_rid();461NavRegion2D *reg = region_owner.get_or_null(rid);462reg->set_self(rid);463return rid;464}465466uint32_t GodotNavigationServer2D::region_get_iteration_id(RID p_region) const {467NavRegion2D *region = region_owner.get_or_null(p_region);468ERR_FAIL_NULL_V(region, 0);469470return region->get_iteration_id();471}472473COMMAND_2(region_set_use_async_iterations, RID, p_region, bool, p_enabled) {474NavRegion2D *region = region_owner.get_or_null(p_region);475ERR_FAIL_NULL(region);476region->set_use_async_iterations(p_enabled);477}478479bool GodotNavigationServer2D::region_get_use_async_iterations(RID p_region) const {480NavRegion2D *region = region_owner.get_or_null(p_region);481ERR_FAIL_NULL_V(region, false);482483return region->get_use_async_iterations();484}485486COMMAND_2(region_set_enabled, RID, p_region, bool, p_enabled) {487NavRegion2D *region = region_owner.get_or_null(p_region);488ERR_FAIL_NULL(region);489490region->set_enabled(p_enabled);491}492493bool GodotNavigationServer2D::region_get_enabled(RID p_region) const {494const NavRegion2D *region = region_owner.get_or_null(p_region);495ERR_FAIL_NULL_V(region, false);496497return region->get_enabled();498}499500COMMAND_2(region_set_use_edge_connections, RID, p_region, bool, p_enabled) {501NavRegion2D *region = region_owner.get_or_null(p_region);502ERR_FAIL_NULL(region);503504region->set_use_edge_connections(p_enabled);505}506507bool GodotNavigationServer2D::region_get_use_edge_connections(RID p_region) const {508NavRegion2D *region = region_owner.get_or_null(p_region);509ERR_FAIL_NULL_V(region, false);510511return region->get_use_edge_connections();512}513514COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost) {515NavRegion2D *region = region_owner.get_or_null(p_region);516ERR_FAIL_NULL(region);517ERR_FAIL_COND(p_enter_cost < 0.0);518519region->set_enter_cost(p_enter_cost);520}521522real_t GodotNavigationServer2D::region_get_enter_cost(RID p_region) const {523NavRegion2D *region = region_owner.get_or_null(p_region);524ERR_FAIL_NULL_V(region, 0);525526return region->get_enter_cost();527}528529COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost) {530NavRegion2D *region = region_owner.get_or_null(p_region);531ERR_FAIL_NULL(region);532ERR_FAIL_COND(p_travel_cost < 0.0);533534region->set_travel_cost(p_travel_cost);535}536537real_t GodotNavigationServer2D::region_get_travel_cost(RID p_region) const {538NavRegion2D *region = region_owner.get_or_null(p_region);539ERR_FAIL_NULL_V(region, 0);540541return region->get_travel_cost();542}543544COMMAND_2(region_set_owner_id, RID, p_region, ObjectID, p_owner_id) {545NavRegion2D *region = region_owner.get_or_null(p_region);546ERR_FAIL_NULL(region);547548region->set_owner_id(p_owner_id);549}550551ObjectID GodotNavigationServer2D::region_get_owner_id(RID p_region) const {552const NavRegion2D *region = region_owner.get_or_null(p_region);553ERR_FAIL_NULL_V(region, ObjectID());554555return region->get_owner_id();556}557558bool GodotNavigationServer2D::region_owns_point(RID p_region, const Vector2 &p_point) const {559const NavRegion2D *region = region_owner.get_or_null(p_region);560ERR_FAIL_NULL_V(region, false);561562if (region->get_map()) {563RID closest_point_owner = map_get_closest_point_owner(region->get_map()->get_self(), p_point);564return closest_point_owner == region->get_self();565}566return false;567}568569COMMAND_2(region_set_map, RID, p_region, RID, p_map) {570NavRegion2D *region = region_owner.get_or_null(p_region);571ERR_FAIL_NULL(region);572573NavMap2D *map = map_owner.get_or_null(p_map);574575region->set_map(map);576}577578COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers) {579NavRegion2D *region = region_owner.get_or_null(p_region);580ERR_FAIL_NULL(region);581582region->set_navigation_layers(p_navigation_layers);583}584585uint32_t GodotNavigationServer2D::region_get_navigation_layers(RID p_region) const {586NavRegion2D *region = region_owner.get_or_null(p_region);587ERR_FAIL_NULL_V(region, 0);588589return region->get_navigation_layers();590}591592COMMAND_2(region_set_transform, RID, p_region, Transform2D, p_transform) {593NavRegion2D *region = region_owner.get_or_null(p_region);594ERR_FAIL_NULL(region);595596region->set_transform(p_transform);597}598599Transform2D GodotNavigationServer2D::region_get_transform(RID p_region) const {600NavRegion2D *region = region_owner.get_or_null(p_region);601ERR_FAIL_NULL_V(region, Transform2D());602603return region->get_transform();604}605606void GodotNavigationServer2D::region_set_navigation_polygon(RID p_region, Ref<NavigationPolygon> p_navigation_polygon) {607NavRegion2D *region = region_owner.get_or_null(p_region);608ERR_FAIL_NULL(region);609610region->set_navigation_mesh(p_navigation_polygon);611}612613int GodotNavigationServer2D::region_get_connections_count(RID p_region) const {614NavRegion2D *region = region_owner.get_or_null(p_region);615ERR_FAIL_NULL_V(region, 0);616NavMap2D *map = region->get_map();617if (map) {618return map->get_region_connections_count(region);619}620return 0;621}622623Vector2 GodotNavigationServer2D::region_get_connection_pathway_start(RID p_region, int p_connection_id) const {624NavRegion2D *region = region_owner.get_or_null(p_region);625ERR_FAIL_NULL_V(region, Vector2());626NavMap2D *map = region->get_map();627if (map) {628return map->get_region_connection_pathway_start(region, p_connection_id);629}630return Vector2();631}632633Vector2 GodotNavigationServer2D::region_get_connection_pathway_end(RID p_region, int p_connection_id) const {634NavRegion2D *region = region_owner.get_or_null(p_region);635ERR_FAIL_NULL_V(region, Vector2());636NavMap2D *map = region->get_map();637if (map) {638return map->get_region_connection_pathway_end(region, p_connection_id);639}640return Vector2();641}642643Vector2 GodotNavigationServer2D::region_get_closest_point(RID p_region, const Vector2 &p_point) const {644const NavRegion2D *region = region_owner.get_or_null(p_region);645ERR_FAIL_NULL_V(region, Vector2());646647return region->get_closest_point_info(p_point).point;648}649650Vector2 GodotNavigationServer2D::region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const {651const NavRegion2D *region = region_owner.get_or_null(p_region);652ERR_FAIL_NULL_V(region, Vector2());653654return region->get_random_point(p_navigation_layers, p_uniformly);655}656657Rect2 GodotNavigationServer2D::region_get_bounds(RID p_region) const {658const NavRegion2D *region = region_owner.get_or_null(p_region);659ERR_FAIL_NULL_V(region, Rect2());660661return region->get_bounds();662}663664RID GodotNavigationServer2D::link_create() {665MutexLock lock(operations_mutex);666667RID rid = link_owner.make_rid();668NavLink2D *link = link_owner.get_or_null(rid);669link->set_self(rid);670return rid;671}672673uint32_t GodotNavigationServer2D::link_get_iteration_id(RID p_link) const {674NavLink2D *link = link_owner.get_or_null(p_link);675ERR_FAIL_NULL_V(link, 0);676677return link->get_iteration_id();678}679680COMMAND_2(link_set_map, RID, p_link, RID, p_map) {681NavLink2D *link = link_owner.get_or_null(p_link);682ERR_FAIL_NULL(link);683684NavMap2D *map = map_owner.get_or_null(p_map);685686link->set_map(map);687}688689RID GodotNavigationServer2D::link_get_map(const RID p_link) const {690const NavLink2D *link = link_owner.get_or_null(p_link);691ERR_FAIL_NULL_V(link, RID());692693if (link->get_map()) {694return link->get_map()->get_self();695}696return RID();697}698699COMMAND_2(link_set_enabled, RID, p_link, bool, p_enabled) {700NavLink2D *link = link_owner.get_or_null(p_link);701ERR_FAIL_NULL(link);702703link->set_enabled(p_enabled);704}705706bool GodotNavigationServer2D::link_get_enabled(RID p_link) const {707const NavLink2D *link = link_owner.get_or_null(p_link);708ERR_FAIL_NULL_V(link, false);709710return link->get_enabled();711}712713COMMAND_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional) {714NavLink2D *link = link_owner.get_or_null(p_link);715ERR_FAIL_NULL(link);716717link->set_bidirectional(p_bidirectional);718}719720bool GodotNavigationServer2D::link_is_bidirectional(RID p_link) const {721const NavLink2D *link = link_owner.get_or_null(p_link);722ERR_FAIL_NULL_V(link, false);723724return link->is_bidirectional();725}726727COMMAND_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers) {728NavLink2D *link = link_owner.get_or_null(p_link);729ERR_FAIL_NULL(link);730731link->set_navigation_layers(p_navigation_layers);732}733734uint32_t GodotNavigationServer2D::link_get_navigation_layers(const RID p_link) const {735const NavLink2D *link = link_owner.get_or_null(p_link);736ERR_FAIL_NULL_V(link, 0);737738return link->get_navigation_layers();739}740741COMMAND_2(link_set_start_position, RID, p_link, Vector2, p_position) {742NavLink2D *link = link_owner.get_or_null(p_link);743ERR_FAIL_NULL(link);744745link->set_start_position(p_position);746}747748Vector2 GodotNavigationServer2D::link_get_start_position(RID p_link) const {749const NavLink2D *link = link_owner.get_or_null(p_link);750ERR_FAIL_NULL_V(link, Vector2());751752return link->get_start_position();753}754755COMMAND_2(link_set_end_position, RID, p_link, Vector2, p_position) {756NavLink2D *link = link_owner.get_or_null(p_link);757ERR_FAIL_NULL(link);758759link->set_end_position(p_position);760}761762Vector2 GodotNavigationServer2D::link_get_end_position(RID p_link) const {763const NavLink2D *link = link_owner.get_or_null(p_link);764ERR_FAIL_NULL_V(link, Vector2());765766return link->get_end_position();767}768769COMMAND_2(link_set_enter_cost, RID, p_link, real_t, p_enter_cost) {770NavLink2D *link = link_owner.get_or_null(p_link);771ERR_FAIL_NULL(link);772773link->set_enter_cost(p_enter_cost);774}775776real_t GodotNavigationServer2D::link_get_enter_cost(const RID p_link) const {777const NavLink2D *link = link_owner.get_or_null(p_link);778ERR_FAIL_NULL_V(link, 0);779780return link->get_enter_cost();781}782783COMMAND_2(link_set_travel_cost, RID, p_link, real_t, p_travel_cost) {784NavLink2D *link = link_owner.get_or_null(p_link);785ERR_FAIL_NULL(link);786787link->set_travel_cost(p_travel_cost);788}789790real_t GodotNavigationServer2D::link_get_travel_cost(const RID p_link) const {791const NavLink2D *link = link_owner.get_or_null(p_link);792ERR_FAIL_NULL_V(link, 0);793794return link->get_travel_cost();795}796797COMMAND_2(link_set_owner_id, RID, p_link, ObjectID, p_owner_id) {798NavLink2D *link = link_owner.get_or_null(p_link);799ERR_FAIL_NULL(link);800801link->set_owner_id(p_owner_id);802}803804ObjectID GodotNavigationServer2D::link_get_owner_id(RID p_link) const {805const NavLink2D *link = link_owner.get_or_null(p_link);806ERR_FAIL_NULL_V(link, ObjectID());807808return link->get_owner_id();809}810811RID GodotNavigationServer2D::agent_create() {812MutexLock lock(operations_mutex);813814RID rid = agent_owner.make_rid();815NavAgent2D *agent = agent_owner.get_or_null(rid);816agent->set_self(rid);817return rid;818}819820COMMAND_2(agent_set_avoidance_enabled, RID, p_agent, bool, p_enabled) {821NavAgent2D *agent = agent_owner.get_or_null(p_agent);822ERR_FAIL_NULL(agent);823824agent->set_avoidance_enabled(p_enabled);825}826827bool GodotNavigationServer2D::agent_get_avoidance_enabled(RID p_agent) const {828NavAgent2D *agent = agent_owner.get_or_null(p_agent);829ERR_FAIL_NULL_V(agent, false);830831return agent->is_avoidance_enabled();832}833834COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) {835NavAgent2D *agent = agent_owner.get_or_null(p_agent);836ERR_FAIL_NULL(agent);837838NavMap2D *map = map_owner.get_or_null(p_map);839840agent->set_map(map);841}842843COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance) {844NavAgent2D *agent = agent_owner.get_or_null(p_agent);845ERR_FAIL_NULL(agent);846847agent->set_neighbor_distance(p_distance);848}849850real_t GodotNavigationServer2D::agent_get_neighbor_distance(RID p_agent) const {851NavAgent2D *agent = agent_owner.get_or_null(p_agent);852ERR_FAIL_NULL_V(agent, 0);853854return agent->get_neighbor_distance();855}856857COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count) {858NavAgent2D *agent = agent_owner.get_or_null(p_agent);859ERR_FAIL_NULL(agent);860861agent->set_max_neighbors(p_count);862}863864int GodotNavigationServer2D::agent_get_max_neighbors(RID p_agent) const {865NavAgent2D *agent = agent_owner.get_or_null(p_agent);866ERR_FAIL_NULL_V(agent, 0);867868return agent->get_max_neighbors();869}870871COMMAND_2(agent_set_time_horizon_agents, RID, p_agent, real_t, p_time_horizon) {872ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizon must be positive.");873NavAgent2D *agent = agent_owner.get_or_null(p_agent);874ERR_FAIL_NULL(agent);875876agent->set_time_horizon_agents(p_time_horizon);877}878879real_t GodotNavigationServer2D::agent_get_time_horizon_agents(RID p_agent) const {880NavAgent2D *agent = agent_owner.get_or_null(p_agent);881ERR_FAIL_NULL_V(agent, 0);882883return agent->get_time_horizon_agents();884}885886COMMAND_2(agent_set_time_horizon_obstacles, RID, p_agent, real_t, p_time_horizon) {887ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizon must be positive.");888NavAgent2D *agent = agent_owner.get_or_null(p_agent);889ERR_FAIL_NULL(agent);890891agent->set_time_horizon_obstacles(p_time_horizon);892}893894real_t GodotNavigationServer2D::agent_get_time_horizon_obstacles(RID p_agent) const {895NavAgent2D *agent = agent_owner.get_or_null(p_agent);896ERR_FAIL_NULL_V(agent, 0);897898return agent->get_time_horizon_obstacles();899}900901COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius) {902ERR_FAIL_COND_MSG(p_radius < 0.0, "Radius must be positive.");903NavAgent2D *agent = agent_owner.get_or_null(p_agent);904ERR_FAIL_NULL(agent);905906agent->set_radius(p_radius);907}908909real_t GodotNavigationServer2D::agent_get_radius(RID p_agent) const {910NavAgent2D *agent = agent_owner.get_or_null(p_agent);911ERR_FAIL_NULL_V(agent, 0);912913return agent->get_radius();914}915916COMMAND_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed) {917ERR_FAIL_COND_MSG(p_max_speed < 0.0, "Max speed must be positive.");918NavAgent2D *agent = agent_owner.get_or_null(p_agent);919ERR_FAIL_NULL(agent);920921agent->set_max_speed(p_max_speed);922}923924real_t GodotNavigationServer2D::agent_get_max_speed(RID p_agent) const {925NavAgent2D *agent = agent_owner.get_or_null(p_agent);926ERR_FAIL_NULL_V(agent, 0);927928return agent->get_max_speed();929}930931COMMAND_2(agent_set_velocity_forced, RID, p_agent, Vector2, p_velocity) {932NavAgent2D *agent = agent_owner.get_or_null(p_agent);933ERR_FAIL_NULL(agent);934935agent->set_velocity_forced(p_velocity);936}937938COMMAND_2(agent_set_velocity, RID, p_agent, Vector2, p_velocity) {939NavAgent2D *agent = agent_owner.get_or_null(p_agent);940ERR_FAIL_NULL(agent);941942agent->set_velocity(p_velocity);943}944945Vector2 GodotNavigationServer2D::agent_get_velocity(RID p_agent) const {946NavAgent2D *agent = agent_owner.get_or_null(p_agent);947ERR_FAIL_NULL_V(agent, Vector2());948949return agent->get_velocity();950}951952COMMAND_2(agent_set_position, RID, p_agent, Vector2, p_position) {953NavAgent2D *agent = agent_owner.get_or_null(p_agent);954ERR_FAIL_NULL(agent);955956agent->set_position(p_position);957}958959Vector2 GodotNavigationServer2D::agent_get_position(RID p_agent) const {960NavAgent2D *agent = agent_owner.get_or_null(p_agent);961ERR_FAIL_NULL_V(agent, Vector2());962963return agent->get_position();964}965966bool GodotNavigationServer2D::agent_is_map_changed(RID p_agent) const {967NavAgent2D *agent = agent_owner.get_or_null(p_agent);968ERR_FAIL_NULL_V(agent, false);969970return agent->is_map_changed();971}972973COMMAND_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback) {974NavAgent2D *agent = agent_owner.get_or_null(p_agent);975ERR_FAIL_NULL(agent);976977agent->set_avoidance_callback(p_callback);978979if (agent->get_map()) {980if (p_callback.is_valid()) {981agent->get_map()->set_agent_as_controlled(agent);982} else {983agent->get_map()->remove_agent_as_controlled(agent);984}985}986}987988bool GodotNavigationServer2D::agent_has_avoidance_callback(RID p_agent) const {989NavAgent2D *agent = agent_owner.get_or_null(p_agent);990ERR_FAIL_NULL_V(agent, false);991992return agent->has_avoidance_callback();993}994995COMMAND_2(agent_set_avoidance_layers, RID, p_agent, uint32_t, p_layers) {996NavAgent2D *agent = agent_owner.get_or_null(p_agent);997ERR_FAIL_NULL(agent);998agent->set_avoidance_layers(p_layers);999}10001001uint32_t GodotNavigationServer2D::agent_get_avoidance_layers(RID p_agent) const {1002NavAgent2D *agent = agent_owner.get_or_null(p_agent);1003ERR_FAIL_NULL_V(agent, 0);10041005return agent->get_avoidance_layers();1006}10071008COMMAND_2(agent_set_avoidance_mask, RID, p_agent, uint32_t, p_mask) {1009NavAgent2D *agent = agent_owner.get_or_null(p_agent);1010ERR_FAIL_NULL(agent);1011agent->set_avoidance_mask(p_mask);1012}10131014uint32_t GodotNavigationServer2D::agent_get_avoidance_mask(RID p_agent) const {1015NavAgent2D *agent = agent_owner.get_or_null(p_agent);1016ERR_FAIL_NULL_V(agent, 0);10171018return agent->get_avoidance_mask();1019}10201021COMMAND_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority) {1022ERR_FAIL_COND_MSG(p_priority < 0.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");1023ERR_FAIL_COND_MSG(p_priority > 1.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");1024NavAgent2D *agent = agent_owner.get_or_null(p_agent);1025ERR_FAIL_NULL(agent);1026agent->set_avoidance_priority(p_priority);1027}10281029real_t GodotNavigationServer2D::agent_get_avoidance_priority(RID p_agent) const {1030NavAgent2D *agent = agent_owner.get_or_null(p_agent);1031ERR_FAIL_NULL_V(agent, 0);10321033return agent->get_avoidance_priority();1034}10351036COMMAND_2(agent_set_paused, RID, p_agent, bool, p_paused) {1037NavAgent2D *agent = agent_owner.get_or_null(p_agent);1038ERR_FAIL_NULL(agent);10391040agent->set_paused(p_paused);1041}10421043bool GodotNavigationServer2D::agent_get_paused(RID p_agent) const {1044NavAgent2D *agent = agent_owner.get_or_null(p_agent);1045ERR_FAIL_NULL_V(agent, false);10461047return agent->get_paused();1048}10491050RID GodotNavigationServer2D::obstacle_create() {1051MutexLock lock(operations_mutex);10521053RID rid = obstacle_owner.make_rid();1054NavObstacle2D *obstacle = obstacle_owner.get_or_null(rid);1055obstacle->set_self(rid);10561057RID agent_rid = agent_owner.make_rid();1058NavAgent2D *agent = agent_owner.get_or_null(agent_rid);1059agent->set_self(agent_rid);10601061obstacle->set_agent(agent);10621063return rid;1064}10651066COMMAND_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled) {1067NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1068ERR_FAIL_NULL(obstacle);10691070obstacle->set_avoidance_enabled(p_enabled);1071}10721073bool GodotNavigationServer2D::obstacle_get_avoidance_enabled(RID p_obstacle) const {1074NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1075ERR_FAIL_NULL_V(obstacle, false);10761077return obstacle->is_avoidance_enabled();1078}10791080COMMAND_2(obstacle_set_map, RID, p_obstacle, RID, p_map) {1081NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1082ERR_FAIL_NULL(obstacle);10831084NavMap2D *map = map_owner.get_or_null(p_map);10851086obstacle->set_map(map);1087}10881089RID GodotNavigationServer2D::obstacle_get_map(RID p_obstacle) const {1090NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1091ERR_FAIL_NULL_V(obstacle, RID());1092if (obstacle->get_map()) {1093return obstacle->get_map()->get_self();1094}1095return RID();1096}10971098COMMAND_2(obstacle_set_paused, RID, p_obstacle, bool, p_paused) {1099NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1100ERR_FAIL_NULL(obstacle);11011102obstacle->set_paused(p_paused);1103}11041105bool GodotNavigationServer2D::obstacle_get_paused(RID p_obstacle) const {1106NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1107ERR_FAIL_NULL_V(obstacle, false);11081109return obstacle->get_paused();1110}11111112COMMAND_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius) {1113ERR_FAIL_COND_MSG(p_radius < 0.0, "Radius must be positive.");1114NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1115ERR_FAIL_NULL(obstacle);11161117obstacle->set_radius(p_radius);1118}11191120real_t GodotNavigationServer2D::obstacle_get_radius(RID p_obstacle) const {1121NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1122ERR_FAIL_NULL_V(obstacle, 0);11231124return obstacle->get_radius();1125}11261127COMMAND_2(obstacle_set_velocity, RID, p_obstacle, Vector2, p_velocity) {1128NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1129ERR_FAIL_NULL(obstacle);11301131obstacle->set_velocity(p_velocity);1132}11331134Vector2 GodotNavigationServer2D::obstacle_get_velocity(RID p_obstacle) const {1135NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1136ERR_FAIL_NULL_V(obstacle, Vector2());11371138return obstacle->get_velocity();1139}11401141COMMAND_2(obstacle_set_position, RID, p_obstacle, Vector2, p_position) {1142NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1143ERR_FAIL_NULL(obstacle);1144obstacle->set_position(p_position);1145}11461147Vector2 GodotNavigationServer2D::obstacle_get_position(RID p_obstacle) const {1148NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1149ERR_FAIL_NULL_V(obstacle, Vector2());11501151return obstacle->get_position();1152}11531154COMMAND_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers) {1155NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1156ERR_FAIL_NULL(obstacle);1157obstacle->set_avoidance_layers(p_layers);1158}11591160uint32_t GodotNavigationServer2D::obstacle_get_avoidance_layers(RID p_obstacle) const {1161NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1162ERR_FAIL_NULL_V(obstacle, 0);11631164return obstacle->get_avoidance_layers();1165}11661167void GodotNavigationServer2D::obstacle_set_vertices(RID p_obstacle, const Vector<Vector2> &p_vertices) {1168NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1169ERR_FAIL_NULL(obstacle);1170obstacle->set_vertices(p_vertices);1171}11721173Vector<Vector2> GodotNavigationServer2D::obstacle_get_vertices(RID p_obstacle) const {1174NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_obstacle);1175ERR_FAIL_NULL_V(obstacle, Vector<Vector2>());11761177return obstacle->get_vertices();1178}11791180void GodotNavigationServer2D::flush_queries() {1181MutexLock lock(commands_mutex);1182MutexLock lock2(operations_mutex);11831184for (SetCommand2D *command : commands) {1185command->exec(this);1186memdelete(command);1187}1188commands.clear();1189}11901191COMMAND_1(free, RID, p_object) {1192if (geometry_parser_owner.owns(p_object)) {1193RWLockWrite write_lock(geometry_parser_rwlock);11941195NavMeshGeometryParser2D *parser = geometry_parser_owner.get_or_null(p_object);1196ERR_FAIL_NULL(parser);11971198generator_parsers.erase(parser);1199#ifdef CLIPPER2_ENABLED1200NavMeshGenerator2D::get_singleton()->set_generator_parsers(generator_parsers);1201#endif1202geometry_parser_owner.free(parser->self);1203return;1204}1205if (map_owner.owns(p_object)) {1206NavMap2D *map = map_owner.get_or_null(p_object);12071208// Removes any assigned region.1209for (NavRegion2D *region : map->get_regions()) {1210map->remove_region(region);1211region->set_map(nullptr);1212}12131214// Removes any assigned links.1215for (NavLink2D *link : map->get_links()) {1216map->remove_link(link);1217link->set_map(nullptr);1218}12191220// Remove any assigned agent.1221for (NavAgent2D *agent : map->get_agents()) {1222map->remove_agent(agent);1223agent->set_map(nullptr);1224}12251226// Remove any assigned obstacles.1227for (NavObstacle2D *obstacle : map->get_obstacles()) {1228map->remove_obstacle(obstacle);1229obstacle->set_map(nullptr);1230}12311232int map_index = active_maps.find(map);1233if (map_index >= 0) {1234active_maps.remove_at(map_index);1235}1236map_owner.free(p_object);12371238} else if (region_owner.owns(p_object)) {1239NavRegion2D *region = region_owner.get_or_null(p_object);12401241// Removes this region from the map if assigned.1242if (region->get_map() != nullptr) {1243region->get_map()->remove_region(region);1244region->set_map(nullptr);1245}12461247region_owner.free(p_object);12481249} else if (link_owner.owns(p_object)) {1250NavLink2D *link = link_owner.get_or_null(p_object);12511252// Removes this link from the map if assigned.1253if (link->get_map() != nullptr) {1254link->get_map()->remove_link(link);1255link->set_map(nullptr);1256}12571258link_owner.free(p_object);12591260} else if (agent_owner.owns(p_object)) {1261internal_free_agent(p_object);12621263} else if (obstacle_owner.owns(p_object)) {1264internal_free_obstacle(p_object);12651266} else {1267ERR_PRINT("Attempted to free a NavigationServer RID that did not exist (or was already freed).");1268}1269}12701271void GodotNavigationServer2D::internal_free_agent(RID p_object) {1272NavAgent2D *agent = agent_owner.get_or_null(p_object);1273if (agent) {1274if (agent->get_map() != nullptr) {1275agent->get_map()->remove_agent(agent);1276agent->set_map(nullptr);1277}1278agent_owner.free(p_object);1279}1280}12811282void GodotNavigationServer2D::internal_free_obstacle(RID p_object) {1283NavObstacle2D *obstacle = obstacle_owner.get_or_null(p_object);1284if (obstacle) {1285NavAgent2D *obstacle_agent = obstacle->get_agent();1286if (obstacle_agent) {1287RID _agent_rid = obstacle_agent->get_self();1288internal_free_agent(_agent_rid);1289obstacle->set_agent(nullptr);1290}1291if (obstacle->get_map() != nullptr) {1292obstacle->get_map()->remove_obstacle(obstacle);1293obstacle->set_map(nullptr);1294}1295obstacle_owner.free(p_object);1296}1297}12981299void GodotNavigationServer2D::process(double p_delta_time) {1300// Called for each main loop iteration AFTER node and user script process() and BEFORE RenderingServer sync.1301// Will run reliably every rendered frame independent of the physics tick rate.1302// Use for things that (only) need to update once per main loop iteration and rendered frame or is visible to the user.1303// E.g. (final) sync of objects for this main loop iteration, updating rendered debug visuals, updating debug statistics, ...13041305sync();1306}13071308void GodotNavigationServer2D::physics_process(double p_delta_time) {1309// Called for each physics process step AFTER node and user script physics_process() and BEFORE PhysicsServer sync.1310// Will NOT run reliably every rendered frame. If there is no physics step this function will not run.1311// Use for physics or step depending calculations and updates where the result affects the next step calculation.1312// E.g. anything physics sync related, avoidance simulations, physics space state queries, ...1313// If physics process needs to play catchup this function will be called multiple times per frame so it should not hold1314// costly updates that are not important outside the stepped calculations to avoid causing a physics performance death spiral.13151316flush_queries();13171318if (!active) {1319return;1320}13211322int _new_pm_region_count = 0;1323int _new_pm_agent_count = 0;1324int _new_pm_link_count = 0;1325int _new_pm_polygon_count = 0;1326int _new_pm_edge_count = 0;1327int _new_pm_edge_merge_count = 0;1328int _new_pm_edge_connection_count = 0;1329int _new_pm_edge_free_count = 0;1330int _new_pm_obstacle_count = 0;13311332MutexLock lock(operations_mutex);1333for (uint32_t i(0); i < active_maps.size(); i++) {1334active_maps[i]->sync();1335active_maps[i]->step(p_delta_time);1336active_maps[i]->dispatch_callbacks();13371338_new_pm_region_count += active_maps[i]->get_pm_region_count();1339_new_pm_agent_count += active_maps[i]->get_pm_agent_count();1340_new_pm_link_count += active_maps[i]->get_pm_link_count();1341_new_pm_polygon_count += active_maps[i]->get_pm_polygon_count();1342_new_pm_edge_count += active_maps[i]->get_pm_edge_count();1343_new_pm_edge_merge_count += active_maps[i]->get_pm_edge_merge_count();1344_new_pm_edge_connection_count += active_maps[i]->get_pm_edge_connection_count();1345_new_pm_edge_free_count += active_maps[i]->get_pm_edge_free_count();1346_new_pm_obstacle_count += active_maps[i]->get_pm_obstacle_count();1347}13481349pm_region_count = _new_pm_region_count;1350pm_agent_count = _new_pm_agent_count;1351pm_link_count = _new_pm_link_count;1352pm_polygon_count = _new_pm_polygon_count;1353pm_edge_count = _new_pm_edge_count;1354pm_edge_merge_count = _new_pm_edge_merge_count;1355pm_edge_connection_count = _new_pm_edge_connection_count;1356pm_edge_free_count = _new_pm_edge_free_count;1357pm_obstacle_count = _new_pm_obstacle_count;1358}13591360void GodotNavigationServer2D::set_active(bool p_active) {1361MutexLock lock(operations_mutex);13621363active = p_active;1364}13651366void GodotNavigationServer2D::query_path(const Ref<NavigationPathQueryParameters2D> &p_query_parameters, Ref<NavigationPathQueryResult2D> p_query_result, const Callable &p_callback) {1367ERR_FAIL_COND(p_query_parameters.is_null());1368ERR_FAIL_COND(p_query_result.is_null());13691370NavMap2D *map = map_owner.get_or_null(p_query_parameters->get_map());1371ERR_FAIL_NULL(map);13721373NavMeshQueries2D::map_query_path(map, p_query_parameters, p_query_result, p_callback);1374}13751376RID GodotNavigationServer2D::source_geometry_parser_create() {1377RWLockWrite write_lock(geometry_parser_rwlock);13781379RID rid = geometry_parser_owner.make_rid();13801381NavMeshGeometryParser2D *parser = geometry_parser_owner.get_or_null(rid);1382parser->self = rid;13831384generator_parsers.push_back(parser);1385#ifdef CLIPPER2_ENABLED1386NavMeshGenerator2D::get_singleton()->set_generator_parsers(generator_parsers);1387#endif1388return rid;1389}13901391void GodotNavigationServer2D::source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) {1392RWLockWrite write_lock(geometry_parser_rwlock);13931394NavMeshGeometryParser2D *parser = geometry_parser_owner.get_or_null(p_parser);1395ERR_FAIL_NULL(parser);13961397parser->callback = p_callback;1398}13991400int GodotNavigationServer2D::get_process_info(ProcessInfo p_info) const {1401switch (p_info) {1402case INFO_ACTIVE_MAPS: {1403return active_maps.size();1404} break;1405case INFO_REGION_COUNT: {1406return pm_region_count;1407} break;1408case INFO_AGENT_COUNT: {1409return pm_agent_count;1410} break;1411case INFO_LINK_COUNT: {1412return pm_link_count;1413} break;1414case INFO_POLYGON_COUNT: {1415return pm_polygon_count;1416} break;1417case INFO_EDGE_COUNT: {1418return pm_edge_count;1419} break;1420case INFO_EDGE_MERGE_COUNT: {1421return pm_edge_merge_count;1422} break;1423case INFO_EDGE_CONNECTION_COUNT: {1424return pm_edge_connection_count;1425} break;1426case INFO_EDGE_FREE_COUNT: {1427return pm_edge_free_count;1428} break;1429case INFO_OBSTACLE_COUNT: {1430return pm_obstacle_count;1431} break;1432}14331434return 0;1435}14361437#undef COMMAND_11438#undef COMMAND_2143914401441