diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 66ef418e42d..df5486512d6 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -245,9 +245,12 @@ void ScriptServer::thread_exit() { } HashMap ScriptServer::global_classes; +HashMap> ScriptServer::inheriters_cache; +bool ScriptServer::inheriters_cache_dirty = true; void ScriptServer::global_classes_clear() { global_classes.clear(); + inheriters_cache.clear(); } void ScriptServer::add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path) { @@ -257,16 +260,44 @@ void ScriptServer::add_global_class(const StringName &p_class, const StringName g.path = p_path; g.base = p_base; global_classes[p_class] = g; + inheriters_cache_dirty = true; } void ScriptServer::remove_global_class(const StringName &p_class) { global_classes.erase(p_class); + inheriters_cache_dirty = true; +} + +void ScriptServer::get_inheriters_list(const StringName &p_base_type, List *r_classes) { + if (inheriters_cache_dirty) { + inheriters_cache.clear(); + for (const KeyValue &K : global_classes) { + if (!inheriters_cache.has(K.value.base)) { + inheriters_cache[K.value.base] = Vector(); + } + inheriters_cache[K.value.base].push_back(K.key); + } + for (KeyValue> &K : inheriters_cache) { + K.value.sort_custom(); + } + inheriters_cache_dirty = false; + } + + if (!inheriters_cache.has(p_base_type)) { + return; + } + + const Vector &v = inheriters_cache[p_base_type]; + for (int i = 0; i < v.size(); i++) { + r_classes->push_back(v[i]); + } } void ScriptServer::remove_global_class_by_path(const String &p_path) { for (const KeyValue &kv : global_classes) { if (kv.value.path == p_path) { global_classes.erase(kv.key); + inheriters_cache_dirty = true; return; } } diff --git a/core/object/script_language.h b/core/object/script_language.h index 02d1880dc2f..0c64b079c1c 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -56,10 +56,12 @@ class ScriptServer { struct GlobalScriptClass { StringName language; String path; - String base; + StringName base; }; static HashMap global_classes; + static HashMap> inheriters_cache; + static bool inheriters_cache_dirty; public: static ScriptEditRequestFunction edit_request_func; @@ -87,6 +89,7 @@ public: static StringName get_global_class_base(const String &p_class); static StringName get_global_class_native_base(const String &p_class); static void get_global_class_list(List *r_global_classes); + static void get_inheriters_list(const StringName &p_base_type, List *r_classes); static void save_global_classes(); static void init_languages(); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index a1c913aaddf..cb71a2457b7 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -42,12 +42,6 @@ #include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" -HashMap> EditorResourcePicker::allowed_types_cache; - -void EditorResourcePicker::clear_caches() { - allowed_types_cache.clear(); -} - void EditorResourcePicker::_update_resource() { String resource_path; if (edited_resource.is_valid() && edited_resource->get_path().is_resource_file()) { @@ -464,7 +458,7 @@ void EditorResourcePicker::set_create_options(Object *p_menu_node) { if (!base_type.is_empty()) { int idx = 0; - HashSet allowed_types; + HashSet allowed_types; _get_allowed_types(false, &allowed_types); Vector custom_resources; @@ -472,7 +466,7 @@ void EditorResourcePicker::set_create_options(Object *p_menu_node) { custom_resources = EditorNode::get_editor_data().get_custom_types()["Resource"]; } - for (const String &E : allowed_types) { + for (const StringName &E : allowed_types) { const String &t = E; bool is_custom_resource = false; @@ -561,53 +555,44 @@ String EditorResourcePicker::_get_resource_type(const Ref &p_resource) return res_type; } -void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet *p_vector) const { +static void _add_allowed_type(const StringName &p_type, HashSet *p_vector) { + if (p_vector->has(p_type)) { + // Already added + return; + } + + if (ClassDB::class_exists(p_type)) { + // Engine class, + + if (!ClassDB::is_virtual(p_type)) { + p_vector->insert(p_type); + } + + List inheriters; + ClassDB::get_inheriters_from_class(p_type, &inheriters); + for (const StringName &S : inheriters) { + _add_allowed_type(S, p_vector); + } + } else { + // Script class. + p_vector->insert(p_type); + } + + List inheriters; + ScriptServer::get_inheriters_list(p_type, &inheriters); + for (const StringName &S : inheriters) { + _add_allowed_type(S, p_vector); + } +} + +void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet *p_vector) const { Vector allowed_types = base_type.split(","); int size = allowed_types.size(); - List global_classes; - ScriptServer::get_global_class_list(&global_classes); - for (int i = 0; i < size; i++) { String base = allowed_types[i].strip_edges(); - if (!ClassDB::is_virtual(base)) { - p_vector->insert(base); - } - // If we hit a familiar base type, take all the data from cache. - if (allowed_types_cache.has(base)) { - List allowed_subtypes = allowed_types_cache[base]; - for (const StringName &subtype_name : allowed_subtypes) { - if (!ClassDB::is_virtual(subtype_name)) { - p_vector->insert(subtype_name); - } - } - } else { - List allowed_subtypes; - - List inheriters; - if (!ScriptServer::is_global_class(base)) { - ClassDB::get_inheriters_from_class(base, &inheriters); - } - for (const StringName &subtype_name : inheriters) { - if (!ClassDB::is_virtual(subtype_name)) { - p_vector->insert(subtype_name); - } - allowed_subtypes.push_back(subtype_name); - } - - for (const StringName &subtype_name : global_classes) { - if (EditorNode::get_editor_data().script_class_is_parent(subtype_name, base)) { - if (!ClassDB::is_virtual(subtype_name)) { - p_vector->insert(subtype_name); - } - allowed_subtypes.push_back(subtype_name); - } - } - - // Store the subtypes of the base type in the cache for future use. - allowed_types_cache[base] = allowed_subtypes; - } + _add_allowed_type(base, p_vector); if (p_with_convert) { if (base == "BaseMaterial3D") { @@ -619,14 +604,6 @@ void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet custom_resources = EditorNode::get_editor_data().get_custom_types()["Resource"]; - - for (int i = 0; i < custom_resources.size(); i++) { - p_vector->insert(custom_resources[i].name); - } - } } bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const { @@ -654,7 +631,7 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const { } } - HashSet allowed_types; + HashSet allowed_types; _get_allowed_types(true, &allowed_types); if (res.is_valid()) { @@ -673,9 +650,9 @@ bool EditorResourcePicker::_is_drop_valid(const Dictionary &p_drag_data) const { return false; } -bool EditorResourcePicker::_is_type_valid(const String p_type_name, HashSet p_allowed_types) const { - for (const String &E : p_allowed_types) { - String at = E.strip_edges(); +bool EditorResourcePicker::_is_type_valid(const String p_type_name, HashSet p_allowed_types) const { + for (const StringName &E : p_allowed_types) { + String at = E; if (p_type_name == at || ClassDB::is_parent_class(p_type_name, at) || EditorNode::get_editor_data().script_class_is_parent(p_type_name, at)) { return true; } @@ -721,15 +698,15 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_ } if (dropped_resource.is_valid()) { - HashSet allowed_types; + HashSet allowed_types; _get_allowed_types(false, &allowed_types); String res_type = _get_resource_type(dropped_resource); // If the accepted dropped resource is from the extended list, it requires conversion. if (!_is_type_valid(res_type, allowed_types)) { - for (const String &E : allowed_types) { - String at = E.strip_edges(); + for (const StringName &E : allowed_types) { + String at = E; if (at == "BaseMaterial3D" && Ref(dropped_resource).is_valid()) { // Use existing resource if possible and only replace its data. @@ -832,7 +809,7 @@ void EditorResourcePicker::set_base_type(const String &p_base_type) { // There is a possibility that the new base type is conflicting with the existing value. // Keep the value, but warn the user that there is a potential mistake. if (!base_type.is_empty() && edited_resource.is_valid()) { - HashSet allowed_types; + HashSet allowed_types; _get_allowed_types(true, &allowed_types); StringName custom_class; @@ -846,10 +823,6 @@ void EditorResourcePicker::set_base_type(const String &p_base_type) { String class_str = (custom_class == StringName() ? edited_resource->get_class() : vformat("%s (%s)", custom_class, edited_resource->get_class())); WARN_PRINT(vformat("Value mismatch between the new base type of this EditorResourcePicker, '%s', and the type of the value it already has, '%s'.", base_type, class_str)); } - } else { - // Call the method to build the cache immediately. - HashSet allowed_types; - _get_allowed_types(false, &allowed_types); } } @@ -858,7 +831,7 @@ String EditorResourcePicker::get_base_type() const { } Vector EditorResourcePicker::get_allowed_types() const { - HashSet allowed_types; + HashSet allowed_types; _get_allowed_types(false, &allowed_types); Vector types; @@ -866,7 +839,7 @@ Vector EditorResourcePicker::get_allowed_types() const { int i = 0; String *w = types.ptrw(); - for (const String &E : allowed_types) { + for (const StringName &E : allowed_types) { w[i] = E; i++; } @@ -882,7 +855,7 @@ void EditorResourcePicker::set_edited_resource(Ref p_resource) { } if (!base_type.is_empty()) { - HashSet allowed_types; + HashSet allowed_types; _get_allowed_types(true, &allowed_types); StringName custom_class; diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h index 8641cb6e844..a302e249571 100644 --- a/editor/editor_resource_picker.h +++ b/editor/editor_resource_picker.h @@ -42,8 +42,6 @@ class EditorQuickOpen; class EditorResourcePicker : public HBoxContainer { GDCLASS(EditorResourcePicker, HBoxContainer); - static HashMap> allowed_types_cache; - String base_type; Ref edited_resource; @@ -92,9 +90,9 @@ class EditorResourcePicker : public HBoxContainer { void _button_input(const Ref &p_event); String _get_resource_type(const Ref &p_resource) const; - void _get_allowed_types(bool p_with_convert, HashSet *p_vector) const; + void _get_allowed_types(bool p_with_convert, HashSet *p_vector) const; bool _is_drop_valid(const Dictionary &p_drag_data) const; - bool _is_type_valid(const String p_type_name, HashSet p_allowed_types) const; + bool _is_type_valid(const String p_type_name, HashSet p_allowed_types) const; Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; @@ -118,8 +116,6 @@ protected: GDVIRTUAL1R(bool, _handle_menu_selected, int) public: - static void clear_caches(); - void set_base_type(const String &p_base_type); String get_base_type() const; Vector get_allowed_types() const; diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index 5f6b5aa42f0..061baaff7ee 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -219,6 +219,4 @@ void unregister_editor_types() { if (EditorPaths::get_singleton()) { EditorPaths::free(); } - - EditorResourcePicker::clear_caches(); }