Path: blob/master/modules/navigation_3d/3d/godot_navigation_server_3d.cpp
10278 views
/**************************************************************************/1/* godot_navigation_server_3d.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_3d.h"3132#include "core/os/mutex.h"33#include "scene/main/node.h"3435#include "nav_mesh_generator_3d.h"3637using namespace NavigationUtilities;3839/// Creates a struct for each function and a function that once called creates40/// an instance of that struct with the submitted parameters.41/// Then, that struct is stored in an array; the `sync` function consume that array.4243#define COMMAND_1(F_NAME, T_0, D_0) \44struct MERGE(F_NAME, _command_3d) : public SetCommand3D { \45T_0 d_0; \46MERGE(F_NAME, _command_3d) \47(T_0 p_d_0) : \48d_0(p_d_0) {} \49virtual void exec(GodotNavigationServer3D *server) override { \50server->MERGE(_cmd_, F_NAME)(d_0); \51} \52}; \53void GodotNavigationServer3D::F_NAME(T_0 D_0) { \54auto cmd = memnew(MERGE(F_NAME, _command_3d)( \55D_0)); \56add_command(cmd); \57} \58void GodotNavigationServer3D::MERGE(_cmd_, F_NAME)(T_0 D_0)5960#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \61struct MERGE(F_NAME, _command_3d) : public SetCommand3D { \62T_0 d_0; \63T_1 d_1; \64MERGE(F_NAME, _command_3d) \65( \66T_0 p_d_0, \67T_1 p_d_1) : \68d_0(p_d_0), \69d_1(p_d_1) {} \70virtual void exec(GodotNavigationServer3D *server) override { \71server->MERGE(_cmd_, F_NAME)(d_0, d_1); \72} \73}; \74void GodotNavigationServer3D::F_NAME(T_0 D_0, T_1 D_1) { \75auto cmd = memnew(MERGE(F_NAME, _command_3d)( \76D_0, \77D_1)); \78add_command(cmd); \79} \80void GodotNavigationServer3D::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1)8182GodotNavigationServer3D::GodotNavigationServer3D() {}8384GodotNavigationServer3D::~GodotNavigationServer3D() {85flush_queries();86}8788void GodotNavigationServer3D::add_command(SetCommand3D *command) {89MutexLock lock(commands_mutex);9091commands.push_back(command);92}9394TypedArray<RID> GodotNavigationServer3D::get_maps() const {95TypedArray<RID> all_map_rids;96LocalVector<RID> maps_owned = map_owner.get_owned_list();97uint32_t map_count = maps_owned.size();98if (map_count) {99all_map_rids.resize(map_count);100for (uint32_t i = 0; i < map_count; i++) {101all_map_rids[i] = maps_owned[i];102}103}104return all_map_rids;105}106107RID GodotNavigationServer3D::map_create() {108MutexLock lock(operations_mutex);109110RID rid = map_owner.make_rid();111NavMap3D *map = map_owner.get_or_null(rid);112map->set_self(rid);113return rid;114}115116COMMAND_2(map_set_active, RID, p_map, bool, p_active) {117NavMap3D *map = map_owner.get_or_null(p_map);118ERR_FAIL_NULL(map);119120if (p_active) {121if (!map_is_active(p_map)) {122active_maps.push_back(map);123}124} else {125int map_index = active_maps.find(map);126ERR_FAIL_COND(map_index < 0);127active_maps.remove_at(map_index);128}129}130131bool GodotNavigationServer3D::map_is_active(RID p_map) const {132NavMap3D *map = map_owner.get_or_null(p_map);133ERR_FAIL_NULL_V(map, false);134135return active_maps.has(map);136}137138COMMAND_2(map_set_up, RID, p_map, Vector3, p_up) {139NavMap3D *map = map_owner.get_or_null(p_map);140ERR_FAIL_NULL(map);141142map->set_up(p_up);143}144145Vector3 GodotNavigationServer3D::map_get_up(RID p_map) const {146const NavMap3D *map = map_owner.get_or_null(p_map);147ERR_FAIL_NULL_V(map, Vector3());148149return map->get_up();150}151152COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size) {153NavMap3D *map = map_owner.get_or_null(p_map);154ERR_FAIL_NULL(map);155156map->set_cell_size(p_cell_size);157}158159real_t GodotNavigationServer3D::map_get_cell_size(RID p_map) const {160const NavMap3D *map = map_owner.get_or_null(p_map);161ERR_FAIL_NULL_V(map, 0);162163return map->get_cell_size();164}165166COMMAND_2(map_set_cell_height, RID, p_map, real_t, p_cell_height) {167NavMap3D *map = map_owner.get_or_null(p_map);168ERR_FAIL_NULL(map);169170map->set_cell_height(p_cell_height);171}172173real_t GodotNavigationServer3D::map_get_cell_height(RID p_map) const {174const NavMap3D *map = map_owner.get_or_null(p_map);175ERR_FAIL_NULL_V(map, 0);176177return map->get_cell_height();178}179180COMMAND_2(map_set_merge_rasterizer_cell_scale, RID, p_map, float, p_value) {181NavMap3D *map = map_owner.get_or_null(p_map);182ERR_FAIL_NULL(map);183184map->set_merge_rasterizer_cell_scale(p_value);185}186187float GodotNavigationServer3D::map_get_merge_rasterizer_cell_scale(RID p_map) const {188NavMap3D *map = map_owner.get_or_null(p_map);189ERR_FAIL_NULL_V(map, false);190191return map->get_merge_rasterizer_cell_scale();192}193194COMMAND_2(map_set_use_edge_connections, RID, p_map, bool, p_enabled) {195NavMap3D *map = map_owner.get_or_null(p_map);196ERR_FAIL_NULL(map);197198map->set_use_edge_connections(p_enabled);199}200201bool GodotNavigationServer3D::map_get_use_edge_connections(RID p_map) const {202NavMap3D *map = map_owner.get_or_null(p_map);203ERR_FAIL_NULL_V(map, false);204205return map->get_use_edge_connections();206}207208COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin) {209NavMap3D *map = map_owner.get_or_null(p_map);210ERR_FAIL_NULL(map);211212map->set_edge_connection_margin(p_connection_margin);213}214215real_t GodotNavigationServer3D::map_get_edge_connection_margin(RID p_map) const {216const NavMap3D *map = map_owner.get_or_null(p_map);217ERR_FAIL_NULL_V(map, 0);218219return map->get_edge_connection_margin();220}221222COMMAND_2(map_set_link_connection_radius, RID, p_map, real_t, p_connection_radius) {223NavMap3D *map = map_owner.get_or_null(p_map);224ERR_FAIL_NULL(map);225226map->set_link_connection_radius(p_connection_radius);227}228229real_t GodotNavigationServer3D::map_get_link_connection_radius(RID p_map) const {230const NavMap3D *map = map_owner.get_or_null(p_map);231ERR_FAIL_NULL_V(map, 0);232233return map->get_link_connection_radius();234}235236Vector<Vector3> GodotNavigationServer3D::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_navigation_layers) {237const NavMap3D *map = map_owner.get_or_null(p_map);238ERR_FAIL_NULL_V(map, Vector<Vector3>());239240Ref<NavigationPathQueryParameters3D> query_parameters;241query_parameters.instantiate();242243query_parameters->set_map(p_map);244query_parameters->set_start_position(p_origin);245query_parameters->set_target_position(p_destination);246query_parameters->set_navigation_layers(p_navigation_layers);247query_parameters->set_pathfinding_algorithm(NavigationPathQueryParameters3D::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR);248query_parameters->set_path_postprocessing(NavigationPathQueryParameters3D::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL);249if (!p_optimize) {250query_parameters->set_path_postprocessing(NavigationPathQueryParameters3D::PATH_POSTPROCESSING_EDGECENTERED);251}252253Ref<NavigationPathQueryResult3D> query_result;254query_result.instantiate();255256query_path(query_parameters, query_result);257258return query_result->get_path();259}260261Vector3 GodotNavigationServer3D::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const {262const NavMap3D *map = map_owner.get_or_null(p_map);263ERR_FAIL_NULL_V(map, Vector3());264265return map->get_closest_point_to_segment(p_from, p_to, p_use_collision);266}267268Vector3 GodotNavigationServer3D::map_get_closest_point(RID p_map, const Vector3 &p_point) const {269const NavMap3D *map = map_owner.get_or_null(p_map);270ERR_FAIL_NULL_V(map, Vector3());271272return map->get_closest_point(p_point);273}274275Vector3 GodotNavigationServer3D::map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const {276const NavMap3D *map = map_owner.get_or_null(p_map);277ERR_FAIL_NULL_V(map, Vector3());278279return map->get_closest_point_normal(p_point);280}281282RID GodotNavigationServer3D::map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const {283const NavMap3D *map = map_owner.get_or_null(p_map);284ERR_FAIL_NULL_V(map, RID());285286return map->get_closest_point_owner(p_point);287}288289TypedArray<RID> GodotNavigationServer3D::map_get_links(RID p_map) const {290TypedArray<RID> link_rids;291const NavMap3D *map = map_owner.get_or_null(p_map);292ERR_FAIL_NULL_V(map, link_rids);293294const LocalVector<NavLink3D *> &links = map->get_links();295link_rids.resize(links.size());296297for (uint32_t i = 0; i < links.size(); i++) {298link_rids[i] = links[i]->get_self();299}300return link_rids;301}302303TypedArray<RID> GodotNavigationServer3D::map_get_regions(RID p_map) const {304TypedArray<RID> regions_rids;305const NavMap3D *map = map_owner.get_or_null(p_map);306ERR_FAIL_NULL_V(map, regions_rids);307308const LocalVector<NavRegion3D *> ®ions = map->get_regions();309regions_rids.resize(regions.size());310311for (uint32_t i = 0; i < regions.size(); i++) {312regions_rids[i] = regions[i]->get_self();313}314return regions_rids;315}316317TypedArray<RID> GodotNavigationServer3D::map_get_agents(RID p_map) const {318TypedArray<RID> agents_rids;319const NavMap3D *map = map_owner.get_or_null(p_map);320ERR_FAIL_NULL_V(map, agents_rids);321322const LocalVector<NavAgent3D *> &agents = map->get_agents();323agents_rids.resize(agents.size());324325for (uint32_t i = 0; i < agents.size(); i++) {326agents_rids[i] = agents[i]->get_self();327}328return agents_rids;329}330331TypedArray<RID> GodotNavigationServer3D::map_get_obstacles(RID p_map) const {332TypedArray<RID> obstacles_rids;333const NavMap3D *map = map_owner.get_or_null(p_map);334ERR_FAIL_NULL_V(map, obstacles_rids);335const LocalVector<NavObstacle3D *> obstacles = map->get_obstacles();336obstacles_rids.resize(obstacles.size());337for (uint32_t i = 0; i < obstacles.size(); i++) {338obstacles_rids[i] = obstacles[i]->get_self();339}340return obstacles_rids;341}342343RID GodotNavigationServer3D::region_get_map(RID p_region) const {344NavRegion3D *region = region_owner.get_or_null(p_region);345ERR_FAIL_NULL_V(region, RID());346347if (region->get_map()) {348return region->get_map()->get_self();349}350return RID();351}352353RID GodotNavigationServer3D::agent_get_map(RID p_agent) const {354NavAgent3D *agent = agent_owner.get_or_null(p_agent);355ERR_FAIL_NULL_V(agent, RID());356357if (agent->get_map()) {358return agent->get_map()->get_self();359}360return RID();361}362363COMMAND_2(map_set_use_async_iterations, RID, p_map, bool, p_enabled) {364NavMap3D *map = map_owner.get_or_null(p_map);365ERR_FAIL_NULL(map);366map->set_use_async_iterations(p_enabled);367}368369bool GodotNavigationServer3D::map_get_use_async_iterations(RID p_map) const {370const NavMap3D *map = map_owner.get_or_null(p_map);371ERR_FAIL_NULL_V(map, false);372373return map->get_use_async_iterations();374}375376Vector3 GodotNavigationServer3D::map_get_random_point(RID p_map, uint32_t p_navigation_layers, bool p_uniformly) const {377const NavMap3D *map = map_owner.get_or_null(p_map);378ERR_FAIL_NULL_V(map, Vector3());379380return map->get_random_point(p_navigation_layers, p_uniformly);381}382383RID GodotNavigationServer3D::region_create() {384MutexLock lock(operations_mutex);385386RID rid = region_owner.make_rid();387NavRegion3D *reg = region_owner.get_or_null(rid);388reg->set_self(rid);389return rid;390}391392uint32_t GodotNavigationServer3D::region_get_iteration_id(RID p_region) const {393NavRegion3D *region = region_owner.get_or_null(p_region);394ERR_FAIL_NULL_V(region, 0);395396return region->get_iteration_id();397}398399COMMAND_2(region_set_use_async_iterations, RID, p_region, bool, p_enabled) {400NavRegion3D *region = region_owner.get_or_null(p_region);401ERR_FAIL_NULL(region);402region->set_use_async_iterations(p_enabled);403}404405bool GodotNavigationServer3D::region_get_use_async_iterations(RID p_region) const {406NavRegion3D *region = region_owner.get_or_null(p_region);407ERR_FAIL_NULL_V(region, false);408409return region->get_use_async_iterations();410}411412COMMAND_2(region_set_enabled, RID, p_region, bool, p_enabled) {413NavRegion3D *region = region_owner.get_or_null(p_region);414ERR_FAIL_NULL(region);415416region->set_enabled(p_enabled);417}418419bool GodotNavigationServer3D::region_get_enabled(RID p_region) const {420const NavRegion3D *region = region_owner.get_or_null(p_region);421ERR_FAIL_NULL_V(region, false);422423return region->get_enabled();424}425426COMMAND_2(region_set_use_edge_connections, RID, p_region, bool, p_enabled) {427NavRegion3D *region = region_owner.get_or_null(p_region);428ERR_FAIL_NULL(region);429430region->set_use_edge_connections(p_enabled);431}432433bool GodotNavigationServer3D::region_get_use_edge_connections(RID p_region) const {434NavRegion3D *region = region_owner.get_or_null(p_region);435ERR_FAIL_NULL_V(region, false);436437return region->get_use_edge_connections();438}439440COMMAND_2(region_set_map, RID, p_region, RID, p_map) {441NavRegion3D *region = region_owner.get_or_null(p_region);442ERR_FAIL_NULL(region);443444NavMap3D *map = map_owner.get_or_null(p_map);445446region->set_map(map);447}448449COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform) {450NavRegion3D *region = region_owner.get_or_null(p_region);451ERR_FAIL_NULL(region);452453region->set_transform(p_transform);454}455456Transform3D GodotNavigationServer3D::region_get_transform(RID p_region) const {457NavRegion3D *region = region_owner.get_or_null(p_region);458ERR_FAIL_NULL_V(region, Transform3D());459460return region->get_transform();461}462463COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost) {464NavRegion3D *region = region_owner.get_or_null(p_region);465ERR_FAIL_NULL(region);466ERR_FAIL_COND(p_enter_cost < 0.0);467468region->set_enter_cost(p_enter_cost);469}470471real_t GodotNavigationServer3D::region_get_enter_cost(RID p_region) const {472NavRegion3D *region = region_owner.get_or_null(p_region);473ERR_FAIL_NULL_V(region, 0);474475return region->get_enter_cost();476}477478COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost) {479NavRegion3D *region = region_owner.get_or_null(p_region);480ERR_FAIL_NULL(region);481ERR_FAIL_COND(p_travel_cost < 0.0);482483region->set_travel_cost(p_travel_cost);484}485486real_t GodotNavigationServer3D::region_get_travel_cost(RID p_region) const {487NavRegion3D *region = region_owner.get_or_null(p_region);488ERR_FAIL_NULL_V(region, 0);489490return region->get_travel_cost();491}492493COMMAND_2(region_set_owner_id, RID, p_region, ObjectID, p_owner_id) {494NavRegion3D *region = region_owner.get_or_null(p_region);495ERR_FAIL_NULL(region);496497region->set_owner_id(p_owner_id);498}499500ObjectID GodotNavigationServer3D::region_get_owner_id(RID p_region) const {501const NavRegion3D *region = region_owner.get_or_null(p_region);502ERR_FAIL_NULL_V(region, ObjectID());503504return region->get_owner_id();505}506507bool GodotNavigationServer3D::region_owns_point(RID p_region, const Vector3 &p_point) const {508const NavRegion3D *region = region_owner.get_or_null(p_region);509ERR_FAIL_NULL_V(region, false);510511if (region->get_map()) {512RID closest_point_owner = map_get_closest_point_owner(region->get_map()->get_self(), p_point);513return closest_point_owner == region->get_self();514}515return false;516}517518COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers) {519NavRegion3D *region = region_owner.get_or_null(p_region);520ERR_FAIL_NULL(region);521522region->set_navigation_layers(p_navigation_layers);523}524525uint32_t GodotNavigationServer3D::region_get_navigation_layers(RID p_region) const {526NavRegion3D *region = region_owner.get_or_null(p_region);527ERR_FAIL_NULL_V(region, 0);528529return region->get_navigation_layers();530}531532COMMAND_2(region_set_navigation_mesh, RID, p_region, Ref<NavigationMesh>, p_navigation_mesh) {533NavRegion3D *region = region_owner.get_or_null(p_region);534ERR_FAIL_NULL(region);535536region->set_navigation_mesh(p_navigation_mesh);537}538539#ifndef DISABLE_DEPRECATED540void GodotNavigationServer3D::region_bake_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh, Node *p_root_node) {541ERR_FAIL_COND(p_navigation_mesh.is_null());542ERR_FAIL_NULL(p_root_node);543544WARN_PRINT_ONCE("NavigationServer3D::region_bake_navigation_mesh() is deprecated due to core threading changes. To upgrade existing code, first create a NavigationMeshSourceGeometryData3D resource. Use this resource with method parse_source_geometry_data() to parse the SceneTree for nodes that should contribute to the navigation mesh baking. The SceneTree parsing needs to happen on the main thread. After the parsing is finished use the resource with method bake_from_source_geometry_data() to bake a navigation mesh..");545546p_navigation_mesh->clear();547Ref<NavigationMeshSourceGeometryData3D> source_geometry_data;548source_geometry_data.instantiate();549parse_source_geometry_data(p_navigation_mesh, source_geometry_data, p_root_node);550bake_from_source_geometry_data(p_navigation_mesh, source_geometry_data);551}552#endif // DISABLE_DEPRECATED553554int GodotNavigationServer3D::region_get_connections_count(RID p_region) const {555NavRegion3D *region = region_owner.get_or_null(p_region);556ERR_FAIL_NULL_V(region, 0);557NavMap3D *map = region->get_map();558if (map) {559return map->get_region_connections_count(region);560}561return 0;562}563564Vector3 GodotNavigationServer3D::region_get_connection_pathway_start(RID p_region, int p_connection_id) const {565NavRegion3D *region = region_owner.get_or_null(p_region);566ERR_FAIL_NULL_V(region, Vector3());567NavMap3D *map = region->get_map();568if (map) {569return map->get_region_connection_pathway_start(region, p_connection_id);570}571return Vector3();572}573574Vector3 GodotNavigationServer3D::region_get_connection_pathway_end(RID p_region, int p_connection_id) const {575NavRegion3D *region = region_owner.get_or_null(p_region);576ERR_FAIL_NULL_V(region, Vector3());577NavMap3D *map = region->get_map();578if (map) {579return map->get_region_connection_pathway_end(region, p_connection_id);580}581return Vector3();582}583584Vector3 GodotNavigationServer3D::region_get_closest_point_to_segment(RID p_region, const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const {585const NavRegion3D *region = region_owner.get_or_null(p_region);586ERR_FAIL_NULL_V(region, Vector3());587588return region->get_closest_point_to_segment(p_from, p_to, p_use_collision);589}590591Vector3 GodotNavigationServer3D::region_get_closest_point(RID p_region, const Vector3 &p_point) const {592const NavRegion3D *region = region_owner.get_or_null(p_region);593ERR_FAIL_NULL_V(region, Vector3());594595return region->get_closest_point_info(p_point).point;596}597598Vector3 GodotNavigationServer3D::region_get_closest_point_normal(RID p_region, const Vector3 &p_point) const {599const NavRegion3D *region = region_owner.get_or_null(p_region);600ERR_FAIL_NULL_V(region, Vector3());601602return region->get_closest_point_info(p_point).normal;603}604605Vector3 GodotNavigationServer3D::region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const {606const NavRegion3D *region = region_owner.get_or_null(p_region);607ERR_FAIL_NULL_V(region, Vector3());608609return region->get_random_point(p_navigation_layers, p_uniformly);610}611612AABB GodotNavigationServer3D::region_get_bounds(RID p_region) const {613const NavRegion3D *region = region_owner.get_or_null(p_region);614ERR_FAIL_NULL_V(region, AABB());615616return region->get_bounds();617}618619RID GodotNavigationServer3D::link_create() {620MutexLock lock(operations_mutex);621622RID rid = link_owner.make_rid();623NavLink3D *link = link_owner.get_or_null(rid);624link->set_self(rid);625return rid;626}627628uint32_t GodotNavigationServer3D::link_get_iteration_id(RID p_link) const {629NavLink3D *link = link_owner.get_or_null(p_link);630ERR_FAIL_NULL_V(link, 0);631632return link->get_iteration_id();633}634635COMMAND_2(link_set_map, RID, p_link, RID, p_map) {636NavLink3D *link = link_owner.get_or_null(p_link);637ERR_FAIL_NULL(link);638639NavMap3D *map = map_owner.get_or_null(p_map);640641link->set_map(map);642}643644RID GodotNavigationServer3D::link_get_map(const RID p_link) const {645const NavLink3D *link = link_owner.get_or_null(p_link);646ERR_FAIL_NULL_V(link, RID());647648if (link->get_map()) {649return link->get_map()->get_self();650}651return RID();652}653654COMMAND_2(link_set_enabled, RID, p_link, bool, p_enabled) {655NavLink3D *link = link_owner.get_or_null(p_link);656ERR_FAIL_NULL(link);657658link->set_enabled(p_enabled);659}660661bool GodotNavigationServer3D::link_get_enabled(RID p_link) const {662const NavLink3D *link = link_owner.get_or_null(p_link);663ERR_FAIL_NULL_V(link, false);664665return link->get_enabled();666}667668COMMAND_2(link_set_bidirectional, RID, p_link, bool, p_bidirectional) {669NavLink3D *link = link_owner.get_or_null(p_link);670ERR_FAIL_NULL(link);671672link->set_bidirectional(p_bidirectional);673}674675bool GodotNavigationServer3D::link_is_bidirectional(RID p_link) const {676const NavLink3D *link = link_owner.get_or_null(p_link);677ERR_FAIL_NULL_V(link, false);678679return link->is_bidirectional();680}681682COMMAND_2(link_set_navigation_layers, RID, p_link, uint32_t, p_navigation_layers) {683NavLink3D *link = link_owner.get_or_null(p_link);684ERR_FAIL_NULL(link);685686link->set_navigation_layers(p_navigation_layers);687}688689uint32_t GodotNavigationServer3D::link_get_navigation_layers(const RID p_link) const {690const NavLink3D *link = link_owner.get_or_null(p_link);691ERR_FAIL_NULL_V(link, 0);692693return link->get_navigation_layers();694}695696COMMAND_2(link_set_start_position, RID, p_link, Vector3, p_position) {697NavLink3D *link = link_owner.get_or_null(p_link);698ERR_FAIL_NULL(link);699700link->set_start_position(p_position);701}702703Vector3 GodotNavigationServer3D::link_get_start_position(RID p_link) const {704const NavLink3D *link = link_owner.get_or_null(p_link);705ERR_FAIL_NULL_V(link, Vector3());706707return link->get_start_position();708}709710COMMAND_2(link_set_end_position, RID, p_link, Vector3, p_position) {711NavLink3D *link = link_owner.get_or_null(p_link);712ERR_FAIL_NULL(link);713714link->set_end_position(p_position);715}716717Vector3 GodotNavigationServer3D::link_get_end_position(RID p_link) const {718const NavLink3D *link = link_owner.get_or_null(p_link);719ERR_FAIL_NULL_V(link, Vector3());720721return link->get_end_position();722}723724COMMAND_2(link_set_enter_cost, RID, p_link, real_t, p_enter_cost) {725NavLink3D *link = link_owner.get_or_null(p_link);726ERR_FAIL_NULL(link);727728link->set_enter_cost(p_enter_cost);729}730731real_t GodotNavigationServer3D::link_get_enter_cost(const RID p_link) const {732const NavLink3D *link = link_owner.get_or_null(p_link);733ERR_FAIL_NULL_V(link, 0);734735return link->get_enter_cost();736}737738COMMAND_2(link_set_travel_cost, RID, p_link, real_t, p_travel_cost) {739NavLink3D *link = link_owner.get_or_null(p_link);740ERR_FAIL_NULL(link);741742link->set_travel_cost(p_travel_cost);743}744745real_t GodotNavigationServer3D::link_get_travel_cost(const RID p_link) const {746const NavLink3D *link = link_owner.get_or_null(p_link);747ERR_FAIL_NULL_V(link, 0);748749return link->get_travel_cost();750}751752COMMAND_2(link_set_owner_id, RID, p_link, ObjectID, p_owner_id) {753NavLink3D *link = link_owner.get_or_null(p_link);754ERR_FAIL_NULL(link);755756link->set_owner_id(p_owner_id);757}758759ObjectID GodotNavigationServer3D::link_get_owner_id(RID p_link) const {760const NavLink3D *link = link_owner.get_or_null(p_link);761ERR_FAIL_NULL_V(link, ObjectID());762763return link->get_owner_id();764}765766RID GodotNavigationServer3D::agent_create() {767MutexLock lock(operations_mutex);768769RID rid = agent_owner.make_rid();770NavAgent3D *agent = agent_owner.get_or_null(rid);771agent->set_self(rid);772return rid;773}774775COMMAND_2(agent_set_avoidance_enabled, RID, p_agent, bool, p_enabled) {776NavAgent3D *agent = agent_owner.get_or_null(p_agent);777ERR_FAIL_NULL(agent);778779agent->set_avoidance_enabled(p_enabled);780}781782bool GodotNavigationServer3D::agent_get_avoidance_enabled(RID p_agent) const {783NavAgent3D *agent = agent_owner.get_or_null(p_agent);784ERR_FAIL_NULL_V(agent, false);785786return agent->is_avoidance_enabled();787}788789COMMAND_2(agent_set_use_3d_avoidance, RID, p_agent, bool, p_enabled) {790NavAgent3D *agent = agent_owner.get_or_null(p_agent);791ERR_FAIL_NULL(agent);792793agent->set_use_3d_avoidance(p_enabled);794}795796bool GodotNavigationServer3D::agent_get_use_3d_avoidance(RID p_agent) const {797NavAgent3D *agent = agent_owner.get_or_null(p_agent);798ERR_FAIL_NULL_V(agent, false);799800return agent->get_use_3d_avoidance();801}802803COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) {804NavAgent3D *agent = agent_owner.get_or_null(p_agent);805ERR_FAIL_NULL(agent);806807NavMap3D *map = map_owner.get_or_null(p_map);808809agent->set_map(map);810}811812COMMAND_2(agent_set_paused, RID, p_agent, bool, p_paused) {813NavAgent3D *agent = agent_owner.get_or_null(p_agent);814ERR_FAIL_NULL(agent);815816agent->set_paused(p_paused);817}818819bool GodotNavigationServer3D::agent_get_paused(RID p_agent) const {820NavAgent3D *agent = agent_owner.get_or_null(p_agent);821ERR_FAIL_NULL_V(agent, false);822823return agent->get_paused();824}825826COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance) {827NavAgent3D *agent = agent_owner.get_or_null(p_agent);828ERR_FAIL_NULL(agent);829830agent->set_neighbor_distance(p_distance);831}832833real_t GodotNavigationServer3D::agent_get_neighbor_distance(RID p_agent) const {834NavAgent3D *agent = agent_owner.get_or_null(p_agent);835ERR_FAIL_NULL_V(agent, 0);836837return agent->get_neighbor_distance();838}839840COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count) {841NavAgent3D *agent = agent_owner.get_or_null(p_agent);842ERR_FAIL_NULL(agent);843844agent->set_max_neighbors(p_count);845}846847int GodotNavigationServer3D::agent_get_max_neighbors(RID p_agent) const {848NavAgent3D *agent = agent_owner.get_or_null(p_agent);849ERR_FAIL_NULL_V(agent, 0);850851return agent->get_max_neighbors();852}853854COMMAND_2(agent_set_time_horizon_agents, RID, p_agent, real_t, p_time_horizon) {855ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizon must be positive.");856NavAgent3D *agent = agent_owner.get_or_null(p_agent);857ERR_FAIL_NULL(agent);858859agent->set_time_horizon_agents(p_time_horizon);860}861862real_t GodotNavigationServer3D::agent_get_time_horizon_agents(RID p_agent) const {863NavAgent3D *agent = agent_owner.get_or_null(p_agent);864ERR_FAIL_NULL_V(agent, 0);865866return agent->get_time_horizon_agents();867}868869COMMAND_2(agent_set_time_horizon_obstacles, RID, p_agent, real_t, p_time_horizon) {870ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizon must be positive.");871NavAgent3D *agent = agent_owner.get_or_null(p_agent);872ERR_FAIL_NULL(agent);873874agent->set_time_horizon_obstacles(p_time_horizon);875}876877real_t GodotNavigationServer3D::agent_get_time_horizon_obstacles(RID p_agent) const {878NavAgent3D *agent = agent_owner.get_or_null(p_agent);879ERR_FAIL_NULL_V(agent, 0);880881return agent->get_time_horizon_obstacles();882}883884COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius) {885ERR_FAIL_COND_MSG(p_radius < 0.0, "Radius must be positive.");886NavAgent3D *agent = agent_owner.get_or_null(p_agent);887ERR_FAIL_NULL(agent);888889agent->set_radius(p_radius);890}891892real_t GodotNavigationServer3D::agent_get_radius(RID p_agent) const {893NavAgent3D *agent = agent_owner.get_or_null(p_agent);894ERR_FAIL_NULL_V(agent, 0);895896return agent->get_radius();897}898899COMMAND_2(agent_set_height, RID, p_agent, real_t, p_height) {900ERR_FAIL_COND_MSG(p_height < 0.0, "Height must be positive.");901NavAgent3D *agent = agent_owner.get_or_null(p_agent);902ERR_FAIL_NULL(agent);903904agent->set_height(p_height);905}906907real_t GodotNavigationServer3D::agent_get_height(RID p_agent) const {908NavAgent3D *agent = agent_owner.get_or_null(p_agent);909ERR_FAIL_NULL_V(agent, 0);910911return agent->get_height();912}913914COMMAND_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed) {915ERR_FAIL_COND_MSG(p_max_speed < 0.0, "Max speed must be positive.");916NavAgent3D *agent = agent_owner.get_or_null(p_agent);917ERR_FAIL_NULL(agent);918919agent->set_max_speed(p_max_speed);920}921922real_t GodotNavigationServer3D::agent_get_max_speed(RID p_agent) const {923NavAgent3D *agent = agent_owner.get_or_null(p_agent);924ERR_FAIL_NULL_V(agent, 0);925926return agent->get_max_speed();927}928929COMMAND_2(agent_set_velocity, RID, p_agent, Vector3, p_velocity) {930NavAgent3D *agent = agent_owner.get_or_null(p_agent);931ERR_FAIL_NULL(agent);932933agent->set_velocity(p_velocity);934}935936Vector3 GodotNavigationServer3D::agent_get_velocity(RID p_agent) const {937NavAgent3D *agent = agent_owner.get_or_null(p_agent);938ERR_FAIL_NULL_V(agent, Vector3());939940return agent->get_velocity();941}942943COMMAND_2(agent_set_velocity_forced, RID, p_agent, Vector3, p_velocity) {944NavAgent3D *agent = agent_owner.get_or_null(p_agent);945ERR_FAIL_NULL(agent);946947agent->set_velocity_forced(p_velocity);948}949950COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position) {951NavAgent3D *agent = agent_owner.get_or_null(p_agent);952ERR_FAIL_NULL(agent);953954agent->set_position(p_position);955}956957Vector3 GodotNavigationServer3D::agent_get_position(RID p_agent) const {958NavAgent3D *agent = agent_owner.get_or_null(p_agent);959ERR_FAIL_NULL_V(agent, Vector3());960961return agent->get_position();962}963964bool GodotNavigationServer3D::agent_is_map_changed(RID p_agent) const {965NavAgent3D *agent = agent_owner.get_or_null(p_agent);966ERR_FAIL_NULL_V(agent, false);967968return agent->is_map_changed();969}970971COMMAND_2(agent_set_avoidance_callback, RID, p_agent, Callable, p_callback) {972NavAgent3D *agent = agent_owner.get_or_null(p_agent);973ERR_FAIL_NULL(agent);974975agent->set_avoidance_callback(p_callback);976977if (agent->get_map()) {978if (p_callback.is_valid()) {979agent->get_map()->set_agent_as_controlled(agent);980} else {981agent->get_map()->remove_agent_as_controlled(agent);982}983}984}985986bool GodotNavigationServer3D::agent_has_avoidance_callback(RID p_agent) const {987NavAgent3D *agent = agent_owner.get_or_null(p_agent);988ERR_FAIL_NULL_V(agent, false);989990return agent->has_avoidance_callback();991}992993COMMAND_2(agent_set_avoidance_layers, RID, p_agent, uint32_t, p_layers) {994NavAgent3D *agent = agent_owner.get_or_null(p_agent);995ERR_FAIL_NULL(agent);996agent->set_avoidance_layers(p_layers);997}998999uint32_t GodotNavigationServer3D::agent_get_avoidance_layers(RID p_agent) const {1000NavAgent3D *agent = agent_owner.get_or_null(p_agent);1001ERR_FAIL_NULL_V(agent, 0);10021003return agent->get_avoidance_layers();1004}10051006COMMAND_2(agent_set_avoidance_mask, RID, p_agent, uint32_t, p_mask) {1007NavAgent3D *agent = agent_owner.get_or_null(p_agent);1008ERR_FAIL_NULL(agent);1009agent->set_avoidance_mask(p_mask);1010}10111012uint32_t GodotNavigationServer3D::agent_get_avoidance_mask(RID p_agent) const {1013NavAgent3D *agent = agent_owner.get_or_null(p_agent);1014ERR_FAIL_NULL_V(agent, 0);10151016return agent->get_avoidance_mask();1017}10181019COMMAND_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority) {1020ERR_FAIL_COND_MSG(p_priority < 0.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");1021ERR_FAIL_COND_MSG(p_priority > 1.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");1022NavAgent3D *agent = agent_owner.get_or_null(p_agent);1023ERR_FAIL_NULL(agent);1024agent->set_avoidance_priority(p_priority);1025}10261027real_t GodotNavigationServer3D::agent_get_avoidance_priority(RID p_agent) const {1028NavAgent3D *agent = agent_owner.get_or_null(p_agent);1029ERR_FAIL_NULL_V(agent, 0);10301031return agent->get_avoidance_priority();1032}10331034RID GodotNavigationServer3D::obstacle_create() {1035MutexLock lock(operations_mutex);10361037RID rid = obstacle_owner.make_rid();1038NavObstacle3D *obstacle = obstacle_owner.get_or_null(rid);1039obstacle->set_self(rid);10401041RID agent_rid = agent_owner.make_rid();1042NavAgent3D *agent = agent_owner.get_or_null(agent_rid);1043agent->set_self(agent_rid);10441045obstacle->set_agent(agent);10461047return rid;1048}10491050COMMAND_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled) {1051NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1052ERR_FAIL_NULL(obstacle);10531054obstacle->set_avoidance_enabled(p_enabled);1055}10561057bool GodotNavigationServer3D::obstacle_get_avoidance_enabled(RID p_obstacle) const {1058NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1059ERR_FAIL_NULL_V(obstacle, false);10601061return obstacle->is_avoidance_enabled();1062}10631064COMMAND_2(obstacle_set_use_3d_avoidance, RID, p_obstacle, bool, p_enabled) {1065NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1066ERR_FAIL_NULL(obstacle);10671068obstacle->set_use_3d_avoidance(p_enabled);1069}10701071bool GodotNavigationServer3D::obstacle_get_use_3d_avoidance(RID p_obstacle) const {1072NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1073ERR_FAIL_NULL_V(obstacle, false);10741075return obstacle->get_use_3d_avoidance();1076}10771078COMMAND_2(obstacle_set_map, RID, p_obstacle, RID, p_map) {1079NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1080ERR_FAIL_NULL(obstacle);10811082NavMap3D *map = map_owner.get_or_null(p_map);10831084obstacle->set_map(map);1085}10861087RID GodotNavigationServer3D::obstacle_get_map(RID p_obstacle) const {1088NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1089ERR_FAIL_NULL_V(obstacle, RID());1090if (obstacle->get_map()) {1091return obstacle->get_map()->get_self();1092}1093return RID();1094}10951096COMMAND_2(obstacle_set_paused, RID, p_obstacle, bool, p_paused) {1097NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1098ERR_FAIL_NULL(obstacle);10991100obstacle->set_paused(p_paused);1101}11021103bool GodotNavigationServer3D::obstacle_get_paused(RID p_obstacle) const {1104NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1105ERR_FAIL_NULL_V(obstacle, false);11061107return obstacle->get_paused();1108}11091110COMMAND_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius) {1111ERR_FAIL_COND_MSG(p_radius < 0.0, "Radius must be positive.");1112NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1113ERR_FAIL_NULL(obstacle);11141115obstacle->set_radius(p_radius);1116}11171118real_t GodotNavigationServer3D::obstacle_get_radius(RID p_obstacle) const {1119NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1120ERR_FAIL_NULL_V(obstacle, 0);11211122return obstacle->get_radius();1123}11241125COMMAND_2(obstacle_set_height, RID, p_obstacle, real_t, p_height) {1126NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1127ERR_FAIL_NULL(obstacle);1128obstacle->set_height(p_height);1129}11301131real_t GodotNavigationServer3D::obstacle_get_height(RID p_obstacle) const {1132NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1133ERR_FAIL_NULL_V(obstacle, 0);11341135return obstacle->get_height();1136}11371138COMMAND_2(obstacle_set_velocity, RID, p_obstacle, Vector3, p_velocity) {1139NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1140ERR_FAIL_NULL(obstacle);11411142obstacle->set_velocity(p_velocity);1143}11441145Vector3 GodotNavigationServer3D::obstacle_get_velocity(RID p_obstacle) const {1146NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1147ERR_FAIL_NULL_V(obstacle, Vector3());11481149return obstacle->get_velocity();1150}11511152COMMAND_2(obstacle_set_position, RID, p_obstacle, Vector3, p_position) {1153NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1154ERR_FAIL_NULL(obstacle);1155obstacle->set_position(p_position);1156}11571158Vector3 GodotNavigationServer3D::obstacle_get_position(RID p_obstacle) const {1159NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1160ERR_FAIL_NULL_V(obstacle, Vector3());11611162return obstacle->get_position();1163}11641165void GodotNavigationServer3D::obstacle_set_vertices(RID p_obstacle, const Vector<Vector3> &p_vertices) {1166NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1167ERR_FAIL_NULL(obstacle);1168obstacle->set_vertices(p_vertices);1169}11701171Vector<Vector3> GodotNavigationServer3D::obstacle_get_vertices(RID p_obstacle) const {1172NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1173ERR_FAIL_NULL_V(obstacle, Vector<Vector3>());11741175return obstacle->get_vertices();1176}11771178COMMAND_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers) {1179NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1180ERR_FAIL_NULL(obstacle);1181obstacle->set_avoidance_layers(p_layers);1182}11831184uint32_t GodotNavigationServer3D::obstacle_get_avoidance_layers(RID p_obstacle) const {1185NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_obstacle);1186ERR_FAIL_NULL_V(obstacle, 0);11871188return obstacle->get_avoidance_layers();1189}11901191void GodotNavigationServer3D::parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, Node *p_root_node, const Callable &p_callback) {1192ERR_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().");1193ERR_FAIL_COND_MSG(p_navigation_mesh.is_null(), "Invalid navigation mesh.");1194ERR_FAIL_NULL_MSG(p_root_node, "No parsing root node specified.");1195ERR_FAIL_COND_MSG(!p_root_node->is_inside_tree(), "The root node needs to be inside the SceneTree.");11961197ERR_FAIL_NULL(NavMeshGenerator3D::get_singleton());1198NavMeshGenerator3D::get_singleton()->parse_source_geometry_data(p_navigation_mesh, p_source_geometry_data, p_root_node, p_callback);1199}12001201void GodotNavigationServer3D::bake_from_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback) {1202ERR_FAIL_COND_MSG(p_navigation_mesh.is_null(), "Invalid navigation mesh.");1203ERR_FAIL_COND_MSG(p_source_geometry_data.is_null(), "Invalid NavigationMeshSourceGeometryData3D.");12041205ERR_FAIL_NULL(NavMeshGenerator3D::get_singleton());1206NavMeshGenerator3D::get_singleton()->bake_from_source_geometry_data(p_navigation_mesh, p_source_geometry_data, p_callback);1207}12081209void GodotNavigationServer3D::bake_from_source_geometry_data_async(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback) {1210ERR_FAIL_COND_MSG(p_navigation_mesh.is_null(), "Invalid navigation mesh.");1211ERR_FAIL_COND_MSG(p_source_geometry_data.is_null(), "Invalid NavigationMeshSourceGeometryData3D.");12121213ERR_FAIL_NULL(NavMeshGenerator3D::get_singleton());1214NavMeshGenerator3D::get_singleton()->bake_from_source_geometry_data_async(p_navigation_mesh, p_source_geometry_data, p_callback);1215}12161217bool GodotNavigationServer3D::is_baking_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh) const {1218return NavMeshGenerator3D::get_singleton()->is_baking(p_navigation_mesh);1219}12201221String GodotNavigationServer3D::get_baking_navigation_mesh_state_msg(Ref<NavigationMesh> p_navigation_mesh) const {1222#ifdef _3D_DISABLED1223return "";1224#else1225return NavMeshGenerator3D::get_singleton()->get_baking_state_msg(p_navigation_mesh);1226#endif // _3D_DISABLED1227}12281229COMMAND_1(free, RID, p_object) {1230if (map_owner.owns(p_object)) {1231NavMap3D *map = map_owner.get_or_null(p_object);12321233// Removes any assigned region1234for (NavRegion3D *region : map->get_regions()) {1235map->remove_region(region);1236region->set_map(nullptr);1237}12381239// Removes any assigned links1240for (NavLink3D *link : map->get_links()) {1241map->remove_link(link);1242link->set_map(nullptr);1243}12441245// Remove any assigned agent1246for (NavAgent3D *agent : map->get_agents()) {1247map->remove_agent(agent);1248agent->set_map(nullptr);1249}12501251// Remove any assigned obstacles1252for (NavObstacle3D *obstacle : map->get_obstacles()) {1253map->remove_obstacle(obstacle);1254obstacle->set_map(nullptr);1255}12561257int map_index = active_maps.find(map);1258if (map_index >= 0) {1259active_maps.remove_at(map_index);1260}1261map_owner.free(p_object);12621263} else if (region_owner.owns(p_object)) {1264NavRegion3D *region = region_owner.get_or_null(p_object);12651266// Removes this region from the map if assigned1267if (region->get_map() != nullptr) {1268region->get_map()->remove_region(region);1269region->set_map(nullptr);1270}12711272region_owner.free(p_object);12731274} else if (link_owner.owns(p_object)) {1275NavLink3D *link = link_owner.get_or_null(p_object);12761277// Removes this link from the map if assigned1278if (link->get_map() != nullptr) {1279link->get_map()->remove_link(link);1280link->set_map(nullptr);1281}12821283link_owner.free(p_object);12841285} else if (agent_owner.owns(p_object)) {1286internal_free_agent(p_object);12871288} else if (obstacle_owner.owns(p_object)) {1289internal_free_obstacle(p_object);12901291} else if (geometry_parser_owner.owns(p_object)) {1292RWLockWrite write_lock(geometry_parser_rwlock);12931294NavMeshGeometryParser3D *parser = geometry_parser_owner.get_or_null(p_object);1295ERR_FAIL_NULL(parser);12961297generator_parsers.erase(parser);1298NavMeshGenerator3D::get_singleton()->set_generator_parsers(generator_parsers);1299geometry_parser_owner.free(parser->self);13001301} else {1302ERR_PRINT("Attempted to free a NavigationServer RID that did not exist (or was already freed).");1303}1304}13051306void GodotNavigationServer3D::internal_free_agent(RID p_object) {1307NavAgent3D *agent = agent_owner.get_or_null(p_object);1308if (agent) {1309if (agent->get_map() != nullptr) {1310agent->get_map()->remove_agent(agent);1311agent->set_map(nullptr);1312}1313agent_owner.free(p_object);1314}1315}13161317void GodotNavigationServer3D::internal_free_obstacle(RID p_object) {1318NavObstacle3D *obstacle = obstacle_owner.get_or_null(p_object);1319if (obstacle) {1320NavAgent3D *obstacle_agent = obstacle->get_agent();1321if (obstacle_agent) {1322RID _agent_rid = obstacle_agent->get_self();1323internal_free_agent(_agent_rid);1324obstacle->set_agent(nullptr);1325}1326if (obstacle->get_map() != nullptr) {1327obstacle->get_map()->remove_obstacle(obstacle);1328obstacle->set_map(nullptr);1329}1330obstacle_owner.free(p_object);1331}1332}13331334void GodotNavigationServer3D::set_active(bool p_active) {1335MutexLock lock(operations_mutex);13361337active = p_active;1338}13391340void GodotNavigationServer3D::flush_queries() {1341MutexLock lock(commands_mutex);1342MutexLock lock2(operations_mutex);13431344for (SetCommand3D *command : commands) {1345command->exec(this);1346memdelete(command);1347}1348commands.clear();1349}13501351void GodotNavigationServer3D::map_force_update(RID p_map) {1352NavMap3D *map = map_owner.get_or_null(p_map);1353ERR_FAIL_NULL(map);13541355flush_queries();13561357map->sync();1358}13591360uint32_t GodotNavigationServer3D::map_get_iteration_id(RID p_map) const {1361NavMap3D *map = map_owner.get_or_null(p_map);1362ERR_FAIL_NULL_V(map, 0);13631364return map->get_iteration_id();1365}13661367void GodotNavigationServer3D::sync() {1368if (navmesh_generator_3d) {1369navmesh_generator_3d->sync();1370}1371}13721373void GodotNavigationServer3D::process(double p_delta_time) {1374// Called for each main loop iteration AFTER node and user script process() and BEFORE RenderingServer sync.1375// Will run reliably every rendered frame independent of the physics tick rate.1376// Use for things that (only) need to update once per main loop iteration and rendered frame or is visible to the user.1377// E.g. (final) sync of objects for this main loop iteration, updating rendered debug visuals, updating debug statistics, ...13781379sync();1380}13811382void GodotNavigationServer3D::physics_process(double p_delta_time) {1383// Called for each physics process step AFTER node and user script physics_process() and BEFORE PhysicsServer sync.1384// Will NOT run reliably every rendered frame. If there is no physics step this function will not run.1385// Use for physics or step depending calculations and updates where the result affects the next step calculation.1386// E.g. anything physics sync related, avoidance simulations, physics space state queries, ...1387// If physics process needs to play catchup this function will be called multiple times per frame so it should not hold1388// costly updates that are not important outside the stepped calculations to avoid causing a physics performance death spiral.13891390flush_queries();13911392if (!active) {1393return;1394}13951396int _new_pm_region_count = 0;1397int _new_pm_agent_count = 0;1398int _new_pm_link_count = 0;1399int _new_pm_polygon_count = 0;1400int _new_pm_edge_count = 0;1401int _new_pm_edge_merge_count = 0;1402int _new_pm_edge_connection_count = 0;1403int _new_pm_edge_free_count = 0;1404int _new_pm_obstacle_count = 0;14051406MutexLock lock(operations_mutex);1407for (uint32_t i(0); i < active_maps.size(); i++) {1408active_maps[i]->sync();1409active_maps[i]->step(p_delta_time);1410active_maps[i]->dispatch_callbacks();14111412_new_pm_region_count += active_maps[i]->get_pm_region_count();1413_new_pm_agent_count += active_maps[i]->get_pm_agent_count();1414_new_pm_link_count += active_maps[i]->get_pm_link_count();1415_new_pm_polygon_count += active_maps[i]->get_pm_polygon_count();1416_new_pm_edge_count += active_maps[i]->get_pm_edge_count();1417_new_pm_edge_merge_count += active_maps[i]->get_pm_edge_merge_count();1418_new_pm_edge_connection_count += active_maps[i]->get_pm_edge_connection_count();1419_new_pm_edge_free_count += active_maps[i]->get_pm_edge_free_count();1420_new_pm_obstacle_count += active_maps[i]->get_pm_obstacle_count();1421}14221423pm_region_count = _new_pm_region_count;1424pm_agent_count = _new_pm_agent_count;1425pm_link_count = _new_pm_link_count;1426pm_polygon_count = _new_pm_polygon_count;1427pm_edge_count = _new_pm_edge_count;1428pm_edge_merge_count = _new_pm_edge_merge_count;1429pm_edge_connection_count = _new_pm_edge_connection_count;1430pm_edge_free_count = _new_pm_edge_free_count;1431pm_obstacle_count = _new_pm_obstacle_count;1432}14331434void GodotNavigationServer3D::init() {1435navmesh_generator_3d = memnew(NavMeshGenerator3D);1436RWLockRead read_lock(geometry_parser_rwlock);1437navmesh_generator_3d->set_generator_parsers(generator_parsers);1438}14391440void GodotNavigationServer3D::finish() {1441flush_queries();1442if (navmesh_generator_3d) {1443navmesh_generator_3d->finish();1444memdelete(navmesh_generator_3d);1445navmesh_generator_3d = nullptr;1446}1447}14481449void GodotNavigationServer3D::query_path(const Ref<NavigationPathQueryParameters3D> &p_query_parameters, Ref<NavigationPathQueryResult3D> p_query_result, const Callable &p_callback) {1450ERR_FAIL_COND(p_query_parameters.is_null());1451ERR_FAIL_COND(p_query_result.is_null());14521453NavMap3D *map = map_owner.get_or_null(p_query_parameters->get_map());1454ERR_FAIL_NULL(map);14551456NavMeshQueries3D::map_query_path(map, p_query_parameters, p_query_result, p_callback);1457}14581459RID GodotNavigationServer3D::source_geometry_parser_create() {1460RWLockWrite write_lock(geometry_parser_rwlock);14611462RID rid = geometry_parser_owner.make_rid();14631464NavMeshGeometryParser3D *parser = geometry_parser_owner.get_or_null(rid);1465parser->self = rid;14661467generator_parsers.push_back(parser);1468NavMeshGenerator3D::get_singleton()->set_generator_parsers(generator_parsers);1469return rid;1470}14711472void GodotNavigationServer3D::source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) {1473RWLockWrite write_lock(geometry_parser_rwlock);14741475NavMeshGeometryParser3D *parser = geometry_parser_owner.get_or_null(p_parser);1476ERR_FAIL_NULL(parser);14771478parser->callback = p_callback;1479}14801481Vector<Vector3> GodotNavigationServer3D::simplify_path(const Vector<Vector3> &p_path, real_t p_epsilon) {1482if (p_path.size() <= 2) {1483return p_path;1484}14851486p_epsilon = MAX(0.0, p_epsilon);14871488LocalVector<Vector3> source_path;1489{1490source_path.resize(p_path.size());1491const Vector3 *r = p_path.ptr();1492for (uint32_t i = 0; i < p_path.size(); i++) {1493source_path[i] = r[i];1494}1495}14961497LocalVector<uint32_t> simplified_path_indices = NavMeshQueries3D::get_simplified_path_indices(source_path, p_epsilon);14981499uint32_t index_count = simplified_path_indices.size();15001501Vector<Vector3> simplified_path;1502{1503simplified_path.resize(index_count);1504Vector3 *w = simplified_path.ptrw();1505const Vector3 *r = source_path.ptr();1506for (uint32_t i = 0; i < index_count; i++) {1507w[i] = r[simplified_path_indices[i]];1508}1509}15101511return simplified_path;1512}15131514int GodotNavigationServer3D::get_process_info(ProcessInfo p_info) const {1515switch (p_info) {1516case INFO_ACTIVE_MAPS: {1517return active_maps.size();1518} break;1519case INFO_REGION_COUNT: {1520return pm_region_count;1521} break;1522case INFO_AGENT_COUNT: {1523return pm_agent_count;1524} break;1525case INFO_LINK_COUNT: {1526return pm_link_count;1527} break;1528case INFO_POLYGON_COUNT: {1529return pm_polygon_count;1530} break;1531case INFO_EDGE_COUNT: {1532return pm_edge_count;1533} break;1534case INFO_EDGE_MERGE_COUNT: {1535return pm_edge_merge_count;1536} break;1537case INFO_EDGE_CONNECTION_COUNT: {1538return pm_edge_connection_count;1539} break;1540case INFO_EDGE_FREE_COUNT: {1541return pm_edge_free_count;1542} break;1543case INFO_OBSTACLE_COUNT: {1544return pm_obstacle_count;1545} break;1546}15471548return 0;1549}15501551#undef COMMAND_11552#undef COMMAND_2155315541555