2020-01-10 12:22:34 +01:00
/*************************************************************************/
2020-03-26 22:49:16 +01:00
/* navigation_region_3d.cpp */
2020-01-10 12:22:34 +01:00
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
2022-01-03 21:27:34 +01:00
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
2020-01-10 12:22:34 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2020-03-26 22:49:16 +01:00
# include "navigation_region_3d.h"
2020-03-30 18:22:57 +02:00
2020-03-26 22:49:16 +01:00
# include "mesh_instance_3d.h"
2020-03-27 19:21:27 +01:00
# include "servers/navigation_server_3d.h"
2020-01-10 12:22:34 +01:00
2020-03-26 22:49:16 +01:00
void NavigationRegion3D : : set_enabled ( bool p_enabled ) {
2020-05-14 16:41:43 +02:00
if ( enabled = = p_enabled ) {
2020-01-10 12:22:34 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2020-01-10 12:22:34 +01:00
enabled = p_enabled ;
2020-05-14 16:41:43 +02:00
if ( ! is_inside_tree ( ) ) {
2020-01-10 12:22:34 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2020-01-10 12:22:34 +01:00
if ( ! enabled ) {
2020-03-27 19:21:27 +01:00
NavigationServer3D : : get_singleton ( ) - > region_set_map ( region , RID ( ) ) ;
2020-01-10 12:22:34 +01:00
} else {
2021-03-08 09:47:18 +01:00
NavigationServer3D : : get_singleton ( ) - > region_set_map ( region , get_world_3d ( ) - > get_navigation_map ( ) ) ;
2020-01-10 12:22:34 +01:00
}
if ( debug_view ) {
2020-03-26 22:49:16 +01:00
MeshInstance3D * dm = Object : : cast_to < MeshInstance3D > ( debug_view ) ;
2020-01-10 12:22:34 +01:00
if ( is_enabled ( ) ) {
dm - > set_material_override ( get_tree ( ) - > get_debug_navigation_material ( ) ) ;
} else {
dm - > set_material_override ( get_tree ( ) - > get_debug_navigation_disabled_material ( ) ) ;
}
}
2021-06-23 16:49:50 +02:00
update_gizmos ( ) ;
2020-01-10 12:22:34 +01:00
}
2020-03-26 22:49:16 +01:00
bool NavigationRegion3D : : is_enabled ( ) const {
2020-01-10 12:22:34 +01:00
return enabled ;
}
2022-06-14 23:34:43 +02:00
void NavigationRegion3D : : set_navigation_layers ( uint32_t p_navigation_layers ) {
NavigationServer3D : : get_singleton ( ) - > region_set_navigation_layers ( region , p_navigation_layers ) ;
2021-03-08 20:56:33 +01:00
}
2022-06-14 23:34:43 +02:00
uint32_t NavigationRegion3D : : get_navigation_layers ( ) const {
return NavigationServer3D : : get_singleton ( ) - > region_get_navigation_layers ( region ) ;
2021-03-08 20:56:33 +01:00
}
2022-06-06 05:24:11 +02:00
void NavigationRegion3D : : set_enter_cost ( real_t p_enter_cost ) {
ERR_FAIL_COND_MSG ( p_enter_cost < 0.0 , " The enter_cost must be positive. " ) ;
enter_cost = MAX ( p_enter_cost , 0.0 ) ;
NavigationServer3D : : get_singleton ( ) - > region_set_enter_cost ( region , p_enter_cost ) ;
}
real_t NavigationRegion3D : : get_enter_cost ( ) const {
return enter_cost ;
}
void NavigationRegion3D : : set_travel_cost ( real_t p_travel_cost ) {
ERR_FAIL_COND_MSG ( p_travel_cost < 0.0 , " The travel_cost must be positive. " ) ;
travel_cost = MAX ( p_travel_cost , 0.0 ) ;
NavigationServer3D : : get_singleton ( ) - > region_set_enter_cost ( region , travel_cost ) ;
}
real_t NavigationRegion3D : : get_travel_cost ( ) const {
return travel_cost ;
}
2022-04-30 13:27:30 +02:00
RID NavigationRegion3D : : get_region_rid ( ) const {
return region ;
}
2020-01-10 12:22:34 +01:00
/////////////////////////////
2020-03-26 22:49:16 +01:00
void NavigationRegion3D : : _notification ( int p_what ) {
2020-01-10 12:22:34 +01:00
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
2021-03-08 09:47:18 +01:00
if ( enabled ) {
NavigationServer3D : : get_singleton ( ) - > region_set_map ( region , get_world_3d ( ) - > get_navigation_map ( ) ) ;
2020-01-10 12:22:34 +01:00
}
if ( navmesh . is_valid ( ) & & get_tree ( ) - > is_debugging_navigation_hint ( ) ) {
2020-03-26 22:49:16 +01:00
MeshInstance3D * dm = memnew ( MeshInstance3D ) ;
2020-01-10 12:22:34 +01:00
dm - > set_mesh ( navmesh - > get_debug_mesh ( ) ) ;
if ( is_enabled ( ) ) {
dm - > set_material_override ( get_tree ( ) - > get_debug_navigation_material ( ) ) ;
} else {
dm - > set_material_override ( get_tree ( ) - > get_debug_navigation_disabled_material ( ) ) ;
}
add_child ( dm ) ;
debug_view = dm ;
}
} break ;
2022-02-15 18:06:48 +01:00
2020-01-10 12:22:34 +01:00
case NOTIFICATION_TRANSFORM_CHANGED : {
2020-03-27 19:21:27 +01:00
NavigationServer3D : : get_singleton ( ) - > region_set_transform ( region , get_global_transform ( ) ) ;
2020-01-10 12:22:34 +01:00
} break ;
2022-02-15 18:06:48 +01:00
2020-01-10 12:22:34 +01:00
case NOTIFICATION_EXIT_TREE : {
2021-03-08 09:47:18 +01:00
NavigationServer3D : : get_singleton ( ) - > region_set_map ( region , RID ( ) ) ;
2020-01-10 12:22:34 +01:00
if ( debug_view ) {
debug_view - > queue_delete ( ) ;
2020-04-02 01:20:12 +02:00
debug_view = nullptr ;
2020-01-10 12:22:34 +01:00
}
} break ;
}
}
2020-03-26 22:49:16 +01:00
void NavigationRegion3D : : set_navigation_mesh ( const Ref < NavigationMesh > & p_navmesh ) {
2020-05-14 16:41:43 +02:00
if ( p_navmesh = = navmesh ) {
2020-01-10 12:22:34 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2020-01-10 12:22:34 +01:00
if ( navmesh . is_valid ( ) ) {
2021-02-10 21:18:45 +01:00
navmesh - > disconnect ( " changed " , callable_mp ( this , & NavigationRegion3D : : _navigation_changed ) ) ;
2020-01-10 12:22:34 +01:00
}
navmesh = p_navmesh ;
if ( navmesh . is_valid ( ) ) {
2021-02-10 21:18:45 +01:00
navmesh - > connect ( " changed " , callable_mp ( this , & NavigationRegion3D : : _navigation_changed ) ) ;
2020-01-10 12:22:34 +01:00
}
2020-03-27 19:21:27 +01:00
NavigationServer3D : : get_singleton ( ) - > region_set_navmesh ( region , p_navmesh ) ;
2020-01-10 12:22:34 +01:00
2022-06-02 10:55:19 +02:00
if ( debug_view = = nullptr & & is_inside_tree ( ) & & navmesh . is_valid ( ) & & get_tree ( ) - > is_debugging_navigation_hint ( ) ) {
MeshInstance3D * dm = memnew ( MeshInstance3D ) ;
dm - > set_mesh ( navmesh - > get_debug_mesh ( ) ) ;
if ( is_enabled ( ) ) {
dm - > set_material_override ( get_tree ( ) - > get_debug_navigation_material ( ) ) ;
} else {
dm - > set_material_override ( get_tree ( ) - > get_debug_navigation_disabled_material ( ) ) ;
}
add_child ( dm ) ;
debug_view = dm ;
}
2020-01-10 12:22:34 +01:00
if ( debug_view & & navmesh . is_valid ( ) ) {
2020-03-26 22:49:16 +01:00
Object : : cast_to < MeshInstance3D > ( debug_view ) - > set_mesh ( navmesh - > get_debug_mesh ( ) ) ;
2020-01-10 12:22:34 +01:00
}
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " navigation_mesh_changed " ) ) ;
2020-01-10 12:22:34 +01:00
2021-06-23 16:49:50 +02:00
update_gizmos ( ) ;
2020-10-29 11:01:28 +01:00
update_configuration_warnings ( ) ;
2020-01-10 12:22:34 +01:00
}
2020-03-26 22:49:16 +01:00
Ref < NavigationMesh > NavigationRegion3D : : get_navigation_mesh ( ) const {
2020-01-10 12:22:34 +01:00
return navmesh ;
}
struct BakeThreadsArgs {
2021-02-07 22:29:31 +01:00
NavigationRegion3D * nav_region = nullptr ;
2020-01-10 12:22:34 +01:00
} ;
void _bake_navigation_mesh ( void * p_user_data ) {
BakeThreadsArgs * args = static_cast < BakeThreadsArgs * > ( p_user_data ) ;
2020-03-08 17:33:34 +01:00
if ( args - > nav_region - > get_navigation_mesh ( ) . is_valid ( ) ) {
Ref < NavigationMesh > nav_mesh = args - > nav_region - > get_navigation_mesh ( ) - > duplicate ( ) ;
2020-01-10 12:22:34 +01:00
2020-03-27 19:21:27 +01:00
NavigationServer3D : : get_singleton ( ) - > region_bake_navmesh ( nav_mesh , args - > nav_region ) ;
2021-07-17 23:22:52 +02:00
args - > nav_region - > call_deferred ( SNAME ( " _bake_finished " ) , nav_mesh ) ;
2020-01-10 12:22:34 +01:00
memdelete ( args ) ;
} else {
ERR_PRINT ( " Can't bake the navigation mesh if the `NavigationMesh` resource doesn't exist " ) ;
2021-07-17 23:22:52 +02:00
args - > nav_region - > call_deferred ( SNAME ( " _bake_finished " ) , Ref < NavigationMesh > ( ) ) ;
2020-01-10 12:22:34 +01:00
memdelete ( args ) ;
}
}
2022-05-04 23:00:18 +02:00
void NavigationRegion3D : : bake_navigation_mesh ( bool p_on_thread ) {
2021-09-03 04:30:04 +02:00
ERR_FAIL_COND_MSG ( bake_thread . is_started ( ) , " Unable to start another bake request. The navigation mesh bake thread is already baking a navigation mesh. " ) ;
2020-01-10 12:22:34 +01:00
BakeThreadsArgs * args = memnew ( BakeThreadsArgs ) ;
2020-03-08 17:33:34 +01:00
args - > nav_region = this ;
2020-01-10 12:22:34 +01:00
2022-05-14 18:25:45 +02:00
if ( p_on_thread & & ! OS : : get_singleton ( ) - > can_use_threads ( ) ) {
WARN_PRINT ( " NavigationMesh bake 'on_thread' will be disabled as the current OS does not support multiple threads. "
" \n As a fallback the navigation mesh will bake on the main thread which can cause framerate issues. " ) ;
}
if ( p_on_thread & & OS : : get_singleton ( ) - > can_use_threads ( ) ) {
2022-05-04 23:00:18 +02:00
bake_thread . start ( _bake_navigation_mesh , args ) ;
} else {
_bake_navigation_mesh ( args ) ;
}
2020-01-10 12:22:34 +01:00
}
2020-03-26 22:49:16 +01:00
void NavigationRegion3D : : _bake_finished ( Ref < NavigationMesh > p_nav_mesh ) {
2020-01-10 12:22:34 +01:00
set_navigation_mesh ( p_nav_mesh ) ;
2021-01-19 13:29:41 +01:00
bake_thread . wait_to_finish ( ) ;
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " bake_finished " ) ) ;
2020-01-10 12:22:34 +01:00
}
2020-10-29 11:01:28 +01:00
TypedArray < String > NavigationRegion3D : : get_configuration_warnings ( ) const {
TypedArray < String > warnings = Node : : get_configuration_warnings ( ) ;
2020-05-14 22:59:27 +02:00
2020-10-29 11:01:28 +01:00
if ( is_visible_in_tree ( ) & & is_inside_tree ( ) ) {
if ( ! navmesh . is_valid ( ) ) {
2022-03-28 15:24:14 +02:00
warnings . push_back ( RTR ( " A NavigationMesh resource must be set or created for this node to work. " ) ) ;
2020-05-14 22:59:27 +02:00
}
2020-01-10 12:22:34 +01:00
}
2020-10-02 09:41:55 +02:00
2020-10-29 11:01:28 +01:00
return warnings ;
2020-01-10 12:22:34 +01:00
}
2020-03-26 22:49:16 +01:00
void NavigationRegion3D : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " set_navigation_mesh " , " navmesh " ) , & NavigationRegion3D : : set_navigation_mesh ) ;
ClassDB : : bind_method ( D_METHOD ( " get_navigation_mesh " ) , & NavigationRegion3D : : get_navigation_mesh ) ;
2020-01-10 12:22:34 +01:00
2020-03-26 22:49:16 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_enabled " , " enabled " ) , & NavigationRegion3D : : set_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_enabled " ) , & NavigationRegion3D : : is_enabled ) ;
2020-01-10 12:22:34 +01:00
2022-06-14 23:34:43 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_navigation_layers " , " navigation_layers " ) , & NavigationRegion3D : : set_navigation_layers ) ;
ClassDB : : bind_method ( D_METHOD ( " get_navigation_layers " ) , & NavigationRegion3D : : get_navigation_layers ) ;
2021-03-08 20:56:33 +01:00
2022-04-30 13:27:30 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_region_rid " ) , & NavigationRegion3D : : get_region_rid ) ;
2022-06-06 05:24:11 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_enter_cost " , " enter_cost " ) , & NavigationRegion3D : : set_enter_cost ) ;
ClassDB : : bind_method ( D_METHOD ( " get_enter_cost " ) , & NavigationRegion3D : : get_enter_cost ) ;
ClassDB : : bind_method ( D_METHOD ( " set_travel_cost " , " travel_cost " ) , & NavigationRegion3D : : set_travel_cost ) ;
ClassDB : : bind_method ( D_METHOD ( " get_travel_cost " ) , & NavigationRegion3D : : get_travel_cost ) ;
2022-05-04 23:00:18 +02:00
ClassDB : : bind_method ( D_METHOD ( " bake_navigation_mesh " , " on_thread " ) , & NavigationRegion3D : : bake_navigation_mesh , DEFVAL ( true ) ) ;
2020-03-26 22:49:16 +01:00
ClassDB : : bind_method ( D_METHOD ( " _bake_finished " , " nav_mesh " ) , & NavigationRegion3D : : _bake_finished ) ;
2020-01-10 12:22:34 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " navmesh " , PROPERTY_HINT_RESOURCE_TYPE , " NavigationMesh " ) , " set_navigation_mesh " , " get_navigation_mesh " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " enabled " ) , " set_enabled " , " is_enabled " ) ;
2022-06-14 23:34:43 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " navigation_layers " , PROPERTY_HINT_LAYERS_3D_NAVIGATION ) , " set_navigation_layers " , " get_navigation_layers " ) ;
2022-06-06 05:24:11 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " enter_cost " ) , " set_enter_cost " , " get_enter_cost " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " travel_cost " ) , " set_travel_cost " , " get_travel_cost " ) ;
2020-01-10 12:22:34 +01:00
ADD_SIGNAL ( MethodInfo ( " navigation_mesh_changed " ) ) ;
ADD_SIGNAL ( MethodInfo ( " bake_finished " ) ) ;
}
2021-02-10 21:18:45 +01:00
void NavigationRegion3D : : _navigation_changed ( ) {
2021-06-23 16:49:50 +02:00
update_gizmos ( ) ;
2020-10-29 11:01:28 +01:00
update_configuration_warnings ( ) ;
2020-01-10 12:22:34 +01:00
}
2020-03-26 22:49:16 +01:00
NavigationRegion3D : : NavigationRegion3D ( ) {
2020-01-10 12:22:34 +01:00
set_notify_transform ( true ) ;
2020-03-27 19:21:27 +01:00
region = NavigationServer3D : : get_singleton ( ) - > region_create ( ) ;
2022-06-06 05:24:11 +02:00
NavigationServer3D : : get_singleton ( ) - > region_set_enter_cost ( region , get_enter_cost ( ) ) ;
NavigationServer3D : : get_singleton ( ) - > region_set_travel_cost ( region , get_travel_cost ( ) ) ;
2020-01-10 12:22:34 +01:00
}
2020-03-26 22:49:16 +01:00
NavigationRegion3D : : ~ NavigationRegion3D ( ) {
2020-05-14 16:41:43 +02:00
if ( navmesh . is_valid ( ) ) {
2021-02-10 21:18:45 +01:00
navmesh - > disconnect ( " changed " , callable_mp ( this , & NavigationRegion3D : : _navigation_changed ) ) ;
2020-05-14 16:41:43 +02:00
}
2020-03-27 19:21:27 +01:00
NavigationServer3D : : get_singleton ( ) - > free ( region ) ;
2020-01-10 12:22:34 +01:00
}