2023-07-21 09:50:06 +00:00
/**
* bt_state . cpp
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2024-03-04 14:53:39 +00:00
* Copyright 2021 - 2024 Serhii Snitsaruk
2023-07-21 09:50:06 +00:00
*
* Use of this source code is governed by an MIT - style
* license that can be found in the LICENSE file or at
* https : //opensource.org/licenses/MIT.
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2022-10-19 18:54:21 +00:00
# include "bt_state.h"
2023-07-20 16:35:36 +00:00
2024-01-09 12:34:24 +00:00
# include "../util/limbo_compat.h"
2024-01-07 04:54:17 +00:00
# include "../util/limbo_string_names.h"
2023-07-20 16:35:36 +00:00
2024-01-07 04:54:17 +00:00
# ifdef LIMBOAI_MODULE
2023-12-28 13:41:58 +00:00
# include "core/debugger/engine_debugger.h"
2024-01-07 04:54:17 +00:00
# endif // LIMBOAI_MODULE
# ifdef LIMBOAI_GDEXTENSION
# include <godot_cpp/classes/engine_debugger.hpp>
# endif // LIMBOAI_GDEXTENSION
2022-10-19 18:54:21 +00:00
2024-01-24 23:23:34 +00:00
void BTState : : set_behavior_tree ( const Ref < BehaviorTree > & p_tree ) {
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2024-04-01 14:34:36 +00:00
if ( behavior_tree . is_valid ( ) & & behavior_tree - > is_connected ( LW_NAME ( plan_changed ) , callable_mp ( this , & BTState : : _update_blackboard_plan ) ) ) {
behavior_tree - > disconnect ( LW_NAME ( plan_changed ) , callable_mp ( this , & BTState : : _update_blackboard_plan ) ) ;
2024-01-23 14:31:56 +00:00
}
2024-01-24 23:23:34 +00:00
if ( p_tree . is_valid ( ) ) {
2024-04-01 14:34:36 +00:00
p_tree - > connect ( LW_NAME ( plan_changed ) , callable_mp ( this , & BTState : : _update_blackboard_plan ) ) ;
2024-01-23 14:31:56 +00:00
}
2024-04-01 13:06:06 +00:00
behavior_tree = p_tree ;
} else {
behavior_tree = p_tree ;
2024-01-23 14:31:56 +00:00
}
2024-05-15 09:43:31 +00:00
_update_blackboard_plan ( ) ;
2024-01-24 23:23:34 +00:00
}
2024-08-05 11:21:57 +00:00
void BTState : : set_scene_root_hint ( Node * p_scene_root ) {
ERR_FAIL_NULL_MSG ( p_scene_root , " BTState: Failed to set scene root hint - scene root is null. " ) ;
ERR_FAIL_COND_MSG ( bt_instance . is_valid ( ) , " BTState: Scene root hint shouldn't be set after initialization. This change will not affect the current behavior tree instance. " ) ;
scene_root_hint = p_scene_root ;
}
2024-08-11 10:37:37 +00:00
void BTState : : set_monitor_performance ( bool p_monitor ) {
2024-08-04 08:29:23 +00:00
monitor_performance = p_monitor ;
2024-08-11 10:37:37 +00:00
# ifdef DEBUG_ENABLED
2024-08-04 08:29:23 +00:00
if ( bt_instance . is_valid ( ) ) {
bt_instance - > set_monitor_performance ( monitor_performance ) ;
}
2024-08-11 10:37:37 +00:00
# endif
2024-08-04 08:29:23 +00:00
}
2024-01-24 23:23:34 +00:00
void BTState : : _update_blackboard_plan ( ) {
if ( get_blackboard_plan ( ) . is_null ( ) ) {
2024-04-01 13:06:06 +00:00
set_blackboard_plan ( memnew ( BlackboardPlan ) ) ;
} else if ( ! RESOURCE_IS_BUILT_IN ( get_blackboard_plan ( ) ) ) {
WARN_PRINT_ED ( " BTState: Using external resource for derived blackboard plan is not supported. Converted to built-in resource. " ) ;
set_blackboard_plan ( get_blackboard_plan ( ) - > duplicate ( ) ) ;
} else {
get_blackboard_plan ( ) - > set_base_plan ( behavior_tree . is_valid ( ) ? behavior_tree - > get_blackboard_plan ( ) : nullptr ) ;
2024-01-24 23:23:34 +00:00
}
2024-01-23 14:31:56 +00:00
}
2024-09-15 12:29:23 +00:00
Node * BTState : : _get_prefetch_root_for_base_plan ( ) {
return _get_scene_root ( ) ;
}
2022-10-19 18:54:21 +00:00
void BTState : : _setup ( ) {
2024-03-02 19:19:38 +00:00
LimboState : : _setup ( ) ;
2022-12-16 14:29:36 +00:00
ERR_FAIL_COND_MSG ( behavior_tree . is_null ( ) , " BTState: BehaviorTree is not assigned. " ) ;
2024-09-15 12:29:23 +00:00
Node * scene_root = _get_scene_root ( ) ;
2024-08-05 11:21:57 +00:00
ERR_FAIL_NULL_MSG ( scene_root , " BTState: Initialization failed - unable to establish scene root. This is likely due to BTState not being owned by a scene node. Check BTState.set_scene_root_hint(). " ) ;
2024-08-31 17:37:44 +00:00
bt_instance = behavior_tree - > instantiate ( get_agent ( ) , get_blackboard ( ) , this , scene_root ) ;
2024-08-05 11:21:57 +00:00
ERR_FAIL_COND_MSG ( bt_instance . is_null ( ) , " BTState: Initialization failed - failed to instantiate behavior tree. " ) ;
2023-04-13 07:29:45 +00:00
# ifdef DEBUG_ENABLED
2024-08-03 09:39:23 +00:00
bt_instance - > register_with_debugger ( ) ;
2024-08-04 08:29:23 +00:00
bt_instance - > set_monitor_performance ( monitor_performance ) ;
2023-04-13 07:29:45 +00:00
# endif
2022-10-19 18:54:21 +00:00
}
void BTState : : _exit ( ) {
2024-08-03 09:39:23 +00:00
if ( bt_instance . is_valid ( ) ) {
bt_instance - > get_root_task ( ) - > abort ( ) ;
2024-04-20 19:30:26 +00:00
} else {
ERR_PRINT_ONCE ( " BTState: BehaviorTree is not assigned. " ) ;
}
2024-03-02 19:19:38 +00:00
LimboState : : _exit ( ) ;
2022-10-19 18:54:21 +00:00
}
2023-04-10 08:08:11 +00:00
void BTState : : _update ( double p_delta ) {
2024-06-30 10:34:06 +00:00
GDVIRTUAL_CALL ( _update , p_delta ) ;
2024-06-03 12:30:30 +00:00
if ( ! is_active ( ) ) {
2024-04-20 18:19:07 +00:00
// Bail out if a transition happened in the meantime.
return ;
}
2024-11-03 03:53:56 +00:00
ERR_FAIL_COND ( bt_instance . is_null ( ) ) ;
2024-08-03 09:47:05 +00:00
BT : : Status status = bt_instance - > update ( p_delta ) ;
2022-10-19 18:54:21 +00:00
if ( status = = BTTask : : SUCCESS ) {
2022-11-04 12:26:49 +00:00
get_root ( ) - > dispatch ( success_event , Variant ( ) ) ;
2022-10-19 18:54:21 +00:00
} else if ( status = = BTTask : : FAILURE ) {
2022-11-04 12:26:49 +00:00
get_root ( ) - > dispatch ( failure_event , Variant ( ) ) ;
2022-10-19 18:54:21 +00:00
}
2024-03-02 19:19:38 +00:00
emit_signal ( LW_NAME ( updated ) , p_delta ) ;
2022-10-19 18:54:21 +00:00
}
2023-04-13 07:29:45 +00:00
void BTState : : _notification ( int p_notification ) {
switch ( p_notification ) {
2024-01-24 23:23:34 +00:00
# ifdef DEBUG_ENABLED
2023-09-09 11:37:09 +00:00
case NOTIFICATION_ENTER_TREE : {
2024-08-03 09:39:23 +00:00
if ( bt_instance . is_valid ( ) ) {
bt_instance - > register_with_debugger ( ) ;
2024-08-04 08:29:23 +00:00
bt_instance - > set_monitor_performance ( monitor_performance ) ;
2023-09-09 11:37:09 +00:00
}
} break ;
2024-01-24 23:23:34 +00:00
# endif // DEBUG_ENABLED
2023-04-13 07:29:45 +00:00
case NOTIFICATION_EXIT_TREE : {
2024-01-24 23:23:34 +00:00
# ifdef DEBUG_ENABLED
2024-08-03 09:39:23 +00:00
if ( bt_instance . is_valid ( ) ) {
bt_instance - > unregister_with_debugger ( ) ;
2024-08-04 08:29:23 +00:00
bt_instance - > set_monitor_performance ( false ) ;
2023-04-15 08:53:57 +00:00
}
2024-08-04 08:29:23 +00:00
2024-01-24 23:23:34 +00:00
# endif // DEBUG_ENABLED
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2024-04-01 14:34:36 +00:00
if ( behavior_tree . is_valid ( ) & & behavior_tree - > is_connected ( LW_NAME ( plan_changed ) , callable_mp ( this , & BTState : : _update_blackboard_plan ) ) ) {
behavior_tree - > disconnect ( LW_NAME ( plan_changed ) , callable_mp ( this , & BTState : : _update_blackboard_plan ) ) ;
2024-01-24 23:23:34 +00:00
}
}
2023-04-13 07:29:45 +00:00
} break ;
}
}
2022-10-19 18:54:21 +00:00
void BTState : : _bind_methods ( ) {
2024-03-04 20:36:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_behavior_tree " , " behavior_tree " ) , & BTState : : set_behavior_tree ) ;
2022-10-19 18:54:21 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_behavior_tree " ) , & BTState : : get_behavior_tree ) ;
2024-08-03 09:39:23 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_bt_instance " ) , & BTState : : get_bt_instance ) ;
2024-02-03 15:31:21 +00:00
2024-03-04 20:36:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_success_event " , " event " ) , & BTState : : set_success_event ) ;
2022-11-04 12:26:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_success_event " ) , & BTState : : get_success_event ) ;
2024-03-04 20:36:16 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_failure_event " , " event " ) , & BTState : : set_failure_event ) ;
2022-11-04 12:26:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_failure_event " ) , & BTState : : get_failure_event ) ;
2024-08-11 10:37:37 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_monitor_performance " , " enable " ) , & BTState : : set_monitor_performance ) ;
ClassDB : : bind_method ( D_METHOD ( " get_monitor_performance " ) , & BTState : : get_monitor_performance ) ;
2024-08-05 11:21:57 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_scene_root_hint " , " scene_root " ) , & BTState : : set_scene_root_hint ) ;
2022-10-19 18:54:21 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " behavior_tree " , PROPERTY_HINT_RESOURCE_TYPE , " BehaviorTree " ) , " set_behavior_tree " , " get_behavior_tree " ) ;
2024-03-04 14:53:39 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING_NAME , " success_event " ) , " set_success_event " , " get_success_event " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING_NAME , " failure_event " ) , " set_failure_event " , " get_failure_event " ) ;
2024-08-11 10:37:37 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " monitor_performance " ) , " set_monitor_performance " , " get_monitor_performance " ) ;
2022-10-19 21:41:56 +00:00
}
BTState : : BTState ( ) {
2024-03-04 14:53:39 +00:00
success_event = LW_NAME ( EVENT_SUCCESS ) ;
failure_event = LW_NAME ( EVENT_FAILURE ) ;
2022-10-19 18:54:21 +00:00
}