Compare commits
9 Commits
bae9ff8a30
...
dc810d9a75
Author | SHA1 | Date |
---|---|---|
Legendsmith | dc810d9a75 | |
Serhii Snitsaruk | d304f957ef | |
Serhii Snitsaruk | bf85350260 | |
Serhii Snitsaruk | 03476721d9 | |
Serhii Snitsaruk | bebd6a15eb | |
Serhii Snitsaruk | 4c9028fc66 | |
Serhii Snitsaruk | e21156df35 | |
Serhii Snitsaruk | 591a1fe672 | |
Legendsmith | bbdafa9033 |
|
@ -35,6 +35,7 @@
|
||||||
#include "editor/editor_file_system.h"
|
#include "editor/editor_file_system.h"
|
||||||
#include "editor/editor_help.h"
|
#include "editor/editor_help.h"
|
||||||
#include "editor/editor_interface.h"
|
#include "editor/editor_interface.h"
|
||||||
|
#include "editor/editor_main_screen.h"
|
||||||
#include "editor/editor_paths.h"
|
#include "editor/editor_paths.h"
|
||||||
#include "editor/editor_settings.h"
|
#include "editor/editor_settings.h"
|
||||||
#include "editor/filesystem_dock.h"
|
#include "editor/filesystem_dock.h"
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
#include <godot_cpp/classes/ref_counted.hpp>
|
#include <godot_cpp/classes/ref_counted.hpp>
|
||||||
#include <godot_cpp/classes/resource_loader.hpp>
|
#include <godot_cpp/classes/resource_loader.hpp>
|
||||||
#include <godot_cpp/classes/resource_saver.hpp>
|
#include <godot_cpp/classes/resource_saver.hpp>
|
||||||
|
#include <godot_cpp/classes/scene_tree.hpp>
|
||||||
#include <godot_cpp/classes/script.hpp>
|
#include <godot_cpp/classes/script.hpp>
|
||||||
#include <godot_cpp/classes/script_editor.hpp>
|
#include <godot_cpp/classes/script_editor.hpp>
|
||||||
#include <godot_cpp/classes/script_editor_base.hpp>
|
#include <godot_cpp/classes/script_editor_base.hpp>
|
||||||
|
@ -73,6 +75,21 @@
|
||||||
#include <godot_cpp/core/error_macros.hpp>
|
#include <godot_cpp/core/error_macros.hpp>
|
||||||
#endif // LIMBOAI_GDEXTENSION
|
#endif // LIMBOAI_GDEXTENSION
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// If built-in resource - switch to the owner scene (open it if not already).
|
||||||
|
inline void _switch_to_owner_scene_if_builtin(const Ref<BehaviorTree> &p_behavior_tree) {
|
||||||
|
if (p_behavior_tree.is_valid() && p_behavior_tree->get_path().contains("::")) {
|
||||||
|
String current_scene = SCENE_TREE()->get_edited_scene_root()->get_scene_file_path();
|
||||||
|
String scene_path = p_behavior_tree->get_path().get_slice("::", 0);
|
||||||
|
if (current_scene != scene_path) {
|
||||||
|
EditorInterface::get_singleton()->open_scene_from_path(scene_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
//**** LimboAIEditor
|
//**** LimboAIEditor
|
||||||
|
|
||||||
_FORCE_INLINE_ String _get_script_template_path() {
|
_FORCE_INLINE_ String _get_script_template_path() {
|
||||||
|
@ -97,7 +114,7 @@ void LimboAIEditor::_commit_action_with_update(EditorUndoRedoManager *p_undo_red
|
||||||
p_undo_redo->add_do_method(this, LW_NAME(_update_task_tree), task_tree->get_bt());
|
p_undo_redo->add_do_method(this, LW_NAME(_update_task_tree), task_tree->get_bt());
|
||||||
p_undo_redo->add_undo_method(this, LW_NAME(_update_task_tree), task_tree->get_bt());
|
p_undo_redo->add_undo_method(this, LW_NAME(_update_task_tree), task_tree->get_bt());
|
||||||
p_undo_redo->commit_action();
|
p_undo_redo->commit_action();
|
||||||
_mark_as_dirty(true);
|
_set_as_dirty(task_tree->get_bt(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboAIEditor::_add_task(const Ref<BTTask> &p_task, bool p_as_sibling) {
|
void LimboAIEditor::_add_task(const Ref<BTTask> &p_task, bool p_as_sibling) {
|
||||||
|
@ -201,20 +218,58 @@ void LimboAIEditor::_new_bt() {
|
||||||
EDIT_RESOURCE(bt);
|
EDIT_RESOURCE(bt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboAIEditor::_save_bt(String p_path) {
|
void LimboAIEditor::_save_bt(const Ref<BehaviorTree> &p_bt, const String &p_path) {
|
||||||
ERR_FAIL_COND_MSG(p_path.is_empty(), "Empty p_path");
|
ERR_FAIL_COND(p_path.is_empty());
|
||||||
ERR_FAIL_COND_MSG(task_tree->get_bt().is_null(), "Behavior Tree is null.");
|
ERR_FAIL_COND(!p_path.begins_with("res://"));
|
||||||
|
ERR_FAIL_COND(p_bt.is_null());
|
||||||
|
|
||||||
|
if (p_bt->get_path() != p_path) {
|
||||||
#ifdef LIMBOAI_MODULE
|
#ifdef LIMBOAI_MODULE
|
||||||
task_tree->get_bt()->set_path(p_path, true);
|
task_tree->get_bt()->set_path(p_path, true);
|
||||||
#elif LIMBOAI_GDEXTENSION
|
#elif LIMBOAI_GDEXTENSION
|
||||||
task_tree->get_bt()->take_over_path(p_path);
|
task_tree->get_bt()->take_over_path(p_path);
|
||||||
#endif
|
#endif
|
||||||
RESOURCE_SAVE(task_tree->get_bt(), p_path, ResourceSaver::FLAG_CHANGE_PATH);
|
}
|
||||||
|
|
||||||
|
// This is a workaround, because EditorNode::save_resource() function is not accessible in GDExtension.
|
||||||
|
if (RESOURCE_IS_BUILT_IN(p_bt)) {
|
||||||
|
// If built-in resource - save the containing resource instead.
|
||||||
|
String file_path = p_path.get_slice("::", 0);
|
||||||
|
ERR_FAIL_COND_MSG(!RESOURCE_EXISTS(file_path, "Resource"), "LimboAI: SAVE FAILED - resource file doesn't exist: " + file_path);
|
||||||
|
if (RESOURCE_IS_SCENE_FILE(file_path)) {
|
||||||
|
// Packed scene - save the scene instead.
|
||||||
|
if (EditorInterface::get_singleton()->get_open_scenes().has(file_path)) {
|
||||||
|
// If scene is open, switch to it first, and then ask to save.
|
||||||
|
// This is needed because saving the currently edited scene can have complications.
|
||||||
|
EditorInterface::get_singleton()->open_scene_from_path(file_path);
|
||||||
|
EditorInterface::get_singleton()->save_scene();
|
||||||
|
} else {
|
||||||
|
// If scene is not currently open in the editor, load and resave it.
|
||||||
|
Ref<Resource> scene = RESOURCE_LOAD(file_path, "PackedScene");
|
||||||
|
RESOURCE_SAVE(scene, file_path, ResourceSaver::FLAG_NONE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not a packed scene - save the containing resource to file.
|
||||||
|
Ref<Resource> res = RESOURCE_LOAD(file_path, "Resource");
|
||||||
|
RESOURCE_SAVE(res, file_path, ResourceSaver::FLAG_NONE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If external resource - save to file.
|
||||||
|
RESOURCE_SAVE(p_bt, p_path, ResourceSaver::FLAG_CHANGE_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
_set_as_dirty(p_bt, false);
|
||||||
_update_tabs();
|
_update_tabs();
|
||||||
_mark_as_dirty(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboAIEditor::_load_bt(String p_path) {
|
void LimboAIEditor::_save_current_bt(const String &p_path) {
|
||||||
|
ERR_FAIL_COND_MSG(p_path.is_empty(), "LimboAI: SAVE FAILED - p_path is empty");
|
||||||
|
ERR_FAIL_COND_MSG(task_tree->get_bt().is_null(), "LimboAI: SAVE FAILED - bt is null");
|
||||||
|
|
||||||
|
_save_bt(task_tree->get_bt(), p_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LimboAIEditor::_load_bt(const String &p_path) {
|
||||||
ERR_FAIL_COND_MSG(p_path.is_empty(), "Empty p_path");
|
ERR_FAIL_COND_MSG(p_path.is_empty(), "Empty p_path");
|
||||||
Ref<BehaviorTree> bt = RESOURCE_LOAD(p_path, "BehaviorTree");
|
Ref<BehaviorTree> bt = RESOURCE_LOAD(p_path, "BehaviorTree");
|
||||||
ERR_FAIL_COND(!bt.is_valid());
|
ERR_FAIL_COND(!bt.is_valid());
|
||||||
|
@ -253,6 +308,8 @@ void LimboAIEditor::_disable_editing() {
|
||||||
void LimboAIEditor::edit_bt(const Ref<BehaviorTree> &p_behavior_tree, bool p_force_refresh) {
|
void LimboAIEditor::edit_bt(const Ref<BehaviorTree> &p_behavior_tree, bool p_force_refresh) {
|
||||||
ERR_FAIL_COND_MSG(p_behavior_tree.is_null(), "p_behavior_tree is null");
|
ERR_FAIL_COND_MSG(p_behavior_tree.is_null(), "p_behavior_tree is null");
|
||||||
|
|
||||||
|
_switch_to_owner_scene_if_builtin(p_behavior_tree);
|
||||||
|
|
||||||
if (!p_force_refresh && task_tree->get_bt() == p_behavior_tree) {
|
if (!p_force_refresh && task_tree->get_bt() == p_behavior_tree) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -268,8 +325,8 @@ void LimboAIEditor::edit_bt(const Ref<BehaviorTree> &p_behavior_tree, bool p_for
|
||||||
|
|
||||||
task_tree->load_bt(p_behavior_tree);
|
task_tree->load_bt(p_behavior_tree);
|
||||||
|
|
||||||
if (task_tree->get_bt().is_valid() && !task_tree->get_bt()->is_connected(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_mark_as_dirty))) {
|
if (task_tree->get_bt().is_valid() && !task_tree->get_bt()->is_connected(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_set_as_dirty))) {
|
||||||
task_tree->get_bt()->connect(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_mark_as_dirty).bind(true));
|
task_tree->get_bt()->connect(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_set_as_dirty).bind(task_tree->get_bt(), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
int idx = history.find(p_behavior_tree);
|
int idx = history.find(p_behavior_tree);
|
||||||
|
@ -334,12 +391,11 @@ void LimboAIEditor::get_window_layout(const Ref<ConfigFile> &p_configuration) {
|
||||||
p_configuration->set_value("LimboAI", "bteditor_hsplit", split_offset);
|
p_configuration->set_value("LimboAI", "bteditor_hsplit", split_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboAIEditor::_mark_as_dirty(bool p_dirty) {
|
void LimboAIEditor::_set_as_dirty(const Ref<BehaviorTree> &p_bt, bool p_dirty) {
|
||||||
Ref<BehaviorTree> bt = task_tree->get_bt();
|
if (p_dirty && !dirty.has(p_bt)) {
|
||||||
if (p_dirty && !dirty.has(bt)) {
|
dirty.insert(p_bt);
|
||||||
dirty.insert(bt);
|
} else if (p_dirty == false && dirty.has(p_bt)) {
|
||||||
} else if (p_dirty == false && dirty.has(bt)) {
|
dirty.erase(p_bt);
|
||||||
dirty.erase(bt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,6 +495,14 @@ void LimboAIEditor::_process_shortcut_input(const Ref<InputEvent> &p_event) {
|
||||||
} else if (LW_IS_SHORTCUT("limbo_ai/close_tab", p_event)) {
|
} else if (LW_IS_SHORTCUT("limbo_ai/close_tab", p_event)) {
|
||||||
_tab_menu_option_selected(TAB_CLOSE);
|
_tab_menu_option_selected(TAB_CLOSE);
|
||||||
handled = true;
|
handled = true;
|
||||||
|
} else if (LW_IS_SHORTCUT("limbo_ai/editor_save_scene", p_event)) {
|
||||||
|
// This intercepts the editor save action, but does not set the event as handled because we don't know the user's intention.
|
||||||
|
// We just want to save the currently edited BT as well, which may cause a loop with built-in resource if done from "_save_external_data".
|
||||||
|
// Workaround for: https://github.com/limbonaut/limboai/issues/240#issuecomment-2453087424
|
||||||
|
if (task_tree->get_bt().is_valid() && RESOURCE_IS_BUILT_IN(task_tree->get_bt())) {
|
||||||
|
_on_save_pressed();
|
||||||
|
}
|
||||||
|
handled = false; // intentionally not set as handled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -837,6 +901,7 @@ void LimboAIEditor::_on_tree_task_activated() {
|
||||||
|
|
||||||
void LimboAIEditor::_on_visibility_changed() {
|
void LimboAIEditor::_on_visibility_changed() {
|
||||||
if (task_tree->is_visible_in_tree()) {
|
if (task_tree->is_visible_in_tree()) {
|
||||||
|
_switch_to_owner_scene_if_builtin(task_tree->get_bt());
|
||||||
Ref<BTTask> sel = task_tree->get_selected();
|
Ref<BTTask> sel = task_tree->get_selected();
|
||||||
if (sel.is_valid()) {
|
if (sel.is_valid()) {
|
||||||
EDIT_RESOURCE(sel);
|
EDIT_RESOURCE(sel);
|
||||||
|
@ -854,16 +919,6 @@ void LimboAIEditor::_on_visibility_changed() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboAIEditor::_on_header_pressed() {
|
|
||||||
task_tree->clear_selection();
|
|
||||||
#ifdef LIMBOAI_MODULE
|
|
||||||
if (task_tree->get_bt().is_valid()) {
|
|
||||||
task_tree->get_bt()->editor_set_section_unfold("blackboard_plan", true);
|
|
||||||
}
|
|
||||||
#endif // LIMBOAI_MODULE
|
|
||||||
EDIT_RESOURCE(task_tree->get_bt());
|
|
||||||
}
|
|
||||||
|
|
||||||
void LimboAIEditor::_on_save_pressed() {
|
void LimboAIEditor::_on_save_pressed() {
|
||||||
if (task_tree->get_bt().is_null()) {
|
if (task_tree->get_bt().is_null()) {
|
||||||
return;
|
return;
|
||||||
|
@ -872,7 +927,7 @@ void LimboAIEditor::_on_save_pressed() {
|
||||||
if (path.is_empty()) {
|
if (path.is_empty()) {
|
||||||
save_dialog->popup_centered_ratio();
|
save_dialog->popup_centered_ratio();
|
||||||
} else {
|
} else {
|
||||||
_save_bt(path);
|
_save_current_bt(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1060,8 +1115,8 @@ void LimboAIEditor::_tab_clicked(int p_tab) {
|
||||||
void LimboAIEditor::_tab_closed(int p_tab) {
|
void LimboAIEditor::_tab_closed(int p_tab) {
|
||||||
ERR_FAIL_INDEX(p_tab, history.size());
|
ERR_FAIL_INDEX(p_tab, history.size());
|
||||||
Ref<BehaviorTree> history_bt = history[p_tab];
|
Ref<BehaviorTree> history_bt = history[p_tab];
|
||||||
if (history_bt.is_valid() && history_bt->is_connected(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_mark_as_dirty))) {
|
if (history_bt.is_valid() && history_bt->is_connected(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_set_as_dirty))) {
|
||||||
history_bt->disconnect(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_mark_as_dirty));
|
history_bt->disconnect(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_set_as_dirty));
|
||||||
}
|
}
|
||||||
if (tab_search_context.has(history_bt)) {
|
if (tab_search_context.has(history_bt)) {
|
||||||
tab_search_context.erase(history_bt);
|
tab_search_context.erase(history_bt);
|
||||||
|
@ -1241,10 +1296,13 @@ void LimboAIEditor::_reload_modified() {
|
||||||
|
|
||||||
void LimboAIEditor::_resave_modified(String _str) {
|
void LimboAIEditor::_resave_modified(String _str) {
|
||||||
for (const String &res_path : disk_changed_files) {
|
for (const String &res_path : disk_changed_files) {
|
||||||
Ref<BehaviorTree> res = RESOURCE_LOAD(res_path, "BehaviorTree");
|
Ref<BehaviorTree> bt = RESOURCE_LOAD(res_path, "BehaviorTree");
|
||||||
if (res.is_valid()) {
|
if (bt.is_valid()) {
|
||||||
ERR_FAIL_COND(!res->is_class("BehaviorTree"));
|
ERR_FAIL_COND(!bt->is_class("BehaviorTree"));
|
||||||
RESOURCE_SAVE(res, res->get_path(), 0);
|
if (RESOURCE_IS_EXTERNAL(bt)) {
|
||||||
|
// Only resave external - scene files are handled by the editor.
|
||||||
|
_save_bt(bt, bt->get_path());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
task_tree->update_tree();
|
task_tree->update_tree();
|
||||||
|
@ -1269,14 +1327,13 @@ void LimboAIEditor::_rename_task_confirmed() {
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimboAIEditor::apply_changes() {
|
void LimboAIEditor::save_all(bool p_external_only) {
|
||||||
for (int i = 0; i < history.size(); i++) {
|
for (int i = 0; i < history.size(); i++) {
|
||||||
Ref<BehaviorTree> bt = history.get(i);
|
Ref<BehaviorTree> bt = history.get(i);
|
||||||
String path = bt->get_path();
|
String path = bt->get_path();
|
||||||
if (RESOURCE_EXISTS(path, "BehaviorTree")) {
|
if (RESOURCE_EXISTS(path, "BehaviorTree") && (!p_external_only || RESOURCE_PATH_IS_EXTERNAL(path))) {
|
||||||
RESOURCE_SAVE(bt, path, 0);
|
_save_bt(bt, path);
|
||||||
}
|
}
|
||||||
dirty.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1423,14 +1480,14 @@ void LimboAIEditor::_notification(int p_what) {
|
||||||
case NOTIFICATION_EXIT_TREE: {
|
case NOTIFICATION_EXIT_TREE: {
|
||||||
task_tree->unload();
|
task_tree->unload();
|
||||||
for (int i = 0; i < history.size(); i++) {
|
for (int i = 0; i < history.size(); i++) {
|
||||||
if (history[i]->is_connected(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_mark_as_dirty))) {
|
if (history[i]->is_connected(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_set_as_dirty))) {
|
||||||
history[i]->disconnect(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_mark_as_dirty));
|
history[i]->disconnect(LW_NAME(changed), callable_mp(this, &LimboAIEditor::_set_as_dirty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_READY: {
|
case NOTIFICATION_READY: {
|
||||||
// **** Signals
|
// **** Signals
|
||||||
save_dialog->connect("file_selected", callable_mp(this, &LimboAIEditor::_save_bt));
|
save_dialog->connect("file_selected", callable_mp(this, &LimboAIEditor::_save_current_bt));
|
||||||
load_dialog->connect("file_selected", callable_mp(this, &LimboAIEditor::_load_bt));
|
load_dialog->connect("file_selected", callable_mp(this, &LimboAIEditor::_load_bt));
|
||||||
extract_dialog->connect("file_selected", callable_mp(this, &LimboAIEditor::_extract_subtree));
|
extract_dialog->connect("file_selected", callable_mp(this, &LimboAIEditor::_extract_subtree));
|
||||||
new_btn->connect(LW_NAME(pressed), callable_mp(this, &LimboAIEditor::_new_bt));
|
new_btn->connect(LW_NAME(pressed), callable_mp(this, &LimboAIEditor::_new_bt));
|
||||||
|
@ -1494,7 +1551,7 @@ void LimboAIEditor::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("_remove_task", "task"), &LimboAIEditor::_remove_task);
|
ClassDB::bind_method(D_METHOD("_remove_task", "task"), &LimboAIEditor::_remove_task);
|
||||||
ClassDB::bind_method(D_METHOD("_add_task_with_prototype", "prototype_task"), &LimboAIEditor::_add_task_with_prototype);
|
ClassDB::bind_method(D_METHOD("_add_task_with_prototype", "prototype_task"), &LimboAIEditor::_add_task_with_prototype);
|
||||||
ClassDB::bind_method(D_METHOD("_new_bt"), &LimboAIEditor::_new_bt);
|
ClassDB::bind_method(D_METHOD("_new_bt"), &LimboAIEditor::_new_bt);
|
||||||
ClassDB::bind_method(D_METHOD("_save_bt", "path"), &LimboAIEditor::_save_bt);
|
ClassDB::bind_method(D_METHOD("_save_bt", "path"), &LimboAIEditor::_save_current_bt);
|
||||||
ClassDB::bind_method(D_METHOD("_load_bt", "path"), &LimboAIEditor::_load_bt);
|
ClassDB::bind_method(D_METHOD("_load_bt", "path"), &LimboAIEditor::_load_bt);
|
||||||
ClassDB::bind_method(D_METHOD("_update_task_tree", "bt", "specific_task"), &LimboAIEditor::_update_task_tree, DEFVAL(Variant()));
|
ClassDB::bind_method(D_METHOD("_update_task_tree", "bt", "specific_task"), &LimboAIEditor::_update_task_tree, DEFVAL(Variant()));
|
||||||
ClassDB::bind_method(D_METHOD("edit_bt", "behavior_tree", "force_refresh"), &LimboAIEditor::edit_bt, Variant(false));
|
ClassDB::bind_method(D_METHOD("edit_bt", "behavior_tree", "force_refresh"), &LimboAIEditor::edit_bt, Variant(false));
|
||||||
|
@ -1541,11 +1598,14 @@ LimboAIEditor::LimboAIEditor() {
|
||||||
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/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/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)));
|
LW_SHORTCUT("limbo_ai/open_debugger", TTR("Open Debugger"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY_MASK(ALT) | LW_KEY(D)));
|
||||||
LW_SHORTCUT("limbo_ai/jump_to_owner", TTR("Jump to Owner"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY(J)));
|
LW_SHORTCUT("limbo_ai/jump_to_owner", TTR("Jump to Owner"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY(G)));
|
||||||
LW_SHORTCUT("limbo_ai/close_tab", TTR("Close Tab"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY(W)));
|
LW_SHORTCUT("limbo_ai/close_tab", TTR("Close Tab"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY(W)));
|
||||||
LW_SHORTCUT("limbo_ai/find_task", TTR("Find Task"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY(F)));
|
LW_SHORTCUT("limbo_ai/find_task", TTR("Find Task"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY(F)));
|
||||||
LW_SHORTCUT("limbo_ai/hide_tree_search", TTR("Close Search"), (Key)(LW_KEY(ESCAPE)));
|
LW_SHORTCUT("limbo_ai/hide_tree_search", TTR("Close Search"), (Key)(LW_KEY(ESCAPE)));
|
||||||
|
|
||||||
|
// Intercept editor save scene action.
|
||||||
|
LW_SHORTCUT("limbo_ai/editor_save_scene", TTR("Save Scene"), (Key)(LW_KEY_MASK(CMD_OR_CTRL) | LW_KEY(S)));
|
||||||
|
|
||||||
set_process_shortcut_input(true);
|
set_process_shortcut_input(true);
|
||||||
|
|
||||||
save_dialog = memnew(FileDialog);
|
save_dialog = memnew(FileDialog);
|
||||||
|
@ -1851,14 +1911,6 @@ LimboAIEditor::~LimboAIEditor() {
|
||||||
|
|
||||||
//**** LimboAIEditorPlugin
|
//**** LimboAIEditorPlugin
|
||||||
|
|
||||||
#ifdef LIMBOAI_MODULE
|
|
||||||
void LimboAIEditorPlugin::apply_changes() {
|
|
||||||
#elif LIMBOAI_GDEXTENSION
|
|
||||||
void LimboAIEditorPlugin::_apply_changes() {
|
|
||||||
#endif
|
|
||||||
limbo_ai_editor->apply_changes();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LimboAIEditorPlugin::_bind_methods() {
|
void LimboAIEditorPlugin::_bind_methods() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1917,8 +1969,9 @@ void LimboAIEditorPlugin::edit(Object *p_object) {
|
||||||
#elif LIMBOAI_GDEXTENSION
|
#elif LIMBOAI_GDEXTENSION
|
||||||
void LimboAIEditorPlugin::_edit(Object *p_object) {
|
void LimboAIEditorPlugin::_edit(Object *p_object) {
|
||||||
#endif
|
#endif
|
||||||
if (Object::cast_to<BehaviorTree>(p_object)) {
|
Ref<BehaviorTree> bt = Object::cast_to<BehaviorTree>(p_object);
|
||||||
limbo_ai_editor->edit_bt(Object::cast_to<BehaviorTree>(p_object));
|
if (bt.is_valid()) {
|
||||||
|
limbo_ai_editor->edit_bt(bt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1933,6 +1986,14 @@ bool LimboAIEditorPlugin::_handles(Object *p_object) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LIMBOAI_MODULE
|
||||||
|
void LimboAIEditorPlugin::save_external_data() {
|
||||||
|
#elif LIMBOAI_GDEXTENSION
|
||||||
|
void LimboAIEditorPlugin::_save_external_data() {
|
||||||
|
#endif
|
||||||
|
limbo_ai_editor->save_all(true);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef LIMBOAI_GDEXTENSION
|
#ifdef LIMBOAI_GDEXTENSION
|
||||||
Ref<Texture2D> LimboAIEditorPlugin::_get_plugin_icon() const {
|
Ref<Texture2D> LimboAIEditorPlugin::_get_plugin_icon() const {
|
||||||
return LimboUtility::get_singleton()->get_task_icon("LimboAI");
|
return LimboUtility::get_singleton()->get_task_icon("LimboAI");
|
||||||
|
|
|
@ -205,11 +205,12 @@ private:
|
||||||
void _update_misc_menu();
|
void _update_misc_menu();
|
||||||
void _update_banners();
|
void _update_banners();
|
||||||
void _new_bt();
|
void _new_bt();
|
||||||
void _save_bt(String p_path);
|
void _save_bt(const Ref<BehaviorTree> &p_bt, const String &p_path);
|
||||||
void _load_bt(String p_path);
|
void _save_current_bt(const String &p_path);
|
||||||
|
void _load_bt(const String &p_path);
|
||||||
void _update_task_tree(const Ref<BehaviorTree> &p_bt, const Ref<BTTask> &p_specific_task = nullptr);
|
void _update_task_tree(const Ref<BehaviorTree> &p_bt, const Ref<BTTask> &p_specific_task = nullptr);
|
||||||
void _disable_editing();
|
void _disable_editing();
|
||||||
void _mark_as_dirty(bool p_dirty);
|
void _set_as_dirty(const Ref<BehaviorTree> &p_bt, bool p_dirty);
|
||||||
void _create_user_task_dir();
|
void _create_user_task_dir();
|
||||||
void _remove_task_from_favorite(const String &p_task);
|
void _remove_task_from_favorite(const String &p_task);
|
||||||
void _save_and_restart();
|
void _save_and_restart();
|
||||||
|
@ -240,7 +241,6 @@ private:
|
||||||
void _on_tree_task_selected(const Ref<BTTask> &p_task);
|
void _on_tree_task_selected(const Ref<BTTask> &p_task);
|
||||||
void _on_tree_task_activated();
|
void _on_tree_task_activated();
|
||||||
void _on_visibility_changed();
|
void _on_visibility_changed();
|
||||||
void _on_header_pressed();
|
|
||||||
void _on_save_pressed();
|
void _on_save_pressed();
|
||||||
void _on_history_back();
|
void _on_history_back();
|
||||||
void _on_history_forward();
|
void _on_history_forward();
|
||||||
|
@ -271,7 +271,7 @@ public:
|
||||||
void set_window_layout(const Ref<ConfigFile> &p_configuration);
|
void set_window_layout(const Ref<ConfigFile> &p_configuration);
|
||||||
void get_window_layout(const Ref<ConfigFile> &p_configuration);
|
void get_window_layout(const Ref<ConfigFile> &p_configuration);
|
||||||
|
|
||||||
void apply_changes();
|
void save_all(bool p_external_only = false);
|
||||||
|
|
||||||
#ifdef LIMBOAI_GDEXTENSION
|
#ifdef LIMBOAI_GDEXTENSION
|
||||||
virtual void _shortcut_input(const Ref<InputEvent> &p_event) override { _process_shortcut_input(p_event); }
|
virtual void _shortcut_input(const Ref<InputEvent> &p_event) override { _process_shortcut_input(p_event); }
|
||||||
|
@ -297,23 +297,23 @@ public:
|
||||||
|
|
||||||
virtual String get_name() const override { return "LimboAI"; }
|
virtual String get_name() const override { return "LimboAI"; }
|
||||||
virtual void make_visible(bool p_visible) override;
|
virtual void make_visible(bool p_visible) override;
|
||||||
virtual void apply_changes() override;
|
|
||||||
virtual void edit(Object *p_object) override;
|
virtual void edit(Object *p_object) override;
|
||||||
virtual bool handles(Object *p_object) const override;
|
virtual bool handles(Object *p_object) const override;
|
||||||
virtual void set_window_layout(Ref<ConfigFile> p_configuration) override;
|
virtual void set_window_layout(Ref<ConfigFile> p_configuration) override;
|
||||||
virtual void get_window_layout(Ref<ConfigFile> p_configuration) override;
|
virtual void get_window_layout(Ref<ConfigFile> p_configuration) override;
|
||||||
|
virtual void save_external_data() override;
|
||||||
|
|
||||||
#elif LIMBOAI_GDEXTENSION
|
#elif LIMBOAI_GDEXTENSION
|
||||||
bool _has_main_screen() const override { return true; }
|
bool _has_main_screen() const override { return true; }
|
||||||
|
|
||||||
virtual String _get_plugin_name() const override { return "LimboAI"; }
|
virtual String _get_plugin_name() const override { return "LimboAI"; }
|
||||||
virtual void _make_visible(bool p_visible) override;
|
virtual void _make_visible(bool p_visible) override;
|
||||||
virtual void _apply_changes() override;
|
|
||||||
virtual void _edit(Object *p_object) override;
|
virtual void _edit(Object *p_object) override;
|
||||||
virtual bool _handles(Object *p_object) const override;
|
virtual bool _handles(Object *p_object) const override;
|
||||||
virtual Ref<Texture2D> _get_plugin_icon() const override;
|
virtual Ref<Texture2D> _get_plugin_icon() const override;
|
||||||
virtual void _set_window_layout(const Ref<ConfigFile> &p_configuration) override;
|
virtual void _set_window_layout(const Ref<ConfigFile> &p_configuration) override;
|
||||||
virtual void _get_window_layout(const Ref<ConfigFile> &p_configuration) override;
|
virtual void _get_window_layout(const Ref<ConfigFile> &p_configuration) override;
|
||||||
|
virtual void _save_external_data() override;
|
||||||
#endif // LIMBOAI_MODULE & LIMBOAI_GDEXTENSION
|
#endif // LIMBOAI_MODULE & LIMBOAI_GDEXTENSION
|
||||||
|
|
||||||
LimboAIEditorPlugin();
|
LimboAIEditorPlugin();
|
||||||
|
|
|
@ -95,7 +95,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
void load_bt(const Ref<BehaviorTree> &p_behavior_tree);
|
void load_bt(const Ref<BehaviorTree> &p_behavior_tree);
|
||||||
void unload();
|
void unload();
|
||||||
Ref<BehaviorTree> get_bt() const { return bt; }
|
_FORCE_INLINE_ Ref<BehaviorTree> get_bt() const { return bt; }
|
||||||
void update_tree() { _update_tree(); }
|
void update_tree() { _update_tree(); }
|
||||||
void update_task(const Ref<BTTask> &p_task);
|
void update_task(const Ref<BTTask> &p_task);
|
||||||
void add_selection(const Ref<BTTask> &p_task);
|
void add_selection(const Ref<BTTask> &p_task);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "core/io/resource.h"
|
#include "core/io/resource.h"
|
||||||
#include "core/variant/variant.h"
|
#include "core/variant/variant.h"
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
|
#include "editor/editor_main_screen.h"
|
||||||
#include "editor/plugins/script_editor_plugin.h"
|
#include "editor/plugins/script_editor_plugin.h"
|
||||||
#endif // TOOLS_ENABLED
|
#endif // TOOLS_ENABLED
|
||||||
|
|
||||||
|
@ -213,7 +214,7 @@ Variant VARIANT_DEFAULT(Variant::Type p_type) {
|
||||||
void SHOW_BUILTIN_DOC(const String &p_topic) {
|
void SHOW_BUILTIN_DOC(const String &p_topic) {
|
||||||
#ifdef LIMBOAI_MODULE
|
#ifdef LIMBOAI_MODULE
|
||||||
ScriptEditor::get_singleton()->goto_help(p_topic);
|
ScriptEditor::get_singleton()->goto_help(p_topic);
|
||||||
EditorNode::get_singleton()->set_visible_editor(EditorNode::EDITOR_SCRIPT);
|
EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_SCRIPT);
|
||||||
#elif LIMBOAI_GDEXTENSION
|
#elif LIMBOAI_GDEXTENSION
|
||||||
TypedArray<ScriptEditorBase> open_editors = EditorInterface::get_singleton()->get_script_editor()->get_open_script_editors();
|
TypedArray<ScriptEditorBase> open_editors = EditorInterface::get_singleton()->get_script_editor()->get_open_script_editors();
|
||||||
ERR_FAIL_COND_MSG(open_editors.size() == 0, "Can't open help page. Need at least one script open in the script editor.");
|
ERR_FAIL_COND_MSG(open_editors.size() == 0, "Can't open help page. Need at least one script open in the script editor.");
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#define EDITOR_FILE_SYSTEM() (EditorFileSystem::get_singleton())
|
#define EDITOR_FILE_SYSTEM() (EditorFileSystem::get_singleton())
|
||||||
#define EDITOR_SETTINGS() (EditorSettings::get_singleton())
|
#define EDITOR_SETTINGS() (EditorSettings::get_singleton())
|
||||||
#define BASE_CONTROL() (EditorNode::get_singleton()->get_gui_base())
|
#define BASE_CONTROL() (EditorNode::get_singleton()->get_gui_base())
|
||||||
#define MAIN_SCREEN_CONTROL() (EditorNode::get_singleton()->get_main_screen_control())
|
#define MAIN_SCREEN_CONTROL() (EditorNode::get_singleton()->get_editor_main_screen()->get_control())
|
||||||
#define SCENE_TREE() (SceneTree::get_singleton())
|
#define SCENE_TREE() (SceneTree::get_singleton())
|
||||||
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::is_active())
|
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::is_active())
|
||||||
#define FS_DOCK_SELECT_FILE(m_path) FileSystemDock::get_singleton()->select_file(m_path)
|
#define FS_DOCK_SELECT_FILE(m_path) FileSystemDock::get_singleton()->select_file(m_path)
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
#define GET_PROJECT_SETTINGS_DIR() EditorPaths::get_singleton()->get_project_settings_dir()
|
#define GET_PROJECT_SETTINGS_DIR() EditorPaths::get_singleton()->get_project_settings_dir()
|
||||||
#define EDIT_RESOURCE(m_res) EditorNode::get_singleton()->edit_resource(m_res)
|
#define EDIT_RESOURCE(m_res) EditorNode::get_singleton()->edit_resource(m_res)
|
||||||
#define INSPECTOR_GET_EDITED_OBJECT() (InspectorDock::get_inspector_singleton()->get_edited_object())
|
#define INSPECTOR_GET_EDITED_OBJECT() (InspectorDock::get_inspector_singleton()->get_edited_object())
|
||||||
#define SET_MAIN_SCREEN_EDITOR(m_name) (EditorNode::get_singleton()->select_editor_by_name(m_name))
|
#define SET_MAIN_SCREEN_EDITOR(m_name) (EditorNode::get_singleton()->get_editor_main_screen()->select_by_name(m_name))
|
||||||
#define FILE_EXISTS(m_path) FileAccess::exists(m_path)
|
#define FILE_EXISTS(m_path) FileAccess::exists(m_path)
|
||||||
#define DIR_ACCESS_CREATE() DirAccess::create(DirAccess::ACCESS_RESOURCES)
|
#define DIR_ACCESS_CREATE() DirAccess::create(DirAccess::ACCESS_RESOURCES)
|
||||||
#define PERFORMANCE_ADD_CUSTOM_MONITOR(m_id, m_callable) (Performance::get_singleton()->add_custom_monitor(m_id, m_callable, Variant()))
|
#define PERFORMANCE_ADD_CUSTOM_MONITOR(m_id, m_callable) (Performance::get_singleton()->add_custom_monitor(m_id, m_callable, Variant()))
|
||||||
|
@ -85,7 +85,7 @@ using namespace godot;
|
||||||
#define EDITOR_FILE_SYSTEM() (EditorInterface::get_singleton()->get_resource_filesystem())
|
#define EDITOR_FILE_SYSTEM() (EditorInterface::get_singleton()->get_resource_filesystem())
|
||||||
#define EDITOR_SETTINGS() (EditorInterface::get_singleton()->get_editor_settings())
|
#define EDITOR_SETTINGS() (EditorInterface::get_singleton()->get_editor_settings())
|
||||||
#define BASE_CONTROL() (EditorInterface::get_singleton()->get_base_control())
|
#define BASE_CONTROL() (EditorInterface::get_singleton()->get_base_control())
|
||||||
#define MAIN_SCREEN_CONTROL() (EditorInterface::get_singleton()->get_editor_main_screen())
|
#define MAIN_SCREEN_CONTROL() (EditorInterface::get_singleton()->get_editor_main_screen()->get_control())
|
||||||
#define SCENE_TREE() ((SceneTree *)(Engine::get_singleton()->get_main_loop()))
|
#define SCENE_TREE() ((SceneTree *)(Engine::get_singleton()->get_main_loop()))
|
||||||
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::get_singleton()->is_active())
|
#define IS_DEBUGGER_ACTIVE() (EngineDebugger::get_singleton()->is_active())
|
||||||
#define FS_DOCK_SELECT_FILE(m_path) EditorInterface::get_singleton()->get_file_system_dock()->navigate_to_path(m_path)
|
#define FS_DOCK_SELECT_FILE(m_path) EditorInterface::get_singleton()->get_file_system_dock()->navigate_to_path(m_path)
|
||||||
|
@ -175,7 +175,9 @@ Variant VARIANT_DEFAULT(Variant::Type p_type);
|
||||||
#define IS_RESOURCE_FILE(m_path) (m_path.begins_with("res://") && m_path.find("::") == -1)
|
#define IS_RESOURCE_FILE(m_path) (m_path.begins_with("res://") && m_path.find("::") == -1)
|
||||||
#define RESOURCE_TYPE_HINT(m_type) vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, m_type)
|
#define RESOURCE_TYPE_HINT(m_type) vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, m_type)
|
||||||
#define RESOURCE_IS_BUILT_IN(m_res) (m_res->get_path().is_empty() || m_res->get_path().contains("::"))
|
#define RESOURCE_IS_BUILT_IN(m_res) (m_res->get_path().is_empty() || m_res->get_path().contains("::"))
|
||||||
|
#define RESOURCE_IS_EXTERNAL(m_res) (!RESOURCE_IS_BUILT_IN(m_res))
|
||||||
#define RESOURCE_PATH_IS_BUILT_IN(m_path) (m_path.is_empty() || m_path.contains("::"))
|
#define RESOURCE_PATH_IS_BUILT_IN(m_path) (m_path.is_empty() || m_path.contains("::"))
|
||||||
|
#define RESOURCE_PATH_IS_EXTERNAL(m_path) (!RESOURCE_PATH_IS_BUILT_IN(m_path))
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
|
|
||||||
|
|
|
@ -416,6 +416,12 @@ String LimboUtility::get_property_hint_text(PropertyHint p_hint) const {
|
||||||
case PROPERTY_HINT_MAX: {
|
case PROPERTY_HINT_MAX: {
|
||||||
return "MAX";
|
return "MAX";
|
||||||
}
|
}
|
||||||
|
case PROPERTY_HINT_DICTIONARY_TYPE: {
|
||||||
|
return "DICTIONARY_TYPE";
|
||||||
|
}
|
||||||
|
case PROPERTY_HINT_TOOL_BUTTON: {
|
||||||
|
return "TOOL_BUTTON";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue