From decf178033d4176b0955b8efa8a081f7bccd7ed1 Mon Sep 17 00:00:00 2001 From: George Marques Date: Tue, 1 May 2018 11:06:23 -0300 Subject: [PATCH] Enable autoload in editor - Tool scripts will be executed and can be accessed by plugins. - Other script languages can implement add/remove_named_global_constant to make use of this functionality. --- core/script_language.h | 2 + editor/editor_autoload_settings.cpp | 166 +++++++++++++++++++-- editor/editor_autoload_settings.h | 2 + main/main.cpp | 194 ++++++++++++++----------- modules/gdscript/gdscript.cpp | 9 ++ modules/gdscript/gdscript.h | 6 +- modules/gdscript/gdscript_compiler.cpp | 24 +++ modules/gdscript/gdscript_compiler.h | 3 + modules/gdscript/gdscript_function.cpp | 15 ++ modules/gdscript/gdscript_function.h | 10 +- 10 files changed, 330 insertions(+), 101 deletions(-) diff --git a/core/script_language.h b/core/script_language.h index 0c1f99cea69..1cd27c07dc2 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -236,6 +236,8 @@ public: virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const = 0; virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) = 0; + virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value) {} + virtual void remove_named_global_constant(const StringName &p_name) {} /* MULTITHREAD FUNCTIONS */ diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index a2f5c1aa1a2..708bff252a4 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -33,6 +33,8 @@ #include "editor_node.h" #include "global_constants.h" #include "project_settings.h" +#include "scene/main/viewport.h" +#include "scene/resources/packed_scene.h" #define PREVIEW_LIST_MAX_SIZE 10 @@ -155,8 +157,8 @@ void EditorAutoloadSettings::_autoload_edited() { undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", selected_autoload, order); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", name); - undo_redo->add_do_method(this, "update_autoload"); - undo_redo->add_undo_method(this, "update_autoload"); + undo_redo->add_do_method(this, "call_deferred", "update_autoload"); + undo_redo->add_undo_method(this, "call_deferred", "update_autoload"); undo_redo->add_do_method(this, "emit_signal", autoload_changed); undo_redo->add_undo_method(this, "emit_signal", autoload_changed); @@ -187,8 +189,8 @@ void EditorAutoloadSettings::_autoload_edited() { undo_redo->add_do_method(ProjectSettings::get_singleton(), "set_order", base, order); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", base, order); - undo_redo->add_do_method(this, "update_autoload"); - undo_redo->add_undo_method(this, "update_autoload"); + undo_redo->add_do_method(this, "call_deferred", "update_autoload"); + undo_redo->add_undo_method(this, "call_deferred", "update_autoload"); undo_redo->add_do_method(this, "emit_signal", autoload_changed); undo_redo->add_undo_method(this, "emit_signal", autoload_changed); @@ -296,6 +298,18 @@ void EditorAutoloadSettings::update_autoload() { updating_autoload = true; + Map to_remove; + Map to_remove_singleton; + List to_add; + List to_add_singleton; // Only for when the node is still the same + + for (List::Element *E = autoload_cache.front(); E; E = E->next()) { + to_remove.insert(E->get().name, E->get()); + if (E->get().is_singleton) { + to_remove_singleton.insert(E->get().name, E->get()); + } + } + autoload_cache.clear(); tree->clear(); @@ -317,19 +331,44 @@ void EditorAutoloadSettings::update_autoload() { if (name.empty()) continue; + AutoLoadInfo old_info; + if (to_remove.has(name)) { + old_info = to_remove[name]; + } + AutoLoadInfo info; - info.name = pi.name; - info.order = ProjectSettings::get_singleton()->get_order(pi.name); + info.is_singleton = path.begins_with("*"); - autoload_cache.push_back(info); - - bool global = false; - - if (path.begins_with("*")) { - global = true; + if (info.is_singleton) { path = path.substr(1, path.length()); } + info.name = name; + info.path = path; + info.order = ProjectSettings::get_singleton()->get_order(pi.name); + + if (old_info.name == info.name) { + if (old_info.path == info.path) { + // Still the same resource, check singleton status + to_remove.erase(name); + if (info.is_singleton) { + if (old_info.is_singleton) { + to_remove_singleton.erase(name); + } else { + to_add_singleton.push_back(name); + } + } + } else { + // Resource changed + to_add.push_back(info); + } + } else { + // New autoload + to_add.push_back(info); + } + + autoload_cache.push_back(info); + TreeItem *item = tree->create_item(root); item->set_text(0, name); item->set_editable(0, true); @@ -340,7 +379,7 @@ void EditorAutoloadSettings::update_autoload() { item->set_cell_mode(2, TreeItem::CELL_MODE_CHECK); item->set_editable(2, true); item->set_text(2, TTR("Enable")); - item->set_checked(2, global); + item->set_checked(2, info.is_singleton); item->add_button(3, get_icon("FileList", "EditorIcons"), BUTTON_OPEN); item->add_button(3, get_icon("MoveUp", "EditorIcons"), BUTTON_MOVE_UP); item->add_button(3, get_icon("MoveDown", "EditorIcons"), BUTTON_MOVE_DOWN); @@ -348,6 +387,77 @@ void EditorAutoloadSettings::update_autoload() { item->set_selectable(3, false); } + // Remove autoload constants + for (Map::Element *E = to_remove_singleton.front(); E; E = E->next()) { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->remove_named_global_constant(E->get().name); + } + } + + // Remove obsolete nodes from the tree + for (Map::Element *E = to_remove.front(); E; E = E->next()) { + AutoLoadInfo &info = E->get(); + Node *al = get_node("/root/" + info.name); + ERR_CONTINUE(!al); + get_tree()->get_root()->remove_child(al); + memdelete(al); + } + + // Register new singletons already in the tree + for (List::Element *E = to_add_singleton.front(); E; E = E->next()) { + Node *al = get_node("/root/" + E->get()); + ERR_CONTINUE(!al); + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->add_named_global_constant(E->get(), al); + } + } + + // Add new nodes to the tree + List nodes_to_add; + for (List::Element *E = to_add.front(); E; E = E->next()) { + AutoLoadInfo &info = E->get(); + + RES res = ResourceLoader::load(info.path); + ERR_EXPLAIN("Can't autoload: " + info.path); + ERR_CONTINUE(res.is_null()); + Node *n = NULL; + if (res->is_class("PackedScene")) { + Ref ps = res; + n = ps->instance(); + } else if (res->is_class("Script")) { + Ref