diff options
-rw-r--r-- | core/script_language.h | 2 | ||||
-rw-r--r-- | editor/editor_autoload_settings.cpp | 164 | ||||
-rw-r--r-- | editor/editor_autoload_settings.h | 2 | ||||
-rw-r--r-- | main/main.cpp | 194 | ||||
-rw-r--r-- | modules/gdscript/gdscript.cpp | 9 | ||||
-rw-r--r-- | modules/gdscript/gdscript.h | 6 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 24 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.h | 3 | ||||
-rw-r--r-- | modules/gdscript/gdscript_function.cpp | 15 | ||||
-rw-r--r-- | modules/gdscript/gdscript_function.h | 10 |
10 files changed, 329 insertions, 100 deletions
diff --git a/core/script_language.h b/core/script_language.h index 55a20c7478..b4c55cac9e 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 a2f5c1aa1a..708bff252a 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<String, AutoLoadInfo> to_remove; + Map<String, AutoLoadInfo> to_remove_singleton; + List<AutoLoadInfo> to_add; + List<String> to_add_singleton; // Only for when the node is still the same + + for (List<AutoLoadInfo>::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); + if (info.is_singleton) { + path = path.substr(1, path.length()); + } - bool global = false; + info.name = name; + info.path = path; + info.order = ProjectSettings::get_singleton()->get_order(pi.name); - if (path.begins_with("*")) { - global = true; - path = path.substr(1, path.length()); + 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<String, AutoLoadInfo>::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<String, AutoLoadInfo>::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<String>::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<Node *> nodes_to_add; + for (List<AutoLoadInfo>::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<PackedScene> ps = res; + n = ps->instance(); + } else if (res->is_class("Script")) { + Ref<Script> s = res; + StringName ibt = s->get_instance_base_type(); + bool valid_type = ClassDB::is_parent_class(ibt, "Node"); + ERR_EXPLAIN("Script does not inherit a Node: " + info.path); + ERR_CONTINUE(!valid_type); + + Object *obj = ClassDB::instance(ibt); + + ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt)); + ERR_CONTINUE(obj == NULL); + + n = Object::cast_to<Node>(obj); + n->set_script(s.get_ref_ptr()); + } + + ERR_EXPLAIN("Path in autoload not a node or script: " + info.path); + ERR_CONTINUE(!n); + n->set_name(info.name); + + //defer so references are all valid on _ready() + nodes_to_add.push_back(n); + + if (info.is_singleton) { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->add_named_global_constant(info.name, n); + } + } + } + + for (List<Node *>::Element *E = nodes_to_add.front(); E; E = E->next()) { + get_tree()->get_root()->add_child(E->get()); + } + updating_autoload = false; } @@ -592,6 +702,36 @@ void EditorAutoloadSettings::_bind_methods() { EditorAutoloadSettings::EditorAutoloadSettings() { + // Make first cache + List<PropertyInfo> props; + ProjectSettings::get_singleton()->get_property_list(&props); + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + + const PropertyInfo &pi = E->get(); + + if (!pi.name.begins_with("autoload/")) + continue; + + String name = pi.name.get_slice("/", 1); + String path = ProjectSettings::get_singleton()->get(pi.name); + + if (name.empty()) + continue; + + AutoLoadInfo info; + info.is_singleton = path.begins_with("*"); + + 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); + + autoload_cache.push_back(info); + } + autoload_changed = "autoload_changed"; updating_autoload = false; diff --git a/editor/editor_autoload_settings.h b/editor/editor_autoload_settings.h index 6f622de6d5..1797c10e61 100644 --- a/editor/editor_autoload_settings.h +++ b/editor/editor_autoload_settings.h @@ -50,6 +50,8 @@ class EditorAutoloadSettings : public VBoxContainer { struct AutoLoadInfo { String name; + String path; + bool is_singleton; int order; bool operator==(const AutoLoadInfo &p_info) { diff --git a/main/main.cpp b/main/main.cpp index 5836c9c739..92b4e31679 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1661,6 +1661,114 @@ bool Main::start() { } #endif + if (!project_manager) { // game or editor + if (game_path != "" || script != "") { + //autoload + List<PropertyInfo> props; + ProjectSettings::get_singleton()->get_property_list(&props); + + //first pass, add the constants so they exist before any script is loaded + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + + String s = E->get().name; + if (!s.begins_with("autoload/")) + continue; + String name = s.get_slicec('/', 1); + String path = ProjectSettings::get_singleton()->get(s); + bool global_var = false; + if (path.begins_with("*")) { + global_var = true; + } + + if (global_var) { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { +#ifdef TOOLS_ENABLED + if (editor) { + ScriptServer::get_language(i)->add_named_global_constant(name, Variant()); + } else { + ScriptServer::get_language(i)->add_global_constant(name, Variant()); + } +#else + ScriptServer::get_language(i)->add_global_constant(name, Variant()); +#endif + } + } + } + + //second pass, load into global constants + List<Node *> to_add; +#ifdef TOOLS_ENABLED + ResourceLoader::set_timestamp_on_load(editor); // Avoid problems when editing +#endif + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + + String s = E->get().name; + if (!s.begins_with("autoload/")) + continue; + String name = s.get_slicec('/', 1); + String path = ProjectSettings::get_singleton()->get(s); + bool global_var = false; + if (path.begins_with("*")) { + global_var = true; + path = path.substr(1, path.length() - 1); + } + + RES res = ResourceLoader::load(path); + ERR_EXPLAIN("Can't autoload: " + path); + ERR_CONTINUE(res.is_null()); + Node *n = NULL; + if (res->is_class("PackedScene")) { + Ref<PackedScene> ps = res; + n = ps->instance(); + } else if (res->is_class("Script")) { + Ref<Script> s = res; + StringName ibt = s->get_instance_base_type(); + bool valid_type = ClassDB::is_parent_class(ibt, "Node"); + ERR_EXPLAIN("Script does not inherit a Node: " + path); + ERR_CONTINUE(!valid_type); + + Object *obj = ClassDB::instance(ibt); + + ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt)); + ERR_CONTINUE(obj == NULL); + + n = Object::cast_to<Node>(obj); + n->set_script(s.get_ref_ptr()); + } + + ERR_EXPLAIN("Path in autoload not a node or script: " + path); + ERR_CONTINUE(!n); + n->set_name(name); + + //defer so references are all valid on _ready() + to_add.push_back(n); + + if (global_var) { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { +#ifdef TOOLS_ENABLED + if (editor) { + ScriptServer::get_language(i)->add_named_global_constant(name, n); + } else { + ScriptServer::get_language(i)->add_global_constant(name, n); + } +#else + ScriptServer::get_language(i)->add_global_constant(name, n); +#endif + } + } + } + +#ifdef TOOLS_ENABLED + ResourceLoader::set_timestamp_on_load(false); +#endif + + for (List<Node *>::Element *E = to_add.front(); E; E = E->next()) { + + sml->get_root()->add_child(E->get()); + } + } + } + #ifdef TOOLS_ENABLED EditorNode *editor_node = NULL; @@ -1680,9 +1788,6 @@ bool Main::start() { } #endif - { - } - if (!editor && !project_manager) { //standard helpers that can be changed from main config @@ -1795,89 +1900,6 @@ bool Main::start() { } if (!project_manager && !editor) { // game - if (game_path != "" || script != "") { - //autoload - List<PropertyInfo> props; - ProjectSettings::get_singleton()->get_property_list(&props); - - //first pass, add the constants so they exist before any script is loaded - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - - String s = E->get().name; - if (!s.begins_with("autoload/")) - continue; - String name = s.get_slicec('/', 1); - String path = ProjectSettings::get_singleton()->get(s); - bool global_var = false; - if (path.begins_with("*")) { - global_var = true; - } - - if (global_var) { - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->add_global_constant(name, Variant()); - } - } - } - - //second pass, load into global constants - List<Node *> to_add; - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - - String s = E->get().name; - if (!s.begins_with("autoload/")) - continue; - String name = s.get_slicec('/', 1); - String path = ProjectSettings::get_singleton()->get(s); - bool global_var = false; - if (path.begins_with("*")) { - global_var = true; - path = path.substr(1, path.length() - 1); - } - - RES res = ResourceLoader::load(path); - ERR_EXPLAIN("Can't autoload: " + path); - ERR_CONTINUE(res.is_null()); - Node *n = NULL; - if (res->is_class("PackedScene")) { - Ref<PackedScene> ps = res; - n = ps->instance(); - } else if (res->is_class("Script")) { - Ref<Script> s = res; - StringName ibt = s->get_instance_base_type(); - bool valid_type = ClassDB::is_parent_class(ibt, "Node"); - ERR_EXPLAIN("Script does not inherit a Node: " + path); - ERR_CONTINUE(!valid_type); - - Object *obj = ClassDB::instance(ibt); - - ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt)); - ERR_CONTINUE(obj == NULL); - - n = Object::cast_to<Node>(obj); - n->set_script(s.get_ref_ptr()); - } - - ERR_EXPLAIN("Path in autoload not a node or script: " + path); - ERR_CONTINUE(!n); - n->set_name(name); - - //defer so references are all valid on _ready() - to_add.push_back(n); - - if (global_var) { - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->add_global_constant(name, n); - } - } - } - - for (List<Node *>::Element *E = to_add.front(); E; E = E->next()) { - - sml->get_root()->add_child(E->get()); - } - } - if (game_path != "") { Node *scene = NULL; Ref<PackedScene> scenedata = ResourceLoader::load(local_game_path); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 4e3ee4d22c..14bdce50ec 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1333,6 +1333,15 @@ void GDScriptLanguage::add_global_constant(const StringName &p_variable, const V _add_global(p_variable, p_value); } +void GDScriptLanguage::add_named_global_constant(const StringName &p_name, const Variant &p_value) { + named_globals[p_name] = p_value; +} + +void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) { + ERR_FAIL_COND(!named_globals.has(p_name)); + named_globals.erase(p_name); +} + void GDScriptLanguage::init() { //populate global constants diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 9566e3b32e..6885fbb7fe 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -262,6 +262,7 @@ class GDScriptLanguage : public ScriptLanguage { Variant *_global_array; Vector<Variant> global_array; Map<StringName, int> globals; + Map<StringName, Variant> named_globals; struct CallLevel { @@ -369,7 +370,8 @@ public: _FORCE_INLINE_ int get_global_array_size() const { return global_array.size(); } _FORCE_INLINE_ Variant *get_global_array() { return _global_array; } - _FORCE_INLINE_ const Map<StringName, int> &get_global_map() { return globals; } + _FORCE_INLINE_ const Map<StringName, int> &get_global_map() const { return globals; } + _FORCE_INLINE_ const Map<StringName, Variant> &get_named_globals_map() const { return named_globals; } _FORCE_INLINE_ static GDScriptLanguage *get_singleton() { return singleton; } @@ -403,6 +405,8 @@ public: virtual String _get_indentation() const; virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const; virtual void add_global_constant(const StringName &p_variable, const Variant &p_value); + virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value); + virtual void remove_named_global_constant(const StringName &p_name); /* DEBUGGER FUNCTIONS */ diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 048948dada..9947512444 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -278,6 +278,18 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: return idx | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root) } +#ifdef TOOLS_ENABLED + if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) { + + int idx = codegen.named_globals.find(identifier); + if (idx == -1) { + idx = codegen.named_globals.size(); + codegen.named_globals.push_back(identifier); + } + return idx | (GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL << GDScriptFunction::ADDR_BITS); + } +#endif + //not found, error _set_error("Identifier not found: " + String(identifier), p_expression); @@ -1511,6 +1523,18 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser gdfunc->_global_names_count = 0; } +#ifdef TOOLS_ENABLED + // Named globals + if (codegen.named_globals.size()) { + gdfunc->named_globals.resize(codegen.named_globals.size()); + gdfunc->_named_globals_ptr = gdfunc->named_globals.ptr(); + for (int i = 0; i < codegen.named_globals.size(); i++) { + gdfunc->named_globals[i] = codegen.named_globals[i]; + } + gdfunc->_named_globals_count = gdfunc->named_globals.size(); + } +#endif + if (codegen.opcodes.size()) { gdfunc->code = codegen.opcodes; diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h index 62aafdbe01..237b0de9e7 100644 --- a/modules/gdscript/gdscript_compiler.h +++ b/modules/gdscript/gdscript_compiler.h @@ -94,6 +94,9 @@ class GDScriptCompiler { HashMap<Variant, int, VariantHasher, VariantComparator> constant_map; Map<StringName, int> name_map; +#ifdef TOOLS_ENABLED + Vector<StringName> named_globals; +#endif int get_name_map_pos(const StringName &p_identifier) { int ret; diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index 1c5b8187ca..dac7da3a28 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -108,6 +108,21 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta #endif return &GDScriptLanguage::get_singleton()->get_global_array()[address]; } break; +#ifdef TOOLS_ENABLED + case ADDR_TYPE_NAMED_GLOBAL: { +#ifdef DEBUG_ENABLED + ERR_FAIL_INDEX_V(address, _named_globals_count, NULL); +#endif + StringName id = _named_globals_ptr[address]; + + if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(id)) { + return (Variant *)&GDScriptLanguage::get_singleton()->get_named_globals_map()[id]; + } else { + r_error = "Autoload singleton '" + String(id) + "' has been removed."; + return NULL; + } + } break; +#endif case ADDR_TYPE_NIL: { return &nil; } break; diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index dff4bdfaf2..ea009dcd96 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -92,7 +92,8 @@ public: ADDR_TYPE_STACK = 5, ADDR_TYPE_STACK_VARIABLE = 6, ADDR_TYPE_GLOBAL = 7, - ADDR_TYPE_NIL = 8 + ADDR_TYPE_NAMED_GLOBAL = 8, + ADDR_TYPE_NIL = 9 }; enum RPCMode { @@ -121,6 +122,10 @@ private: int _constant_count; const StringName *_global_names_ptr; int _global_names_count; +#ifdef TOOLS_ENABLED + const StringName *_named_globals_ptr; + int _named_globals_count; +#endif const int *_default_arg_ptr; int _default_arg_count; const int *_code_ptr; @@ -137,6 +142,9 @@ private: StringName name; Vector<Variant> constants; Vector<StringName> global_names; +#ifdef TOOLS_ENABLED + Vector<StringName> named_globals; +#endif Vector<int> default_arguments; Vector<int> code; |