2023-07-21 09:50:06 +00:00
/**
* limbo_ai_editor_plugin . cpp
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Copyright 2021 - 2023 Serhii Snitsaruk
*
* 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-09-01 22:20:37 +00:00
# ifdef TOOLS_ENABLED
# include "limbo_ai_editor_plugin.h"
2024-01-09 12:34:24 +00:00
# include "../bt/behavior_tree.h"
# include "../bt/tasks/bt_comment.h"
# include "../bt/tasks/composites/bt_probability_selector.h"
# include "../bt/tasks/composites/bt_selector.h"
# include "../bt/tasks/decorators/bt_subtree.h"
2024-01-09 20:47:22 +00:00
# include "../editor/debugger/limbo_debugger_plugin.h"
2024-01-09 12:34:24 +00:00
# include "../editor/editor_property_bb_param.h"
2024-01-09 20:47:22 +00:00
# include "../util/limbo_compat.h"
2024-01-09 12:34:24 +00:00
# include "../util/limbo_utility.h"
2023-08-22 10:20:09 +00:00
# include "action_banner.h"
2023-07-20 16:35:36 +00:00
2024-01-09 12:34:24 +00:00
# ifdef LIMBOAI_MODULE
2022-12-15 07:26:52 +00:00
# include "core/config/project_settings.h"
2023-09-25 16:07:26 +00:00
# include "core/error/error_macros.h"
2023-12-17 13:26:38 +00:00
# include "core/input/input.h"
2023-08-20 09:34:13 +00:00
# include "editor/debugger/editor_debugger_node.h"
# include "editor/debugger/script_editor_debugger.h"
2022-12-15 07:26:52 +00:00
# include "editor/editor_file_system.h"
2023-08-23 11:06:18 +00:00
# include "editor/editor_help.h"
2022-12-15 07:26:52 +00:00
# include "editor/editor_paths.h"
2022-09-05 14:39:40 +00:00
# include "editor/editor_scale.h"
2022-09-06 11:28:25 +00:00
# include "editor/editor_settings.h"
2022-12-22 12:19:39 +00:00
# include "editor/editor_undo_redo_manager.h"
2022-12-15 07:26:52 +00:00
# include "editor/inspector_dock.h"
# include "editor/plugins/script_editor_plugin.h"
2023-08-21 09:51:19 +00:00
# include "editor/project_settings_editor.h"
2023-09-25 20:36:37 +00:00
# include "scene/gui/panel_container.h"
2022-09-01 22:20:37 +00:00
# include "scene/gui/separator.h"
2024-01-09 12:34:24 +00:00
# endif // ! LIMBOAI_MODULE
# ifdef LIMBOAI_GDEXTENSION
# include <godot_cpp/classes/button_group.hpp>
# include <godot_cpp/classes/config_file.hpp>
# include <godot_cpp/classes/dir_access.hpp>
# include <godot_cpp/classes/display_server.hpp>
# include <godot_cpp/classes/editor_file_system.hpp>
# include <godot_cpp/classes/editor_inspector.hpp>
2024-01-09 23:02:24 +00:00
# include <godot_cpp/classes/editor_interface.hpp>
# include <godot_cpp/classes/editor_paths.hpp>
2024-01-09 12:34:24 +00:00
# include <godot_cpp/classes/editor_settings.hpp>
# include <godot_cpp/classes/editor_undo_redo_manager.hpp>
# include <godot_cpp/classes/file_access.hpp>
# include <godot_cpp/classes/input.hpp>
# include <godot_cpp/classes/input_event.hpp>
# include <godot_cpp/classes/project_settings.hpp>
2024-01-09 23:02:24 +00:00
# include <godot_cpp/classes/ref_counted.hpp>
2024-01-09 12:34:24 +00:00
# include <godot_cpp/classes/resource_loader.hpp>
# include <godot_cpp/classes/resource_saver.hpp>
# include <godot_cpp/classes/script.hpp>
# include <godot_cpp/classes/script_editor.hpp>
# include <godot_cpp/classes/script_editor_base.hpp>
# include <godot_cpp/classes/v_separator.hpp>
2024-01-09 23:02:24 +00:00
# include <godot_cpp/core/error_macros.hpp>
2024-01-09 12:34:24 +00:00
# endif // ! LIMBOAI_GDEXTENSION
2022-09-03 15:00:20 +00:00
2023-08-16 09:19:51 +00:00
//**** LimboAIEditor
2022-09-02 12:25:03 +00:00
2023-08-21 13:27:30 +00:00
_FORCE_INLINE_ String _get_script_template_path ( ) {
String templates_search_path = GLOBAL_GET ( " editor/script/templates_search_path " ) ;
return templates_search_path . path_join ( " BTTask " ) . path_join ( " custom_task.gd " ) ;
}
2022-09-03 12:11:47 +00:00
void LimboAIEditor : : _add_task ( const Ref < BTTask > & p_task ) {
2023-10-29 12:45:32 +00:00
if ( task_tree - > get_bt ( ) . is_null ( ) ) {
return ;
}
2022-09-03 12:11:47 +00:00
ERR_FAIL_COND ( p_task . is_null ( ) ) ;
2023-12-17 13:26:38 +00:00
2024-01-09 12:34:24 +00:00
EditorUndoRedoManager * undo_redo = GET_UNDO_REDO ( ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > create_action ( TTR ( " Add BT Task " ) ) ;
2023-12-17 13:26:38 +00:00
int insert_idx = - 1 ;
Ref < BTTask > selected = task_tree - > get_selected ( ) ;
Ref < BTTask > parent = selected ;
2022-09-01 22:20:37 +00:00
if ( parent . is_null ( ) ) {
2023-12-17 13:26:38 +00:00
// When no task is selected, use the root task.
2022-09-01 22:20:37 +00:00
parent = task_tree - > get_bt ( ) - > get_root_task ( ) ;
2023-12-17 13:26:38 +00:00
selected = parent ;
2022-09-01 22:20:37 +00:00
}
if ( parent . is_null ( ) ) {
2023-12-17 13:26:38 +00:00
// When tree is empty.
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( task_tree - > get_bt ( ) . ptr ( ) , LW_NAME ( set_root_task ) , p_task ) ;
undo_redo - > add_undo_method ( task_tree - > get_bt ( ) . ptr ( ) , LW_NAME ( set_root_task ) , task_tree - > get_bt ( ) - > get_root_task ( ) ) ;
2022-09-01 22:20:37 +00:00
} else {
2024-01-09 12:34:24 +00:00
if ( Input : : get_singleton ( ) - > is_key_pressed ( LW_KEY ( SHIFT ) ) & & selected - > get_parent ( ) . is_valid ( ) ) {
2023-12-17 13:26:38 +00:00
// When shift is pressed, insert task after the currently selected and on the same level.
parent = selected - > get_parent ( ) ;
insert_idx = selected - > get_index ( ) + 1 ;
}
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( parent . ptr ( ) , LW_NAME ( add_child_at_index ) , p_task , insert_idx ) ;
undo_redo - > add_undo_method ( parent . ptr ( ) , LW_NAME ( remove_child ) , p_task ) ;
2022-09-01 22:20:37 +00:00
}
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( task_tree , LW_NAME ( update_tree ) ) ;
undo_redo - > add_undo_method ( task_tree , LW_NAME ( update_tree ) ) ;
2023-12-17 13:26:38 +00:00
2022-12-22 12:19:39 +00:00
undo_redo - > commit_action ( ) ;
2022-09-03 12:01:13 +00:00
_mark_as_dirty ( true ) ;
2022-12-22 12:19:39 +00:00
}
2023-12-14 22:18:44 +00:00
Ref < BTTask > LimboAIEditor : : _create_task_by_class_or_path ( const String & p_class_or_path ) const {
Ref < BTTask > ret ;
2023-08-18 10:12:55 +00:00
if ( p_class_or_path . begins_with ( " res: " ) ) {
2024-01-09 12:34:24 +00:00
Ref < Script > s = RESOURCE_LOAD ( p_class_or_path , " Script " ) ;
ERR_FAIL_COND_V_MSG ( s . is_null ( ) | | ! s - > can_instantiate ( ) , nullptr , vformat ( " LimboAI: Failed to instantiate task. Bad script: %s " , p_class_or_path ) ) ;
2023-08-18 10:12:55 +00:00
Variant inst = ClassDB : : instantiate ( s - > get_instance_base_type ( ) ) ;
2024-01-09 12:34:24 +00:00
ERR_FAIL_COND_V_MSG ( inst = = Variant ( ) , nullptr , vformat ( " LimboAI: Failed to instantiate base type \" %s \" . " , s - > get_instance_base_type ( ) ) ) ;
2023-08-18 10:12:55 +00:00
if ( unlikely ( ! ( ( Object * ) inst ) - > is_class ( " BTTask " ) ) ) {
2024-01-09 12:34:24 +00:00
VARIANT_DELETE_IF_OBJECT ( inst ) ;
2023-08-18 10:12:55 +00:00
ERR_PRINT ( vformat ( " LimboAI: Failed to instantiate task. Script is not a BTTask: %s " , p_class_or_path ) ) ;
2023-12-14 22:18:44 +00:00
return nullptr ;
2023-08-18 10:12:55 +00:00
}
if ( inst & & s . is_valid ( ) ) {
( ( Object * ) inst ) - > set_script ( s ) ;
2023-12-14 22:18:44 +00:00
ret = inst ;
2023-08-18 10:12:55 +00:00
}
} else {
2023-12-14 22:18:44 +00:00
ret = ClassDB : : instantiate ( p_class_or_path ) ;
2023-08-18 10:12:55 +00:00
}
2023-12-14 22:18:44 +00:00
return ret ;
}
void LimboAIEditor : : _add_task_by_class_or_path ( const String & p_class_or_path ) {
_add_task ( _create_task_by_class_or_path ( p_class_or_path ) ) ;
2023-08-18 10:12:55 +00:00
}
2022-12-22 12:19:39 +00:00
void LimboAIEditor : : _remove_task ( const Ref < BTTask > & p_task ) {
ERR_FAIL_COND ( p_task . is_null ( ) ) ;
ERR_FAIL_COND ( task_tree - > get_bt ( ) . is_null ( ) ) ;
2024-01-09 12:34:24 +00:00
EditorUndoRedoManager * undo_redo = GET_UNDO_REDO ( ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > create_action ( TTR ( " Remove BT Task " ) ) ;
if ( p_task - > get_parent ( ) = = nullptr ) {
ERR_FAIL_COND ( task_tree - > get_bt ( ) - > get_root_task ( ) ! = p_task ) ;
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( task_tree - > get_bt ( ) . ptr ( ) , LW_NAME ( set_root_task ) , Variant ( ) ) ;
undo_redo - > add_undo_method ( task_tree - > get_bt ( ) . ptr ( ) , LW_NAME ( set_root_task ) , task_tree - > get_bt ( ) - > get_root_task ( ) ) ;
2022-12-22 12:19:39 +00:00
} else {
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( p_task - > get_parent ( ) . ptr ( ) , LW_NAME ( remove_child ) , p_task ) ;
undo_redo - > add_undo_method ( p_task - > get_parent ( ) . ptr ( ) , LW_NAME ( add_child_at_index ) , p_task , p_task - > get_index ( ) ) ;
2022-12-22 12:19:39 +00:00
}
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( task_tree , LW_NAME ( update_tree ) ) ;
undo_redo - > add_undo_method ( task_tree , LW_NAME ( update_tree ) ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > commit_action ( ) ;
2022-09-01 22:20:37 +00:00
}
2022-11-22 21:58:53 +00:00
void LimboAIEditor : : _update_header ( ) const {
2023-08-16 09:19:51 +00:00
if ( task_tree - > get_bt ( ) . is_null ( ) ) {
header - > set_text ( " " ) ;
2024-01-09 12:34:24 +00:00
BUTTON_SET_ICON ( header , nullptr ) ;
2023-08-16 09:19:51 +00:00
return ;
}
2022-09-01 22:20:37 +00:00
String text = task_tree - > get_bt ( ) - > get_path ( ) ;
2022-12-15 07:26:52 +00:00
if ( text . is_empty ( ) ) {
2022-09-01 22:20:37 +00:00
text = TTR ( " New Behavior Tree " ) ;
2022-09-03 12:01:13 +00:00
} else if ( dirty . has ( task_tree - > get_bt ( ) ) ) {
text + = " (*) " ;
2022-09-01 22:20:37 +00:00
}
2022-09-03 12:01:13 +00:00
2022-09-01 22:20:37 +00:00
header - > set_text ( text ) ;
2024-01-09 12:34:24 +00:00
BUTTON_SET_ICON ( header , theme_cache . behavior_tree_icon ) ;
2022-09-01 22:20:37 +00:00
}
2022-09-02 13:43:54 +00:00
void LimboAIEditor : : _update_history_buttons ( ) {
history_back - > set_disabled ( idx_history = = 0 ) ;
2024-01-09 23:02:24 +00:00
history_forward - > set_disabled ( idx_history > = ( history . size ( ) - 1 ) ) ;
2022-09-02 13:43:54 +00:00
}
2022-09-01 22:20:37 +00:00
void LimboAIEditor : : _new_bt ( ) {
BehaviorTree * bt = memnew ( BehaviorTree ) ;
bt - > set_root_task ( memnew ( BTSelector ) ) ;
2024-01-09 12:34:24 +00:00
EDIT_RESOURCE ( bt ) ;
2022-09-01 22:20:37 +00:00
}
void LimboAIEditor : : _save_bt ( String p_path ) {
2022-12-15 07:26:52 +00:00
ERR_FAIL_COND_MSG ( p_path . is_empty ( ) , " Empty p_path " ) ;
2022-09-01 22:20:37 +00:00
ERR_FAIL_COND_MSG ( task_tree - > get_bt ( ) . is_null ( ) , " Behavior Tree is null. " ) ;
2024-01-10 21:45:42 +00:00
# ifdef LIMBOAI_MODULE
task_tree - > get_bt ( ) - > set_path ( p_path , true ) ;
# else // LIMBOAI_GDEXTENSION
2024-01-09 12:34:24 +00:00
task_tree - > get_bt ( ) - > take_over_path ( p_path ) ;
2024-01-10 21:45:42 +00:00
# endif // LIMBOAI_MODULE
2024-01-09 12:34:24 +00:00
RESOURCE_SAVE ( task_tree - > get_bt ( ) , p_path , ResourceSaver : : FLAG_CHANGE_PATH ) ;
2022-09-01 22:20:37 +00:00
_update_header ( ) ;
2022-09-03 12:01:13 +00:00
_mark_as_dirty ( false ) ;
2022-09-01 22:20:37 +00:00
}
void LimboAIEditor : : _load_bt ( String p_path ) {
2022-12-15 07:26:52 +00:00
ERR_FAIL_COND_MSG ( p_path . is_empty ( ) , " Empty p_path " ) ;
2024-01-09 12:34:24 +00:00
Ref < BehaviorTree > bt = RESOURCE_LOAD ( p_path , " BehaviorTree " ) ;
2022-12-19 11:38:40 +00:00
ERR_FAIL_COND ( ! bt . is_valid ( ) ) ;
2022-09-02 13:43:54 +00:00
if ( history . find ( bt ) ! = - 1 ) {
history . erase ( bt ) ;
history . push_back ( bt ) ;
}
2024-01-09 12:34:24 +00:00
EDIT_RESOURCE ( bt ) ;
2022-09-02 13:43:54 +00:00
}
2022-11-22 20:00:08 +00:00
void LimboAIEditor : : edit_bt ( Ref < BehaviorTree > p_behavior_tree , bool p_force_refresh ) {
2022-09-02 13:43:54 +00:00
ERR_FAIL_COND_MSG ( p_behavior_tree . is_null ( ) , " p_behavior_tree is null " ) ;
2022-09-05 19:57:24 +00:00
2022-11-22 20:00:08 +00:00
if ( ! p_force_refresh & & task_tree - > get_bt ( ) = = p_behavior_tree ) {
2022-09-05 19:57:24 +00:00
return ;
}
2022-09-02 13:43:54 +00:00
task_tree - > load_bt ( p_behavior_tree ) ;
int idx = history . find ( p_behavior_tree ) ;
if ( idx ! = - 1 ) {
idx_history = idx ;
} else {
history . push_back ( p_behavior_tree ) ;
idx_history = history . size ( ) - 1 ;
}
2022-09-05 19:57:24 +00:00
usage_hint - > hide ( ) ;
task_tree - > show ( ) ;
2023-08-26 08:08:01 +00:00
task_palette - > show ( ) ;
2022-09-05 19:57:24 +00:00
2022-09-02 13:43:54 +00:00
_update_history_buttons ( ) ;
2022-09-01 22:20:37 +00:00
_update_header ( ) ;
}
2022-09-03 12:01:13 +00:00
void LimboAIEditor : : _mark_as_dirty ( bool p_dirty ) {
Ref < BehaviorTree > bt = task_tree - > get_bt ( ) ;
if ( p_dirty & & ! dirty . has ( bt ) ) {
dirty . insert ( bt ) ;
_update_header ( ) ;
} else if ( p_dirty = = false & & dirty . has ( bt ) ) {
dirty . erase ( bt ) ;
_update_header ( ) ;
}
}
2023-08-21 16:17:34 +00:00
void LimboAIEditor : : _create_user_task_dir ( ) {
String task_dir = GLOBAL_GET ( " limbo_ai/behavior_tree/user_task_dir_1 " ) ;
2024-01-09 12:34:24 +00:00
ERR_FAIL_COND_MSG ( DirAccess : : dir_exists_absolute ( task_dir ) , " LimboAIEditor: Directory already exists: " + task_dir ) ;
2023-08-21 16:17:34 +00:00
2024-01-09 12:34:24 +00:00
Error err = DirAccess : : make_dir_recursive_absolute ( task_dir ) ;
2023-08-21 16:17:34 +00:00
ERR_FAIL_COND_MSG ( err ! = OK , " LimboAIEditor: Failed to create directory: " + task_dir ) ;
2024-01-09 12:34:24 +00:00
# ifdef LIMBOAI_MODULE
2023-08-21 16:17:34 +00:00
EditorFileSystem : : get_singleton ( ) - > scan_changes ( ) ;
2024-01-09 12:34:24 +00:00
# else // LIMBOAI_GDEXTENSION
EditorInterface : : get_singleton ( ) - > get_resource_filesystem ( ) - > scan_sources ( ) ;
# endif
2023-08-22 10:20:09 +00:00
_update_banners ( ) ;
2023-08-21 16:17:34 +00:00
}
void LimboAIEditor : : _edit_project_settings ( ) {
2024-01-09 12:34:24 +00:00
# ifdef LIMBOAI_MODULE
2023-08-21 16:17:34 +00:00
ProjectSettingsEditor : : get_singleton ( ) - > set_general_page ( " limbo_ai/behavior_tree " ) ;
ProjectSettingsEditor : : get_singleton ( ) - > popup_project_settings ( ) ;
2024-01-09 12:42:54 +00:00
ProjectSettingsEditor : : get_singleton ( ) - > connect ( LW_NAME ( visibility_changed ) , callable_mp ( this , & LimboAIEditor : : _update_banners ) , CONNECT_ONE_SHOT ) ;
2024-01-09 12:34:24 +00:00
# else // LIMBOAI_GDEXTENSION
// TODO: Find a way to show project setting in GDExtension.
// TODO: Maybe show a popup dialog instead.
ERR_PRINT ( " Can't do in GDExtension. To edit project settings, navigate to \" Project->Project Settings \" , enable \" Advanced settings \" , and scroll down to the \" LimboAI \" section. " ) ;
# endif
2023-08-21 16:17:34 +00:00
}
2023-08-22 12:43:45 +00:00
void LimboAIEditor : : _remove_task_from_favorite ( const String & p_task ) {
PackedStringArray favorite_tasks = GLOBAL_GET ( " limbo_ai/behavior_tree/favorite_tasks " ) ;
2024-01-09 12:34:24 +00:00
int idx = favorite_tasks . find ( p_task ) ;
if ( idx > = 0 ) {
favorite_tasks . remove_at ( idx ) ;
}
2023-08-22 12:43:45 +00:00
ProjectSettings : : get_singleton ( ) - > set_setting ( " limbo_ai/behavior_tree/favorite_tasks " , favorite_tasks ) ;
ProjectSettings : : get_singleton ( ) - > save ( ) ;
}
2023-12-17 14:24:38 +00:00
void LimboAIEditor : : _extract_subtree ( const String & p_path ) {
Ref < BTTask > selected = task_tree - > get_selected ( ) ;
ERR_FAIL_COND ( selected . is_null ( ) ) ;
2024-01-09 12:34:24 +00:00
EditorUndoRedoManager * undo_redo = GET_UNDO_REDO ( ) ;
2023-12-17 14:24:38 +00:00
undo_redo - > create_action ( TTR ( " Extract Subtree " ) ) ;
Ref < BehaviorTree > bt = memnew ( BehaviorTree ) ;
bt - > set_root_task ( selected - > clone ( ) ) ;
bt - > set_path ( p_path ) ;
2024-01-09 12:34:24 +00:00
RESOURCE_SAVE ( bt , p_path , ResourceSaver : : FLAG_CHANGE_PATH ) ;
2023-12-17 14:24:38 +00:00
Ref < BTSubtree > subtree = memnew ( BTSubtree ) ;
subtree - > set_subtree ( bt ) ;
if ( selected - > is_root ( ) ) {
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( task_tree - > get_bt ( ) . ptr ( ) , LW_NAME ( set_root_task ) , subtree ) ;
undo_redo - > add_undo_method ( task_tree - > get_bt ( ) . ptr ( ) , LW_NAME ( set_root_task ) , selected ) ;
2023-12-17 14:24:38 +00:00
} else {
int idx = selected - > get_index ( ) ;
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( selected - > get_parent ( ) . ptr ( ) , LW_NAME ( remove_child ) , selected ) ;
undo_redo - > add_do_method ( selected - > get_parent ( ) . ptr ( ) , LW_NAME ( add_child_at_index ) , subtree , idx ) ;
undo_redo - > add_undo_method ( selected - > get_parent ( ) . ptr ( ) , LW_NAME ( remove_child ) , subtree ) ;
undo_redo - > add_undo_method ( selected - > get_parent ( ) . ptr ( ) , LW_NAME ( add_child_at_index ) , selected , idx ) ;
2023-12-17 14:24:38 +00:00
}
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( task_tree , LW_NAME ( update_tree ) ) ;
undo_redo - > add_undo_method ( task_tree , LW_NAME ( update_tree ) ) ;
2023-12-17 14:24:38 +00:00
undo_redo - > commit_action ( ) ;
2024-01-09 12:34:24 +00:00
EDIT_RESOURCE ( task_tree - > get_selected ( ) ) ;
2023-12-17 14:24:38 +00:00
_mark_as_dirty ( true ) ;
}
2024-01-09 12:34:24 +00:00
void LimboAIEditor : : _process_shortcut_input ( const Ref < InputEvent > & p_event ) {
2023-08-20 09:49:33 +00:00
if ( ! p_event - > is_pressed ( ) ) {
return ;
}
// * Global shortcuts.
2024-01-09 12:34:24 +00:00
if ( LW_IS_SHORTCUT ( " limbo_ai/open_debugger " , p_event ) ) {
2023-08-20 09:49:33 +00:00
_misc_option_selected ( MISC_OPEN_DEBUGGER ) ;
accept_event ( ) ;
}
// * Local shortcuts.
2023-08-23 14:32:02 +00:00
if ( ! ( has_focus ( ) | | get_viewport ( ) - > gui_get_focus_owner ( ) = = nullptr | | is_ancestor_of ( get_viewport ( ) - > gui_get_focus_owner ( ) ) ) ) {
2023-08-16 14:07:04 +00:00
return ;
}
2024-01-09 12:34:24 +00:00
if ( LW_IS_SHORTCUT ( " limbo_ai/rename_task " , p_event ) ) {
2023-08-16 14:07:04 +00:00
_action_selected ( ACTION_RENAME ) ;
2024-01-09 12:34:24 +00:00
} else if ( LW_IS_SHORTCUT ( " limbo_ai/move_task_up " , p_event ) ) {
2023-08-16 14:07:04 +00:00
_action_selected ( ACTION_MOVE_UP ) ;
2024-01-09 12:34:24 +00:00
} else if ( LW_IS_SHORTCUT ( " limbo_ai/move_task_down " , p_event ) ) {
2023-08-16 14:07:04 +00:00
_action_selected ( ACTION_MOVE_DOWN ) ;
2024-01-09 12:34:24 +00:00
} else if ( LW_IS_SHORTCUT ( " limbo_ai/duplicate_task " , p_event ) ) {
2023-08-16 14:07:04 +00:00
_action_selected ( ACTION_DUPLICATE ) ;
2024-01-09 12:34:24 +00:00
} else if ( LW_IS_SHORTCUT ( " limbo_ai/remove_task " , p_event ) ) {
2023-08-16 14:07:04 +00:00
_action_selected ( ACTION_REMOVE ) ;
2024-01-09 12:34:24 +00:00
} else if ( LW_IS_SHORTCUT ( " limbo_ai/new_behavior_tree " , p_event ) ) {
2023-08-16 14:07:04 +00:00
_new_bt ( ) ;
2024-01-09 12:34:24 +00:00
} else if ( LW_IS_SHORTCUT ( " limbo_ai/save_behavior_tree " , p_event ) ) {
2023-08-16 14:07:04 +00:00
_on_save_pressed ( ) ;
2024-01-09 12:34:24 +00:00
} else if ( LW_IS_SHORTCUT ( " limbo_ai/load_behavior_tree " , p_event ) ) {
_popup_file_dialog ( load_dialog ) ;
2023-08-16 14:07:04 +00:00
} else {
return ;
}
accept_event ( ) ;
}
2023-08-17 09:41:40 +00:00
void LimboAIEditor : : _on_tree_rmb ( const Vector2 & p_menu_pos ) {
2022-09-01 22:20:37 +00:00
menu - > clear ( ) ;
2023-08-17 09:41:40 +00:00
Ref < BTTask > task = task_tree - > get_selected ( ) ;
ERR_FAIL_COND_MSG ( task . is_null ( ) , " LimboAIEditor: get_selected() returned null " ) ;
2023-09-25 16:07:26 +00:00
if ( task_tree - > selected_has_probability ( ) ) {
2023-09-26 14:12:10 +00:00
menu - > add_icon_item ( theme_cache . percent_icon , TTR ( " Edit Probability " ) , ACTION_EDIT_PROBABILITY ) ;
2023-09-25 16:07:26 +00:00
}
2024-01-09 12:34:24 +00:00
menu - > add_icon_shortcut ( theme_cache . rename_task_icon , LW_GET_SHORTCUT ( " limbo_ai/rename_task " ) , ACTION_RENAME ) ;
2023-12-14 22:18:44 +00:00
menu - > add_icon_item ( theme_cache . change_type_icon , TTR ( " Change Type " ) , ACTION_CHANGE_TYPE ) ;
2023-08-29 09:47:48 +00:00
menu - > add_icon_item ( theme_cache . edit_script_icon , TTR ( " Edit Script " ) , ACTION_EDIT_SCRIPT ) ;
menu - > add_icon_item ( theme_cache . open_doc_icon , TTR ( " Open Documentation " ) , ACTION_OPEN_DOC ) ;
2024-01-09 12:34:24 +00:00
menu - > set_item_disabled ( menu - > get_item_index ( ACTION_EDIT_SCRIPT ) , task - > get_script ( ) = = Variant ( ) ) ;
2023-08-17 09:41:40 +00:00
2022-09-01 22:20:37 +00:00
menu - > add_separator ( ) ;
2024-01-09 12:34:24 +00:00
menu - > add_icon_shortcut ( theme_cache . move_task_up_icon , LW_GET_SHORTCUT ( " limbo_ai/move_task_up " ) , ACTION_MOVE_UP ) ;
menu - > add_icon_shortcut ( theme_cache . move_task_down_icon , LW_GET_SHORTCUT ( " limbo_ai/move_task_down " ) , ACTION_MOVE_DOWN ) ;
menu - > add_icon_shortcut ( theme_cache . duplicate_task_icon , LW_GET_SHORTCUT ( " limbo_ai/duplicate_task " ) , ACTION_DUPLICATE ) ;
2023-08-29 09:47:48 +00:00
menu - > add_icon_item ( theme_cache . make_root_icon , TTR ( " Make Root " ) , ACTION_MAKE_ROOT ) ;
2023-12-17 14:24:38 +00:00
menu - > add_icon_item ( theme_cache . extract_subtree_icon , TTR ( " Extract Subtree " ) , ACTION_EXTRACT_SUBTREE ) ;
2023-08-17 09:41:40 +00:00
2023-08-16 14:07:04 +00:00
menu - > add_separator ( ) ;
2024-01-09 12:34:24 +00:00
menu - > add_icon_shortcut ( theme_cache . remove_task_icon , LW_GET_SHORTCUT ( " limbo_ai/remove_task " ) , ACTION_REMOVE ) ;
2022-09-01 22:20:37 +00:00
2022-12-15 17:29:22 +00:00
menu - > reset_size ( ) ;
menu - > set_position ( p_menu_pos ) ;
2022-09-01 22:20:37 +00:00
menu - > popup ( ) ;
}
2023-08-16 14:07:04 +00:00
void LimboAIEditor : : _action_selected ( int p_id ) {
2024-01-09 12:34:24 +00:00
EditorUndoRedoManager * undo_redo = GET_UNDO_REDO ( ) ;
2022-09-01 22:20:37 +00:00
switch ( p_id ) {
2023-08-16 14:07:04 +00:00
case ACTION_RENAME : {
if ( ! task_tree - > get_selected ( ) . is_valid ( ) ) {
return ;
2022-09-01 22:20:37 +00:00
}
2023-08-19 11:12:24 +00:00
Ref < BTTask > task = task_tree - > get_selected ( ) ;
2024-01-09 12:34:24 +00:00
if ( IS_CLASS ( task , BTComment ) ) {
2023-08-19 11:12:24 +00:00
rename_dialog - > set_title ( TTR ( " Edit Comment " ) ) ;
rename_dialog - > get_ok_button ( ) - > set_text ( TTR ( " OK " ) ) ;
rename_edit - > set_placeholder ( TTR ( " Comment " ) ) ;
} else {
rename_dialog - > set_title ( TTR ( " Rename Task " ) ) ;
rename_dialog - > get_ok_button ( ) - > set_text ( TTR ( " Rename " ) ) ;
rename_edit - > set_placeholder ( TTR ( " Custom Name " ) ) ;
}
rename_edit - > set_text ( task - > get_custom_name ( ) ) ;
2023-08-16 14:07:04 +00:00
rename_dialog - > popup_centered ( ) ;
rename_edit - > select_all ( ) ;
rename_edit - > grab_focus ( ) ;
2022-09-01 22:20:37 +00:00
} break ;
2023-12-14 22:18:44 +00:00
case ACTION_CHANGE_TYPE : {
2023-12-14 22:38:02 +00:00
change_type_palette - > clear_filter ( ) ;
2023-12-14 22:18:44 +00:00
change_type_palette - > refresh ( ) ;
Rect2 rect = Rect2 ( get_global_mouse_position ( ) , Size2 ( 400.0 , 600.0 ) * EDSCALE ) ;
change_type_popup - > popup ( rect ) ;
} break ;
2023-09-25 16:07:26 +00:00
case ACTION_EDIT_PROBABILITY : {
Rect2 rect = task_tree - > get_selected_probability_rect ( ) ;
ERR_FAIL_COND ( rect = = Rect2 ( ) ) ;
rect . position . y + = rect . size . y ;
rect . position + = task_tree - > get_rect ( ) . position ;
rect = task_tree - > get_screen_transform ( ) . xform ( rect ) ;
2023-09-25 20:36:37 +00:00
_update_probability_edit ( ) ;
2023-09-25 16:07:26 +00:00
probability_popup - > popup ( rect ) ;
} break ;
2023-08-17 09:41:40 +00:00
case ACTION_EDIT_SCRIPT : {
ERR_FAIL_COND ( task_tree - > get_selected ( ) . is_null ( ) ) ;
2024-01-09 12:34:24 +00:00
EDIT_RESOURCE ( task_tree - > get_selected ( ) - > get_script ( ) ) ;
2023-08-17 09:41:40 +00:00
} break ;
2023-08-17 13:29:12 +00:00
case ACTION_OPEN_DOC : {
Ref < BTTask > task = task_tree - > get_selected ( ) ;
ERR_FAIL_COND ( task . is_null ( ) ) ;
String help_class ;
2024-01-09 12:34:24 +00:00
String res_path = task - > get_path ( ) ;
if ( res_path . begins_with ( " res:// " ) ) {
help_class = " \" " + res_path . get_basename ( ) . to_pascal_case ( ) + " \" " ;
} else {
// Assuming context task is core class.
2023-08-17 13:29:12 +00:00
help_class = task - > get_class ( ) ;
}
2024-01-09 12:34:24 +00:00
SHOW_DOC ( " class_name: " + help_class ) ;
2023-08-17 13:29:12 +00:00
} break ;
2022-09-01 22:20:37 +00:00
case ACTION_MOVE_UP : {
Ref < BTTask > sel = task_tree - > get_selected ( ) ;
if ( sel . is_valid ( ) & & sel - > get_parent ( ) . is_valid ( ) ) {
Ref < BTTask > parent = sel - > get_parent ( ) ;
2023-11-22 12:05:55 +00:00
int idx = sel - > get_index ( ) ;
2022-09-01 22:20:37 +00:00
if ( idx > 0 & & idx < parent - > get_child_count ( ) ) {
2022-12-22 12:19:39 +00:00
undo_redo - > create_action ( TTR ( " Move BT Task " ) ) ;
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( parent . ptr ( ) , LW_NAME ( remove_child ) , sel ) ;
undo_redo - > add_do_method ( parent . ptr ( ) , LW_NAME ( add_child_at_index ) , sel , idx - 1 ) ;
undo_redo - > add_undo_method ( parent . ptr ( ) , LW_NAME ( remove_child ) , sel ) ;
undo_redo - > add_undo_method ( parent . ptr ( ) , LW_NAME ( add_child_at_index ) , sel , idx ) ;
undo_redo - > add_do_method ( task_tree , LW_NAME ( update_tree ) ) ;
undo_redo - > add_undo_method ( task_tree , LW_NAME ( update_tree ) ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > commit_action ( ) ;
2022-09-03 12:01:13 +00:00
_mark_as_dirty ( true ) ;
2022-09-01 22:20:37 +00:00
}
}
} break ;
case ACTION_MOVE_DOWN : {
Ref < BTTask > sel = task_tree - > get_selected ( ) ;
if ( sel . is_valid ( ) & & sel - > get_parent ( ) . is_valid ( ) ) {
Ref < BTTask > parent = sel - > get_parent ( ) ;
2023-11-22 12:05:55 +00:00
int idx = sel - > get_index ( ) ;
2022-09-01 22:20:37 +00:00
if ( idx > = 0 & & idx < ( parent - > get_child_count ( ) - 1 ) ) {
2022-12-22 12:19:39 +00:00
undo_redo - > create_action ( TTR ( " Move BT Task " ) ) ;
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( parent . ptr ( ) , LW_NAME ( remove_child ) , sel ) ;
undo_redo - > add_do_method ( parent . ptr ( ) , LW_NAME ( add_child_at_index ) , sel , idx + 1 ) ;
undo_redo - > add_undo_method ( parent . ptr ( ) , LW_NAME ( remove_child ) , sel ) ;
undo_redo - > add_undo_method ( parent . ptr ( ) , LW_NAME ( add_child_at_index ) , sel , idx ) ;
undo_redo - > add_do_method ( task_tree , LW_NAME ( update_tree ) ) ;
undo_redo - > add_undo_method ( task_tree , LW_NAME ( update_tree ) ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > commit_action ( ) ;
2022-09-03 12:01:13 +00:00
_mark_as_dirty ( true ) ;
2022-09-01 22:20:37 +00:00
}
}
} break ;
case ACTION_DUPLICATE : {
Ref < BTTask > sel = task_tree - > get_selected ( ) ;
if ( sel . is_valid ( ) ) {
2022-12-22 12:19:39 +00:00
undo_redo - > create_action ( TTR ( " Duplicate BT Task " ) ) ;
2022-09-01 22:20:37 +00:00
Ref < BTTask > parent = sel - > get_parent ( ) ;
if ( parent . is_null ( ) ) {
parent = sel ;
}
2022-12-22 12:19:39 +00:00
const Ref < BTTask > & sel_dup = sel - > clone ( ) ;
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( parent . ptr ( ) , LW_NAME ( add_child_at_index ) , sel_dup , sel - > get_index ( ) + 1 ) ;
undo_redo - > add_undo_method ( parent . ptr ( ) , LW_NAME ( remove_child ) , sel_dup ) ;
undo_redo - > add_do_method ( task_tree , LW_NAME ( update_tree ) ) ;
undo_redo - > add_undo_method ( task_tree , LW_NAME ( update_tree ) ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > commit_action ( ) ;
2022-09-03 12:01:13 +00:00
_mark_as_dirty ( true ) ;
2022-09-01 22:20:37 +00:00
}
} break ;
case ACTION_MAKE_ROOT : {
Ref < BTTask > sel = task_tree - > get_selected ( ) ;
if ( sel . is_valid ( ) & & task_tree - > get_bt ( ) - > get_root_task ( ) ! = sel ) {
Ref < BTTask > parent = sel - > get_parent ( ) ;
ERR_FAIL_COND ( parent . is_null ( ) ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > create_action ( TTR ( " Make Root " ) ) ;
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( parent . ptr ( ) , LW_NAME ( remove_child ) , sel ) ;
2022-09-01 22:20:37 +00:00
Ref < BTTask > old_root = task_tree - > get_bt ( ) - > get_root_task ( ) ;
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( task_tree - > get_bt ( ) . ptr ( ) , LW_NAME ( set_root_task ) , sel ) ;
undo_redo - > add_do_method ( sel . ptr ( ) , LW_NAME ( add_child ) , old_root ) ;
undo_redo - > add_undo_method ( sel . ptr ( ) , LW_NAME ( remove_child ) , old_root ) ;
undo_redo - > add_undo_method ( task_tree - > get_bt ( ) . ptr ( ) , LW_NAME ( set_root_task ) , old_root ) ;
undo_redo - > add_undo_method ( parent . ptr ( ) , LW_NAME ( add_child_at_index ) , sel , sel - > get_index ( ) ) ;
undo_redo - > add_do_method ( task_tree , LW_NAME ( update_tree ) ) ;
undo_redo - > add_undo_method ( task_tree , LW_NAME ( update_tree ) ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > commit_action ( ) ;
2022-09-03 12:01:13 +00:00
_mark_as_dirty ( true ) ;
2022-09-01 22:20:37 +00:00
}
} break ;
2023-12-17 14:24:38 +00:00
case ACTION_EXTRACT_SUBTREE : {
Ref < BTTask > sel = task_tree - > get_selected ( ) ;
2024-01-09 12:34:24 +00:00
if ( sel . is_valid ( ) & & ! IS_CLASS ( sel , BTSubtree ) ) {
2023-12-17 14:24:38 +00:00
extract_dialog - > popup_centered_ratio ( ) ;
}
} break ;
2023-08-16 14:07:04 +00:00
case ACTION_REMOVE : {
Ref < BTTask > sel = task_tree - > get_selected ( ) ;
if ( sel . is_valid ( ) ) {
undo_redo - > create_action ( TTR ( " Remove BT Task " ) ) ;
2023-12-17 14:24:38 +00:00
if ( sel - > is_root ( ) ) {
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( task_tree - > get_bt ( ) . ptr ( ) , LW_NAME ( set_root_task ) , Variant ( ) ) ;
undo_redo - > add_undo_method ( task_tree - > get_bt ( ) . ptr ( ) , LW_NAME ( set_root_task ) , task_tree - > get_bt ( ) - > get_root_task ( ) ) ;
2023-08-16 14:07:04 +00:00
} else {
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( sel - > get_parent ( ) . ptr ( ) , LW_NAME ( remove_child ) , sel ) ;
undo_redo - > add_undo_method ( sel - > get_parent ( ) . ptr ( ) , LW_NAME ( add_child_at_index ) , sel , sel - > get_index ( ) ) ;
2023-08-16 14:07:04 +00:00
}
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( task_tree , LW_NAME ( update_tree ) ) ;
undo_redo - > add_undo_method ( task_tree , LW_NAME ( update_tree ) ) ;
2023-08-16 14:07:04 +00:00
undo_redo - > commit_action ( ) ;
2024-01-09 12:34:24 +00:00
EDIT_RESOURCE ( task_tree - > get_selected ( ) ) ;
2023-08-16 14:07:04 +00:00
_mark_as_dirty ( true ) ;
}
} break ;
2022-09-01 22:20:37 +00:00
}
}
2023-09-25 16:07:26 +00:00
void LimboAIEditor : : _on_probability_edited ( double p_value ) {
Ref < BTTask > selected = task_tree - > get_selected ( ) ;
ERR_FAIL_COND ( selected = = nullptr ) ;
Ref < BTProbabilitySelector > probability_selector = selected - > get_parent ( ) ;
ERR_FAIL_COND ( probability_selector . is_null ( ) ) ;
2023-09-25 20:36:37 +00:00
if ( percent_mode - > is_pressed ( ) ) {
2023-11-22 12:05:55 +00:00
probability_selector - > set_probability ( selected - > get_index ( ) , p_value * 0.01 ) ;
2023-09-25 20:36:37 +00:00
} else {
2023-11-22 12:05:55 +00:00
probability_selector - > set_weight ( selected - > get_index ( ) , p_value ) ;
2023-09-25 20:36:37 +00:00
}
}
void LimboAIEditor : : _update_probability_edit ( ) {
Ref < BTTask > selected = task_tree - > get_selected ( ) ;
ERR_FAIL_COND ( selected . is_null ( ) ) ;
Ref < BTProbabilitySelector > prob = selected - > get_parent ( ) ;
ERR_FAIL_COND ( prob . is_null ( ) ) ;
2023-11-22 12:05:55 +00:00
double others_weight = prob - > get_total_weight ( ) - prob - > get_weight ( selected - > get_index ( ) ) ;
2023-09-25 20:36:37 +00:00
bool cannot_edit_percent = others_weight = = 0.0 ;
percent_mode - > set_disabled ( cannot_edit_percent ) ;
if ( cannot_edit_percent & & percent_mode - > is_pressed ( ) ) {
weight_mode - > set_pressed ( true ) ;
}
if ( percent_mode - > is_pressed ( ) ) {
probability_edit - > set_suffix ( " % " ) ;
probability_edit - > set_max ( 99.0 ) ;
probability_edit - > set_allow_greater ( false ) ;
probability_edit - > set_step ( 0.01 ) ;
probability_edit - > set_value_no_signal ( task_tree - > get_selected_probability_percent ( ) ) ;
} else {
probability_edit - > set_suffix ( " " ) ;
probability_edit - > set_allow_greater ( true ) ;
probability_edit - > set_max ( 10.0 ) ;
probability_edit - > set_step ( 0.01 ) ;
probability_edit - > set_value_no_signal ( task_tree - > get_selected_probability_weight ( ) ) ;
}
}
void LimboAIEditor : : _probability_popup_closed ( ) {
2023-09-26 09:10:23 +00:00
probability_edit - > grab_focus ( ) ; // Hack: Workaround for an EditorSpinSlider bug keeping LineEdit visible and "stuck" with ghost value.
2023-09-25 16:07:26 +00:00
}
2023-08-20 09:34:13 +00:00
void LimboAIEditor : : _misc_option_selected ( int p_id ) {
switch ( p_id ) {
2023-10-24 13:44:18 +00:00
case MISC_INTRODUCTION : {
2024-01-09 12:34:24 +00:00
SHOW_DOC ( " class_name:BehaviorTree " ) ;
2023-10-24 13:44:18 +00:00
} break ;
2023-08-20 09:34:13 +00:00
case MISC_OPEN_DEBUGGER : {
2024-01-09 20:59:09 +00:00
ERR_FAIL_COND ( LimboDebuggerPlugin : : get_singleton ( ) = = nullptr ) ;
if ( LimboDebuggerPlugin : : get_singleton ( ) - > get_session_tab ( ) - > get_window_enabled ( ) ) {
LimboDebuggerPlugin : : get_singleton ( ) - > get_session_tab ( ) - > set_window_enabled ( true ) ;
} else {
# ifdef LIMBOAI_MODULE
EditorNode : : get_singleton ( ) - > make_bottom_panel_item_visible ( EditorDebuggerNode : : get_singleton ( ) ) ;
EditorDebuggerNode : : get_singleton ( ) - > get_default_debugger ( ) - > switch_to_debugger (
LimboDebuggerPlugin : : get_singleton ( ) - > get_session_tab_index ( ) ) ;
# else // LIMBOAI_GDEXTENSION
// TODO: Unsure how to switch to debugger pane with GDExtension.
# endif // LIMBOAI_MODULE
}
2023-08-20 09:34:13 +00:00
} break ;
2023-08-21 09:51:19 +00:00
case MISC_PROJECT_SETTINGS : {
2023-08-21 16:17:34 +00:00
_edit_project_settings ( ) ;
2023-08-21 09:51:19 +00:00
} break ;
2023-08-21 11:46:35 +00:00
case MISC_CREATE_SCRIPT_TEMPLATE : {
2023-08-21 13:27:30 +00:00
String template_path = _get_script_template_path ( ) ;
String template_dir = template_path . get_base_dir ( ) ;
2024-01-09 12:34:24 +00:00
if ( ! FILE_EXISTS ( template_path ) ) {
if ( ! DirAccess : : dir_exists_absolute ( template_dir ) ) {
2024-01-10 14:23:04 +00:00
Error err = DirAccess : : make_dir_recursive_absolute ( template_dir ) ;
2023-08-21 13:27:30 +00:00
ERR_FAIL_COND ( err ! = OK ) ;
}
2024-01-09 12:34:24 +00:00
Ref < FileAccess > f = FileAccess : : open ( template_path , FileAccess : : WRITE ) ;
ERR_FAIL_COND ( f . is_null ( ) ) ;
2023-08-21 11:46:35 +00:00
String script_template =
" # meta-name: Custom Task \n "
" # meta-description: Custom task to be used in a BehaviorTree \n "
" # meta-default: true \n "
" @tool \n "
" extends _BASE_ \n "
" ## _CLASS_ \n "
" \n \n "
" # Display a customized name (requires @tool). \n "
" func _generate_name() -> String: \n "
" _TS_return \" _CLASS_ \" \n "
" \n \n "
" # Called once during initialization. \n "
" func _setup() -> void: \n "
" _TS_pass \n "
" \n \n "
" # Called each time this task is entered. \n "
" func _enter() -> void: \n "
" _TS_pass \n "
" \n \n "
" # Called each time this task is exited. \n "
" func _exit() -> void: \n "
" _TS_pass \n "
" \n \n "
" # Called each time this task is ticked (aka executed). \n "
2023-09-19 11:45:56 +00:00
" func _tick(delta: float) -> Status: \n "
2024-01-10 14:23:04 +00:00
" _TS_return SUCCESS \n "
" \n \n "
" # Strings returned from this method are displayed as warnings in the behavior tree editor (requires @tool). \n "
" func _get_configuration_warnings() -> PackedStringArray: \n "
" _TS_var warnings := PackedStringArray() \n "
" _TS_return warnings \n " ;
2023-08-21 11:46:35 +00:00
f - > store_string ( script_template ) ;
f - > close ( ) ;
}
2024-01-10 14:23:04 +00:00
EDITOR_FILE_SYSTEM ( ) - > scan ( ) ;
2024-01-09 12:34:24 +00:00
EDIT_SCRIPT ( template_path ) ;
2023-08-21 11:46:35 +00:00
} break ;
2023-08-20 09:34:13 +00:00
}
}
2022-12-15 07:26:52 +00:00
void LimboAIEditor : : _on_tree_task_selected ( const Ref < BTTask > & p_task ) {
2024-01-09 12:34:24 +00:00
EDIT_RESOURCE ( p_task ) ;
2022-09-01 22:20:37 +00:00
}
2022-12-15 07:26:52 +00:00
void LimboAIEditor : : _on_visibility_changed ( ) {
2023-08-26 17:42:17 +00:00
if ( task_tree - > is_visible_in_tree ( ) ) {
2022-09-01 22:20:37 +00:00
Ref < BTTask > sel = task_tree - > get_selected ( ) ;
if ( sel . is_valid ( ) ) {
2024-01-09 12:34:24 +00:00
EDIT_RESOURCE ( sel ) ;
} else if ( task_tree - > get_bt ( ) . is_valid ( ) & & INSPECTOR_GET_EDITED_OBJECT ( ) ! = task_tree - > get_bt ( ) . ptr ( ) ) {
EDIT_RESOURCE ( task_tree - > get_bt ( ) ) ;
2022-09-01 22:20:37 +00:00
}
2022-09-05 15:56:38 +00:00
2023-08-26 08:08:01 +00:00
task_palette - > refresh ( ) ;
2022-09-01 22:20:37 +00:00
}
2023-08-18 10:12:55 +00:00
_update_favorite_tasks ( ) ;
2022-09-01 22:20:37 +00:00
}
2022-12-15 07:26:52 +00:00
void LimboAIEditor : : _on_header_pressed ( ) {
2022-11-22 21:58:53 +00:00
_update_header ( ) ;
2022-09-01 22:20:37 +00:00
task_tree - > deselect ( ) ;
2024-01-09 12:34:24 +00:00
EDIT_RESOURCE ( task_tree - > get_bt ( ) ) ;
2022-09-01 22:20:37 +00:00
}
void LimboAIEditor : : _on_save_pressed ( ) {
2022-09-06 11:08:27 +00:00
if ( task_tree - > get_bt ( ) . is_null ( ) ) {
return ;
}
2022-09-01 22:20:37 +00:00
String path = task_tree - > get_bt ( ) - > get_path ( ) ;
2022-12-15 07:26:52 +00:00
if ( path . is_empty ( ) ) {
2022-09-01 22:20:37 +00:00
save_dialog - > popup_centered_ratio ( ) ;
} else {
_save_bt ( path ) ;
}
}
2022-09-02 13:43:54 +00:00
void LimboAIEditor : : _on_history_back ( ) {
2024-01-09 23:02:24 +00:00
ERR_FAIL_COND ( history . size ( ) = = 0 ) ;
2022-09-02 13:43:54 +00:00
idx_history = MAX ( idx_history - 1 , 0 ) ;
2024-01-09 12:34:24 +00:00
EDIT_RESOURCE ( history [ idx_history ] ) ;
2022-09-02 13:43:54 +00:00
}
void LimboAIEditor : : _on_history_forward ( ) {
2024-01-09 23:02:24 +00:00
ERR_FAIL_COND ( history . size ( ) = = 0 ) ;
2022-09-02 13:43:54 +00:00
idx_history = MIN ( idx_history + 1 , history . size ( ) - 1 ) ;
2024-01-09 12:34:24 +00:00
EDIT_RESOURCE ( history [ idx_history ] ) ;
2022-09-02 13:43:54 +00:00
}
2022-09-03 15:00:20 +00:00
void LimboAIEditor : : _on_task_dragged ( Ref < BTTask > p_task , Ref < BTTask > p_to_task , int p_type ) {
2022-12-22 12:19:39 +00:00
ERR_FAIL_COND ( p_type < - 1 | | p_type > 1 ) ;
2023-08-28 14:22:44 +00:00
ERR_FAIL_COND ( p_type ! = 0 & & p_to_task - > get_parent ( ) . is_null ( ) ) ;
2022-09-03 15:00:20 +00:00
if ( p_task = = p_to_task ) {
return ;
}
2022-12-22 12:19:39 +00:00
2024-01-09 12:34:24 +00:00
EditorUndoRedoManager * undo_redo = GET_UNDO_REDO ( ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > create_action ( TTR ( " Drag BT Task " ) ) ;
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( p_task - > get_parent ( ) . ptr ( ) , LW_NAME ( remove_child ) , p_task ) ;
2022-12-22 12:19:39 +00:00
2022-09-03 15:00:20 +00:00
if ( p_type = = 0 ) {
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( p_to_task . ptr ( ) , LW_NAME ( add_child ) , p_task ) ;
undo_redo - > add_undo_method ( p_to_task . ptr ( ) , LW_NAME ( remove_child ) , p_task ) ;
2023-11-22 12:05:55 +00:00
} else {
int drop_idx = p_to_task - > get_index ( ) ;
if ( p_to_task - > get_parent ( ) = = p_task - > get_parent ( ) & & drop_idx > p_task - > get_index ( ) ) {
drop_idx - = 1 ;
}
if ( p_type = = - 1 ) {
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( p_to_task - > get_parent ( ) . ptr ( ) , LW_NAME ( add_child_at_index ) , p_task , drop_idx ) ;
undo_redo - > add_undo_method ( p_to_task - > get_parent ( ) . ptr ( ) , LW_NAME ( remove_child ) , p_task ) ;
2023-11-22 12:05:55 +00:00
} else if ( p_type = = 1 ) {
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( p_to_task - > get_parent ( ) . ptr ( ) , LW_NAME ( add_child_at_index ) , p_task , drop_idx + 1 ) ;
undo_redo - > add_undo_method ( p_to_task - > get_parent ( ) . ptr ( ) , LW_NAME ( remove_child ) , p_task ) ;
2023-11-22 12:05:55 +00:00
}
2022-09-03 15:00:20 +00:00
}
2022-12-22 12:19:39 +00:00
2023-11-22 12:05:55 +00:00
undo_redo - > add_undo_method ( p_task - > get_parent ( ) . ptr ( ) , " add_child_at_index " , p_task , p_task - > get_index ( ) ) ;
2022-12-22 12:19:39 +00:00
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( task_tree , LW_NAME ( update_tree ) ) ;
undo_redo - > add_undo_method ( task_tree , LW_NAME ( update_tree ) ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > commit_action ( ) ;
_mark_as_dirty ( true ) ;
2022-09-03 15:00:20 +00:00
}
2024-01-09 12:34:24 +00:00
void LimboAIEditor : : _on_resources_reload ( const PackedStringArray & p_resources ) {
2022-12-19 11:38:40 +00:00
for ( const String & res_path : p_resources ) {
2024-01-09 12:34:24 +00:00
if ( ! RESOURCE_IS_CACHED ( res_path ) ) {
2022-11-22 20:00:08 +00:00
continue ;
}
2024-01-09 12:34:24 +00:00
if ( RESOURCE_EXISTS ( res_path , " BehaviorTree " ) ) {
Ref < BehaviorTree > res = RESOURCE_LOAD ( res_path , " BehaviorTree " ) ;
2022-12-19 11:38:40 +00:00
if ( res . is_valid ( ) ) {
if ( history . has ( res ) ) {
disk_changed_files . insert ( res_path ) ;
} else {
2024-01-09 12:34:24 +00:00
Ref < BehaviorTree > reloaded = RESOURCE_LOAD_NO_CACHE ( res_path , " BehaviorTree " ) ;
2024-01-10 21:45:42 +00:00
res - > copy_other ( reloaded ) ;
2022-12-19 11:38:40 +00:00
}
}
2022-11-22 20:00:08 +00:00
}
}
2024-01-10 19:00:04 +00:00
// TODO: Find a way to allow resaving trees when they change outside of Godot.
// * Currently, editor reloads them without asking in GDExtension. There is no Resource::editor_can_reload_from_file().
# ifdef LIMBOAI_MODULE
2022-11-22 20:00:08 +00:00
if ( disk_changed_files . size ( ) > 0 ) {
disk_changed_list - > clear ( ) ;
disk_changed_list - > set_hide_root ( true ) ;
disk_changed_list - > create_item ( ) ;
2022-12-15 07:26:52 +00:00
for ( const String & fn : disk_changed_files ) {
2022-11-22 20:00:08 +00:00
TreeItem * ti = disk_changed_list - > create_item ( ) ;
2022-12-15 07:26:52 +00:00
ti - > set_text ( 0 , fn ) ;
2022-11-22 20:00:08 +00:00
}
if ( ! is_visible ( ) ) {
2024-01-09 12:34:24 +00:00
SET_MAIN_SCREEN_EDITOR ( " LimboAI " ) ;
2022-11-22 20:00:08 +00:00
}
disk_changed - > call_deferred ( " popup_centered_ratio " , 0.5 ) ;
}
2024-01-10 19:00:04 +00:00
# else //LIMBOAI_GDEXTENSION
task_tree - > update_tree ( ) ;
# endif // LIMBOAI_MODULE
2022-11-22 20:00:08 +00:00
}
2023-12-14 22:18:44 +00:00
void LimboAIEditor : : _task_type_selected ( const String & p_class_or_path ) {
change_type_popup - > hide ( ) ;
Ref < BTTask > selected_task = task_tree - > get_selected ( ) ;
ERR_FAIL_COND ( selected_task . is_null ( ) ) ;
Ref < BTTask > new_task = _create_task_by_class_or_path ( p_class_or_path ) ;
ERR_FAIL_COND_MSG ( new_task . is_null ( ) , " LimboAI: Unable to construct task. " ) ;
2024-01-09 12:34:24 +00:00
EditorUndoRedoManager * undo_redo = GET_UNDO_REDO ( ) ;
2023-12-14 22:18:44 +00:00
undo_redo - > create_action ( TTR ( " Change BT task type " ) ) ;
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( this , LW_NAME ( _replace_task ) , selected_task , new_task ) ;
undo_redo - > add_undo_method ( this , LW_NAME ( _replace_task ) , new_task , selected_task ) ;
undo_redo - > add_do_method ( task_tree , LW_NAME ( update_tree ) ) ;
undo_redo - > add_undo_method ( task_tree , LW_NAME ( update_tree ) ) ;
2023-12-14 22:18:44 +00:00
undo_redo - > commit_action ( ) ;
_mark_as_dirty ( true ) ;
}
void LimboAIEditor : : _replace_task ( const Ref < BTTask > & p_task , const Ref < BTTask > & p_by_task ) {
ERR_FAIL_COND ( p_task . is_null ( ) ) ;
ERR_FAIL_COND ( p_by_task . is_null ( ) ) ;
ERR_FAIL_COND ( p_by_task - > get_child_count ( ) > 0 ) ;
ERR_FAIL_COND ( p_by_task - > get_parent ( ) . is_valid ( ) ) ;
while ( p_task - > get_child_count ( ) > 0 ) {
Ref < BTTask > child = p_task - > get_child ( 0 ) ;
p_task - > remove_child_at_index ( 0 ) ;
p_by_task - > add_child ( child ) ;
}
p_by_task - > set_custom_name ( p_task - > get_custom_name ( ) ) ;
Ref < BTTask > parent = p_task - > get_parent ( ) ;
if ( parent . is_null ( ) ) {
// Assuming root task is replaced.
ERR_FAIL_COND ( task_tree - > get_bt ( ) . is_null ( ) ) ;
ERR_FAIL_COND ( task_tree - > get_bt ( ) - > get_root_task ( ) ! = p_task ) ;
task_tree - > get_bt ( ) - > set_root_task ( p_by_task ) ;
} else {
// Non-root task is replaced.
int idx = p_task - > get_index ( ) ;
double weight = 0.0 ;
Ref < BTProbabilitySelector > probability_selector = parent ;
if ( probability_selector . is_valid ( ) ) {
weight = probability_selector - > get_weight ( idx ) ;
}
parent - > remove_child ( p_task ) ;
parent - > add_child_at_index ( p_by_task , idx ) ;
if ( probability_selector . is_valid ( ) ) {
probability_selector - > set_weight ( idx , weight ) ;
}
}
}
2022-11-22 20:00:08 +00:00
void LimboAIEditor : : _reload_modified ( ) {
2024-01-09 12:34:24 +00:00
for ( const String & res_path : disk_changed_files ) {
Ref < BehaviorTree > res = RESOURCE_LOAD ( res_path , " BehaviorTree " ) ;
2022-12-19 09:29:46 +00:00
if ( res . is_valid ( ) ) {
2024-01-09 12:34:24 +00:00
Ref < BehaviorTree > reloaded = RESOURCE_LOAD_NO_CACHE ( res_path , " BehaviorTree " ) ;
2024-01-10 21:45:42 +00:00
res - > copy_other ( reloaded ) ;
2022-12-19 09:29:46 +00:00
if ( idx_history > = 0 & & history . get ( idx_history ) = = res ) {
edit_bt ( res , true ) ;
2022-11-22 20:00:08 +00:00
}
}
}
disk_changed_files . clear ( ) ;
2024-01-10 19:00:04 +00:00
task_tree - > update_tree ( ) ;
2022-11-22 20:00:08 +00:00
}
void LimboAIEditor : : _resave_modified ( String _str ) {
2024-01-09 12:34:24 +00:00
for ( const String & res_path : disk_changed_files ) {
Ref < BehaviorTree > res = RESOURCE_LOAD ( res_path , " BehaviorTree " ) ;
2022-12-19 11:38:40 +00:00
if ( res . is_valid ( ) ) {
ERR_FAIL_COND ( ! res - > is_class ( " BehaviorTree " ) ) ;
2024-01-09 12:34:24 +00:00
RESOURCE_SAVE ( res , res - > get_path ( ) , 0 ) ;
2022-11-22 20:00:08 +00:00
}
}
2024-01-10 19:00:04 +00:00
task_tree - > update_tree ( ) ;
2022-11-22 20:00:08 +00:00
disk_changed - > hide ( ) ;
disk_changed_files . clear ( ) ;
}
2022-12-17 12:39:37 +00:00
void LimboAIEditor : : _rename_task_confirmed ( ) {
2022-11-23 15:25:32 +00:00
ERR_FAIL_COND ( ! task_tree - > get_selected ( ) . is_valid ( ) ) ;
rename_dialog - > hide ( ) ;
2022-12-22 12:19:39 +00:00
2024-01-09 12:34:24 +00:00
EditorUndoRedoManager * undo_redo = GET_UNDO_REDO ( ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > create_action ( TTR ( " Set Custom Name " ) ) ;
2024-01-09 12:42:54 +00:00
undo_redo - > add_do_method ( task_tree - > get_selected ( ) . ptr ( ) , LW_NAME ( set_custom_name ) , rename_edit - > get_text ( ) ) ;
undo_redo - > add_undo_method ( task_tree - > get_selected ( ) . ptr ( ) , LW_NAME ( set_custom_name ) , task_tree - > get_selected ( ) - > get_custom_name ( ) ) ;
undo_redo - > add_do_method ( task_tree , LW_NAME ( update_task ) , task_tree - > get_selected ( ) ) ;
undo_redo - > add_undo_method ( task_tree , LW_NAME ( update_task ) , task_tree - > get_selected ( ) ) ;
2022-12-22 12:19:39 +00:00
undo_redo - > commit_action ( ) ;
2022-11-23 15:25:32 +00:00
}
2022-09-03 12:01:13 +00:00
void LimboAIEditor : : apply_changes ( ) {
for ( int i = 0 ; i < history . size ( ) ; i + + ) {
Ref < BehaviorTree > bt = history . get ( i ) ;
String path = bt - > get_path ( ) ;
2024-01-09 12:34:24 +00:00
if ( RESOURCE_EXISTS ( path , " BehaviorTree " ) ) {
RESOURCE_SAVE ( bt , path , 0 ) ;
2022-09-03 12:01:13 +00:00
}
dirty . clear ( ) ;
_update_header ( ) ;
}
}
2023-08-18 10:12:55 +00:00
void LimboAIEditor : : _update_favorite_tasks ( ) {
for ( int i = 0 ; i < fav_tasks_hbox - > get_child_count ( ) ; i + + ) {
fav_tasks_hbox - > get_child ( i ) - > queue_free ( ) ;
}
Array favorite_tasks = GLOBAL_GET ( " limbo_ai/behavior_tree/favorite_tasks " ) ;
for ( int i = 0 ; i < favorite_tasks . size ( ) ; i + + ) {
String task_meta = favorite_tasks [ i ] ;
2023-08-22 12:43:45 +00:00
2024-01-09 12:34:24 +00:00
if ( task_meta . is_empty ( ) | | ( ! FILE_EXISTS ( task_meta ) & & ! ClassDB : : class_exists ( task_meta ) ) ) {
2024-01-09 12:42:54 +00:00
call_deferred ( LW_NAME ( _update_banners ) ) ;
2023-08-22 12:43:45 +00:00
continue ;
}
2023-08-18 10:12:55 +00:00
Button * btn = memnew ( Button ) ;
String task_name ;
if ( task_meta . begins_with ( " res: " ) ) {
task_name = task_meta . get_file ( ) . get_basename ( ) . trim_prefix ( " BT " ) . to_pascal_case ( ) ;
} else {
task_name = task_meta . trim_prefix ( " BT " ) ;
}
btn - > set_text ( task_name ) ;
2024-01-09 12:42:54 +00:00
btn - > set_meta ( LW_NAME ( task_meta ) , task_meta ) ;
2024-01-09 12:34:24 +00:00
BUTTON_SET_ICON ( btn , LimboUtility : : get_singleton ( ) - > get_task_icon ( task_meta ) ) ;
2023-08-18 10:12:55 +00:00
btn - > set_tooltip_text ( vformat ( TTR ( " Add %s task. " ) , task_name ) ) ;
btn - > set_flat ( true ) ;
2024-01-09 12:42:54 +00:00
btn - > add_theme_constant_override ( LW_NAME ( icon_max_width ) , 16 * EDSCALE ) ; // Force user icons to be of the proper size.
2023-08-18 10:12:55 +00:00
btn - > set_focus_mode ( Control : : FOCUS_NONE ) ;
2024-01-09 12:42:54 +00:00
btn - > connect ( LW_NAME ( pressed ) , callable_mp ( this , & LimboAIEditor : : _add_task_by_class_or_path ) . bind ( task_meta ) ) ;
2023-08-18 10:12:55 +00:00
fav_tasks_hbox - > add_child ( btn ) ;
}
}
2023-08-21 11:46:35 +00:00
void LimboAIEditor : : _update_misc_menu ( ) {
PopupMenu * misc_menu = misc_btn - > get_popup ( ) ;
misc_menu - > clear ( ) ;
2023-10-24 13:44:18 +00:00
misc_menu - > add_icon_item ( theme_cache . open_doc_icon , TTR ( " Introduction " ) , MISC_INTRODUCTION ) ;
misc_menu - > add_separator ( ) ;
2024-01-09 20:59:09 +00:00
# ifdef LIMBOAI_MODULE
// * Not sure how to switch to debugger pane with GDExtension.
2024-01-09 12:34:24 +00:00
misc_menu - > add_icon_shortcut ( theme_cache . open_debugger_icon , LW_GET_SHORTCUT ( " limbo_ai/open_debugger " ) , MISC_OPEN_DEBUGGER ) ;
2024-01-09 20:59:09 +00:00
# endif // LIMBOAI_MODULE
2023-08-21 11:46:35 +00:00
misc_menu - > add_item ( TTR ( " Project Settings... " ) , MISC_PROJECT_SETTINGS ) ;
misc_menu - > add_separator ( ) ;
misc_menu - > add_item (
2024-01-09 12:34:24 +00:00
FILE_EXISTS ( _get_script_template_path ( ) ) ? TTR ( " Edit Script Template " ) : TTR ( " Create Script Template " ) ,
2023-08-21 11:46:35 +00:00
MISC_CREATE_SCRIPT_TEMPLATE ) ;
}
2023-08-22 10:20:09 +00:00
void LimboAIEditor : : _update_banners ( ) {
for ( int i = 0 ; i < banners - > get_child_count ( ) ; i + + ) {
2024-01-09 12:42:54 +00:00
if ( banners - > get_child ( i ) - > has_meta ( LW_NAME ( managed ) ) ) {
2023-08-22 12:43:45 +00:00
banners - > get_child ( i ) - > queue_free ( ) ;
}
2023-08-22 10:20:09 +00:00
}
for ( String dir_setting : { " limbo_ai/behavior_tree/user_task_dir_1 " , " limbo_ai/behavior_tree/user_task_dir_2 " , " limbo_ai/behavior_tree/user_task_dir_3 " } ) {
String task_dir = GLOBAL_GET ( dir_setting ) ;
2024-01-09 12:34:24 +00:00
if ( ! task_dir . is_empty ( ) & & ! DirAccess : : dir_exists_absolute ( task_dir ) ) {
2023-08-22 10:20:09 +00:00
ActionBanner * banner = memnew ( ActionBanner ) ;
banner - > set_text ( vformat ( TTR ( " Task folder not found: %s " ) , task_dir ) ) ;
banner - > add_action ( TTR ( " Create " ) , callable_mp ( this , & LimboAIEditor : : _create_user_task_dir ) , true ) ;
banner - > add_action ( TTR ( " Edit Path... " ) , callable_mp ( this , & LimboAIEditor : : _edit_project_settings ) ) ;
2024-01-09 12:42:54 +00:00
banner - > set_meta ( LW_NAME ( managed ) , Variant ( true ) ) ;
banners - > call_deferred ( LW_NAME ( add_child ) , banner ) ;
2023-08-22 12:43:45 +00:00
}
}
Array favorite_tasks = GLOBAL_GET ( " limbo_ai/behavior_tree/favorite_tasks " ) ;
for ( int i = 0 ; i < favorite_tasks . size ( ) ; i + + ) {
String task_meta = favorite_tasks [ i ] ;
2024-01-09 12:34:24 +00:00
if ( task_meta . is_empty ( ) | | ( ! FILE_EXISTS ( task_meta ) & & ! ClassDB : : class_exists ( task_meta ) ) ) {
2023-08-22 12:43:45 +00:00
ActionBanner * banner = memnew ( ActionBanner ) ;
banner - > set_text ( vformat ( TTR ( " Favorite task not found: %s " ) , task_meta ) ) ;
banner - > add_action ( TTR ( " Remove " ) , callable_mp ( this , & LimboAIEditor : : _remove_task_from_favorite ) . bind ( task_meta ) , true ) ;
banner - > add_action ( TTR ( " Edit Favorite Tasks... " ) , callable_mp ( this , & LimboAIEditor : : _edit_project_settings ) ) ;
2024-01-09 12:42:54 +00:00
banner - > set_meta ( LW_NAME ( managed ) , Variant ( true ) ) ;
banners - > call_deferred ( LW_NAME ( add_child ) , banner ) ;
2023-08-22 10:20:09 +00:00
}
}
2023-08-21 16:17:34 +00:00
}
2024-01-09 12:34:24 +00:00
void LimboAIEditor : : _do_update_theme_item_cache ( ) {
2024-01-09 12:42:54 +00:00
theme_cache . duplicate_task_icon = get_theme_icon ( LW_NAME ( Duplicate ) , LW_NAME ( EditorIcons ) ) ;
theme_cache . edit_script_icon = get_theme_icon ( LW_NAME ( Script ) , LW_NAME ( EditorIcons ) ) ;
theme_cache . make_root_icon = get_theme_icon ( LW_NAME ( NewRoot ) , LW_NAME ( EditorIcons ) ) ;
theme_cache . move_task_down_icon = get_theme_icon ( LW_NAME ( MoveDown ) , LW_NAME ( EditorIcons ) ) ;
theme_cache . move_task_up_icon = get_theme_icon ( LW_NAME ( MoveUp ) , LW_NAME ( EditorIcons ) ) ;
theme_cache . open_debugger_icon = get_theme_icon ( LW_NAME ( Debug ) , LW_NAME ( EditorIcons ) ) ;
theme_cache . open_doc_icon = get_theme_icon ( LW_NAME ( Help ) , LW_NAME ( EditorIcons ) ) ;
theme_cache . remove_task_icon = get_theme_icon ( LW_NAME ( Remove ) , LW_NAME ( EditorIcons ) ) ;
theme_cache . rename_task_icon = get_theme_icon ( LW_NAME ( Rename ) , LW_NAME ( EditorIcons ) ) ;
theme_cache . change_type_icon = get_theme_icon ( LW_NAME ( Reload ) , LW_NAME ( EditorIcons ) ) ;
2024-01-10 00:17:09 +00:00
theme_cache . behavior_tree_icon = LimboUtility : : get_singleton ( ) - > get_task_icon ( " BehaviorTree " ) ;
theme_cache . percent_icon = LimboUtility : : get_singleton ( ) - > get_task_icon ( " LimboPercent " ) ;
theme_cache . extract_subtree_icon = LimboUtility : : get_singleton ( ) - > get_task_icon ( " LimboExtractSubtree " ) ;
2023-08-29 09:47:48 +00:00
}
2022-09-06 11:28:25 +00:00
void LimboAIEditor : : _notification ( int p_what ) {
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
2023-08-28 09:39:56 +00:00
Ref < ConfigFile > cf ;
cf . instantiate ( ) ;
2024-01-09 14:23:02 +00:00
String conf_path = PROJECT_CONFIG_FILE ( ) ;
2023-08-28 09:39:56 +00:00
if ( cf - > load ( conf_path ) = = OK ) {
hsc - > set_split_offset ( cf - > get_value ( " bt_editor " , " bteditor_hsplit " , hsc - > get_split_offset ( ) ) ) ;
2022-09-06 11:28:25 +00:00
}
} break ;
case NOTIFICATION_EXIT_TREE : {
2023-08-28 09:39:56 +00:00
Ref < ConfigFile > cf ;
cf . instantiate ( ) ;
2024-01-09 14:23:02 +00:00
String conf_path = PROJECT_CONFIG_FILE ( ) ;
2023-08-28 09:39:56 +00:00
cf - > load ( conf_path ) ;
cf - > set_value ( " bt_editor " , " bteditor_hsplit " , hsc - > get_split_offset ( ) ) ;
cf - > save ( conf_path ) ;
2022-09-06 11:28:25 +00:00
} break ;
2024-01-09 12:34:24 +00:00
case NOTIFICATION_READY : {
// **** Signals
save_dialog - > connect ( " file_selected " , callable_mp ( this , & LimboAIEditor : : _save_bt ) ) ;
load_dialog - > connect ( " file_selected " , callable_mp ( this , & LimboAIEditor : : _load_bt ) ) ;
extract_dialog - > connect ( " file_selected " , callable_mp ( this , & LimboAIEditor : : _extract_subtree ) ) ;
2024-01-09 12:42:54 +00:00
new_btn - > connect ( LW_NAME ( pressed ) , callable_mp ( this , & LimboAIEditor : : _new_bt ) ) ;
load_btn - > connect ( LW_NAME ( pressed ) , callable_mp ( this , & LimboAIEditor : : _popup_file_dialog ) . bind ( load_dialog ) ) ;
2024-01-09 12:34:24 +00:00
task_tree - > connect ( " rmb_pressed " , callable_mp ( this , & LimboAIEditor : : _on_tree_rmb ) ) ;
task_tree - > connect ( " task_selected " , callable_mp ( this , & LimboAIEditor : : _on_tree_task_selected ) ) ;
task_tree - > connect ( " task_dragged " , callable_mp ( this , & LimboAIEditor : : _on_task_dragged ) ) ;
task_tree - > connect ( " task_activated " , callable_mp ( this , & LimboAIEditor : : _action_selected ) . bind ( ACTION_RENAME ) ) ;
task_tree - > connect ( " probability_clicked " , callable_mp ( this , & LimboAIEditor : : _action_selected ) . bind ( ACTION_EDIT_PROBABILITY ) ) ;
task_tree - > connect ( " visibility_changed " , callable_mp ( this , & LimboAIEditor : : _on_visibility_changed ) ) ;
task_tree - > connect ( " visibility_changed " , callable_mp ( this , & LimboAIEditor : : _update_banners ) ) ;
2024-01-09 12:42:54 +00:00
save_btn - > connect ( LW_NAME ( pressed ) , callable_mp ( this , & LimboAIEditor : : _on_save_pressed ) ) ;
misc_btn - > connect ( LW_NAME ( pressed ) , callable_mp ( this , & LimboAIEditor : : _update_misc_menu ) ) ;
2024-01-09 12:34:24 +00:00
misc_btn - > get_popup ( ) - > connect ( " id_pressed " , callable_mp ( this , & LimboAIEditor : : _misc_option_selected ) ) ;
2024-01-09 12:42:54 +00:00
history_back - > connect ( LW_NAME ( pressed ) , callable_mp ( this , & LimboAIEditor : : _on_history_back ) ) ;
history_forward - > connect ( LW_NAME ( pressed ) , callable_mp ( this , & LimboAIEditor : : _on_history_forward ) ) ;
header - > connect ( LW_NAME ( pressed ) , callable_mp ( this , & LimboAIEditor : : _on_header_pressed ) ) ;
2024-01-09 12:34:24 +00:00
task_palette - > connect ( " task_selected " , callable_mp ( this , & LimboAIEditor : : _add_task_by_class_or_path ) ) ;
task_palette - > connect ( " favorite_tasks_changed " , callable_mp ( this , & LimboAIEditor : : _update_favorite_tasks ) ) ;
change_type_palette - > connect ( " task_selected " , callable_mp ( this , & LimboAIEditor : : _task_type_selected ) ) ;
menu - > connect ( " id_pressed " , callable_mp ( this , & LimboAIEditor : : _action_selected ) ) ;
2024-01-09 12:42:54 +00:00
weight_mode - > connect ( LW_NAME ( pressed ) , callable_mp ( this , & LimboAIEditor : : _update_probability_edit ) ) ;
percent_mode - > connect ( LW_NAME ( pressed ) , callable_mp ( this , & LimboAIEditor : : _update_probability_edit ) ) ;
2024-01-09 12:34:24 +00:00
probability_edit - > connect ( " value_changed " , callable_mp ( this , & LimboAIEditor : : _on_probability_edited ) ) ;
probability_popup - > connect ( " popup_hide " , callable_mp ( this , & LimboAIEditor : : _probability_popup_closed ) ) ;
disk_changed - > connect ( " confirmed " , callable_mp ( this , & LimboAIEditor : : _reload_modified ) ) ;
disk_changed - > connect ( " custom_action " , callable_mp ( this , & LimboAIEditor : : _resave_modified ) ) ;
rename_dialog - > connect ( " confirmed " , callable_mp ( this , & LimboAIEditor : : _rename_task_confirmed ) ) ;
2024-01-09 12:42:54 +00:00
new_script_btn - > connect ( LW_NAME ( pressed ) , callable_mp ( SCRIPT_EDITOR ( ) , & ScriptEditor : : open_script_create_dialog ) . bind ( " BTAction " , String ( GLOBAL_GET ( " limbo_ai/behavior_tree/user_task_dir_1 " ) ) . path_join ( " new_task " ) ) ) ;
2024-01-09 12:34:24 +00:00
EDITOR_FILE_SYSTEM ( ) - > connect ( " resources_reload " , callable_mp ( this , & LimboAIEditor : : _on_resources_reload ) ) ;
2024-01-09 23:02:24 +00:00
_update_history_buttons ( ) ;
_update_header ( ) ;
2024-01-09 12:34:24 +00:00
} break ;
2023-08-16 09:19:51 +00:00
case NOTIFICATION_THEME_CHANGED : {
2024-01-09 12:34:24 +00:00
_do_update_theme_item_cache ( ) ;
2024-01-09 12:42:54 +00:00
BUTTON_SET_ICON ( new_btn , get_theme_icon ( LW_NAME ( New ) , LW_NAME ( EditorIcons ) ) ) ;
BUTTON_SET_ICON ( load_btn , get_theme_icon ( LW_NAME ( Load ) , LW_NAME ( EditorIcons ) ) ) ;
BUTTON_SET_ICON ( save_btn , get_theme_icon ( LW_NAME ( Save ) , LW_NAME ( EditorIcons ) ) ) ;
BUTTON_SET_ICON ( new_script_btn , get_theme_icon ( LW_NAME ( ScriptCreate ) , LW_NAME ( EditorIcons ) ) ) ;
BUTTON_SET_ICON ( history_back , get_theme_icon ( LW_NAME ( Back ) , LW_NAME ( EditorIcons ) ) ) ;
BUTTON_SET_ICON ( history_forward , get_theme_icon ( LW_NAME ( Forward ) , LW_NAME ( EditorIcons ) ) ) ;
BUTTON_SET_ICON ( misc_btn , get_theme_icon ( LW_NAME ( Tools ) , LW_NAME ( EditorIcons ) ) ) ;
2023-08-20 09:34:13 +00:00
2023-08-18 10:12:55 +00:00
_update_favorite_tasks ( ) ;
2023-08-16 09:19:51 +00:00
_update_header ( ) ;
}
2022-09-06 11:28:25 +00:00
}
}
2022-09-01 22:20:37 +00:00
void LimboAIEditor : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " _add_task " , " p_task " ) , & LimboAIEditor : : _add_task ) ;
2022-12-22 12:19:39 +00:00
ClassDB : : bind_method ( D_METHOD ( " _remove_task " , " p_task " ) , & LimboAIEditor : : _remove_task ) ;
2022-09-03 12:11:47 +00:00
ClassDB : : bind_method ( D_METHOD ( " _add_task_with_prototype " , " p_prototype " ) , & LimboAIEditor : : _add_task_with_prototype ) ;
2022-09-01 22:20:37 +00:00
ClassDB : : bind_method ( D_METHOD ( " _new_bt " ) , & LimboAIEditor : : _new_bt ) ;
ClassDB : : bind_method ( D_METHOD ( " _save_bt " , " p_path " ) , & LimboAIEditor : : _save_bt ) ;
ClassDB : : bind_method ( D_METHOD ( " _load_bt " , " p_path " ) , & LimboAIEditor : : _load_bt ) ;
2022-11-22 20:00:08 +00:00
ClassDB : : bind_method ( D_METHOD ( " edit_bt " , " p_behavior_tree " , " p_force_refresh " ) , & LimboAIEditor : : edit_bt , Variant ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " _reload_modified " ) , & LimboAIEditor : : _reload_modified ) ;
ClassDB : : bind_method ( D_METHOD ( " _resave_modified " ) , & LimboAIEditor : : _resave_modified ) ;
2023-12-14 22:18:44 +00:00
ClassDB : : bind_method ( D_METHOD ( " _replace_task " , " p_task " , " p_by_task " ) , & LimboAIEditor : : _replace_task ) ;
2024-01-09 12:34:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " _popup_file_dialog " ) , & LimboAIEditor : : _popup_file_dialog ) ;
2022-09-01 22:20:37 +00:00
}
2022-12-15 07:26:52 +00:00
LimboAIEditor : : LimboAIEditor ( ) {
idx_history = 0 ;
2022-09-01 22:20:37 +00:00
2024-01-09 12:34:24 +00:00
LW_SHORTCUT ( " limbo_ai/rename_task " , TTR ( " Rename " ) , LW_KEY ( F2 ) ) ;
// Todo: Add override support for shortcuts.
// LW_SHORTCUT_OVERRIDE("limbo_ai/rename_task", "macos", Key::ENTER);
LW_SHORTCUT ( " limbo_ai/move_task_up " , TTR ( " Move Up " ) , ( Key ) ( LW_KEY_MASK ( CMD_OR_CTRL ) | LW_KEY ( UP ) ) ) ;
LW_SHORTCUT ( " limbo_ai/move_task_down " , TTR ( " Move Down " ) , ( Key ) ( LW_KEY_MASK ( CMD_OR_CTRL ) | LW_KEY ( DOWN ) ) ) ;
LW_SHORTCUT ( " limbo_ai/duplicate_task " , TTR ( " Duplicate " ) , ( Key ) ( LW_KEY_MASK ( CMD_OR_CTRL ) | LW_KEY ( D ) ) ) ;
LW_SHORTCUT ( " limbo_ai/remove_task " , TTR ( " Remove " ) , Key : : KEY_DELETE ) ;
2023-08-16 14:07:04 +00:00
2024-01-09 12:34:24 +00:00
LW_SHORTCUT ( " limbo_ai/new_behavior_tree " , TTR ( " New Behavior Tree " ) , ( Key ) ( LW_KEY_MASK ( CMD_OR_CTRL ) | LW_KEY_MASK ( ALT ) | LW_KEY ( N ) ) ) ;
LW_SHORTCUT ( " limbo_ai/save_behavior_tree " , TTR ( " Save Behavior Tree " ) , ( Key ) ( LW_KEY_MASK ( CMD_OR_CTRL ) | LW_KEY_MASK ( ALT ) | LW_KEY ( S ) ) ) ;
LW_SHORTCUT ( " limbo_ai/load_behavior_tree " , TTR ( " Load Behavior Tree " ) , ( Key ) ( LW_KEY_MASK ( CMD_OR_CTRL ) | LW_KEY_MASK ( ALT ) | LW_KEY ( L ) ) ) ;
LW_SHORTCUT ( " limbo_ai/open_debugger " , TTR ( " Open Debugger " ) , ( Key ) ( LW_KEY_MASK ( CMD_OR_CTRL ) | LW_KEY_MASK ( ALT ) | LW_KEY ( D ) ) ) ;
2023-08-16 14:07:04 +00:00
set_process_shortcut_input ( true ) ;
2022-09-01 22:20:37 +00:00
save_dialog = memnew ( FileDialog ) ;
2022-12-15 07:26:52 +00:00
save_dialog - > set_file_mode ( FileDialog : : FILE_MODE_SAVE_FILE ) ;
2023-12-17 14:24:38 +00:00
save_dialog - > set_title ( TTR ( " Save Behavior Tree " ) ) ;
2022-09-01 22:20:37 +00:00
save_dialog - > add_filter ( " *.tres " ) ;
save_dialog - > hide ( ) ;
2023-08-16 09:19:51 +00:00
add_child ( save_dialog ) ;
2022-09-01 22:20:37 +00:00
load_dialog = memnew ( FileDialog ) ;
2022-12-15 07:26:52 +00:00
load_dialog - > set_file_mode ( FileDialog : : FILE_MODE_OPEN_FILE ) ;
2023-12-17 14:24:38 +00:00
load_dialog - > set_title ( TTR ( " Load Behavior Tree " ) ) ;
2022-09-01 22:20:37 +00:00
load_dialog - > add_filter ( " *.tres " ) ;
load_dialog - > hide ( ) ;
2023-08-16 09:19:51 +00:00
add_child ( load_dialog ) ;
2022-09-01 22:20:37 +00:00
2023-12-17 14:24:38 +00:00
extract_dialog = memnew ( FileDialog ) ;
extract_dialog - > set_file_mode ( FileDialog : : FILE_MODE_SAVE_FILE ) ;
extract_dialog - > set_title ( TTR ( " Save Extracted Tree " ) ) ;
extract_dialog - > add_filter ( " *.tres " ) ;
extract_dialog - > hide ( ) ;
add_child ( extract_dialog ) ;
2023-08-22 10:20:09 +00:00
vbox = memnew ( VBoxContainer ) ;
vbox - > set_anchor ( SIDE_RIGHT , ANCHOR_END ) ;
vbox - > set_anchor ( SIDE_BOTTOM , ANCHOR_END ) ;
add_child ( vbox ) ;
2022-09-01 22:20:37 +00:00
2023-08-18 10:12:55 +00:00
HBoxContainer * toolbar = memnew ( HBoxContainer ) ;
2023-08-22 10:20:09 +00:00
vbox - > add_child ( toolbar ) ;
2023-08-18 10:12:55 +00:00
2023-08-22 12:43:45 +00:00
PackedStringArray favorite_tasks_default ;
2023-08-18 10:12:55 +00:00
favorite_tasks_default . append ( " BTSelector " ) ;
favorite_tasks_default . append ( " BTSequence " ) ;
2023-08-28 11:23:25 +00:00
favorite_tasks_default . append ( " BTComment " ) ;
2023-08-22 12:43:45 +00:00
GLOBAL_DEF ( PropertyInfo ( Variant : : PACKED_STRING_ARRAY , " limbo_ai/behavior_tree/favorite_tasks " , PROPERTY_HINT_ARRAY_TYPE , " String " ) , favorite_tasks_default ) ;
2023-08-18 10:12:55 +00:00
fav_tasks_hbox = memnew ( HBoxContainer ) ;
toolbar - > add_child ( fav_tasks_hbox ) ;
toolbar - > add_child ( memnew ( VSeparator ) ) ;
2022-09-01 22:20:37 +00:00
2023-08-16 09:19:51 +00:00
new_btn = memnew ( Button ) ;
2022-09-01 22:20:37 +00:00
new_btn - > set_text ( TTR ( " New " ) ) ;
2023-08-16 14:07:04 +00:00
new_btn - > set_tooltip_text ( TTR ( " Create a new behavior tree. " ) ) ;
2024-01-09 12:34:24 +00:00
new_btn - > set_shortcut ( LW_GET_SHORTCUT ( " limbo_ai/new_behavior_tree " ) ) ;
2022-09-01 22:20:37 +00:00
new_btn - > set_flat ( true ) ;
new_btn - > set_focus_mode ( Control : : FOCUS_NONE ) ;
2023-08-18 10:12:55 +00:00
toolbar - > add_child ( new_btn ) ;
2022-09-01 22:20:37 +00:00
2023-08-16 09:19:51 +00:00
load_btn = memnew ( Button ) ;
2022-09-01 22:20:37 +00:00
load_btn - > set_text ( TTR ( " Load " ) ) ;
2023-08-16 14:07:04 +00:00
load_btn - > set_tooltip_text ( TTR ( " Load behavior tree from a resource file. " ) ) ;
2024-01-09 12:34:24 +00:00
load_btn - > set_shortcut ( LW_GET_SHORTCUT ( " limbo_ai/load_behavior_tree " ) ) ;
2022-09-01 22:20:37 +00:00
load_btn - > set_flat ( true ) ;
load_btn - > set_focus_mode ( Control : : FOCUS_NONE ) ;
2023-08-18 10:12:55 +00:00
toolbar - > add_child ( load_btn ) ;
2022-09-01 22:20:37 +00:00
2023-08-16 09:19:51 +00:00
save_btn = memnew ( Button ) ;
2022-09-01 22:20:37 +00:00
save_btn - > set_text ( TTR ( " Save " ) ) ;
2023-08-16 14:07:04 +00:00
save_btn - > set_tooltip_text ( TTR ( " Save edited behavior tree to a resource file. " ) ) ;
2024-01-09 12:34:24 +00:00
save_btn - > set_shortcut ( LW_GET_SHORTCUT ( " limbo_ai/save_behavior_tree " ) ) ;
2022-09-01 22:20:37 +00:00
save_btn - > set_flat ( true ) ;
save_btn - > set_focus_mode ( Control : : FOCUS_NONE ) ;
2023-08-18 10:12:55 +00:00
toolbar - > add_child ( save_btn ) ;
2022-09-01 22:20:37 +00:00
2023-08-18 10:12:55 +00:00
toolbar - > add_child ( memnew ( VSeparator ) ) ;
2022-09-01 22:20:37 +00:00
2023-08-16 09:19:51 +00:00
new_script_btn = memnew ( Button ) ;
2022-09-05 11:31:38 +00:00
new_script_btn - > set_text ( TTR ( " New Task " ) ) ;
2022-12-15 07:26:52 +00:00
new_script_btn - > set_tooltip_text ( TTR ( " Create new task script and edit it. " ) ) ;
2022-09-05 11:31:38 +00:00
new_script_btn - > set_flat ( true ) ;
new_script_btn - > set_focus_mode ( Control : : FOCUS_NONE ) ;
2023-08-18 10:12:55 +00:00
toolbar - > add_child ( new_script_btn ) ;
2022-09-05 11:31:38 +00:00
2023-08-20 09:34:13 +00:00
misc_btn = memnew ( MenuButton ) ;
misc_btn - > set_text ( TTR ( " Misc " ) ) ;
misc_btn - > set_flat ( true ) ;
toolbar - > add_child ( misc_btn ) ;
2022-09-02 13:43:54 +00:00
HBoxContainer * nav = memnew ( HBoxContainer ) ;
nav - > set_h_size_flags ( SIZE_EXPAND | SIZE_SHRINK_END ) ;
2023-08-18 10:12:55 +00:00
toolbar - > add_child ( nav ) ;
2022-09-02 13:43:54 +00:00
history_back = memnew ( Button ) ;
history_back - > set_flat ( true ) ;
history_back - > set_focus_mode ( FOCUS_NONE ) ;
nav - > add_child ( history_back ) ;
history_forward = memnew ( Button ) ;
history_forward - > set_flat ( true ) ;
history_forward - > set_focus_mode ( FOCUS_NONE ) ;
nav - > add_child ( history_forward ) ;
2022-09-01 22:20:37 +00:00
header = memnew ( Button ) ;
2022-12-15 07:26:52 +00:00
header - > set_text_alignment ( HORIZONTAL_ALIGNMENT_LEFT ) ;
header - > add_theme_constant_override ( " hseparation " , 8 ) ;
2023-08-22 10:20:09 +00:00
vbox - > add_child ( header ) ;
2022-09-01 22:20:37 +00:00
2022-09-06 11:28:25 +00:00
hsc = memnew ( HSplitContainer ) ;
2022-09-02 12:25:03 +00:00
hsc - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
hsc - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2023-08-16 14:07:04 +00:00
hsc - > set_focus_mode ( FOCUS_NONE ) ;
2023-08-22 10:20:09 +00:00
vbox - > add_child ( hsc ) ;
2022-09-02 12:25:03 +00:00
2022-09-01 22:20:37 +00:00
task_tree = memnew ( TaskTree ) ;
task_tree - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
task_tree - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2023-08-21 16:17:34 +00:00
task_tree - > hide ( ) ;
2023-08-16 09:19:51 +00:00
hsc - > add_child ( task_tree ) ;
2022-09-05 19:57:24 +00:00
usage_hint = memnew ( Panel ) ;
usage_hint - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
usage_hint - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
hsc - > add_child ( usage_hint ) ;
2023-08-16 09:19:51 +00:00
2022-09-05 19:57:24 +00:00
Label * usage_label = memnew ( Label ) ;
2022-12-15 07:26:52 +00:00
usage_label - > set_anchor ( SIDE_RIGHT , 1 ) ;
usage_label - > set_anchor ( SIDE_BOTTOM , 1 ) ;
usage_label - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
usage_label - > set_vertical_alignment ( VERTICAL_ALIGNMENT_CENTER ) ;
2022-09-05 19:57:24 +00:00
usage_label - > set_text ( TTR ( " Create a new or load an existing behavior tree. " ) ) ;
usage_hint - > add_child ( usage_label ) ;
2022-09-02 12:25:03 +00:00
2023-08-26 08:08:01 +00:00
task_palette = memnew ( TaskPalette ( ) ) ;
2022-09-02 13:43:54 +00:00
hsc - > set_split_offset ( - 300 ) ;
2023-08-26 08:08:01 +00:00
task_palette - > hide ( ) ;
hsc - > add_child ( task_palette ) ;
2022-09-01 22:20:37 +00:00
2023-12-14 22:18:44 +00:00
change_type_popup = memnew ( PopupPanel ) ;
add_child ( change_type_popup ) ;
2023-12-14 22:51:48 +00:00
{
VBoxContainer * change_type_vbox = memnew ( VBoxContainer ) ;
change_type_popup - > add_child ( change_type_vbox ) ;
Label * change_type_title = memnew ( Label ) ;
change_type_vbox - > add_child ( change_type_title ) ;
change_type_title - > set_theme_type_variation ( " HeaderSmall " ) ;
change_type_title - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
change_type_title - > set_text ( TTR ( " Choose New Type " ) ) ;
change_type_palette = memnew ( TaskPalette ) ;
change_type_vbox - > add_child ( change_type_palette ) ;
change_type_palette - > use_dialog_mode ( ) ;
change_type_palette - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
}
2023-12-14 22:18:44 +00:00
2023-08-22 10:20:09 +00:00
banners = memnew ( VBoxContainer ) ;
vbox - > add_child ( banners ) ;
2023-08-21 16:17:34 +00:00
2022-09-01 22:20:37 +00:00
menu = memnew ( PopupMenu ) ;
add_child ( menu ) ;
2023-09-25 16:07:26 +00:00
probability_popup = memnew ( PopupPanel ) ;
{
VBoxContainer * vbc = memnew ( VBoxContainer ) ;
probability_popup - > add_child ( vbc ) ;
2023-09-25 20:36:37 +00:00
PanelContainer * mode_panel = memnew ( PanelContainer ) ;
vbc - > add_child ( mode_panel ) ;
HBoxContainer * mode_hbox = memnew ( HBoxContainer ) ;
mode_panel - > add_child ( mode_hbox ) ;
Ref < ButtonGroup > button_group ;
button_group . instantiate ( ) ;
weight_mode = memnew ( Button ) ;
mode_hbox - > add_child ( weight_mode ) ;
weight_mode - > set_toggle_mode ( true ) ;
weight_mode - > set_button_group ( button_group ) ;
weight_mode - > set_focus_mode ( Control : : FOCUS_NONE ) ;
weight_mode - > set_text ( TTR ( " Weight " ) ) ;
weight_mode - > set_tooltip_text ( TTR ( " Edit weight " ) ) ;
weight_mode - > set_pressed_no_signal ( true ) ;
percent_mode = memnew ( Button ) ;
mode_hbox - > add_child ( percent_mode ) ;
percent_mode - > set_toggle_mode ( true ) ;
percent_mode - > set_button_group ( button_group ) ;
percent_mode - > set_focus_mode ( Control : : FOCUS_NONE ) ;
percent_mode - > set_text ( TTR ( " Percent " ) ) ;
percent_mode - > set_tooltip_text ( TTR ( " Edit percent " ) ) ;
2023-09-25 16:07:26 +00:00
probability_edit = memnew ( EditorSpinSlider ) ;
vbc - > add_child ( probability_edit ) ;
probability_edit - > set_min ( 0.0 ) ;
probability_edit - > set_max ( 10.0 ) ;
probability_edit - > set_step ( 0.01 ) ;
probability_edit - > set_allow_greater ( true ) ;
probability_edit - > set_custom_minimum_size ( Size2 ( 200.0 * EDSCALE , 0.0 ) ) ;
}
add_child ( probability_popup ) ;
2022-11-23 15:25:32 +00:00
rename_dialog = memnew ( ConfirmationDialog ) ;
{
VBoxContainer * vbc = memnew ( VBoxContainer ) ;
rename_dialog - > add_child ( vbc ) ;
rename_edit = memnew ( LineEdit ) ;
vbc - > add_child ( rename_edit ) ;
rename_edit - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
rename_edit - > set_custom_minimum_size ( Size2 ( 350.0 , 0.0 ) ) ;
2022-12-17 12:39:37 +00:00
rename_dialog - > register_text_enter ( rename_edit ) ;
2022-11-23 15:25:32 +00:00
}
add_child ( rename_dialog ) ;
2022-11-22 20:00:08 +00:00
disk_changed = memnew ( ConfirmationDialog ) ;
{
VBoxContainer * vbc = memnew ( VBoxContainer ) ;
disk_changed - > add_child ( vbc ) ;
Label * dl = memnew ( Label ) ;
dl - > set_text ( TTR ( " The following BehaviorTree resources are newer on disk. \n What action should be taken? " ) ) ;
vbc - > add_child ( dl ) ;
disk_changed_list = memnew ( Tree ) ;
vbc - > add_child ( disk_changed_list ) ;
disk_changed_list - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2022-12-15 07:26:52 +00:00
disk_changed - > get_ok_button ( ) - > set_text ( TTR ( " Reload " ) ) ;
disk_changed - > add_button ( TTR ( " Resave " ) , ! DisplayServer : : get_singleton ( ) - > get_swap_cancel_ok ( ) , " resave " ) ;
2022-11-22 20:00:08 +00:00
}
2024-01-09 12:34:24 +00:00
BASE_CONTROL ( ) - > add_child ( disk_changed ) ;
2022-11-22 20:00:08 +00:00
2023-03-02 14:41:01 +00:00
GLOBAL_DEF ( PropertyInfo ( Variant : : STRING , " limbo_ai/behavior_tree/behavior_tree_default_dir " , PROPERTY_HINT_DIR ) , " res://ai/trees " ) ;
GLOBAL_DEF ( PropertyInfo ( Variant : : STRING , " limbo_ai/behavior_tree/user_task_dir_1 " , PROPERTY_HINT_DIR ) , " res://ai/tasks " ) ;
GLOBAL_DEF ( PropertyInfo ( Variant : : STRING , " limbo_ai/behavior_tree/user_task_dir_2 " , PROPERTY_HINT_DIR ) , " " ) ;
GLOBAL_DEF ( PropertyInfo ( Variant : : STRING , " limbo_ai/behavior_tree/user_task_dir_3 " , PROPERTY_HINT_DIR ) , " " ) ;
2022-09-05 11:11:47 +00:00
2023-12-17 14:24:38 +00:00
String bt_default_dir = GLOBAL_GET ( " limbo_ai/behavior_tree/behavior_tree_default_dir " ) ;
save_dialog - > set_current_dir ( bt_default_dir ) ;
load_dialog - > set_current_dir ( bt_default_dir ) ;
extract_dialog - > set_current_dir ( bt_default_dir ) ;
2022-09-01 22:20:37 +00:00
}
LimboAIEditor : : ~ LimboAIEditor ( ) {
}
2023-08-16 09:19:51 +00:00
//**** LimboAIEditor ^
2022-09-03 15:00:20 +00:00
2023-08-16 09:19:51 +00:00
//**** LimboAIEditorPlugin
2022-09-01 22:20:37 +00:00
2024-01-09 12:34:24 +00:00
# ifdef LIMBOAI_MODULE
2022-09-03 12:01:13 +00:00
void LimboAIEditorPlugin : : apply_changes ( ) {
2024-01-09 12:34:24 +00:00
# else // LIMBOAI_MODULE
void LimboAIEditorPlugin : : _apply_changes ( ) {
# endif
2022-09-03 12:01:13 +00:00
limbo_ai_editor - > apply_changes ( ) ;
}
2024-01-09 20:47:22 +00:00
void LimboAIEditorPlugin : : _bind_methods ( ) {
}
2022-09-01 22:20:37 +00:00
void LimboAIEditorPlugin : : _notification ( int p_notification ) {
2024-01-09 20:47:22 +00:00
switch ( p_notification ) {
case NOTIFICATION_READY : {
add_debugger_plugin ( memnew ( LimboDebuggerPlugin ) ) ;
} break ;
case NOTIFICATION_ENTER_TREE : {
// Add BehaviorTree to the list of resources that should open in a new inspector.
PackedStringArray open_in_new_inspector = EDITOR_GET ( " interface/inspector/resources_to_open_in_new_inspector " ) ;
if ( ! open_in_new_inspector . has ( " BehaviorTree " ) ) {
open_in_new_inspector . push_back ( " BehaviorTree " ) ;
EDITOR_SETTINGS ( ) - > set_setting ( " interface/inspector/resources_to_open_in_new_inspector " , open_in_new_inspector ) ;
}
} break ;
2023-12-18 14:49:20 +00:00
}
2022-09-01 22:20:37 +00:00
}
2024-01-09 12:34:24 +00:00
# ifdef LIMBOAI_MODULE
2022-09-01 22:20:37 +00:00
void LimboAIEditorPlugin : : make_visible ( bool p_visible ) {
2024-01-09 12:34:24 +00:00
# else // LIMBOAI_GDEXTENSION
void LimboAIEditorPlugin : : _make_visible ( bool p_visible ) {
# endif
2022-09-01 22:20:37 +00:00
limbo_ai_editor - > set_visible ( p_visible ) ;
}
2024-01-09 12:34:24 +00:00
# ifdef LIMBOAI_MODULE
2022-09-05 19:57:24 +00:00
void LimboAIEditorPlugin : : edit ( Object * p_object ) {
2024-01-09 12:34:24 +00:00
# else // LIMBOAI_GDEXTENSION
void LimboAIEditorPlugin : : _edit ( Object * p_object ) {
# endif
2022-09-05 19:57:24 +00:00
if ( Object : : cast_to < BehaviorTree > ( p_object ) ) {
limbo_ai_editor - > edit_bt ( Object : : cast_to < BehaviorTree > ( p_object ) ) ;
}
}
2024-01-09 12:34:24 +00:00
# ifdef LIMBOAI_MODULE
2022-09-05 19:57:24 +00:00
bool LimboAIEditorPlugin : : handles ( Object * p_object ) const {
2024-01-09 12:34:24 +00:00
# else // LIMBOAI_GDEXTENSION
bool LimboAIEditorPlugin : : _handles ( Object * p_object ) const {
# endif
2022-12-15 17:29:22 +00:00
if ( Object : : cast_to < BehaviorTree > ( p_object ) ) {
return true ;
}
2022-12-15 18:14:36 +00:00
return false ;
2022-09-05 19:57:24 +00:00
}
2024-01-10 00:17:09 +00:00
# ifdef LIMBOAI_GDEXTENSION
Ref < Texture2D > LimboAIEditorPlugin : : _get_plugin_icon ( ) const {
return LimboUtility : : get_singleton ( ) - > get_task_icon ( " LimboAI " ) ;
}
# endif // LIMBOAI_GDEXTENSION
2022-12-15 07:26:52 +00:00
LimboAIEditorPlugin : : LimboAIEditorPlugin ( ) {
limbo_ai_editor = memnew ( LimboAIEditor ( ) ) ;
2022-09-01 22:20:37 +00:00
limbo_ai_editor - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2024-01-09 12:34:24 +00:00
MAIN_SCREEN_CONTROL ( ) - > add_child ( limbo_ai_editor ) ;
2022-09-01 22:20:37 +00:00
limbo_ai_editor - > hide ( ) ;
2024-01-09 12:34:24 +00:00
limbo_ai_editor - > set_plugin ( this ) ;
# ifdef LIMBOAI_MODULE
// ! Only used in the module version.
2023-12-08 20:56:14 +00:00
add_inspector_plugin ( memnew ( EditorInspectorPluginBBParam ) ) ;
2024-01-09 12:34:24 +00:00
# endif // LIMBOAI_MODULE
2022-09-01 22:20:37 +00:00
}
LimboAIEditorPlugin : : ~ LimboAIEditorPlugin ( ) {
}
2024-01-11 10:22:02 +00:00
# endif // ! TOOLS_ENABLED