Add hack to associate undo-redo actions with global history

This commit is contained in:
Serhii Snitsaruk 2024-08-21 15:23:27 +02:00
parent 9ae61e0556
commit c94ec7613d
No known key found for this signature in database
GPG Key ID: A965EF8799FFEC2D
2 changed files with 33 additions and 28 deletions

View File

@ -37,7 +37,6 @@
#include "editor/editor_interface.h" #include "editor/editor_interface.h"
#include "editor/editor_paths.h" #include "editor/editor_paths.h"
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/filesystem_dock.h" #include "editor/filesystem_dock.h"
#include "editor/gui/editor_bottom_panel.h" #include "editor/gui/editor_bottom_panel.h"
#include "editor/inspector_dock.h" #include "editor/inspector_dock.h"
@ -58,7 +57,6 @@
#include <godot_cpp/classes/editor_interface.hpp> #include <godot_cpp/classes/editor_interface.hpp>
#include <godot_cpp/classes/editor_paths.hpp> #include <godot_cpp/classes/editor_paths.hpp>
#include <godot_cpp/classes/editor_settings.hpp> #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/file_access.hpp>
#include <godot_cpp/classes/file_system_dock.hpp> #include <godot_cpp/classes/file_system_dock.hpp>
#include <godot_cpp/classes/input.hpp> #include <godot_cpp/classes/input.hpp>
@ -82,14 +80,25 @@ _FORCE_INLINE_ String _get_script_template_path() {
return templates_search_path.path_join("BTTask").path_join("custom_task.gd"); return templates_search_path.path_join("BTTask").path_join("custom_task.gd");
} }
EditorUndoRedoManager *LimboAIEditor::_new_undo_redo_action(const String &p_name, UndoRedo::MergeMode p_mode) {
#ifdef LIMBOAI_MODULE
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
#elif LIMBOAI_GDEXTENSION
EditorUndoRedoManager *undo_redo = plugin->get_undo_redo();
#endif
// ! HACK: Force global history to be used for resources without a set path.
undo_redo->create_action(p_name, p_mode, dummy_history_context);
undo_redo->force_fixed_history();
return undo_redo;
}
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) {
if (task_tree->get_bt().is_null()) { if (task_tree->get_bt().is_null()) {
return; return;
} }
ERR_FAIL_COND(p_task.is_null()); ERR_FAIL_COND(p_task.is_null());
EditorUndoRedoManager *undo_redo = GET_UNDO_REDO(); EditorUndoRedoManager *undo_redo = _new_undo_redo_action(TTR("Add BT Task"));
undo_redo->create_action(TTR("Add BT Task"));
int insert_idx = -1; int insert_idx = -1;
Ref<BTTask> selected = task_tree->get_selected(); Ref<BTTask> selected = task_tree->get_selected();
@ -169,8 +178,7 @@ void LimboAIEditor::_add_task_by_class_or_path(const String &p_class_or_path) {
void LimboAIEditor::_remove_task(const Ref<BTTask> &p_task) { void LimboAIEditor::_remove_task(const Ref<BTTask> &p_task) {
ERR_FAIL_COND(p_task.is_null()); ERR_FAIL_COND(p_task.is_null());
ERR_FAIL_COND(task_tree->get_bt().is_null()); ERR_FAIL_COND(task_tree->get_bt().is_null());
EditorUndoRedoManager *undo_redo = GET_UNDO_REDO(); EditorUndoRedoManager *undo_redo = _new_undo_redo_action(TTR("Remove BT Task"));
undo_redo->create_action(TTR("Remove BT Task"));
if (p_task->get_parent() == nullptr) { if (p_task->get_parent() == nullptr) {
ERR_FAIL_COND(task_tree->get_bt()->get_root_task() != p_task); ERR_FAIL_COND(task_tree->get_bt()->get_root_task() != p_task);
undo_redo->add_do_method(task_tree->get_bt().ptr(), LW_NAME(set_root_task), Variant()); undo_redo->add_do_method(task_tree->get_bt().ptr(), LW_NAME(set_root_task), Variant());
@ -226,7 +234,7 @@ void LimboAIEditor::_disable_editing() {
usage_hint->show(); usage_hint->show();
} }
void LimboAIEditor::edit_bt(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");
if (!p_force_refresh && task_tree->get_bt() == p_behavior_tree) { if (!p_force_refresh && task_tree->get_bt() == p_behavior_tree) {
@ -327,8 +335,7 @@ void LimboAIEditor::_extract_subtree(const String &p_path) {
Ref<BTTask> selected = task_tree->get_selected(); Ref<BTTask> selected = task_tree->get_selected();
ERR_FAIL_COND(selected.is_null()); ERR_FAIL_COND(selected.is_null());
EditorUndoRedoManager *undo_redo = GET_UNDO_REDO(); EditorUndoRedoManager *undo_redo = _new_undo_redo_action(TTR("Extract Subtree"));
undo_redo->create_action(TTR("Extract Subtree"));
Ref<BehaviorTree> bt = memnew(BehaviorTree); Ref<BehaviorTree> bt = memnew(BehaviorTree);
bt->set_root_task(selected->clone()); bt->set_root_task(selected->clone());
@ -459,7 +466,6 @@ void LimboAIEditor::_on_tree_rmb(const Vector2 &p_menu_pos) {
} }
void LimboAIEditor::_action_selected(int p_id) { void LimboAIEditor::_action_selected(int p_id) {
EditorUndoRedoManager *undo_redo = GET_UNDO_REDO();
switch (p_id) { switch (p_id) {
case ACTION_RENAME: { case ACTION_RENAME: {
if (!task_tree->get_selected().is_valid()) { if (!task_tree->get_selected().is_valid()) {
@ -537,7 +543,7 @@ void LimboAIEditor::_action_selected(int p_id) {
Ref<BTTask> parent = sel->get_parent(); Ref<BTTask> parent = sel->get_parent();
int idx = sel->get_index(); int idx = sel->get_index();
if (idx > 0 && idx < parent->get_child_count()) { if (idx > 0 && idx < parent->get_child_count()) {
undo_redo->create_action(TTR("Move BT Task")); EditorUndoRedoManager *undo_redo = _new_undo_redo_action(TTR("Move BT Task"));
undo_redo->add_do_method(parent.ptr(), LW_NAME(remove_child), sel); 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_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(remove_child), sel);
@ -555,7 +561,7 @@ void LimboAIEditor::_action_selected(int p_id) {
Ref<BTTask> parent = sel->get_parent(); Ref<BTTask> parent = sel->get_parent();
int idx = sel->get_index(); int idx = sel->get_index();
if (idx >= 0 && idx < (parent->get_child_count() - 1)) { if (idx >= 0 && idx < (parent->get_child_count() - 1)) {
undo_redo->create_action(TTR("Move BT Task")); EditorUndoRedoManager *undo_redo = _new_undo_redo_action(TTR("Move BT Task"));
undo_redo->add_do_method(parent.ptr(), LW_NAME(remove_child), sel); 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_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(remove_child), sel);
@ -570,7 +576,7 @@ void LimboAIEditor::_action_selected(int p_id) {
case ACTION_DUPLICATE: { case ACTION_DUPLICATE: {
Ref<BTTask> sel = task_tree->get_selected(); Ref<BTTask> sel = task_tree->get_selected();
if (sel.is_valid()) { if (sel.is_valid()) {
undo_redo->create_action(TTR("Duplicate BT Task")); EditorUndoRedoManager *undo_redo = _new_undo_redo_action(TTR("Duplicate BT Task"));
Ref<BTTask> parent = sel->get_parent(); Ref<BTTask> parent = sel->get_parent();
if (parent.is_null()) { if (parent.is_null()) {
parent = sel; parent = sel;
@ -589,7 +595,7 @@ void LimboAIEditor::_action_selected(int p_id) {
if (sel.is_valid() && task_tree->get_bt()->get_root_task() != sel) { if (sel.is_valid() && task_tree->get_bt()->get_root_task() != sel) {
Ref<BTTask> parent = sel->get_parent(); Ref<BTTask> parent = sel->get_parent();
ERR_FAIL_COND(parent.is_null()); ERR_FAIL_COND(parent.is_null());
undo_redo->create_action(TTR("Make Root")); EditorUndoRedoManager *undo_redo = _new_undo_redo_action(TTR("Make Root"));
undo_redo->add_do_method(parent.ptr(), LW_NAME(remove_child), sel); undo_redo->add_do_method(parent.ptr(), LW_NAME(remove_child), sel);
Ref<BTTask> old_root = task_tree->get_bt()->get_root_task(); Ref<BTTask> old_root = task_tree->get_bt()->get_root_task();
undo_redo->add_do_method(task_tree->get_bt().ptr(), LW_NAME(set_root_task), sel); undo_redo->add_do_method(task_tree->get_bt().ptr(), LW_NAME(set_root_task), sel);
@ -616,8 +622,7 @@ void LimboAIEditor::_action_selected(int p_id) {
if (p_id == ACTION_CUT) { if (p_id == ACTION_CUT) {
clipboard_task = sel->clone(); clipboard_task = sel->clone();
} }
EditorUndoRedoManager *undo_redo = _new_undo_redo_action(TTR("Remove BT Task"));
undo_redo->create_action(TTR("Remove BT Task"));
if (sel->is_root()) { if (sel->is_root()) {
undo_redo->add_do_method(task_tree->get_bt().ptr(), LW_NAME(set_root_task), Variant()); 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()); undo_redo->add_undo_method(task_tree->get_bt().ptr(), LW_NAME(set_root_task), task_tree->get_bt()->get_root_task());
@ -848,8 +853,7 @@ void LimboAIEditor::_on_task_dragged(Ref<BTTask> p_task, Ref<BTTask> p_to_task,
return; return;
} }
EditorUndoRedoManager *undo_redo = GET_UNDO_REDO(); EditorUndoRedoManager *undo_redo = _new_undo_redo_action(TTR("Drag BT Task"));
undo_redo->create_action(TTR("Drag BT Task"));
undo_redo->add_do_method(p_task->get_parent().ptr(), LW_NAME(remove_child), p_task); undo_redo->add_do_method(p_task->get_parent().ptr(), LW_NAME(remove_child), p_task);
if (p_type == 0) { if (p_type == 0) {
@ -943,8 +947,7 @@ void LimboAIEditor::_task_type_selected(const String &p_class_or_path) {
Ref<BTTask> new_task = _create_task_by_class_or_path(p_class_or_path); 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."); ERR_FAIL_COND_MSG(new_task.is_null(), "LimboAI: Unable to construct task.");
EditorUndoRedoManager *undo_redo = GET_UNDO_REDO(); EditorUndoRedoManager *undo_redo = _new_undo_redo_action(TTR("Change BT task type"));
undo_redo->create_action(TTR("Change BT task type"));
undo_redo->add_do_method(this, LW_NAME(_replace_task), selected_task, new_task); 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_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_do_method(task_tree, LW_NAME(update_tree));
@ -1198,8 +1201,7 @@ void LimboAIEditor::_rename_task_confirmed() {
ERR_FAIL_COND(!task_tree->get_selected().is_valid()); ERR_FAIL_COND(!task_tree->get_selected().is_valid());
rename_dialog->hide(); rename_dialog->hide();
EditorUndoRedoManager *undo_redo = GET_UNDO_REDO(); EditorUndoRedoManager *undo_redo = _new_undo_redo_action(TTR("Set Custom Name"));
undo_redo->create_action(TTR("Set Custom Name"));
undo_redo->add_do_method(task_tree->get_selected().ptr(), LW_NAME(set_custom_name), rename_edit->get_text()); 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_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_do_method(task_tree, LW_NAME(update_task), task_tree->get_selected());
@ -1462,6 +1464,7 @@ void LimboAIEditor::_bind_methods() {
LimboAIEditor::LimboAIEditor() { LimboAIEditor::LimboAIEditor() {
plugin = nullptr; plugin = nullptr;
idx_history = 0; idx_history = 0;
dummy_history_context = memnew(Object);
EDITOR_DEF("limbo_ai/editor/prefer_online_documentation", false); EDITOR_DEF("limbo_ai/editor/prefer_online_documentation", false);
@ -1795,6 +1798,7 @@ LimboAIEditor::LimboAIEditor() {
} }
LimboAIEditor::~LimboAIEditor() { LimboAIEditor::~LimboAIEditor() {
memdelete(dummy_history_context);
} }
//**** LimboAIEditor ^ //**** LimboAIEditor ^

View File

@ -26,6 +26,7 @@
#include "core/object/object.h" #include "core/object/object.h"
#include "core/templates/hash_set.h" #include "core/templates/hash_set.h"
#include "editor/editor_node.h" #include "editor/editor_node.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/gui/editor_spin_slider.h" #include "editor/gui/editor_spin_slider.h"
#include "editor/plugins/editor_plugin.h" #include "editor/plugins/editor_plugin.h"
#include "scene/gui/box_container.h" #include "scene/gui/box_container.h"
@ -42,9 +43,6 @@
#include "scene/gui/split_container.h" #include "scene/gui/split_container.h"
#include "scene/gui/tree.h" #include "scene/gui/tree.h"
#include "scene/resources/texture.h" #include "scene/resources/texture.h"
#define GET_UNDO_REDO() EditorUndoRedoManager::get_singleton()
#endif // LIMBOAI_MODULE #endif // LIMBOAI_MODULE
#ifdef LIMBOAI_GDEXTENSION #ifdef LIMBOAI_GDEXTENSION
@ -52,6 +50,7 @@
#include <godot_cpp/classes/control.hpp> #include <godot_cpp/classes/control.hpp>
#include <godot_cpp/classes/editor_plugin.hpp> #include <godot_cpp/classes/editor_plugin.hpp>
#include <godot_cpp/classes/editor_spin_slider.hpp> #include <godot_cpp/classes/editor_spin_slider.hpp>
#include <godot_cpp/classes/editor_undo_redo_manager.hpp>
#include <godot_cpp/classes/file_dialog.hpp> #include <godot_cpp/classes/file_dialog.hpp>
#include <godot_cpp/classes/h_box_container.hpp> #include <godot_cpp/classes/h_box_container.hpp>
#include <godot_cpp/classes/h_split_container.hpp> #include <godot_cpp/classes/h_split_container.hpp>
@ -67,8 +66,6 @@
using namespace godot; using namespace godot;
#define GET_UNDO_REDO() plugin->get_undo_redo()
#endif // LIMBOAI_GDEXTENSION #endif // LIMBOAI_GDEXTENSION
class LimboAIEditor : public Control { class LimboAIEditor : public Control {
@ -189,6 +186,10 @@ private:
AcceptDialog *info_dialog; AcceptDialog *info_dialog;
// ! HACK: Force global history to be used for resources without a set path.
Object *dummy_history_context = nullptr;
EditorUndoRedoManager *_new_undo_redo_action(const String &p_name = "", UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE);
void _add_task(const Ref<BTTask> &p_task, bool p_as_sibling); void _add_task(const Ref<BTTask> &p_task, bool p_as_sibling);
void _add_task_with_prototype(const Ref<BTTask> &p_prototype); void _add_task_with_prototype(const Ref<BTTask> &p_prototype);
Ref<BTTask> _create_task_by_class_or_path(const String &p_class_or_path) const; Ref<BTTask> _create_task_by_class_or_path(const String &p_class_or_path) const;
@ -258,7 +259,7 @@ protected:
public: public:
void set_plugin(EditorPlugin *p_plugin) { plugin = p_plugin; }; void set_plugin(EditorPlugin *p_plugin) { plugin = p_plugin; };
void edit_bt(Ref<BehaviorTree> p_behavior_tree, bool p_force_refresh = false); void edit_bt(const Ref<BehaviorTree> &p_behavior_tree, bool p_force_refresh = false);
Ref<BlackboardPlan> get_edited_blackboard_plan(); Ref<BlackboardPlan> get_edited_blackboard_plan();
void apply_changes(); void apply_changes();